ContactImageDetailView.swift 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import SwiftUI
  2. struct ContactImageDetailView: View {
  3. @Environment(\.dismiss) var dismiss
  4. @Environment(\.colorScheme) var colorScheme
  5. @Environment(AppState.self) var appState
  6. @ObservedObject var state: ContactImage.StateModel
  7. @State private var contactImageEntry: ContactImageEntry
  8. @State private var initialContactImageEntry: ContactImageEntry
  9. init(entry: ContactImageEntry, state: ContactImage.StateModel) {
  10. self.state = state
  11. _contactImageEntry = State(initialValue: entry)
  12. _initialContactImageEntry = State(initialValue: entry)
  13. }
  14. var body: some View {
  15. VStack {
  16. HStack {
  17. // TODO: - make this beautiful @Dan
  18. Spacer()
  19. ZStack {
  20. Circle()
  21. .fill(.black)
  22. .foregroundColor(.white)
  23. .frame(width: 100, height: 100)
  24. Image(uiImage: ContactPicture.getImage(contact: contactImageEntry, state: state.state))
  25. .resizable()
  26. .frame(width: 100, height: 100)
  27. .clipShape(Circle())
  28. Circle()
  29. .stroke(lineWidth: 2)
  30. .foregroundColor(colorScheme == .dark ? .white : .black)
  31. .frame(width: 100, height: 100)
  32. }
  33. Spacer()
  34. }
  35. .padding(.top, 80)
  36. .padding(.bottom)
  37. Form {
  38. Section(header: Text("Style")) {
  39. Picker("Layout", selection: $contactImageEntry.layout) {
  40. ForEach(ContactImageLayout.allCases, id: \.id) { layout in
  41. Text(layout.displayName).tag(layout)
  42. }
  43. }.onChange(of: contactImageEntry.layout, { oldLayout, newLayout in
  44. if oldLayout != newLayout, newLayout == .split {
  45. contactImageEntry.top = .glucose
  46. } else {
  47. contactImageEntry.top = .none
  48. }
  49. })
  50. Toggle("High Contrast Mode", isOn: $contactImageEntry.hasHighContrast)
  51. }.listRowBackground(Color.chart)
  52. Section(header: Text("Display Values")) {
  53. Picker("Top Value", selection: $contactImageEntry.top) {
  54. ForEach(ContactImageValue.allCases, id: \.id) { value in
  55. Text(value.displayName).tag(value)
  56. }
  57. }
  58. if contactImageEntry.layout == .default {
  59. Picker("Primary", selection: $contactImageEntry.primary) {
  60. ForEach(ContactImageValue.allCases, id: \.id) { value in
  61. Text(value.displayName).tag(value)
  62. }
  63. }
  64. }
  65. Picker("Bottom Value", selection: $contactImageEntry.bottom) {
  66. ForEach(ContactImageValue.allCases, id: \.id) { value in
  67. Text(value.displayName).tag(value)
  68. }
  69. }
  70. }.listRowBackground(Color.chart)
  71. // Ring Settings Section
  72. Section(header: Text("Ring Settings")) {
  73. Picker("Ring Type", selection: $contactImageEntry.ring) {
  74. ForEach(ContactImageLargeRing.allCases, id: \.self) { ring in
  75. Text(ring.displayName).tag(ring)
  76. }
  77. }
  78. if contactImageEntry.ring != .none {
  79. Picker("Ring Width", selection: $contactImageEntry.ringWidth) {
  80. ForEach(ContactImageEntry.RingWidth.allCases, id: \.self) { width in
  81. Text(width.displayName).tag(width)
  82. }
  83. }
  84. Picker("Ring Gap", selection: $contactImageEntry.ringGap) {
  85. ForEach(ContactImageEntry.RingGap.allCases, id: \.self) { gap in
  86. Text(gap.displayName).tag(gap)
  87. }
  88. }
  89. }
  90. }.listRowBackground(Color.chart)
  91. // Font Settings Section
  92. Section(header: Text("Font Settings")) {
  93. fontSizePicker
  94. if contactImageEntry.layout == .split {
  95. secondaryFontSizePicker
  96. }
  97. fontWeightPicker
  98. fontWidthPicker
  99. }.listRowBackground(Color.chart)
  100. }
  101. }
  102. .navigationTitle("Edit Contact Items")
  103. .navigationBarTitleDisplayMode(.inline)
  104. .safeAreaInset(edge: .bottom, spacing: 0) { stickySaveButton }
  105. .listSectionSpacing(10)
  106. .padding(.top, 30)
  107. .ignoresSafeArea(edges: .top)
  108. .scrollContentBackground(.hidden)
  109. .background(appState.trioBackgroundColor(for: colorScheme))
  110. .toolbar {
  111. ToolbarItem(placement: .topBarTrailing) {
  112. Button(
  113. action: {
  114. state.isHelpSheetPresented.toggle()
  115. },
  116. label: {
  117. Image(systemName: "questionmark.circle")
  118. }
  119. )
  120. }
  121. }
  122. .sheet(isPresented: $state.isHelpSheetPresented) {
  123. ContactImageHelpView(state: state, helpSheetDetent: $state.helpSheetDetent)
  124. }
  125. }
  126. private func saveChanges() {
  127. Task {
  128. await state.updateContact(with: contactImageEntry)
  129. dismiss()
  130. }
  131. }
  132. var stickySaveButton: some View {
  133. var isUnchanged: Bool { initialContactImageEntry == contactImageEntry }
  134. return ZStack {
  135. Rectangle()
  136. .frame(width: UIScreen.main.bounds.width, height: 65)
  137. .foregroundStyle(colorScheme == .dark ? Color.bgDarkerDarkBlue : Color.white)
  138. .background(.thinMaterial)
  139. .opacity(0.8)
  140. .clipShape(Rectangle())
  141. Button(action: {
  142. saveChanges()
  143. }, label: {
  144. Text("Save").padding(10)
  145. })
  146. .frame(width: UIScreen.main.bounds.width * 0.9, alignment: .center)
  147. .background(isUnchanged ? Color(.systemGray4) : Color(.systemBlue))
  148. .disabled(isUnchanged)
  149. .tint(.white)
  150. .clipShape(RoundedRectangle(cornerRadius: 8))
  151. .padding(5)
  152. }
  153. }
  154. private var fontSizePicker: some View {
  155. Picker("Font Size", selection: $contactImageEntry.fontSize) {
  156. ForEach(ContactImageEntry.FontSize.allCases, id: \.self) { size in
  157. Text(size.displayName).tag(size)
  158. }
  159. }
  160. }
  161. private var secondaryFontSizePicker: some View {
  162. Picker("Secondary Font Size", selection: $contactImageEntry.secondaryFontSize) {
  163. ForEach(ContactImageEntry.FontSize.allCases, id: \.self) { size in
  164. Text(size.displayName).tag(size)
  165. }
  166. }
  167. }
  168. private var fontWeightPicker: some View {
  169. Picker("Font Weight", selection: $contactImageEntry.fontWeight) {
  170. ForEach(
  171. [Font.Weight.light, Font.Weight.regular, Font.Weight.medium, Font.Weight.bold, Font.Weight.black],
  172. id: \.self
  173. ) { weight in
  174. Text("\(weight.displayName)".capitalized).tag(weight)
  175. }
  176. }
  177. }
  178. private var fontWidthPicker: some View {
  179. Picker("Font Width", selection: $contactImageEntry.fontWidth) {
  180. ForEach(
  181. [Font.Width.standard, Font.Width.expanded],
  182. id: \.self
  183. ) { width in
  184. Text("\(width.displayName)".capitalized).tag(width)
  185. }
  186. }
  187. }
  188. }