From 1a7aa792c587d1eb7ec37b42e68ab37fbd489b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20Bj=C3=B6rkert?= Date: Tue, 7 Jul 2026 20:40:03 +0200 Subject: [PATCH] Add search to the alarms list --- LoopFollow/Alarm/AlarmListView.swift | 37 +++++++++++++++++++++++++--- 1 file changed, 34 insertions(+), 3 deletions(-) diff --git a/LoopFollow/Alarm/AlarmListView.swift b/LoopFollow/Alarm/AlarmListView.swift index 3240208db..f8a6beeb0 100644 --- a/LoopFollow/Alarm/AlarmListView.swift +++ b/LoopFollow/Alarm/AlarmListView.swift @@ -22,21 +22,35 @@ struct AlarmListView: View { @State private var sheetInfo: SheetInfo? @State private var deleteAfterDismiss: UUID? @State private var selectedAlarm: Alarm? + @State private var searchText = "" + + // MARK: - Search + + private func matches(_ alarm: Alarm) -> Bool { + let query = searchText.trimmingCharacters(in: .whitespacesAndNewlines) + guard !query.isEmpty else { return true } + return alarm.name.localizedCaseInsensitiveContains(query) + || alarm.type.rawValue.localizedCaseInsensitiveContains(query) + } + + private var hasResults: Bool { + !snoozedAlarms.isEmpty || !activeAlarms.isEmpty || !inactiveAlarms.isEmpty + } // MARK: - Categorized Alarms private var snoozedAlarms: [Alarm] { - store.value.filter { $0.snoozedUntil ?? .distantPast > Date() && $0.isEnabled } + store.value.filter { $0.snoozedUntil ?? .distantPast > Date() && $0.isEnabled && matches($0) } .sorted(by: Alarm.byPriorityThenSpec) } private var activeAlarms: [Alarm] { - store.value.filter { $0.isEnabled && ($0.snoozedUntil ?? .distantPast <= Date()) } + store.value.filter { $0.isEnabled && ($0.snoozedUntil ?? .distantPast <= Date()) && matches($0) } .sorted(by: Alarm.byPriorityThenSpec) } private var inactiveAlarms: [Alarm] { - store.value.filter { !$0.isEnabled } + store.value.filter { !$0.isEnabled && matches($0) } .sorted(by: Alarm.byPriorityThenSpec) } @@ -81,6 +95,23 @@ struct AlarmListView: View { } } } + .overlay { + if !hasResults, !searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + VStack(spacing: 8) { + Image(systemName: "magnifyingglass") + .font(.largeTitle) + .foregroundColor(.secondary) + Text("No Results") + .font(.headline) + Text("No alarms match “\(searchText)”.") + .font(.subheadline) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) + } + .padding(.horizontal) + } + } + .searchable(text: $searchText, prompt: "Search alarms") .sheet(item: $sheetInfo, onDismiss: handleSheetDismiss) { info in sheetContent(for: info) }