Add view of most samples
This commit is contained in:
parent
778e83682a
commit
03469446e1
@ -36,8 +36,26 @@
|
||||
E2A38EA32B9A024500BAD02E /* Workout+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A38EA22B9A024500BAD02E /* Workout+Extensions.swift */; };
|
||||
E2A38EA52B9C6EA900BAD02E /* SearchHealthStoreView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2A38EA42B9C6EA900BAD02E /* SearchHealthStoreView.swift */; };
|
||||
E2A38EA82B9C6EE800BAD02E /* SFSafeSymbols in Frameworks */ = {isa = PBXBuildFile; productRef = E2A38EA72B9C6EE800BAD02E /* SFSafeSymbols */; };
|
||||
E2D82B2A2BCD25B60075EAF0 /* QuantitySampleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B292BCD25B60075EAF0 /* QuantitySampleList.swift */; };
|
||||
E2D82B2C2BCD28720075EAF0 /* QuantitySampleRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B2B2BCD28720075EAF0 /* QuantitySampleRow.swift */; };
|
||||
E2D82B2E2BCD319D0075EAF0 /* BodyMeasurementsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B2D2BCD319D0075EAF0 /* BodyMeasurementsList.swift */; };
|
||||
E2D82B302BCD32F20075EAF0 /* CycleTrackingList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B2F2BCD32F20075EAF0 /* CycleTrackingList.swift */; };
|
||||
E2D82B322BCD34B80075EAF0 /* CategoryEnumSampleRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B312BCD34B80075EAF0 /* CategoryEnumSampleRow.swift */; };
|
||||
E2D82B342BCD34EB0075EAF0 /* CategoryEmptySampleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B332BCD34EB0075EAF0 /* CategoryEmptySampleList.swift */; };
|
||||
E2D82B362BCD35DD0075EAF0 /* CategoryEnumSampleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B352BCD35DD0075EAF0 /* CategoryEnumSampleList.swift */; };
|
||||
E2D82B3B2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B3A2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift */; };
|
||||
E2D82B3D2BCD3C3F0075EAF0 /* HearingSamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B3C2BCD3C3F0075EAF0 /* HearingSamplesList.swift */; };
|
||||
E2D82B3F2BCD47E80075EAF0 /* HeartSamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B3E2BCD47E80075EAF0 /* HeartSamplesList.swift */; };
|
||||
E2D82B432BCD53D10075EAF0 /* GenericSampleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B422BCD53D10075EAF0 /* GenericSampleList.swift */; };
|
||||
E2D82B452BCD582D0075EAF0 /* MentalHealthList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B442BCD582D0075EAF0 /* MentalHealthList.swift */; };
|
||||
E2D82B472BCD59380075EAF0 /* MobilitySamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B462BCD59380075EAF0 /* MobilitySamplesList.swift */; };
|
||||
E2D82B492BCD5BA00075EAF0 /* NutritionSamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B482BCD5BA00075EAF0 /* NutritionSamplesList.swift */; };
|
||||
E2D82B4B2BCD5E520075EAF0 /* RespiratorySamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B4A2BCD5E520075EAF0 /* RespiratorySamplesList.swift */; };
|
||||
E2D82B4D2BCD5F780075EAF0 /* SymptomsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B4C2BCD5F780075EAF0 /* SymptomsList.swift */; };
|
||||
E2D82B4F2BCD61590075EAF0 /* VitalsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B4E2BCD61590075EAF0 /* VitalsList.swift */; };
|
||||
E2D82B512BCD626D0075EAF0 /* OtherSamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2D82B502BCD626D0075EAF0 /* OtherSamplesList.swift */; };
|
||||
E2E552892BA2194400BF5E9B /* DatabasesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552882BA2194400BF5E9B /* DatabasesTab.swift */; };
|
||||
E2E5528C2BA21C0700BF5E9B /* HealthDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E5528B2BA21C0700BF5E9B /* HealthDatabase.swift */; };
|
||||
E2E5528C2BA21C0700BF5E9B /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E5528B2BA21C0700BF5E9B /* Database.swift */; };
|
||||
E2E5528E2BA21C5900BF5E9B /* FileManager+Directory.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E5528D2BA21C5900BF5E9B /* FileManager+Directory.swift */; };
|
||||
E2E552902BA236A000BF5E9B /* DatabaseList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E5528F2BA236A000BF5E9B /* DatabaseList.swift */; };
|
||||
E2E552922BA236D000BF5E9B /* DatabaseFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552912BA236D000BF5E9B /* DatabaseFile.swift */; };
|
||||
@ -55,7 +73,7 @@
|
||||
E2E552B72BA9A69400BF5E9B /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552B62BA9A69400BF5E9B /* Color+Extensions.swift */; };
|
||||
E2E552B92BA9A77D00BF5E9B /* HKWorkoutActivityType+Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552B82BA9A77D00BF5E9B /* HKWorkoutActivityType+Icon.swift */; };
|
||||
E2E552BB2BA9CAAE00BF5E9B /* SamplesTab.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552BA2BA9CAAE00BF5E9B /* SamplesTab.swift */; };
|
||||
E2E552C02BAB38DC00BF5E9B /* ActivitySampleList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552BF2BAB38DC00BF5E9B /* ActivitySampleList.swift */; };
|
||||
E2E552C02BAB38DC00BF5E9B /* ActivitySamplesList.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2E552BF2BAB38DC00BF5E9B /* ActivitySamplesList.swift */; };
|
||||
E2FDFF202B6BE34C0080A7B3 /* SwiftProtobuf in Frameworks */ = {isa = PBXBuildFile; productRef = E2FDFF1F2B6BE34C0080A7B3 /* SwiftProtobuf */; };
|
||||
E2FDFF292B6D10D60080A7B3 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = E2FDFF282B6D10D60080A7B3 /* String+Extensions.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -85,8 +103,27 @@
|
||||
E27BC6972B5FD76F003A8873 /* Data+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Extensions.swift"; sourceTree = "<group>"; };
|
||||
E2A38EA22B9A024500BAD02E /* Workout+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Workout+Extensions.swift"; sourceTree = "<group>"; };
|
||||
E2A38EA42B9C6EA900BAD02E /* SearchHealthStoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHealthStoreView.swift; sourceTree = "<group>"; };
|
||||
E2D82B292BCD25B60075EAF0 /* QuantitySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantitySampleList.swift; sourceTree = "<group>"; };
|
||||
E2D82B2B2BCD28720075EAF0 /* QuantitySampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantitySampleRow.swift; sourceTree = "<group>"; };
|
||||
E2D82B2D2BCD319D0075EAF0 /* BodyMeasurementsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BodyMeasurementsList.swift; sourceTree = "<group>"; };
|
||||
E2D82B2F2BCD32F20075EAF0 /* CycleTrackingList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CycleTrackingList.swift; sourceTree = "<group>"; };
|
||||
E2D82B312BCD34B80075EAF0 /* CategoryEnumSampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEnumSampleRow.swift; sourceTree = "<group>"; };
|
||||
E2D82B332BCD34EB0075EAF0 /* CategoryEmptySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEmptySampleList.swift; sourceTree = "<group>"; };
|
||||
E2D82B352BCD35DD0075EAF0 /* CategoryEnumSampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEnumSampleList.swift; sourceTree = "<group>"; };
|
||||
E2D82B372BCD36A90075EAF0 /* healthdb_secure.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = healthdb_secure.sqlite; sourceTree = "<group>"; };
|
||||
E2D82B3A2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEmptySampleRow.swift; sourceTree = "<group>"; };
|
||||
E2D82B3C2BCD3C3F0075EAF0 /* HearingSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HearingSamplesList.swift; sourceTree = "<group>"; };
|
||||
E2D82B3E2BCD47E80075EAF0 /* HeartSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartSamplesList.swift; sourceTree = "<group>"; };
|
||||
E2D82B422BCD53D10075EAF0 /* GenericSampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericSampleList.swift; sourceTree = "<group>"; };
|
||||
E2D82B442BCD582D0075EAF0 /* MentalHealthList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentalHealthList.swift; sourceTree = "<group>"; };
|
||||
E2D82B462BCD59380075EAF0 /* MobilitySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobilitySamplesList.swift; sourceTree = "<group>"; };
|
||||
E2D82B482BCD5BA00075EAF0 /* NutritionSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NutritionSamplesList.swift; sourceTree = "<group>"; };
|
||||
E2D82B4A2BCD5E520075EAF0 /* RespiratorySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RespiratorySamplesList.swift; sourceTree = "<group>"; };
|
||||
E2D82B4C2BCD5F780075EAF0 /* SymptomsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymptomsList.swift; sourceTree = "<group>"; };
|
||||
E2D82B4E2BCD61590075EAF0 /* VitalsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VitalsList.swift; sourceTree = "<group>"; };
|
||||
E2D82B502BCD626D0075EAF0 /* OtherSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherSamplesList.swift; sourceTree = "<group>"; };
|
||||
E2E552882BA2194400BF5E9B /* DatabasesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabasesTab.swift; sourceTree = "<group>"; };
|
||||
E2E5528B2BA21C0700BF5E9B /* HealthDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthDatabase.swift; sourceTree = "<group>"; };
|
||||
E2E5528B2BA21C0700BF5E9B /* Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
||||
E2E5528D2BA21C5900BF5E9B /* FileManager+Directory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Directory.swift"; sourceTree = "<group>"; };
|
||||
E2E5528F2BA236A000BF5E9B /* DatabaseList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseList.swift; sourceTree = "<group>"; };
|
||||
E2E552912BA236D000BF5E9B /* DatabaseFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseFile.swift; sourceTree = "<group>"; };
|
||||
@ -104,7 +141,7 @@
|
||||
E2E552B62BA9A69400BF5E9B /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = "<group>"; };
|
||||
E2E552B82BA9A77D00BF5E9B /* HKWorkoutActivityType+Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HKWorkoutActivityType+Icon.swift"; sourceTree = "<group>"; };
|
||||
E2E552BA2BA9CAAE00BF5E9B /* SamplesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SamplesTab.swift; sourceTree = "<group>"; };
|
||||
E2E552BF2BAB38DC00BF5E9B /* ActivitySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySampleList.swift; sourceTree = "<group>"; };
|
||||
E2E552BF2BAB38DC00BF5E9B /* ActivitySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySamplesList.swift; sourceTree = "<group>"; };
|
||||
E2FDFF282B6D10D60080A7B3 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
|
||||
E2FDFF342B6E59030080A7B3 /* HealthImport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HealthImport.entitlements; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@ -166,6 +203,7 @@
|
||||
885002602B5C273E00E7D4DB /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2D82B372BCD36A90075EAF0 /* healthdb_secure.sqlite */,
|
||||
885002612B5C273E00E7D4DB /* Preview Assets.xcassets */,
|
||||
E27BC6832B5E76A4003A8873 /* Location+Mock.swift */,
|
||||
E27BC6912B5FD488003A8873 /* HealthDatabase+Mock.swift */,
|
||||
@ -198,6 +236,25 @@
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E2D82B392BCD37FA0075EAF0 /* Lists */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2E552BF2BAB38DC00BF5E9B /* ActivitySamplesList.swift */,
|
||||
E2D82B2D2BCD319D0075EAF0 /* BodyMeasurementsList.swift */,
|
||||
E2D82B2F2BCD32F20075EAF0 /* CycleTrackingList.swift */,
|
||||
E2D82B3C2BCD3C3F0075EAF0 /* HearingSamplesList.swift */,
|
||||
E2D82B3E2BCD47E80075EAF0 /* HeartSamplesList.swift */,
|
||||
E2D82B442BCD582D0075EAF0 /* MentalHealthList.swift */,
|
||||
E2D82B462BCD59380075EAF0 /* MobilitySamplesList.swift */,
|
||||
E2D82B482BCD5BA00075EAF0 /* NutritionSamplesList.swift */,
|
||||
E2D82B4A2BCD5E520075EAF0 /* RespiratorySamplesList.swift */,
|
||||
E2D82B4C2BCD5F780075EAF0 /* SymptomsList.swift */,
|
||||
E2D82B4E2BCD61590075EAF0 /* VitalsList.swift */,
|
||||
E2D82B502BCD626D0075EAF0 /* OtherSamplesList.swift */,
|
||||
);
|
||||
path = Lists;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
E2E552872BA2193B00BF5E9B /* Tabs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -211,7 +268,7 @@
|
||||
E2E5528A2BA21BFB00BF5E9B /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2E5528B2BA21C0700BF5E9B /* HealthDatabase.swift */,
|
||||
E2E5528B2BA21C0700BF5E9B /* Database.swift */,
|
||||
E2E5528F2BA236A000BF5E9B /* DatabaseList.swift */,
|
||||
E2E552912BA236D000BF5E9B /* DatabaseFile.swift */,
|
||||
);
|
||||
@ -247,7 +304,14 @@
|
||||
E2E552BE2BAB38AC00BF5E9B /* Samples */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
E2E552BF2BAB38DC00BF5E9B /* ActivitySampleList.swift */,
|
||||
E2D82B392BCD37FA0075EAF0 /* Lists */,
|
||||
E2D82B332BCD34EB0075EAF0 /* CategoryEmptySampleList.swift */,
|
||||
E2D82B352BCD35DD0075EAF0 /* CategoryEnumSampleList.swift */,
|
||||
E2D82B312BCD34B80075EAF0 /* CategoryEnumSampleRow.swift */,
|
||||
E2D82B3A2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift */,
|
||||
E2D82B292BCD25B60075EAF0 /* QuantitySampleList.swift */,
|
||||
E2D82B422BCD53D10075EAF0 /* GenericSampleList.swift */,
|
||||
E2D82B2B2BCD28720075EAF0 /* QuantitySampleRow.swift */,
|
||||
);
|
||||
path = Samples;
|
||||
sourceTree = "<group>";
|
||||
@ -342,42 +406,60 @@
|
||||
files = (
|
||||
E2A38EA32B9A024500BAD02E /* Workout+Extensions.swift in Sources */,
|
||||
E2E552922BA236D000BF5E9B /* DatabaseFile.swift in Sources */,
|
||||
E2D82B472BCD59380075EAF0 /* MobilitySamplesList.swift in Sources */,
|
||||
E27BC6982B5FD76F003A8873 /* Data+Extensions.swift in Sources */,
|
||||
8850025D2B5C273C00E7D4DB /* WorkoutTab.swift in Sources */,
|
||||
8850029B2B5D16E200E7D4DB /* TimeInterval+Extensions.swift in Sources */,
|
||||
885002792B5C320400E7D4DB /* Optional+Extensions.swift in Sources */,
|
||||
E2D82B3F2BCD47E80075EAF0 /* HeartSamplesList.swift in Sources */,
|
||||
E2D82B432BCD53D10075EAF0 /* GenericSampleList.swift in Sources */,
|
||||
E27BC6822B5E762D003A8873 /* LocationSampleDetailView.swift in Sources */,
|
||||
E2D82B2C2BCD28720075EAF0 /* QuantitySampleRow.swift in Sources */,
|
||||
E2D82B362BCD35DD0075EAF0 /* CategoryEnumSampleList.swift in Sources */,
|
||||
E201EC752B626B19005B83D3 /* Metadata+Mock.swift in Sources */,
|
||||
E2E552B92BA9A77D00BF5E9B /* HKWorkoutActivityType+Icon.swift in Sources */,
|
||||
8850028F2B5D0EAF00E7D4DB /* Date+Extensions.swift in Sources */,
|
||||
E2E552B72BA9A69400BF5E9B /* Color+Extensions.swift in Sources */,
|
||||
E27BC6922B5FD488003A8873 /* HealthDatabase+Mock.swift in Sources */,
|
||||
E27BC6842B5E76A4003A8873 /* Location+Mock.swift in Sources */,
|
||||
E2D82B302BCD32F20075EAF0 /* CycleTrackingList.swift in Sources */,
|
||||
885002932B5D129300E7D4DB /* ActivityDetailView.swift in Sources */,
|
||||
E2D82B4D2BCD5F780075EAF0 /* SymptomsList.swift in Sources */,
|
||||
E2E552A32BA4B58F00BF5E9B /* HeartRateGraph.swift in Sources */,
|
||||
E2E552AF2BA98BCF00BF5E9B /* WorkoutMapView.swift in Sources */,
|
||||
E2D82B342BCD34EB0075EAF0 /* CategoryEmptySampleList.swift in Sources */,
|
||||
E2E552BB2BA9CAAE00BF5E9B /* SamplesTab.swift in Sources */,
|
||||
E2E552C02BAB38DC00BF5E9B /* ActivitySampleList.swift in Sources */,
|
||||
E2D82B3B2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift in Sources */,
|
||||
E2E552C02BAB38DC00BF5E9B /* ActivitySamplesList.swift in Sources */,
|
||||
E2D82B322BCD34B80075EAF0 /* CategoryEnumSampleRow.swift in Sources */,
|
||||
E2D82B492BCD5BA00075EAF0 /* NutritionSamplesList.swift in Sources */,
|
||||
E27BC6962B5FD61D003A8873 /* WorkoutEvent+Mock.swift in Sources */,
|
||||
E2E5529B2BA3935600BF5E9B /* HKWorkout+Extensions.swift in Sources */,
|
||||
E27BC6802B5E74D7003A8873 /* LocationSampleListView.swift in Sources */,
|
||||
8850028D2B5D0B5000E7D4DB /* WorkoutDetailView.swift in Sources */,
|
||||
E2D82B2A2BCD25B60075EAF0 /* QuantitySampleList.swift in Sources */,
|
||||
E2E552A72BA7531C00BF5E9B /* Event+Identifiable.swift in Sources */,
|
||||
E2D82B512BCD626D0075EAF0 /* OtherSamplesList.swift in Sources */,
|
||||
885002952B5D147100E7D4DB /* DetailRow.swift in Sources */,
|
||||
E2D82B4F2BCD61590075EAF0 /* VitalsList.swift in Sources */,
|
||||
E2E552A12BA4B14600BF5E9B /* HeartRateSample.swift in Sources */,
|
||||
E2FDFF292B6D10D60080A7B3 /* String+Extensions.swift in Sources */,
|
||||
E2D82B2E2BCD319D0075EAF0 /* BodyMeasurementsList.swift in Sources */,
|
||||
E201EC732B626A30005B83D3 /* WorkoutActivity+Mock.swift in Sources */,
|
||||
E2E552892BA2194400BF5E9B /* DatabasesTab.swift in Sources */,
|
||||
E2D82B452BCD582D0075EAF0 /* MentalHealthList.swift in Sources */,
|
||||
E2E552902BA236A000BF5E9B /* DatabaseList.swift in Sources */,
|
||||
E2E552B12BA98BE000BF5E9B /* MKMapRect+Extensions.swift in Sources */,
|
||||
8850029D2B5D197300E7D4DB /* EventDetailView.swift in Sources */,
|
||||
E2E5528C2BA21C0700BF5E9B /* HealthDatabase.swift in Sources */,
|
||||
E2E5528C2BA21C0700BF5E9B /* Database.swift in Sources */,
|
||||
E2D82B3D2BCD3C3F0075EAF0 /* HearingSamplesList.swift in Sources */,
|
||||
E2E5528E2BA21C5900BF5E9B /* FileManager+Directory.swift in Sources */,
|
||||
E2A38EA52B9C6EA900BAD02E /* SearchHealthStoreView.swift in Sources */,
|
||||
E2E552B32BA9A1D600BF5E9B /* WorkoutTypeSelection.swift in Sources */,
|
||||
E27BC67E2B5E6CE3003A8873 /* Sequence+Extensions.swift in Sources */,
|
||||
E2E552AB2BA859A700BF5E9B /* MetadataKey+String.swift in Sources */,
|
||||
E2E552B52BA9A5D200BF5E9B /* WorkoutListRow.swift in Sources */,
|
||||
E2D82B4B2BCD5E520075EAF0 /* RespiratorySamplesList.swift in Sources */,
|
||||
E27BC6942B5FD587003A8873 /* Workout+Mock.swift in Sources */,
|
||||
E2E552AD2BA98B9B00BF5E9B /* RouteView.swift in Sources */,
|
||||
8850025B2B5C273C00E7D4DB /* HealthImportApp.swift in Sources */,
|
||||
|
@ -32,7 +32,6 @@ struct HealthImportApp: App {
|
||||
DispatchQueue.main.async {
|
||||
// Go back to main queue so that list will be updated
|
||||
guard let databaseToLoad = databaseList.databases.first(where: { $0.isDefault }) else {
|
||||
print("No default database to load")
|
||||
return
|
||||
}
|
||||
Task {
|
||||
@ -41,7 +40,6 @@ struct HealthImportApp: App {
|
||||
return
|
||||
}
|
||||
DispatchQueue.main.async {
|
||||
print("Setting selection to workouts")
|
||||
self.selection = .workouts
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,32 @@ import SQLite
|
||||
import HealthKit
|
||||
import HealthDB
|
||||
|
||||
extension Database {
|
||||
extension HealthDatabase {
|
||||
|
||||
private static let databaseFileUrl = Bundle.main.url(forResource: "healthdb_secure", withExtension: "sqlite")
|
||||
|
||||
static var mock: Database {
|
||||
let bundleUrl = Database.databaseFileUrl!
|
||||
static var mock: HealthDatabase {
|
||||
let bundleUrl = databaseFileUrl!
|
||||
let local = FileManager.default.documentDirectory.appendingPathComponent("db.sqlite")
|
||||
if !FileManager.default.fileExists(atPath: local.path) {
|
||||
try! FileManager.default.copyItem(at: bundleUrl, to: local)
|
||||
}
|
||||
let store = try! HealthDatabase(fileUrl: local)
|
||||
return .init(store: store)
|
||||
return try! HealthDatabase(fileUrl: local)
|
||||
}
|
||||
|
||||
static var empty: HealthDatabase {
|
||||
let store = try! HKDatabaseStore(database: Connection(.inMemory))
|
||||
try! store.createTables()
|
||||
return .init(wrapping: store)
|
||||
}
|
||||
}
|
||||
|
||||
extension Database {
|
||||
|
||||
// static var mock: Database {
|
||||
// return .init(store: .mock)
|
||||
// }
|
||||
|
||||
static var empty: Database {
|
||||
|
||||
do {
|
||||
|
@ -10,9 +10,9 @@ extension HKWorkoutEvent {
|
||||
duration: 1114.56374406815),
|
||||
metadata: [
|
||||
"_HKPrivateMetadataTotalDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1000),
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": NSNumber(1),
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": NSNumber(value: UInt64(1)),
|
||||
"_HKPrivateMetadataSplitDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1000),
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": NSNumber(1),
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": NSNumber(value: UInt64(1)),
|
||||
"_HKPrivateMetadataIsPartialSplit": NSNumber(0),
|
||||
"_HKPrivateMetadataSplitActiveDurationQuantity": HKQuantity(unit: .second(), doubleValue: 1114.56)
|
||||
]),
|
||||
@ -22,10 +22,10 @@ extension HKWorkoutEvent {
|
||||
metadata: [
|
||||
"_HKPrivateMetadataSplitDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1609.34),
|
||||
"_HKPrivateMetadataSplitActiveDurationQuantity": HKQuantity(unit: .second(), doubleValue: 1972.17),
|
||||
"_HKPrivateMetadataIsPartialSplit": 0,
|
||||
"_HKPrivateMetadataIsPartialSplit": NSNumber(value: UInt64(0)),
|
||||
"_HKPrivateMetadataTotalDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1609.34),
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": 1,
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": 2
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": NSNumber(value: UInt64(1)),
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": NSNumber(value: UInt64(2))
|
||||
]),
|
||||
.init(type: .init(rawValue: 1)!,
|
||||
dateInterval: .init(start: Date(timeIntervalSinceReferenceDate: 702112942.707113),
|
||||
@ -33,10 +33,10 @@ extension HKWorkoutEvent {
|
||||
metadata: [
|
||||
"_HKPrivateMetadataSplitDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1609.34),
|
||||
"_HKPrivateMetadataSplitActiveDurationQuantity": HKQuantity(unit: .second(), doubleValue: 1972.17),
|
||||
"_HKPrivateMetadataIsPartialSplit": 0,
|
||||
"_HKPrivateMetadataIsPartialSplit": NSNumber(value: UInt64(0)),
|
||||
"_HKPrivateMetadataTotalDistanceQuantity": HKQuantity(unit: .meter(), doubleValue: 1609.34),
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": 1,
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": 2
|
||||
"_HKPrivateWorkoutSegmentEventSubtype": NSNumber(value: UInt64(1)),
|
||||
"_HKPrivateMetadataSplitMeasuringSystem": NSNumber(value: UInt64(2)),
|
||||
]),
|
||||
.init(type: .init(rawValue: 2)!,
|
||||
dateInterval: .init(start: Date(timeIntervalSinceReferenceDate: 702113161.221132),
|
||||
|
@ -1,15 +0,0 @@
|
||||
import SwiftUI
|
||||
|
||||
struct ActivitySampleList: View {
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
|
||||
}
|
||||
.navigationTitle("Activity")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ActivitySampleList()
|
||||
}
|
27
HealthImport/Samples/CategoryEmptySampleList.swift
Normal file
27
HealthImport/Samples/CategoryEmptySampleList.swift
Normal file
@ -0,0 +1,27 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
import HealthKitExtensions
|
||||
|
||||
struct CategoryEmptySampleList<T>: View where T: HKCategoryEmptySample {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
@State
|
||||
private var samples: [T] = []
|
||||
|
||||
var body: some View {
|
||||
GenericSampleList(sampleView: { sample in
|
||||
Text(sample.endDate.formatted())
|
||||
}, search: { start, end, _ -> [T] in
|
||||
try database.samples(from: start, to: end)
|
||||
})
|
||||
.navigationTitle(T.categoryTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
CategoryEmptySampleList<MindfulSession>(database: .empty)
|
||||
}
|
||||
}
|
27
HealthImport/Samples/CategoryEmptySampleRow.swift
Normal file
27
HealthImport/Samples/CategoryEmptySampleRow.swift
Normal file
@ -0,0 +1,27 @@
|
||||
import SwiftUI
|
||||
import HealthKitExtensions
|
||||
import HealthDB
|
||||
|
||||
struct CategoryEmptySampleRow<T>: View where T: HKCategoryEmptySample {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
let title: String?
|
||||
|
||||
init(database: HealthDatabase, title: String? = nil) {
|
||||
self.database = database
|
||||
self.title = title
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationLink {
|
||||
CategoryEmptySampleList<T>(database: database)
|
||||
} label: {
|
||||
Text(title ?? T.categoryTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
CategoryEmptySampleRow<MindfulSession>(database: .empty)
|
||||
}
|
31
HealthImport/Samples/CategoryEnumSampleList.swift
Normal file
31
HealthImport/Samples/CategoryEnumSampleList.swift
Normal file
@ -0,0 +1,31 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
import HealthKitExtensions
|
||||
|
||||
struct CategoryEnumSampleList<T>: View where T: HKCategoryEnumSample {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
@State
|
||||
private var samples: [T] = []
|
||||
|
||||
var body: some View {
|
||||
GenericSampleList(sampleView: { sample in
|
||||
HStack {
|
||||
Text("\(sample.value)")
|
||||
Spacer()
|
||||
Text(sample.endDate.formatted())
|
||||
}
|
||||
}, search: { start, end, _ -> [T] in
|
||||
try database.samples(from: start, to: end)
|
||||
})
|
||||
.navigationTitle(T.categoryTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
CategoryEnumSampleList<AbdominalCramps>(database: .empty)
|
||||
}
|
||||
}
|
27
HealthImport/Samples/CategoryEnumSampleRow.swift
Normal file
27
HealthImport/Samples/CategoryEnumSampleRow.swift
Normal file
@ -0,0 +1,27 @@
|
||||
import SwiftUI
|
||||
import HealthKitExtensions
|
||||
import HealthDB
|
||||
|
||||
struct CategoryEnumSampleRow<T>: View where T: HKCategoryEnumSample {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
let title: String?
|
||||
|
||||
init(database: HealthDatabase, title: String? = nil) {
|
||||
self.database = database
|
||||
self.title = title
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationLink {
|
||||
CategoryEnumSampleList<T>(database: database)
|
||||
} label: {
|
||||
Text(title ?? T.categoryTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
CategoryEnumSampleRow<AbdominalCramps>(database: .empty)
|
||||
}
|
82
HealthImport/Samples/GenericSampleList.swift
Normal file
82
HealthImport/Samples/GenericSampleList.swift
Normal file
@ -0,0 +1,82 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
import HealthKitExtensions
|
||||
|
||||
struct GenericSampleList<Sample, Content>: View where Content: View, Sample: HKSampleContainer {
|
||||
|
||||
let sampleView: (Sample) -> Content
|
||||
|
||||
let search: (Date, Date, Bool) throws -> [Sample]
|
||||
|
||||
@State
|
||||
private var samples: [Sample] = []
|
||||
|
||||
@State
|
||||
private var startDate = Date.now.addingTimeInterval(-86400)
|
||||
|
||||
@State
|
||||
private var endDate = Date.now
|
||||
|
||||
@State
|
||||
private var sortAscending = false
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Section("Search") {
|
||||
DatePicker("Start", selection: $startDate)
|
||||
.datePickerStyle(.compact)
|
||||
DatePicker("End", selection: $endDate)
|
||||
.datePickerStyle(.compact)
|
||||
Toggle("Sort ascending", isOn: $sortAscending)
|
||||
Button(action: load) {
|
||||
HStack {
|
||||
Spacer()
|
||||
Text("Find samples")
|
||||
Spacer()
|
||||
}
|
||||
}
|
||||
}
|
||||
Section("Samples") {
|
||||
ForEach(samples, id: \.uuid) { sample in
|
||||
sampleView(sample)
|
||||
}
|
||||
}
|
||||
}.onAppear {
|
||||
load()
|
||||
}
|
||||
}
|
||||
|
||||
func load() {
|
||||
print("Finding samples from \(startDate.formatted()) to \(endDate.formatted()) for \(Sample.self)")
|
||||
Task {
|
||||
do {
|
||||
try await loadSamplesAsync()
|
||||
} catch {
|
||||
print("Failed to load samples: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func loadSamplesAsync() async throws {
|
||||
let samples = try search(startDate, endDate, sortAscending)
|
||||
.sorted(ascending: false) { $0.endDate }
|
||||
print("Finished loading \(samples.count) samples")
|
||||
DispatchQueue.main.async {
|
||||
self.samples = samples
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
GenericSampleList(sampleView: { sample in
|
||||
HStack {
|
||||
Text(sample.quantity.description)
|
||||
Spacer()
|
||||
Text(sample.endDate.formatted())
|
||||
}
|
||||
}, search: { (_, _, _) -> [ActiveEnergyBurned] in
|
||||
[] })
|
||||
}
|
||||
}
|
44
HealthImport/Samples/Lists/ActivitySamplesList.swift
Normal file
44
HealthImport/Samples/Lists/ActivitySamplesList.swift
Normal file
@ -0,0 +1,44 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct ActivitySamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<ActiveEnergyBurned>(database: database)
|
||||
QuantitySampleRow<AppleExerciseTime>(database: database)
|
||||
QuantitySampleRow<AppleMoveTime>(database: database)
|
||||
QuantitySampleRow<AppleStandTime>(database: database)
|
||||
QuantitySampleRow<BasalEnergyBurned>(database: database)
|
||||
QuantitySampleRow<CyclingCadence>(database: database)
|
||||
QuantitySampleRow<CyclingFunctionalThresholdPower>(database: database)
|
||||
QuantitySampleRow<CyclingPower>(database: database)
|
||||
QuantitySampleRow<CyclingSpeed>(database: database)
|
||||
QuantitySampleRow<DistanceCycling>(database: database)
|
||||
QuantitySampleRow<DistanceDownhillSnowSports>(database: database)
|
||||
QuantitySampleRow<FlightsClimbed>(database: database)
|
||||
QuantitySampleRow<NikeFuel>(database: database)
|
||||
QuantitySampleRow<PhysicalEffort>(database: database)
|
||||
QuantitySampleRow<PushCount>(database: database)
|
||||
QuantitySampleRow<RunningPower>(database: database)
|
||||
QuantitySampleRow<RunningSpeed>(database: database)
|
||||
QuantitySampleRow<StepCount>(database: database)
|
||||
QuantitySampleRow<DistanceSwimming>(database: database)
|
||||
QuantitySampleRow<SwimmingStrokeCount>(database: database)
|
||||
QuantitySampleRow<UnderwaterDepth>(database: database)
|
||||
QuantitySampleRow<DistanceWalkingRunning>(database: database)
|
||||
QuantitySampleRow<DistanceWheelchair>(database: database)
|
||||
|
||||
}
|
||||
.navigationTitle("Activity")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
ActivitySamplesList(database: .empty)
|
||||
}
|
||||
}
|
32
HealthImport/Samples/Lists/BodyMeasurementsList.swift
Normal file
32
HealthImport/Samples/Lists/BodyMeasurementsList.swift
Normal file
@ -0,0 +1,32 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct BodyMeasurementsList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<BasalBodyTemperature>(database: database)
|
||||
QuantitySampleRow<BodyFatPercentage>(database: database)
|
||||
QuantitySampleRow<BodyMass>(database: database)
|
||||
QuantitySampleRow<BodyMassIndex>(database: database)
|
||||
QuantitySampleRow<BodyTemperature>(database: database)
|
||||
QuantitySampleRow<ElectrodermalActivity>(database: database)
|
||||
QuantitySampleRow<Height>(database: database)
|
||||
QuantitySampleRow<LeanBodyMass>(database: database)
|
||||
Text("Vision prescription")
|
||||
.foregroundStyle(.secondary)
|
||||
QuantitySampleRow<WaistCircumference>(database: database)
|
||||
QuantitySampleRow<AppleSleepingWristTemperature>(database: database, title: "Wrist temperature")
|
||||
}
|
||||
.navigationTitle("Body Measurements")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
BodyMeasurementsList(database: .empty)
|
||||
}
|
||||
}
|
57
HealthImport/Samples/Lists/CycleTrackingList.swift
Normal file
57
HealthImport/Samples/Lists/CycleTrackingList.swift
Normal file
@ -0,0 +1,57 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct CycleTrackingList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
CategoryEnumSampleRow<AbdominalCramps>(database: database)
|
||||
CategoryEnumSampleRow<Acne>(database: database)
|
||||
CategoryEnumSampleRow<AppetiteChanges>(database: database)
|
||||
QuantitySampleRow<BasalBodyTemperature>(database: database)
|
||||
CategoryEnumSampleRow<BladderIncontinence>(database: database)
|
||||
CategoryEnumSampleRow<Bloating>(database: database)
|
||||
CategoryEnumSampleRow<BreastPain>(database: database)
|
||||
CategoryEnumSampleRow<CervicalMucusQuality>(database: database)
|
||||
CategoryEnumSampleRow<Chills>(database: database)
|
||||
CategoryEnumSampleRow<Constipation>(database: database)
|
||||
CategoryEnumSampleRow<Contraceptive>(database: database)
|
||||
CategoryEnumSampleRow<Diarrhea>(database: database)
|
||||
CategoryEnumSampleRow<DrySkin>(database: database)
|
||||
CategoryEnumSampleRow<Fatigue>(database: database)
|
||||
CategoryEnumSampleRow<HairLoss>(database: database)
|
||||
CategoryEnumSampleRow<Headache>(database: database)
|
||||
CategoryEnumSampleRow<HotFlashes>(database: database)
|
||||
CategoryEmptySampleRow<InfrequentMenstrualCycles>(database: database)
|
||||
CategoryEmptySampleRow<IntermenstrualBleeding>(database: database)
|
||||
CategoryEmptySampleRow<IrregularMenstrualCycles>(database: database)
|
||||
CategoryEmptySampleRow<Lactation>(database: database)
|
||||
CategoryEnumSampleRow<LowerBackPain>(database: database)
|
||||
CategoryEnumSampleRow<MemoryLapse>(database: database)
|
||||
CategoryEnumSampleRow<MenstrualFlow>(database: database)
|
||||
CategoryEnumSampleRow<MoodChanges>(database: database)
|
||||
CategoryEnumSampleRow<Nausea>(database: database)
|
||||
CategoryEnumSampleRow<NightSweats>(database: database)
|
||||
CategoryEnumSampleRow<OvulationTestResult>(database: database)
|
||||
CategoryEnumSampleRow<PelvicPain>(database: database)
|
||||
CategoryEmptySampleRow<PersistentIntermenstrualBleeding>(database: database)
|
||||
CategoryEmptySampleRow<Pregnancy>(database: database)
|
||||
CategoryEnumSampleRow<PregnancyTestResult>(database: database)
|
||||
CategoryEnumSampleRow<ProgesteroneTestResult>(database: database)
|
||||
CategoryEmptySampleRow<ProlongedMenstrualPeriods>(database: database)
|
||||
CategoryEmptySampleRow<SexualActivity>(database: database)
|
||||
CategoryEnumSampleRow<SleepChanges>(database: database)
|
||||
CategoryEnumSampleRow<VaginalDryness>(database: database)
|
||||
}
|
||||
.navigationTitle("Cycle Tracking")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
CycleTrackingList(database: .empty)
|
||||
}
|
||||
}
|
27
HealthImport/Samples/Lists/HearingSamplesList.swift
Normal file
27
HealthImport/Samples/Lists/HearingSamplesList.swift
Normal file
@ -0,0 +1,27 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct HearingSamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Text("Audiogram")
|
||||
.foregroundStyle(.secondary)
|
||||
QuantitySampleRow<EnvironmentalAudioExposure>(database: database)
|
||||
CategoryEnumSampleRow<EnvironmentalAudioExposureEvent>(database: database)
|
||||
QuantitySampleRow<EnvironmentalSoundReduction>(database: database)
|
||||
QuantitySampleRow<HeadphoneAudioExposure>(database: database)
|
||||
CategoryEnumSampleRow<HeadphoneAudioExposureEvent>(database: database)
|
||||
}
|
||||
.navigationTitle("Hearing")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
HearingSamplesList(database: .empty)
|
||||
}
|
||||
}
|
39
HealthImport/Samples/Lists/HeartSamplesList.swift
Normal file
39
HealthImport/Samples/Lists/HeartSamplesList.swift
Normal file
@ -0,0 +1,39 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct HeartSamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<HeartRate>(database: database)
|
||||
QuantitySampleRow<HeartRateVariabilitySDNN>(database: database, title: "Heart Rate Variability")
|
||||
QuantitySampleRow<RestingHeartRate>(database: database)
|
||||
QuantitySampleRow<WalkingHeartRateAverage>(database: database)
|
||||
QuantitySampleRow<Vo2Max>(database: database, title: "Cardio Fitness")
|
||||
CategoryEmptySampleRow<LowHeartRateEvent>(database: database)
|
||||
Text("Electrocardiograms (ECG)")
|
||||
.foregroundStyle(.secondary)
|
||||
#warning("Create view for Electrocardiograms")
|
||||
QuantitySampleRow<AtrialFibrillationBurden>(database: database)
|
||||
Text("Blood Pressure")
|
||||
.foregroundStyle(.secondary)
|
||||
#warning("Create view for blood pressure")
|
||||
QuantitySampleRow<BloodPressureDiastolic>(database: database)
|
||||
QuantitySampleRow<BloodPressureSystolic>(database: database)
|
||||
CategoryEnumSampleRow<LowCardioFitnessEvent>(database: database)
|
||||
CategoryEmptySampleRow<HighHeartRateEvent>(database: database)
|
||||
CategoryEmptySampleRow<IrregularHeartRhythmEvent>(database: database)
|
||||
QuantitySampleRow<PeripheralPerfusionIndex>(database: database)
|
||||
}
|
||||
.navigationTitle("Heart")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
HeartSamplesList(database: .empty)
|
||||
}
|
||||
}
|
31
HealthImport/Samples/Lists/MentalHealthList.swift
Normal file
31
HealthImport/Samples/Lists/MentalHealthList.swift
Normal file
@ -0,0 +1,31 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct MentalHealthList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
Text("Anxiety Risk")
|
||||
.foregroundStyle(.secondary)
|
||||
Text("Depression Risk")
|
||||
.foregroundStyle(.secondary)
|
||||
QuantitySampleRow<AppleExerciseTime>(database: database, title: "Exercise Minutes")
|
||||
CategoryEmptySampleRow<MindfulSession>(database: database, title: "Mindful Minutes")
|
||||
Text("Sleep")
|
||||
.foregroundStyle(.secondary)
|
||||
Text("State of Mind")
|
||||
.foregroundStyle(.secondary)
|
||||
QuantitySampleRow<TimeInDaylight>(database: database)
|
||||
}
|
||||
.navigationTitle("Mental Wellbeing")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
MentalHealthList(database: .empty)
|
||||
}
|
||||
}
|
33
HealthImport/Samples/Lists/MobilitySamplesList.swift
Normal file
33
HealthImport/Samples/Lists/MobilitySamplesList.swift
Normal file
@ -0,0 +1,33 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct MobilitySamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<Vo2Max>(database: database, title: "Cardio Fitness")
|
||||
QuantitySampleRow<WalkingDoubleSupportPercentage>(database: database, title: "Double Support Time")
|
||||
QuantitySampleRow<RunningGroundContactTime>(database: database, title: "Ground Contact Time")
|
||||
QuantitySampleRow<RunningStrideLength>(database: database)
|
||||
QuantitySampleRow<SixMinuteWalkTestDistance>(database: database, title: "Six-Minute Walk")
|
||||
QuantitySampleRow<StairDescentSpeed>(database: database, title: "Stair Speed: Down")
|
||||
QuantitySampleRow<StairAscentSpeed>(database: database, title: "Stair Speed: Up")
|
||||
QuantitySampleRow<RunningVerticalOscillation>(database: database, title: "Vertical Oscillation")
|
||||
QuantitySampleRow<WalkingAsymmetryPercentage>(database: database, title: "Walking Asymmetry")
|
||||
QuantitySampleRow<WalkingSpeed>(database: database)
|
||||
QuantitySampleRow<AppleWalkingSteadiness>(database: database, title: "Walking Steadiness")
|
||||
QuantitySampleRow<WalkingStepLength>(database: database)
|
||||
CategoryEnumSampleRow<AppleWalkingSteadinessEvent>(database: database, title: "Walking Steadiness Notifications")
|
||||
}
|
||||
.navigationTitle("Mobility")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
MobilitySamplesList(database: .empty)
|
||||
}
|
||||
}
|
59
HealthImport/Samples/Lists/NutritionSamplesList.swift
Normal file
59
HealthImport/Samples/Lists/NutritionSamplesList.swift
Normal file
@ -0,0 +1,59 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct NutritionSamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<DietaryBiotin>(database: database, title: "Biotin")
|
||||
QuantitySampleRow<DietaryCaffeine>(database: database, title: "Caffeine")
|
||||
QuantitySampleRow<DietaryCalcium>(database: database, title: "Calcium")
|
||||
QuantitySampleRow<DietaryCarbohydrates>(database: database, title: "Carbohydrates")
|
||||
QuantitySampleRow<DietaryChloride>(database: database, title: "Chloride")
|
||||
QuantitySampleRow<DietaryChromium>(database: database, title: "Chromium")
|
||||
QuantitySampleRow<DietaryCopper>(database: database, title: "Copper")
|
||||
QuantitySampleRow<DietaryCholesterol>(database: database)
|
||||
QuantitySampleRow<DietaryEnergyConsumed>(database: database, title: "Dietary Energy")
|
||||
QuantitySampleRow<DietarySugar>(database: database)
|
||||
QuantitySampleRow<DietaryFiber>(database: database, title: "Fiber")
|
||||
QuantitySampleRow<DietaryFolate>(database: database, title: "Folate")
|
||||
QuantitySampleRow<DietaryIodine>(database: database, title: "Iodine")
|
||||
QuantitySampleRow<DietaryIron>(database: database, title: "Iron")
|
||||
QuantitySampleRow<DietaryMagnesium>(database: database, title: "Magnesium")
|
||||
QuantitySampleRow<DietaryManganese>(database: database, title: "Manganese")
|
||||
QuantitySampleRow<DietaryMolybdenum>(database: database, title: "Molybdenum")
|
||||
QuantitySampleRow<DietaryFatMonounsaturated>(database: database, title: "Monounsaturated Fat")
|
||||
QuantitySampleRow<DietaryNiacin>(database: database, title: "Niacin")
|
||||
QuantitySampleRow<DietaryPantothenicAcid>(database: database, title: "Pantothenic Acid")
|
||||
QuantitySampleRow<DietaryPhosphorus>(database: database, title: "Phosphorus")
|
||||
QuantitySampleRow<DietaryFatPolyunsaturated>(database: database, title: "Polyunsaturated Fat")
|
||||
QuantitySampleRow<DietaryPotassium>(database: database, title: "Potassium")
|
||||
QuantitySampleRow<DietaryProtein>(database: database, title: "Protein")
|
||||
QuantitySampleRow<DietaryRiboflavin>(database: database, title: "Riboflavin")
|
||||
QuantitySampleRow<DietaryFatSaturated>(database: database, title: "Saturated Fat")
|
||||
QuantitySampleRow<DietarySelenium>(database: database, title: "Selenium")
|
||||
QuantitySampleRow<DietarySodium>(database: database, title: "Sodium")
|
||||
QuantitySampleRow<DietaryThiamin>(database: database, title: "Thiamine")
|
||||
QuantitySampleRow<DietaryFatTotal>(database: database, title: "Total Fat")
|
||||
QuantitySampleRow<DietaryVitaminA>(database: database, title: "Vitamin A")
|
||||
QuantitySampleRow<DietaryVitaminB6>(database: database, title: "Vitamin B6")
|
||||
QuantitySampleRow<DietaryVitaminB12>(database: database, title: "Vitamin B12")
|
||||
QuantitySampleRow<DietaryVitaminC>(database: database, title: "Vitamin C")
|
||||
QuantitySampleRow<DietaryVitaminD>(database: database, title: "Vitamin D")
|
||||
QuantitySampleRow<DietaryVitaminE>(database: database, title: "Vitamin E")
|
||||
QuantitySampleRow<DietaryVitaminK>(database: database, title: "Vitamin K")
|
||||
QuantitySampleRow<DietaryWater>(database: database, title: "Water")
|
||||
QuantitySampleRow<DietaryZinc>(database: database, title: "Zinc")
|
||||
}
|
||||
.navigationTitle("Nutrition")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
NutritionSamplesList(database: .empty)
|
||||
}
|
||||
}
|
31
HealthImport/Samples/Lists/OtherSamplesList.swift
Normal file
31
HealthImport/Samples/Lists/OtherSamplesList.swift
Normal file
@ -0,0 +1,31 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct OtherSamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<BloodAlcoholContent>(database: database)
|
||||
QuantitySampleRow<BloodGlucose>(database: database)
|
||||
CategoryEmptySampleRow<HandwashingEvent>(database: database)
|
||||
QuantitySampleRow<InhalerUsage>(database: database)
|
||||
QuantitySampleRow<InsulinDelivery>(database: database)
|
||||
QuantitySampleRow<NumberOfTimesFallen>(database: database, title: "Number of Times Fallen")
|
||||
CategoryEmptySampleRow<SexualActivity>(database: database)
|
||||
QuantitySampleRow<TimeInDaylight>(database: database)
|
||||
CategoryEmptySampleRow<ToothbrushingEvent>(database: database)
|
||||
QuantitySampleRow<UvExposure>(database: database, title: "UV Index")
|
||||
QuantitySampleRow<WaterTemperature>(database: database)
|
||||
}
|
||||
.navigationTitle("Other Data")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
OtherSamplesList(database: .empty)
|
||||
}
|
||||
}
|
28
HealthImport/Samples/Lists/RespiratorySamplesList.swift
Normal file
28
HealthImport/Samples/Lists/RespiratorySamplesList.swift
Normal file
@ -0,0 +1,28 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct RespiratorySamplesList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<OxygenSaturation>(database: database, title: "Blood Oxygen")
|
||||
QuantitySampleRow<Vo2Max>(database: database, title: "Cardio Fitness")
|
||||
QuantitySampleRow<ForcedExpiratoryVolume1>(database: database, title: "Forced Expiratory Volume, 1 sec")
|
||||
QuantitySampleRow<ForcedVitalCapacity>(database: database)
|
||||
QuantitySampleRow<InhalerUsage>(database: database)
|
||||
QuantitySampleRow<PeakExpiratoryFlowRate>(database: database)
|
||||
QuantitySampleRow<RespiratoryRate>(database: database)
|
||||
QuantitySampleRow<SixMinuteWalkTestDistance>(database: database, title: "Six Minute Walk Distance")
|
||||
}
|
||||
.navigationTitle("Respiratory")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
RespiratorySamplesList(database: .empty)
|
||||
}
|
||||
}
|
57
HealthImport/Samples/Lists/SymptomsList.swift
Normal file
57
HealthImport/Samples/Lists/SymptomsList.swift
Normal file
@ -0,0 +1,57 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct SymptomsList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
CategoryEnumSampleRow<AbdominalCramps>(database: database)
|
||||
CategoryEnumSampleRow<Acne>(database: database)
|
||||
CategoryEnumSampleRow<AppetiteChanges>(database: database)
|
||||
CategoryEnumSampleRow<BladderIncontinence>(database: database)
|
||||
CategoryEnumSampleRow<Bloating>(database: database)
|
||||
CategoryEnumSampleRow<GeneralizedBodyAche>(database: database, title: "Body and Muscle Ache")
|
||||
CategoryEnumSampleRow<BreastPain>(database: database)
|
||||
CategoryEnumSampleRow<ChestTightnessOrPain>(database: database)
|
||||
CategoryEnumSampleRow<Chills>(database: database)
|
||||
CategoryEnumSampleRow<SinusCongestion>(database: database, title: "Congestion")
|
||||
CategoryEnumSampleRow<Constipation>(database: database)
|
||||
CategoryEnumSampleRow<Coughing>(database: database)
|
||||
CategoryEnumSampleRow<Diarrhea>(database: database, title: "Diarrhoea")
|
||||
CategoryEnumSampleRow<DrySkin>(database: database)
|
||||
CategoryEnumSampleRow<Fainting>(database: database)
|
||||
CategoryEnumSampleRow<Fatigue>(database: database)
|
||||
CategoryEnumSampleRow<Fever>(database: database)
|
||||
CategoryEnumSampleRow<HairLoss>(database: database)
|
||||
CategoryEnumSampleRow<Headache>(database: database)
|
||||
CategoryEnumSampleRow<Heartburn>(database: database)
|
||||
CategoryEnumSampleRow<HotFlashes>(database: database)
|
||||
CategoryEnumSampleRow<LossOfSmell>(database: database)
|
||||
CategoryEnumSampleRow<LossOfTaste>(database: database)
|
||||
CategoryEnumSampleRow<LowerBackPain>(database: database)
|
||||
CategoryEnumSampleRow<MemoryLapse>(database: database)
|
||||
CategoryEnumSampleRow<MoodChanges>(database: database)
|
||||
CategoryEnumSampleRow<Nausea>(database: database)
|
||||
CategoryEnumSampleRow<NightSweats>(database: database)
|
||||
CategoryEnumSampleRow<PelvicPain>(database: database)
|
||||
CategoryEnumSampleRow<RapidPoundingOrFlutteringHeartbeat>(database: database)
|
||||
CategoryEnumSampleRow<RunnyNose>(database: database)
|
||||
CategoryEnumSampleRow<ShortnessOfBreath>(database: database)
|
||||
CategoryEnumSampleRow<SleepChanges>(database: database)
|
||||
CategoryEnumSampleRow<SoreThroat>(database: database)
|
||||
CategoryEnumSampleRow<VaginalDryness>(database: database)
|
||||
CategoryEnumSampleRow<Vomiting>(database: database)
|
||||
CategoryEnumSampleRow<Wheezing>(database: database)
|
||||
}
|
||||
.navigationTitle("Symptoms")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
SymptomsList(database: .empty)
|
||||
}
|
||||
}
|
29
HealthImport/Samples/Lists/VitalsList.swift
Normal file
29
HealthImport/Samples/Lists/VitalsList.swift
Normal file
@ -0,0 +1,29 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
struct VitalsList: View {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
QuantitySampleRow<BloodGlucose>(database: database)
|
||||
QuantitySampleRow<OxygenSaturation>(database: database, title: "Blood Oxygen")
|
||||
Text("Blood Pressure")
|
||||
.foregroundStyle(.secondary)
|
||||
QuantitySampleRow<BodyTemperature>(database: database)
|
||||
QuantitySampleRow<HeartRate>(database: database)
|
||||
CategoryEnumSampleRow<MenstrualFlow>(database: database)
|
||||
QuantitySampleRow<RespiratoryRate>(database: database)
|
||||
|
||||
}
|
||||
.navigationTitle("Vitals")
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
VitalsList(database: .empty)
|
||||
}
|
||||
}
|
28
HealthImport/Samples/QuantitySampleList.swift
Normal file
28
HealthImport/Samples/QuantitySampleList.swift
Normal file
@ -0,0 +1,28 @@
|
||||
import SwiftUI
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
import HealthKitExtensions
|
||||
|
||||
struct QuantitySampleList<T>: View where T: HKQuantitySampleContainer {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
var body: some View {
|
||||
GenericSampleList(sampleView: { sample in
|
||||
HStack {
|
||||
Text(sample.quantity.description)
|
||||
Spacer()
|
||||
Text(sample.endDate.formatted())
|
||||
}
|
||||
}, search: { start, end, _ -> [T] in
|
||||
try database.samples(includingSeriesData: true, from: start, to: end)
|
||||
})
|
||||
.navigationTitle(T.quantityTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
QuantitySampleList<ActiveEnergyBurned>(database: .empty)
|
||||
}
|
||||
}
|
27
HealthImport/Samples/QuantitySampleRow.swift
Normal file
27
HealthImport/Samples/QuantitySampleRow.swift
Normal file
@ -0,0 +1,27 @@
|
||||
import SwiftUI
|
||||
import HealthKitExtensions
|
||||
import HealthDB
|
||||
|
||||
struct QuantitySampleRow<T>: View where T: HKQuantitySampleContainer {
|
||||
|
||||
let database: HealthDatabase
|
||||
|
||||
let title: String?
|
||||
|
||||
init(database: HealthDatabase, title: String? = nil) {
|
||||
self.database = database
|
||||
self.title = title
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
NavigationLink {
|
||||
QuantitySampleList<T>(database: database)
|
||||
} label: {
|
||||
Text(title ?? T.quantityTypeIdentifier.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
QuantitySampleRow<ActiveEnergyBurned>(database: .empty)
|
||||
}
|
@ -8,26 +8,73 @@ struct SamplesTab: View {
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
List {
|
||||
if let db = database.store {
|
||||
NavigationLink {
|
||||
ActivitySampleList()
|
||||
ActivitySamplesList(database: db)
|
||||
} label: {
|
||||
Label("Activity", systemSymbol: .flame)
|
||||
|
||||
}
|
||||
NavigationLink {
|
||||
BodyMeasurementsList(database: db)
|
||||
} label: {
|
||||
Label("Body Measurements", systemSymbol: .figure)
|
||||
}
|
||||
Label("Clinical documents", systemSymbol: .listClipboard)
|
||||
.foregroundColor(.secondary)
|
||||
NavigationLink {
|
||||
CycleTrackingList(database: db)
|
||||
} label: {
|
||||
Label("Cycle Tracking", systemSymbol: .circleHexagonpath)
|
||||
}
|
||||
NavigationLink {
|
||||
HearingSamplesList(database: db)
|
||||
} label: {
|
||||
Label("Hearing", systemSymbol: .ear)
|
||||
}
|
||||
NavigationLink {
|
||||
HeartSamplesList(database: db)
|
||||
} label: {
|
||||
Label("Heart", systemSymbol: .heart)
|
||||
}
|
||||
Label("Medications", systemSymbol: .pills)
|
||||
.foregroundColor(.secondary)
|
||||
NavigationLink {
|
||||
MentalHealthList(database: db)
|
||||
} label: {
|
||||
Label("Mental Wellbeing", systemSymbol: .brainHeadProfile)
|
||||
}
|
||||
NavigationLink {
|
||||
MobilitySamplesList(database: db)
|
||||
} label: {
|
||||
Label("Mobility", systemSymbol: .arrowLeftAndRight)
|
||||
}
|
||||
NavigationLink {
|
||||
NutritionSamplesList(database: db)
|
||||
} label: {
|
||||
Label("Nutrition", systemSymbol: .carrot)
|
||||
}
|
||||
NavigationLink {
|
||||
RespiratorySamplesList(database: db)
|
||||
} label: {
|
||||
Label("Respiratory", systemSymbol: .lungs)
|
||||
}
|
||||
Label("Sleep", systemSymbol: .bedDouble)
|
||||
.foregroundColor(.secondary)
|
||||
NavigationLink {
|
||||
SymptomsList(database: db)
|
||||
} label: {
|
||||
Label("Symptoms", systemSymbol: .listBulletClipboard)
|
||||
}
|
||||
NavigationLink {
|
||||
VitalsList(database: db)
|
||||
} label: {
|
||||
Label("Vitals", systemSymbol: .waveformPathEcgRectangle)
|
||||
}
|
||||
Label("Other Data", systemSymbol: .cross)
|
||||
|
||||
} else {
|
||||
Text("No database loaded")
|
||||
}
|
||||
}
|
||||
.navigationTitle("Health")
|
||||
}
|
||||
@ -35,6 +82,6 @@ struct SamplesTab: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
SamplesTab(database: Database())
|
||||
SamplesTab(database: Database.empty)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
|
@ -146,5 +146,5 @@ struct WorkoutTab: View {
|
||||
|
||||
#Preview {
|
||||
WorkoutTab()
|
||||
.environmentObject(Database.mock)
|
||||
.environmentObject(Database.empty)
|
||||
}
|
||||
|
@ -120,6 +120,6 @@ struct ActivityDetailView: View {
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
ActivityDetailView(workout: .mock1, activity: .mock1)
|
||||
.environmentObject(Database.mock)
|
||||
.environmentObject(Database.empty)
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ struct WorkoutDetailView: View {
|
||||
#Preview {
|
||||
return NavigationStack {
|
||||
WorkoutDetailView(workout: .mock1)
|
||||
.environmentObject(Database.mock)
|
||||
.environmentObject(Database.empty)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user