Showing 6 changed files with 23 additions and 3 deletions
+3 -0
HealthProbe/ViewModels/DashboardViewModel.swift
@@ -24,6 +24,7 @@ final class DashboardViewModel {
24 24
     var ambiguousDisappearedMetrics: [AmbiguousDisappearedMetric] = []
25 25
     var latestArchiveObservation: CachedArchiveObservationRow?
26 26
     var archiveObservationRows: [CachedArchiveObservationRow] = []
27
+    var isLoadingArchiveStatus = false
27 28
     var archiveHealthStatus: CachedArchiveHealthStatus?
28 29
     var archiveCacheError: String?
29 30
 
@@ -321,6 +322,8 @@ final class DashboardViewModel {
321 322
 
322 323
     @MainActor
323 324
     func loadArchiveCacheStatus() async {
325
+        isLoadingArchiveStatus = true
326
+        defer { isLoadingArchiveStatus = false }
324 327
         do {
325 328
             archiveObservationRows = try await SQLiteHealthArchiveStore.shared.observationRows(limit: 2)
326 329
             latestArchiveObservation = archiveObservationRows.first
+3 -0
HealthProbe/ViewModels/DataTypesViewModel.swift
@@ -10,6 +10,7 @@ final class DataTypesViewModel {
10 10
     var filter: DiffFilter = .all
11 11
     var comparisonMode: ComparisonMode = .previous
12 12
     var observationRows: [CachedArchiveObservationRow] = []
13
+    var hasLoadedObservationRows = false
13 14
     var observationRowsError: String?
14 15
     var archiveDiffs: [TypeDiff]?
15 16
     var archiveDiffError: String?
@@ -43,9 +44,11 @@ final class DataTypesViewModel {
43 44
     func loadArchiveRows(limit: Int = 200) async {
44 45
         do {
45 46
             observationRows = try await SQLiteHealthArchiveStore.shared.observationRows(limit: limit)
47
+            hasLoadedObservationRows = true
46 48
             observationRowsError = nil
47 49
         } catch {
48 50
             observationRows = []
51
+            hasLoadedObservationRows = true
49 52
             observationRowsError = error.localizedDescription
50 53
         }
51 54
     }
+3 -0
HealthProbe/ViewModels/SnapshotsViewModel.swift
@@ -26,6 +26,7 @@ final class SnapshotsViewModel {
26 26
     var comparisonMode: ComparisonMode = .previous
27 27
     var selectedBaselineObservationID: Int64?
28 28
     var archiveRows: [CachedArchiveObservationRow]?
29
+    var hasLoadedArchiveRows = false
29 30
     var archiveRowsError: String?
30 31
 
31 32
     @MainActor
@@ -33,9 +34,11 @@ final class SnapshotsViewModel {
33 34
         do {
34 35
             let rows = try await SQLiteHealthArchiveStore.shared.observationRows(limit: limit)
35 36
             archiveRows = rows.isEmpty ? nil : rows
37
+            hasLoadedArchiveRows = true
36 38
             archiveRowsError = nil
37 39
         } catch {
38 40
             archiveRows = nil
41
+            hasLoadedArchiveRows = true
39 42
             archiveRowsError = error.localizedDescription
40 43
         }
41 44
     }
+4 -1
HealthProbe/Views/Dashboard/DashboardView.swift
@@ -1158,6 +1158,9 @@ struct DashboardView: View {
1158 1158
                     Text("\(latestArchiveObservation.trackedTypeCount)")
1159 1159
                         .foregroundStyle(.secondary)
1160 1160
                 }
1161
+            } else if viewModel.isLoadingArchiveStatus {
1162
+                Label("Loading archive observations", systemImage: "clock.arrow.circlepath")
1163
+                    .foregroundStyle(.secondary)
1161 1164
             } else {
1162 1165
                 Label("No archive observations yet", systemImage: "camera.viewfinder")
1163 1166
                     .foregroundStyle(.secondary)
@@ -1199,7 +1202,7 @@ struct DashboardView: View {
1199 1202
                     Text("\(archiveHealthStatus.cacheSchemaVersion)")
1200 1203
                         .foregroundStyle(.secondary)
1201 1204
                 }
1202
-            } else {
1205
+            } else if !viewModel.isLoadingArchiveStatus {
1203 1206
                 Label("Archive cache not built", systemImage: "externaldrive.badge.questionmark")
1204 1207
                     .font(.caption)
1205 1208
                     .foregroundStyle(.secondary)
+5 -1
HealthProbe/Views/DataTypes/DataTypesView.swift
@@ -28,7 +28,11 @@ struct DataTypesView: View {
28 28
     var body: some View {
29 29
         NavigationStack {
30 30
             Group {
31
-                if displayedSnapshotContexts.count < 2 {
31
+                if !viewModel.hasLoadedObservationRows {
32
+                    ContentUnavailableView {
33
+                        Label("Loading data types", systemImage: "waveform.path.ecg")
34
+                    }
35
+                } else if displayedSnapshotContexts.count < 2 {
32 36
                     EmptyStateView(
33 37
                         icon: "waveform.path.ecg",
34 38
                         title: "Not Enough Data",
+5 -1
HealthProbe/Views/Snapshots/SnapshotsView.swift
@@ -25,7 +25,11 @@ struct SnapshotsView: View {
25 25
     var body: some View {
26 26
         NavigationStack {
27 27
             Group {
28
-                if !hasTimelineRows {
28
+                if !viewModel.hasLoadedArchiveRows {
29
+                    ContentUnavailableView {
30
+                        Label("Loading snapshots", systemImage: "clock.arrow.circlepath")
31
+                    }
32
+                } else if !hasTimelineRows {
29 33
                     EmptyStateView(
30 34
                         icon: "clock.arrow.circlepath",
31 35
                         title: "No Snapshots",