krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v2.8.2: Hutch/Views/Lookup/UserProfileView.swift · raw
1import SwiftUI
2
3struct UserProfileView: View {
4 let user: User
5
6 private static let iso8601Formatter: ISO8601DateFormatter = {
7 let formatter = ISO8601DateFormatter()
8 formatter.formatOptions = [.withInternetDateTime]
9 formatter.timeZone = TimeZone(secondsFromGMT: 0)
10 return formatter
11 }()
12
13 var body: some View {
14 List {
15 if let avatarURL = user.avatar.flatMap(URL.init(string:)) {
16 Section {
17 HStack {
18 Spacer()
19 AsyncImage(url: avatarURL) { phase in
20 switch phase {
21 case .success(let image):
22 image
23 .resizable()
24 .scaledToFill()
25 case .failure, .empty:
26 Image(systemName: "person.crop.circle.fill")
27 .resizable()
28 .scaledToFit()
29 .foregroundStyle(.secondary)
30 .padding(20)
31 @unknown default:
32 EmptyView()
33 }
34 }
35 .frame(width: 96, height: 96)
36 .clipShape(Circle())
37 .overlay {
38 Circle()
39 .stroke(Color.secondary.opacity(0.2), lineWidth: 1)
40 }
41 Spacer()
42 }
43 .listRowBackground(Color.clear)
44 }
45 }
46
47 Section {
48 LabeledContent("Username", value: user.username)
49 LabeledContent("Canonical Name", value: user.canonicalName)
50 if let userType = user.userType {
51 LabeledContent("User Type", value: userType)
52 }
53 if let pronouns = user.pronouns {
54 LabeledContent("Pronouns", value: pronouns)
55 }
56 if let suspensionNotice = user.suspensionNotice {
57 LabeledContent("Suspension Notice", value: suspensionNotice)
58 }
59 }
60
61 Section {
62 LabeledContent("Email", value: user.email)
63 if let urlString = user.url, let url = URL(string: urlString) {
64 LabeledContent("URL") {
65 Link(urlString, destination: url)
66 }
67 }
68 if let location = user.location {
69 LabeledContent("Location", value: location)
70 }
71 }
72
73 if let bio = user.bio {
74 Section("Bio") {
75 Text(bio)
76 }
77 }
78
79 if user.created != nil || user.updated != nil {
80 Section {
81 if let created = user.created {
82 LabeledContent("Joined", value: formattedTimestamp(created))
83 }
84 if let updated = user.updated {
85 LabeledContent("Updated", value: formattedTimestamp(updated))
86 }
87 }
88 }
89 }
90 .listStyle(.insetGrouped)
91 .navigationTitle(user.canonicalName)
92 .navigationBarTitleDisplayMode(.inline)
93 }
94
95 private func formattedTimestamp(_ value: String) -> String {
96 guard let date = Self.iso8601Formatter.date(from: value) else {
97 return value
98 }
99
100 return date.formatted(date: .abbreviated, time: .shortened)
101 }
102}