Add cross-device grocery list sync via Nextcloud Cookbook API
Store a _groceryState JSON field on each recipe to track which ingredients have been added, completed, or removed. Uses per-item last-writer-wins conflict resolution with ISO 8601 timestamps. Debounced push (2s) avoids excessive API calls; pull reconciles on recipe open and app launch. Includes a settings toggle to enable/disable sync. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -81,6 +81,10 @@ struct MainView: View {
|
||||
}
|
||||
}
|
||||
await groceryList.load()
|
||||
groceryList.configureSyncManager(appState: appState)
|
||||
if UserSettings.shared.grocerySyncEnabled {
|
||||
await groceryList.syncManager?.performInitialSync()
|
||||
}
|
||||
recipeViewModel.presentLoadingIndicator = false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import SwiftUI
|
||||
|
||||
struct RecipeView: View {
|
||||
@EnvironmentObject var appState: AppState
|
||||
@EnvironmentObject var groceryList: GroceryListManager
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@StateObject var viewModel: ViewModel
|
||||
@GestureState private var dragOffset = CGSize.zero
|
||||
@@ -75,6 +76,15 @@ struct RecipeView: View {
|
||||
fetchMode: UserSettings.shared.storeImages ? .preferLocal : .onlyServer
|
||||
)
|
||||
|
||||
// Reconcile server grocery state with local data
|
||||
if UserSettings.shared.grocerySyncEnabled {
|
||||
groceryList.syncManager?.reconcileFromServer(
|
||||
serverState: viewModel.recipeDetail.groceryState,
|
||||
recipeId: String(viewModel.recipe.recipe_id),
|
||||
recipeName: viewModel.recipeDetail.name
|
||||
)
|
||||
}
|
||||
|
||||
} else {
|
||||
// Prepare view for a new recipe
|
||||
if let preloaded = viewModel.preloadedRecipeDetail {
|
||||
|
||||
@@ -93,10 +93,16 @@ struct SettingsView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Toggle(isOn: $userSettings.grocerySyncEnabled) {
|
||||
Text("Sync grocery list across devices")
|
||||
}
|
||||
} header: {
|
||||
Text("Grocery List")
|
||||
} footer: {
|
||||
if userSettings.groceryListMode == GroceryListMode.appleReminders.rawValue {
|
||||
if userSettings.grocerySyncEnabled {
|
||||
Text("Grocery list state is synced via your Nextcloud server by storing it alongside recipe data.")
|
||||
} else if userSettings.groceryListMode == GroceryListMode.appleReminders.rawValue {
|
||||
Text("Grocery items will be saved to Apple Reminders. The Grocery List tab will be hidden since you can manage items directly in the Reminders app.")
|
||||
} else {
|
||||
Text("Grocery items are stored locally on this device.")
|
||||
|
||||
Reference in New Issue
Block a user