Skip to content

Commit 6dad461

Browse files
authored
Merge pull request #568 from tidepool-org/cameron/COASTAL-1246-reset-loop-cleanup
2 parents 4018d8e + 419bb05 commit 6dad461

File tree

5 files changed

+68
-17
lines changed

5 files changed

+68
-17
lines changed

Loop/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider {
4646
func applicationWillEnterForeground(_ application: UIApplication) {
4747
log.default(#function)
4848

49-
loopAppManager.askUserToConfirmCrashIfNecessary()
49+
loopAppManager.askUserToConfirmLoopReset()
5050
}
5151

5252
func applicationWillTerminate(_ application: UIApplication) {

Loop/Managers/Alerts/AlertManager.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -784,14 +784,16 @@ extension AlertManager: AlertPermissionsCheckerDelegate {
784784
}
785785

786786
extension AlertManager {
787-
func presentConfirmCrashAlert(confirmAction: @escaping (@escaping () -> Void) -> Void) {
788-
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, Tidepool Loop will need to restart.", preferredStyle: .alert)
787+
func presentLoopResetConfirmationAlert(confirmAction: @escaping (@escaping () -> Void) -> Void, cancelAction: @escaping () -> Void) {
788+
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)
789789
alert.addAction(UIAlertAction(title: "Confirm", style: .default, handler: { _ in
790790
confirmAction() {
791791
fatalError("DEBUG: Resetting Loop")
792792
}
793793
}))
794-
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel))
794+
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
795+
cancelAction()
796+
}))
795797

796798
alertPresenter.present(alert, animated: true)
797799
}

Loop/Managers/LoopAppManager.swift

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ class LoopAppManager: NSObject {
290290

291291
alertManager.playbackAlertsFromPersistence()
292292

293-
askUserToConfirmCrashIfNecessary()
293+
askUserToConfirmLoopReset()
294294
}
295295

296296
// MARK: - Life Cycle
@@ -400,27 +400,68 @@ class LoopAppManager: NSObject {
400400
return false
401401
}
402402

403-
func askUserToConfirmCrashIfNecessary() {
404-
deviceDataManager.pluginManager.availableSupports.forEach { supportUI in
405-
if supportUI.loopNeedsReset {
406-
alertManager.presentConfirmCrashAlert() { [weak self] completion in
403+
func askUserToConfirmLoopReset() {
404+
if UserDefaults.appGroup?.userRequestedLoopReset == true {
405+
alertManager.presentLoopResetConfirmationAlert(
406+
confirmAction: { [weak self] completion in
407407
guard let pumpManager = self?.deviceDataManager.pumpManager else {
408-
supportUI.resetLoop()
408+
self?.resetLoop()
409409
completion()
410410
return
411411
}
412412

413413
pumpManager.prepareForDeactivation() { [weak self] error in
414414
guard let error = error else {
415-
supportUI.resetLoop()
415+
self?.resetLoop()
416416
completion()
417417
return
418418
}
419419
self?.alertManager.presentCouldNotResetLoopAlert(error: error)
420420
}
421+
},
422+
cancelAction: {
423+
UserDefaults.appGroup?.userRequestedLoopReset = false
421424
}
425+
)
426+
}
427+
}
428+
429+
private func resetLoop() {
430+
deviceDataManager.pluginManager.availableSupports.enumerated().forEach { index, supportUI in
431+
supportUI.loopWillReset()
432+
433+
if index == deviceDataManager.pluginManager.availableSupports.count - 1 {
434+
resetLoopDocuments()
435+
resetLoopUserDefaults()
422436
}
437+
438+
supportUI.loopDidReset()
439+
}
440+
}
441+
442+
private func resetLoopUserDefaults() {
443+
// Store values to persist
444+
let allowDebugFeatures = UserDefaults.appGroup?.allowDebugFeatures
445+
446+
// Wipe away whole domain
447+
UserDefaults.appGroup?.removePersistentDomain(forName: Bundle.main.appGroupSuiteName)
448+
449+
// Restore values to persist
450+
UserDefaults.appGroup?.allowDebugFeatures = allowDebugFeatures ?? false
451+
}
452+
453+
private func resetLoopDocuments() {
454+
guard let directoryURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Bundle.main.appGroupSuiteName) else {
455+
preconditionFailure("Could not get a container directory URL. Please ensure App Groups are set up correctly in entitlements.")
456+
}
457+
458+
let documents: URL = directoryURL.appendingPathComponent("com.loopkit.LoopKit", isDirectory: true)
459+
try? FileManager.default.removeItem(at: documents)
460+
461+
guard let localDocuments = try? FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {
462+
preconditionFailure("Could not get a documents directory URL.")
423463
}
464+
try? FileManager.default.removeItem(at: localDocuments)
424465
}
425466

426467
private var rootViewController: UIViewController? {

LoopCore/NSUserDefaults.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extension UserDefaults {
2121
case allowDebugFeatures = "com.loopkit.Loop.allowDebugFeatures"
2222
case allowSimulators = "com.loopkit.Loop.allowSimulators"
2323
case LastMissedMealNotification = "com.loopkit.Loop.lastMissedMealNotification"
24+
case userRequestedLoopReset = "com.loopkit.Loop.userRequestedLoopReset"
2425
}
2526

2627
public static let appGroup = UserDefaults(suiteName: Bundle.main.appGroupSuiteName)
@@ -150,6 +151,15 @@ extension UserDefaults {
150151
public var allowSimulators: Bool {
151152
return bool(forKey: Key.allowSimulators.rawValue)
152153
}
154+
155+
public var userRequestedLoopReset: Bool {
156+
get {
157+
bool(forKey: Key.userRequestedLoopReset.rawValue)
158+
}
159+
set {
160+
setValue(newValue, forKey: Key.userRequestedLoopReset.rawValue)
161+
}
162+
}
153163

154164
public func removeLegacyLoopSettings() {
155165
removeObject(forKey: "com.loudnate.Naterade.BasalRateSchedule")

LoopTests/Managers/SupportManagerTests.swift

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ class SupportManagerTests: XCTestCase {
4040
required init?(rawState: RawStateValue) { super.init() }
4141
var rawState: RawStateValue = [:]
4242

43-
var loopNeedsReset: Bool = false
44-
var studyProductSelection: String? = nil
4543
func getScenarios(from scenarioURLs: [URL]) -> [LoopScenario] { [] }
46-
func resetLoop() {}
44+
func loopWillReset() {}
45+
func loopDidReset() {}
4746
}
4847
class AnotherMockSupport: Mixin, SupportUI {
4948
func configurationMenuItems() -> [AnyView] { return [] }
@@ -52,10 +51,9 @@ class SupportManagerTests: XCTestCase {
5251
required init?(rawState: RawStateValue) { super.init() }
5352
var rawState: RawStateValue = [:]
5453

55-
var loopNeedsReset: Bool = false
56-
var studyProductSelection: String? = nil
5754
func getScenarios(from scenarioURLs: [URL]) -> [LoopScenario] { [] }
58-
func resetLoop() {}
55+
func loopWillReset() {}
56+
func loopDidReset() {}
5957
}
6058

6159
class MockAlertIssuer: AlertIssuer {

0 commit comments

Comments
 (0)