Files
OpenAppLock/OpenAppLock/Views/Rules/NewRuleSheet.swift

112 lines
3.8 KiB
Swift

//
// NewRuleSheet.swift
// OpenAppLock
//
import SwiftData
import SwiftUI
/// "New Rule" as a plain list: a Rule Type section, then the preset sections.
/// Picking either pushes the editor; committing saves and closes the sheet.
struct NewRuleSheet: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) private var modelContext
@State private var pendingDraft: RuleDraft?
var body: some View {
NavigationStack {
List {
Section {
ForEach(RuleKind.allCases, id: \.self) { kind in
kindRow(kind)
}
} header: {
Text("Rule Type").textCase(nil)
}
ForEach(RulePresetSection.all) { section in
Section {
ForEach(section.presets) { preset in
presetRow(preset)
}
} header: {
VStack(alignment: .leading, spacing: 2) {
Text(section.title)
Text(section.subtitle)
.font(.caption)
.foregroundStyle(.secondary)
}
.textCase(nil)
}
}
}
.navigationTitle("New Rule")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Close", systemImage: "xmark") {
dismiss()
}
.accessibilityIdentifier("closeNewRuleButton")
}
}
.navigationDestination(item: $pendingDraft) { draft in
RuleEditorView(
mode: .create,
draft: draft,
onCommit: { committed in
modelContext.insert(committed.makeRule())
dismiss()
}
)
}
}
}
private func kindRow(_ kind: RuleKind) -> some View {
Button {
pendingDraft = RuleDraft(kind: kind)
} label: {
HStack {
Image(systemName: kind.symbolName)
.foregroundStyle(.tint)
.frame(width: 28)
VStack(alignment: .leading, spacing: 2) {
Text(kind.displayName)
.foregroundStyle(Color.primary)
Text(kind.exampleText)
.font(.caption)
.foregroundStyle(Color.secondary)
}
Spacer()
Image(systemName: "chevron.right")
.font(.caption.weight(.semibold))
.foregroundStyle(Color(.tertiaryLabel))
}
}
.accessibilityIdentifier("ruleKind-\(kind.rawValue)")
}
private func presetRow(_ preset: RulePreset) -> some View {
Button {
pendingDraft = RuleDraft(preset: preset)
} label: {
HStack {
Image(systemName: preset.symbolName)
.foregroundStyle(.tint)
.frame(width: 28)
VStack(alignment: .leading, spacing: 2) {
Text(preset.name)
.foregroundStyle(Color.primary)
Text("\(preset.schedule.timeRangeLabel) · \(preset.days.summary)")
.font(.caption)
.foregroundStyle(Color.secondary)
}
Spacer()
Image(systemName: "plus.circle.fill")
.foregroundStyle(.tint)
}
}
.accessibilityIdentifier("preset-\(preset.id)")
}
}