Fixed major issue with sync logic. Should be stable now. Solidified with

tests... turns out syncing is hard...
This commit is contained in:
2025-10-06 18:04:56 -06:00
parent a19ff8ef66
commit 603a683ab2
4 changed files with 172 additions and 49 deletions

View File

@@ -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)")