Просмотр исходного кода

use scroll wheel pickers in Override UI

* Use scroll wheel picker for SMB Disabling schedule and Max SMB/UAM Minutes.
* Renames `SMB Minutes` and `UAM SMB Minutes` to `Max SMB Minutes` and `Max UAM SMB Minutes`
* Limits SMB Disabling schedule to 00:00 - 23:00 for 24hr and 12:00 AM - 11:00 PM for am/pm
* Limits Max SMB/UAM Minutes to 0-180 in 5 min increments
Mike Plante 1 год назад
Родитель
Сommit
b1a1343785

+ 33 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -231,8 +231,9 @@ extension Home {
 
             let smbScheduleString = latestOverride
                 .smbIsScheduledOff && ((latestOverride.start?.stringValue ?? "") != (latestOverride.end?.stringValue ?? ""))
-                ? " \(latestOverride.start?.stringValue ?? "")-\(latestOverride.end?.stringValue ?? "")"
+                ? " \(formatTimeRange(start: latestOverride.start?.stringValue, end: latestOverride.end?.stringValue))"
                 : ""
+
             let smbToggleString = latestOverride.smbIsOff || latestOverride
                 .smbIsScheduledOff ? "SMBs Off\(smbScheduleString)" : ""
 
@@ -1031,3 +1032,34 @@ extension UIScreen {
         UIScreen.main.bounds.width
     }
 }
+
+// Helper function to convert a start and end hour to either 24-hour or AM/PM format
+func formatTimeRange(start: String?, end: String?) -> String {
+    guard let start = start, let end = end else {
+        return ""
+    }
+
+    // Check if the format is 24-hour or AM/PM
+    if is24HourFormat() {
+        // Return the original 24-hour format
+        return "\(start)-\(end)"
+    } else {
+        // Convert to AM/PM format using DateFormatter
+        let formatter = DateFormatter()
+        formatter.dateFormat = "HH"
+
+        if let startHour = Int(start), let endHour = Int(end) {
+            let startDate = Calendar.current.date(bySettingHour: startHour, minute: 0, second: 0, of: Date()) ?? Date()
+            let endDate = Calendar.current.date(bySettingHour: endHour, minute: 0, second: 0, of: Date()) ?? Date()
+
+            // Customize the format to "2p" or "2a"
+            formatter.dateFormat = "ha"
+            let startFormatted = formatter.string(from: startDate).lowercased().replacingOccurrences(of: "m", with: "")
+            let endFormatted = formatter.string(from: endDate).lowercased().replacingOccurrences(of: "m", with: "")
+
+            return "\(startFormatted)-\(endFormatted)"
+        } else {
+            return ""
+        }
+    }
+}

+ 151 - 16
FreeAPS/Sources/Modules/OverrideConfig/View/AddOverrideForm.swift

