Explorar el Código

Calendar Event refactor for settings
* Move Create Calendar Events and associated settings to Notification Settings
* Refactor Calendar Manager requestAccessIfNeeded() to be async/await conform
* Refactor calendarCreate state model to be async/await conform
* Handle storage of calendar settings
* Create new views, etc.

Deniz Cengiz hace 1 año
padre
commit
b3d2d40b64

+ 32 - 0
FreeAPS.xcodeproj/project.pbxproj

@@ -385,6 +385,10 @@
 		D6DEC113821A7F1056C4AA1E /* NightscoutConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2F2A13DF0EDEEEDC4106AA2A /* NightscoutConfigDataFlow.swift */; };
 		D76333C9256787610B3B4875 /* AutotuneConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D295A3F870E826BE371C0BB5 /* AutotuneConfigStateModel.swift */; };
 		DBA5254DBB2586C98F61220C /* ISFEditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F9F137F126D9F8DEB799F26 /* ISFEditorProvider.swift */; };
+		DD09D47B2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD09D47A2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift */; };
+		DD09D47D2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD09D47C2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift */; };
+		DD09D47F2C5986E5003FEA5D /* CalendarEventSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD09D47E2C5986E5003FEA5D /* CalendarEventSettingsStateModel.swift */; };
+		DD09D4822C5986F6003FEA5D /* CalendarEventSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD09D4812C5986F6003FEA5D /* CalendarEventSettingsRootView.swift */; };
 		DD1745132C54169400211FAC /* DevicesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745122C54169400211FAC /* DevicesView.swift */; };
 		DD1745152C54388A00211FAC /* TherapySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745142C54388A00211FAC /* TherapySettingsView.swift */; };
 		DD1745172C54389F00211FAC /* FeatureSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745162C54389F00211FAC /* FeatureSettingsView.swift */; };
