From ee347bb402fd0543b1a5c71907af8cb729ac2a32 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 27 Jan 2026 15:06:33 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- Andromida/App/Models/RitualPresets.swift | 16 ++++++++-------- Andromida/App/State/RitualStore.swift | 21 ++++++++++++++++++++- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Andromida/App/Models/RitualPresets.swift b/Andromida/App/Models/RitualPresets.swift index ef0de1f..3fab7ff 100644 --- a/Andromida/App/Models/RitualPresets.swift +++ b/Andromida/App/Models/RitualPresets.swift @@ -65,7 +65,7 @@ enum RitualPresetLibrary { title: String(localized: "Morning Hydration"), theme: String(localized: "Start your day refreshed"), notes: String(localized: "Build the habit of hydrating first thing in the morning."), - durationDays: 21, + durationDays: 28, timeOfDay: .morning, iconName: "drop.fill", category: PresetCategory.health.rawValue, @@ -113,7 +113,7 @@ enum RitualPresetLibrary { title: String(localized: "Deep Work Prep"), theme: String(localized: "Set up for focus"), notes: String(localized: "Create the conditions for uninterrupted deep work."), - durationDays: 21, + durationDays: 28, timeOfDay: .morning, iconName: "brain", category: PresetCategory.productivity.rawValue, @@ -143,7 +143,7 @@ enum RitualPresetLibrary { title: String(localized: "Focus Reset"), theme: String(localized: "Regain clarity"), notes: String(localized: "When you feel scattered, use this to refocus."), - durationDays: 14, + durationDays: 28, timeOfDay: .anytime, iconName: "target", category: PresetCategory.productivity.rawValue, @@ -162,7 +162,7 @@ enum RitualPresetLibrary { title: String(localized: "Morning Meditation"), theme: String(localized: "Start with stillness"), notes: String(localized: "A calm mind sets the tone for a calm day."), - durationDays: 30, + durationDays: 28, timeOfDay: .morning, iconName: "figure.mind.and.body", category: PresetCategory.mindfulness.rawValue, @@ -176,7 +176,7 @@ enum RitualPresetLibrary { title: String(localized: "Gratitude Practice"), theme: String(localized: "Find the good"), notes: String(localized: "Shift your focus to what's going well."), - durationDays: 21, + durationDays: 28, timeOfDay: .evening, iconName: "heart.text.square.fill", category: PresetCategory.mindfulness.rawValue, @@ -190,7 +190,7 @@ enum RitualPresetLibrary { title: String(localized: "Breathwork"), theme: String(localized: "Calm your nervous system"), notes: String(localized: "Use breath to reduce stress and increase focus."), - durationDays: 14, + durationDays: 28, timeOfDay: .anytime, iconName: "wind", category: PresetCategory.mindfulness.rawValue, @@ -238,7 +238,7 @@ enum RitualPresetLibrary { title: String(localized: "Digital Detox"), theme: String(localized: "Disconnect to reconnect"), notes: String(localized: "Give your mind a break from screens."), - durationDays: 21, + durationDays: 28, timeOfDay: .evening, iconName: "iphone.slash", category: PresetCategory.selfCare.rawValue, @@ -267,7 +267,7 @@ enum RitualPresetLibrary { title: String(localized: "Weekly Reset"), theme: String(localized: "Prepare for a fresh week"), notes: String(localized: "Sunday evening ritual to start Monday strong."), - durationDays: 12, + durationDays: 28, timeOfDay: .evening, iconName: "arrow.counterclockwise.circle.fill", category: PresetCategory.selfCare.rawValue, diff --git a/Andromida/App/State/RitualStore.swift b/Andromida/App/State/RitualStore.swift index 6a7dae3..38f0ac7 100644 --- a/Andromida/App/State/RitualStore.swift +++ b/Andromida/App/State/RitualStore.swift @@ -31,6 +31,9 @@ final class RitualStore: RitualStoreProviding { /// Ritual that needs renewal prompt (arc just completed) var ritualNeedingRenewal: Ritual? + + /// Rituals that have been dismissed for renewal this session + private var dismissedRenewalRituals: Set = [] init( modelContext: ModelContext, @@ -213,7 +216,7 @@ final class RitualStore: RitualStoreProviding { /// Checks for rituals that need renewal and triggers the prompt. func checkForCompletedArcs() { for ritual in currentRituals { - if isArcCompleted(ritual) { + if isArcCompleted(ritual) && !dismissedRenewalRituals.contains(ritual.persistentModelID) { ritualNeedingRenewal = ritual break } @@ -226,6 +229,9 @@ final class RitualStore: RitualStoreProviding { /// - durationDays: Duration for the new arc (defaults to ritual's default) /// - copyHabits: Whether to copy habits from the previous arc func renewArc(for ritual: Ritual, durationDays: Int? = nil, copyHabits: Bool = true) { + // Clear dismissed status since user is taking action + dismissedRenewalRituals.remove(ritual.persistentModelID) + // Mark current arc as inactive if let currentArc = ritual.currentArc { currentArc.isActive = false @@ -266,6 +272,9 @@ final class RitualStore: RitualStoreProviding { /// Ends a ritual without renewal (marks it as having no active arc). func endArc(for ritual: Ritual) { + // Clear dismissed status since user is taking action + dismissedRenewalRituals.remove(ritual.persistentModelID) + if let currentArc = ritual.currentArc { currentArc.isActive = false saveContext() @@ -274,6 +283,9 @@ final class RitualStore: RitualStoreProviding { /// Dismisses the renewal prompt without taking action. func dismissRenewalPrompt() { + if let ritual = ritualNeedingRenewal { + dismissedRenewalRituals.insert(ritual.persistentModelID) + } ritualNeedingRenewal = nil } @@ -760,6 +772,13 @@ final class RitualStore: RitualStoreProviding { ritual.timeOfDay = timeOfDay ritual.iconName = iconName ritual.category = category + + // Also update the current arc's end date if duration changed + if let currentArc = ritual.currentArc, currentArc.durationDays != durationDays { + let newEndDate = calendar.date(byAdding: .day, value: durationDays - 1, to: currentArc.startDate) ?? currentArc.endDate + currentArc.endDate = newEndDate + } + saveContext() }