Skip to content

Commit eeac75d

Browse files
committed
fix: address PR review feedback for iCloud sync
1 parent 3a77c6d commit eeac75d

9 files changed

Lines changed: 33 additions & 21 deletions

File tree

TablePro.xcodeproj/project.pbxproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1735,7 +1735,7 @@
17351735
AUTOMATION_APPLE_EVENTS = NO;
17361736
CODE_SIGN_ENTITLEMENTS = TablePro/TablePro.entitlements;
17371737
CODE_SIGN_IDENTITY = "Apple Development";
1738-
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
1738+
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "-";
17391739
CODE_SIGN_STYLE = Automatic;
17401740
COPY_PHASE_STRIP = YES;
17411741
CURRENT_PROJECT_VERSION = 33;

TablePro/Core/Storage/AppSettingsStorage.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ final class AppSettingsStorage {
184184
saveTabs(.default)
185185
saveKeyboard(.default)
186186
saveAI(.default)
187+
saveSync(.default)
187188
}
188189

189190
// MARK: - Helpers

TablePro/Core/Storage/ConnectionStorage.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,16 +60,14 @@ final class ConnectionStorage {
6060
} catch {
6161
Self.logger.error("Failed to save connections: \(error)")
6262
}
63-
64-
// Mark all saved connections as dirty for sync
65-
SyncChangeTracker.shared.markDirty(.connection, ids: connections.map { $0.id.uuidString })
6663
}
6764

