WatchConfigGarminAppConfigView.swift 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. import SwiftUI
  2. struct WatchConfigGarminAppConfigView: View {
  3. @ObservedObject var state: WatchConfig.StateModel
  4. @State private var shouldDisplayHint1: Bool = false
  5. @State private var shouldDisplayHint2: Bool = false
  6. @State private var shouldDisplayHint3: Bool = false
  7. @State private var shouldDisplayHint4: Bool = false
  8. @State var hintDetent = PresentationDetent.large
  9. @Environment(\.colorScheme) var colorScheme
  10. @Environment(AppState.self) var appState
  11. var body: some View {
  12. Form {
  13. // MARK: - Watchface Selection Section
  14. Section(
  15. header: Text("Watchface Settings"),
  16. content: {
  17. VStack {
  18. Picker(
  19. selection: $state.garminSettings.watchface,
  20. label: Text("Watchface Selection").multilineTextAlignment(.leading)
  21. ) {
  22. ForEach(GarminWatchface.allCases) { selection in
  23. Text(selection.displayName).tag(selection)
  24. }
  25. }
  26. .padding(.top)
  27. .onChange(of: state.garminSettings.watchface) { _ in
  28. state.handleWatchfaceChange()
  29. }
  30. HStack(alignment: .center) {
  31. Text(
  32. "Choose which watchface to support."
  33. )
  34. .font(.footnote)
  35. .foregroundColor(.secondary)
  36. .lineLimit(nil)
  37. Spacer()
  38. Button(
  39. action: {
  40. shouldDisplayHint1.toggle()
  41. },
  42. label: {
  43. HStack {
  44. Image(systemName: "questionmark.circle")
  45. }
  46. }
  47. ).buttonStyle(BorderlessButtonStyle())
  48. }.padding(.top)
  49. Spacer()
  50. // Inverted binding: "Disable" toggle controls "isEnabled" boolean
  51. // When toggle is ON → data transmission is DISABLED (isEnabled = false)
  52. // When toggle is OFF → data transmission is ENABLED (isEnabled = true)
  53. Toggle("Disable Watchface Data", isOn: Binding(
  54. get: { !state.garminSettings.isWatchfaceDataEnabled },
  55. set: { state.garminSettings.isWatchfaceDataEnabled = !$0 }
  56. ))
  57. .disabled(state.isWatchfaceDataCooldownActive)
  58. // Display cooldown warning when toggle is locked
  59. if state.isWatchfaceDataCooldownActive {
  60. HStack {
  61. Text(
  62. "Please wait \(state.watchfaceSwitchCooldownSeconds) seconds!\n\n" +
  63. "After the lockout you can re-enable watchface data transmission, but you need to change to the new watchface on your Garmin watch before that - e.g. now!"
  64. )
  65. .font(.footnote)
  66. .foregroundColor(.orange)
  67. .multilineTextAlignment(.leading)
  68. .lineLimit(nil)
  69. Spacer()
  70. }
  71. }
  72. HStack(alignment: .center) {
  73. Text(
  74. "Choose if you only want to use a datafield and no supported watchface!"
  75. )
  76. .font(.footnote)
  77. .foregroundColor(.secondary)
  78. .lineLimit(nil)
  79. Spacer()
  80. Button(
  81. action: {
  82. shouldDisplayHint2.toggle()
  83. },
  84. label: {
  85. HStack {
  86. Image(systemName: "questionmark.circle")
  87. }
  88. }
  89. ).buttonStyle(BorderlessButtonStyle())
  90. }.padding(.top)
  91. }.padding(.vertical)
  92. }
  93. ).listRowBackground(Color.chart)
  94. // MARK: - Datafield Selection Section
  95. Section(
  96. header: Text("Datafield Settings"),
  97. content: {
  98. VStack {
  99. Picker(
  100. selection: $state.garminSettings.datafield,
  101. label: Text("Datafield Selection").multilineTextAlignment(.leading)
  102. ) {
  103. ForEach(GarminDatafield.allCases) { selection in
  104. Text(selection.displayName).tag(selection)
  105. }
  106. }
  107. .padding(.top)
  108. HStack(alignment: .center) {
  109. Text(
  110. "Choose which datafield to support. Can be used independently of watchface selection."
  111. )
  112. .font(.footnote)
  113. .foregroundColor(.secondary)
  114. .lineLimit(nil)
  115. Spacer()
  116. Button(
  117. action: {
  118. shouldDisplayHint4.toggle()
  119. },
  120. label: {
  121. HStack {
  122. Image(systemName: "questionmark.circle")
  123. }
  124. }
  125. ).buttonStyle(BorderlessButtonStyle())
  126. }.padding(.top)
  127. }.padding(.vertical)
  128. }
  129. ).listRowBackground(Color.chart)
  130. // MARK: - Data Field Selection Section
  131. Section(
  132. header: Text("Watch App Display Settings"),
  133. content: {
  134. VStack {
  135. Picker(
  136. selection: $state.garminSettings.primaryAttributeChoice,
  137. label: Text("Data Choice 1").multilineTextAlignment(.leading)
  138. ) {
  139. ForEach(GarminPrimaryAttributeChoice.allCases) { selection in
  140. Text(selection.displayName).tag(selection)
  141. }
  142. }.padding(.top)
  143. Picker(
  144. selection: $state.garminSettings.secondaryAttributeChoice,
  145. label: Text("Data Choice 2").multilineTextAlignment(.leading)
  146. ) {
  147. ForEach(GarminSecondaryAttributeChoice.allCases) { selection in
  148. Text(selection.displayName).tag(selection)
  149. }
  150. }.padding(.top)
  151. HStack(alignment: .center) {
  152. Text(
  153. "Choose between displayed data types on Garmin device."
  154. )
  155. .font(.footnote)
  156. .foregroundColor(.secondary)
  157. .lineLimit(nil)
  158. Spacer()
  159. Button(
  160. action: {
  161. shouldDisplayHint3.toggle()
  162. },
  163. label: {
  164. HStack {
  165. Image(systemName: "questionmark.circle")
  166. }
  167. }
  168. ).buttonStyle(BorderlessButtonStyle())
  169. }.padding(.top)
  170. }.padding(.vertical)
  171. }
  172. ).listRowBackground(Color.chart)
  173. }
  174. .listSectionSpacing(sectionSpacing)
  175. .scrollContentBackground(.hidden)
  176. .background(appState.trioBackgroundColor(for: colorScheme))
  177. // MARK: - Help Sheets
  178. .sheet(isPresented: $shouldDisplayHint1) {
  179. SettingInputHintView(
  180. hintDetent: $hintDetent,
  181. shouldDisplayHint: $shouldDisplayHint1,
  182. hintLabel: "Choose Garmin Watchface",
  183. hintText: Text(
  184. "Choose which watchface on your Garmin device you wish to provide data for. You can independently select which datafield to use in the next section.\n\n" +
  185. "You must use this configuration setting here BEFORE you switch the watchface on your Garmin device to another watchface.\n\n" +
  186. "⚠️ Changing the watchface will automatically disable data transmission and lock that setting for 20 seconds to allow time for you to switch the watchface on your Garmin device."
  187. ),
  188. sheetTitle: String(localized: "Help", comment: "Help sheet title")
  189. )
  190. }
  191. .sheet(isPresented: $shouldDisplayHint4) {
  192. SettingInputHintView(
  193. hintDetent: $hintDetent,
  194. shouldDisplayHint: $shouldDisplayHint4,
  195. hintLabel: "Choose Garmin Datafield",
  196. hintText: Text(
  197. "Choose which datafield on your Garmin device you wish to provide data for. The datafield can be used independently from the watchface selection.\n\n" +
  198. "Select 'None' if you don't want to use a datafield, or want to preserve battery while not exercising."
  199. ),
  200. sheetTitle: String(localized: "Help", comment: "Help sheet title")
  201. )
  202. }
  203. .sheet(isPresented: $shouldDisplayHint2) {
  204. SettingInputHintView(
  205. hintDetent: $hintDetent,
  206. shouldDisplayHint: $shouldDisplayHint2,
  207. hintLabel: "Disable watchface data transmission",
  208. hintText: Text(
  209. "Important: If you want to use a different watchface on your Garmin device that has no data requirement from this app, disable data transmission to the Garmin watchface app! Otherwise you will not be able to get current data once you re-enable the supported watchface that shows Trio data and you will have to re-install it on your Garmin device.\n\n" +
  210. "Note: When switching between supported watchfaces, data transmission is automatically disabled for 20 seconds. You would manually need to re-enable it."
  211. ),
  212. sheetTitle: String(localized: "Help", comment: "Help sheet title")
  213. )
  214. }
  215. .sheet(isPresented: $shouldDisplayHint3) {
  216. SettingInputHintView(
  217. hintDetent: $hintDetent,
  218. shouldDisplayHint: $shouldDisplayHint3,
  219. hintLabel: "Choose data support",
  220. hintText: Text(
  221. "Choose which data types, along with BG and IOB etc., you want to show on your Garmin device. That data type will be shown both on watchface and datafield."
  222. ),
  223. sheetTitle: String(localized: "Help", comment: "Help sheet title")
  224. )
  225. }
  226. }
  227. }