Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>

This commit is contained in:
Matt Bruce 2026-02-09 14:13:22 -06:00
parent 950af793c0
commit bda088c9f3
3 changed files with 70 additions and 29 deletions

View File

@ -1682,7 +1682,6 @@
} }
}, },
"Branding Preview" : { "Branding Preview" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -2101,7 +2100,6 @@
} }
}, },
"Clear All Completions" : { "Clear All Completions" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -2352,7 +2350,6 @@
} }
}, },
"Complete First Active Arc (Test Renewal)" : { "Complete First Active Arc (Test Renewal)" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -2949,7 +2946,6 @@
} }
}, },
"Debug" : { "Debug" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -3957,7 +3953,6 @@
} }
}, },
"Generate the app icon" : { "Generate the app icon" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -4471,7 +4466,6 @@
} }
}, },
"Icon Generator" : { "Icon Generator" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -6094,7 +6088,6 @@
} }
}, },
"Preload 6 Months Demo Data" : { "Preload 6 Months Demo Data" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -6219,7 +6212,6 @@
} }
}, },
"Preview launch and icon" : { "Preview launch and icon" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -6337,7 +6329,6 @@
}, },
"Real" : { "Real" : {
"comment" : "The text for the \"Real\" option in the time of day picker.", "comment" : "The text for the \"Real\" option in the time of day picker.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -6356,7 +6347,6 @@
}, },
"Real Time (%@)" : { "Real Time (%@)" : {
"comment" : "Text displayed in the debug picker to indicate whether it is showing the real time or a simulated time.", "comment" : "Text displayed in the debug picker to indicate whether it is showing the real time or a simulated time.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -6468,7 +6458,6 @@
} }
}, },
"Reload Widget Timelines" : { "Reload Widget Timelines" : {
"extractionState" : "stale",
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
"stringUnit" : { "stringUnit" : {
@ -6558,7 +6547,6 @@
}, },
"Reset Setup Wizard" : { "Reset Setup Wizard" : {
"comment" : "Title of a navigation row in the Settings view that resets the setup wizard state.", "comment" : "Title of a navigation row in the Settings view that resets the setup wizard state.",
"extractionState" : "stale",
"localizations" : { "localizations" : {
"en" : { "en" : {
"stringUnit" : { "stringUnit" : {
@ -7245,7 +7233,6 @@
}, },
"Simulate Foreground Refresh" : { "Simulate Foreground Refresh" : {
"comment" : "Title of a settings option that simulates a foreground refresh of the app.", "comment" : "Title of a settings option that simulates a foreground refresh of the app.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -7264,7 +7251,6 @@
}, },
"Simulate Time of Day" : { "Simulate Time of Day" : {
"comment" : "A label for the time of day picker.", "comment" : "A label for the time of day picker.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {
@ -8513,7 +8499,6 @@
}, },
"Trigger Test Notification (5s)" : { "Trigger Test Notification (5s)" : {
"comment" : "Title of a settings option that triggers a test local notification.", "comment" : "Title of a settings option that triggers a test local notification.",
"extractionState" : "stale",
"isCommentAutoGenerated" : true, "isCommentAutoGenerated" : true,
"localizations" : { "localizations" : {
"es-MX" : { "es-MX" : {

View File

@ -25,6 +25,8 @@ struct SettingsView: View {
accentColor: AppAccent.primary accentColor: AppAccent.primary
) )
SettingsDivider(color: AppBorder.subtle)
SettingsToggle( SettingsToggle(
title: String(localized: "Haptics"), title: String(localized: "Haptics"),
subtitle: String(localized: "Vibrate when completing habits"), subtitle: String(localized: "Vibrate when completing habits"),
@ -32,6 +34,8 @@ struct SettingsView: View {
accentColor: AppAccent.primary accentColor: AppAccent.primary
) )
SettingsDivider(color: AppBorder.subtle)
SettingsToggle( SettingsToggle(
title: String(localized: "Sound"), title: String(localized: "Sound"),
subtitle: String(localized: "Play subtle completion sounds"), subtitle: String(localized: "Play subtle completion sounds"),
@ -53,10 +57,12 @@ struct SettingsView: View {
) )
if let categoryStore { if let categoryStore {
SettingsDivider(color: AppBorder.subtle)
SettingsNavigationRow( SettingsNavigationRow(
title: String(localized: "Categories"), title: String(localized: "Categories"),
subtitle: String(localized: "Manage ritual categories"), subtitle: String(localized: "Manage ritual categories"),
backgroundColor: AppSurface.primary backgroundColor: .clear
) { ) {
CategoryListView(store: categoryStore) CategoryListView(store: categoryStore)
} }
@ -88,7 +94,7 @@ struct SettingsView: View {
SettingsNavigationRow( SettingsNavigationRow(
title: String(localized: "Rituals mission"), title: String(localized: "Rituals mission"),
subtitle: String(localized: "Why arcs keep habits grounded"), subtitle: String(localized: "Why arcs keep habits grounded"),
backgroundColor: AppSurface.primary backgroundColor: .clear
) { ) {
SettingsAboutView() SettingsAboutView()
} }
@ -105,15 +111,17 @@ struct SettingsView: View {
SettingsNavigationRow( SettingsNavigationRow(
title: String(localized: "Icon Generator"), title: String(localized: "Icon Generator"),
subtitle: String(localized: "Generate the app icon"), subtitle: String(localized: "Generate the app icon"),
backgroundColor: AppSurface.primary backgroundColor: .clear
) { ) {
IconGeneratorView(config: .rituals, appName: "Rituals") IconGeneratorView(config: .rituals, appName: "Rituals")
} }
SettingsDivider(color: AppBorder.subtle)
SettingsNavigationRow( SettingsNavigationRow(
title: String(localized: "Branding Preview"), title: String(localized: "Branding Preview"),
subtitle: String(localized: "Preview launch and icon"), subtitle: String(localized: "Preview launch and icon"),
backgroundColor: AppSurface.primary backgroundColor: .clear
) { ) {
BrandingPreviewView( BrandingPreviewView(
iconConfig: .rituals, iconConfig: .rituals,
@ -122,7 +130,9 @@ struct SettingsView: View {
) )
} }
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "arrow.counterclockwise", systemImage: "arrow.counterclockwise",
title: String(localized: "Reset Setup Wizard"), title: String(localized: "Reset Setup Wizard"),
iconColor: AppStatus.warning iconColor: AppStatus.warning
@ -133,7 +143,9 @@ struct SettingsView: View {
} }
if let ritualStore { if let ritualStore {
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "calendar.badge.plus", systemImage: "calendar.badge.plus",
title: String(localized: "Preload 6 Months Demo Data"), title: String(localized: "Preload 6 Months Demo Data"),
iconColor: AppStatus.info iconColor: AppStatus.info
@ -142,7 +154,9 @@ struct SettingsView: View {
} }
.accessibilityIdentifier("settings.debug.preloadDemoData") .accessibilityIdentifier("settings.debug.preloadDemoData")
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "checkmark.circle.badge.xmark", systemImage: "checkmark.circle.badge.xmark",
title: String(localized: "Complete First Active Arc (Test Renewal)"), title: String(localized: "Complete First Active Arc (Test Renewal)"),
iconColor: AppStatus.success iconColor: AppStatus.success
@ -150,7 +164,9 @@ struct SettingsView: View {
ritualStore.simulateArcCompletion() ritualStore.simulateArcCompletion()
} }
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "trash", systemImage: "trash",
title: String(localized: "Clear All Completions"), title: String(localized: "Clear All Completions"),
iconColor: AppStatus.error iconColor: AppStatus.error
@ -158,7 +174,9 @@ struct SettingsView: View {
ritualStore.clearAllCompletions() ritualStore.clearAllCompletions()
} }
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "bell.badge", systemImage: "bell.badge",
title: String(localized: "Trigger Test Notification (5s)"), title: String(localized: "Trigger Test Notification (5s)"),
iconColor: AppStatus.info iconColor: AppStatus.info
@ -167,7 +185,9 @@ struct SettingsView: View {
} }
} }
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "arrow.clockwise", systemImage: "arrow.clockwise",
title: String(localized: "Simulate Foreground Refresh"), title: String(localized: "Simulate Foreground Refresh"),
iconColor: AppStatus.info iconColor: AppStatus.info
@ -175,7 +195,9 @@ struct SettingsView: View {
UserDefaults.standard.set(true, forKey: "debugForegroundRefreshNextForeground") UserDefaults.standard.set(true, forKey: "debugForegroundRefreshNextForeground")
} }
SettingsRow( SettingsDivider(color: AppBorder.subtle)
SettingsDebugActionRow(
systemImage: "widget.small", systemImage: "widget.small",
title: String(localized: "Reload Widget Timelines"), title: String(localized: "Reload Widget Timelines"),
iconColor: AppAccent.primary iconColor: AppAccent.primary
@ -184,7 +206,11 @@ struct SettingsView: View {
} }
if let ritualStore { if let ritualStore {
TimeOfDayDebugPicker(store: ritualStore) SettingsDivider(color: AppBorder.subtle)
SettingsCardRow {
TimeOfDayDebugPicker(store: ritualStore)
}
} }
} }
#endif #endif
@ -257,6 +283,37 @@ extension SettingsView {
// MARK: - Debug Time of Day Picker // MARK: - Debug Time of Day Picker
#if DEBUG #if DEBUG
private struct SettingsDebugActionRow: View {
let systemImage: String
let title: String
let iconColor: Color
let action: () -> Void
var body: some View {
SettingsCardRow {
Button(action: action) {
HStack(spacing: Design.Spacing.medium) {
SymbolIcon(systemImage, size: .inline, color: .white)
.frame(width: Design.Size.iconContainerSmall, height: Design.Size.iconContainerSmall)
.background(iconColor.opacity(Design.Opacity.heavy))
.clipShape(.rect(cornerRadius: Design.CornerRadius.xSmall))
Text(title).styled(.subheading)
Spacer()
SymbolIcon.chevron()
}
.padding(.vertical, Design.Spacing.medium)
.padding(.horizontal, Design.Spacing.medium)
.background(Color(.secondarySystemGroupedBackground))
.clipShape(.rect(cornerRadius: Design.CornerRadius.small))
}
.buttonStyle(.plain)
}
}
}
/// Debug picker for simulating different times of day /// Debug picker for simulating different times of day
private struct TimeOfDayDebugPicker: View { private struct TimeOfDayDebugPicker: View {
@Bindable var store: RitualStore @Bindable var store: RitualStore
@ -328,7 +385,6 @@ private struct TimeOfDayDebugPicker: View {
} }
} }
} }
.padding(.horizontal, Design.Spacing.medium)
} }
} }
#endif #endif

View File

@ -158,7 +158,7 @@ Andromida/
- **Theming**: App-specific color providers + `AppSurface`, `AppAccent`, etc. - **Theming**: App-specific color providers + `AppSurface`, `AppAccent`, etc.
- **Branding**: AppLaunchView, AppIconConfig, LaunchScreenConfig - **Branding**: AppLaunchView, AppIconConfig, LaunchScreenConfig
- **Settings UI**: SettingsToggle, SettingsSlider, SettingsSegmentedPicker, SettingsCard - **Settings UI**: `SettingsCard` owns row insets; use `SettingsDivider` between rows, `SettingsCardRow` for custom rows, and `SettingsNavigationRow(backgroundColor: .clear)` for in-card navigation
- **Cloud Sync**: iCloud sync for settings using CloudSyncManager - **Cloud Sync**: iCloud sync for settings using CloudSyncManager
- **Onboarding**: Custom `SetupWizardView` flow (Sherpa integration pending) - **Onboarding**: Custom `SetupWizardView` flow (Sherpa integration pending)