BusinessCard/BusinessCard/Views/SettingsView.swift

204 lines
6.6 KiB
Swift

//
// SettingsView.swift
// BusinessCard
//
// App settings screen using Bedrock settings layout contract:
// SettingsCard owns horizontal inset, custom rows use SettingsCardRow,
// and in-card separators use SettingsDivider.
//
import SwiftUI
import Bedrock
struct SettingsView: View {
@Environment(AppState.self) private var appState
@State private var settingsState = SettingsState()
var body: some View {
NavigationStack {
ScrollView {
VStack(spacing: Design.Spacing.large) {
// MARK: - About Section
appearanceSection
aboutSection
// MARK: - Debug Section
#if DEBUG
debugSection
#endif
Spacer(minLength: Design.Spacing.xxxLarge)
}
.padding(.horizontal, Design.Spacing.large)
.padding(.top, Design.Spacing.medium)
}
.background(Color.AppBackground.base)
.navigationTitle(String.localized("Settings"))
.navigationBarTitleDisplayMode(.large)
}
}
// MARK: - Appearance Section
private var appearanceSection: some View {
VStack(alignment: .leading, spacing: Design.Spacing.small) {
SettingsSectionHeader(
title: "Appearance",
systemImage: "paintbrush",
accentColor: AppThemeAccent.primary
)
SettingsCard(
backgroundColor: Color.AppBackground.elevated,
borderColor: AppBorder.standard
) {
SettingsSegmentedPicker(
title: "Theme",
subtitle: "Choose app theme",
options: [
("System", AppAppearance.system),
("Light", AppAppearance.light),
("Dark", AppAppearance.dark)
],
selection: Binding(
get: { appState.preferences.appearance },
set: { appState.preferences.appearance = $0 }
),
accentColor: AppThemeAccent.primary
)
}
}
}
// MARK: - About Section
private var aboutSection: some View {
VStack(alignment: .leading, spacing: Design.Spacing.small) {
SettingsSectionHeader(
title: String.localized("About"),
systemImage: "info.circle",
accentColor: AppThemeAccent.primary
)
SettingsCard(
backgroundColor: Color.AppBackground.elevated,
borderColor: AppBorder.standard
) {
SettingsCardRow {
HStack {
Text(settingsState.appName)
.typography(.title3Bold)
.foregroundStyle(Color.AppText.primary)
Spacer()
}
}
SettingsDivider(color: AppBorder.subtle)
SettingsCardRow {
HStack {
Text(String.localized("Version"))
.typography(.bodyEmphasis)
.foregroundStyle(Color.AppText.primary)
Spacer()
Text(settingsState.versionString)
.typography(.body)
.fontDesign(.monospaced)
.foregroundStyle(Color.AppText.secondary)
}
}
SettingsDivider(color: AppBorder.subtle)
SettingsCardRow {
HStack {
Text(String.localized("Developer"))
.typography(.bodyEmphasis)
.foregroundStyle(Color.AppText.primary)
Spacer()
Text("Matt Bruce")
.typography(.body)
.foregroundStyle(Color.AppText.secondary)
}
}
SettingsDivider(color: AppBorder.subtle)
SettingsNavigationRow(
title: String.localized("Widgets"),
subtitle: "Phone and watch preview",
backgroundColor: .clear
) {
WidgetsView()
}
}
}
}
// MARK: - Debug Section
#if DEBUG
private var debugSection: some View {
VStack(alignment: .leading, spacing: Design.Spacing.small) {
SettingsSectionHeader(
title: "Debug",
systemImage: "ant.fill",
accentColor: AppStatus.error
)
SettingsCard(
backgroundColor: Color.AppBackground.elevated,
borderColor: AppBorder.standard
) {
SettingsToggle(
title: "Enable Debug Premium",
subtitle: "Unlock all premium features for testing",
isOn: Binding(
get: { appState.preferences.isDebugPremiumEnabled },
set: { appState.preferences.isDebugPremiumEnabled = $0 }
),
accentColor: AppStatus.warning
)
SettingsDivider(color: AppBorder.subtle)
SettingsNavigationRow(
title: "Icon Generator",
subtitle: "Generate and save app icon to Files",
backgroundColor: .clear
) {
IconGeneratorView(config: .businessCard, appName: "BusinessCard")
}
SettingsDivider(color: AppBorder.subtle)
SettingsNavigationRow(
title: "Branding Preview",
subtitle: "Preview app icon and launch screen",
backgroundColor: .clear
) {
BrandingPreviewView(
iconConfig: .businessCard,
launchConfig: .businessCard,
appName: "BusinessCard"
)
}
}
}
}
#endif
}
// MARK: - Preview
#Preview {
SettingsView()
}