import ActivityKit import Combine import SwiftUI import Swinject extension GlucoseNotificationSettings { struct RootView: BaseView { let resolver: Resolver @StateObject var state = StateModel() @State private var shouldDisplayHint: Bool = false @State var hintDetent = PresentationDetent.large @State var selectedVerboseHint: AnyView? @State var hintLabel: String? @State private var decimalPlaceholder: Decimal = 0.0 @State private var booleanPlaceholder: Bool = false @State private var displayPickerLowGlucose: Bool = false @State private var displayPickerHighGlucose: Bool = false 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 } private var carbsFormatter: NumberFormatter { let formatter = NumberFormatter() formatter.numberStyle = .decimal formatter.maximumFractionDigits = 0 return formatter } @Environment(\.colorScheme) var colorScheme @Environment(AppState.self) var appState var body: some View { List { SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.notificationsPump, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Always Notify Pump" } ), units: state.units, type: .boolean, label: "Always Notify Pump", miniHint: "Always Notify Pump Warnings.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: ON").bold() Text( "With iOS Trio Notifications enabled, you can let Trio display most Pump Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue. Set iOS Notifications Banner Style to Persistent to display banners in the app until dismissed." ) Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.") Text("An example of a Pump Warning is 'Pod Expiration Reminder'") }, headerText: "Trio Information Notifications" ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.notificationsCgm, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Always Notify CGM" } ), units: state.units, type: .boolean, label: "Always Notify CGM", miniHint: "Always Notify CGM Warnings.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: ON").bold() Text( "With iOS Trio Notifications enabled, you can let Trio display most CGM Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue. Set iOS Notifications Banner Style to Persistent to display banners in the app until dismissed." ) Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.") Text("An example of a CGM Warning is 'Unable to open the app'") } ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.notificationsCarb, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Always Notify Carb" } ), units: state.units, type: .boolean, label: "Always Notify Carb", miniHint: "Always Notify Carb Warnings.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: ON").bold() Text( "With iOS Trio Notifications enabled, you can let Trio display most Carb Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue. Set iOS Notifications Banner Style to Persistent to display banners in the app until dismissed." ) Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.") Text("An example of a Carb Warning is 'Carbs required: 30 g'") } ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.notificationsAlgorithm, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Always Notify Algorithm" } ), units: state.units, type: .boolean, label: "Always Notify Algorithm", miniHint: "Always Notify Algorithm Warnings.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: ON").bold() Text( "With iOS Trio Notifications enabled, you can let Trio display most Algorithm Notifications in iOS Notification Center as a Banner, List and on the Lock Screen. It allows you to refer to Trio Information at a glance and troubleshoot any informational issue. Set iOS Notifications Banner Style to Persistent to display banners in the app until dismissed." ) Text("If iOS Trio Notifications is disabled, Trio will display these messages in-app as a banner only.") Text( "An example of an Algorithm Warning is 'Error: Invalid glucose: Not enough glucose data'" ) } ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.glucoseBadge, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Show Glucose App Badge" } ), units: state.units, type: .boolean, label: "Show Glucose App Badge", miniHint: "Show your current glucose on Trio app icon.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: OFF").bold() Text("This will add your current glucose on the top right of your Trio icon as a red notification badge.") }, headerText: "Various Glucose Notifications" ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.glucoseNotificationsAlways, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Always Notify Glucose" } ), units: state.units, type: .boolean, label: "Always Notify Glucose", miniHint: "Trigger a notification every time your glucose is updated.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: OFF").bold() Text("A notification will be triggered every time your glucose is updated in Trio.") } ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.useAlarmSound, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Play Alarm Sound" } ), units: state.units, type: .boolean, label: "Play Alarm Sound", miniHint: "Alarm with every Trio notification.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: OFF").bold() Text("This will cause a sound to be triggered by every Trio notification.") } ) SettingInputSection( decimalValue: $decimalPlaceholder, booleanValue: $state.addSourceInfoToGlucoseNotifications, shouldDisplayHint: $shouldDisplayHint, selectedVerboseHint: Binding( get: { selectedVerboseHint }, set: { selectedVerboseHint = $0.map { AnyView($0) } hintLabel = "Add Glucose Source to Alarm" } ), units: state.units, type: .boolean, label: "Add Glucose Source to Alarm", miniHint: "Source of the glucose reading will be added to the notification.", verboseHint: VStack(alignment: .leading, spacing: 10) { Text("Default: OFF").bold() Text("The source of the glucose reading will be added to the notification.") } ) self.lowAndHighGlucoseAlertSection } .listSectionSpacing(sectionSpacing) .sheet(isPresented: $shouldDisplayHint) { SettingInputHintView( hintDetent: $hintDetent, shouldDisplayHint: $shouldDisplayHint, hintLabel: hintLabel ?? "", hintText: selectedVerboseHint ?? AnyView(EmptyView()), sheetTitle: "Help" ) } .scrollContentBackground(.hidden).background(appState.trioBackgroundColor(for: colorScheme)) .onAppear(perform: configureView) .navigationBarTitle("Trio Notifications") .navigationBarTitleDisplayMode(.automatic) } var lowAndHighGlucoseAlertSection: some View { Section { VStack { VStack { HStack { Text("Low Glucose Alarm Limit") Spacer() Group { Text( state.units == .mgdL ? state.lowGlucose.description : state.lowGlucose.formattedAsMmolL ) .foregroundColor(!displayPickerLowGlucose ? .primary : .accentColor) Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary) } } .onTapGesture { displayPickerLowGlucose.toggle() } } .padding(.top) if displayPickerLowGlucose { let setting = PickerSettingsProvider.shared.settings.lowGlucose Picker(selection: $state.lowGlucose, label: Text("")) { ForEach( PickerSettingsProvider.shared.generatePickerValues(from: setting, units: state.units), id: \.self ) { value in let displayValue = state.units == .mgdL ? value.description : value.formattedAsMmolL Text(displayValue).tag(value) } } .pickerStyle(WheelPickerStyle()) .frame(maxWidth: .infinity) } VStack { HStack { Text("High Glucose Alarm Limit") Spacer() Group { Text( state.units == .mgdL ? state.highGlucose.description : state.highGlucose.formattedAsMmolL ) .foregroundColor(!displayPickerHighGlucose ? .primary : .accentColor) Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary) } } .onTapGesture { displayPickerHighGlucose.toggle() } } .padding(.top) if displayPickerHighGlucose { let setting = PickerSettingsProvider.shared.settings.highGlucose Picker(selection: $state.highGlucose, label: Text("")) { ForEach( PickerSettingsProvider.shared.generatePickerValues(from: setting, units: state.units), id: \.self ) { value in let displayValue = state.units == .mgdL ? value.description : value.formattedAsMmolL Text(displayValue).tag(value) } } .pickerStyle(WheelPickerStyle()) .frame(maxWidth: .infinity) } HStack(alignment: .center) { Text( "Sets the lower and upper limit for glucose alarms." ) .lineLimit(nil) .font(.footnote) .foregroundColor(.secondary) Spacer() Button( action: { hintLabel = "Low and High Glucose Alarm Limits" selectedVerboseHint = AnyView(VStack(alignment: .leading, spacing: 10) { Text("Low Default: 70 mg/dL").bold() Text("High Default: 180 mg/dL").bold() VStack(alignment: .leading, spacing: 10) { Text( "These two settings determine the range outside of which you will be notified via push notifications." ) Text( "If your CGM readings are below the Low value or above the High value, you will receive a glucose alarm." ) } }) shouldDisplayHint.toggle() }, label: { HStack { Image(systemName: "questionmark.circle") } } ).buttonStyle(BorderlessButtonStyle()) }.padding(.top) }.padding(.bottom) }.listRowBackground(Color.chart) } } }