فهرست منبع

Glucose alarms removed from LibreTransmitter

Ivan Valkou 4 سال پیش
والد
کامیت
4bc7afec77

+ 0 - 226
Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/GlucoseSchedules.swift

@@ -1,226 +0,0 @@
-//
-//  GlucoseSchedules.swift
-//  MiaomiaoClient
-//
-//  Created by Bjørn Inge Berg on 19/04/2019.
-//  Copyright © 2019 Bjørn Inge Berg. All rights reserved.
-//
-
-import Foundation
-import HealthKit
-//import MiaomiaoClient
-public enum GlucoseScheduleAlarmResult: Int, CaseIterable {
-    case none = 0
-    case low
-    case high
-
-    func isAlarming() -> Bool {
-        rawValue != GlucoseScheduleAlarmResult.none.rawValue
-    }
-}
-
-enum GlucoseSchedulesValidationStatus {
-    case success
-    case error(String)
-}
-
-class GlucoseScheduleList: Codable, CustomStringConvertible {
-    var description: String {
-        "(schedules: \(schedules) )"
-    }
-
-    public var schedules = [GlucoseSchedule]()
-
-    public var enabledSchedules: [GlucoseSchedule] {
-        schedules.compactMap({ $0.enabled == true ? $0 : nil })
-    }
-
-    //this is only used by the ui to count total number of schedules
-    public static let minimumSchedulesCount = 2
-
-    public var activeSchedules: [GlucoseSchedule] {
-        enabledSchedules.compactMap {
-            if let activeTime = $0.getScheduleActiveToFrom() {
-                let now = Date()
-                return activeTime.contains(now) ? $0 : nil
-            }
-            return nil
-        }
-    }
-
-    private func validateGlucoseThresholds() -> GlucoseSchedulesValidationStatus? {
-        // This is on purpose
-        // we check all chedules for valid thresholds
-        for schedule in self.schedules {
-            if let low = schedule.lowAlarm, let high = schedule.highAlarm {
-                if low == high {
-                    return .error("One of your glucose schedules had the same value for low and high thresholds")
-                }
-                if low > high {
-                    return .error("One of your glucose schedules had a low threshold set above your high threshold")
-                }
-                //just for completness sake, this would never be called
-                if high < low {
-                    return .error("One of your glucose schedules had a high threshold set below your low threshold")
-                }
-            }
-        }
-        return nil
-    }
-
-    public func validateGlucoseSchedules() -> GlucoseSchedulesValidationStatus {
-        if let errors = validateGlucoseThresholds() {
-            return errors
-        }
-
-        // if we have zero or 1 enabled schedules, overlapping would not be possible
-        // (there is nothing to overlap on), so we skip interval check
-        guard self.enabledSchedules.count > 1 else {
-            return .success
-        }
-
-        var sameStartEnd = false
-        let intervals: [DateInterval] = enabledSchedules.compactMap({
-            var schedule = $0.getScheduleActiveToFrom()
-            if let start = schedule?.start, let end = schedule?.end {
-                if start == end {
-                    sameStartEnd = true
-                    return nil
-                }
-            }
-            // This compensates for Datetimes being closed range in nature
-            // example,
-            // interval1start = 12:00, interval1end=14:00
-            // interval2start = 14:00, interval2end=24:00
-            // interval1end and interval2 would collide when .intersect()-ing,
-            // so we change interval1end to 13:59:59
-            // and interval2end to 23:59:59
-            // This function is only used in the gui for validation, so this is acceptable
-            //
-            if let end = schedule?.end {
-                if let newEnd = Calendar.current.date(byAdding: .second, value: -1, to: end) {
-                    schedule?.end = newEnd
-                }
-            }
-            return schedule
-        })
-        if sameStartEnd {
-            return .error("One interval had the same start and end!")
-        }
-        if let intersects = intervals.intersect() {
-            print("Glucose schedule collided, not valid! \(intersects)")
-            return .error("Glucose schedules had overlapping time intervals")
-        }
-        return .success
-    }
-    //for convenience
-    public static var snoozedUntil: Date? {
-        UserDefaults.standard.snoozedUntil
-    }
-
-    public static func isSnoozed() -> Bool {
-        let now = Date()
-
-        if let snoozedUntil = snoozedUntil {
-            return snoozedUntil >= now
-        }
-        return false
-    }
-
-    public func getActiveAlarms(_ currentGlucoseInMGDL: Double) -> GlucoseScheduleAlarmResult {
-        for schedule in self.activeSchedules {
-            if let lowAlarm = schedule.lowAlarm, currentGlucoseInMGDL <= lowAlarm {
-                return .low
-            }
-            if let highAlarm = schedule.highAlarm, currentGlucoseInMGDL >= highAlarm {
-                return .high
-            }
-        }
-        return .none
-    }
-}
-
-class GlucoseSchedule: Codable, CustomStringConvertible {
-    var from: DateComponents?
-    var to: DateComponents?
-    var lowAlarm: Double?
-    var highAlarm: Double?
-    var enabled: Bool?
-
-    init() {
-    }
-
-    //glucose schedules are stored as standalone datecomponents (i.e. offsets)
-    //this takes the current start of day and adds those offsets,
-    // and returns a Dateinterval with those offsets applied
-    public func getScheduleActiveToFrom() -> DateInterval? {
-        guard let fromComponents = from, let toComponents = to else {
-            return nil
-        }
-
-        let now = Date()
-        let previousMidnight = Calendar.current.startOfDay(for: now)
-        let helper = Calendar.current.date(byAdding: .day, value: 1, to: previousMidnight)!
-        let nextMidnight = Calendar.current.startOfDay(for: helper)
-
-        let fromDate: Date? =  Calendar.current.date(byAdding: fromComponents, to: previousMidnight)
-        var toDate: Date?
-        if  toComponents.minute == 0 && toComponents.hour == 0 {
-            toDate = nextMidnight
-        } else {
-            toDate = Calendar.current.date(byAdding: toComponents, to: previousMidnight)!
-        }
-
-        if let fromDate = fromDate, let toDate = toDate, toDate >= fromDate {
-            return DateInterval(start: fromDate, end: toDate)
-        }
-        return nil
-    }
-    //stores the alarm. It does not synhronize the value with the underlaying userdefaults
-    //that is up to the caller of this class
-    public func storeLowAlarm(forUnit unit: HKUnit, lowAlarm: Double) {
-        if unit == HKUnit.millimolesPerLiter {
-            self.lowAlarm = lowAlarm * 18
-            return
-        }
-
-        self.lowAlarm = lowAlarm
-    }
-
-    public func retrieveLowAlarm(forUnit unit: HKUnit) -> Double? {
-        if let lowAlarm = self.lowAlarm {
-            if unit == HKUnit.millimolesPerLiter {
-                return (lowAlarm / 18).roundTo(places: 1)
-            } else {
-                return lowAlarm
-            }
-        }
-
-        return nil
-    }
-
-    //stores the alarm. It does not synhronize the value with the underlaying userdefaults
-    //that is up to the caller of this class
-    public func storeHighAlarm(forUnit unit: HKUnit, highAlarm: Double) {
-        if unit == HKUnit.millimolesPerLiter {
-            self.highAlarm = highAlarm * 18
-            return
-        }
-
-        self.highAlarm = highAlarm
-    }
-    public func retrieveHighAlarm(forUnit unit: HKUnit) -> Double? {
-        if let highAlarm = self.highAlarm {
-            if unit == HKUnit.millimolesPerLiter {
-                return (highAlarm / 18).roundTo(places: 1)
-            }
-            return highAlarm
-        }
-
-        return nil
-    }
-
-    var description: String {
-        "(from: \(String(describing: from)), to: \(String(describing: to)), low: \(String(describing: lowAlarm)), high: \(String(describing: highAlarm)), enabled: \(String(describing: enabled)))"
-    }
-}

