diff options
| author | Christian Cleberg <[email protected]> | 2026-07-16 17:08:45 -0500 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-07-16 17:08:45 -0500 |
| commit | a5d1064ff798cda8a237f2a11877634cd81f7ac3 (patch) | |
| tree | 2a57a9f152a05ae61307ca8be1220c2a1ee2d708 /Hutch | |
| parent | cd8742a0b932627401467bef8b7d5c376798382e (diff) | |
| parent | 7b817a1d2aed0e8b89f36b410f2779f4a6b35407 (diff) | |
| download | hutch-a5d1064ff798cda8a237f2a11877634cd81f7ac3.tar.gz hutch-a5d1064ff798cda8a237f2a11877634cd81f7ac3.tar.bz2 hutch-a5d1064ff798cda8a237f2a11877634cd81f7ac3.zip | |
Merge pull request #20 from zerolabsco/home-status-badge
Move Home system status into a title-bar status badge
Diffstat (limited to 'Hutch')
| -rw-r--r-- | Hutch/Views/Home/HomeView.swift | 73 | ||||
| -rw-r--r-- | Hutch/Views/Home/HomeViewModel.swift | 23 |
2 files changed, 65 insertions, 31 deletions
diff --git a/Hutch/Views/Home/HomeView.swift b/Hutch/Views/Home/HomeView.swift index 3e95f0b..f0ec9ff 100644 --- a/Hutch/Views/Home/HomeView.swift +++ b/Hutch/Views/Home/HomeView.swift @@ -10,6 +10,7 @@ struct HomeView: View { @State private var isOpeningRecentItem = false @State private var selectedPinnedProject: Project? @State private var selectedPinnedUser: User? + @State private var isShowingSystemStatus = false var body: some View { Group { @@ -20,6 +21,19 @@ struct HomeView: View { } } .navigationTitle("Home") + .toolbar { + ToolbarItem(placement: .topBarTrailing) { + Button { + isShowingSystemStatus = true + } label: { + HomeSystemStatusIndicator( + snapshot: viewModel?.systemStatusSnapshot, + isLoading: viewModel?.isLoadingSystemStatus ?? false + ) + } + .accessibilityLabel("System status") + } + } .navigationDestination(isPresented: Binding( get: { selectedPinnedProject != nil }, set: { isPresented in @@ -44,6 +58,9 @@ struct HomeView: View { UserProfileView(user: selectedPinnedUser) } } + .navigationDestination(isPresented: $isShowingSystemStatus) { + SystemStatusView() + } .task { guard let currentUser = appState.currentUser else { return } await ensureViewModel(currentUser: currentUser).loadDashboard() @@ -64,7 +81,6 @@ struct HomeView: View { @ViewBuilder private func content(_ viewModel: HomeViewModel) -> some View { List { - systemStatusSection(viewModel) workSection(viewModel) recentSection buildsSection(viewModel) @@ -84,26 +100,6 @@ struct HomeView: View { } } - @ViewBuilder - private func systemStatusSection(_ viewModel: HomeViewModel) -> some View { - if viewModel.systemStatusSnapshot?.hasDisruption == true { - Section { - NavigationLink { - SystemStatusView() - } label: { - SystemStatusSummaryRow( - snapshot: viewModel.systemStatusSnapshot, - isLoading: viewModel.isLoadingSystemStatus, - errorMessage: viewModel.systemStatusErrorMessage, - isShowingStaleData: viewModel.isShowingStaleSystemStatus - ) - } - .buttonStyle(.plain) - .themedRow() - } - } - } - private func workSection(_ viewModel: HomeViewModel) -> some View { Section("Work") { NavigationLink(value: HomeRoute.work(scope: .all)) { @@ -490,6 +486,41 @@ private struct HomeSummaryRow: View { } } +private struct HomeSystemStatusIndicator: View { + let snapshot: SystemStatusSnapshot? + let isLoading: Bool + + var body: some View { + if isLoading && snapshot == nil { + ProgressView() + .controlSize(.small) + } else { + Circle() + .fill(color) + .frame(width: 22, height: 22) + .overlay { + Image(systemName: glyph) + .font(.system(size: 11, weight: .bold)) + .foregroundStyle(.white) + } + } + } + + private var color: Color { + if let snapshot { + return snapshot.hasDisruption ? .orange : .green + } + return .secondary + } + + private var glyph: String { + if let snapshot { + return snapshot.hasDisruption ? "exclamationmark" : "checkmark" + } + return "questionmark" + } +} + private struct HomeRecentRow: View { let item: RecentActivityEntry diff --git a/Hutch/Views/Home/HomeViewModel.swift b/Hutch/Views/Home/HomeViewModel.swift index 3789c11..7779bea 100644 --- a/Hutch/Views/Home/HomeViewModel.swift +++ b/Hutch/Views/Home/HomeViewModel.swift @@ -365,6 +365,19 @@ final class HomeViewModel { async let inboxUnreadTask = loadInboxUnreadSnapshot(forceRefresh: forceRefresh) async let systemStatusTask = loadSystemStatusSnapshot(forceRefresh: forceRefresh) + // Resolve system status first so the Home title-bar status badge can + // settle from cache without waiting on the slower list data below. + let systemStatusResult = await systemStatusTask + switch systemStatusResult { + case .success(let result): + systemStatusSnapshot = result.value + isShowingStaleSystemStatus = result.isStale + systemStatusErrorMessage = result.isStale ? result.refreshErrorMessage : nil + case .failure(let error): + systemStatusErrorMessage = error.userFacingMessage + } + isLoadingSystemStatus = false + let projectsResult = await projectsTask switch projectsResult { case .success(let projects): @@ -404,16 +417,6 @@ final class HomeViewModel { unreadInboxThreadCount = inboxUnreadSnapshot?.unreadCount unreadInboxThreads = inboxUnreadSnapshot?.threads ?? [] hasUnreadInboxThreads = (unreadInboxThreadCount ?? 0) > 0 - let systemStatusResult = await systemStatusTask - switch systemStatusResult { - case .success(let result): - systemStatusSnapshot = result.value - isShowingStaleSystemStatus = result.isStale - systemStatusErrorMessage = result.isStale ? result.refreshErrorMessage : nil - case .failure(let error): - systemStatusErrorMessage = error.userFacingMessage - } - isLoadingSystemStatus = false lastRefreshed = Date() persistNeedsAttentionSnapshot() persistSystemStatusWidgetSnapshot() |
