a native ios client for gitbay

client ios swift

https://gitbay.org

gitbay/Views/Repos/LogView.swift

105 lines · 3449 bytes

  1import SwiftUI
  2
  3struct LogView: View {
  4
  5    @State private var model: LogViewModel
  6
  7    init(client: GitbayClient, repo: String, ref: String?, path: String?) {
  8        _model = State(initialValue: LogViewModel(
  9            client: client, repoPath: repo, ref: ref, path: path
 10        ))
 11    }
 12
 13    /// Name what this history is of: a file, a ref, or the repository.
 14    private var title: String {
 15        if let path = model.path {
 16            return String(path.split(separator: "/").last ?? "")
 17        }
 18        return model.ref.map { "History · \($0)" } ?? "History"
 19    }
 20
 21
 22    var body: some View {
 23        List {
 24            ForEach(model.state.value ?? []) { commit in
 25                NavigationLink(value: RepoRoute.commit(repo: model.repoPath, sha: commit.sha)) {
 26                    CommitRow(commit: commit)
 27                }
 28            }
 29        }
 30        .overlay { LoadStateOverlay(state: model.state) }
 31        .navigationTitle(title)
 32        .navigationBarTitleDisplayMode(.inline)
 33        .task { await model.load() }
 34        .refreshable { await model.load() }
 35    }
 36}
 37
 38struct CommitRow: View {
 39    let commit: Commit
 40
 41    var body: some View {
 42        VStack(alignment: .leading, spacing: 4) {
 43            Text(commit.subject)
 44                .font(.gbSans(.subheadline).weight(.medium))
 45                .lineLimit(2)
 46            HStack(spacing: 6) {
 47                Text(commit.shortSHA)
 48                    .font(.gbMono(.caption))
 49                    .foregroundStyle(.secondary)
 50                SignatureBadge(signature: commit.signature)
 51                Spacer()
 52                Text(commit.authorName)
 53                    .font(.gbSans(.caption))
 54                    .foregroundStyle(.secondary)
 55                    .lineLimit(1)
 56                Text(commit.date, format: .relative(presentation: .named))
 57                    .font(.gbSans(.caption))
 58                    .foregroundStyle(.secondary)
 59            }
 60        }
 61        .padding(.vertical, 2)
 62    }
 63}
 64
 65/// The server's signature verdict, worn as a small badge. The states come
 66/// from the registry; the app only chooses glyph and colour.
 67struct SignatureBadge: View {
 68    let signature: Commit.Signature
 69
 70    var body: some View {
 71        if let (icon, color, text) = presentation {
 72            Label {
 73                Text(text)
 74            } icon: {
 75                Image(systemName: icon)
 76            }
 77            .font(.gbSans(.caption2))
 78            .foregroundStyle(color)
 79            .labelStyle(.titleAndIcon)
 80        }
 81    }
 82
 83    /// Unsigned commits are the norm  no badge at all. Everything else
 84    /// says what the server concluded.
 85    private var presentation: (String, Color, String)? {
 86        switch signature.state {
 87        case .unsigned:
 88            nil
 89        case .verified:
 90            ("checkmark.seal.fill", .gbOK, signature.signer ?? "verified")
 91        case .signedUnknownKey:
 92            ("questionmark.diamond", .secondary, "unknown key")
 93        case .signedEmailMismatch:
 94            ("exclamationmark.triangle", .gbWarn, "email mismatch")
 95        case .signedKeyExpired:
 96            ("clock.badge.exclamationmark", .gbWarn, "key expired")
 97        case .signedKeyRevoked:
 98            ("xmark.seal", .gbBad, "key revoked")
 99        case .badSignature:
100            ("xmark.seal.fill", .gbBad, "bad signature")
101        case .unrecognized(let state):
102            ("questionmark.circle", .secondary, state)
103        }
104    }
105}