Commit fd4d8f49e0

fd4d8f49e05054c05722cb16da555943d4007736

parent: c619fe4a96

Unsigned

cmc <hello@cleberg.net> · 2026-04-02 04:54 UTC

feat: expand user profile in Look Up

Layout: unified · split

Hutch/Models/User.swift +9
@@ -3,8 +3,17 @@ import Foundation
33/// A Sourcehut user from meta.sr.ht.
44struct User: Decodable, Sendable {
55 let id: Int
6 let created: String?
7 let updated: String?
68 let username: String
79 let canonicalName: String
810 let email: String
11 let url: String?
12 let location: String?
13 let bio: String?
914 let avatar: String?
15 let pronouns: String?
16 let userType: String?
17 let receivesPaidServices: Bool?
18 let suspensionNotice: String?
1019}
Hutch/Views/Lookup/LookupView.swift +40 −7
@@ -1,4 +1,7 @@
11import SwiftUI
2import os
3
4private let lookupLogger = Logger(subsystem: "net.cleberg.Hutch", category: "Lookup")
25
36enum LookupType: String, CaseIterable, Identifiable {
47 case user = "User"
@@ -166,17 +169,47 @@ final class LookupViewModel {
166169 let query = """
167170 query userLookup($username: String!) {
168171 user: userByName(username: $username) {
169 id username canonicalName email avatar
172 id
173 created
174 updated
175 canonicalName
176 username
177 email
178 url
179 location
180 bio
181 avatar
182 pronouns
183 userType
170184 }
171185 }
172186 """
173187
174 let result = try await client.execute(
175 service: .meta,
176 query: query,
177 variables: ["username": username],
178 responseType: Response.self
179 )
188 lookupLogger.debug("Looking up user profile for username: \(username, privacy: .public)")
189
190 let result: Response
191 do {
192 result = try await client.execute(
193 service: .meta,
194 query: query,
195 variables: ["username": username],
196 responseType: Response.self
197 )
198 } catch {
199 lookupLogger.error(
200 """
201 User lookup failed
202 username: \(username, privacy: .public)
203 query:
204 \(query, privacy: .public)
205 error:
206 \(String(describing: error), privacy: .public)
207 """
208 )
209 throw error
210 }
211
212 lookupLogger.debug("User lookup succeeded for username: \(username, privacy: .public)")
180213
181214 return .user(result.user)
182215 }
Hutch/Views/Lookup/UserProfileView.swift +51 −1
@@ -3,7 +3,12 @@ import SwiftUI
33struct UserProfileView: View {
44 let user: User
55
6 @Environment(AppState.self) private var appState
6 private static let iso8601Formatter: ISO8601DateFormatter = {
7 let formatter = ISO8601DateFormatter()
8 formatter.formatOptions = [.withInternetDateTime]
9 formatter.timeZone = TimeZone(secondsFromGMT: 0)
10 return formatter
11 }()
712
813 var body: some View {
914 List {
@@ -42,11 +47,56 @@ struct UserProfileView: View {
4247 Section {
4348 LabeledContent("Username", value: user.username)
4449 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 {
4562 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 }
4688 }
4789 }
4890 .listStyle(.insetGrouped)
4991 .navigationTitle(user.canonicalName)
5092 .navigationBarTitleDisplayMode(.inline)
5193 }
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 }
52102}