UserInterfaceSettingsRootView.swift 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. import SwiftUI
  2. import Swinject
  3. extension UserInterfaceSettings {
  4. struct RootView: BaseView {
  5. let resolver: Resolver
  6. @StateObject var state = StateModel()
  7. @State private var shouldDisplayHint: Bool = false
  8. @State var hintDetent = PresentationDetent.large
  9. @State var selectedVerboseHint: String?
  10. @State var hintLabel: String?
  11. @State private var decimalPlaceholder: Decimal = 0.0
  12. @State private var booleanPlaceholder: Bool = false
  13. @State private var displayPickerLowThreshold: Bool = false
  14. @State private var displayPickerHighThreshold: Bool = false
  15. @Environment(\.colorScheme) var colorScheme
  16. var color: LinearGradient {
  17. colorScheme == .dark ? LinearGradient(
  18. gradient: Gradient(colors: [
  19. Color.bgDarkBlue,
  20. Color.bgDarkerDarkBlue
  21. ]),
  22. startPoint: .top,
  23. endPoint: .bottom
  24. )
  25. :
  26. LinearGradient(
  27. gradient: Gradient(colors: [Color.gray.opacity(0.1)]),
  28. startPoint: .top,
  29. endPoint: .bottom
  30. )
  31. }
  32. private var glucoseFormatter: NumberFormatter {
  33. let formatter = NumberFormatter()
  34. formatter.numberStyle = .decimal
  35. formatter.maximumFractionDigits = 0
  36. if state.units == .mmolL {
  37. formatter.maximumFractionDigits = 1
  38. }
  39. formatter.roundingMode = .halfUp
  40. return formatter
  41. }
  42. private var carbsFormatter: NumberFormatter {
  43. let formatter = NumberFormatter()
  44. formatter.numberStyle = .decimal
  45. formatter.maximumFractionDigits = 0
  46. return formatter
  47. }
  48. var body: some View {
  49. Form {
  50. Section(
  51. header: Text("Home View Settings"),
  52. content: {
  53. VStack {
  54. Toggle("Show X-Axis Grid Lines", isOn: $state.xGridLines)
  55. Toggle("Show Y-Axis Grid Lines", isOn: $state.yGridLines)
  56. HStack(alignment: .top) {
  57. Text(
  58. "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  59. )
  60. .font(.footnote)
  61. .foregroundColor(.secondary)
  62. .lineLimit(nil)
  63. Spacer()
  64. Button(
  65. action: {
  66. hintLabel = "Show Main Chart X- and Y-Axis Grid Lines"
  67. selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  68. shouldDisplayHint.toggle()
  69. },
  70. label: {
  71. HStack {
  72. Image(systemName: "questionmark.circle")
  73. }
  74. }
  75. ).buttonStyle(BorderlessButtonStyle())
  76. }.padding(.top)
  77. }.padding(.bottom)
  78. }
  79. ).listRowBackground(Color.chart)
  80. SettingInputSection(
  81. decimalValue: $decimalPlaceholder,
  82. booleanValue: $state.rulerMarks,
  83. shouldDisplayHint: $shouldDisplayHint,
  84. selectedVerboseHint: Binding(
  85. get: { selectedVerboseHint },
  86. set: {
  87. selectedVerboseHint = $0
  88. hintLabel = "Show Low and High Thresholds"
  89. }
  90. ),
  91. type: .boolean,
  92. label: "Show Low and High Thresholds",
  93. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  94. verboseHint: "Display Low and High Thresholds… bla bla bla"
  95. )
  96. Section {
  97. VStack {
  98. VStack {
  99. HStack {
  100. Text("Low Threshold")
  101. Spacer()
  102. Group {
  103. Text(state.low.description)
  104. .foregroundColor(!displayPickerLowThreshold ? .primary : .accentColor)
  105. Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary)
  106. }
  107. }
  108. .onTapGesture {
  109. displayPickerLowThreshold.toggle()
  110. }
  111. }
  112. .padding(.top)
  113. if displayPickerLowThreshold {
  114. let setting = PickerSettingsProvider.shared.settings.low
  115. Picker(selection: $state.low, label: Text("")) {
  116. ForEach(
  117. PickerSettingsProvider.shared.generatePickerValues(from: setting),
  118. id: \.self
  119. ) { value in
  120. Text("\(value.description)").tag(value)
  121. }
  122. }
  123. .pickerStyle(WheelPickerStyle())
  124. .frame(maxWidth: .infinity)
  125. }
  126. VStack {
  127. HStack {
  128. Text("High Threshold")
  129. Spacer()
  130. Group {
  131. Text(state.high.description)
  132. .foregroundColor(!displayPickerHighThreshold ? .primary : .accentColor)
  133. Text(state.units == .mgdL ? " mg/dL" : " mmol/L").foregroundColor(.secondary)
  134. }
  135. }
  136. .onTapGesture {
  137. displayPickerHighThreshold.toggle()
  138. }
  139. }
  140. .padding(.top)
  141. if displayPickerHighThreshold {
  142. let setting = PickerSettingsProvider.shared.settings.high
  143. Picker(selection: $state.high, label: Text("")) {
  144. ForEach(
  145. PickerSettingsProvider.shared.generatePickerValues(from: setting),
  146. id: \.self
  147. ) { value in
  148. Text("\(value.description)").tag(value)
  149. }
  150. }
  151. .pickerStyle(WheelPickerStyle())
  152. .frame(maxWidth: .infinity)
  153. }
  154. HStack(alignment: .top) {
  155. Text(
  156. "Sets thresholds for low and high glucose in home view main chart and statistics view."
  157. )
  158. .lineLimit(nil)
  159. .font(.footnote)
  160. .foregroundColor(.secondary)
  161. Spacer()
  162. Button(
  163. action: {
  164. hintLabel = "Low and High Thresholds"
  165. selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  166. shouldDisplayHint.toggle()
  167. },
  168. label: {
  169. HStack {
  170. Image(systemName: "questionmark.circle")
  171. }
  172. }
  173. ).buttonStyle(BorderlessButtonStyle())
  174. }.padding(.top)
  175. }.padding(.bottom)
  176. }.listRowBackground(Color.chart)
  177. SettingInputSection(
  178. decimalValue: $state.hours,
  179. booleanValue: $booleanPlaceholder,
  180. shouldDisplayHint: $shouldDisplayHint,
  181. selectedVerboseHint: Binding(
  182. get: { selectedVerboseHint },
  183. set: {
  184. selectedVerboseHint = $0
  185. hintLabel = "X-Axis Interval Step"
  186. }
  187. ),
  188. type: .decimal("hours"),
  189. label: "X-Axis Interval Step",
  190. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  191. verboseHint: "X-Axis Interval Step… bla bla bla"
  192. )
  193. Section {
  194. VStack {
  195. Picker(
  196. selection: $state.totalInsulinDisplayType,
  197. label: Text("Total Insulin Display Type")
  198. ) {
  199. ForEach(TotalInsulinDisplayType.allCases) { selection in
  200. Text(selection.displayName).tag(selection)
  201. }
  202. }.padding(.top)
  203. HStack(alignment: .top) {
  204. Text(
  205. "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  206. )
  207. .font(.footnote)
  208. .foregroundColor(.secondary)
  209. .lineLimit(nil)
  210. Spacer()
  211. Button(
  212. action: {
  213. hintLabel = "Total Insulin Display Type"
  214. selectedVerboseHint = "Lorem ipsum dolor sit amet, consetetur sadipscing elitr."
  215. shouldDisplayHint.toggle()
  216. },
  217. label: {
  218. HStack {
  219. Image(systemName: "questionmark.circle")
  220. }
  221. }
  222. ).buttonStyle(BorderlessButtonStyle())
  223. }.padding(.top)
  224. }.padding(.bottom)
  225. }.listRowBackground(Color.chart)
  226. // TODO: this needs to be a picker: mmol/L or %
  227. SettingInputSection(
  228. decimalValue: $decimalPlaceholder,
  229. booleanValue: $state.overrideHbA1cUnit,
  230. shouldDisplayHint: $shouldDisplayHint,
  231. selectedVerboseHint: Binding(
  232. get: { selectedVerboseHint },
  233. set: {
  234. selectedVerboseHint = $0
  235. hintLabel = "Override HbA1c Unit"
  236. }
  237. ),
  238. type: .boolean,
  239. label: "Override HbA1c Unit",
  240. miniHint: "Display HbA1c in mmol/L or %. Default is percent.",
  241. verboseHint: "Override HbA1c Unit… bla bla bla",
  242. headerText: "Trio Statistics"
  243. )
  244. // TODO: this needs to be a picker: choose bar chart or progress bar
  245. SettingInputSection(
  246. decimalValue: $decimalPlaceholder,
  247. booleanValue: $state.oneDimensionalGraph,
  248. shouldDisplayHint: $shouldDisplayHint,
  249. selectedVerboseHint: Binding(
  250. get: { selectedVerboseHint },
  251. set: {
  252. selectedVerboseHint = $0
  253. hintLabel = "Standing / Laying TIR Chart"
  254. }
  255. ),
  256. type: .boolean,
  257. label: "Standing / Laying TIR Chart",
  258. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  259. verboseHint: "Standing / Laying TIR Chart… bla bla bla"
  260. )
  261. SettingInputSection(
  262. decimalValue: $state.carbsRequiredThreshold,
  263. booleanValue: $state.showCarbsRequiredBadge,
  264. shouldDisplayHint: $shouldDisplayHint,
  265. selectedVerboseHint: Binding(
  266. get: { selectedVerboseHint },
  267. set: {
  268. selectedVerboseHint = $0
  269. hintLabel = "Show Carbs Required Badge"
  270. }
  271. ),
  272. type: .conditionalDecimal("carbsRequiredThreshold"),
  273. label: "Show Carbs Required Badge",
  274. conditionalLabel: "Carbs Required Threshold",
  275. miniHint: "Lorem ipsum dolor sit amet, consetetur sadipscing elitr.",
  276. verboseHint: "Show Carbs Required Badge… bla bla bla",
  277. headerText: "Carbs Required Badge"
  278. )
  279. }
  280. .sheet(isPresented: $shouldDisplayHint) {
  281. SettingInputHintView(
  282. hintDetent: $hintDetent,
  283. shouldDisplayHint: $shouldDisplayHint,
  284. hintLabel: hintLabel ?? "",
  285. hintText: selectedVerboseHint ?? "",
  286. sheetTitle: "Help"
  287. )
  288. }
  289. .scrollContentBackground(.hidden).background(color)
  290. .onAppear(perform: configureView)
  291. .navigationBarTitle("User Interface")
  292. .navigationBarTitleDisplayMode(.automatic)
  293. }
  294. }
  295. }