AlarmListView.swift 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  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. // TODO: sort these in the alarm prio order, as they are evaluated
  19. ForEach(store.value) { alarm in
  20. NavigationLink(alarm.name) {
  21. AlarmEditor(alarm: binding(for: alarm))
  22. }
  23. }
  24. .onDelete { idxs in
  25. store.value.remove(atOffsets: idxs)
  26. }
  27. }
  28. .navigationTitle("Alarms")
  29. .toolbar {
  30. ToolbarItem(placement: .navigationBarTrailing) {
  31. Button {
  32. showingTypePicker = true
  33. } label: {
  34. Image(systemName: "plus")
  35. }
  36. }
  37. ToolbarItem(placement: .navigationBarLeading) {
  38. Button("Done") {
  39. presentationMode.wrappedValue.dismiss()
  40. }
  41. }
  42. }
  43. // Step 1: pick a type for the new alarm
  44. // TODO: Sort these in the type order
  45. .actionSheet(isPresented: $showingTypePicker) {
  46. ActionSheet(
  47. title: Text("Select Alarm Type"),
  48. buttons: AlarmType.allCases.map { type in
  49. .default(Text(type.rawValue)) {
  50. let newAlarm = Alarm(type: type)
  51. store.value.append(newAlarm)
  52. editingAlarmID = newAlarm.id
  53. }
  54. } + [.cancel()]
  55. )
  56. }
  57. // Step 2: when an ID is set, present the editor
  58. .sheet(item: $editingAlarmID) { id in
  59. if let idx = store.value.firstIndex(where: { $0.id == id }) {
  60. AlarmEditor(alarm: $store.value[idx])
  61. } else {
  62. Text("Alarm not found")
  63. .padding()
  64. }
  65. }
  66. }
  67. }
  68. /// Find and return a binding to the given alarm in the store
  69. private func binding(for alarm: Alarm) -> Binding<Alarm> {
  70. guard let idx = store.value.firstIndex(where: { $0.id == alarm.id }) else {
  71. fatalError("Alarm not found in store")
  72. }
  73. return $store.value[idx]
  74. }
  75. }