Skip to content

Commit db4328f

Browse files
author
Darin Krauss
authored
LOOP-1201 Export of Critical Event Logs (#254)
- https://tidepool.atlassian.net/browse/LOOP-1201 - Replace StoredSettings.InsulinModel with StoredInsulinModel - Implement Codable StoredDosingDecision.NotificationSettings - Add ZipArchive - Add CriticalEventLogExportManager - Add CriticalEventLogExportView and CriticalEventLogExportViewModel - Add Checkmark image for successful critical event log export - Add minizip dependency
1 parent 18be4cf commit db4328f

34 files changed

+2863
-167
lines changed

Cartfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ github "LoopKit/G4ShareSpy" "merge-from-tidepool"
66
github "ps2/rileylink_ios" "merge-from-tidepool"
77
github "LoopKit/Amplitude-iOS" "decreepify"
88
github "LoopKit/MKRingProgressView" "appex-safe"
9+
github "dexman/Minizip" "master"

Cartfile.resolved

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ github "LoopKit/MKRingProgressView" "f548a5c64832be2d37d7c91b5800e284887a2a0a"
66
github "LoopKit/dexcom-share-client-swift" "e59763001a100816761e3480697c228fc2cefa27"
77
github "i-schuetz/SwiftCharts" "0.6.5"
88
github "ps2/rileylink_ios" "7876b86701bb9ba4703be0a37af6cbb0c04e21f0"
9+
github "dexman/Minizip" "6be834b517aedb2b3b51e997a1244af738bb41f8"

Common/Extensions/NSBundle.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,10 @@ extension Bundle {
7070
return object(forInfoDictionaryKey: "com-loopkit-Loop-xcode-version") as? String
7171
}
7272

73-
var localCacheDuration: TimeInterval? {
73+
var localCacheDuration: TimeInterval {
7474
guard let localCacheDurationDaysString = object(forInfoDictionaryKey: "LoopLocalCacheDurationDays") as? String,
7575
let localCacheDurationDays = Double(localCacheDurationDaysString) else {
76-
return nil
76+
return .days(1)
7777
}
7878
return .days(localCacheDurationDays)
7979
}

Learn/Managers/DataManager.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ final class DataManager {
4040
observationInterval: 0,
4141
carbRatioSchedule: carbRatioSchedule,
4242
insulinSensitivitySchedule: insulinSensitivitySchedule,
43-
provenanceIdentifier: Bundle.main.bundleIdentifier!
43+
provenanceIdentifier: HKSource.default().bundleIdentifier
4444
)
4545

4646
doseStore = DoseStore(

Loop.xcodeproj/project.pbxproj

Lines changed: 50 additions & 6 deletions
Large diffs are not rendered by default.

Loop/AppDelegate.swift

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, DeviceOrientationCo
5858
UIDevice.current.isBatteryMonitoringEnabled = true
5959

6060
bluetoothStateManager = BluetoothStateManager()
61-
alertManager = AlertManager(rootViewController: rootViewController, expireAfter: Bundle.main.localCacheDuration ?? .days(1))
61+
alertManager = AlertManager(rootViewController: rootViewController, expireAfter: Bundle.main.localCacheDuration)
6262
deviceDataManager = DeviceDataManager(pluginManager: pluginManager, alertManager: alertManager, bluetoothStateManager: bluetoothStateManager, rootViewController: rootViewController)
6363

6464
let statusTableViewController = UIStoryboard(name: "Main", bundle: Bundle(for: AppDelegate.self)).instantiateViewController(withIdentifier: "MainStatusViewController") as! StatusTableViewController
@@ -86,6 +86,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, DeviceOrientationCo
8686
deviceDataManager?.handleRemoteNotification(notification)
8787
}
8888

89+
scheduleBackgroundTasks()
90+
8991
launchOptions = nil
9092
}
9193

@@ -95,6 +97,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, DeviceOrientationCo
9597

9698
log.default("didFinishLaunchingWithOptions %{public}@", String(describing: launchOptions))
9799

100+
registerBackgroundTasks()
101+
98102
guard isAfterFirstUnlock() else {
99103
log.default("Launching before first unlock; pausing launch...")
100104
return false
@@ -103,7 +107,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, DeviceOrientationCo
103107
finishLaunch(application: application)
104108

105109
window?.tintColor = .loopAccent
106-
110+
107111
return true
108112
}
109113

@@ -190,6 +194,20 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, DeviceOrientationCo
190194
func application(_ application: UIApplication, supportedInterfaceOrientationsFor window: UIWindow?) -> UIInterfaceOrientationMask {
191195
supportedInterfaceOrientations
192196
}
197+
198+
// MARK: - Background Tasks
199+
200+
private func registerBackgroundTasks() {
201+
if DeviceDataManager.registerCriticalEventLogHistoricalExportBackgroundTask({ self.deviceDataManager.handleCriticalEventLogHistoricalExportBackgroundTask($0) }) {
202+
log.debug("Critical event log export background task registered")
203+
} else {
204+
log.error("Critical event log export background task not registered")
205+
}
206+
}
207+
208+
private func scheduleBackgroundTasks() {
209+
deviceDataManager.scheduleCriticalEventLogHistoricalExportBackgroundTask()
210+
}
193211
}
194212

