|
|
@@ -7,22 +7,33 @@ struct AddAlarmSheet: View {
|
|
|
let onSelect: (AlarmType) -> Void
|
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
|
|
+ @State private var searchText = ""
|
|
|
+
|
|
|
private let columns = [
|
|
|
GridItem(.adaptive(minimum: 110), spacing: 16),
|
|
|
]
|
|
|
|
|
|
+ private func matches(_ type: AlarmType) -> Bool {
|
|
|
+ let query = searchText.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
|
+ guard !query.isEmpty else { return true }
|
|
|
+ return type.rawValue.localizedCaseInsensitiveContains(query)
|
|
|
+ || type.blurb.localizedCaseInsensitiveContains(query)
|
|
|
+ || type.group.rawValue.localizedCaseInsensitiveContains(query)
|
|
|
+ }
|
|
|
+
|
|
|
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 }) {
|
|
|
+ let types = AlarmType.allCases.filter { $0.group == group && matches($0) }
|
|
|
+ if !types.isEmpty {
|
|
|
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
|
|
|
+ ForEach(types, id: \.self) { type in
|
|
|
AlarmTile(type: type) {
|
|
|
onSelect(type)
|
|
|
}
|
|
|
@@ -32,8 +43,25 @@ struct AddAlarmSheet: View {
|
|
|
}
|
|
|
}
|
|
|
.padding()
|
|
|
+
|
|
|
+ if !AlarmType.allCases.contains(where: matches) {
|
|
|
+ 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(.top, 40)
|
|
|
+ .padding(.horizontal)
|
|
|
+ }
|
|
|
}
|
|
|
.navigationTitle("Add Alarm")
|
|
|
+ .searchable(text: $searchText, prompt: "Search alarms")
|
|
|
.toolbar {
|
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
|
Button("Cancel") { dismiss() }
|