Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Loop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@
1DB1065124467E18005542BD /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1065024467E18005542BD /* AlertManager.swift */; };
1DB1CA4D24A55F0000B3B94C /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1CA4C24A55F0000B3B94C /* Image.swift */; };
1DB619AC270BAD3D006C9D07 /* VersionUpdateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB619AB270BAD3D006C9D07 /* VersionUpdateViewModel.swift */; };
1DD0B76724EC77AC008A2DC3 /* SupportScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */; };
1DDE273D24AEA4B000796622 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1CA4E24A56D7600B3B94C /* SettingsViewModel.swift */; };
1DDE273E24AEA4B000796622 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */; };
1DDE274024AEA4F200796622 /* NotificationsCriticalAlertPermissionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA46B5F2492E2E300D71A63 /* NotificationsCriticalAlertPermissionsView.swift */; };
Expand Down Expand Up @@ -270,6 +269,7 @@
7D7076591FE06EE2004AC8EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D70765B1FE06EE2004AC8EA /* Localizable.strings */; };
7D70765E1FE06EE3004AC8EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D7076601FE06EE3004AC8EA /* Localizable.strings */; };
7D7076631FE06EE4004AC8EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7D7076651FE06EE4004AC8EA /* Localizable.strings */; };
7E69CFFC2A16A77E00203CBD /* ResetLoopManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E69CFFB2A16A77E00203CBD /* ResetLoopManager.swift */; };
891B508524342BE1005DA578 /* CarbAndBolusFlowViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 891B508424342BE1005DA578 /* CarbAndBolusFlowViewModel.swift */; };
892A5D59222F0A27008961AB /* Debug.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D58222F0A27008961AB /* Debug.swift */; };
892A5D692230C41D008961AB /* RangeReplaceableCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892A5D682230C41D008961AB /* RangeReplaceableCollection.swift */; };
Expand Down Expand Up @@ -821,7 +821,6 @@
1DB1CA4E24A56D7600B3B94C /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
1DB619AB270BAD3D006C9D07 /* VersionUpdateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpdateViewModel.swift; sourceTree = "<group>"; };
1DC63E7325351BDF004605DA /* TrueTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TrueTime.framework; path = Carthage/Build/iOS/TrueTime.framework; sourceTree = "<group>"; };
1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportScreenView.swift; sourceTree = "<group>"; };
1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
1DFE9E162447B6270082C280 /* UserNotificationAlertSchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationAlertSchedulerTests.swift; sourceTree = "<group>"; };
4302F4E01D4E9C8900F0FCAF /* TextFieldTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewController.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1254,6 +1253,7 @@
7DD382771F8DBFC60071272B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Main.strings; sourceTree = "<group>"; };
7DD382781F8DBFC60071272B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/MainInterface.strings; sourceTree = "<group>"; };
7DD382791F8DBFC60071272B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Interface.strings; sourceTree = "<group>"; };
7E69CFFB2A16A77E00203CBD /* ResetLoopManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResetLoopManager.swift; sourceTree = "<group>"; };
80F864E52433BF5D0026EC26 /* fi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fi; path = fi.lproj/InfoPlist.strings; sourceTree = "<group>"; };
891B508424342BE1005DA578 /* CarbAndBolusFlowViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbAndBolusFlowViewModel.swift; sourceTree = "<group>"; };
892A5D29222EF60A008961AB /* MockKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = MockKit.framework; path = Carthage/Build/iOS/MockKit.framework; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -2396,7 +2396,6 @@
439706E522D2E84900C81566 /* PredictionSettingTableViewCell.swift */,
1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */,
C1DE5D22251BFC4D00439E49 /* SimpleBolusView.swift */,
1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */,
43F64DD81D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift */,
4311FB9A1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift */,
C1AF062229426300002C1B19 /* ManualGlucoseEntryRow.swift */,
Expand Down Expand Up @@ -2440,6 +2439,7 @@
E9B355232935906B0076AB04 /* Missed Meal Detection */,
C1F2075B26D6F9B0007AB7EB /* ProfileExpirationAlerter.swift */,
A96DAC2B2838F31200D94E38 /* SharedLogging.swift */,
7E69CFFB2A16A77E00203CBD /* ResetLoopManager.swift */,
);
path = Managers;
sourceTree = "<group>";
Expand Down Expand Up @@ -3964,7 +3964,6 @@
43DFB62320D4CAE7008A7BAE /* PumpManager.swift in Sources */,
A9FB75F1252BE320004C7D3F /* BolusDosingDecision.swift in Sources */,
892A5D59222F0A27008961AB /* Debug.swift in Sources */,
1DD0B76724EC77AC008A2DC3 /* SupportScreenView.swift in Sources */,
431A8C401EC6E8AB00823B9C /* CircleMaskView.swift in Sources */,
1D05219D2469F1F5000EBBDE /* AlertStore.swift in Sources */,
439897371CD2F80600223065 /* AnalyticsServicesManager.swift in Sources */,
Expand All @@ -3982,6 +3981,7 @@
C1C660D1252E4DD5009B5C32 /* LoopConstants.swift in Sources */,
432E73CB1D24B3D6009AD15D /* RemoteDataServicesManager.swift in Sources */,
C18913B52524F24C007B0683 /* DeviceDataManager+SimpleBolusViewModelDelegate.swift in Sources */,
7E69CFFC2A16A77E00203CBD /* ResetLoopManager.swift in Sources */,
B40D07C7251A89D500C1C6D7 /* GlucoseDisplay.swift in Sources */,
43C2FAE11EB656A500364AFF /* GlucoseEffectVelocity.swift in Sources */,
);
Expand Down
2 changes: 1 addition & 1 deletion Loop/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider {
func applicationWillEnterForeground(_ application: UIApplication) {
log.default(#function)

loopAppManager.askUserToConfirmCrashIfNecessary()
loopAppManager.askUserToConfirmLoopReset()
}

func applicationWillTerminate(_ application: UIApplication) {
Expand Down
8 changes: 5 additions & 3 deletions Loop/Managers/Alerts/AlertManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -784,14 +784,16 @@ extension AlertManager: AlertPermissionsCheckerDelegate {
}

extension AlertManager {
func presentConfirmCrashAlert(confirmAction: @escaping (@escaping () -> Void) -> Void) {
let alert = UIAlertController(title: "New Study Product Detected", message: "We've detected a new study product is selected. In order to show use this study product, Loop will need to restart.", preferredStyle: .alert)
func presentLoopResetConfirmationAlert(confirmAction: @escaping (@escaping () -> Void) -> Void, cancelAction: @escaping () -> Void) {
let alert = UIAlertController(title: "Loop Reset Requested", message: "We've detected a Loop reset may be needed. Tapping confirm will reset Loop and quit the app.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Confirm", style: .default, handler: { _ in
confirmAction() {
fatalError("DEBUG: Resetting Loop")
}
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
cancelAction()
}))

alertPresenter.present(alert, animated: true)
}
Expand Down
161 changes: 59 additions & 102 deletions Loop/Managers/DeviceDataManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ final class DeviceDataManager {
/// Remember the launch date of the app for diagnostic reporting
private let launchDate = Date()

private(set) var testingScenariosManager: TestingScenariosManager?

/// The last error recorded by a device manager
/// Should be accessed only on the main queue
private(set) var lastError: (date: Date, error: Error)?
Expand Down Expand Up @@ -417,10 +415,6 @@ final class DeviceDataManager {
directory: FileManager.default.exportsDirectoryURL,
historicalDuration: Bundle.main.localCacheDuration)

if FeatureFlags.scenariosEnabled {
testingScenariosManager = LocalTestingScenariosManager(deviceManager: self)
}

loopManager.delegate = self

alertManager.alertStore.delegate = self
Expand Down Expand Up @@ -658,64 +652,6 @@ final class DeviceDataManager {
self.getHealthStoreAuthorization(completion)
}
}

func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) {
self.loopManager.generateDiagnosticReport { (loopReport) in

let logDurationHours = 84.0

self.alertManager.getStoredEntries(startDate: Date() - .hours(logDurationHours)) { (alertReport) in
self.deviceLog.getLogEntries(startDate: Date() - .hours(logDurationHours)) { (result) in
let deviceLogReport: String
switch result {
case .failure(let error):
deviceLogReport = "Error fetching entries: \(error)"
case .success(let entries):
deviceLogReport = entries.map { "* \($0.timestamp) \($0.managerIdentifier) \($0.deviceIdentifier ?? "") \($0.type) \($0.message)" }.joined(separator: "\n")
}

let report = [
"## Build Details",
"* appNameAndVersion: \(Bundle.main.localizedNameAndVersion)",
"* profileExpiration: \(Bundle.main.profileExpirationString)",
"* gitRevision: \(Bundle.main.gitRevision ?? "N/A")",
"* gitBranch: \(Bundle.main.gitBranch ?? "N/A")",
"* workspaceGitRevision: \(Bundle.main.workspaceGitRevision ?? "N/A")",
"* workspaceGitBranch: \(Bundle.main.workspaceGitBranch ?? "N/A")",
"* sourceRoot: \(Bundle.main.sourceRoot ?? "N/A")",
"* buildDateString: \(Bundle.main.buildDateString ?? "N/A")",
"* xcodeVersion: \(Bundle.main.xcodeVersion ?? "N/A")",
"",
"## FeatureFlags",
"\(FeatureFlags)",
"",
alertReport,
"",
"## DeviceDataManager",
"* launchDate: \(self.launchDate)",
"* lastError: \(String(describing: self.lastError))",
"",
"cacheStore: \(String(reflecting: self.cacheStore))",
"",
self.cgmManager != nil ? String(reflecting: self.cgmManager!) : "cgmManager: nil",
"",
self.pumpManager != nil ? String(reflecting: self.pumpManager!) : "pumpManager: nil",
"",
"## Device Communication Log",
deviceLogReport,
"",
String(reflecting: self.watchManager!),
"",
String(reflecting: self.statusExtensionManager!),
"",
loopReport,
].joined(separator: "\n")

completion(report)
}
}
}
}
}

private extension DeviceDataManager {
Expand Down Expand Up @@ -1286,9 +1222,6 @@ extension DeviceDataManager {
}

insulinDeliveryStore.purgeAllDoseEntries(healthKitPredicate: devicePredicate) { error in
if error == nil {
insulinDeliveryStore.test_lastImmutableBasalEndDate = nil
}
completion?(error)
}
}
Expand Down Expand Up @@ -1659,40 +1592,6 @@ fileprivate extension FileManager {
extension GlucoseStore : CGMStalenessMonitorDelegate { }


//MARK: - SupportInfoProvider protocol conformance

extension DeviceDataManager: SupportInfoProvider {

private var branchNameIfNotReleaseBranch: String? {
return Bundle.main.gitBranch.filter { branch in
return branch != "" &&
branch != "main" &&
branch != "master" &&
!branch.starts(with: "release/")
}
}

public var localizedAppNameAndVersion: String {
if let branch = branchNameIfNotReleaseBranch {
return Bundle.main.localizedNameAndVersion + " (\(branch))"
}
return Bundle.main.localizedNameAndVersion
}

public var pumpStatus: PumpManagerStatus? {
return pumpManager?.status
}

public var cgmStatus: CGMManagerStatus? {
return cgmManager?.cgmManagerStatus
}

public func generateIssueReport(completion: @escaping (String) -> Void) {
generateDiagnosticReport(completion)
}

}

//MARK: TherapySettingsViewModelDelegate
struct CancelTempBasalFailedError: LocalizedError {
let reason: Error?
Expand Down Expand Up @@ -1793,8 +1692,66 @@ extension DeviceDataManager {
}
}

extension DeviceDataManager {
extension DeviceDataManager: DeviceSupportDelegate {
var availableSupports: [SupportUI] { [cgmManager, pumpManager].compactMap { $0 as? SupportUI } }

func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) {
self.loopManager.generateDiagnosticReport { (loopReport) in

let logDurationHours = 84.0

self.alertManager.getStoredEntries(startDate: Date() - .hours(logDurationHours)) { (alertReport) in
self.deviceLog.getLogEntries(startDate: Date() - .hours(logDurationHours)) { (result) in
let deviceLogReport: String
switch result {
case .failure(let error):
deviceLogReport = "Error fetching entries: \(error)"
case .success(let entries):
deviceLogReport = entries.map { "* \($0.timestamp) \($0.managerIdentifier) \($0.deviceIdentifier ?? "") \($0.type) \($0.message)" }.joined(separator: "\n")
}

let report = [
"## Build Details",
"* appNameAndVersion: \(Bundle.main.localizedNameAndVersion)",
"* profileExpiration: \(Bundle.main.profileExpirationString)",
"* gitRevision: \(Bundle.main.gitRevision ?? "N/A")",
"* gitBranch: \(Bundle.main.gitBranch ?? "N/A")",
"* workspaceGitRevision: \(Bundle.main.workspaceGitRevision ?? "N/A")",
"* workspaceGitBranch: \(Bundle.main.workspaceGitBranch ?? "N/A")",
"* sourceRoot: \(Bundle.main.sourceRoot ?? "N/A")",
"* buildDateString: \(Bundle.main.buildDateString ?? "N/A")",
"* xcodeVersion: \(Bundle.main.xcodeVersion ?? "N/A")",
"",
"## FeatureFlags",
"\(FeatureFlags)",
"",
alertReport,
"",
"## DeviceDataManager",
"* launchDate: \(self.launchDate)",
"* lastError: \(String(describing: self.lastError))",
"",
"cacheStore: \(String(reflecting: self.cacheStore))",
"",
self.cgmManager != nil ? String(reflecting: self.cgmManager!) : "cgmManager: nil",
"",
self.pumpManager != nil ? String(reflecting: self.pumpManager!) : "pumpManager: nil",
"",
"## Device Communication Log",
deviceLogReport,
"",
String(reflecting: self.watchManager!),
"",
String(reflecting: self.statusExtensionManager!),
"",
loopReport,
].joined(separator: "\n")

completion(report)
}
}
}
}
}

extension DeviceDataManager: DeviceStatusProvider {}
Expand Down
4 changes: 3 additions & 1 deletion Loop/Managers/LocalTestingScenariosManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import OSLog
final class LocalTestingScenariosManager: TestingScenariosManagerRequirements, DirectoryObserver {

unowned let deviceManager: DeviceDataManager
unowned let supportManager: SupportManager

let log = DiagnosticLog(category: "LocalTestingScenariosManager")

Expand All @@ -35,12 +36,13 @@ final class LocalTestingScenariosManager: TestingScenariosManagerRequirements, D
deviceManager.pluginManager
}

init(deviceManager: DeviceDataManager) {
init(deviceManager: DeviceDataManager, supportManager: SupportManager) {
guard FeatureFlags.scenariosEnabled else {
fatalError("\(#function) should be invoked only when scenarios are enabled")
}

self.deviceManager = deviceManager
self.supportManager = supportManager
self.scenariosSource = Bundle.main.bundleURL.appendingPathComponent("Scenarios")

log.debug("Loading testing scenarios from %{public}@", scenariosSource.path)
Expand Down
Loading