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}