diff --git a/HealthImport.xcodeproj/project.pbxproj b/HealthImport.xcodeproj/project.pbxproj index 6048705..af0122b 100644 --- a/HealthImport.xcodeproj/project.pbxproj +++ b/HealthImport.xcodeproj/project.pbxproj @@ -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 = ""; }; E2A38EA22B9A024500BAD02E /* Workout+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Workout+Extensions.swift"; sourceTree = ""; }; E2A38EA42B9C6EA900BAD02E /* SearchHealthStoreView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchHealthStoreView.swift; sourceTree = ""; }; + E2D82B292BCD25B60075EAF0 /* QuantitySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantitySampleList.swift; sourceTree = ""; }; + E2D82B2B2BCD28720075EAF0 /* QuantitySampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuantitySampleRow.swift; sourceTree = ""; }; + E2D82B2D2BCD319D0075EAF0 /* BodyMeasurementsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BodyMeasurementsList.swift; sourceTree = ""; }; + E2D82B2F2BCD32F20075EAF0 /* CycleTrackingList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CycleTrackingList.swift; sourceTree = ""; }; + E2D82B312BCD34B80075EAF0 /* CategoryEnumSampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEnumSampleRow.swift; sourceTree = ""; }; + E2D82B332BCD34EB0075EAF0 /* CategoryEmptySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEmptySampleList.swift; sourceTree = ""; }; + E2D82B352BCD35DD0075EAF0 /* CategoryEnumSampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEnumSampleList.swift; sourceTree = ""; }; + E2D82B372BCD36A90075EAF0 /* healthdb_secure.sqlite */ = {isa = PBXFileReference; lastKnownFileType = file; path = healthdb_secure.sqlite; sourceTree = ""; }; + E2D82B3A2BCD38E30075EAF0 /* CategoryEmptySampleRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryEmptySampleRow.swift; sourceTree = ""; }; + E2D82B3C2BCD3C3F0075EAF0 /* HearingSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HearingSamplesList.swift; sourceTree = ""; }; + E2D82B3E2BCD47E80075EAF0 /* HeartSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartSamplesList.swift; sourceTree = ""; }; + E2D82B422BCD53D10075EAF0 /* GenericSampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GenericSampleList.swift; sourceTree = ""; }; + E2D82B442BCD582D0075EAF0 /* MentalHealthList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentalHealthList.swift; sourceTree = ""; }; + E2D82B462BCD59380075EAF0 /* MobilitySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MobilitySamplesList.swift; sourceTree = ""; }; + E2D82B482BCD5BA00075EAF0 /* NutritionSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NutritionSamplesList.swift; sourceTree = ""; }; + E2D82B4A2BCD5E520075EAF0 /* RespiratorySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RespiratorySamplesList.swift; sourceTree = ""; }; + E2D82B4C2BCD5F780075EAF0 /* SymptomsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SymptomsList.swift; sourceTree = ""; }; + E2D82B4E2BCD61590075EAF0 /* VitalsList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VitalsList.swift; sourceTree = ""; }; + E2D82B502BCD626D0075EAF0 /* OtherSamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OtherSamplesList.swift; sourceTree = ""; }; E2E552882BA2194400BF5E9B /* DatabasesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabasesTab.swift; sourceTree = ""; }; - E2E5528B2BA21C0700BF5E9B /* HealthDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthDatabase.swift; sourceTree = ""; }; + E2E5528B2BA21C0700BF5E9B /* Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = ""; }; E2E5528D2BA21C5900BF5E9B /* FileManager+Directory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileManager+Directory.swift"; sourceTree = ""; }; E2E5528F2BA236A000BF5E9B /* DatabaseList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseList.swift; sourceTree = ""; }; E2E552912BA236D000BF5E9B /* DatabaseFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseFile.swift; sourceTree = ""; }; @@ -104,7 +141,7 @@ E2E552B62BA9A69400BF5E9B /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = ""; }; E2E552B82BA9A77D00BF5E9B /* HKWorkoutActivityType+Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HKWorkoutActivityType+Icon.swift"; sourceTree = ""; }; E2E552BA2BA9CAAE00BF5E9B /* SamplesTab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SamplesTab.swift; sourceTree = ""; }; - E2E552BF2BAB38DC00BF5E9B /* ActivitySampleList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySampleList.swift; sourceTree = ""; }; + E2E552BF2BAB38DC00BF5E9B /* ActivitySamplesList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivitySamplesList.swift; sourceTree = ""; }; E2FDFF282B6D10D60080A7B3 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = ""; }; E2FDFF342B6E59030080A7B3 /* HealthImport.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HealthImport.entitlements; sourceTree = ""; }; /* 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 = ""; }; + 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 = ""; + }; 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 = ""; @@ -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 */, diff --git a/HealthImport/HealthImportApp.swift b/HealthImport/HealthImportApp.swift index 5b6997a..c3c57d3 100644 --- a/HealthImport/HealthImportApp.swift +++ b/HealthImport/HealthImportApp.swift @@ -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 } } diff --git a/HealthImport/Model/HealthDatabase.swift b/HealthImport/Model/Database.swift similarity index 100% rename from HealthImport/Model/HealthDatabase.swift rename to HealthImport/Model/Database.swift diff --git a/HealthImport/Preview Content/HealthDatabase+Mock.swift b/HealthImport/Preview Content/HealthDatabase+Mock.swift index 27a7e70..fc7a014 100644 --- a/HealthImport/Preview Content/HealthDatabase+Mock.swift +++ b/HealthImport/Preview Content/HealthDatabase+Mock.swift @@ -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 { diff --git a/HealthImport/Preview Content/WorkoutEvent+Mock.swift b/HealthImport/Preview Content/WorkoutEvent+Mock.swift index 7c22c7f..3ab527f 100644 --- a/HealthImport/Preview Content/WorkoutEvent+Mock.swift +++ b/HealthImport/Preview Content/WorkoutEvent+Mock.swift @@ -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), diff --git a/HealthImport/Samples/ActivitySampleList.swift b/HealthImport/Samples/ActivitySampleList.swift deleted file mode 100644 index 7a797bd..0000000 --- a/HealthImport/Samples/ActivitySampleList.swift +++ /dev/null @@ -1,15 +0,0 @@ -import SwiftUI - -struct ActivitySampleList: View { - - var body: some View { - List { - - } - .navigationTitle("Activity") - } -} - -#Preview { - ActivitySampleList() -} diff --git a/HealthImport/Samples/CategoryEmptySampleList.swift b/HealthImport/Samples/CategoryEmptySampleList.swift new file mode 100644 index 0000000..48e4fb9 --- /dev/null +++ b/HealthImport/Samples/CategoryEmptySampleList.swift @@ -0,0 +1,27 @@ +import SwiftUI +import HealthDB +import HealthKit +import HealthKitExtensions + +struct CategoryEmptySampleList: 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(database: .empty) + } +} diff --git a/HealthImport/Samples/CategoryEmptySampleRow.swift b/HealthImport/Samples/CategoryEmptySampleRow.swift new file mode 100644 index 0000000..d422855 --- /dev/null +++ b/HealthImport/Samples/CategoryEmptySampleRow.swift @@ -0,0 +1,27 @@ +import SwiftUI +import HealthKitExtensions +import HealthDB + +struct CategoryEmptySampleRow: 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(database: database) + } label: { + Text(title ?? T.categoryTypeIdentifier.description) + } + } +} + +#Preview { + CategoryEmptySampleRow(database: .empty) +} diff --git a/HealthImport/Samples/CategoryEnumSampleList.swift b/HealthImport/Samples/CategoryEnumSampleList.swift new file mode 100644 index 0000000..f01115a --- /dev/null +++ b/HealthImport/Samples/CategoryEnumSampleList.swift @@ -0,0 +1,31 @@ +import SwiftUI +import HealthDB +import HealthKit +import HealthKitExtensions + +struct CategoryEnumSampleList: 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(database: .empty) + } +} diff --git a/HealthImport/Samples/CategoryEnumSampleRow.swift b/HealthImport/Samples/CategoryEnumSampleRow.swift new file mode 100644 index 0000000..7952731 --- /dev/null +++ b/HealthImport/Samples/CategoryEnumSampleRow.swift @@ -0,0 +1,27 @@ +import SwiftUI +import HealthKitExtensions +import HealthDB + +struct CategoryEnumSampleRow: 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(database: database) + } label: { + Text(title ?? T.categoryTypeIdentifier.description) + } + } +} + +#Preview { + CategoryEnumSampleRow(database: .empty) +} diff --git a/HealthImport/Samples/GenericSampleList.swift b/HealthImport/Samples/GenericSampleList.swift new file mode 100644 index 0000000..4629269 --- /dev/null +++ b/HealthImport/Samples/GenericSampleList.swift @@ -0,0 +1,82 @@ +import SwiftUI +import HealthDB +import HealthKit +import HealthKitExtensions + +struct GenericSampleList: 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 + [] }) + } +} diff --git a/HealthImport/Samples/Lists/ActivitySamplesList.swift b/HealthImport/Samples/Lists/ActivitySamplesList.swift new file mode 100644 index 0000000..fdad8e5 --- /dev/null +++ b/HealthImport/Samples/Lists/ActivitySamplesList.swift @@ -0,0 +1,44 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct ActivitySamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + + } + .navigationTitle("Activity") + } +} + +#Preview { + NavigationStack { + ActivitySamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/BodyMeasurementsList.swift b/HealthImport/Samples/Lists/BodyMeasurementsList.swift new file mode 100644 index 0000000..5adc9fc --- /dev/null +++ b/HealthImport/Samples/Lists/BodyMeasurementsList.swift @@ -0,0 +1,32 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct BodyMeasurementsList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + Text("Vision prescription") + .foregroundStyle(.secondary) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Wrist temperature") + } + .navigationTitle("Body Measurements") + } +} + +#Preview { + NavigationStack { + BodyMeasurementsList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/CycleTrackingList.swift b/HealthImport/Samples/Lists/CycleTrackingList.swift new file mode 100644 index 0000000..e809ed3 --- /dev/null +++ b/HealthImport/Samples/Lists/CycleTrackingList.swift @@ -0,0 +1,57 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct CycleTrackingList: View { + + let database: HealthDatabase + + var body: some View { + List { + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + } + .navigationTitle("Cycle Tracking") + } +} + +#Preview { + NavigationStack { + CycleTrackingList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/HearingSamplesList.swift b/HealthImport/Samples/Lists/HearingSamplesList.swift new file mode 100644 index 0000000..7338dda --- /dev/null +++ b/HealthImport/Samples/Lists/HearingSamplesList.swift @@ -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(database: database) + CategoryEnumSampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEnumSampleRow(database: database) + } + .navigationTitle("Hearing") + } +} + +#Preview { + NavigationStack { + HearingSamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/HeartSamplesList.swift b/HealthImport/Samples/Lists/HeartSamplesList.swift new file mode 100644 index 0000000..bd2adcd --- /dev/null +++ b/HealthImport/Samples/Lists/HeartSamplesList.swift @@ -0,0 +1,39 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct HeartSamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Heart Rate Variability") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Cardio Fitness") + CategoryEmptySampleRow(database: database) + Text("Electrocardiograms (ECG)") + .foregroundStyle(.secondary) + #warning("Create view for Electrocardiograms") + QuantitySampleRow(database: database) + Text("Blood Pressure") + .foregroundStyle(.secondary) + #warning("Create view for blood pressure") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEmptySampleRow(database: database) + CategoryEmptySampleRow(database: database) + QuantitySampleRow(database: database) + } + .navigationTitle("Heart") + } +} + +#Preview { + NavigationStack { + HeartSamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/MentalHealthList.swift b/HealthImport/Samples/Lists/MentalHealthList.swift new file mode 100644 index 0000000..300dcb5 --- /dev/null +++ b/HealthImport/Samples/Lists/MentalHealthList.swift @@ -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(database: database, title: "Exercise Minutes") + CategoryEmptySampleRow(database: database, title: "Mindful Minutes") + Text("Sleep") + .foregroundStyle(.secondary) + Text("State of Mind") + .foregroundStyle(.secondary) + QuantitySampleRow(database: database) + } + .navigationTitle("Mental Wellbeing") + } +} + +#Preview { + NavigationStack { + MentalHealthList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/MobilitySamplesList.swift b/HealthImport/Samples/Lists/MobilitySamplesList.swift new file mode 100644 index 0000000..75d17bd --- /dev/null +++ b/HealthImport/Samples/Lists/MobilitySamplesList.swift @@ -0,0 +1,33 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct MobilitySamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database, title: "Cardio Fitness") + QuantitySampleRow(database: database, title: "Double Support Time") + QuantitySampleRow(database: database, title: "Ground Contact Time") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Six-Minute Walk") + QuantitySampleRow(database: database, title: "Stair Speed: Down") + QuantitySampleRow(database: database, title: "Stair Speed: Up") + QuantitySampleRow(database: database, title: "Vertical Oscillation") + QuantitySampleRow(database: database, title: "Walking Asymmetry") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Walking Steadiness") + QuantitySampleRow(database: database) + CategoryEnumSampleRow(database: database, title: "Walking Steadiness Notifications") + } + .navigationTitle("Mobility") + } +} + +#Preview { + NavigationStack { + MobilitySamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/NutritionSamplesList.swift b/HealthImport/Samples/Lists/NutritionSamplesList.swift new file mode 100644 index 0000000..33b8bd9 --- /dev/null +++ b/HealthImport/Samples/Lists/NutritionSamplesList.swift @@ -0,0 +1,59 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct NutritionSamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database, title: "Biotin") + QuantitySampleRow(database: database, title: "Caffeine") + QuantitySampleRow(database: database, title: "Calcium") + QuantitySampleRow(database: database, title: "Carbohydrates") + QuantitySampleRow(database: database, title: "Chloride") + QuantitySampleRow(database: database, title: "Chromium") + QuantitySampleRow(database: database, title: "Copper") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Dietary Energy") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Fiber") + QuantitySampleRow(database: database, title: "Folate") + QuantitySampleRow(database: database, title: "Iodine") + QuantitySampleRow(database: database, title: "Iron") + QuantitySampleRow(database: database, title: "Magnesium") + QuantitySampleRow(database: database, title: "Manganese") + QuantitySampleRow(database: database, title: "Molybdenum") + QuantitySampleRow(database: database, title: "Monounsaturated Fat") + QuantitySampleRow(database: database, title: "Niacin") + QuantitySampleRow(database: database, title: "Pantothenic Acid") + QuantitySampleRow(database: database, title: "Phosphorus") + QuantitySampleRow(database: database, title: "Polyunsaturated Fat") + QuantitySampleRow(database: database, title: "Potassium") + QuantitySampleRow(database: database, title: "Protein") + QuantitySampleRow(database: database, title: "Riboflavin") + QuantitySampleRow(database: database, title: "Saturated Fat") + QuantitySampleRow(database: database, title: "Selenium") + QuantitySampleRow(database: database, title: "Sodium") + QuantitySampleRow(database: database, title: "Thiamine") + QuantitySampleRow(database: database, title: "Total Fat") + QuantitySampleRow(database: database, title: "Vitamin A") + QuantitySampleRow(database: database, title: "Vitamin B6") + QuantitySampleRow(database: database, title: "Vitamin B12") + QuantitySampleRow(database: database, title: "Vitamin C") + QuantitySampleRow(database: database, title: "Vitamin D") + QuantitySampleRow(database: database, title: "Vitamin E") + QuantitySampleRow(database: database, title: "Vitamin K") + QuantitySampleRow(database: database, title: "Water") + QuantitySampleRow(database: database, title: "Zinc") + } + .navigationTitle("Nutrition") + } +} + +#Preview { + NavigationStack { + NutritionSamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/OtherSamplesList.swift b/HealthImport/Samples/Lists/OtherSamplesList.swift new file mode 100644 index 0000000..1ba2ae1 --- /dev/null +++ b/HealthImport/Samples/Lists/OtherSamplesList.swift @@ -0,0 +1,31 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct OtherSamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEmptySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Number of Times Fallen") + CategoryEmptySampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEmptySampleRow(database: database) + QuantitySampleRow(database: database, title: "UV Index") + QuantitySampleRow(database: database) + } + .navigationTitle("Other Data") + } +} + +#Preview { + NavigationStack { + OtherSamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/RespiratorySamplesList.swift b/HealthImport/Samples/Lists/RespiratorySamplesList.swift new file mode 100644 index 0000000..29a063b --- /dev/null +++ b/HealthImport/Samples/Lists/RespiratorySamplesList.swift @@ -0,0 +1,28 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct RespiratorySamplesList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database, title: "Blood Oxygen") + QuantitySampleRow(database: database, title: "Cardio Fitness") + QuantitySampleRow(database: database, title: "Forced Expiratory Volume, 1 sec") + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Six Minute Walk Distance") + } + .navigationTitle("Respiratory") + } +} + +#Preview { + NavigationStack { + RespiratorySamplesList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/SymptomsList.swift b/HealthImport/Samples/Lists/SymptomsList.swift new file mode 100644 index 0000000..08357ce --- /dev/null +++ b/HealthImport/Samples/Lists/SymptomsList.swift @@ -0,0 +1,57 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct SymptomsList: View { + + let database: HealthDatabase + + var body: some View { + List { + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database, title: "Body and Muscle Ache") + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database, title: "Congestion") + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database, title: "Diarrhoea") + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + CategoryEnumSampleRow(database: database) + } + .navigationTitle("Symptoms") + } +} + +#Preview { + NavigationStack { + SymptomsList(database: .empty) + } +} diff --git a/HealthImport/Samples/Lists/VitalsList.swift b/HealthImport/Samples/Lists/VitalsList.swift new file mode 100644 index 0000000..c8dd0c9 --- /dev/null +++ b/HealthImport/Samples/Lists/VitalsList.swift @@ -0,0 +1,29 @@ +import SwiftUI +import HealthDB +import HealthKitExtensions + +struct VitalsList: View { + + let database: HealthDatabase + + var body: some View { + List { + QuantitySampleRow(database: database) + QuantitySampleRow(database: database, title: "Blood Oxygen") + Text("Blood Pressure") + .foregroundStyle(.secondary) + QuantitySampleRow(database: database) + QuantitySampleRow(database: database) + CategoryEnumSampleRow(database: database) + QuantitySampleRow(database: database) + + } + .navigationTitle("Vitals") + } +} + +#Preview { + NavigationStack { + VitalsList(database: .empty) + } +} diff --git a/HealthImport/Samples/QuantitySampleList.swift b/HealthImport/Samples/QuantitySampleList.swift new file mode 100644 index 0000000..91c8dc0 --- /dev/null +++ b/HealthImport/Samples/QuantitySampleList.swift @@ -0,0 +1,28 @@ +import SwiftUI +import HealthDB +import HealthKit +import HealthKitExtensions + +struct QuantitySampleList: 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(database: .empty) + } +} diff --git a/HealthImport/Samples/QuantitySampleRow.swift b/HealthImport/Samples/QuantitySampleRow.swift new file mode 100644 index 0000000..83f4c40 --- /dev/null +++ b/HealthImport/Samples/QuantitySampleRow.swift @@ -0,0 +1,27 @@ +import SwiftUI +import HealthKitExtensions +import HealthDB + +struct QuantitySampleRow: 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(database: database) + } label: { + Text(title ?? T.quantityTypeIdentifier.description) + } + } +} + +#Preview { + QuantitySampleRow(database: .empty) +} diff --git a/HealthImport/Tabs/SamplesTab.swift b/HealthImport/Tabs/SamplesTab.swift index e9b1c05..c3355fb 100644 --- a/HealthImport/Tabs/SamplesTab.swift +++ b/HealthImport/Tabs/SamplesTab.swift @@ -8,26 +8,73 @@ struct SamplesTab: View { var body: some View { NavigationStack { List { - NavigationLink { - ActivitySampleList() - } label: { - Label("Activity", systemSymbol: .flame) + if let db = database.store { + NavigationLink { + 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") } - Label("Body Measurements", systemSymbol: .figure) - Label("Cycle Tracking", systemSymbol: .circleHexagonpath) - Label("Hearing", systemSymbol: .ear) - Label("Heart", systemSymbol: .heart) - Label("Medications", systemSymbol: .pills) - Label("Mental Wellbeing", systemSymbol: .brainHeadProfile) - Label("Mobility", systemSymbol: .arrowLeftAndRight) - Label("Nutrition", systemSymbol: .carrot) - Label("Respiratory", systemSymbol: .lungs) - Label("Sleep", systemSymbol: .bedDouble) - Label("Symptoms", systemSymbol: .listBulletClipboard) - Label("Vitals", systemSymbol: .waveformPathEcgRectangle) - Label("Other Data", systemSymbol: .cross) - } .navigationTitle("Health") } @@ -35,6 +82,6 @@ struct SamplesTab: View { } #Preview { - SamplesTab(database: Database()) + SamplesTab(database: Database.empty) .preferredColorScheme(.dark) } diff --git a/HealthImport/Tabs/WorkoutTab.swift b/HealthImport/Tabs/WorkoutTab.swift index e0e890b..6430a2b 100644 --- a/HealthImport/Tabs/WorkoutTab.swift +++ b/HealthImport/Tabs/WorkoutTab.swift @@ -146,5 +146,5 @@ struct WorkoutTab: View { #Preview { WorkoutTab() - .environmentObject(Database.mock) + .environmentObject(Database.empty) } diff --git a/HealthImport/Workouts/ActivityDetailView.swift b/HealthImport/Workouts/ActivityDetailView.swift index cdf6dd4..9f82605 100644 --- a/HealthImport/Workouts/ActivityDetailView.swift +++ b/HealthImport/Workouts/ActivityDetailView.swift @@ -120,6 +120,6 @@ struct ActivityDetailView: View { #Preview { NavigationStack { ActivityDetailView(workout: .mock1, activity: .mock1) - .environmentObject(Database.mock) + .environmentObject(Database.empty) } } diff --git a/HealthImport/Workouts/WorkoutDetailView.swift b/HealthImport/Workouts/WorkoutDetailView.swift index e3fb50d..8e2cab6 100644 --- a/HealthImport/Workouts/WorkoutDetailView.swift +++ b/HealthImport/Workouts/WorkoutDetailView.swift @@ -444,7 +444,7 @@ struct WorkoutDetailView: View { #Preview { return NavigationStack { WorkoutDetailView(workout: .mock1) - .environmentObject(Database.mock) + .environmentObject(Database.empty) .preferredColorScheme(.dark) } }