| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172 |
- //
- // AlarmListView.swift
- // LoopFollow
- //
- // Created by Jonas Björkert on 2025-04-21.
- // Copyright © 2025 Jon Fawcett. All rights reserved.
- //
- import SwiftUI
- struct AddAlarmSheet: View {
- let onSelect: (AlarmType) -> Void
- @Environment(\.dismiss) private var dismiss
- private let columns = [
- GridItem(.adaptive(minimum: 110), spacing: 16)
- ]
- var body: some View {
- NavigationStack {
- ScrollView {
- LazyVGrid(columns: columns, spacing: 16) {
- ForEach(AlarmType.Group.allCases, id: \.self) { group in
- if AlarmType.allCases.contains(where: { $0.group == group }) {
- Section(header:
- Text(group.rawValue)
- .font(.headline)
- .frame(maxWidth: .infinity, alignment: .leading)
- .padding(.horizontal, 4)
- ) {
- ForEach(AlarmType.allCases.filter { $0.group == group },
- id: \.self) { type in
- AlarmTile(type: type) {
- onSelect(type)
- // dismiss()
- }
- }
- }
- }
- }
- }
- .padding()
- }
- .navigationTitle("Add Alarm")
- .toolbar {
- ToolbarItem(placement: .cancellationAction) {
- Button("Cancel") { dismiss() }
- }
- }
- }
- }
- }
- private struct AlarmTile: View {
- let type: AlarmType
- let action: () -> Void
- var body: some View {
- Button(action: action) {
- VStack(spacing: 8) {
- Image(systemName: type.icon)
- .font(.title2)
- .foregroundColor(.accentColor)
- Text(type.rawValue)
- .font(.subheadline)
- .multilineTextAlignment(.center)
- .lineLimit(2)
- Text(type.blurb)
- .font(.caption2)
- .foregroundColor(.secondary)
- .multilineTextAlignment(.center)
- .lineLimit(2)
- }
- .padding()
- .frame(maxWidth: .infinity, minHeight: 110)
- .background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12))
- }
- .buttonStyle(.plain)
- }
- }
- private enum SheetInfo: Identifiable {
- case picker
- case editor(id: UUID, isNew: Bool)
- var id: UUID {
- switch self {
- case .picker:
- return UUID(uuidString:"00000000-0000-0000-0000-000000000000")!
- case .editor(let id, _):
- return id
- }
- }
- }
- struct AlarmListView: View {
- @ObservedObject private var store = Storage.shared.alarms
- @Environment(\.dismiss) private var dismiss
- @State private var sheetInfo: SheetInfo?
- @State private var deleteAfterDismiss: UUID?
- var body: some View {
- NavigationStack {
- List {
- ForEach(store.value) { alarm in
- NavigationLink(alarm.name) {
- AlarmEditor(alarm: binding(for: alarm))
- }
- }
- .onDelete { store.value.remove(atOffsets: $0) }
- }
- .navigationTitle("Alarms")
- .toolbar {
- ToolbarItem(placement: .navigationBarLeading) {
- Button("Done") { dismiss() }
- }
- ToolbarItem(placement: .navigationBarTrailing) {
- Button { sheetInfo = .picker } label: { Image(systemName:"plus") }
- }
- }
- .sheet(item: $sheetInfo,
- onDismiss: handleSheetDismiss) { info in
- sheetContent(for: info)
- }
- }
- }
- private func handleSheetDismiss() {
- if let id = deleteAfterDismiss,
- let idx = store.value.firstIndex(where: { $0.id == id }) {
- store.value.remove(at: idx)
- }
- deleteAfterDismiss = nil
- }
- @ViewBuilder
- private func sheetContent(for info: SheetInfo) -> some View {
- switch info {
- case .picker:
- AddAlarmSheet { type in
- let new = Alarm(type: type)
- store.value.append(new)
- sheetInfo = .editor(id: new.id, isNew: true)
- }
- case .editor(let id, let isNew):
- if let idx = store.value.firstIndex(where: { $0.id == id }) {
- AlarmEditor(
- alarm: $store.value[idx],
- isNew: isNew,
- onDone: { sheetInfo = nil },
- onCancel: {
- deleteAfterDismiss = id
- sheetInfo = nil
- }
- )
- } else {
- Text("Alarm not found").padding()
- }
- }
- }
- private func binding(for alarm: Alarm) -> Binding<Alarm> {
- guard let idx = store.value.firstIndex(where: { $0.id == alarm.id }) else {
- fatalError("Alarm not found")
- }
- return $store.value[idx]
- }
- }
|