+ 0 - 27
Dependencies/LibreTransmitter/Sources/LibreTransmitter/Common/Settings/UserDefaults+Alarmsettings.swift

@@ -11,7 +11,6 @@ import HealthKit
 
 extension UserDefaults {
     private enum Key: String {
-        case glucoseSchedules = "no.bjorninge.glucoseschedules"
         case mmAlertLowBatteryWarning = "no.bjorninge.mmLowBatteryWarning"
         case mmAlertInvalidSensorDetected = "no.bjorninge.mmInvalidSensorDetected"
         case mmAlertNewSensorDetected = "no.bjorninge.mmNewSensorDetected"
@@ -106,14 +105,6 @@ extension UserDefaults {
         }
     }
 
-    var enabledSchedules: [GlucoseSchedule]? {
-        glucoseSchedules?.schedules.compactMap({ schedule -> GlucoseSchedule? in
-            if schedule.enabled ?? false {
-                return schedule
-            }
-            return nil
-        })
-    }
     var snoozedUntil: Date? {
         get {
             object(forKey: Key.mmSnoozedUntil.rawValue) as? Date
@@ -122,22 +113,4 @@ extension UserDefaults {
             set(newValue, forKey: Key.mmSnoozedUntil.rawValue)
         }
     }
-    var glucoseSchedules: GlucoseScheduleList? {
-        get {
-            if let savedGlucoseSchedules = object(forKey: Key.glucoseSchedules.rawValue) as? Data {
-                let decoder = JSONDecoder()
-                if let loadedGlucoseSchedules = try? decoder.decode(GlucoseScheduleList.self, from: savedGlucoseSchedules) {
-                    return loadedGlucoseSchedules
-                }
-            }
-
-            return GlucoseScheduleList()
-        }
-        set {
-            let encoder = JSONEncoder()
-            if let val = newValue, let encoded = try? encoder.encode(val) {
-                set(encoded, forKey: Key.glucoseSchedules.rawValue)
-            }
-        }
-    }
 }

+ 0 - 380
Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/AlarmSettings/AlarmSettingsView.swift

@@ -1,380 +0,0 @@
-//
-//  AlarmSettingsView.swift
-//  LibreTransmitterUI
-//
-//  Created by Bjørn Inge Berg on 11/05/2021.
-//  Copyright © 2021 Mark Wilson. All rights reserved.
-//
-
-import SwiftUI
-import HealthKit
-
-private class AlarmSettingsIcons {
-
-    public static var Shared = AlarmSettingsIcons()
-
-    public func getImage(resourceName: String) -> some View{
-        let bundle = Bundle(for: type(of: self))
-        if let uiimage = UIImage(named: resourceName, in: bundle, compatibleWith: nil) {
-            return AnyView(Image(uiImage: uiimage))
-        }
-        return AnyView(EmptyView())
-    }
-    lazy var icons8_schedule_50 : some View = getImage(resourceName: "icons8-schedule-50")
-    lazy var icons8_drop_down_arrow_50 : some View = getImage(resourceName: "icons8-drop-down-arrow-50")
-    lazy var icons8_slide_up_50: some View = getImage(resourceName: "icons8-slide-up-50")
-}
-
-
-class AlarmScheduleState : ObservableObject, Identifiable, Hashable{
-
-    var id = UUID()
-
-    private let glucoseRate = 18.018
-
-    @Published var lowmgdl : Double = 72
-    @Published var highmgdl : Double = 180  
-    @Published var enabled : Bool? = false
-
-
-    @Published var alarmDateComponents  : AlarmTimeCellExternalState = AlarmTimeCellExternalState()
-
-    public func setLowAlarm(forUnit unit: HKUnit, lowAlarm: Double) {
-
-        if unit == HKUnit.millimolesPerLiter {
-            self.lowmgdl = lowAlarm * glucoseRate
-            return
-        }
-
-        self.lowmgdl = lowAlarm
-    }
-
-    public func getLowAlarm(forUnit unit: HKUnit) -> Double {
-
-        if unit == HKUnit.millimolesPerLiter {
-            return (lowmgdl / glucoseRate).roundTo(places: 1)
-        }
-
-        return lowmgdl
-
-
-
-
-    }
-
-    public func setHighAlarm(forUnit unit: HKUnit, highAlarm: Double) {
-
-        if unit == HKUnit.millimolesPerLiter {
-            self.highmgdl = highAlarm * glucoseRate
-            return
-        }
-
-        self.highmgdl = highAlarm
-    }
-
-    public func getHighAlarm(forUnit unit: HKUnit) -> Double {
-
-        if unit == HKUnit.millimolesPerLiter {
-            return (highmgdl / glucoseRate).roundTo(places: 1)
-        }
-        return highmgdl
-
-    }
-
-
-}
-
-class AlarmSettingsState : ObservableObject     {
-    @Published var schedules : [AlarmScheduleState] = []
-
-
-    static private func setDateComponentState(_ state: AlarmScheduleState) {
-        if state.alarmDateComponents.startComponents == nil {
-            state.alarmDateComponents.startComponents = DateComponents(hour:0, minute: 0)
-        }
-
-        if state.alarmDateComponents.endComponents == nil {
-            state.alarmDateComponents.endComponents = DateComponents(hour:0, minute: 0)
-        }
-
-        let from = state.alarmDateComponents.startComponents!.ToTimeString()
-        let to = state.alarmDateComponents.endComponents!.ToTimeString()
-
-        state.alarmDateComponents.componentsAsText = "\(from) - \(to)"
-
-
-    }
-
-    //this is just to be able to use old serialized schedules from uikit version
-    //i.e. we want to be drop in compatible
-    static func loadState()-> AlarmSettingsState {
-
-        guard let storedState = UserDefaults.standard.glucoseSchedules, storedState.schedules.count > 0 else {
-            print("stored state for alarms was empty")
-            let newState = AlarmSettingsState()
-            for _ in (0..<GlucoseScheduleList.minimumSchedulesCount) {
-                let schedule = AlarmScheduleState()
-                setDateComponentState(schedule)
-                schedule.enabled = false
-                newState.schedules.append(schedule)
-            }
-
-            return newState
-        }
-
-        let alarmState = AlarmSettingsState()
-
-        print("stored state for alarms contains \(storedState.schedules.count) elements")
-
-        for i in (0..<storedState.schedules.count) {
-            let schedule = AlarmScheduleState()
-
-            schedule.enabled = storedState.schedules[i].enabled
-            schedule.lowmgdl = storedState.schedules[i].lowAlarm ?? -1
-            schedule.highmgdl = storedState.schedules[i].highAlarm ?? -1
-
-
-            schedule.alarmDateComponents.startComponents = storedState.schedules[i].from
-            schedule.alarmDateComponents.endComponents  = storedState.schedules[i].to
-
-            setDateComponentState(schedule)
-
-            alarmState.schedules.append(schedule)
-
-
-        }
-
-        return alarmState
-
-
-    }
-
-
-    func trySaveState() -> StatusMessage?{
-        let legacyState = GlucoseScheduleList()
-        for newStateSchedule in self.schedules {
-            let glucoseSchedule = GlucoseSchedule()
-            glucoseSchedule.enabled = newStateSchedule.enabled
-            //view is using wrapper binding to store these values so should be safe
-            glucoseSchedule.lowAlarm = newStateSchedule.lowmgdl
-            glucoseSchedule.highAlarm = newStateSchedule.highmgdl
-            glucoseSchedule.from = newStateSchedule.alarmDateComponents.startComponents
-            glucoseSchedule.to = newStateSchedule.alarmDateComponents.endComponents
-
-            legacyState.schedules.append(glucoseSchedule)
-
-        }
-        let result = legacyState.validateGlucoseSchedules()
-        switch result {
-        case .success:
-
-            print("glucose schedule valid: \(String(describing: legacyState))")
-            UserDefaults.standard.glucoseSchedules = legacyState
-        case .error(let description):
-            print("Could not save glucose schedules, validation failed: \(description)")
-            return StatusMessage(title: "Error", message: description)
-        }
-
-        return nil
-
-
-    }
-}
-
-
-
-struct AlarmDateRow: View {
-    var schedule: AlarmScheduleState
-    @State var tag: Int
-    @Binding var subviewSelection: Int?
-
-    var body: some View {
-
-        HStack(alignment: .center){
-            NavigationLink(destination: CustomDataPickerView().environmentObject(schedule.alarmDateComponents),
-                           tag: tag,
-                           selection: $subviewSelection) {
-                Group {
-                    AlarmSettingsIcons.Shared.icons8_schedule_50
-                        .frame(maxWidth: 50, alignment: .leading)
-                    TextField("Active from - to ", text:  Binding<String>(get: { "\(schedule.alarmDateComponents.componentsAsText)" },
-                                                      set: { schedule.alarmDateComponents.componentsAsText = $0 }))
-                        .textFieldStyle(RoundedBorderTextFieldStyle())
-                        .disableAutocorrection(true)
-                        .keyboardType(.decimalPad)
-                        .border(Color(UIColor.separator))
-                        .disabled(true)
-                        .frame(minWidth: 130, idealWidth: 130, maxWidth: .infinity, alignment: .center)
-                }.onTapGesture {
-                    print("cheduleActivationRow tapped")
-                    subviewSelection = tag
-                    self.hideKeyboard()
-
-                }
-
-            }
-
-
-            Toggle("", isOn: Binding<Bool>(get: { (schedule.enabled) ?? false },
-                                             set: { schedule.enabled = $0 }))
-                .frame(maxWidth: 50, alignment: .trailing)
-
-        }
-    }
-}
-
-struct AlarmLowRow: View {
-    var schedule: AlarmScheduleState
-    var glucoseUnit: HKUnit
-    var glucoseUnitDesc: String
-
-    var errorReporter: FormErrorState
-
-    var body: some View {
-        HStack(alignment: .center){
-
-            AlarmSettingsIcons.Shared.icons8_drop_down_arrow_50
-                .frame(maxWidth: 50, alignment: .leading)
-            Text("Low")
-                .frame(maxWidth: 100, alignment: .leading)
-            Spacer()
-
-            /*TextField("glucose", text:  Binding<String>(get: { schedule.getLowAlarm(forUnit: glucoseUnit) },
-                                                        set: { schedule.setLowAlarm(forUnit: glucoseUnit, lowAlarm: $0) }))
-                .textFieldStyle(RoundedBorderTextFieldStyle())
-                .disableAutocorrection(true)
-                .keyboardType(.decimalPad)
-                .border(Color(UIColor.separator))
-                .frame(maxWidth: 100, alignment: .trailing)*/
-
-            NumericTextField(description: "glucose", showDescription: false, numericValue: Binding<Double>(get: { schedule.getLowAlarm(forUnit: glucoseUnit) },
-                                                                                                           set: { schedule.setLowAlarm(forUnit: glucoseUnit, lowAlarm: $0) }), formErrorState: errorReporter)
-
-            Text("\(glucoseUnitDesc)")
-                .font(.footnote)
-                .frame(maxWidth: 100, alignment: .trailing)
-
-        }
-        .onTapGesture {
-            self.hideKeyboard()
-        }
-    }
-}
-
-struct AlarmHighRow: View {
-    var schedule: AlarmScheduleState
-    var glucoseUnit: HKUnit
-    var glucoseUnitDesc: String
-
-    var errorReporter: FormErrorState
-
-    var body: some View {
-        HStack(alignment: .center){
-
-            AlarmSettingsIcons.Shared.icons8_slide_up_50
-                .frame(maxWidth: 50, alignment: .leading)
-            Text("High")
-                .frame(maxWidth: 100, alignment: .leading)
-            Spacer()
-
-            NumericTextField(description: "glucose", showDescription: false, numericValue: Binding<Double>(get: { schedule.getHighAlarm(forUnit: glucoseUnit) },
-                                                                                                           set: { schedule.setHighAlarm(forUnit: glucoseUnit, highAlarm: $0) }), formErrorState: errorReporter)
-
-
-            Text("\(glucoseUnitDesc)")
-                .font(.footnote)
-                .frame(maxWidth: 100, alignment: .trailing)
-
-
-        }
-        .onTapGesture {
-            self.hideKeyboard()
-        }
-    }
-}
-
-struct AlarmSettingsView: View {
-
-
-
-    private(set) var glucoseUnit: HKUnit
-
-    var glucoseUnitDesc : String {
-        //"mmol/L"
-        glucoseUnit.localizedShortUnitString
-    }
-
-
-    @State private var presentableStatus: StatusMessage?
-
-    @StateObject var alarmState = AlarmSettingsState.loadState()
-
-
-    @State private var subviewSelection: Int? = nil
-
-    
-
-
-    var body: some View {
-
-        list
-        .ignoresSafeArea()
-        .alert(item: $presentableStatus) { status in
-            Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!")))
-        }
-        
-
-    }
-
-    @StateObject var errorReporter = FormErrorState()
-    
-
-    var list: some View {
-
-        List {
-            ForEach(Array(alarmState.schedules.enumerated()), id: \.1) { i, schedule in
-                Section(header: Text(NSLocalizedString("Schedule ", comment: "") + "\(i+1)")){
-                    AlarmDateRow(schedule: schedule, tag: i, subviewSelection: $subviewSelection)
-                    AlarmLowRow(schedule: schedule, glucoseUnit: glucoseUnit, glucoseUnitDesc: glucoseUnitDesc, errorReporter: errorReporter)
-                    AlarmHighRow(schedule: schedule, glucoseUnit: glucoseUnit, glucoseUnitDesc: glucoseUnitDesc, errorReporter: errorReporter)
-
-                }.onTapGesture {
-                    self.hideKeyboard()
-                }
-
-            }
-
-
-            Section {
-                Button("Save") {
-                    saveButtonAction()
-                }.buttonStyle(BlueButtonStyle())
-            }
-        }
-        .listStyle(InsetGroupedListStyle())
-
-    }
-
-    func saveButtonAction() {
-        print("tapped save schedules")
-        if errorReporter.hasAnyError {
-            presentableStatus = StatusMessage(title: "Error", message: "Some ui element was incorrectly specified")
-            return
-        }
-        if let error = alarmState.trySaveState() {
-            presentableStatus = error
-        } else {
-            presentableStatus = StatusMessage(title: "Success", message: "Schedules were saved successfully!")
-        }
-
-
-    }
-
-    
-}
-
-struct AlarmSettingsView_Previews: PreviewProvider {
-    static var previews: some View {
-        AlarmSettingsView(glucoseUnit: .millimolesPerLiter)
-    }
-}

+ 0 - 270
Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/AlarmSettings/CustomDataPickerView.swift

@@ -1,270 +0,0 @@
-//
-//  CustomDataPickerView.swift
-//  LibreTransmitterUI
-//
-//  Created by Bjørn Inge Berg on 28/04/2021.
-//  Copyright © 2021 Mark Wilson. All rights reserved.
-//
-
-import SwiftUI
-
-protocol CustomDataPickerDelegate: AnyObject {
-    func pickerDidPickValidRange()
-
-}
-
-class AlarmTimeCellExternalState :ObservableObject, Identifiable, Hashable {
-
-    var id = UUID()
-
-    @Published var start : Int = 0
-    @Published var end : Int = 0
-
-    // These will be auto populøated
-    // when the start and end properties above change
-    @Published var startComponents : DateComponents? = nil
-    @Published var endComponents : DateComponents? = nil
-
-    @Published var componentsAsText : String = ""
-
-}
-
-//handle parts of alarmsettingsview's state (=externalstate)
-struct CustomDataPickerView: View {
-    private var startComponentTimes : [DateComponents]
-    private var endComponentTimes : [DateComponents]
-
-    private var startTimes = [String]()
-    private var endTimes = [String]()
-
-
-
-    @Environment(\.presentationMode) var presentationMode
-    @EnvironmentObject var externalState: AlarmTimeCellExternalState
-
-    @State var externalStateCopy: AlarmTimeCellExternalState = AlarmTimeCellExternalState()
-
-    public weak var delegate: CustomDataPickerDelegate?
-
-    private func popView() {
-        self.presentationMode.wrappedValue.dismiss()
-    }
-
-    static func defaultTimeArray() -> [DateComponents] {
-        var arr  = [DateComponents]()
-
-        for hr in 0...23 {
-            for min in 0 ..< 2 {
-                var components = DateComponents()
-                components.hour = hr
-                components.minute = min == 1 ? 30 : 0
-                arr.append(components)
-            }
-        }
-        var components = DateComponents()
-        components.hour = 0
-        components.minute = 0
-        arr.append(components)
-
-        return arr
-    }
-
-
-
-    private func callDelegate() {
-        delegate?.pickerDidPickValidRange()
-    }
-
-    private func verifyRange(){
-
-        // This can be simplified but decided not to do so
-        // because the intention becomes more clear
-
-        var isok : Bool
-
-        if externalState.start == 0 || externalState.end == 0 {
-            isok = true
-        } else {
-            if externalState.start > externalState.end {
-                isok = false
-            } else if externalState.end < externalState.start {
-                isok = false
-            } else {
-                isok = true
-            }
-        }
-
-        print("is ok? \(isok)")
-        if isok {
-            updateTextualState()
-            callDelegate()
-            popView()
-
-        } else {
-            presentableStatus = .init(title: "Interval error", message: "Selected time interval was incorrectly specified")
-        }
-
-
-    }
-
-    
-    var pickers: some View {
-        HStack {
-            Picker("", selection: $externalState.start.animation(), content: {
-                ForEach(startTimes.indices) { i in
-                    Text("\(startTimes[i])").tag(i)
-               }
-            })
-            //.border(Color.green)
-
-            .zIndex(10)
-            .frame(width: 100)
-            .clipped()
-            .labelsHidden()
-
-            Text("To ")
-
-            Picker("", selection: $externalState.end.animation(), content: {
-                ForEach(endTimes.indices) { i in
-                    Text("\(endTimes[i])").tag(i)
-               }
-            })
-            //.border(Color.red)
-            .zIndex(11)
-            .frame(width: 100)
-            .clipped()
-            .labelsHidden()
-
-        //}
-
-        .navigationBarBackButtonHidden(true)
-        .navigationBarItems(leading:
-            Button("Cancel"){
-                print("cancel button pressed, restoring state...")
-                restoreAlarmExternalState()
-                popView()
-
-            }.accentColor(.red), trailing:
-                Button("Save") {
-                    print("Save button pressed...")
-                    verifyRange()
-                }
-                .accentColor(.red)
-
-        )
-        }
-
-
-    }
-
-
-    @State private var presentableStatus: StatusMessage?
-
-    private func updateTextualState(_ shouldDelete: Bool = false){
-        if shouldDelete {
-            externalState.componentsAsText = ""
-            return
-        }
-        if let p1 = externalState.startComponents?.ToTimeString(), let p2 = externalState.endComponents?.ToTimeString() {
-            externalState.componentsAsText = "\(p1)-\(p2)"
-        }
-    }
-
-
-    var body: some View {
-
-        pickers
-        .pickerStyle(InlinePickerStyle())
-        .onChange(of: externalState.start, perform: { value in
-            print("selectedtart changed to \(value)")
-            externalState.startComponents = startComponentTimes[value]
-
-
-
-        })
-        .onChange(of: externalState.end, perform: { value in
-            print("selectedEnd changed to \(value)")
-            externalState.endComponents = endComponentTimes[value]
-
-
-
-        })
-        .onAppear {
-            //this could potentially fail with out of bounds but we trust our parent view!
-            externalState.startComponents = startComponentTimes[externalState.start]
-            externalState.endComponents = endComponentTimes[externalState.end]
-            updateTextualState()
-
-
-            copyAlarmExternalState()
-
-        }
-        .alert(item: $presentableStatus) { status in
-            Alert(title: Text(status.title), message: Text(status.message) , dismissButton: .default(Text("Got it!")))
-        }
-
-
-    }
-
-    //decided against uding nscoding with copy() here
-    private func copyAlarmExternalState() {
-        externalStateCopy = AlarmTimeCellExternalState()
-        /*
-         var id = UUID()
-
-         @Published var start : Int = 0
-         @Published var end : Int = 0
-
-         // These will be auto populøated
-         // when the start and end properties above change
-         @Published var startComponents : DateComponents? = nil
-         @Published var endComponents : DateComponents? = nil
-
-         @Published var componentsAsText : String = ""**/
-        externalStateCopy.id = externalState.id
-        externalStateCopy.start = externalState.start
-        externalStateCopy.end = externalState.end
-        externalStateCopy.startComponents = externalState.startComponents
-        externalStateCopy.endComponents = externalStateCopy.endComponents
-        externalStateCopy.componentsAsText = externalState.componentsAsText
-
-
-    }
-
-    private func restoreAlarmExternalState(){
-        externalState.id = externalStateCopy.id
-        externalState.start = externalStateCopy.start
-        externalState.end = externalStateCopy.end
-        externalState.startComponents = externalStateCopy.startComponents
-        externalStateCopy.endComponents =  externalStateCopy.endComponents
-        externalState.componentsAsText = externalStateCopy.componentsAsText
-
-
-    }
-
-
-    init() {
-        startComponentTimes = Self.defaultTimeArray()
-        endComponentTimes = Self.defaultTimeArray()
-
-
-        //string representations of the datecomponents arrays   
-
-        for component in startComponentTimes {
-            startTimes.append(component.ToTimeString(wantsAMPM:  Date.LocaleWantsAMPM))
-        }
-
-        for component in endComponentTimes {
-            endTimes.append(component.ToTimeString(wantsAMPM:  Date.LocaleWantsAMPM))
-
-        }
-
-
-    }
-}
-
-struct CustomDataPickerView_Previews: PreviewProvider {
-    static var previews: some View {
-        CustomDataPickerView().environmentObject(AlarmTimeCellExternalState())
-    }
-}

+ 0 - 14
Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/SettingsView.swift

@@ -181,12 +181,6 @@ struct SettingsView: View {
 
     }
 
-    var snoozeSection: some View {
-        Section {
-            Text("Snooze Alerts").frame(alignment: .center)
-        }
-    }
-
     var measurementSection : some View {
         Section(header: Text("Last measurement")) {
             if glucoseUnit == .millimolesPerLiter {
@@ -303,13 +297,6 @@ struct SettingsView: View {
     //todo: replace sub with navigationlinks
     var advancedSection: some View {
         Section(header: Text("Advanced")) {
-            //these subviews don't really need to be notified once glucose unit changes
-            // so we just pass glucoseunit directly on init
-            ZStack {
-                NavigationLink(destination: AlarmSettingsView(glucoseUnit: self.glucoseUnit)) {
-                    SettingsItem(title: "Alarms", detail: .constant(""))
-                }
-            }
             ZStack {
                 NavigationLink(destination: GlucoseSettingsView(glucoseUnit: self.glucoseUnit)) {
                     SettingsItem(title: "Glucose Settings", detail: .constant(""))
@@ -339,7 +326,6 @@ struct SettingsView: View {
 
     var overview: some View {
         List {
-            snoozeSection
             measurementSection
 //            if !glucoseMeasurement.predictionDate.isEmpty{
 //                predictionSection

+ 0 - 140
Dependencies/LibreTransmitter/Sources/LibreTransmitter/LibreTransmitterUI/Views/Settings/SnoozeView.swift

@@ -1,140 +0,0 @@
-//
-//  TestView.swift
-//  MiaomiaoClientUI
-//
-//  Created by Bjørn Inge Berg on 15/10/2020.
-//  Copyright © 2020 Bjørn Inge Vikhammermo Berg. All rights reserved.
-//
-
-import SwiftUI
-
-struct SnoozeView: View {
-
-    private var pickerTimes: [TimeInterval] {
-        SnoozeView.pickerTimesArray()
-    }
-
-    private var formatter: DateComponentsFormatter {
-        let formatter = DateComponentsFormatter()
-        formatter.allowsFractionalUnits = false
-        formatter.unitsStyle = .full
-        return formatter
-    }
-
-    private func formatInterval(_ interval: TimeInterval) -> String {
-        formatter.string(from: interval)!
-    }
-
-    private var dateFormatter: DateFormatter {
-        let formatter = DateFormatter()
-        formatter.timeStyle = .short
-        return formatter
-    }
-
-    @Binding var isAlarming : Bool
-    @Binding var activeAlarms: LibreTransmitter.GlucoseScheduleAlarmResult
-
-    static func pickerTimesArray() -> [TimeInterval] {
-        var arr  = [TimeInterval]()
-
-        let mins10 = 0.166_67
-        let mins20 = mins10 * 2
-        let mins30 = mins10 * 3
-        //let mins40 = mins10 * 4
-
-        for hr in 0..<2 {
-            for min in [0.0, mins20, mins20 * 2] {
-                arr.append(TimeInterval(hours: Double(hr) + min))
-            }
-        }
-        for hr in 2..<4 {
-            for min in [0.0, mins30] {
-                arr.append(TimeInterval(hours: Double(hr) + min))
-            }
-        }
-
-        for hr in 4...8 {
-            arr.append(TimeInterval(hours: Double(hr)))
-        }
-
-        return arr
-    }
-
-    func getSnoozeDescription() -> String {
-        var snoozeDescription  = ""
-        var celltext = ""
-
-        switch activeAlarms {
-            case .high:
-                celltext = NSLocalizedString("High Glucose Alarm active", comment: "High Glucose Alarm active")
-            case .low:
-                celltext = NSLocalizedString("Low Glucose Alarm active", comment: "Low Glucose Alarm active")
-            case .none:
-                celltext = NSLocalizedString("No Glucose Alarm active", comment: "No Glucose Alarm active")
-        }
-
-        if let until = GlucoseScheduleList.snoozedUntil, until > Date() {
-            snoozeDescription = String(format: NSLocalizedString("snoozing until %@", comment: "snoozing until %@"), dateFormatter.string(from: until))
-        } else {
-            snoozeDescription = NSLocalizedString("not snoozing", comment: "not snoozing")  
-        }
-
-        return [celltext, snoozeDescription].joined(separator: ", ")
-    }
-
-    @State private var selectedInterval = 0
-    @State private var snoozeDescription = "nothing to see here"
-
-    var snoozeButton: some View {
-        VStack(alignment: .leading) {
-            Button(action: {
-                print("snooze from testview clicked")
-                let interval = pickerTimes[selectedInterval]
-                let snoozeFor = formatter.string(from: interval)!
-                let untilDate = Date() + interval
-                UserDefaults.standard.snoozedUntil = untilDate < Date() ? nil : untilDate
-                print("will snooze for \(snoozeFor) until \(dateFormatter.string(from: untilDate))")
-                snoozeDescription = getSnoozeDescription()
-            }) {
-                Text("Click to Snooze Alerts")
-                    .padding()
-            }
-        }
-
-    }
-
-    var snoozePicker: some View {
-        VStack {
-            Picker(selection: $selectedInterval, label: Text("Strength")) {
-                ForEach(0 ..< pickerTimes.count) {
-                    Text(formatInterval(self.pickerTimes[$0]))
-                }
-            }
-            .pickerStyle(.wheel)
-        }
-
-    }
-
-    var snoozeDesc : some View {
-        VStack(alignment: .leading) {
-            Text(snoozeDescription)
-        }
-    }
-
-    var body: some View {
-        Form {
-            snoozeDesc
-            snoozePicker
-            snoozeButton
-        }
-        .onAppear {
-            snoozeDescription = getSnoozeDescription()
-        }
-    }
-}
-
-struct TestView_Previews: PreviewProvider {
-    static var previews: some View {
-        SnoozeView(isAlarming: .constant(true), activeAlarms: .constant(.none))
-    }
-}

+ 0 - 21
Dependencies/LibreTransmitter/Sources/LibreTransmitter/Observables/AlarmStatus.swift

@@ -1,21 +0,0 @@
-//
-//  AlarmStatus.swift
-//  LibreTransmitter
-//
-//  Created by Bjørn Inge Berg on 09/07/2021.
-//  Copyright © 2021 Mark Wilson. All rights reserved.
-//
-
-import Foundation
-public class AlarmStatus : ObservableObject , Equatable, Hashable{
-    @Published public var isAlarming = false
-    @Published public var glucoseScheduleAlarmResult = GlucoseScheduleAlarmResult.none
-
-    public static func ==(lhs: AlarmStatus, rhs: AlarmStatus) -> Bool {
-         lhs.isAlarming == rhs.isAlarming && lhs.glucoseScheduleAlarmResult == rhs.glucoseScheduleAlarmResult
-    }
-
-    static public func createNew() -> AlarmStatus{
-        AlarmStatus()
-    }
-}

+ 3 - 3
FreeAPS.xcodeproj/xcuserdata/i.valkou.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -33,17 +33,17 @@
 		<key>FreeAPSWatch (Complication).xcscheme_^#shared#^_</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>11</integer>
+			<integer>18</integer>
 		</dict>
 		<key>FreeAPSWatch (Notification).xcscheme_^#shared#^_</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>12</integer>
+			<integer>17</integer>
 		</dict>
 		<key>FreeAPSWatch.xcscheme_^#shared#^_</key>
 		<dict>
 			<key>orderHint</key>
-			<integer>8</integer>
+			<integer>16</integer>
 		</dict>
 		<key>ReactiveSwift (Playground) 1.xcscheme</key>
 		<dict>

+ 1 - 1
FreeAPS/Sources/APS/CGM/AppGroupSource.swift

@@ -62,7 +62,7 @@ struct AppGroupSource: GlucoseSource {
     }
 
     func sourceInfo() -> [String: Any]? {
-        [GlucoseSourceKey.description.rawValue: "Group ID: \(String(describing: Bundle.main.appGroupSuiteName))"]
+        [GlucoseSourceKey.description.rawValue: "Group ID: \(Bundle.main.appGroupSuiteName ?? "Not set"))"]
     }
 }