Skip to content

Commit aaacb8d

Browse files
authored
CPA-92 Caregiver invitations. (#567)
* Updates for plugin menu items, avoid double creation of support plugins, and use full list of activeSupports elsewhere in Loop * Fix merge issues * Update tests for SupportManager changes * Fixes for merge issues
1 parent 867f825 commit aaacb8d

14 files changed

+293
-309
lines changed

Loop.xcodeproj/project.pbxproj

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,6 @@
5656
1DB1065124467E18005542BD /* AlertManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1065024467E18005542BD /* AlertManager.swift */; };
5757
1DB1CA4D24A55F0000B3B94C /* Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1CA4C24A55F0000B3B94C /* Image.swift */; };
5858
1DB619AC270BAD3D006C9D07 /* VersionUpdateViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB619AB270BAD3D006C9D07 /* VersionUpdateViewModel.swift */; };
59-
1DD0B76724EC77AC008A2DC3 /* SupportScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */; };
6059
1DDE273D24AEA4B000796622 /* SettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB1CA4E24A56D7600B3B94C /* SettingsViewModel.swift */; };
6160
1DDE273E24AEA4B000796622 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */; };
6261
1DDE274024AEA4F200796622 /* NotificationsCriticalAlertPermissionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA46B5F2492E2E300D71A63 /* NotificationsCriticalAlertPermissionsView.swift */; };
@@ -822,7 +821,6 @@
822821
1DB1CA4E24A56D7600B3B94C /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = "<group>"; };
823822
1DB619AB270BAD3D006C9D07 /* VersionUpdateViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionUpdateViewModel.swift; sourceTree = "<group>"; };
824823
1DC63E7325351BDF004605DA /* TrueTime.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TrueTime.framework; path = Carthage/Build/iOS/TrueTime.framework; sourceTree = "<group>"; };
825-
1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SupportScreenView.swift; sourceTree = "<group>"; };
826824
1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsView.swift; sourceTree = "<group>"; };
827825
1DFE9E162447B6270082C280 /* UserNotificationAlertSchedulerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationAlertSchedulerTests.swift; sourceTree = "<group>"; };
828826
4302F4E01D4E9C8900F0FCAF /* TextFieldTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TextFieldTableViewController.swift; sourceTree = "<group>"; };
@@ -2398,7 +2396,6 @@
23982396
439706E522D2E84900C81566 /* PredictionSettingTableViewCell.swift */,
23992397
1DE09BA824A3E23F009EE9F9 /* SettingsView.swift */,
24002398
C1DE5D22251BFC4D00439E49 /* SimpleBolusView.swift */,
2401-
1DD0B76624EC77AC008A2DC3 /* SupportScreenView.swift */,
24022399
43F64DD81D9C92C900D24DC6 /* TitleSubtitleTableViewCell.swift */,
24032400
4311FB9A1F37FE1B00D4C0A7 /* TitleSubtitleTextFieldTableViewCell.swift */,
24042401
C1AF062229426300002C1B19 /* ManualGlucoseEntryRow.swift */,
@@ -3967,7 +3964,6 @@
39673964
43DFB62320D4CAE7008A7BAE /* PumpManager.swift in Sources */,
39683965
A9FB75F1252BE320004C7D3F /* BolusDosingDecision.swift in Sources */,
39693966
892A5D59222F0A27008961AB /* Debug.swift in Sources */,
3970-
1DD0B76724EC77AC008A2DC3 /* SupportScreenView.swift in Sources */,
39713967
431A8C401EC6E8AB00823B9C /* CircleMaskView.swift in Sources */,
39723968
1D05219D2469F1F5000EBBDE /* AlertStore.swift in Sources */,
39733969
439897371CD2F80600223065 /* AnalyticsServicesManager.swift in Sources */,

Loop/Managers/DeviceDataManager.swift

