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

This commit is contained in:
Matt Bruce 2026-01-25 16:47:50 -06:00
parent 1f4c28041a
commit 5739e81044
7 changed files with 286 additions and 35 deletions

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array/>
<key>com.apple.developer.ubiquity-kvstore-identifier</key>
<string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
</dict>
</plist>

View File

@ -155,6 +155,10 @@
}
}
},
"Advanced Insights" : {
"comment" : "Subtitle for a feature in the \"Rituals Pro\" upgrade screen, related to \"Advanced Insights\".",
"isCommentAutoGenerated" : true
},
"Begin a four-week arc" : {
"localizations" : {
"en" : {
@ -265,8 +269,11 @@
}
}
},
"Coming Soon" : {
"comment" : "A label indicating that a feature is coming soon.",
"isCommentAutoGenerated" : true
},
"Completed" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
@ -310,6 +317,10 @@
}
}
},
"Create as many arcs as you need" : {
"comment" : "Subtitle for a feature row in the \"Rituals Pro\" upgrade view, describing the ability to create as many rituals as needed.",
"isCommentAutoGenerated" : true
},
"Create ritual" : {
"localizations" : {
"en" : {
@ -464,6 +475,10 @@
}
}
},
"Deeper analytics on your progress" : {
"comment" : "Subtitle for a feature row in the \"Pro\" upgrade view, describing advanced insights.",
"isCommentAutoGenerated" : true
},
"Done" : {
"extractionState" : "stale",
"localizations" : {
@ -487,6 +502,14 @@
}
}
},
"Double tap to check in" : {
"comment" : "A hint text that appears when a user long-presses a \"Today's Habits\" row, indicating that they can mark a habit as completed by double-tapping it.",
"isCommentAutoGenerated" : true
},
"Double tap to mark incomplete" : {
"comment" : "A hint text that appears when a user long-presses a \"Today's Habits\" row, explaining that tapping it again will mark the task as incomplete.",
"isCommentAutoGenerated" : true
},
"Double tap to toggle" : {
"extractionState" : "stale",
"localizations" : {
@ -553,6 +576,9 @@
}
}
}
},
"Faster iCloud synchronization" : {
},
"Feel a soft response on check-in" : {
"localizations" : {
@ -817,6 +843,9 @@
}
}
}
},
"Help us build more features" : {
},
"Hydrate" : {
"localizations" : {
@ -1084,7 +1113,6 @@
}
},
"Not completed" : {
"extractionState" : "stale",
"localizations" : {
"en" : {
"stringUnit" : {
@ -1194,6 +1222,13 @@
}
}
},
"Priority Sync" : {
},
"Pro features are in development" : {
"comment" : "A description below the button that says that the Pro features are in development.",
"isCommentAutoGenerated" : true
},
"Read 10 pages" : {
"localizations" : {
"en" : {
@ -1238,6 +1273,10 @@
}
}
},
"Reset Onboarding" : {
"comment" : "Title of a navigation row in the Settings view that resets the user's onboarding state.",
"isCommentAutoGenerated" : true
},
"Ritual" : {
"localizations" : {
"en" : {
@ -1392,6 +1431,14 @@
}
}
},
"Rituals Pro" : {
"comment" : "The title of the \"Rituals Pro\" view.",
"isCommentAutoGenerated" : true
},
"Rituals Pro gives you everything you need to build lasting habits." : {
"comment" : "A description of what \"Rituals Pro\" offers.",
"isCommentAutoGenerated" : true
},
"Settings" : {
"localizations" : {
"en" : {
@ -1547,6 +1594,10 @@
}
}
},
"Support Development" : {
"comment" : "Subtitle for a feature row in the \"Pro\" upgrade view, related to supporting the development of the app.",
"isCommentAutoGenerated" : true
},
"Switch tabs to explore rituals and insights" : {
"localizations" : {
"en" : {
@ -1817,6 +1868,22 @@
}
}
},
"Unlimited Rituals" : {
"comment" : "Description of a feature in the \"Pro\" upgrade section, describing that users can create as many rituals as they need.",
"isCommentAutoGenerated" : true
},
"Unlock unlimited rituals and more" : {
"comment" : "Title of a navigation link in the \"Rituals Pro\" section of the settings view, leading to the ProUpgradeView.",
"isCommentAutoGenerated" : true
},
"Unlock Your Full Potential" : {
"comment" : "A heading describing the primary benefit of the Pro upgrade.",
"isCommentAutoGenerated" : true
},
"Upgrade to Pro" : {
"comment" : "Text for a settings card that allows users to upgrade to the Pro version of the app.",
"isCommentAutoGenerated" : true
},
"Why arcs keep habits grounded" : {
"localizations" : {
"en" : {
@ -1928,5 +1995,5 @@
}
}
},
"version" : "1.0"
"version" : "1.1"
}

View File

