Version casi lista

This commit is contained in:
alexandrev-tibco
2026-02-17 13:34:02 +01:00
commit e593453abd
99 changed files with 10867 additions and 0 deletions
+235
View File
@@ -0,0 +1,235 @@
import SwiftUI
import SwiftData
import EventKit
struct SettingsView: View {
@Environment(\.modelContext) private var context
@Query private var allSettings: [AppSettings]
@StateObject private var viewModel = SettingsViewModel()
@State private var showResetAllDataAlert = false
private var settings: AppSettings? { allSettings.first }
var body: some View {
ZStack {
Color.mealMoodBackground.ignoresSafeArea()
if let settings = settings {
settingsContent(settings: settings)
}
}
.navigationTitle("settings_title")
.navigationBarTitleDisplayMode(.inline)
.toolbarBackground(Color.mealMoodBackground, for: .navigationBar)
.toolbarBackground(.visible, for: .navigationBar)
.environment(\.isEnabled, true)
}
@ViewBuilder
private func settingsContent(settings: AppSettings) -> some View {
List {
// Planning section
Section {
Picker("settings_meal_windows", selection: Binding(
get: { settings.mealWindowsEnum },
set: { settings.mealWindowsEnum = $0 }
)) {
Text("meal_windows_dinner_only").tag(MealWindows.dinnerOnly)
Text("meal_windows_lunch_only").tag(MealWindows.lunchOnly)
Text("meal_windows_both").tag(MealWindows.both)
}
Toggle("settings_include_weekends", isOn: Binding(
get: { settings.includeWeekends },
set: { settings.includeWeekends = $0 }
))
.tint(.mealMoodCoral)
} header: {
Label("settings_planning", systemImage: "fork.knife")
}
.listRowBackground(Color.mealMoodSurface)
// Calendar section
Section {
Toggle("settings_icloud_sync", isOn: Binding(
get: { settings.iCloudSyncEnabledResolved },
set: { settings.iCloudSyncEnabledResolved = $0 }
))
.tint(.mealMoodCoral)
Toggle("settings_sync", isOn: Binding(
get: { settings.syncEnabled },
set: { newValue in
if newValue {
Task {
let granted = await viewModel.requestCalendarAccess()
if granted {
settings.syncEnabled = true
}
}
} else {
settings.syncEnabled = false
}
}
))
.tint(.mealMoodCoral)
if settings.syncEnabled {
Picker("settings_sync_mode", selection: Binding(
get: { settings.syncModeEnum },
set: { settings.syncModeEnum = $0 }
)) {
ForEach(CalendarSyncMode.allCases, id: \.self) { mode in
Text(LocalizedStringKey(mode.localizedKey)).tag(mode)
}
}
if !viewModel.availableCalendars.isEmpty {
Picker("calendar_select", selection: Binding(
get: { settings.calendarId },
set: { settings.calendarId = $0 }
)) {
Text("calendar_select").tag(nil as String?)
ForEach(viewModel.availableCalendars, id: \.calendarIdentifier) { cal in
Text(cal.title).tag(cal.calendarIdentifier as String?)
}
}
}
DatePicker("settings_lunch_time", selection: Binding(
get: { settings.lunchTime },
set: { settings.lunchTime = $0 }
), displayedComponents: .hourAndMinute)
DatePicker("settings_dinner_time", selection: Binding(
get: { settings.dinnerTime },
set: { settings.dinnerTime = $0 }
), displayedComponents: .hourAndMinute)
Picker("settings_event_duration", selection: Binding(
get: { settings.eventDuration },
set: { settings.eventDuration = $0 }
)) {
Text("duration_30").tag(30)
Text("duration_60").tag(60)
Text("duration_90").tag(90)
Text("duration_120").tag(120)
}
TextField("settings_event_prefix", text: Binding(
get: { settings.eventPrefix },
set: { settings.eventPrefix = $0 }
))
Picker("settings_reminder", selection: Binding(
get: { settings.reminderMinutesBefore },
set: { settings.reminderMinutesBefore = $0 }
)) {
Text("settings_reminder_none").tag(nil as Int?)
Text("reminder_30").tag(30 as Int?)
Text("reminder_60").tag(60 as Int?)
Text("reminder_120").tag(120 as Int?)
}
}
} header: {
Label("settings_calendar", systemImage: "calendar")
}
.listRowBackground(Color.mealMoodSurface)
// Tags section
Section {
NavigationLink(destination: TagListView()) {
Text("settings_manage_tags")
}
} header: {
Label("settings_tags", systemImage: "tag")
}
.listRowBackground(Color.mealMoodSurface)
// Language section
Section {
Picker("settings_language", selection: Binding(
get: { settings.languageEnum },
set: { settings.languageEnum = $0 }
)) {
ForEach(AppLanguage.allCases, id: \.self) { lang in
Text(lang.displayName).tag(lang)
}
}
} header: {
Label("settings_language", systemImage: "globe")
}
.listRowBackground(Color.mealMoodSurface)
// Premium section
Section {
HStack {
Text("settings_premium_status")
Spacer()
Text(settings.isPremium ? "Premium" : "Free")
.foregroundColor(.mealMoodTextSecondary)
}
NavigationLink(destination: PremiumView(settings: settings)) {
Text("settings_remove_ads")
}
} header: {
Label("settings_premium", systemImage: "star")
}
.listRowBackground(Color.mealMoodSurface)
Section {
Button {
ReviewPromptService.shared.requestFromSettings()
} label: {
Label("settings_rate_app", systemImage: "star.bubble")
}
Link(destination: URL(string: "https://mealmood.app")!) {
Label("settings_website", systemImage: "safari")
}
Link(destination: URL(string: "mailto:support@mealmood.app")!) {
Label("settings_support", systemImage: "envelope")
}
} header: {
Label("settings_about", systemImage: "info.circle")
}
.listRowBackground(Color.mealMoodSurface)
Section {
Button(role: .destructive) {
showResetAllDataAlert = true
} label: {
Label("settings_reset_all_data", systemImage: "trash")
}
} header: {
Label("settings_danger_zone", systemImage: "exclamationmark.triangle")
}
.listRowBackground(Color.mealMoodSurface)
}
.scrollContentBackground(.hidden)
.listStyle(.insetGrouped)
.foregroundColor(.mealMoodTextPrimary)
.tint(.mealMoodCoral)
.onAppear {
if settings.syncEnabled {
viewModel.loadCalendars()
}
}
.alert("calendar_permission_title", isPresented: $viewModel.showCalendarPermissionAlert) {
Button("calendar_permission_settings") { viewModel.openSystemSettings() }
Button("reset_cancel", role: .cancel) {}
} message: {
Text("calendar_permission_message")
}
.alert("settings_reset_all_data_title", isPresented: $showResetAllDataAlert) {
Button("reset_cancel", role: .cancel) {}
Button("settings_reset_all_data_confirm", role: .destructive) {
viewModel.resetAllData(context: context)
}
} message: {
Text("settings_reset_all_data_message")
}
}
}