-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathActivityCollector.swift
More file actions
146 lines (119 loc) · 4.85 KB
/
Copy pathActivityCollector.swift
File metadata and controls
146 lines (119 loc) · 4.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//
// ActivityCollector.swift
// C3PRO
//
// Created by Pascal Pfiffner on 15/07/16.
// Copyright © 2016 University Hospital Zurich. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
import SMART
/**
Class that uses both `HealthKitReporter` and `CoreMotionReporter` to retrieve activity data from both stores.
See [HealthKit/README.md](https://github.com/C3-PRO/c3-pro-ios-framework/tree/master/Sources/HealthKit#activity-reporter) for detailed instructions.
*/
open class ActivityCollector: ActivityReporter {
var hkReporter: HealthKitReporter?
var cmReporter: CoreMotionReporter?
/// Path to the CoreMotionReporter local data store; you usually place this in ~/Library.
open let cmPath: String
/// The CoreMotionActivityInterpreter to use to interpret core motion activity sampled by the receiver.
open let cmInterpreter: CoreMotionActivityInterpreter?
/**
Designated initializer.
- parameter coreMotionDBPath: The path to the local CoreMotion database, as used by `CoreMotionReporter`
- parameter coreMotionInterpreter: The core motion activity interpreter to use; uses `CoreMotionReporter` itself if nil
*/
public init(coreMotionDBPath: String, coreMotionInterpreter: CoreMotionActivityInterpreter?) {
cmPath = coreMotionDBPath
cmInterpreter = coreMotionInterpreter
}
// MARK: - Activity Resource Reporting
/**
Creates a `QuestionnaireResponse` resource containing all activities of the past x days.
- parameter ofLastDays: The number of days before today to start on
- parameter callback: The callback to call when all activities are retrieved
*/
open func resourceForAllActivity(ofLastDays days: Int = 7, callback: @escaping ((QuestionnaireResponse?, Error?) -> Void)) {
let end = Date()
var comps = DateComponents()
comps.day = -1 * days
let start = Calendar.current.date(byAdding: comps, to: end)!
resourceForAllActivity(startingAt: start, until: end, callback: callback)
}
/**
Creates a `QuestionnaireResponse` resource for all activity that was reported in the given period.
- parameter startingAt: The start date
- parameter until: The end date
- parameter callback: The callback to call when all activities are retrieved
*/
open func resourceForAllActivity(startingAt start: Date, until: Date, callback: @escaping ((QuestionnaireResponse?, Error?) -> Void)) {
reportForActivityPeriod(startingAt: start, until: until) { report, error in
do {
let answer = try report?.asQuestionnaireResponse(linkId: "org.chip.c3-pro.activity")
callback(answer, error)
}
catch let error {
c3_logIfDebug("Failed to create response resource: \(error)")
callback(nil, error)
}
}
}
// MARK: - Reporting
/**
Collect activities from HealthKit and CoreMotion over the given period.
- parameter startingAt: The start date
- parameter until: The end date
- parameter callback: The callback to call when all activities are retrieved
*/
open func reportForActivityPeriod(startingAt start: Date, until: Date, callback: @escaping ((ActivityReportPeriod?, Error?) -> Void)) {
let queueGroup = DispatchGroup()
var errors = [Error]()
// motion co-processor data
queueGroup.enter()
var cmReport: ActivityReportPeriod?
let cm = cmReporter ?? CoreMotionReporter(path: cmPath)
cmReporter = cm
cm.reportForActivityPeriod(startingAt: start, until: until, interpreter: cmInterpreter) { report, error in // TODO: handle interpreter with protocols
cmReport = report
if let error = error {
errors.append(error)
}
queueGroup.leave()
}
// HealthKit data
queueGroup.enter()
var hkReport: ActivityReportPeriod?
let hk = hkReporter ?? HealthKitReporter()
hkReporter = hk
hk.reportForActivityPeriod(startingAt: start, until: until) { report, error in
hkReport = report
if let error = error {
errors.append(error)
}
queueGroup.leave()
}
// some FHIR preparations while we wait
let period = Period()
period.start = start.fhir_asDateTime()
period.end = until.fhir_asDateTime()
// put both reports into one
queueGroup.notify(queue: DispatchQueue.main) {
let period = ActivityReportPeriod(period: period)
period.coreMotionActivities = cmReport?.coreMotionActivities
period.healthKitSamples = hkReport?.healthKitSamples
callback(period, (errors.count > 0) ? C3Error.multipleErrors(errors) : nil)
}
}
}