@ -0,0 +1,129 @@
import SwiftUI
import Bedrock
struct ProUpgradeView: View {
var body: some View {
ScrollView(.vertical, showsIndicators: false) {
VStack(spacing: Design.Spacing.xxLarge) {
headerSection
featuresSection
comingSoonSection
}
.padding(Design.Spacing.large)
}
.background(AppSurface.primary)
.navigationTitle(String(localized: "Rituals Pro"))
.navigationBarTitleDisplayMode(.inline)
}
private var headerSection: some View {
VStack(spacing: Design.Spacing.medium) {
Image(systemName: "crown.fill")
.font(.system(size: Design.BaseFontSize.title))
.foregroundStyle(AppAccent.primary)
.accessibilityHidden(true)
Text(String(localized: "Unlock Your Full Potential"))
.font(.title2)
.bold()
.foregroundStyle(AppTextColors.primary)
.multilineTextAlignment(.center)
Text(String(localized: "Rituals Pro gives you everything you need to build lasting habits."))
.font(.body)
.foregroundStyle(AppTextColors.secondary)
.multilineTextAlignment(.center)
}
.padding(.top, Design.Spacing.large)
}
private var featuresSection: some View {
VStack(alignment: .leading, spacing: Design.Spacing.medium) {
ProFeatureRowView(
icon: "infinity",
title: String(localized: "Unlimited Rituals"),
subtitle: String(localized: "Create as many arcs as you need")
)
ProFeatureRowView(
icon: "chart.line.uptrend.xyaxis",
title: String(localized: "Advanced Insights"),
subtitle: String(localized: "Deeper analytics on your progress")
)
ProFeatureRowView(
icon: "icloud.fill",
title: String(localized: "Priority Sync"),
subtitle: String(localized: "Faster iCloud synchronization")
)
ProFeatureRowView(
icon: "heart.fill",
title: String(localized: "Support Development"),
subtitle: String(localized: "Help us build more features")
)
}
.padding(Design.Spacing.large)
.background(AppSurface.card)
.clipShape(.rect(cornerRadius: Design.CornerRadius.large))
}
private var comingSoonSection: some View {
VStack(spacing: Design.Spacing.medium) {
Button {
// No action - coming soon
} label: {
Text(String(localized: "Coming Soon"))
.font(.headline)
.foregroundStyle(AppTextColors.disabled)
.frame(maxWidth: .infinity)
.frame(height: AppMetrics.Size.buttonHeight)
.background(AppSurface.tertiary)
.clipShape(.rect(cornerRadius: Design.CornerRadius.medium))
}
.disabled(true)
Text(String(localized: "Pro features are in development"))
.font(.caption)
.foregroundStyle(AppTextColors.secondary)
}
}
}
private struct ProFeatureRowView: View {
let icon: String
let title: String
let subtitle: String
var body: some View {
HStack(spacing: Design.Spacing.medium) {
Image(systemName: icon)
.font(.title3)
.foregroundStyle(AppAccent.primary)
.frame(width: AppMetrics.Size.iconLarge)
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: Design.Spacing.xxxSmall) {
Text(title)
.font(.subheadline)
.bold()
.foregroundStyle(AppTextColors.primary)
Text(subtitle)
.font(.caption)
.foregroundStyle(AppTextColors.secondary)
}
Spacer(minLength: Design.Spacing.small)
}
.accessibilityElement(children: .combine)
}
}
#Preview {
NavigationStack {
ProUpgradeView()
}
}

View File

@ -38,6 +38,22 @@ struct SettingsView: View {
)
}
SettingsSectionHeader(
title: String(localized: "Rituals Pro"),
systemImage: "crown.fill",
accentColor: AppAccent.secondary
)
SettingsCard(backgroundColor: AppSurface.card, borderColor: AppBorder.subtle) {
SettingsNavigationRow(
title: String(localized: "Upgrade to Pro"),
subtitle: String(localized: "Unlock unlimited rituals and more"),
backgroundColor: AppSurface.primary
) {
ProUpgradeView()
}
}
SettingsSectionHeader(
title: String(localized: "Ritual pacing"),
systemImage: "timer",
@ -124,6 +140,14 @@ struct SettingsView: View {
appName: "Rituals"
)
}
SettingsRow(
systemImage: "arrow.counterclockwise",
title: String(localized: "Reset Onboarding"),
iconColor: AppStatus.warning
) {
UserDefaults.standard.removeObject(forKey: "hasCompletedOnboarding")
}
}
#endif

View File

@ -45,6 +45,8 @@ struct TodayHabitRowView: View {
.clipShape(.rect(cornerRadius: Design.CornerRadius.medium))
}
.accessibilityLabel(Text(title))
.accessibilityValue(isCompleted ? String(localized: "Completed") : String(localized: "Not completed"))
.accessibilityHint(isCompleted ? String(localized: "Double tap to mark incomplete") : String(localized: "Double tap to check in"))
.buttonStyle(.plain)
}
}

View File

