1- // periphery:ignore all
21// swiftlint:disable all
2+ // periphery:ignore all
33// This source file is part of the NeutroFeverGuard based on the Stanford Spezi Template Application project
44//
55// SPDX-FileCopyrightText: 2025 Stanford University
@@ -12,7 +12,16 @@ import HealthKit
1212import SpeziAccount
1313import SwiftUI
1414
15- // Parses the raw HealthKit data.
15+
16+ struct HKData : Identifiable , Codable {
17+ var id = UUID ( )
18+ var date : Date
19+ var sumValue : Double
20+ var avgValue : Double
21+ var minValue : Double
22+ var maxValue : Double
23+ }
24+
1625func parseSampleQueryData( results: [ HKSample ] , quantityTypeIDF: HKQuantityTypeIdentifier ) -> [ HKData ] {
1726 // Retrieve quantity value and time for each data point.
1827
@@ -79,23 +88,16 @@ func handleAuthorizationError(_ error: Error) -> String {
7988 }
8089}
8190
82- struct HKData : Identifiable {
83- var date : Date
84- var id = UUID ( )
85- var sumValue : Double
86- var avgValue : Double
87- var minValue : Double
88- var maxValue : Double
89- }
90-
9191struct HKVisualization : View {
92- // swiftlint:disable closure_body_length
92+ @ Environment ( LabResultsManager . self ) private var labResultsManager
9393 @State var bodyTemperatureData : [ HKData ] = [ ]
9494 @State var heartRateData : [ HKData ] = [ ]
9595 @State var oxygenSaturationData : [ HKData ] = [ ]
9696 @State var heartRateScatterData : [ HKData ] = [ ]
9797 @State var oxygenSaturationScatterData : [ HKData ] = [ ]
9898 @State var bodyTemperatureScatterData : [ HKData ] = [ ]
99+ @State var neutrophilData : [ HKData ] = [ ]
100+ @State var neutrophilScatterData : [ HKData ] = [ ]
99101
100102 var vizList : some View {
101103 self . readAllHKData ( )
@@ -106,7 +108,7 @@ struct HKVisualization: View {
106108 data: heartRateData,
107109 xName: " Time " ,
108110 yName: " Heart Rate (bpm) " ,
109- title: " Heart Rate Over Time " ,
111+ title: " Heart Rate " ,
110112 threshold: 100 ,
111113 scatterData: heartRateScatterData
112114 )
@@ -121,7 +123,7 @@ struct HKVisualization: View {
121123 data: bodyTemperatureData,
122124 xName: " Time " ,
123125 yName: " Body Temperature (°F) " ,
124- title: " Body Temperature Over Time " ,
126+ title: " Body Temperature " ,
125127 threshold: 99.0 ,
126128 scatterData: bodyTemperatureScatterData
127129 )
@@ -136,7 +138,7 @@ struct HKVisualization: View {
136138 data: oxygenSaturationData,
137139 xName: " Time " ,
138140 yName: " Oxygen Saturation (%) " ,
139- title: " Oxygen Saturation Over Time " ,
141+ title: " Oxygen Saturation " ,
140142 threshold: 94.0 ,
141143 scatterData: oxygenSaturationScatterData
142144 )
@@ -145,6 +147,21 @@ struct HKVisualization: View {
145147 . foregroundColor ( . gray)
146148 }
147149 }
150+ Section {
151+ if !neutrophilData. isEmpty {
152+ HKVisualizationItem (
153+ data: neutrophilData,
154+ xName: " Date " ,
155+ yName: " Neutrophil Count " ,
156+ title: " Absolute Neutrophil Count " ,
157+ threshold: 500 , // Adjust the threshold if necessary
158+ scatterData: neutrophilScatterData
159+ )
160+ } else {
161+ Text ( " No neutrophil count data available. " )
162+ . foregroundColor ( . gray)
163+ }
164+ }
148165 }
149166 }
150167
@@ -164,6 +181,8 @@ struct HKVisualization: View {
164181 . onAppear {
165182 // Ensure that data up-to-date when the view is activated.
166183 self . readAllHKData ( ensureUpdate: true )
184+ labResultsManager. loadLabResults ( )
185+ loadNeutrophilData ( ) // Ensure this is called
167186 }
168187 . toolbar {
169188 if account != nil {
@@ -173,6 +192,41 @@ struct HKVisualization: View {
173192 }
174193 }
175194
195+ private func loadNeutrophilData( ) {
196+ if FeatureFlags . mockVizData {
197+ loadMockDataNew ( )
198+ return
199+ }
200+ let rawData = labResultsManager. getAllAncValues ( ) . filter {
201+ $0. date >= Calendar . current. date ( byAdding: . day, value: - 7 , to: Date ( ) ) ?? Date ( )
202+ }
203+
204+ // Convert to HKData for bar plot
205+ neutrophilData = rawData. map { record in
206+ HKData (
207+ date: record. date,
208+ sumValue: record. ancValue,
209+ avgValue: record. ancValue,
210+ minValue: record. ancValue,
211+ maxValue: record. ancValue
212+ )
213+ }
214+
215+ // Create scatter data (with some random variation to separate points)
216+ neutrophilScatterData = rawData. map { record in
217+ HKData (
218+ date: record. date,
219+ sumValue: record. ancValue + Double. random ( in: - 0.5 ... 0.5 ) , // Add slight variation for visualization
220+ avgValue: - 1.0 ,
221+ minValue: - 1.0 ,
222+ maxValue: - 1.0
223+ )
224+ }
225+
226+ print ( " ✅ Converted neutrophil data: \( neutrophilData) " )
227+ print ( " ✅ Scatter neutrophil data: \( neutrophilScatterData) " )
228+ }
229+
176230 func readAllHKData( ensureUpdate: Bool = false ) {
177231 if FeatureFlags . mockVizData {
178232 loadMockDataNew ( )
@@ -331,7 +385,8 @@ struct HKVisualization: View {
331385 self . heartRateData = minMaxAvgStatData
332386 self . bodyTemperatureData = minMaxAvgStatData
333387 self . oxygenSaturationData = minMaxAvgStatData
334-
388+ self . neutrophilData = [ HKData ( date: today, sumValue: 0 , avgValue: 500 , minValue: 1 , maxValue: 1000 ) ]
389+
335390 // ✅ Heart Rate Scatter Data (60-100 bpm normal range)
336391 self . heartRateScatterData = [
337392 HKData ( date: today, sumValue: 75 , avgValue: 75 , minValue: 75 , maxValue: 75 ) ,
@@ -352,8 +407,24 @@ struct HKVisualization: View {
352407 HKData ( date: yesterday, sumValue: 97 , avgValue: 97 , minValue: 97 , maxValue: 97 ) ,
353408 HKData ( date: twoDaysAgo, sumValue: 96 , avgValue: 96 , minValue: 96 , maxValue: 96 )
354409 ]
410+
411+ let mockNeutrophilData = [
412+ ( date: today, wbc: 1000 , neutrophils: 50 ) ,
413+ ( date: yesterday, wbc: 1000 , neutrophils: 5 ) ,
414+ ( date: twoDaysAgo, wbc: 1200 , neutrophils: 20 )
415+ ]
416+
417+ self . neutrophilScatterData = mockNeutrophilData. map { record in
418+ let ancValue = ( Double ( record. neutrophils) / 100.0 ) * Double( record. wbc)
419+ return HKData (
420+ date: record. date,
421+ sumValue: ancValue,
422+ avgValue: ancValue,
423+ minValue: ancValue,
424+ maxValue: ancValue
425+ )
426+ }
355427 }
356- // swiftlint:enable closure_body_length
357428}
358429
359430func parseStat( statistics: HKStatistics , quantityTypeIDF: HKQuantityTypeIdentifier ) -> HKData ? {
@@ -392,7 +463,3 @@ func parseValue(quantity: HKQuantity, quantityTypeIDF: HKQuantityTypeIdentifier)
392463 return - 1.0
393464 }
394465}
395-
396- #Preview {
397-
398- }
0 commit comments