From 285e91a4296858e4d13d611f5879e5093c5c171a Mon Sep 17 00:00:00 2001 From: Hendrik Hogertz Date: Sun, 15 Feb 2026 11:54:13 +0100 Subject: [PATCH] Fix meal plan removal ignored on first attempt after app launch Guard reconcileFromServer() with a syncStartTime so that entries modified locally during an active performSync() cycle are never overwritten by stale server data. This prevents the race condition where a user removes a meal plan entry while Phase 2 of sync is still iterating server recipes. Co-Authored-By: Claude Sonnet 4.5 --- Nextcloud Cookbook iOS Client/Data/MealPlanManager.swift | 8 ++++++++ .../Data/MealPlanSyncManager.swift | 3 +++ 2 files changed, 11 insertions(+) diff --git a/Nextcloud Cookbook iOS Client/Data/MealPlanManager.swift b/Nextcloud Cookbook iOS Client/Data/MealPlanManager.swift index 3f6ab50..0115e07 100644 --- a/Nextcloud Cookbook iOS Client/Data/MealPlanManager.swift +++ b/Nextcloud Cookbook iOS Client/Data/MealPlanManager.swift @@ -14,6 +14,7 @@ class MealPlanManager: ObservableObject { private var recipeNames: [String: String] = [:] private let dataStore = DataStore() var syncManager: MealPlanSyncManager? + var syncStartTime: String? private static let persistencePath = "meal_plan.data" @@ -128,6 +129,13 @@ class MealPlanManager: ObservableObject { for (dayStr, serverEntry) in serverAssignment.dates { if let localEntry = local.dates[dayStr] { + // Skip entries modified locally during this sync cycle + if let syncStart = syncStartTime, + let syncStartDate = MealPlanDate.date(from: syncStart), + let localModDate = MealPlanDate.date(from: localEntry.modifiedAt), + localModDate >= syncStartDate { + continue + } let localDate = MealPlanDate.date(from: localEntry.modifiedAt) ?? .distantPast let serverDate = MealPlanDate.date(from: serverEntry.modifiedAt) ?? .distantPast if serverDate > localDate { diff --git a/Nextcloud Cookbook iOS Client/Data/MealPlanSyncManager.swift b/Nextcloud Cookbook iOS Client/Data/MealPlanSyncManager.swift index 57525a1..f50b8b2 100644 --- a/Nextcloud Cookbook iOS Client/Data/MealPlanSyncManager.swift +++ b/Nextcloud Cookbook iOS Client/Data/MealPlanSyncManager.swift @@ -65,6 +65,9 @@ class MealPlanSyncManager { func performSync() async { guard let appState, let mealPlanManager else { return } + mealPlanManager.syncStartTime = MealPlanDate.now() + defer { mealPlanManager.syncStartTime = nil } + // Phase 1: Push locally-known meal plan state let localRecipeIds = Array(Set( mealPlanManager.entriesByDate.values.flatMap { $0 }.map(\.recipeId)