195213
// MARK: UNUserNotificationCenterDelegate implementation

Loop/Extensions/CarbStore+SimulatedCoreData.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@ extension CarbStore {
6262

6363
fileprivate extension NewCarbEntry {
6464
static func simulated(startDate: Date, grams: Double, absorptionTime: TimeInterval) -> NewCarbEntry {
65-
return NewCarbEntry(quantity: HKQuantity(unit: .gram(), doubleValue: grams),
65+
return NewCarbEntry(date: startDate,
66+
quantity: HKQuantity(unit: .gram(), doubleValue: grams),
6667
startDate: startDate,
6768
foodType: "Simulated",
6869
absorptionTime: absorptionTime)

Loop/Extensions/DosingDecisionStore+SimulatedCoreData.swift

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,18 @@ fileprivate extension StoredDosingDecision {
124124
pumpBatteryChargeRemaining: 3.5,
125125
basalDeliveryState: .initiatingTempBasal,
126126
bolusState: .none)
127+
let notificationSettings = NotificationSettings(authorizationStatus: .authorized,
128+
soundSetting: .enabled,
129+
badgeSetting: .enabled,
130+
alertSetting: .enabled,
131+
notificationCenterSetting: .enabled,
132+
lockScreenSetting: .enabled,
133+
carPlaySetting: .enabled,
134+
alertStyle: .banner,
135+
showPreviewsSetting: .always,
136+
criticalAlertSetting: .enabled,
137+
providesAppNotificationSettings: true,
138+
announcementSetting: .enabled)
127139
let deviceSettings = StoredDosingDecision.DeviceSettings(name: "Device Name",
128140
systemName: "Device System Name",
129141
systemVersion: "Device System Version",
@@ -144,19 +156,9 @@ fileprivate extension StoredDosingDecision {
144156
recommendedTempBasal: recommendedTempBasal,
145157
recommendedBolus: recommendedBolus,
146158
pumpManagerStatus: pumpManagerStatus,
147-
notificationSettings: historicalNotificationSettings,
159+
notificationSettings: notificationSettings,
148160
deviceSettings: deviceSettings,
149161
errors: nil,
150162
syncIdentifier: UUID().uuidString)
151163
}
152164
}
153-
154-
fileprivate let historicalNotificationSettingsBase64 = "YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMSAAGGoF8QD05TS2V" +
155-
"5ZWRBcmNoaXZlctEICVRyb290gAGjCwwgVSRudWxs3g0ODxAREhMUFRYXGBkaGxsbGxscHBwdHhsfHBtcYmFkZ2VTZXR0aW5nXxATYXV0aG9yaXphdGlvblN0YXR" +
156-
"1c1xzb3VuZFNldHRpbmdfEBlub3RpZmljYXRpb25DZW50ZXJTZXR0aW5nXxAUY3JpdGljYWxBbGVydFNldHRpbmdfEBNzaG93UHJldmlld3NTZXR0aW5nXxAPZ3J" +
157-
"vdXBpbmdTZXR0aW5nXmNhclBsYXlTZXR0aW5nXxAfcHJvdmlkZXNBcHBOb3RpZmljYXRpb25TZXR0aW5nc1YkY2xhc3NfEBFsb2NrU2NyZWVuU2V0dGluZ1phbGV" +
158-
"ydFN0eWxlXxATYW5ub3VuY2VtZW50U2V0dGluZ1xhbGVydFNldHRpbmcQAhAACIACEAHSISIjJFokY2xhc3NuYW1lWCRjbGFzc2VzXxAWVU5Ob3RpZmljYXRpb25" +
159-
"TZXR0aW5nc6IlJl8QFlVOTm90aWZpY2F0aW9uU2V0dGluZ3NYTlNPYmplY3QACAARABoAJAApADIANwBJAEwAUQBTAFcAXQB6AIcAnQCqAMYA3QDzAQUBFAE2AT0" +
160-
"BUQFcAXIBfwGBAYMBhAGGAYgBjQGYAaEBugG9AdYAAAAAAAACAQAAAAAAAAAnAAAAAAAAAAAAAAAAAAAB3w=="
161-
fileprivate let historicalNotificationSettingsData = Data(base64Encoded: historicalNotificationSettingsBase64)!
162-
fileprivate let historicalNotificationSettings = try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(historicalNotificationSettingsData) as! UNNotificationSettings

Loop/Extensions/OutputStream.swift

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//
2+
// OutputStream.swift
3+
// Loop
4+
//
5+
// Created by Darin Krauss on 8/28/20.
6+
// Copyright © 2020 LoopKit Authors. All rights reserved.
7+
//
8+
9+
import Foundation
10+
11+
extension OutputStream {
12+
func write(_ string: String) throws {
13+
if let streamError = streamError {
14+
throw streamError
15+
}
16+
let bytes = [UInt8](string.utf8)
17+
write(bytes, maxLength: bytes.count)
18+
if let streamError = streamError {
19+
throw streamError
20+
}
21+
}
22+
23+
func write(_ data: Data) throws {
24+
if let streamError = streamError {
25+
throw streamError
26+
}
27+
if data.isEmpty {
28+
return
29+
}
30+
_ = data.withUnsafeBytes { (unsafeRawBuffer: UnsafeRawBufferPointer) -> UInt8 in
31+
if let unsafe = unsafeRawBuffer.baseAddress?.assumingMemoryBound(to: UInt8.self) {
32+
write(unsafe, maxLength: unsafeRawBuffer.count)
33+
}
34+
return 0
35+
}
36+
if let streamError = streamError {
37+
throw streamError
38+
}
39+
}
40+
}

Loop/Extensions/SettingsStore+SimulatedCoreData.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ fileprivate extension StoredSettings {
122122
maximumBolus: 10.0,
123123
suspendThreshold: GlucoseThreshold(unit: .milligramsPerDeciliter, value: 75.0),
124124
deviceToken: UUID().uuidString,
125-
insulinModel: StoredSettings.InsulinModel(modelType: .rapidAdult, actionDuration: .hours(6), peakActivity: .hours(3)),
125+
insulinModel: StoredInsulinModel(modelType: .rapidAdult, actionDuration: .hours(6), peakActivity: .hours(3)),
126126
basalRateSchedule: basalRateSchedule,
127127
insulinSensitivitySchedule: insulinSensitivitySchedule,
128128
carbRatioSchedule: carbRatioSchedule,

0 commit comments

Comments
 (0)