@@ -5,6 +5,10 @@ struct AddOverrideForm: View {
     @Environment(\.presentationMode) var presentationMode
     @StateObject var state: OverrideConfig.StateModel
     @State private var isEditing = false
+    @State private var displayPickerStart: Bool = false
+    @State private var displayPickerEnd: Bool = false
+    @State private var displayPickerSmbMinutes: Bool = false
+    @State private var displayPickerUamMinutes: Bool = false
     @State private var overrideTarget = false
     @Environment(\.colorScheme) var colorScheme
     @State private var showAlert = false
@@ -150,16 +154,71 @@ struct AddOverrideForm: View {
                 }
 
                 if state.smbIsScheduledOff {
-                    HStack {
-                        Text("First Hour SMBs Are Disabled (24 hours)")
-                        TextFieldWithToolBar(text: $state.start, placeholder: "0", numberFormatter: formatter)
-                        Text("hour").foregroundColor(.secondary)
+                    // First Hour SMBs Are Disabled
+                    VStack {
+                        HStack {
+                            Text("First Hour SMBs Are Disabled")
+                            Spacer()
+
+                            // Display current selection based on format
+                            Text(
+                                is24HourFormat() ? format24Hour(Int(truncating: state.start as NSNumber)) + ":00" :
+                                    convertTo12HourFormat(Int(truncating: state.start as NSNumber))
+                            )
+                            .foregroundColor(!displayPickerStart ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerStart.toggle() // Toggle the picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerStart {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: state.start as NSNumber) },
+                                set: { state.start = Decimal($0) }
+                            ), label: Text("")) {
+                                ForEach(0 ..< 24, id: \.self) { hour in
+                                    Text(is24HourFormat() ? format24Hour(hour) + ":00" : convertTo12HourFormat(hour)).tag(hour)
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
-                    HStack {
-                        Text("First Hour SMBs Are Resumed (24 hours)")
-                        TextFieldWithToolBar(text: $state.end, placeholder: "0", numberFormatter: formatter)
-                        Text("hour").foregroundColor(.secondary)
+                    .padding(.top)
+
+                    // First Hour SMBs Are Resumed
+                    VStack {
+                        HStack {
+                            Text("First Hour SMBs Are Resumed")
+                            Spacer()
+
+                            // Display current selection based on format
+                            Text(
+                                is24HourFormat() ? format24Hour(Int(truncating: state.end as NSNumber)) + ":00" :
+                                    convertTo12HourFormat(Int(truncating: state.end as NSNumber))
+                            )
+                            .foregroundColor(!displayPickerEnd ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerEnd.toggle() // Toggle the picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerEnd {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: state.end as NSNumber) },
+                                set: { state.end = Decimal($0) }
+                            ), label: Text("")) {
+                                ForEach(0 ..< 24, id: \.self) { hour in
+                                    Text(is24HourFormat() ? format24Hour(hour) + ":00" : convertTo12HourFormat(hour)).tag(hour)
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
                 }
                 HStack {
                     Toggle(isOn: $state.isfAndCr) {
@@ -179,16 +238,63 @@ struct AddOverrideForm: View {
                     }
                 }
                 if !state.smbIsOff {
-                    HStack {
-                        Text("SMB Minutes")
-                        TextFieldWithToolBar(text: $state.smbMinutes, placeholder: "0", numberFormatter: formatter)
-                        Text("minutes").foregroundColor(.secondary)
+                    // SMB Minutes Picker
+                    VStack {
+                        HStack {
+                            Text("Max SMB Minutes")
+                            Spacer()
+
+                            // Display current selection based on format
+                            Text("\(state.smbMinutes.formatted(.number)) min")
+                                .foregroundColor(!displayPickerSmbMinutes ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerSmbMinutes.toggle() // Toggle the picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerSmbMinutes {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: state.smbMinutes as NSNumber) },
+                                set: { state.smbMinutes = Decimal($0) }
+                            ), label: Text("")) {
+                                ForEach(Array(stride(from: 0, through: 180, by: 5)), id: \.self) { minute in
+                                    Text("\(minute) min").tag(minute)
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
-                    HStack {
-                        Text("UAM SMB Minutes")
-                        TextFieldWithToolBar(text: $state.uamMinutes, placeholder: "0", numberFormatter: formatter)
-                        Text("minutes").foregroundColor(.secondary)
+                    .padding(.top)
+
+                    // UAM SMB Minutes Picker
+                    VStack {
+                        HStack {
+                            Text("Max UAM SMB Minutes")
+                            Spacer()
+                            Text("\(state.uamMinutes.formatted(.number)) min")
+                                .foregroundColor(!displayPickerUamMinutes ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerUamMinutes.toggle() // Toggle picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerUamMinutes {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: state.uamMinutes as NSNumber) },
+                                set: { state.uamMinutes = Decimal($0) }
+                            ), label: Text("")) {
+                                ForEach(Array(stride(from: 0, through: 180, by: 5)), id: \.self) { minute in
+                                    Text("\(minute) min").tag(minute)
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
                 }
             }
 
@@ -299,3 +405,32 @@ struct AddOverrideForm: View {
         return defaultProfile || noDurationSpecified || targetZeroWithOverride || allSettingsDefault
     }
 }
+
+// Function to check if the phone is using 24-hour format
+func is24HourFormat() -> Bool {
+    let formatter = DateFormatter()
+    formatter.locale = Locale.current
+    formatter.dateStyle = .none
+    formatter.timeStyle = .short
+    let dateString = formatter.string(from: Date())
+
+    return !dateString.contains("AM") && !dateString.contains("PM")
+}
+
+// Helper function to convert hours to AM/PM format
+func convertTo12HourFormat(_ hour: Int) -> String {
+    let formatter = DateFormatter()
+    formatter.dateFormat = "h a"
+
+    // Create a date from the hour and format it to AM/PM
+    let calendar = Calendar.current
+    let components = DateComponents(hour: hour)
+    let date = calendar.date(from: components) ?? Date()
+
+    return formatter.string(from: date)
+}
+
+// Helper function to format 24-hour numbers as two digits
+func format24Hour(_ hour: Int) -> String {
+    String(format: "%02d", hour)
+}

+ 138 - 48
FreeAPS/Sources/Modules/OverrideConfig/View/EditOverrideForm.swift

@@ -27,6 +27,10 @@ struct EditOverrideForm: View {
     @State private var isEditing = false
     @State private var target_override = false
     @State private var showAlert = false
+    @State private var displayPickerStart: Bool = false
+    @State private var displayPickerEnd: Bool = false
+    @State private var displayPickerSmbMinutes: Bool = false
+    @State private var displayPickerUamMinutes: Bool = false
 
     init(overrideToEdit: OverrideStored, state: OverrideConfig.StateModel) {
         override = overrideToEdit
@@ -223,37 +227,89 @@ struct EditOverrideForm: View {
                 }
 
                 if smbIsScheduledOff {
-                    HStack {
-                        Text("First Hour SMBs Are Disabled (24 hours)")
-                        TextFieldWithToolBar(
-                            text: Binding(
-                                get: { start ?? 0 },
+                    // First Hour SMBs Are Disabled
+                    VStack {
+                        HStack {
+                            Text("First Hour SMBs Are Disabled")
+                            Spacer()
+
+                            // Display current selection based on format
+                            Text(
+                                is24HourFormat() ? format24Hour(Int(truncating: start! as NSNumber)) + ":00" :
+                                    convertTo12HourFormat(Int(truncating: start! as NSNumber))
+                            )
+                            .foregroundColor(!displayPickerStart ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerStart.toggle() // Toggle the picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerStart {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: start! as NSNumber) },
                                 set: {
-                                    start = $0
+                                    start = Decimal($0)
                                     hasChanges = true
                                 }
-                            ),
-                            placeholder: "0",
-                            numberFormatter: formatter
-                        )
-                        Text("hour").foregroundColor(.secondary)
+                            ), label: Text("")) {
+                                if is24HourFormat() {
+                                    ForEach(0 ..< 24, id: \.self) { hour in
+                                        Text(format24Hour(hour) + ":00").tag(hour)
+                                    }
+                                } else {
+                                    ForEach(0 ..< 24, id: \.self) { hour in
+                                        Text(convertTo12HourFormat(hour)).tag(hour)
+                                    }
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
 
-                    HStack {
-                        Text("First Hour SMBs Are Resumed (24 hours)")
-                        TextFieldWithToolBar(
-                            text: Binding(
-                                get: { end ?? 0 },
+                    // First Hour SMBs Are Resumed
+                    VStack {
+                        HStack {
+                            Text("First Hour SMBs Are Resumed")
+                            Spacer()
+
+                            // Display current selection based on format
+                            Text(
+                                is24HourFormat() ? format24Hour(Int(truncating: end! as NSNumber)) + ":00" :
+                                    convertTo12HourFormat(Int(truncating: end! as NSNumber))
+                            )
+                            .foregroundColor(!displayPickerEnd ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerEnd.toggle() // Toggle the picker visibility
+                        }
+
+                        // Show picker if toggled
+                        if displayPickerEnd {
+                            Picker(selection: Binding(
+                                get: { Int(truncating: end! as NSNumber) },
                                 set: {
-                                    end = $0
+                                    end = Decimal($0)
                                     hasChanges = true
                                 }
-                            ),
-                            placeholder: "0",
-                            numberFormatter: formatter
-                        )
-                        Text("hour").foregroundColor(.secondary)
+                            ), label: Text("")) {
+                                if is24HourFormat() {
+                                    ForEach(0 ..< 24, id: \.self) { hour in
+                                        Text(format24Hour(hour) + ":00").tag(hour)
+                                    }
+                                } else {
+                                    ForEach(0 ..< 24, id: \.self) { hour in
+                                        Text(convertTo12HourFormat(hour)).tag(hour)
+                                    }
+                                }
+                            }
+                            .pickerStyle(WheelPickerStyle()) // Use wheel style
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
                 }
 
                 Toggle(isOn: $isfAndCr) {
@@ -271,37 +327,71 @@ struct EditOverrideForm: View {
                 }
 
                 if !smbIsOff {
-                    HStack {
-                        Text("SMB Minutes")
-                        TextFieldWithToolBar(
-                            text: Binding(
-                                get: { smbMinutes ?? state.defaultSmbMinutes },
-                                set: {
-                                    smbMinutes = $0
-                                    hasChanges = true
+                    // SMB Minutes Picker
+                    VStack {
+                        HStack {
+                            Text("Max SMB Minutes")
+                            Spacer()
+                            Text("\(smbMinutes?.formatted(.number) ?? "\(state.defaultSmbMinutes)") min")
+                                .foregroundColor(!displayPickerSmbMinutes ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerSmbMinutes.toggle()
+                        }
+
+                        if displayPickerSmbMinutes {
+                            Picker(
+                                selection: Binding(
+                                    get: { smbMinutes ?? state.defaultSmbMinutes },
+                                    set: {
+                                        smbMinutes = $0
+                                        hasChanges = true
+                                    }
+                                ),
+                                label: Text("")
+                            ) {
+                                ForEach(Array(stride(from: 0, through: 180, by: 5)), id: \.self) { minute in
+                                    Text("\(minute) min").tag(Decimal(minute))
                                 }
-                            ),
-                            placeholder: "0",
-                            numberFormatter: formatter
-                        )
-                        Text("minutes").foregroundColor(.secondary)
+                            }
+                            .pickerStyle(WheelPickerStyle())
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
 
-                    HStack {
-                        Text("UAM SMB Minutes")
-                        TextFieldWithToolBar(
-                            text: Binding(
-                                get: { uamMinutes ?? state.defaultUamMinutes },
-                                set: {
-                                    uamMinutes = $0
-                                    hasChanges = true
+                    // UAM SMB Minutes Picker
+                    VStack {
+                        HStack {
+                            Text("Max UAM SMB Minutes")
+                            Spacer()
+                            Text("\(uamMinutes?.formatted(.number) ?? "\(state.defaultUamMinutes)") min")
+                                .foregroundColor(!displayPickerUamMinutes ? .primary : .accentColor)
+                        }
+                        .onTapGesture {
+                            displayPickerUamMinutes.toggle()
+                        }
+
+                        if displayPickerUamMinutes {
+                            Picker(
+                                selection: Binding(
+                                    get: { uamMinutes ?? state.defaultUamMinutes },
+                                    set: {
+                                        uamMinutes = $0
+                                        hasChanges = true
+                                    }
+                                ),
+                                label: Text("")
+                            ) {
+                                ForEach(Array(stride(from: 0, through: 180, by: 5)), id: \.self) { minute in
+                                    Text("\(minute) min").tag(Decimal(minute))
                                 }
-                            ),
-                            placeholder: "0",
-                            numberFormatter: formatter
-                        )
-                        Text("minutes").foregroundColor(.secondary)
+                            }
+                            .pickerStyle(WheelPickerStyle())
+                            .frame(maxWidth: .infinity)
+                        }
                     }
+                    .padding(.top)
                 }
             }
         }.listRowBackground(Color.chart)

+ 2 - 1
FreeAPS/Sources/Modules/OverrideConfig/View/OverrideRootView.swift

@@ -464,7 +464,8 @@ extension OverrideConfig {
             let perpetual = preset.indefinite
             let durationString = perpetual ? "∞" : "\(formatter.string(from: duration as NSNumber)!) min"
             let scheduledSMBstring = preset.smbIsScheduledOff && preset.start != preset.end
-                ? " \(preset.start?.stringValue ?? "")-\(preset.end?.stringValue ?? "")" : ""
+                ? " \(formatTimeRange(start: preset.start?.stringValue, end: preset.end?.stringValue))"
+                : ""
             let smbString = (preset.smbIsOff || preset.smbIsScheduledOff) ? "SMBs Off\(scheduledSMBstring)" : ""
             let targetString = target != 0 ? "\(target.description) \(state.units.rawValue)" : ""
             let maxMinutesSMB = (preset.smbMinutes as Decimal?) != nil ? (preset.smbMinutes ?? 0) as Decimal : 0