Lines changed: 59 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ final class DeviceDataManager {
2929
/// Remember the launch date of the app for diagnostic reporting
3030
private let launchDate = Date()
3131

32-
private(set) var testingScenariosManager: TestingScenariosManager?
33-
3432
/// The last error recorded by a device manager
3533
/// Should be accessed only on the main queue
3634
private(set) var lastError: (date: Date, error: Error)?
@@ -417,10 +415,6 @@ final class DeviceDataManager {
417415
directory: FileManager.default.exportsDirectoryURL,
418416
historicalDuration: Bundle.main.localCacheDuration)
419417

420-
if FeatureFlags.scenariosEnabled {
421-
testingScenariosManager = LocalTestingScenariosManager(deviceManager: self)
422-
}
423-
424418
loopManager.delegate = self
425419

426420
alertManager.alertStore.delegate = self
@@ -658,64 +652,6 @@ final class DeviceDataManager {
658652
self.getHealthStoreAuthorization(completion)
659653
}
660654
}
661-
662-
func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) {
663-
self.loopManager.generateDiagnosticReport { (loopReport) in
664-
665-
let logDurationHours = 84.0
666-
667-
self.alertManager.getStoredEntries(startDate: Date() - .hours(logDurationHours)) { (alertReport) in
668-
self.deviceLog.getLogEntries(startDate: Date() - .hours(logDurationHours)) { (result) in
669-
let deviceLogReport: String
670-
switch result {
671-
case .failure(let error):
672-
deviceLogReport = "Error fetching entries: \(error)"
673-
case .success(let entries):
674-
deviceLogReport = entries.map { "* \($0.timestamp) \($0.managerIdentifier) \($0.deviceIdentifier ?? "") \($0.type) \($0.message)" }.joined(separator: "\n")
675-
}
676-
677-
let report = [
678-
"## Build Details",
679-
"* appNameAndVersion: \(Bundle.main.localizedNameAndVersion)",
680-
"* profileExpiration: \(Bundle.main.profileExpirationString)",
681-
"* gitRevision: \(Bundle.main.gitRevision ?? "N/A")",
682-
"* gitBranch: \(Bundle.main.gitBranch ?? "N/A")",
683-
"* workspaceGitRevision: \(Bundle.main.workspaceGitRevision ?? "N/A")",
684-
"* workspaceGitBranch: \(Bundle.main.workspaceGitBranch ?? "N/A")",
685-
"* sourceRoot: \(Bundle.main.sourceRoot ?? "N/A")",
686-
"* buildDateString: \(Bundle.main.buildDateString ?? "N/A")",
687-
"* xcodeVersion: \(Bundle.main.xcodeVersion ?? "N/A")",
688-
"",
689-
"## FeatureFlags",
690-
"\(FeatureFlags)",
691-
"",
692-
alertReport,
693-
"",
694-
"## DeviceDataManager",
695-
"* launchDate: \(self.launchDate)",
696-
"* lastError: \(String(describing: self.lastError))",
697-
"",
698-
"cacheStore: \(String(reflecting: self.cacheStore))",
699-
"",
700-
self.cgmManager != nil ? String(reflecting: self.cgmManager!) : "cgmManager: nil",
701-
"",
702-
self.pumpManager != nil ? String(reflecting: self.pumpManager!) : "pumpManager: nil",
703-
"",
704-
"## Device Communication Log",
705-
deviceLogReport,
706-
"",
707-
String(reflecting: self.watchManager!),
708-
"",
709-
String(reflecting: self.statusExtensionManager!),
710-
"",
711-
loopReport,
712-
].joined(separator: "\n")
713-
714-
completion(report)
715-
}
716-
}
717-
}
718-
}
719655
}
720656