@@ -1015,6 +1019,10 @@
 		D295A3F870E826BE371C0BB5 /* AutotuneConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AutotuneConfigStateModel.swift; sourceTree = "<group>"; };
 		D97F14812C1AFED3621165A5 /* PumpSettingsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpSettingsEditorProvider.swift; sourceTree = "<group>"; };
 		DC2C6489D29ECCCAD78E0721 /* NotificationsConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationsConfigStateModel.swift; sourceTree = "<group>"; };
+		DD09D47A2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEventSettingsDataFlow.swift; sourceTree = "<group>"; };
+		DD09D47C2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEventSettingsProvider.swift; sourceTree = "<group>"; };
+		DD09D47E2C5986E5003FEA5D /* CalendarEventSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEventSettingsStateModel.swift; sourceTree = "<group>"; };
+		DD09D4812C5986F6003FEA5D /* CalendarEventSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarEventSettingsRootView.swift; sourceTree = "<group>"; };
 		DD1745122C54169400211FAC /* DevicesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DevicesView.swift; sourceTree = "<group>"; };
 		DD1745142C54388A00211FAC /* TherapySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TherapySettingsView.swift; sourceTree = "<group>"; };
 		DD1745162C54389F00211FAC /* FeatureSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureSettingsView.swift; sourceTree = "<group>"; };
@@ -1383,6 +1391,7 @@
 		3811DE0325C9D31700A708ED /* Modules */ = {
 			isa = PBXGroup;
 			children = (
+				DD09D4792C5986BA003FEA5D /* CalendarEventSettings */,
 				DD17454C2C55CA0200211FAC /* GeneralSettings */,
 				DD1745422C55C5C400211FAC /* AutosensSettings */,
 				DD1745382C55BF8B00211FAC /* AlgorithmVariousSettings */,
@@ -2458,6 +2467,25 @@
 			path = ISFEditor;
 			sourceTree = "<group>";
 		};
+		DD09D4792C5986BA003FEA5D /* CalendarEventSettings */ = {
+			isa = PBXGroup;
+			children = (
+				DD09D4802C5986E8003FEA5D /* View */,
+				DD09D47A2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift */,
+				DD09D47C2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift */,
+				DD09D47E2C5986E5003FEA5D /* CalendarEventSettingsStateModel.swift */,
+			);
+			path = CalendarEventSettings;
+			sourceTree = "<group>";
+		};
+		DD09D4802C5986E8003FEA5D /* View */ = {
+			isa = PBXGroup;
+			children = (
+				DD09D4812C5986F6003FEA5D /* CalendarEventSettingsRootView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		DD1745112C54168300211FAC /* Subviews */ = {
 			isa = PBXGroup;
 			children = (
@@ -3330,6 +3358,7 @@
 				8B759CFCF47B392BB365C251 /* BasalProfileEditorDataFlow.swift in Sources */,
 				195D80B42AF6973A00D25097 /* DynamicSettingsRootView.swift in Sources */,
 				389442CB25F65F7100FA1F27 /* NightscoutTreatment.swift in Sources */,
+				DD09D47F2C5986E5003FEA5D /* CalendarEventSettingsStateModel.swift in Sources */,
 				CE7CA3512A064973004BE681 /* ApplyTempPresetIntent.swift in Sources */,
 				FA630397F76B582C8D8681A7 /* BasalProfileEditorProvider.swift in Sources */,
 				DD1745172C54389F00211FAC /* FeatureSettingsView.swift in Sources */,
@@ -3387,6 +3416,7 @@
 				E4984C5262A90469788754BB /* PreferencesEditorProvider.swift in Sources */,
 				DD399FB31EACB9343C944C4C /* PreferencesEditorStateModel.swift in Sources */,
 				19E1F7EA29D082ED005C8D20 /* IconConfigProvider.swift in Sources */,
+				DD09D4822C5986F6003FEA5D /* CalendarEventSettingsRootView.swift in Sources */,
 				44190F0BBA464D74B857D1FB /* PreferencesEditorRootView.swift in Sources */,
 				CE48C86428CA69D5007C0598 /* OmniBLEPumpManagerExtensions.swift in Sources */,
 				38E8755427561E9800975559 /* DataFlow.swift in Sources */,
@@ -3436,6 +3466,8 @@
 				0D9A5E34A899219C5C4CDFAF /* DataTableStateModel.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				195D80B92AF697F700D25097 /* DynamicSettingsProvider.swift in Sources */,
+				DD09D47D2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift in Sources */,
+				DD09D47B2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				DD1745202C55523E00211FAC /* SMBSettingsDataFlow.swift in Sources */,
 				D6D02515BBFBE64FEBE89856 /* DataTableRootView.swift in Sources */,

+ 5 - 2
FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json

@@ -51,6 +51,9 @@
   "fattyMeals": false,
   "fattyMealFactor": 0.7,
   "sweetMeals": false,
-  "sweetMealFactor": 2
-  "lockScreenView": "simple"
+  "sweetMealFactor": 2,
+  "lockScreenView": "simple",
+  "useCalendar": false,
+  "displayCalendarIOBandCOB": false,
+  "displayCalendarEmojis": false
 }

+ 2 - 38
FreeAPS/Sources/Modules/CGM/CGMStateModel.swift

@@ -21,7 +21,6 @@ let cgmDefaultName = cgmName(
 extension CGM {
     final class StateModel: BaseStateModel<Provider> {
         @Injected() var cgmManager: FetchGlucoseManager!
-        @Injected() var calendarManager: CalendarManager!
         @Injected() var pluginCGMManager: PluginManager!
         @Injected() private var broadcaster: Broadcaster!
         @Injected() var nightscoutManager: NightscoutManager!
@@ -29,12 +28,7 @@ extension CGM {
         @Published var setupCGM: Bool = false
         @Published var cgmCurrent = cgmDefaultName
         @Published var smoothGlucose = false
-        @Published var createCalendarEvents = false
-        @Published var displayCalendarIOBandCOB = false
-        @Published var displayCalendarEmojis = false
-        @Published var calendarIDs: [String] = []
-        @Published var currentCalendarID: String = ""
-        @Persisted(key: "CalendarManager.currentCalendarID") var storedCalendarID: String? = nil
+
         @Published var cgmTransmitterDeviceAddress: String? = nil
         @Published var listOfCGM: [cgmName] = []
         @Published var url: URL?
@@ -81,13 +75,8 @@ extension CGM {
             default: break
             }
 
-            currentCalendarID = storedCalendarID ?? ""
-            calendarIDs = calendarManager.calendarIDs()
             cgmTransmitterDeviceAddress = UserDefaults.standard.cgmTransmitterDeviceAddress
 
-            subscribeSetting(\.useCalendar, on: $createCalendarEvents) { createCalendarEvents = $0 }
-            subscribeSetting(\.displayCalendarIOBandCOB, on: $displayCalendarIOBandCOB) { displayCalendarIOBandCOB = $0 }
-            subscribeSetting(\.displayCalendarEmojis, on: $displayCalendarEmojis) { displayCalendarEmojis = $0 }
             subscribeSetting(\.smoothGlucose, on: $smoothGlucose, initial: { smoothGlucose = $0 })
 
             $cgmCurrent
@@ -111,31 +100,6 @@ extension CGM {
                     }
                 }
                 .store(in: &lifetime)
-
-            $createCalendarEvents
-                .removeDuplicates()
-                .flatMap { [weak self] ok -> AnyPublisher<Bool, Never> in
-                    guard ok, let self = self else { return Just(false).eraseToAnyPublisher() }
-                    return self.calendarManager.requestAccessIfNeeded()
-                }
-                .map { [weak self] ok -> [String] in
-                    guard ok, let self = self else { return [] }
-                    return self.calendarManager.calendarIDs()
-                }
-                .receive(on: DispatchQueue.main)
-                .weakAssign(to: \.calendarIDs, on: self)
-                .store(in: &lifetime)
-
-            $currentCalendarID
-                .removeDuplicates()
-                .sink { [weak self] id in
-                    guard id.isNotEmpty else {
-                        self?.calendarManager.currentCalendarID = nil
-                        return
-                    }
-                    self?.calendarManager.currentCalendarID = id
-                }
-                .store(in: &lifetime)
         }
 
         func displayNameOfApp() -> String? {
@@ -167,7 +131,7 @@ extension CGM.StateModel: CompletionDelegate {
         setupCGM = false
 
         // if CGM was deleted
-        if cgmManager.cgmGlucoseSourceType == nil {
+        if cgmManager.cgmGlucoseSourceType != nil {
             cgmCurrent = cgmDefaultName
             settingsManager.settings.cgm = cgmDefaultName.type
             settingsManager.settings.cgmPluginIdentifier = cgmDefaultName.id

+ 0 - 28
FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift

@@ -122,34 +122,6 @@ extension CGM {
                         }
                     }
 
-                    // }
-
-                    Section(header: Text("Calendar")) {
-                        Toggle("Create Events in Calendar", isOn: $state.createCalendarEvents)
-                        if state.calendarIDs.isNotEmpty {
-                            Picker("Calendar", selection: $state.currentCalendarID) {
-                                ForEach(state.calendarIDs, id: \.self) {
-                                    Text($0).tag($0)
-                                }
-                            }
-                            Toggle("Display Emojis as Labels", isOn: $state.displayCalendarEmojis)
-                            Toggle("Display IOB and COB", isOn: $state.displayCalendarIOBandCOB)
-                        } else if state.createCalendarEvents {
-                            if #available(iOS 17.0, *) {
-                                Text(
-                                    "If you are not seeing calendars to choose here, please go to Settings -> iAPS -> Calendars and change permissions to \"Full Access\""
-                                ).font(.footnote)
-
-                                Button("Open Settings") {
-                                    // Get the settings URL and open it
-                                    if let url = URL(string: UIApplication.openSettingsURLString) {
-                                        UIApplication.shared.open(url)
-                                    }
-                                }
-                            }
-                        }
-                    }
-
                     Section(header: Text("Experimental")) {
                         Toggle("Smooth Glucose Value", isOn: $state.smoothGlucose)
                     }

+ 5 - 0
FreeAPS/Sources/Modules/CalendarEventSettings/CalendarEventSettingsDataFlow.swift

@@ -0,0 +1,5 @@
+enum CalendarEventSettings {
+    enum Config {}
+}
+
+protocol CalendarEventSettingsProvider: Provider {}

+ 3 - 0
FreeAPS/Sources/Modules/CalendarEventSettings/CalendarEventSettingsProvider.swift

@@ -0,0 +1,3 @@
+extension CalendarEventSettings {
+    final class Provider: BaseProvider, CalendarEventSettingsProvider {}
+}

+ 59 - 0
FreeAPS/Sources/Modules/CalendarEventSettings/CalendarEventSettingsStateModel.swift

@@ -0,0 +1,59 @@
+import Combine
+import SwiftUI
+
+extension CalendarEventSettings {
+    final class StateModel: BaseStateModel<Provider> {
+        @Injected() var settings: SettingsManager!
+        @Injected() var storage: FileStorage!
+        @Injected() var calendarManager: CalendarManager!
+
+        @Published var units: GlucoseUnits = .mgdL
+        @Published var useCalendar = false
+        @Published var displayCalendarIOBandCOB = false
+        @Published var displayCalendarEmojis = false
+        @Published var calendarIDs: [String] = []
+        @Published var currentCalendarID: String = ""
+        @Persisted(key: "CalendarManager.currentCalendarID") var storedCalendarID: String? = nil
+
+        override func subscribe() {
+            units = settingsManager.settings.units
+
+            currentCalendarID = storedCalendarID ?? ""
+            calendarIDs = calendarManager.calendarIDs()
+
+            subscribeSetting(\.useCalendar, on: $useCalendar) { useCalendar = $0 }
+            subscribeSetting(\.displayCalendarIOBandCOB, on: $displayCalendarIOBandCOB) { displayCalendarIOBandCOB = $0 }
+            subscribeSetting(\.displayCalendarEmojis, on: $displayCalendarEmojis) { displayCalendarEmojis = $0 }
+
+            observeCreateCalendarEvents()
+            observeCurrentCalendarID()
+        }
+
+        private func observeCreateCalendarEvents() {
+            Task {
+                for await ok in $useCalendar.removeDuplicates().values {
+                    guard ok else { continue }
+                    let accessGranted = await calendarManager.requestAccessIfNeeded()
+                    if accessGranted {
+                        let ids = calendarManager.calendarIDs()
+                        await MainActor.run {
+                            self.calendarIDs = ids
+                        }
+                    }
+                }
+            }
+        }
+
+        private func observeCurrentCalendarID() {
+            Task {
+                for await id in $currentCalendarID.removeDuplicates().values {
+                    if id.isEmpty {
+                        calendarManager.currentCalendarID = nil
+                    } else {
+                        calendarManager.currentCalendarID = id
+                    }
+                }
+            }
+        }
+    }
+}

+ 129 - 0
FreeAPS/Sources/Modules/CalendarEventSettings/View/CalendarEventSettingsRootView.swift

@@ -0,0 +1,129 @@
+import SwiftUI
+import Swinject
+
+extension CalendarEventSettings {
+    struct RootView: BaseView {
+        let resolver: Resolver
+        @StateObject var state = StateModel()
+        @State private var shouldDisplayHint: Bool = false
+        @State var hintDetent = PresentationDetent.large
+        @State var selectedVerboseHint: String?
+        @State var hintLabel: String?
+        @State private var decimalPlaceholder: Decimal = 0.0
+        @State private var booleanPlaceholder: Bool = false
+
+        @Environment(\.colorScheme) var colorScheme
+        @EnvironmentObject var appIcons: Icons
+
+        private var color: LinearGradient {
+            colorScheme == .dark ? LinearGradient(
+                gradient: Gradient(colors: [
+                    Color.bgDarkBlue,
+                    Color.bgDarkerDarkBlue
+                ]),
+                startPoint: .top,
+                endPoint: .bottom
+            )
+                :
+                LinearGradient(
+                    gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
+                    startPoint: .top,
+                    endPoint: .bottom
+                )
+        }
+
+        var body: some View {
+            List {
+                SettingInputSection(
+                    decimalValue: $decimalPlaceholder,
+                    booleanValue: $state.useCalendar,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    selectedVerboseHint: Binding(
+                        get: { selectedVerboseHint },
+                        set: {
+                            selectedVerboseHint = $0
+                            hintLabel = "Create Events in Calendar"
+                        }
+                    ),
+                    type: .boolean,
+                    label: "Create Events in Calendar",
+                    miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                    verboseHint: "Create Calendar Events… bla bla bla",
+                    headerText: "Diabetes Data as Calendar Event"
+                )
+
+                if state.calendarIDs.isNotEmpty, state.useCalendar {
+                    Section {
+                        VStack {
+                            Picker("Choose Calendar", selection: $state.currentCalendarID) {
+                                ForEach(state.calendarIDs, id: \.self) {
+                                    Text($0).tag($0)
+                                }
+                            }.padding(.vertical)
+                        }
+                    }.listRowBackground(Color.chart)
+
+                    SettingInputSection(
+                        decimalValue: $decimalPlaceholder,
+                        booleanValue: $state.displayCalendarEmojis,
+                        shouldDisplayHint: $shouldDisplayHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0
+                                hintLabel = "Display Emojis as Labels"
+                            }
+                        ),
+                        type: .boolean,
+                        label: "Display Emojis as Labels",
+                        miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                        verboseHint: "Display Emojis as Labels… bla bla bla"
+                    )
+
+                    SettingInputSection(
+                        decimalValue: $decimalPlaceholder,
+                        booleanValue: $state.displayCalendarIOBandCOB,
+                        shouldDisplayHint: $shouldDisplayHint,
+                        selectedVerboseHint: Binding(
+                            get: { selectedVerboseHint },
+                            set: {
+                                selectedVerboseHint = $0
+                                hintLabel = "Display IOB and COB"
+                            }
+                        ),
+                        type: .boolean,
+                        label: "Display IOB and COB",
+                        miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
+                        verboseHint: "Display IOB and COB… bla bla bla"
+                    )
+                } else if state.useCalendar {
+                    if #available(iOS 17.0, *) {
+                        Text(
+                            "If you are not seeing calendars to choose here, please go to Settings -> Trio -> Calendars and change permissions to \"Full Access\""
+                        ).font(.footnote)
+
+                        Button("Open Settings") {
+                            // Get the settings URL and open it
+                            if let url = URL(string: UIApplication.openSettingsURLString) {
+                                UIApplication.shared.open(url)
+                            }
+                        }
+                    }
+                }
+            }
+            .sheet(isPresented: $shouldDisplayHint) {
+                SettingInputHintView(
+                    hintDetent: $hintDetent,
+                    shouldDisplayHint: $shouldDisplayHint,
+                    hintLabel: hintLabel ?? "",
+                    hintText: selectedVerboseHint ?? "",
+                    sheetTitle: "Help"
+                )
+            }
+            .scrollContentBackground(.hidden).background(color)
+            .onAppear(perform: configureView)
+            .navigationTitle("Calendar Events")
+            .navigationBarTitleDisplayMode(.automatic)
+        }
+    }
+}

+ 1 - 1
FreeAPS/Sources/Modules/GeneralSettings/UnitsLimitsSettingsStateModel.swift

@@ -6,7 +6,7 @@ extension UnitsLimitsSettings {
         @Injected() var storage: FileStorage!
 
         @Published var units: GlucoseUnits = .mgdL
-        @Published var unitsIndex = 1
+        @Published var unitsIndex = 0 // 0 = mg/dl
 
         @Published var maxIOB: Decimal = 0
         @Published var maxCOB: Decimal = 120

+ 11 - 0
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -154,6 +154,17 @@ extension Settings {
                             Spacer()
                             Image(systemName: "chevron.right").foregroundColor(.secondary)
                         }
+
+                        HStack {
+                            Text("Trio Website")
+                                .onTapGesture {
+                                    if let url = URL(string: "https://diy-trio.org/") {
+                                        UIApplication.shared.open(url)
+                                    }
+                                }
+                            Spacer()
+                            Image(systemName: "chevron.right").foregroundColor(.secondary)
+                        }
                     }
                 ).listRowBackground(Color.chart)
 

+ 1 - 1
FreeAPS/Sources/Modules/Settings/View/Subviews/NotificationsView.swift

@@ -38,7 +38,7 @@ struct NotificationsView: BaseView {
                 content: {
                     Text("Alerts").navigationLink(to: .notificationsConfig, from: self)
                     Text("TODO: Live Activity Settings View")
-                    Text("TODO: Calendar Events Settings View")
+                    Text("Calendar Events").navigationLink(to: .calendarEventSettings, from: self)
                 }
             )
             .listRowBackground(Color.chart)

+ 3 - 0
FreeAPS/Sources/Router/Screen.swift

@@ -40,6 +40,7 @@ enum Screen: Identifiable, Hashable {
     case algorithmSettings
     case featureSettings
     case notificationSettings
+    case calendarEventSettings
     case serviceSettings
     case autosensSettings
     case smbSettings
@@ -129,6 +130,8 @@ extension Screen {
             FeatureSettingsView(resolver: resolver, state: Settings.StateModel())
         case .notificationSettings:
             NotificationsView(resolver: resolver, state: Settings.StateModel())
+        case .calendarEventSettings:
+            CalendarEventSettings.RootView(resolver: resolver)
         case .serviceSettings:
             ServicesView(resolver: resolver, state: Settings.StateModel())
         case .autosensSettings:

+ 38 - 33
FreeAPS/Sources/Services/Calendar/CalendarManager.swift

@@ -4,7 +4,7 @@ import EventKit
 import Swinject
 
 protocol CalendarManager {
-    func requestAccessIfNeeded() -> AnyPublisher<Bool, Never>
+    func requestAccessIfNeeded() async -> Bool
     func calendarIDs() -> [String]
     var currentCalendarID: String? { get set }
     func createEvent(for glucose: GlucoseStored, delta: Int)
@@ -27,61 +27,66 @@ final class BaseCalendarManager: CalendarManager, Injectable {
 
     let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
 
-    func requestAccessIfNeeded() -> AnyPublisher<Bool, Never> {
-        Future { promise in
-            let status = EKEventStore.authorizationStatus(for: .event)
-            switch status {
-            case .notDetermined:
+    func requestAccessIfNeeded() async -> Bool {
+        let status = EKEventStore.authorizationStatus(for: .event)
+        switch status {
+        case .notDetermined:
+            return await withCheckedContinuation { continuation in
                 #if swift(>=5.9)
                     if #available(iOS 17.0, *) {
-                        EKEventStore().requestFullAccessToEvents(completion: { (granted: Bool, error: Error?) -> Void in
+                        EKEventStore().requestFullAccessToEvents { granted, error in
                             if let error = error {
+                                print("Calendar access not granted: \(error)")
                                 warning(.service, "Calendar access not granted", error: error)
                             }
-                            promise(.success(granted))
-                        })
+                            continuation.resume(returning: granted)
+                        }
                     } else {
                         EKEventStore().requestAccess(to: .event) { granted, error in
                             if let error = error {
+                                print("Calendar access not granted: \(error)")
                                 warning(.service, "Calendar access not granted", error: error)
                             }
-                            promise(.success(granted))
+                            continuation.resume(returning: granted)
                         }
                     }
                 #else
                     EKEventStore().requestAccess(to: .event) { granted, error in
                         if let error = error {
+                            print("Calendar access not granted: \(error)")
                             warning(.service, "Calendar access not granted", error: error)
                         }
-                        promise(.success(granted))
+                        continuation.resume(returning: granted)
                     }
                 #endif
-            case .denied,
-                 .restricted:
-                promise(.success(false))
-            case .authorized:
-                promise(.success(true))
-
-            #if swift(>=5.9)
-                case .fullAccess:
-                    promise(.success(true))
-                case .writeOnly:
-                    if #available(iOS 17.0, *) {
-                        EKEventStore().requestFullAccessToEvents(completion: { (granted: Bool, error: Error?) -> Void in
+            }
+        case .denied,
+             .restricted:
+            return false
+        case .authorized:
+            return true
+        #if swift(>=5.9)
+            case .fullAccess:
+                return true
+            case .writeOnly:
+                if #available(iOS 17.0, *) {
+                    return await withCheckedContinuation { continuation in
+                        EKEventStore().requestFullAccessToEvents { granted, error in
                             if let error = error {
-                                print("Calendar access not upgraded")
+                                print("Calendar access not upgraded: \(error)")
                                 warning(.service, "Calendar access not upgraded", error: error)
                             }
-                            promise(.success(granted))
-                        })
+                            continuation.resume(returning: granted)
+                        }
                     }
-            #endif
-
-            @unknown default:
-                warning(.service, "Unknown calendar access status")
-                promise(.success(false))
-            }
-        }.eraseToAnyPublisher()
+                } else {
+                    return false
+                }
+        #endif
+        @unknown default:
+            warning(.service, "Unknown calendar access status")
+            return false
+        }
     }
 
     func calendarIDs() -> [String] {