@@ -16,6 +16,7 @@ struct ContentView: View {
16
16
17
17
private let userDefaults = UserDefaults ( )
18
18
19
+ @State private var loading = true
19
20
@State private var currentMetricIndex : Int = 0
20
21
@State private var metricTotals : [ HKQuantityTypeIdentifier : Double ] = [ metricOptions [ 0 ] : 0.0 ]
21
22
@State private var metricCounts : [ HKQuantityTypeIdentifier : [ MetricEntry ] ] = [
@@ -24,80 +25,101 @@ struct ContentView: View {
24
25
@State private var showingSheet = false
25
26
@State private var dataAnimationPower = 0.0
26
27
28
+ @State private var killDataTimer = Timer
29
+ . publish ( every: 3600 , on: . current, in: . default)
30
+ . autoconnect ( )
31
+
27
32
@AppStorage ( STEP_GOAL_KEY) var stepGoal = 0
28
33
29
34
@ViewBuilder
30
35
var body : some View {
31
36
let metricID = metricOptions [ currentMetricIndex]
32
37
let currentMetricList = metricCounts [ metricID, default: [ ] ]
33
- if !HKHealthStore. isHealthDataAvailable ( ) {
34
- Text (
35
- NSLocalizedString (
36
- " no-health-access " ,
37
- comment: " Text for when the app does not have access to health data "
38
+ if loading {
39
+ NavigationView {
40
+ ProgressView ( )
41
+ }
42
+ . onAppear {
43
+ Task {
44
+ onAppear ( )
45
+ }
46
+ }
47
+ . navigationTitle ( " OneK Day " )
48
+ . navigationBarTitleDisplayMode ( . inline)
49
+ . toolbarBackground ( Color . accentColor, for: . navigationBar)
50
+ . toolbarBackground ( . visible, for: . navigationBar)
51
+ } else if !HKHealthStore. isHealthDataAvailable ( ) || currentMetricList. isEmpty {
52
+ NavigationView {
53
+ Text (
54
+ NSLocalizedString (
55
+ " no-health-access " ,
56
+ comment: " Text for when the app does not have access to health data "
57
+ )
38
58
)
39
- )
59
+ }
60
+ . navigationTitle ( " OneK Day " )
61
+ . navigationBarTitleDisplayMode ( . inline)
62
+ . toolbarBackground ( Color . accentColor, for: . navigationBar)
63
+ . toolbarBackground ( . visible, for: . navigationBar)
40
64
} else {
41
65
NavigationView {
42
66
VStack {
43
- if !currentMetricList. isEmpty {
44
- Chart ( currentMetricList, id: \. startDate) {
45
- BarMark (
46
- x: . value(
47
- NSLocalizedString (
48
- " time-value-label " ,
49
- comment: " The lael for the time axis of the graph "
67
+ Chart ( currentMetricList, id: \. startDate) {
68
+ BarMark (
69
+ x: . value(
70
+ NSLocalizedString (
71
+ " time-value-label " ,
72
+ comment: " The label for the time axis of the graph "
73
+ ) ,
74
+ $0. startDate,
75
+ unit: . hour,
76
+ calendar: Calendar . current
77
+ ) ,
78
+ y: . value(
79
+ getUnitSuffix (
80
+ for: preferredUnit (
81
+ for: metricID
50
82
) ,
51
- $0. startDate,
52
- unit: . hour,
53
- calendar: Calendar . current
83
+ with: $0. metric
84
+ ) ? . capitalized ( with: Locale . current) ??
85
+ NSLocalizedString (
86
+ " unknown-measurement-unit " ,
87
+ comment: " Default measurement unit if the real one is unknown "
54
88
) ,
89
+ max ( pow ( $0. metric, dataAnimationPower) , 0 )
90
+ )
91
+ )
92
+ . foregroundStyle ( getBarGraphStyle ( for: $0. metric) )
93
+ . accessibilityLabel ( formatDate ( $0. startDate) )
94
+ . accessibilityValue ( formattedValue (
95
+ $0. metric,
96
+ typeIdentifier: metricID
97
+ ) ?? " X " )
98
+ if currentMetricIndex == 0 {
99
+ RuleMark (
55
100
y: . value(
56
- getUnitSuffix (
57
- for: preferredUnit (
58
- for: metricID
59
- ) ,
60
- with: $0. metric
61
- ) ? . capitalized ( with: Locale . current) ??
62
101
NSLocalizedString (
63
- " unknown-measurement-unit " ,
64
- comment: " Default measurement unit if the real one is unknown "
102
+ " goal-a11y-label " ,
103
+ comment: " A11y label for the goal line "
65
104
) ,
66
- max ( pow ( $0. metric, dataAnimationPower) , 0 )
105
+ stepGoal
106
+ )
107
+ )
108
+ . accessibilityLabel (
109
+ NSLocalizedString (
110
+ " goal-a11y-label " ,
111
+ comment: " A11y label for the goal line "
67
112
)
68
113
)
69
- . foregroundStyle ( getBarGraphStyle ( for: $0. metric) )
70
- . accessibilityLabel ( formatDate ( $0. startDate) )
71
114
. accessibilityValue ( formattedValue (
72
- $0 . metric ,
115
+ Double ( stepGoal ) ,
73
116
typeIdentifier: metricID
74
117
) ?? " X " )
75
- if currentMetricIndex == 0 {
76
- RuleMark (
77
- y: . value(
78
- NSLocalizedString (
79
- " goal-a11y-label " ,
80
- comment: " A11y label for the goal line "
81
- ) ,
82
- stepGoal
83
- )
84
- )
85
- . accessibilityLabel (
86
- NSLocalizedString (
87
- " goal-a11y-label " ,
88
- comment: " A11y label for the goal line "
89
- )
90
- )
91
- . accessibilityValue ( formattedValue (
92
- Double ( stepGoal) ,
93
- typeIdentifier: metricID
94
- ) ?? " X " )
95
- }
96
118
}
97
- . padding ( EdgeInsets ( top: 0 , leading: 16 , bottom: 0 , trailing: 16 ) )
98
-
99
- subtitle
100
119
}
120
+ . padding ( EdgeInsets ( top: 0 , leading: 16 , bottom: 0 , trailing: 16 ) )
121
+
122
+ subtitle
101
123
}
102
124
. padding ( EdgeInsets ( top: 16 , leading: 0 , bottom: 16 , trailing: 0 ) )
103
125
. navigationTitle ( " OneK Day " )
@@ -112,7 +134,6 @@ struct ContentView: View {
112
134
}
113
135
. toolbarBackground ( Color . accentColor, for: . navigationBar)
114
136
. toolbarBackground ( . visible, for: . navigationBar)
115
- . onAppear ( perform: onAppear)
116
137
. onChange ( of: scenePhase) { newPhase in
117
138
if newPhase == . active {
118
139
loadMetrics ( for: metricOptions [ currentMetricIndex] )
@@ -121,6 +142,9 @@ struct ContentView: View {
121
142
. sheet ( isPresented: $showingSheet, onDismiss: setValuesFromDefault) {
122
143
SettingsSheet ( )
123
144
}
145
+ . onReceive ( killDataTimer) { _ in
146
+ loadMetrics ( for: metricOptions [ currentMetricIndex] )
147
+ }
124
148
}
125
149
}
126
150
}
@@ -131,8 +155,9 @@ struct ContentView: View {
131
155
let currentMetricList = metricCounts [ metricID, default: [ ] ]
132
156
Button {
133
157
currentMetricIndex = ( currentMetricIndex + 1 ) % metricOptions. count
134
- loadMetrics ( for: metricOptions [ currentMetricIndex] )
135
- animateData ( )
158
+ Task {
159
+ loadMetrics ( for: metricOptions [ currentMetricIndex] )
160
+ }
136
161
} label: {
137
162
VStack ( alignment: . center) {
138
163
let metricStringOpt = formattedValue (
@@ -160,8 +185,8 @@ struct ContentView: View {
160
185
lastHourMetricString
161
186
)
162
187
)
163
- . multilineTextAlignment ( . center)
164
- . font ( . title2)
188
+ . multilineTextAlignment ( . center)
189
+ . font ( . title2)
165
190
}
166
191
}
167
192
}
@@ -212,13 +237,13 @@ struct ContentView: View {
212
237
}
213
238
214
239
func loadMetrics( for identifier: HKQuantityTypeIdentifier ) {
240
+ loading = true
215
241
#if DEBUG
216
242
let components = Calendar . current. dateComponents ( [ . hour, . day, . month, . year] , from: Date ( timeIntervalSinceNow: 3600 ) )
217
243
var result : [ MetricEntry ] = [ ]
218
244
for i in ( 1 ... 24 ) . reversed ( ) {
219
245
let startDate = Date ( timeInterval: - 3600 * Double( i) , since: Calendar . current. date ( from: components) !)
220
246
let testComponents = Calendar . current. dateComponents ( [ . hour] , from: startDate)
221
- print ( testComponents. hour!)
222
247
var stepCount = Double . random ( in: 800 ... 1500 )
223
248
if testComponents. hour! == 7 || testComponents. hour! == 21 || testComponents. hour! == 22 {
224
249
stepCount = Double . random ( in: 200 ... 500 )
@@ -245,24 +270,38 @@ struct ContentView: View {
245
270
return acc
246
271
}
247
272
}
273
+ loading = false
248
274
animateData ( )
249
275
#else
250
276
if metricTotals [ identifier, default: 0 ] . isZero {
251
277
let components = Calendar . current. dateComponents ( [ . day, . month, . year] , from: Date ( ) )
252
278
HealthData . getHourlyMetricCount ( for: identifier) { result in
253
- metricCounts [ identifier] = result
254
- metricTotals [ identifier] = result. reduce ( 0.0 ) { acc, item in
255
- let testComponents = Calendar . current. dateComponents ( [ . day, . month, . year] , from: item. endDate)
256
- if testComponents. day! == components. day! &&
257
- testComponents. month! == components. month! &&
258
- testComponents. year! == components. year! {
259
- return acc + item. metric
279
+ if result. count > 0 {
280
+ metricCounts [ identifier] = result
281
+ metricTotals [ identifier] = result. reduce ( 0.0 ) { acc, item in
282
+ let testComponents = Calendar . current. dateComponents ( [ . day, . month, . year] , from: item. endDate)
283
+ if testComponents. day! == components. day! &&
284
+ testComponents. month! == components. month! &&
285
+ testComponents. year! == components. year! {
286
+ return acc + item. metric
287
+ } else {
288
+ return acc
289
+ }
290
+ }
291
+ loading = false
292
+ animateData ( )
293
+ } else {
294
+ currentMetricIndex = ( currentMetricIndex + 1 ) % metricOptions. count
295
+ if currentMetricIndex > 0 {
296
+ // Only load if you haven't cycled around to the start
297
+ loadMetrics ( for: metricOptions [ currentMetricIndex] )
260
298
} else {
261
- return acc
299
+ loading = false
262
300
}
263
301
}
264
- animateData ( )
265
302
}
303
+ } else {
304
+ loading = false
266
305
}
267
306
#endif
268
307
}
0 commit comments