AlarmListView.swift 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. //
  2. // AlarmListView.swift
  3. // LoopFollow
  4. //
  5. // Created by Jonas Björkert on 2025-04-21.
  6. // Copyright © 2025 Jon Fawcett. All rights reserved.
  7. //
  8. import SwiftUI
  9. /// Displays all configured alarms and allows adding a new one by selecting its type.
  10. struct AlarmListView: View {
  11. @ObservedObject private var store = Storage.shared.alarms
  12. @Environment(\.presentationMode) var presentationMode
  13. @State private var showingTypePicker = false
  14. @State private var editingAlarmID: UUID?
  15. var body: some View {
  16. NavigationView {
  17. List {
  18. ForEach(store.value) { alarm in
  19. NavigationLink(alarm.name) {
  20. AlarmEditor(alarm: binding(for: alarm))
  21. }
  22. }
  23. .onDelete { idxs in
  24. store.value.remove(atOffsets: idxs)
  25. }
  26. }
  27. .navigationTitle("Alarms")
  28. .toolbar {
  29. ToolbarItem(placement: .navigationBarLeading) {
  30. Button {
  31. showingTypePicker = true
  32. } label: {
  33. Image(systemName: "plus")
  34. }
  35. }
  36. ToolbarItem(placement: .navigationBarTrailing) {
  37. Button("Done") {
  38. presentationMode.wrappedValue.dismiss()
  39. }
  40. }
  41. }
  42. // Step 1: pick a type for the new alarm
  43. .actionSheet(isPresented: $showingTypePicker) {
  44. ActionSheet(
  45. title: Text("Select Alarm Type"),
  46. buttons: AlarmType.allCases.map { type in
  47. .default(Text(type.rawValue)) {
  48. let newAlarm = Alarm(type: type)
  49. store.value.append(newAlarm)
  50. editingAlarmID = newAlarm.id
  51. }
  52. } + [.cancel()]
  53. )
  54. }
  55. // Step 2: when an ID is set, present the editor
  56. .sheet(item: $editingAlarmID) { id in
  57. if let idx = store.value.firstIndex(where: { $0.id == id }) {
  58. AlarmEditor(alarm: $store.value[idx])
  59. } else {
  60. Text("Alarm not found")
  61. .padding()
  62. }
  63. }
  64. }
  65. }
  66. /// Find and return a binding to the given alarm in the store
  67. private func binding(for alarm: Alarm) -> Binding<Alarm> {
  68. guard let idx = store.value.firstIndex(where: { $0.id == alarm.id }) else {
  69. fatalError("Alarm not found in store")
  70. }
  71. return $store.value[idx]
  72. }
  73. }