From 3a8d2c9d3575c3695791eb9508c59982fdc1633c Mon Sep 17 00:00:00 2001 From: Cameron Ingham Date: Mon, 21 Aug 2023 23:08:25 -0700 Subject: [PATCH 1/2] [LOOP-4652] Replace AnyView --- .../StatusTableViewController.swift | 50 ++++++++++++++----- ...icationsCriticalAlertPermissionsView.swift | 4 +- Loop/Views/SettingsView.swift | 48 +++++++++--------- LoopTests/Managers/SupportManagerTests.swift | 6 +-- .../DismissibleHostingController.swift | 4 +- 5 files changed, 69 insertions(+), 43 deletions(-) diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index 74b49790aa..3e5312dafb 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -1385,22 +1385,46 @@ final class StatusTableViewController: LoopChartsTableViewController { @IBAction func presentBolusScreen() { presentBolusEntryView() } - - func presentBolusEntryView(enableManualGlucoseEntry: Bool = false) { - let hostingController: DismissibleHostingController + + @ViewBuilder + func bolusEntryView(enableManualGlucoseEntry: Bool = false) -> some View { if FeatureFlags.simpleBolusCalculatorEnabled && !automaticDosingStatus.automaticDosingEnabled { - let viewModel = SimpleBolusViewModel(delegate: deviceManager, displayMealEntry: false) - let bolusEntryView = SimpleBolusView(viewModel: viewModel).environmentObject(deviceManager.displayGlucosePreference) - hostingController = DismissibleHostingController(rootView: bolusEntryView, isModalInPresentation: false) + SimpleBolusView( + viewModel: SimpleBolusViewModel( + delegate: deviceManager, + displayMealEntry: false + ) + ) + .environmentObject(deviceManager.displayGlucosePreference) } else { - let viewModel = BolusEntryViewModel(delegate: deviceManager, screenWidth: UIScreen.main.bounds.width, isManualGlucoseEntryEnabled: enableManualGlucoseEntry) - Task { @MainActor in - await viewModel.generateRecommendationAndStartObserving() - } - viewModel.analyticsServicesManager = deviceManager.analyticsServicesManager - let bolusEntryView = BolusEntryView(viewModel: viewModel).environmentObject(deviceManager.displayGlucosePreference) - hostingController = DismissibleHostingController(rootView: bolusEntryView, isModalInPresentation: false) + let viewModel: BolusEntryViewModel = { + let viewModel = BolusEntryViewModel( + delegate: deviceManager, + screenWidth: UIScreen.main.bounds.width, + isManualGlucoseEntryEnabled: enableManualGlucoseEntry + ) + + Task { @MainActor in + await viewModel.generateRecommendationAndStartObserving() + } + + viewModel.analyticsServicesManager = deviceManager.analyticsServicesManager + + return viewModel + }() + + BolusEntryView(viewModel: viewModel) + .environmentObject(deviceManager.displayGlucosePreference) } + } + + func presentBolusEntryView(enableManualGlucoseEntry: Bool = false) { + let hostingController = DismissibleHostingController( + content: bolusEntryView( + enableManualGlucoseEntry: enableManualGlucoseEntry + ) + ) + let navigationWrapper = UINavigationController(rootViewController: hostingController) hostingController.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel, target: navigationWrapper, action: #selector(dismissWithAnimation)) present(navigationWrapper, animated: true) diff --git a/Loop/Views/NotificationsCriticalAlertPermissionsView.swift b/Loop/Views/NotificationsCriticalAlertPermissionsView.swift index e69084a46a..b9e1552036 100644 --- a/Loop/Views/NotificationsCriticalAlertPermissionsView.swift +++ b/Loop/Views/NotificationsCriticalAlertPermissionsView.swift @@ -32,8 +32,8 @@ public struct NotificationsCriticalAlertPermissionsView: View { public var body: some View { switch mode { - case .flow: return AnyView(content()) - case .topLevel: return AnyView(navigationContent()) + case .flow: content() + case .topLevel: navigationContent() } } diff --git a/Loop/Views/SettingsView.swift b/Loop/Views/SettingsView.swift index 0b4cb55133..7eadb7f1ec 100644 --- a/Loop/Views/SettingsView.swift +++ b/Loop/Views/SettingsView.swift @@ -119,13 +119,13 @@ extension String: Identifiable { } } -struct PluginMenuItem: Identifiable { +struct PluginMenuItem: Identifiable { var id: String { return pluginIdentifier + String(describing: offset) } let section: SettingsMenuSection - let view: AnyView + let view: Content let pluginIdentifier: String let offset: Int } @@ -206,7 +206,7 @@ extension SettingsView { Section(header: SectionHeader(label: NSLocalizedString("Configuration", comment: "The title of the Configuration section in settings"))) { LargeButton(action: { self.therapySettingsIsPresented = true }, includeArrow: true, - imageView: AnyView(Image("Therapy Icon")), + imageView: Image("Therapy Icon"), label: NSLocalizedString("Therapy Settings", comment: "Title text for button to Therapy Settings"), descriptiveText: NSLocalizedString("Diabetes Treatment", comment: "Descriptive text for Therapy Settings")) .sheet(isPresented: $therapySettingsIsPresented) { @@ -235,7 +235,7 @@ extension SettingsView { } } - private var pluginMenuItems: [PluginMenuItem] { + private var pluginMenuItems: [PluginMenuItem] { self.viewModel.availableSupports.flatMap { plugin in plugin.configurationMenuItems().enumerated().map { index, item in PluginMenuItem(section: item.section, view: item.view, pluginIdentifier: plugin.identifier, offset: index) @@ -261,7 +261,7 @@ extension SettingsView { } else if viewModel.isOnboardingComplete { LargeButton(action: { self.pumpChooserIsPresented = true }, includeArrow: false, - imageView: AnyView(plusImage), + imageView: plusImage, label: NSLocalizedString("Add Pump", comment: "Title text for button to add pump device"), descriptiveText: NSLocalizedString("Tap here to set up a pump", comment: "Descriptive text for button to add pump device")) .actionSheet(isPresented: $pumpChooserIsPresented) { @@ -293,7 +293,7 @@ extension SettingsView { } else { LargeButton(action: { self.cgmChooserIsPresented = true }, includeArrow: false, - imageView: AnyView(plusImage), + imageView: plusImage, label: NSLocalizedString("Add CGM", comment: "Title text for button to add CGM device"), descriptiveText: NSLocalizedString("Tap here to set up a CGM", comment: "Descriptive text for button to add CGM device")) .actionSheet(isPresented: $cgmChooserIsPresented) { @@ -306,7 +306,7 @@ extension SettingsView { Section { LargeButton(action: { self.favoriteFoodsIsPresented = true }, includeArrow: true, - imageView: AnyView(Image("Favorite Foods Icon").renderingMode(.template).foregroundColor(carbTintColor)), + imageView: Image("Favorite Foods Icon").renderingMode(.template).foregroundColor(carbTintColor), label: "Favorite Foods", descriptiveText: "Simplify Carb Entry") } @@ -339,7 +339,7 @@ extension SettingsView { if viewModel.servicesViewModel.inactiveServices().count > 0 { LargeButton(action: { self.serviceChooserIsPresented = true }, includeArrow: false, - imageView: AnyView(plusImage), + imageView: plusImage, label: NSLocalizedString("Add Service", comment: "The title of the add service button in settings"), descriptiveText: NSLocalizedString("Tap here to set up a Service", comment: "The descriptive text of the add service button in settings")) .actionSheet(isPresented: $serviceChooserIsPresented) { @@ -455,41 +455,43 @@ extension SettingsView { .padding(EdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)) } - private func deviceImage(uiImage: UIImage?) -> AnyView { + @ViewBuilder + private func deviceImage(uiImage: UIImage?) -> some View { if let uiImage = uiImage { - return AnyView(Image(uiImage: uiImage) + Image(uiImage: uiImage) .renderingMode(.original) .resizable() - .scaledToFit()) + .scaledToFit() } else { - return AnyView(Spacer()) + Spacer() } } - private func serviceImage(uiImage: UIImage?) -> AnyView { - return deviceImage(uiImage: uiImage) + @ViewBuilder + private func serviceImage(uiImage: UIImage?) -> some View { + deviceImage(uiImage: uiImage) } } -fileprivate struct LargeButton: View { +fileprivate struct LargeButton: View { let action: () -> Void var includeArrow: Bool = true - let imageView: AnyView + let imageView: Content let label: String let descriptiveText: String // TODO: The design doesn't show this, but do we need to consider different values here for different size classes? - static let spacing: CGFloat = 15 - static let imageWidth: CGFloat = 60 - static let imageHeight: CGFloat = 60 - static let topBottomPadding: CGFloat = 10 + private let spacing: CGFloat = 15 + private let imageWidth: CGFloat = 60 + private let imageHeight: CGFloat = 60 + private let topBottomPadding: CGFloat = 10 public var body: some View { Button(action: action) { HStack { - HStack(spacing: Self.spacing) { - imageView.frame(width: Self.imageWidth, height: Self.imageHeight) + HStack(spacing: spacing) { + imageView.frame(width: imageWidth, height: imageHeight) VStack(alignment: .leading) { Text(label) .foregroundColor(.primary) @@ -502,7 +504,7 @@ fileprivate struct LargeButton: View { Image(systemName: "chevron.right").foregroundColor(.gray).font(.footnote) } } - .padding(EdgeInsets(top: Self.topBottomPadding, leading: 0, bottom: Self.topBottomPadding, trailing: 0)) + .padding(EdgeInsets(top: topBottomPadding, leading: 0, bottom: topBottomPadding, trailing: 0)) } } } diff --git a/LoopTests/Managers/SupportManagerTests.swift b/LoopTests/Managers/SupportManagerTests.swift index f245549573..ac0d42b512 100644 --- a/LoopTests/Managers/SupportManagerTests.swift +++ b/LoopTests/Managers/SupportManagerTests.swift @@ -16,9 +16,9 @@ class SupportManagerTests: XCTestCase { enum MockError: Error { case nothing } class Mixin { - func supportMenuItem(supportInfoProvider: SupportInfoProvider, urlHandler: @escaping (URL) -> Void) -> AnyView? { - nil - } + @ViewBuilder + func supportMenuItem(supportInfoProvider: SupportInfoProvider, urlHandler: @escaping (URL) -> Void) -> some View {} + func softwareUpdateView(bundleIdentifier: String, currentVersion: String, guidanceColors: GuidanceColors, openAppStore: (() -> Void)?) -> AnyView? { nil } diff --git a/LoopUI/Extensions/DismissibleHostingController.swift b/LoopUI/Extensions/DismissibleHostingController.swift index ce0bab23b9..47670f1b27 100644 --- a/LoopUI/Extensions/DismissibleHostingController.swift +++ b/LoopUI/Extensions/DismissibleHostingController.swift @@ -10,13 +10,13 @@ import SwiftUI import LoopKitUI extension DismissibleHostingController { - public convenience init( + public convenience init( rootView: Content, dismissalMode: DismissalMode = .modalDismiss, isModalInPresentation: Bool = true, onDisappear: @escaping () -> Void = {} ) { - self.init(rootView: rootView, + self.init(content: rootView, dismissalMode: dismissalMode, isModalInPresentation: isModalInPresentation, onDisappear: onDisappear, From 2e16e1ea72ec75e1d2c3bc05069657838eb5bea4 Mon Sep 17 00:00:00 2001 From: Pete Schwamb Date: Wed, 6 Sep 2023 16:06:44 -0500 Subject: [PATCH 2/2] Revert test optimization; some pump tests that attempt ble comms are failing with the optimization --- Loop/AppDelegate.swift | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/Loop/AppDelegate.swift b/Loop/AppDelegate.swift index 41569632d3..5da6ce9cb6 100644 --- a/Loop/AppDelegate.swift +++ b/Loop/AppDelegate.swift @@ -22,11 +22,8 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider { setenv("CFNETWORK_DIAGNOSTICS", "3", 1) - if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil { - // Code only executes when not running tests - loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions) - loopAppManager.launch() - } + loopAppManager.initialize(windowProvider: self, launchOptions: launchOptions) + loopAppManager.launch() return loopAppManager.isLaunchComplete } @@ -35,10 +32,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate, WindowProvider { func applicationDidBecomeActive(_ application: UIApplication) { log.default(#function) - if ProcessInfo.processInfo.environment["XCTestConfigurationFilePath"] == nil { - // Code only executes when not running tests - loopAppManager.didBecomeActive() - } + loopAppManager.didBecomeActive() } func applicationWillResignActive(_ application: UIApplication) {