157 lines
5.8 KiB
Swift
157 lines
5.8 KiB
Swift
import SwiftUI
|
|
import Bedrock
|
|
|
|
/// Sheet for creating or editing a category
|
|
struct CategoryEditSheet: View {
|
|
@Bindable var store: CategoryStore
|
|
let category: Category?
|
|
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
@State private var name: String = ""
|
|
@State private var selectedColorName: String = "gray"
|
|
@State private var showingDeleteConfirmation = false
|
|
|
|
private var isEditing: Bool { category != nil }
|
|
private var isPreset: Bool { category?.isPreset ?? false }
|
|
|
|
private var canSave: Bool {
|
|
let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
if isPreset {
|
|
// Presets can always save (just color change)
|
|
return true
|
|
}
|
|
// New/user categories need a valid unique name
|
|
return !trimmedName.isEmpty && store.isNameAvailable(trimmedName, excluding: category)
|
|
}
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section {
|
|
if isPreset {
|
|
// Preset name is read-only
|
|
HStack {
|
|
Text(String(localized: "Name"))
|
|
Spacer()
|
|
Text(name)
|
|
.foregroundStyle(AppTextColors.secondary)
|
|
}
|
|
} else {
|
|
TextField(String(localized: "Category Name"), text: $name)
|
|
}
|
|
} header: {
|
|
Text(String(localized: "Name"))
|
|
}
|
|
.listRowBackground(AppSurface.card)
|
|
|
|
Section {
|
|
LazyVGrid(columns: [GridItem(.adaptive(minimum: 44))], spacing: Design.Spacing.medium) {
|
|
ForEach(Category.availableColors, id: \.name) { colorOption in
|
|
Button {
|
|
selectedColorName = colorOption.name
|
|
} label: {
|
|
Circle()
|
|
.fill(colorOption.color)
|
|
.frame(width: 40, height: 40)
|
|
.overlay(
|
|
Circle()
|
|
.strokeBorder(Color.white, lineWidth: selectedColorName == colorOption.name ? 3 : 0)
|
|
)
|
|
.shadow(color: selectedColorName == colorOption.name ? colorOption.color.opacity(0.5) : .clear, radius: 4)
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
}
|
|
.padding(.vertical, Design.Spacing.small)
|
|
} header: {
|
|
Text(String(localized: "Color"))
|
|
}
|
|
.listRowBackground(AppSurface.card)
|
|
|
|
// Delete button for user categories
|
|
if isEditing && !isPreset {
|
|
Section {
|
|
Button(role: .destructive) {
|
|
showingDeleteConfirmation = true
|
|
} label: {
|
|
HStack {
|
|
Spacer()
|
|
Text(String(localized: "Delete Category"))
|
|
Spacer()
|
|
}
|
|
}
|
|
}
|
|
.listRowBackground(AppSurface.card)
|
|
}
|
|
}
|
|
.scrollContentBackground(.hidden)
|
|
.background(AppSurface.primary)
|
|
.navigationTitle(isEditing ? String(localized: "Edit Category") : String(localized: "New Category"))
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button(String(localized: "Cancel")) {
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
ToolbarItem(placement: .confirmationAction) {
|
|
Button(String(localized: "Save")) {
|
|
save()
|
|
dismiss()
|
|
}
|
|
.disabled(!canSave)
|
|
}
|
|
}
|
|
.onAppear {
|
|
loadCategory()
|
|
}
|
|
.alert(String(localized: "Delete Category?"), isPresented: $showingDeleteConfirmation) {
|
|
Button(String(localized: "Cancel"), role: .cancel) {}
|
|
Button(String(localized: "Delete"), role: .destructive) {
|
|
if let category {
|
|
store.deleteCategory(category)
|
|
}
|
|
dismiss()
|
|
}
|
|
} message: {
|
|
Text(String(localized: "Rituals using this category will be set to no category."))
|
|
}
|
|
}
|
|
.presentationDetents([.medium])
|
|
}
|
|
|
|
private func loadCategory() {
|
|
if let category {
|
|
name = category.name
|
|
selectedColorName = category.colorName
|
|
} else {
|
|
name = ""
|
|
selectedColorName = "blue" // Default for new categories
|
|
}
|
|
}
|
|
|
|
private func save() {
|
|
if let category {
|
|
// Update existing
|
|
if isPreset {
|
|
store.updateCategory(category, colorName: selectedColorName)
|
|
} else {
|
|
store.updateCategory(category, name: name, colorName: selectedColorName)
|
|
}
|
|
} else {
|
|
// Create new
|
|
store.addCategory(name: name, colorName: selectedColorName)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview("New Category") {
|
|
CategoryEditSheet(store: CategoryStore.preview, category: nil)
|
|
}
|
|
|
|
#Preview("Edit Preset") {
|
|
CategoryEditSheet(store: CategoryStore.preview, category: Category.defaultPresets.first!)
|
|
}
|