Natives iOS-App-Gerüst (Xcode 26, synchronisierte Ordner, iOS 18+). Features: - Gewohnheiten anlegen (Name, SF-Symbol, Farbe), heute abhaken, Streaks, Löschen - Detailansicht mit Monatskalender (Tage nachtragbar) und Statistiken - Tägliche Erinnerungen via lokale Notifications - Home-Screen-Widget (klein/mittel) mit App-Group-Datenaustausch
101 lines
3.6 KiB
Swift
101 lines
3.6 KiB
Swift
import SwiftUI
|
|
import SwiftData
|
|
|
|
struct AddHabitView: View {
|
|
@Environment(\.modelContext) private var context
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
@State private var name = ""
|
|
@State private var symbolName = "star.fill"
|
|
@State private var colorHex = "#34C759"
|
|
@State private var reminderTime: Date?
|
|
|
|
private let symbols = [
|
|
"star.fill", "drop.fill", "flame.fill", "book.fill", "dumbbell.fill",
|
|
"leaf.fill", "heart.fill", "moon.fill", "cup.and.saucer.fill", "figure.run"
|
|
]
|
|
private let colors = ["#34C759", "#007AFF", "#FF9500", "#FF2D55", "#AF52DE", "#5AC8FA"]
|
|
|
|
private let columns = [GridItem(.adaptive(minimum: 44), spacing: 12)]
|
|
|
|
var body: some View {
|
|
NavigationStack {
|
|
Form {
|
|
Section("Name") {
|
|
TextField("z. B. Wasser trinken", text: $name)
|
|
}
|
|
|
|
Section("Symbol") {
|
|
LazyVGrid(columns: columns, spacing: 12) {
|
|
ForEach(symbols, id: \.self) { symbol in
|
|
Image(systemName: symbol)
|
|
.font(.title2)
|
|
.frame(width: 44, height: 44)
|
|
.background(symbol == symbolName ? Color(hex: colorHex).opacity(0.2) : Color.clear)
|
|
.foregroundStyle(symbol == symbolName ? Color(hex: colorHex) : Color.secondary)
|
|
.clipShape(RoundedRectangle(cornerRadius: 10))
|
|
.onTapGesture { symbolName = symbol }
|
|
}
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
|
|
Section("Farbe") {
|
|
HStack(spacing: 12) {
|
|
ForEach(colors, id: \.self) { hex in
|
|
Circle()
|
|
.fill(Color(hex: hex))
|
|
.frame(width: 32, height: 32)
|
|
.overlay {
|
|
if hex == colorHex {
|
|
Image(systemName: "checkmark")
|
|
.font(.caption.bold())
|
|
.foregroundStyle(.white)
|
|
}
|
|
}
|
|
.onTapGesture { colorHex = hex }
|
|
}
|
|
}
|
|
.padding(.vertical, 4)
|
|
}
|
|
|
|
Section("Erinnerung") {
|
|
ReminderEditor(reminderTime: $reminderTime)
|
|
}
|
|
}
|
|
.navigationTitle("Neue Gewohnheit")
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Abbrechen") { dismiss() }
|
|
}
|
|
ToolbarItem(placement: .confirmationAction) {
|
|
Button("Sichern") { save() }
|
|
.disabled(trimmedName.isEmpty)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private var trimmedName: String {
|
|
name.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
}
|
|
|
|
private func save() {
|
|
let habit = Habit(
|
|
name: trimmedName,
|
|
symbolName: symbolName,
|
|
colorHex: colorHex,
|
|
reminderTime: reminderTime
|
|
)
|
|
context.insert(habit)
|
|
NotificationManager.reschedule(for: habit)
|
|
WidgetSync.refresh(context)
|
|
dismiss()
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
AddHabitView()
|
|
.modelContainer(for: [Habit.self, HabitEntry.self], inMemory: true)
|
|
}
|