forked from LoopKit/LoopKit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMockSupport.swift
166 lines (133 loc) · 6.34 KB
/
MockSupport.swift
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
//
// MockSupport.swift
// MockKitUI
//
// Created by Rick Pasetto on 10/13/21.
// Copyright © 2021 LoopKit Authors. All rights reserved.
//
import Foundation
import LoopKit
import LoopKitUI
import SwiftUI
public class MockSupport: SupportUI {
public static let pluginIdentifier = "MockSupport"
var versionUpdate: VersionUpdate?
var alertIssuer: AlertIssuer? {
return self.delegate
}
var lastVersionCheckAlertDate: Date?
public init() { }
public required init?(rawState: RawStateValue) {
lastVersionCheckAlertDate = rawState["lastVersionCheckAlertDate"] as? Date
}
public var rawState: RawStateValue {
var rawValue: RawStateValue = [:]
rawValue["lastVersionCheckAlertDate"] = lastVersionCheckAlertDate
return rawValue
}
public func checkVersion(bundleIdentifier: String, currentVersion: String) async -> VersionUpdate? {
maybeIssueAlert(versionUpdate ?? .noUpdateNeeded)
return versionUpdate
}
public weak var delegate: SupportUIDelegate?
public func configurationMenuItems() -> [LoopKitUI.CustomMenuItem] {
return []
}
@ViewBuilder
public func supportMenuItem(supportInfoProvider: SupportInfoProvider, urlHandler: @escaping (URL) -> Void) -> some View {
SupportMenuItem(mockSupport: self)
}
public func softwareUpdateView(bundleIdentifier: String, currentVersion: String, guidanceColors: GuidanceColors, openAppStore: (() -> Void)?) -> AnyView? {
return AnyView(
Button("versionUpdate: \(versionUpdate!.localizedDescription)\n\nbundleIdentifier: \(bundleIdentifier)\n\ncurrentVersion: \(currentVersion)") {
openAppStore?()
}
)
}
public func getScenarios(from scenarioURLs: [URL]) -> [LoopScenario] {
scenarioURLs.map { LoopScenario(name: $0.lastPathComponent, url: $0) }
}
public func loopWillReset() {}
public func loopDidReset() {}
}
extension MockSupport {
var alertCadence: TimeInterval {
return TimeInterval.minutes(1)
}
private var appName: String {
return Bundle.main.object(forInfoDictionaryKey: "CFBundleDisplayName") as! String
}
private func maybeIssueAlert(_ versionUpdate: VersionUpdate) {
guard versionUpdate >= .recommended else {
noAlertNecessary()
return
}
let alertIdentifier = Alert.Identifier(managerIdentifier: MockSupport.pluginIdentifier, alertIdentifier: versionUpdate.rawValue)
let alertContent: LoopKit.Alert.Content
if firstAlert {
alertContent = Alert.Content(title: versionUpdate.localizedDescription,
body: String(format: LocalizedString("""
Your %1$@ app is out of date. It will continue to work, but we recommend updating to the latest version.
Go to %2$@ Settings > Software Update to complete.
""", comment: "Alert content body for first software update alert (1: app name)(2: app name)"), appName, appName),
acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Default acknowledgement"))
} else if let lastVersionCheckAlertDate = lastVersionCheckAlertDate,
abs(lastVersionCheckAlertDate.timeIntervalSinceNow) > alertCadence {
alertContent = Alert.Content(title: LocalizedString("Update Reminder", comment: "Recurring software update alert title"),
body: String(format: LocalizedString("""
A software update is recommended to continue using the %1$@ app.
Go to %2$@ Settings > Software Update to install the latest version.
""", comment: "Alert content body for recurring software update alert"), appName, appName),
acknowledgeActionButtonLabel: LocalizedString("OK", comment: "Default acknowledgement"))
} else {
return
}
let interruptionLevel: LoopKit.Alert.InterruptionLevel = versionUpdate == .required ? .critical : .active
alertIssuer?.issueAlert(Alert(identifier: alertIdentifier, foregroundContent: alertContent, backgroundContent: alertContent, trigger: .immediate, interruptionLevel: interruptionLevel))
recordLastAlertDate()
}
private func noAlertNecessary() {
lastVersionCheckAlertDate = nil
}
private var firstAlert: Bool {
return lastVersionCheckAlertDate == nil
}
private func recordLastAlertDate() {
lastVersionCheckAlertDate = Date()
}
}
struct SupportMenuItem : View {
let mockSupport: MockSupport
@State var showActionSheet: Bool = false
private var buttons: [ActionSheet.Button] {
VersionUpdate.allCases.map { versionUpdate in
let setter = { mockSupport.versionUpdate = versionUpdate }
switch versionUpdate {
case .required:
return ActionSheet.Button.destructive(Text(versionUpdate.localizedDescription), action: setter)
default:
return ActionSheet.Button.default(Text(versionUpdate.localizedDescription), action: setter)
}
} +
[.cancel(Text("Cancel"))]
}
private var actionSheet: ActionSheet {
ActionSheet(title: Text("Version Check Response"), message: Text("How should the simulator respond to a version check?"), buttons: buttons)
}
var body: some View {
Button(action: {
self.showActionSheet.toggle()
}) {
Text("Mock Version Check \(currentVersionUpdate)")
}
.actionSheet(isPresented: $showActionSheet, content: {
self.actionSheet
})
Button(action: { mockSupport.lastVersionCheckAlertDate = nil } ) {
Text("Clear Last Version Check Alert Date")
}
}
var currentVersionUpdate: String {
return mockSupport.versionUpdate.map { "(\($0.rawValue))" } ?? ""
}
}