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
82 lines
2.7 KiB
Swift
82 lines
2.7 KiB
Swift
import SwiftUI
|
|
import SwiftData
|
|
|
|
struct HabitDetailView: View {
|
|
@Environment(\.modelContext) private var context
|
|
@Bindable var habit: Habit
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: 24) {
|
|
header
|
|
|
|
HStack(spacing: 12) {
|
|
StatTile(value: "\(habit.currentStreak)", label: "Aktuell", systemImage: "flame.fill", color: color)
|
|
StatTile(value: "\(habit.longestStreak)", label: "Rekord", systemImage: "trophy.fill", color: color)
|
|
StatTile(value: "\(habit.totalCompletions)", label: "Gesamt", systemImage: "checkmark.seal.fill", color: color)
|
|
}
|
|
|
|
MonthCalendarView(habit: habit) { day in
|
|
context.toggleCompletion(for: habit, on: day)
|
|
}
|
|
.padding()
|
|
.background(.background.secondary, in: RoundedRectangle(cornerRadius: 16))
|
|
|
|
VStack(spacing: 12) {
|
|
ReminderEditor(reminderTime: $habit.reminderTime)
|
|
}
|
|
.padding()
|
|
.background(.background.secondary, in: RoundedRectangle(cornerRadius: 16))
|
|
.onChange(of: habit.reminderTime) {
|
|
NotificationManager.reschedule(for: habit)
|
|
}
|
|
}
|
|
.padding()
|
|
}
|
|
.navigationTitle(habit.name)
|
|
.navigationBarTitleDisplayMode(.inline)
|
|
}
|
|
|
|
private var color: Color { Color(hex: habit.colorHex) }
|
|
|
|
private var header: some View {
|
|
VStack(spacing: 8) {
|
|
Image(systemName: habit.symbolName)
|
|
.font(.system(size: 44))
|
|
.foregroundStyle(color)
|
|
.frame(width: 88, height: 88)
|
|
.background(color.opacity(0.15), in: Circle())
|
|
Text(habit.name)
|
|
.font(.title2.bold())
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct StatTile: View {
|
|
let value: String
|
|
let label: String
|
|
let systemImage: String
|
|
let color: Color
|
|
|
|
var body: some View {
|
|
VStack(spacing: 6) {
|
|
Image(systemName: systemImage)
|
|
.foregroundStyle(color)
|
|
Text(value)
|
|
.font(.title3.bold())
|
|
Text(label)
|
|
.font(.caption)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
.frame(maxWidth: .infinity)
|
|
.padding(.vertical, 16)
|
|
.background(.background.secondary, in: RoundedRectangle(cornerRadius: 16))
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
NavigationStack {
|
|
HabitDetailView(habit: Habit(name: "Wasser trinken", symbolName: "drop.fill", colorHex: "#007AFF"))
|
|
}
|
|
.modelContainer(for: [Habit.self, HabitEntry.self], inMemory: true)
|
|
}
|