| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342 |
- import Foundation
- import SwiftUI
- struct EditProfileForm: View {
- // @Injected() var settingsManager: SettingsManager!
- @ObservedObject var profile: OverrideStored
- @Environment(\.presentationMode) var presentationMode
- @Environment(\.colorScheme) var colorScheme
- @StateObject var state: OverrideProfilesConfig.StateModel
- @State private var name: String
- @State private var percentage: Double
- @State private var indefinite: Bool
- @State private var duration: Decimal
- @State private var target: Decimal?
- @State private var advancedSettings: Bool
- @State private var smbIsOff: Bool
- @State private var smbIsAlwaysOff: Bool
- @State private var start: Decimal?
- @State private var end: Decimal?
- @State private var isfAndCr: Bool
- @State private var isf: Bool
- @State private var cr: Bool
- @State private var smbMinutes: Decimal?
- @State private var uamMinutes: Decimal?
- @State private var hasChanges = false
- @State private var isEditing = false
- @State private var target_override = false
- init(profile: OverrideStored, state: OverrideProfilesConfig.StateModel) {
- self.profile = profile
- _state = StateObject(wrappedValue: state)
- _name = State(initialValue: profile.name ?? "")
- _percentage = State(initialValue: profile.percentage)
- _indefinite = State(initialValue: profile.indefinite)
- _duration = State(initialValue: profile.duration?.decimalValue ?? 0)
- _target = State(initialValue: profile.target?.decimalValue)
- _target_override = State(initialValue: profile.target?.decimalValue != 0)
- _advancedSettings = State(initialValue: profile.advancedSettings)
- _smbIsOff = State(initialValue: profile.smbIsOff)
- _smbIsAlwaysOff = State(initialValue: profile.smbIsAlwaysOff)
- _start = State(initialValue: profile.start?.decimalValue)
- _end = State(initialValue: profile.end?.decimalValue)
- _isfAndCr = State(initialValue: profile.isfAndCr)
- _isf = State(initialValue: profile.isf)
- _cr = State(initialValue: profile.cr)
- _smbMinutes = State(initialValue: profile.smbMinutes?.decimalValue)
- _uamMinutes = State(initialValue: profile.uamMinutes?.decimalValue)
- }
- 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
- )
- }
- private var formatter: NumberFormatter {
- let formatter = NumberFormatter()
- formatter.numberStyle = .decimal
- formatter.maximumFractionDigits = 0
- return formatter
- }
- private var glucoseFormatter: NumberFormatter {
- let formatter = NumberFormatter()
- formatter.numberStyle = .decimal
- formatter.maximumFractionDigits = 0
- if state.units == .mmolL {
- formatter.maximumFractionDigits = 1
- }
- formatter.roundingMode = .halfUp
- return formatter
- }
- var body: some View {
- NavigationView {
- Form {
- editProfile()
- saveButton
- }.scrollContentBackground(.hidden).background(color)
- .navigationTitle("Edit Profile")
- .navigationBarTitleDisplayMode(.inline)
- .navigationBarItems(leading: Button("Close") {
- presentationMode.wrappedValue.dismiss()
- })
- .onDisappear {
- if !hasChanges {
- // Reset UI changes
- resetValues()
- }
- }
- }
- }
- @ViewBuilder private func editProfile() -> some View {
- if profile.name != nil {
- Section {
- VStack {
- TextField("Name", text: $name)
- .onChange(of: name) { _ in hasChanges = true }
- }
- } header: {
- Text("Name")
- }.listRowBackground(Color.chart)
- }
- Section {
- VStack {
- Spacer()
- Text("\(percentage.formatted(.number)) %")
- .foregroundColor(
- state
- .percentageProfiles >= 130 ? .red :
- (isEditing ? .orange : Color.tabBar)
- )
- .font(.largeTitle)
- Slider(
- value: $percentage,
- in: 10 ... 200,
- step: 1
- ).onChange(of: percentage) { _ in hasChanges = true }
- Spacer()
- Toggle(isOn: $indefinite) {
- Text("Enable indefinitely")
- }.onChange(of: indefinite) { _ in hasChanges = true }
- }
- if !indefinite {
- HStack {
- Text("Duration")
- TextFieldWithToolBar(
- text: Binding(
- get: { duration },
- set: {
- duration = $0
- hasChanges = true
- }
- ),
- placeholder: "0",
- numberFormatter: formatter
- )
- Text("minutes").foregroundColor(.secondary)
- }
- }
- HStack {
- Toggle(isOn: $target_override) {
- Text("Override Profile Target")
- }.onChange(of: target_override) { _ in
- hasChanges = true
- }
- }
- if target_override {
- HStack {
- Text("Target Glucose")
- TextFieldWithToolBar(text: Binding(
- get: { target ?? 0 },
- set: {
- target = $0
- hasChanges = true
- }
- ), placeholder: "0", numberFormatter: glucoseFormatter)
- Text(state.units.rawValue).foregroundColor(.secondary)
- }
- }
- Toggle(isOn: $advancedSettings) {
- Text("More options")
- }.onChange(of: advancedSettings) { _ in hasChanges = true }
- if advancedSettings {
- Toggle(isOn: $smbIsOff) {
- Text("Disable SMBs")
- }.onChange(of: smbIsOff) { _ in hasChanges = true }
- Toggle(isOn: $smbIsAlwaysOff) {
- Text("Schedule when SMBs are Off")
- }.onChange(of: smbIsAlwaysOff) { _ in hasChanges = true }
- if smbIsAlwaysOff {
- HStack {
- Text("First Hour SMBs are Off (24 hours)")
- TextFieldWithToolBar(
- text: Binding(
- get: { start ?? 0 },
- set: {
- start = $0
- hasChanges = true
- }
- ),
- placeholder: "0",
- numberFormatter: formatter
- )
- Text("hour").foregroundColor(.secondary)
- }
- HStack {
- Text("Last Hour SMBs are Off (24 hours)")
- TextFieldWithToolBar(
- text: Binding(
- get: { end ?? 23 },
- set: {
- end = $0
- hasChanges = true
- }
- ),
- placeholder: "0",
- numberFormatter: formatter
- )
- Text("hour").foregroundColor(.secondary)
- }
- }
- Toggle(isOn: $isfAndCr) {
- Text("Change ISF and CR")
- }.onChange(of: isfAndCr) { _ in hasChanges = true }
- if !isfAndCr {
- Toggle(isOn: $isf) {
- Text("Change ISF")
- }.onChange(of: isf) { _ in hasChanges = true }
- Toggle(isOn: $cr) {
- Text("Change CR")
- }.onChange(of: cr) { _ in hasChanges = true }
- }
- HStack {
- Text("SMB Minutes")
- TextFieldWithToolBar(
- text: Binding(
- get: { smbMinutes ?? state.defaultSmbMinutes },
- set: {
- smbMinutes = $0
- hasChanges = true
- }
- ),
- placeholder: "0",
- numberFormatter: formatter
- )
- Text("minutes").foregroundColor(.secondary)
- }
- HStack {
- Text("UAM SMB Minutes")
- TextFieldWithToolBar(
- text: Binding(
- get: { uamMinutes ?? state.defaultUamMinutes },
- set: {
- uamMinutes = $0
- hasChanges = true
- }
- ),
- placeholder: "0",
- numberFormatter: formatter
- )
- Text("minutes").foregroundColor(.secondary)
- }
- }
- }.listRowBackground(Color.chart)
- }
- private var saveButton: some View {
- HStack {
- Spacer()
- Button(action: {
- saveChanges()
- do {
- try profile.managedObjectContext?.save()
- hasChanges = false
- presentationMode.wrappedValue.dismiss()
- } catch {
- debugPrint("\(DebuggingIdentifiers.failed) \(#file) \(#function) Failed to edit Profile")
- }
- }, label: {
- Text("Save")
- })
- .disabled(!hasChanges)
- .frame(maxWidth: .infinity, alignment: .center)
- .tint(.white)
- Spacer()
- }.listRowBackground(hasChanges ? Color(.systemBlue) : Color(.systemGray4))
- }
- private func saveChanges() {
- if !profile.isPreset, hasChanges, name == (profile.name ?? "") {
- profile.name = "Custom Override"
- } else {
- profile.name = name
- }
- profile.percentage = percentage
- profile.indefinite = indefinite
- profile.duration = NSDecimalNumber(decimal: duration)
- if target_override {
- profile.target = target.map { NSDecimalNumber(decimal: $0) }
- } else {
- profile.target = 0
- }
- profile.advancedSettings = advancedSettings
- profile.smbIsOff = smbIsOff
- profile.smbIsAlwaysOff = smbIsAlwaysOff
- profile.start = start.map { NSDecimalNumber(decimal: $0) }
- profile.end = end.map { NSDecimalNumber(decimal: $0) }
- profile.isfAndCr = isfAndCr
- profile.isf = isf
- profile.cr = cr
- profile.smbMinutes = smbMinutes.map { NSDecimalNumber(decimal: $0) }
- profile.uamMinutes = uamMinutes.map { NSDecimalNumber(decimal: $0) }
- state.scheduleOverrideDisabling(for: profile)
- }
- private func resetValues() {
- name = profile.name ?? ""
- percentage = profile.percentage
- indefinite = profile.indefinite
- duration = profile.duration?.decimalValue ?? 0
- target = profile.target?.decimalValue
- advancedSettings = profile.advancedSettings
- smbIsOff = profile.smbIsOff
- smbIsAlwaysOff = profile.smbIsAlwaysOff
- start = profile.start?.decimalValue
- end = profile.end?.decimalValue
- isfAndCr = profile.isfAndCr
- isf = profile.isf
- cr = profile.cr
- smbMinutes = profile.smbMinutes?.decimalValue ?? state.defaultSmbMinutes
- uamMinutes = profile.uamMinutes?.decimalValue ?? state.defaultUamMinutes
- }
- }
|