Update dependency
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
import SwiftUI
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import CoreLocation
|
||||
|
||||
struct ActivityDetailView: View {
|
||||
|
||||
@EnvironmentObject
|
||||
var database: HealthDatabase
|
||||
var database: Database
|
||||
|
||||
let workout: Workout
|
||||
|
||||
@@ -91,6 +91,6 @@ struct ActivityDetailView: View {
|
||||
#Preview {
|
||||
NavigationStack {
|
||||
ActivityDetailView(workout: .mock1, activity: .mock1)
|
||||
.environmentObject(HealthDatabase.mock)
|
||||
.environmentObject(Database.mock)
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import SwiftUI
|
||||
import OrderedCollections
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
|
||||
struct ActivitySamplesView: View {
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import SwiftUI
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import SFSafeSymbols
|
||||
|
||||
private enum TabSelection: Int {
|
||||
@@ -12,7 +12,7 @@ private enum TabSelection: Int {
|
||||
struct HealthImportApp: App {
|
||||
|
||||
@State
|
||||
var database = HealthDatabase()
|
||||
var database = Database()
|
||||
|
||||
@State
|
||||
private var selection: TabSelection = .databases
|
||||
|
@@ -1,15 +1,15 @@
|
||||
import Foundation
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
|
||||
final class HealthDatabase: ObservableObject {
|
||||
final class Database: ObservableObject {
|
||||
|
||||
@Published
|
||||
var store: HKDatabaseStoreWrapper? = nil
|
||||
var store: HealthDatabase? = nil
|
||||
|
||||
@Published
|
||||
var file: DatabaseFile? = nil
|
||||
|
||||
init(store: HKDatabaseStoreWrapper? = nil) {
|
||||
init(store: HealthDatabase? = nil) {
|
||||
self.store = store
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ final class HealthDatabase: ObservableObject {
|
||||
}
|
||||
close()
|
||||
do {
|
||||
let store = try HKDatabaseStoreWrapper(fileUrl: database.url)
|
||||
let store = try HealthDatabase(fileUrl: database.url)
|
||||
DispatchQueue.main.async {
|
||||
self.store = store
|
||||
self.file = database
|
||||
|
@@ -1,23 +1,23 @@
|
||||
import Foundation
|
||||
import SQLite
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
|
||||
extension HealthDatabase {
|
||||
extension Database {
|
||||
|
||||
private static let databaseFileUrl = Bundle.main.url(forResource: "healthdb_secure", withExtension: "sqlite")
|
||||
|
||||
static var mock: HealthDatabase {
|
||||
let bundleUrl = HealthDatabase.databaseFileUrl!
|
||||
static var mock: Database {
|
||||
let bundleUrl = Database.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! HKDatabaseStoreWrapper(fileUrl: local)
|
||||
let store = try! HealthDatabase(fileUrl: local)
|
||||
return .init(store: store)
|
||||
}
|
||||
|
||||
static var empty: HealthDatabase {
|
||||
static var empty: Database {
|
||||
|
||||
do {
|
||||
let connection = try Connection(.inMemory)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import Foundation
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
import HealthKit
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import Foundation
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
|
||||
extension Workout {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import Foundation
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
|
||||
private let df: DateFormatter = {
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import SwiftUI
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import SFSafeSymbols
|
||||
|
||||
struct DatabasesTab: View {
|
||||
|
||||
@ObservedObject
|
||||
var database: HealthDatabase
|
||||
var database: Database
|
||||
|
||||
@ObservedObject
|
||||
var databases: DatabaseList
|
||||
@@ -160,5 +160,5 @@ struct DatabasesTab: View {
|
||||
}
|
||||
|
||||
#Preview {
|
||||
DatabasesTab(database: HealthDatabase(), databases: .init())
|
||||
DatabasesTab(database: Database(), databases: .init())
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import SwiftUI
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import SFSafeSymbols
|
||||
|
||||
struct WorkoutTab: View {
|
||||
|
||||
@EnvironmentObject
|
||||
var database: HealthDatabase
|
||||
var database: Database
|
||||
|
||||
@State var navigationPath: NavigationPath = .init()
|
||||
|
||||
@@ -80,7 +80,7 @@ struct WorkoutTab: View {
|
||||
|
||||
#Preview {
|
||||
WorkoutTab()
|
||||
.environmentObject(HealthDatabase.mock)
|
||||
.environmentObject(Database.mock)
|
||||
}
|
||||
|
||||
/*
|
||||
|
@@ -4,7 +4,7 @@ import HealthKitExtensions
|
||||
|
||||
func insertExamplesOfAllTypes() async throws {
|
||||
|
||||
let store = HKHealthStore()
|
||||
let store = HealthStore()
|
||||
|
||||
guard try await requestAllPermissions(in: store) else {
|
||||
return
|
||||
@@ -16,7 +16,7 @@ func insertExamplesOfAllTypes() async throws {
|
||||
try await insertQuantityTypes(in: store, startDate: &startDate)
|
||||
}
|
||||
|
||||
func requestAllPermissions(in store: HKHealthStore) async throws -> Bool {
|
||||
func requestAllPermissions(in store: HealthStore) async throws -> Bool {
|
||||
|
||||
let writable: [HKSampleContainer.Type] = HKQuantityType.writableTypes + HKCorrelationType.writableTypes + HKCategoryType.writableTypes
|
||||
let readable: [HKObjectContainer.Type] = HKQuantityType.readableTypes + HKCorrelationType.readableTypes + HKCategoryType.readableTypes
|
||||
@@ -25,7 +25,7 @@ func requestAllPermissions(in store: HKHealthStore) async throws -> Bool {
|
||||
|
||||
var hasAllPermissions = true
|
||||
writable.forEach {
|
||||
if store.authorizationStatus(for: $0.objectType) != .sharingAuthorized {
|
||||
if store.authorizationStatus(for: $0) != .sharingAuthorized {
|
||||
print("Missing permission for \($0.objectType)")
|
||||
hasAllPermissions = false
|
||||
}
|
||||
@@ -33,7 +33,7 @@ func requestAllPermissions(in store: HKHealthStore) async throws -> Bool {
|
||||
return hasAllPermissions
|
||||
}
|
||||
|
||||
private func insertCategoryTypes(in store: HKHealthStore, startDate: inout Date) async throws {
|
||||
private func insertCategoryTypes(in store: HealthStore, startDate: inout Date) async throws {
|
||||
|
||||
func make<T>(convert: (Date, Date) -> T) -> T where T: HKObjectContainer {
|
||||
let result = convert(startDate, startDate.addingTimeInterval(1))
|
||||
@@ -101,7 +101,7 @@ private func insertCategoryTypes(in store: HKHealthStore, startDate: inout Date)
|
||||
print("Done.")
|
||||
}
|
||||
|
||||
private func insertQuantityTypes(in store: HKHealthStore, startDate: inout Date) async throws {
|
||||
private func insertQuantityTypes(in store: HealthStore, startDate: inout Date) async throws {
|
||||
|
||||
func make<T>(convert: (Date, Date) -> T) -> T where T: HKObjectContainer {
|
||||
let result = convert(startDate, startDate.addingTimeInterval(1))
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import SwiftUI
|
||||
import Collections
|
||||
import HealthKit
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import HealthKitExtensions
|
||||
import CoreLocation
|
||||
|
||||
struct WorkoutDetailView: View {
|
||||
|
||||
@EnvironmentObject
|
||||
var database: HealthDatabase
|
||||
var database: Database
|
||||
|
||||
private let store = HKHealthStore()
|
||||
private let store = HealthStore()
|
||||
|
||||
let workout: Workout
|
||||
|
||||
@@ -119,15 +119,15 @@ struct WorkoutDetailView: View {
|
||||
|
||||
private func checkPermissionsAndFindWorkout() async throws {
|
||||
|
||||
switch store.authorizationStatus(for: .workoutType()) {
|
||||
switch store.authorizationStatus(for: HKWorkout.self) {
|
||||
case .notDetermined:
|
||||
try await requestWorkoutPermission()
|
||||
try await checkPermissionsAndFindWorkout()
|
||||
case .sharingAuthorized:
|
||||
findWorkoutInHealth()
|
||||
await findWorkoutInHealth()
|
||||
case .sharingDenied:
|
||||
print("No permission to write workouts")
|
||||
findWorkoutInHealth()
|
||||
await findWorkoutInHealth()
|
||||
return
|
||||
@unknown default:
|
||||
print("Unknown permission for workouts")
|
||||
@@ -139,76 +139,33 @@ struct WorkoutDetailView: View {
|
||||
try await store.requestAuthorization(read: HKWorkout.self)
|
||||
}
|
||||
|
||||
private func findWorkoutInHealth() {
|
||||
private func findWorkoutInHealth() async {
|
||||
guard let activityType = workout.workoutActivities.first?.workoutConfiguration.activityType else {
|
||||
print("No activity type to find workout")
|
||||
return
|
||||
}
|
||||
|
||||
let start = workout.startDate.addingTimeInterval(-60)
|
||||
let end = workout.endDate.addingTimeInterval(60)
|
||||
let workoutPredicate = HKQuery.predicateForWorkouts(with: activityType)
|
||||
let timePredicate = HKQuery.predicateForSamples(withStart: start, end: end)
|
||||
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [workoutPredicate, timePredicate])
|
||||
let sortDescriptor = NSSortDescriptor(
|
||||
key: HKSampleSortIdentifierEndDate,
|
||||
ascending: true)
|
||||
guard let workout = try? await store.workouts(activityType: activityType, from: start, to: end)
|
||||
.first else {
|
||||
print("No workout found or error")
|
||||
return
|
||||
}
|
||||
|
||||
let query = HKSampleQuery(
|
||||
sampleType: .workoutType(),
|
||||
predicate: predicate,
|
||||
limit: 0,
|
||||
sortDescriptors: [sortDescriptor]) { _, samples, error in
|
||||
if let error {
|
||||
print("Failed to search for workout: \(error)")
|
||||
}
|
||||
guard let workout = samples?.first as? HKWorkout else {
|
||||
print("No suitable workout found: \(samples?.count ?? 0)")
|
||||
return
|
||||
}
|
||||
foundHealthStore(workout: workout)
|
||||
}
|
||||
|
||||
store.execute(query)
|
||||
}
|
||||
|
||||
private func foundHealthStore(workout: HKWorkout) {
|
||||
print("Found matching workout in health")
|
||||
DispatchQueue.main.async {
|
||||
self.healthWorkout = workout
|
||||
}
|
||||
findHealthStoreHeartRates(for: workout)
|
||||
}
|
||||
|
||||
private func findHealthStoreHeartRates(for workout: HKWorkout) {
|
||||
let forWorkout = HKQuery.predicateForObjects(from: workout)
|
||||
let heartRate = HKQuantityType(.heartRate)
|
||||
|
||||
let heartRateDescriptor = HKQueryDescriptor(
|
||||
sampleType: heartRate,
|
||||
predicate: forWorkout)
|
||||
|
||||
let heartRateQuery = HKSampleQuery(
|
||||
queryDescriptors: [heartRateDescriptor],
|
||||
limit: HKObjectQueryNoLimit)
|
||||
{ query, samples, error in
|
||||
if let error {
|
||||
print("Failed to search for heart rates: \(error)")
|
||||
do {
|
||||
let heartRates: [HeartRate] = try await store.samples(associatedWith: workout)
|
||||
print("Found \(heartRates.count) heart rate samples in Health")
|
||||
DispatchQueue.main.async {
|
||||
self.heartRateSamplesInHealth = heartRates
|
||||
}
|
||||
guard let samples else {
|
||||
print("No heart rate samples found in Health")
|
||||
return
|
||||
}
|
||||
let heartRates = samples.map { HeartRate(sample: $0) }
|
||||
processHealthStore(heartRateSamples: heartRates)
|
||||
}
|
||||
|
||||
store.execute(heartRateQuery)
|
||||
}
|
||||
|
||||
private func processHealthStore(heartRateSamples: [HeartRate]) {
|
||||
print("Found \(heartRateSamples.count) heart rate samples in Health")
|
||||
DispatchQueue.main.async {
|
||||
self.heartRateSamplesInHealth = heartRateSamples
|
||||
} catch {
|
||||
print("Failed to get heart rates for workout: \(error)")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,7 +173,7 @@ struct WorkoutDetailView: View {
|
||||
#Preview {
|
||||
return NavigationStack {
|
||||
WorkoutDetailView(workout: .mock1)
|
||||
.environmentObject(HealthDatabase.mock)
|
||||
.environmentObject(Database.mock)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import SwiftUI
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
import HealthKit
|
||||
|
||||
struct WorkoutEventsView: View {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import SwiftUI
|
||||
import HKDatabase
|
||||
import HealthDB
|
||||
|
||||
struct WorkoutMetadataView: View {
|
||||
|
||||
|
Reference in New Issue
Block a user