krz/hutch
an ios client for sourcehut
clone: git clone https://gitbay.org/krz/hutch.git
v2.6.0: Hutch/Views/Repositories/RepositoryDetailView.swift · raw
1import SwiftUI
2
3struct RepositoryDetailView: View {
4 var repository: RepositorySummary
5 var onDeleted: (() -> Void)?
6
7 @Environment(AppState.self) private var appState
8 @Environment(\.dismiss) private var dismiss
9 @State private var viewModel: RepositoryDetailViewModel?
10 @State private var selectedTab: RepositoryDetailViewModel.Tab = .summary
11 @State private var showSettings = false
12 @State private var displayName: String
13
14 init(repository: RepositorySummary, onDeleted: (() -> Void)? = nil) {
15 self.repository = repository
16 self.onDeleted = onDeleted
17 self._displayName = State(initialValue: repository.name)
18 }
19
20 var body: some View {
21 if repository.service == .hg {
22 HgRepositoryDetailView(repository: repository, onDeleted: onDeleted)
23 } else {
24 Group {
25 if let viewModel {
26 detailContent(viewModel)
27 } else {
28 SRHTLoadingStateView(message: "Loading repository…")
29 }
30 }
31 .navigationTitle(displayName)
32 .navigationBarTitleDisplayMode(.inline)
33 .toolbar {
34 ToolbarItemGroup(placement: .topBarTrailing) {
35 SRHTShareButton(url: SRHTWebURL.repository(repository), target: .repository) {
36 Image(systemName: "square.and.arrow.up")
37 }
38
39 Button {
40 showSettings = true
41 } label: {
42 Image(systemName: "gear")
43 }
44 }
45 }
46 .sheet(isPresented: $showSettings) {
47 RepositorySettingsView(
48 repository: repository,
49 branches: viewModel?.branches ?? [],
50 client: appState.client,
51 onRenamed: { newName in
52 displayName = newName
53 },
54 onDeleted: {
55 dismiss()
56 onDeleted?()
57 }
58 )
59 }
60 .task {
61 if viewModel == nil {
62 viewModel = RepositoryDetailViewModel(
63 repository: repository,
64 client: appState.client
65 )
66 }
67 }
68 }
69 }
70
71 @ViewBuilder
72 private func detailContent(_ viewModel: RepositoryDetailViewModel) -> some View {
73 VStack(spacing: 0) {
74 Picker("Tab", selection: $selectedTab) {
75 ForEach(RepositoryDetailViewModel.Tab.allCases, id: \.self) { tab in
76 Text(tab.rawValue).tag(tab)
77 }
78 }
79 .pickerStyle(.segmented)
80 .padding(.horizontal)
81 .padding(.vertical, 8)
82
83 Divider()
84
85 switch selectedTab {
86 case .summary:
87 ReadmeView(viewModel: viewModel)
88 case .tree:
89 FileTreeView(
90 repository: repository,
91 client: appState.client
92 )
93 case .log:
94 CommitLogView(viewModel: viewModel)
95 case .refs:
96 ReferencesListView(viewModel: viewModel)
97 case .artifacts:
98 ArtifactsView(viewModel: viewModel)
99 }
100 }
101 .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
102 .srhtErrorBanner(error: Binding(
103 get: { viewModel.error },
104 set: { viewModel.error = $0 }
105 ))
106 }
107}