summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Hutch/Models/User.swift9
-rw-r--r--Hutch/Views/Lookup/LookupView.swift47
-rw-r--r--Hutch/Views/Lookup/UserProfileView.swift52
3 files changed, 100 insertions, 8 deletions
diff --git a/Hutch/Models/User.swift b/Hutch/Models/User.swift
index a9350a3..625cfdc 100644
--- a/Hutch/Models/User.swift
+++ b/Hutch/Models/User.swift
@@ -3,8 +3,17 @@ import Foundation
/// A Sourcehut user from meta.sr.ht.
struct User: Decodable, Sendable {
let id: Int
+ let created: String?
+ let updated: String?
let username: String
let canonicalName: String
let email: String
+ let url: String?
+ let location: String?
+ let bio: String?
let avatar: String?
+ let pronouns: String?
+ let userType: String?
+ let receivesPaidServices: Bool?
+ let suspensionNotice: String?
}
diff --git a/Hutch/Views/Lookup/LookupView.swift b/Hutch/Views/Lookup/LookupView.swift
index 9f42d9e..413ea12 100644
--- a/Hutch/Views/Lookup/LookupView.swift
+++ b/Hutch/Views/Lookup/LookupView.swift
@@ -1,4 +1,7 @@
import SwiftUI
+import os
+
+private let lookupLogger = Logger(subsystem: "net.cleberg.Hutch", category: "Lookup")
enum LookupType: String, CaseIterable, Identifiable {
case user = "User"
@@ -166,17 +169,47 @@ final class LookupViewModel {
let query = """
query userLookup($username: String!) {
user: userByName(username: $username) {
- id username canonicalName email avatar
+ id
+ created
+ updated
+ canonicalName
+ username
+ email
+ url
+ location
+ bio
+ avatar
+ pronouns
+ userType
}
}
"""
- let result = try await client.execute(
- service: .meta,
- query: query,
- variables: ["username": username],
- responseType: Response.self
- )
+ lookupLogger.debug("Looking up user profile for username: \(username, privacy: .public)")
+
+ let result: Response
+ do {
+ result = try await client.execute(
+ service: .meta,
+ query: query,
+ variables: ["username": username],
+ responseType: Response.self
+ )
+ } catch {
+ lookupLogger.error(
+ """
+ User lookup failed
+ username: \(username, privacy: .public)
+ query:
+ \(query, privacy: .public)
+ error:
+ \(String(describing: error), privacy: .public)
+ """
+ )
+ throw error
+ }
+
+ lookupLogger.debug("User lookup succeeded for username: \(username, privacy: .public)")
return .user(result.user)
}
diff --git a/Hutch/Views/Lookup/UserProfileView.swift b/Hutch/Views/Lookup/UserProfileView.swift
index 3fcbb2f..4c91244 100644
--- a/Hutch/Views/Lookup/UserProfileView.swift
+++ b/Hutch/Views/Lookup/UserProfileView.swift
@@ -3,7 +3,12 @@ import SwiftUI
struct UserProfileView: View {
let user: User
- @Environment(AppState.self) private var appState
+ private static let iso8601Formatter: ISO8601DateFormatter = {
+ let formatter = ISO8601DateFormatter()
+ formatter.formatOptions = [.withInternetDateTime]
+ formatter.timeZone = TimeZone(secondsFromGMT: 0)
+ return formatter
+ }()
var body: some View {
List {
@@ -42,11 +47,56 @@ struct UserProfileView: View {
Section {
LabeledContent("Username", value: user.username)
LabeledContent("Canonical Name", value: user.canonicalName)
+ if let userType = user.userType {
+ LabeledContent("User Type", value: userType)
+ }
+ if let pronouns = user.pronouns {
+ LabeledContent("Pronouns", value: pronouns)
+ }
+ if let suspensionNotice = user.suspensionNotice {
+ LabeledContent("Suspension Notice", value: suspensionNotice)
+ }
+ }
+
+ Section {
LabeledContent("Email", value: user.email)
+ if let urlString = user.url, let url = URL(string: urlString) {
+ LabeledContent("URL") {
+ Link(urlString, destination: url)
+ }
+ }
+ if let location = user.location {
+ LabeledContent("Location", value: location)
+ }
+ }
+
+ if let bio = user.bio {
+ Section("Bio") {
+ Text(bio)
+ }
+ }
+
+ if user.created != nil || user.updated != nil {
+ Section {
+ if let created = user.created {
+ LabeledContent("Joined", value: formattedTimestamp(created))
+ }
+ if let updated = user.updated {
+ LabeledContent("Updated", value: formattedTimestamp(updated))
+ }
+ }
}
}
.listStyle(.insetGrouped)
.navigationTitle(user.canonicalName)
.navigationBarTitleDisplayMode(.inline)
}
+
+ private func formattedTimestamp(_ value: String) -> String {
+ guard let date = Self.iso8601Formatter.date(from: value) else {
+ return value
+ }
+
+ return date.formatted(date: .abbreviated, time: .shortened)
+ }
}