Version casi lista
This commit is contained in:
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user