721657
private extension DeviceDataManager {
@@ -1656,40 +1592,6 @@ fileprivate extension FileManager {
16561592
extension GlucoseStore : CGMStalenessMonitorDelegate { }
16571593

16581594

1659-
//MARK: - SupportInfoProvider protocol conformance
1660-
1661-
extension DeviceDataManager: SupportInfoProvider {
1662-
1663-
private var branchNameIfNotReleaseBranch: String? {
1664-
return Bundle.main.gitBranch.filter { branch in
1665-
return branch != "" &&
1666-
branch != "main" &&
1667-
branch != "master" &&
1668-
!branch.starts(with: "release/")
1669-
}
1670-
}
1671-
1672-
public var localizedAppNameAndVersion: String {
1673-
if let branch = branchNameIfNotReleaseBranch {
1674-
return Bundle.main.localizedNameAndVersion + " (\(branch))"
1675-
}
1676-
return Bundle.main.localizedNameAndVersion
1677-
}
1678-
1679-
public var pumpStatus: PumpManagerStatus? {
1680-
return pumpManager?.status
1681-
}
1682-
1683-
public var cgmStatus: CGMManagerStatus? {
1684-
return cgmManager?.cgmManagerStatus
1685-
}
1686-
1687-
public func generateIssueReport(completion: @escaping (String) -> Void) {
1688-
generateDiagnosticReport(completion)
1689-
}
1690-
1691-
}
1692-
16931595
//MARK: TherapySettingsViewModelDelegate
16941596
struct CancelTempBasalFailedError: LocalizedError {
16951597
let reason: Error?
@@ -1790,8 +1692,66 @@ extension DeviceDataManager {
17901692
}
17911693
}
17921694

1793-
extension DeviceDataManager {
1695+
extension DeviceDataManager: DeviceSupportDelegate {
17941696
var availableSupports: [SupportUI] { [cgmManager, pumpManager].compactMap { $0 as? SupportUI } }
1697+
1698+
func generateDiagnosticReport(_ completion: @escaping (_ report: String) -> Void) {
1699+
self.loopManager.generateDiagnosticReport { (loopReport) in
1700+
1701+
let logDurationHours = 84.0
1702+
1703+
self.alertManager.getStoredEntries(startDate: Date() - .hours(logDurationHours)) { (alertReport) in
1704+
self.deviceLog.getLogEntries(startDate: Date() - .hours(logDurationHours)) { (result) in
1705+
let deviceLogReport: String
1706+
switch result {
1707+
case .failure(let error):
1708+
deviceLogReport = "Error fetching entries: \(error)"
1709+
case .success(let entries):
1710+
deviceLogReport = entries.map { "* \($0.timestamp) \($0.managerIdentifier) \($0.deviceIdentifier ?? "") \($0.type) \($0.message)" }.joined(separator: "\n")
1711+
}
1712+
1713+
let report = [
1714+
"## Build Details",
1715+
"* appNameAndVersion: \(Bundle.main.localizedNameAndVersion)",
1716+
"* profileExpiration: \(Bundle.main.profileExpirationString)",
1717+
"* gitRevision: \(Bundle.main.gitRevision ?? "N/A")",
1718+
"* gitBranch: \(Bundle.main.gitBranch ?? "N/A")",
1719+
"* workspaceGitRevision: \(Bundle.main.workspaceGitRevision ?? "N/A")",
1720+
"* workspaceGitBranch: \(Bundle.main.workspaceGitBranch ?? "N/A")",
1721+
"* sourceRoot: \(Bundle.main.sourceRoot ?? "N/A")",
1722+
"* buildDateString: \(Bundle.main.buildDateString ?? "N/A")",
1723+
"* xcodeVersion: \(Bundle.main.xcodeVersion ?? "N/A")",
1724+
"",
1725+
"## FeatureFlags",
1726+
"\(FeatureFlags)",
1727+
"",
1728+
alertReport,
1729+
"",
1730+
"## DeviceDataManager",
1731+
"* launchDate: \(self.launchDate)",
1732+
"* lastError: \(String(describing: self.lastError))",
1733+
"",
1734+
"cacheStore: \(String(reflecting: self.cacheStore))",
1735+
"",
1736+
self.cgmManager != nil ? String(reflecting: self.cgmManager!) : "cgmManager: nil",
1737+
"",
1738+
self.pumpManager != nil ? String(reflecting: self.pumpManager!) : "pumpManager: nil",
1739+
"",
1740+
"## Device Communication Log",
1741+
deviceLogReport,
1742+
"",
1743+
String(reflecting: self.watchManager!),
1744+
"",
1745+
String(reflecting: self.statusExtensionManager!),
1746+
"",
1747+
loopReport,
1748+
].joined(separator: "\n")
1749+
1750+
completion(report)
1751+
}
1752+
}
1753+
}
1754+
}
17951755
}
17961756

17971757
extension DeviceDataManager: DeviceStatusProvider {}

Loop/Managers/LocalTestingScenariosManager.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import OSLog
1414
final class LocalTestingScenariosManager: TestingScenariosManagerRequirements, DirectoryObserver {
1515

1616
unowned let deviceManager: DeviceDataManager
17+
unowned let supportManager: SupportManager
1718

1819
let log = DiagnosticLog(category: "LocalTestingScenariosManager")
1920

@@ -35,12 +36,13 @@ final class LocalTestingScenariosManager: TestingScenariosManagerRequirements, D
3536
deviceManager.pluginManager
3637
}
3738

38-
init(deviceManager: DeviceDataManager) {
39+
init(deviceManager: DeviceDataManager, supportManager: SupportManager) {
3940
guard FeatureFlags.scenariosEnabled else {
4041
fatalError("\(#function) should be invoked only when scenarios are enabled")
4142
}
4243

4344
self.deviceManager = deviceManager
45+
self.supportManager = supportManager
4446
self.scenariosSource = Bundle.main.bundleURL.appendingPathComponent("Scenarios")
4547

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

Loop/Managers/LoopAppManager.swift

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class LoopAppManager: NSObject {
8181
private var settingsManager: SettingsManager!
8282
private var loggingServicesManager = LoggingServicesManager()
8383
private var analyticsServicesManager = AnalyticsServicesManager()
84+
private(set) var testingScenariosManager: TestingScenariosManager?
8485
private var resetLoopManager: ResetLoopManager!
8586

8687
private var overrideHistory = UserDefaults.appGroup?.overrideHistory ?? TemporaryScheduleOverrideHistory.init()
@@ -174,11 +175,6 @@ class LoopAppManager: NSObject {
174175

175176
pluginManager = PluginManager()
176177

177-
for support in pluginManager.availableSupports {
178-
if let analyticsService = support as? AnalyticsService {
179-
analyticsServicesManager.addService(analyticsService)
180-
}
181-
}
182178

183179
bluetoothStateManager = BluetoothStateManager()
184180
alertManager = AlertManager(alertPresenter: self,
@@ -219,14 +215,31 @@ class LoopAppManager: NSObject {
219215

220216
scheduleBackgroundTasks()
221217

218+
supportManager = SupportManager(pluginManager: pluginManager,
219+
deviceSupportDelegate: deviceDataManager,
220+
servicesManager: deviceDataManager.servicesManager,
221+
alertIssuer: alertManager)
222+
222223
onboardingManager = OnboardingManager(pluginManager: pluginManager,
223224
bluetoothProvider: bluetoothStateManager,
224225
deviceDataManager: deviceDataManager,
225226
servicesManager: deviceDataManager.servicesManager,
226227
loopDataManager: deviceDataManager.loopManager,
228+
supportManager: supportManager,
227229
windowProvider: windowProvider,
228230
userDefaults: UserDefaults.appGroup!)
229231

232+
233+
for support in supportManager.availableSupports {
234+
if let analyticsService = support as? AnalyticsService {
235+
analyticsServicesManager.addService(analyticsService)
236+
}
237+
}
238+
for support in supportManager.availableSupports {
239+
support.initializationComplete(for: deviceDataManager.servicesManager.activeServices)
240+
}
241+
242+
230243
deviceDataManager.onboardingManager = onboardingManager
231244

232245
analyticsServicesManager.identifyAppName(Bundle.main.bundleDisplayName)
@@ -235,12 +248,12 @@ class LoopAppManager: NSObject {
235248
analyticsServicesManager.identifyWorkspaceGitRevision(workspaceGitRevision)
236249
}
237250

251+
if FeatureFlags.scenariosEnabled {
252+
testingScenariosManager = LocalTestingScenariosManager(deviceManager: deviceDataManager, supportManager: supportManager)
253+
}
254+
238255
analyticsServicesManager.application(didFinishLaunchingWithOptions: launchOptions)
239256

240-
supportManager = SupportManager(pluginManager: pluginManager,
241-
deviceDataManager: deviceDataManager,
242-
servicesManager: deviceDataManager.servicesManager,
243-
alertIssuer: alertManager)
244257

245258
automaticDosingStatus.$isAutomaticDosingAllowed
246259
.combineLatest(deviceDataManager.loopManager.$dosingEnabled)
@@ -402,7 +415,7 @@ class LoopAppManager: NSObject {
402415
}
403416
return false
404417
}
405-
418+
406419
private var rootViewController: UIViewController? {
407420
get { windowProvider?.window?.rootViewController }
408421
set { windowProvider?.window?.rootViewController = newValue }
@@ -581,13 +594,13 @@ extension LoopAppManager: ResetLoopManagerDelegate {
581594
}
582595

583596
func loopWillReset() {
584-
deviceDataManager.pluginManager.availableSupports.forEach { supportUI in
597+
supportManager.availableSupports.forEach { supportUI in
585598
supportUI.loopWillReset()
586599
}
587600
}
588601

589602
func loopDidReset() {
590-
deviceDataManager.pluginManager.availableSupports.forEach { supportUI in
603+
supportManager.availableSupports.forEach { supportUI in
591604
supportUI.loopDidReset()
592605
}
593606
}

Loop/Managers/OnboardingManager.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ class OnboardingManager {
1717
private let deviceDataManager: DeviceDataManager
1818
private let servicesManager: ServicesManager
1919
private let loopDataManager: LoopDataManager
20+
private let supportManager: SupportManager
2021
private weak var windowProvider: WindowProvider?
2122
private let userDefaults: UserDefaults
2223

@@ -38,12 +39,13 @@ class OnboardingManager {
3839

3940
private var onboardingCompletion: (() -> Void)?
4041

41-
init(pluginManager: PluginManager, bluetoothProvider: BluetoothProvider, deviceDataManager: DeviceDataManager, servicesManager: ServicesManager, loopDataManager: LoopDataManager, windowProvider: WindowProvider?, userDefaults: UserDefaults = .standard) {
42+
init(pluginManager: PluginManager, bluetoothProvider: BluetoothProvider, deviceDataManager: DeviceDataManager, servicesManager: ServicesManager, loopDataManager: LoopDataManager, supportManager: SupportManager, windowProvider: WindowProvider?, userDefaults: UserDefaults = .standard) {
4243
self.pluginManager = pluginManager
4344
self.bluetoothProvider = bluetoothProvider
4445
self.deviceDataManager = deviceDataManager
4546
self.servicesManager = servicesManager
4647
self.loopDataManager = loopDataManager
48+
self.supportManager = supportManager
4749
self.windowProvider = windowProvider
4850
self.userDefaults = userDefaults
4951

@@ -440,7 +442,7 @@ extension OnboardingManager: OnboardingProvider {
440442
// MARK: - SupportProvider
441443

442444
extension OnboardingManager: SupportProvider {
443-
var availableSupports: [SupportUI] { deviceDataManager.pluginManager.availableSupports }
445+
var availableSupports: [SupportUI] { supportManager.availableSupports }
444446
}
445447

446448
// MARK: - OnboardingUI

0 commit comments

Comments
 (0)