@ -1,5 +1,6 @@
import SwiftUI
import Bedrock
import Sherpa
struct HabitRowModel: Identifiable {
let id: UUID
@ -18,12 +19,24 @@ struct TodayRitualSectionView: View {
let habitRows: [HabitRowModel]
var body: some View {
VStack(alignment: .leading, spacing: Design.Spacing.large) {
VStack(alignment: .leading, spacing: Bedrock.Design.Spacing.large) {
SectionHeaderView(
title: String(localized: "Focus ritual"),
subtitle: String(localized: "Four-week arc in progress")
)
focusCard
SectionHeaderView(
title: String(localized: "Habits"),
subtitle: String(localized: "Tap to check in")
)
habitsList
}
}
private var focusCard: some View {
RitualFocusCardView(
title: focusTitle,
theme: focusTheme,
@ -31,14 +44,21 @@ struct TodayRitualSectionView: View {
completionSummary: completionSummary,
progress: progress
)
.sherpaTag(RitualsOnboardingTag.focusRitual)
}
SectionHeaderView(
title: String(localized: "Habits"),
subtitle: String(localized: "Tap to check in")
private var habitsList: some View {
VStack(spacing: Bedrock.Design.Spacing.medium) {
if let firstHabit = habitRows.first {
TodayHabitRowView(
title: firstHabit.title,
symbolName: firstHabit.symbolName,
isCompleted: firstHabit.isCompleted,
action: firstHabit.action
)
VStack(spacing: Design.Spacing.medium) {
ForEach(habitRows) { habit in
.sherpaTag(RitualsOnboardingTag.firstHabit)
}
ForEach(habitRows.dropFirst()) { habit in
TodayHabitRowView(
title: habit.title,
symbolName: habit.symbolName,
@ -48,7 +68,6 @@ struct TodayRitualSectionView: View {
}
}
}
}
}
#Preview {

30
TODO.md
View File

@ -1,31 +1,31 @@
# Andromida Focus & Fix List
## 1) Onboarding walkthrough (Sherpa)
- [ ] Restore Sherpa tags for focus ritual card and first habit row without triggering Swift compiler crashes.
- [ ] Confirm walkthrough starts on first launch (ensure `hasCompletedOnboarding` is false in `@AppStorage`).
- [ ] Add a debug-only “Reset Onboarding” action in Settings to clear `hasCompletedOnboarding`.
- [ ] Verify tags visually align with the intended UI elements on iPhone 17 Pro Max.
- [x] Restore Sherpa tags for focus ritual card and first habit row without triggering Swift compiler crashes.
- [x] Confirm walkthrough starts on first launch (ensure `hasCompletedOnboarding` is false in `@AppStorage`).
- [x] Add a debug-only "Reset Onboarding" action in Settings to clear `hasCompletedOnboarding`.
- [x] Verify tags visually align with the intended UI elements on iPhone 17 Pro Max.
## 2) Swift compiler stability
- [ ] Identify the minimal Sherpa usage pattern that avoids the “failed to produce diagnostic” crash.
- [ ] Avoid `#Preview` macro ambiguity when Sherpa is imported (use `#if DEBUG` + `PreviewProvider` or remove previews for Sherpa-tagged views).
- [ ] Avoid ambiguous accessibility modifier overloads when Sherpa is imported.
- [x] Identify the minimal Sherpa usage pattern that avoids the "failed to produce diagnostic" crash.
- [x] Avoid `#Preview` macro ambiguity when Sherpa is imported (use `#if DEBUG` + `PreviewProvider` or remove previews for Sherpa-tagged views).
- [x] Avoid ambiguous accessibility modifier overloads when Sherpa is imported.
## 3) Today tab UX polish
- [ ] Re-add accessibility value/hint for habit rows once Sherpa-related ambiguity is resolved.
- [ ] Confirm focus ritual card and habit rows still match the intended visual hierarchy after refactors.
- [x] Re-add accessibility value/hint for habit rows once Sherpa-related ambiguity is resolved.
- [x] Confirm focus ritual card and habit rows still match the intended visual hierarchy after refactors.
## 4) Settings & product readiness
- [ ] Add a paid-app placeholder (e.g., “Pro unlock” copy) without backend requirements.
- [x] Add a paid-app placeholder (e.g., "Pro unlock" copy) without backend requirements.
- [ ] Confirm default settings and theme in Settings match Bedrock branding.
## 5) Data & defaults
- [ ] Confirm seed ritual creation and quick ritual creation behave as expected.
- [ ] Validate SwiftData sync (if enabled) doesnt require any external API.
- [ ] Validate SwiftData sync (if enabled) doesn't require any external API.
## 6) QA checklist
- [ ] First-launch walkthrough appears on a clean install.
- [ ] Onboarding can be manually reset from Settings.
- [ ] No build warnings or Swift compiler crashes.
- [ ] iPhone 17 Pro Max simulator layout verified on Today, Rituals, Insights, Settings.
- [x] First-launch walkthrough appears on a clean install.
- [x] Onboarding can be manually reset from Settings.
- [x] No build warnings or Swift compiler crashes.
- [x] iPhone 17 Pro Max simulator layout verified on Today, Rituals, Insights, Settings.