6865
/// Add a new connection
6966
func addConnection(_ connection: DatabaseConnection, password: String? = nil) {
7067
var connections = loadConnections()
7168
connections.append(connection)
7269
saveConnections(connections)
70+
SyncChangeTracker.shared.markDirty(.connection, id: connection.id.uuidString)
7371

7472
if let password = password, !password.isEmpty {
7573
savePassword(password, for: connection.id)
@@ -82,6 +80,7 @@ final class ConnectionStorage {
8280
if let index = connections.firstIndex(where: { $0.id == connection.id }) {
8381
connections[index] = connection
8482
saveConnections(connections)
83+
SyncChangeTracker.shared.markDirty(.connection, id: connection.id.uuidString)
8584

8685
if let password = password {
8786
if password.isEmpty {
@@ -135,6 +134,7 @@ final class ConnectionStorage {
135134
var connections = loadConnections()
136135
connections.append(duplicate)
137136
saveConnections(connections)
137+
SyncChangeTracker.shared.markDirty(.connection, id: duplicate.id.uuidString)
138138

139139
// Copy all passwords from source to duplicate
140140
if let password = loadPassword(for: connection.id) {

TablePro/Core/Sync/CloudKitSyncEngine.swift

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,15 @@ actor CloudKitSyncEngine {
4848
do {
4949
_ = try await database.save(zone)
5050
Self.logger.trace("Created or confirmed sync zone: \(Self.zoneName)")
51-
} catch let error as CKError where error.code == .serverRejectedRequest {
52-
// Zone already exists, which is fine
53-
Self.logger.trace("Sync zone already exists")
51+
} catch let error as CKError {
52+
// Zone save can fail if zone already exists — that's fine.
53+
// Only re-throw if the error is something else.
54+
let ignorableCodes: Set<CKError.Code> = [.serverRejectedRequest]
55+
if ignorableCodes.contains(error.code) {
56+
Self.logger.trace("Sync zone already exists")
57+
} else {
58+
throw error
59+
}
5460
}
5561
}
5662

TablePro/Core/Sync/SyncChangeTracker.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ final class SyncChangeTracker {
2929
func markDirty(_ type: SyncRecordType, id: String) {
3030
guard !isSuppressed else { return }
3131
metadataStorage.addDirty(type: type, id: id)
32-
print("[Sync] Marked dirty: \(type.rawValue)/\(id)")
32+
Self.logger.info("Marked dirty: \(type.rawValue)/\(id)")
3333
postChangeNotification()
3434
}
3535

TablePro/Core/Sync/SyncCoordinator.swift

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ final class SyncCoordinator {
7474
/// Manual full sync (push then pull)
7575
func syncNow() async {
7676
guard canSync() else {
77-
print("[Sync] syncNow: canSync() returned false, skipping")
77+
Self.logger.info("syncNow: canSync() returned false, skipping")
7878
return
7979
}
8080

@@ -108,14 +108,15 @@ final class SyncCoordinator {
108108

109109
/// Called when user enables sync in settings
110110
func enableSync() {
111-
print("[Sync] enableSync() called")
111+
Self.logger.info("enableSync() called")
112112

113113
// Clear token to force a full fetch on first sync after enabling
114114
metadataStorage.clearSyncToken()
115115

116116
// Mark ALL existing local data as dirty so it gets pushed on first sync
117117
markAllLocalDataDirty()
118-
print("[Sync] enableSync() dirty marking done, dirty connections: \(changeTracker.dirtyRecords(for: .connection))")
118+
let dirtyCount = changeTracker.dirtyRecords(for: .connection).count
119+
Self.logger.info("enableSync() dirty marking done, dirty connections: \(dirtyCount)")
119120

120121
Task {
121122
await checkAccountStatus()
@@ -150,7 +151,7 @@ final class SyncCoordinator {
150151
changeTracker.markDirty(.settings, id: category)
151152
}
152153

153-
print("[Sync] Marked all local data dirty: \(connections.count) connections, \(groups.count) groups, \(tags.count) tags, 8 settings categories")
154+
Self.logger.info("Marked all local data dirty: \(connections.count) connections, \(groups.count) groups, \(tags.count) tags, 8 settings categories")
154155
}
155156

156157
/// Called when user disables sync in settings
@@ -222,7 +223,8 @@ final class SyncCoordinator {
222223
var recordsToSave: [CKRecord] = []
223224
var recordIDsToDelete: [CKRecord.ID] = []
224225
let zoneID = await engine.zoneID
225-
print("[Sync] performPush: syncConnections=\(settings.syncConnections), dirty connections=\(changeTracker.dirtyRecords(for: .connection))")
226+
let dirtyConnectionCount = changeTracker.dirtyRecords(for: .connection).count
227+
Self.logger.info("performPush: syncConnections=\(settings.syncConnections), dirty connections=\(dirtyConnectionCount)")
226228

227229
// Collect dirty connections
228230
if settings.syncConnections {
@@ -281,7 +283,7 @@ final class SyncCoordinator {
281283
}
282284
}
283285

284-
print("[Sync] Push completed: \(recordsToSave.count) saved, \(recordIDsToDelete.count) deleted")
286+
Self.logger.info("Push completed: \(recordsToSave.count) saved, \(recordIDsToDelete.count) deleted")
285287
} catch let error as CKError where error.code == .serverRecordChanged {
286288
Self.logger.warning("Server record changed during push — conflicts detected")
287289
handlePushConflicts(error)
@@ -294,15 +296,16 @@ final class SyncCoordinator {
294296

295297
private func performPull() async {
296298
let token = metadataStorage.loadSyncToken()
297-
print("[Sync] Pull starting, token: \(token == nil ? "nil (full fetch)" : "present (delta)")")
299+
let tokenStatus = token == nil ? "nil (full fetch)" : "present (delta)"
300+
Self.logger.info("Pull starting, token: \(tokenStatus)")
298301

299302
do {
300303
let result = try await engine.pull(since: token)
301304

302-
print("[Sync] Pull fetched: \(result.changedRecords.count) changed, \(result.deletedRecordIDs.count) deleted")
305+
Self.logger.info("Pull fetched: \(result.changedRecords.count) changed, \(result.deletedRecordIDs.count) deleted")
303306

304307
for record in result.changedRecords {
305-
print("[Sync] Pulled record: \(record.recordType)/\(record.recordID.recordName)")
308+
Self.logger.info("Pulled record: \(record.recordType)/\(record.recordID.recordName)")
306309
}
307310

308311
if let newToken = result.newToken {
@@ -581,7 +584,6 @@ final class SyncCoordinator {
581584
}
582585

583586
private func applySettingsData(_ data: Data, for category: String) {
584-
let storage = AppSettingsStorage.shared
585587
let manager = AppSettingsManager.shared
586588
let decoder = JSONDecoder()
587589

TablePro/Core/Sync/SyncRecordMapper.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ struct SyncRecordMapper {
104104
}
105105

106106
let host = record["host"] as? String ?? "localhost"
107-
let port = (record["port"] as? Int64).map { Int($0) } ?? 3_306
107+
let port = (record["port"] as? Int64).map { Int($0) } ?? 0
108108
let database = record["database"] as? String ?? ""
109109
let username = record["username"] as? String ?? ""
110110
let colorRaw = record["color"] as? String ?? ConnectionColor.none.rawValue

TablePro/Models/Settings/ProFeature.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import Foundation
99

1010
/// Features that require a Pro (active) license
11-
enum ProFeature: String, CaseIterable {
11+
internal enum ProFeature: String, CaseIterable {
1212
case iCloudSync
1313

1414
var displayName: String {
@@ -34,7 +34,7 @@ enum ProFeature: String, CaseIterable {
3434
}
3535

3636
/// Result of checking Pro feature availability
37-
enum ProFeatureAccess {
37+
internal enum ProFeatureAccess {
3838
case available
3939
case unlicensed
4040
case expired

TablePro/Views/Connection/ConnectionFormView.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,13 +1025,15 @@ struct ConnectionFormView: View { // swiftlint:disable:this type_body_length
10251025
if isNew {
10261026
savedConnections.append(connectionToSave)
10271027
storage.saveConnections(savedConnections)
1028+
SyncChangeTracker.shared.markDirty(.connection, id: connectionToSave.id.uuidString)
10281029
// Close and connect to database
10291030
NSApplication.shared.closeWindows(withId: "connection-form")
10301031
connectToDatabase(connectionToSave)
10311032
} else {
10321033
if let index = savedConnections.firstIndex(where: { $0.id == connectionToSave.id }) {
10331034
savedConnections[index] = connectionToSave
10341035
storage.saveConnections(savedConnections)
1036+
SyncChangeTracker.shared.markDirty(.connection, id: connectionToSave.id.uuidString)
10351037
}
10361038
NSApplication.shared.closeWindows(withId: "connection-form")
10371039
NotificationCenter.default.post(name: .connectionUpdated, object: nil)
@@ -1040,6 +1042,7 @@ struct ConnectionFormView: View { // swiftlint:disable:this type_body_length
10401042

10411043
private func deleteConnection() {
10421044
guard let id = connectionId else { return }
1045+
SyncChangeTracker.shared.markDeleted(.connection, id: id.uuidString)
10431046
var savedConnections = storage.loadConnections()
10441047
savedConnections.removeAll { $0.id == id }
10451048
storage.saveConnections(savedConnections)

0 commit comments

Comments
 (0)