import SwiftUI /// Activity on everything you can reach — the `feed` command, paginated. struct FeedView: View { @State private var list: PagedListModel init(client: GitbayClient) { _list = State(initialValue: PagedListModel( client: client, argv: ["feed"], emptyMessage: "Nothing has happened yet on repositories you can reach." )) } var body: some View { List { ForEach(list.state.value ?? []) { event in link(for: event) } PageFooter(list: list) } .overlay { LoadStateOverlay(state: list.state) } .navigationTitle("Feed") .toolbar { AccountMenu() } .task { if list.state.value == nil { await list.reload() } } .refreshable { await list.reload() } } @ViewBuilder private func link(for event: FeedEvent) -> some View { switch event.destination { case .repo(let repo): NavigationLink(value: RepoRoute.repo(repo)) { FeedRow(event: event) } case .mr(let repo, let number): NavigationLink(value: MRRoute.mr(repo: repo, number: number)) { FeedRow(event: event) } case .issue(let repo, let number): NavigationLink(value: IssueRoute.issue(repo: repo, number: number)) { FeedRow(event: event) } case .build(let repo, let number): NavigationLink(value: BuildRoute.log(repo: repo, number: number)) { FeedRow(event: event) } case .release(let repo, let tag): NavigationLink(value: ReleaseRoute.release(repo: repo, tag: tag)) { FeedRow(event: event) } case nil: FeedRow(event: event) } } } private struct FeedRow: View { let event: FeedEvent var body: some View { HStack(spacing: 10) { Image(systemName: event.icon.name) .foregroundStyle(color) .frame(width: 22) VStack(alignment: .leading, spacing: 2) { Text(event.repo) .font(.caption) .foregroundStyle(.secondary) HStack(spacing: 4) { if let actor = event.actor, !actor.isEmpty { Text(actor) .font(.subheadline.weight(.semibold)) } Text(event.phrase) .font(.subheadline) .lineLimit(1) } } Spacer() Text(event.createdAt, format: .relative(presentation: .named)) .font(.caption) .foregroundStyle(.tertiary) } .padding(.vertical, 2) } private var color: Color { switch event.icon.isPositive { case true: .green case false: .red default: .secondary } } }