Fixed major issue with sync logic. Should be stable now. Solidified with
tests... turns out syncing is hard...
This commit is contained in:
@@ -465,11 +465,25 @@ class SyncService: ObservableObject {
|
||||
imagePathMapping: [String: String] = [:]
|
||||
) throws {
|
||||
do {
|
||||
// Store active sessions and their attempts before import
|
||||
let activeSessions = dataManager.sessions.filter { $0.status == .active }
|
||||
// Store active sessions and their attempts before import (but exclude any that were deleted)
|
||||
let localDeletedItems = dataManager.getDeletedItems()
|
||||
let allDeletedSessionIds = Set(
|
||||
(backup.deletedItems + localDeletedItems)
|
||||
.filter { $0.type == "session" }
|
||||
.map { $0.id }
|
||||
)
|
||||
let activeSessions = dataManager.sessions.filter {
|
||||
$0.status == .active && !allDeletedSessionIds.contains($0.id.uuidString)
|
||||
}
|
||||
let activeSessionIds = Set(activeSessions.map { $0.id })
|
||||
let allDeletedAttemptIds = Set(
|
||||
(backup.deletedItems + localDeletedItems)
|
||||
.filter { $0.type == "attempt" }
|
||||
.map { $0.id }
|
||||
)
|
||||
let activeAttempts = dataManager.attempts.filter {
|
||||
activeSessionIds.contains($0.sessionId)
|
||||
&& !allDeletedAttemptIds.contains($0.id.uuidString)
|
||||
}
|
||||
|
||||
print(
|
||||
@@ -500,18 +514,58 @@ class SyncService: ObservableObject {
|
||||
updatedAt: problem.updatedAt
|
||||
)
|
||||
}
|
||||
// Filter out deleted items before creating updated backup
|
||||
let deletedGymIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "gym" }.map { $0.id })
|
||||
let deletedProblemIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "problem" }.map { $0.id })
|
||||
let deletedSessionIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "session" }.map { $0.id })
|
||||
let deletedAttemptIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "attempt" }.map { $0.id })
|
||||
|
||||
let filteredGyms = backup.gyms.filter { !deletedGymIds.contains($0.id) }
|
||||
let filteredProblems = updatedProblems.filter { !deletedProblemIds.contains($0.id) }
|
||||
let filteredSessions = backup.sessions.filter { !deletedSessionIds.contains($0.id) }
|
||||
let filteredAttempts = backup.attempts.filter { !deletedAttemptIds.contains($0.id) }
|
||||
|
||||
updatedBackup = ClimbDataBackup(
|
||||
exportedAt: backup.exportedAt,
|
||||
version: backup.version,
|
||||
formatVersion: backup.formatVersion,
|
||||
gyms: backup.gyms,
|
||||
problems: updatedProblems,
|
||||
sessions: backup.sessions,
|
||||
attempts: backup.attempts
|
||||
gyms: filteredGyms,
|
||||
problems: filteredProblems,
|
||||
sessions: filteredSessions,
|
||||
attempts: filteredAttempts,
|
||||
deletedItems: backup.deletedItems
|
||||
)
|
||||
|
||||
} else {
|
||||
updatedBackup = backup
|
||||
// Filter out deleted items even when no image path mapping
|
||||
let deletedGymIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "gym" }.map { $0.id })
|
||||
let deletedProblemIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "problem" }.map { $0.id })
|
||||
let deletedSessionIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "session" }.map { $0.id })
|
||||
let deletedAttemptIds = Set(
|
||||
backup.deletedItems.filter { $0.type == "attempt" }.map { $0.id })
|
||||
|
||||
let filteredGyms = backup.gyms.filter { !deletedGymIds.contains($0.id) }
|
||||
let filteredProblems = backup.problems.filter { !deletedProblemIds.contains($0.id) }
|
||||
let filteredSessions = backup.sessions.filter { !deletedSessionIds.contains($0.id) }
|
||||
let filteredAttempts = backup.attempts.filter { !deletedAttemptIds.contains($0.id) }
|
||||
|
||||
updatedBackup = ClimbDataBackup(
|
||||
exportedAt: backup.exportedAt,
|
||||
version: backup.version,
|
||||
formatVersion: backup.formatVersion,
|
||||
gyms: filteredGyms,
|
||||
problems: filteredProblems,
|
||||
sessions: filteredSessions,
|
||||
attempts: filteredAttempts,
|
||||
deletedItems: backup.deletedItems
|
||||
)
|
||||
}
|
||||
|
||||
// Create a minimal ZIP with just the JSON data for existing import mechanism
|
||||
@@ -538,6 +592,13 @@ class SyncService: ObservableObject {
|
||||
dataManager.saveAttempts()
|
||||
dataManager.saveActiveSession()
|
||||
|
||||
// Import deletion records to prevent future resurrections
|
||||
dataManager.clearDeletedItems()
|
||||
if let data = try? JSONEncoder().encode(backup.deletedItems) {
|
||||
UserDefaults.standard.set(data, forKey: "openclimb_deleted_items")
|
||||
print("iOS IMPORT: Imported \(backup.deletedItems.count) deletion records")
|
||||
}
|
||||
|
||||
// Update local data state to match imported data timestamp
|
||||
DataStateManager.shared.setLastModified(backup.exportedAt)
|
||||
print("Data state synchronized to imported timestamp: \(backup.exportedAt)")
|
||||
|
||||
Reference in New Issue
Block a user