ContactTrickRootView.swift 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. import Contacts
  2. import ContactsUI
  3. import SwiftUI
  4. import Swinject
  5. extension ContactTrick {
  6. struct RootView: BaseView {
  7. let resolver: Resolver
  8. @State var state = StateModel()
  9. @State private var isAddSheetPresented = false
  10. var body: some View {
  11. NavigationView {
  12. List {
  13. ForEach(state.contactTrickEntries, id: \.id) { entry in
  14. NavigationLink(destination: ContactTrickDetailView(entry: entry, state: state)) {
  15. Text("\(entry.name)")
  16. }
  17. }
  18. .onDelete(perform: onDelete)
  19. }
  20. .navigationTitle("Contact Tricks")
  21. .onAppear(perform: configureView)
  22. .navigationBarItems(
  23. trailing: Button(action: {
  24. isAddSheetPresented.toggle()
  25. }) {
  26. Image(systemName: "plus")
  27. }
  28. )
  29. .sheet(isPresented: $isAddSheetPresented) {
  30. AddContactTrickSheet(state: state)
  31. }
  32. }
  33. }
  34. private func onDelete(offsets: IndexSet) {
  35. Task {
  36. for offset in offsets {
  37. let entry = state.contactTrickEntries[offset]
  38. await state.deleteContact(entry: entry)
  39. }
  40. }
  41. }
  42. }
  43. }
  44. struct AddContactTrickSheet: View {
  45. @Environment(\.dismiss) var dismiss
  46. var state: ContactTrick.StateModel
  47. @State private var name: String = ""
  48. @State private var isDarkMode: Bool = false
  49. @State private var ringWidth: ContactTrickEntry.RingWidth = .regular
  50. @State private var ringGap: ContactTrickEntry.RingGap = .small
  51. @State private var layout: ContactTrickLayout = .single
  52. @State private var primary: ContactTrickValue = .glucose
  53. @State private var top: ContactTrickValue = .none
  54. @State private var bottom: ContactTrickValue = .none
  55. var body: some View {
  56. NavigationView {
  57. Form {
  58. TextField("Name", text: $name)
  59. Section(header: Text("Layout")) {
  60. Toggle("Dark Mode", isOn: $isDarkMode)
  61. Picker("Layout", selection: $layout) {
  62. ForEach(ContactTrickLayout.allCases, id: \.id) { layout in
  63. Text(layout.displayName).tag(layout)
  64. }
  65. }
  66. .pickerStyle(SegmentedPickerStyle())
  67. }
  68. Section(header: Text("Primary Value")) {
  69. Picker("Primary", selection: $primary) {
  70. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  71. Text(value.displayName).tag(value)
  72. }
  73. }
  74. }
  75. Section(header: Text("Additional Values")) {
  76. Picker("Top Value", selection: $top) {
  77. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  78. Text(value.displayName).tag(value)
  79. }
  80. }
  81. Picker("Bottom Value", selection: $bottom) {
  82. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  83. Text(value.displayName).tag(value)
  84. }
  85. }
  86. }
  87. Section(header: Text("Ring Settings")) {
  88. Picker("Ring Width", selection: $ringWidth) {
  89. ForEach(ContactTrickEntry.RingWidth.allCases, id: \.self) { width in
  90. Text(width.displayName).tag(width)
  91. }
  92. }
  93. Picker("Ring Gap", selection: $ringGap) {
  94. ForEach(ContactTrickEntry.RingGap.allCases, id: \.self) { gap in
  95. Text(gap.displayName).tag(gap)
  96. }
  97. }
  98. }
  99. }
  100. .navigationBarTitle("Add Contact Trick", displayMode: .inline)
  101. .navigationBarItems(
  102. leading: Button("Cancel") {
  103. dismiss()
  104. },
  105. trailing: Button("Save") {
  106. saveNewEntry()
  107. }
  108. )
  109. }
  110. }
  111. private func saveNewEntry() {
  112. let newEntry = ContactTrickEntry(
  113. id: UUID(),
  114. name: name,
  115. layout: layout,
  116. ring: .none,
  117. primary: primary,
  118. top: top,
  119. bottom: bottom,
  120. contactId: nil, // Wird später durch die API gesetzt
  121. darkMode: isDarkMode,
  122. ringWidth: ringWidth,
  123. ringGap: ringGap,
  124. fontSize: .regular,
  125. secondaryFontSize: .small,
  126. fontWeight: .medium,
  127. fontWidth: .standard
  128. )
  129. Task {
  130. await state.createAndSaveContactTrick(entry: newEntry, name: name)
  131. dismiss()
  132. }
  133. }
  134. }
  135. struct ContactTrickDetailView: View {
  136. @Environment(\.dismiss) var dismiss
  137. @ObservedObject var state: ContactTrick.StateModel
  138. @State private var contactTrickEntry: ContactTrickEntry
  139. init(entry: ContactTrickEntry, state: ContactTrick.StateModel) {
  140. self.state = state
  141. _contactTrickEntry = State(initialValue: entry)
  142. }
  143. var body: some View {
  144. Form {
  145. TextField("Name", text: $contactTrickEntry.name)
  146. Section(header: Text("Layout")) {
  147. Toggle("Dark Mode", isOn: $contactTrickEntry.darkMode)
  148. Picker("Layout", selection: $contactTrickEntry.layout) {
  149. ForEach(ContactTrickLayout.allCases, id: \.id) { layout in
  150. Text(layout.displayName).tag(layout)
  151. }
  152. }
  153. .pickerStyle(SegmentedPickerStyle())
  154. }
  155. Section(header: Text("Primary Value")) {
  156. Picker("Primary", selection: $contactTrickEntry.primary) {
  157. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  158. Text(value.displayName).tag(value)
  159. }
  160. }
  161. }
  162. Section(header: Text("Additional Values")) {
  163. Picker("Top Value", selection: $contactTrickEntry.top) {
  164. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  165. Text(value.displayName).tag(value)
  166. }
  167. }
  168. Picker("Bottom Value", selection: $contactTrickEntry.bottom) {
  169. ForEach(ContactTrickValue.allCases, id: \.id) { value in
  170. Text(value.displayName).tag(value)
  171. }
  172. }
  173. }
  174. Section(header: Text("Ring Settings")) {
  175. Picker("Ring Width", selection: $contactTrickEntry.ringWidth) {
  176. ForEach(ContactTrickEntry.RingWidth.allCases, id: \.self) { width in
  177. Text(width.displayName)
  178. .tag(width)
  179. }
  180. }
  181. Picker("Ring Gap", selection: $contactTrickEntry.ringGap) {
  182. ForEach(ContactTrickEntry.RingGap.allCases, id: \.self) { gap in
  183. Text(gap.displayName)
  184. .tag(gap)
  185. }
  186. }
  187. }
  188. }
  189. .navigationBarTitle("Edit Contact Trick", displayMode: .inline)
  190. .navigationBarItems(
  191. trailing: Button("Save") {
  192. saveChanges()
  193. }
  194. )
  195. }
  196. private func saveChanges() {
  197. Task {
  198. await state.updateContact(entry: contactTrickEntry, newName: contactTrickEntry.name)
  199. dismiss()
  200. }
  201. }
  202. }