gitbay/ContentView.swift
192 lines · 7099 bytes
1import SwiftUI
2
3struct ContentView: View {
4
5 @Environment(SessionStore.self) private var session
6
7 var body: some View {
8 if let client = session.client, let account = session.current {
9 TabView {
10 Tab("Dashboard", systemImage: "square.grid.2x2") {
11 NavigationStack {
12 DashboardView(client: client)
13 .navigationDestinations(client: client)
14 }
15 }
16 Tab("Feed", systemImage: "bolt") {
17 NavigationStack {
18 FeedView(client: client)
19 .navigationDestinations(client: client)
20 }
21 }
22 Tab("Repositories", systemImage: "books.vertical") {
23 NavigationStack {
24 RepoListView(client: client)
25 .navigationDestinations(client: client)
26 }
27 }
28 Tab("Explore", systemImage: "safari") {
29 NavigationStack {
30 ExploreView(client: client)
31 .navigationDestinations(client: client)
32 }
33 }
34 Tab("My Profile", systemImage: "person.crop.circle") {
35 NavigationStack {
36 ProfileView(client: client, name: account.username,
37 title: "My Profile")
38 .toolbar { AccountMenu() }
39 .navigationDestinations(client: client)
40 }
41 }
42 }
43 .id(account.id) // fresh screens on account switch
44 } else {
45 NavigationStack {
46 SignInView()
47 }
48 }
49 }
50
51}
52
53/// Every value-routed screen, attachable to any stack root.
54private struct RouteDestinations: ViewModifier {
55
56 let client: GitbayClient
57
58 func body(content: Content) -> some View {
59 content
60 .navigationDestination(for: RepoRoute.self) { route in
61 destination(route, client: client)
62 }
63 .navigationDestination(for: MRRoute.self) { route in
64 destination(route, client: client)
65 }
66 .navigationDestination(for: IssueRoute.self) { route in
67 destination(route, client: client)
68 }
69 .navigationDestination(for: BuildRoute.self) { route in
70 destination(route, client: client)
71 }
72 .navigationDestination(for: ReleaseRoute.self) { route in
73 destination(route, client: client)
74 }
75 .navigationDestination(for: OrgRoute.self) { route in
76 destination(route, client: client)
77 }
78 }
79
80 @ViewBuilder
81 private func destination(_ route: RepoRoute, client: GitbayClient) -> some View {
82 switch route {
83 case .repo(let path):
84 RepoView(client: client, path: path)
85 case .tree(let repo, let directory, let ref):
86 TreeView(client: client, repo: repo, directory: directory, ref: ref)
87 case .file(let repo, let path, let ref):
88 FileView(client: client, repo: repo, path: path, ref: ref)
89 case .log(let repo, let ref, let path):
90 LogView(client: client, repo: repo, ref: ref, path: path)
91 case .settings(let repo):
92 RepoSettingsView(client: client, repo: repo)
93 case .grep(let repo):
94 GrepView(client: client, repo: repo)
95 case .blame(let repo, let path, let ref):
96 BlameView(client: client, repo: repo, path: path, ref: ref)
97 case .refs(let repo):
98 RefsView(client: client, repo: repo)
99 case .compare(let repo, let defaultBranch):
100 CompareView(client: client, repo: repo, defaultBranch: defaultBranch)
101 case .milestones(let repo):
102 MilestoneListView(client: client, repo: repo)
103 case .labels(let repo):
104 LabelListView(client: client, repo: repo)
105 case .bookmarks:
106 BookmarkListView(client: client)
107 case .webhooks(let repo):
108 WebhookListView(client: client, repo: repo)
109 case .webhookDeliveries(let repo):
110 WebhookDeliveriesView(client: client, repo: repo)
111 case .wiki(let repo):
112 WikiView(client: client, repo: repo)
113 case .wikiPage(let repo, let page):
114 WikiPageView(client: client, repo: repo, page: page)
115 case .commit(let repo, let sha):
116 CommitView(client: client, repo: repo, sha: sha)
117 case .profile(let name):
118 ProfileView(client: client, name: name)
119 case .account:
120 AccountView(client: client)
121 case .addAccount:
122 SignInView()
123 case .notifications:
124 NotificationsView(client: client)
125 }
126 }
127
128 @ViewBuilder
129 private func destination(_ route: MRRoute, client: GitbayClient) -> some View {
130 switch route {
131 case .list(let repo):
132 MRListView(client: client, repo: repo)
133 case .mr(let repo, let number):
134 MRView(client: client, repo: repo, number: number)
135 case .diff(let repo, let number):
136 DiffView(client: client, repo: repo, number: number)
137 case .rangeDiff(let repo, let number, let from, let to):
138 RangeDiffView(client: client, repo: repo, number: number, from: from, to: to)
139 }
140 }
141
142 @ViewBuilder
143 private func destination(_ route: IssueRoute, client: GitbayClient) -> some View {
144 switch route {
145 case .list(let repo):
146 IssueListView(client: client, repo: repo)
147 case .issue(let repo, let number):
148 IssueView(client: client, repo: repo, number: number)
149 }
150 }
151
152 @ViewBuilder
153 private func destination(_ route: OrgRoute, client: GitbayClient) -> some View {
154 switch route {
155 case .org(let name):
156 OrgView(client: client, org: name)
157 case .team(let org, let team):
158 TeamView(client: client, org: org, team: team)
159 }
160 }
161
162 @ViewBuilder
163 private func destination(_ route: ReleaseRoute, client: GitbayClient) -> some View {
164 switch route {
165 case .list(let repo):
166 ReleaseListView(client: client, repo: repo)
167 case .release(let repo, let tag):
168 ReleaseView(client: client, repo: repo, tag: tag)
169 }
170 }
171
172 @ViewBuilder
173 private func destination(_ route: BuildRoute, client: GitbayClient) -> some View {
174 switch route {
175 case .list(let repo):
176 BuildListView(client: client, repo: repo)
177 case .detail(let repo, let number):
178 BuildDetailView(client: client, repo: repo, number: number)
179 }
180 }
181}
182
183extension View {
184 func navigationDestinations(client: GitbayClient) -> some View {
185 modifier(RouteDestinations(client: client))
186 }
187}
188
189#Preview {
190 ContentView()
191 .environment(SessionStore())
192}