@@ -238,33 +238,15 @@ class ImportExportSettingsViewModel: ObservableObject {
238238 exportedAlarmIds. removeAll ( )
239239 }
240240
241- // MARK: - iCloud Methods (using CloudKit )
241+ // MARK: - iCloud Methods (using Key-Value Storage )
242242
243- private let cloudKitRecordType = " AppSettings "
244- private var cloudKitRecordID : CKRecord . ID {
245- CKRecord . ID ( recordName: " \( AppConstants . appInstanceId) _settings " )
243+ private var iCloudSettingsKey : String {
244+ " \( AppConstants . appInstanceId) _settings "
246245 }
247246
248- /// Check if CloudKit is available
249- private func checkCloudKitAvailability( completion: @escaping ( Bool , String ? ) -> Void ) {
250- CKContainer . default ( ) . accountStatus { status, error in
251- DispatchQueue . main. async {
252- switch status {
253- case . available:
254- completion ( true , nil )
255- case . noAccount:
256- completion ( false , " iCloud is not available. Please sign in to iCloud in Settings. " )
257- case . restricted:
258- completion ( false , " iCloud access is restricted on this device. " )
259- case . couldNotDetermine:
260- completion ( false , " Could not determine iCloud status: \( error? . localizedDescription ?? " Unknown error " ) " )
261- case . temporarilyUnavailable:
262- completion ( false , " iCloud is temporarily unavailable. Please try again later. " )
263- @unknown default :
264- completion ( false , " Unknown iCloud status. " )
265- }
266- }
267- }
247+ /// Check if iCloud Key-Value Storage is available
248+ private func isICloudAvailable( ) -> Bool {
249+ return FileManager . default. ubiquityIdentityToken != nil
268250 }
269251
270252 func exportToiCloud( ) {
@@ -287,130 +269,86 @@ class ImportExportSettingsViewModel: ObservableObject {
287269 return
288270 }
289271
290- LogManager . shared. log ( category: . general, message: " Attempting to export settings to CloudKit " )
272+ guard isICloudAvailable ( ) else {
273+ qrCodeErrorMessage = " iCloud is not available. Please sign in to iCloud in Settings. "
274+ LogManager . shared. log ( category: . general, message: " iCloud not available for export " )
275+ return
276+ }
291277
292- checkCloudKitAvailability { [ weak self] available, errorMessage in
293- guard let self = self else { return }
278+ LogManager . shared. log ( category: . general, message: " Attempting to export settings to iCloud Key-Value Storage " )
294279
295- if !available {
296- self . qrCodeErrorMessage = errorMessage ?? " iCloud is not available. "
297- LogManager . shared. log ( category: . general, message: " CloudKit not available: \( errorMessage ?? " Unknown " ) " )
298- return
299- }
280+ let store = NSUbiquitousKeyValueStore . default
281+ store. set ( jsonString, forKey: iCloudSettingsKey)
282+ store. set ( Date ( ) , forKey: " \( iCloudSettingsKey) _date " )
283+ store. set ( AppVersionManager ( ) . version ( ) , forKey: " \( iCloudSettingsKey) _version " )
300284
301- let privateDatabase = CKContainer . default ( ) . privateCloudDatabase
285+ // Explicitly synchronize to push changes
286+ let synchronized = store. synchronize ( )
287+ LogManager . shared. log ( category: . general, message: " iCloud KVS synchronize called, result: \( synchronized) " )
302288
303- // First try to fetch existing record to update it, or create new one
304- privateDatabase. fetch ( withRecordID: self . cloudKitRecordID) { [ weak self] existingRecord, error in
305- guard let self = self else { return }
289+ // Build export details for the success alert
290+ var details : [ String ] = [ ]
306291
307- let record : CKRecord
308- if let existing = existingRecord {
309- record = existing
310- } else {
311- record = CKRecord ( recordType: self . cloudKitRecordType, recordID: self . cloudKitRecordID)
312- }
313-
314- record [ " settingsJSON " ] = jsonString as CKRecordValue
315- record [ " exportDate " ] = Date ( ) as CKRecordValue
316- record [ " appVersion " ] = AppVersionManager ( ) . version ( ) as CKRecordValue
317-
318- privateDatabase. save ( record) { [ weak self] _, saveError in
319- DispatchQueue . main. async {
320- guard let self = self else { return }
321-
322- if let saveError = saveError {
323- self . qrCodeErrorMessage = " Failed to export to iCloud: \( saveError. localizedDescription) "
324- LogManager . shared. log ( category: . general, message: " CloudKit save failed: \( saveError. localizedDescription) " )
325- return
326- }
327-
328- // Build export details for the success alert
329- var details : [ String ] = [ ]
330-
331- if !nightscoutSettings. url. isEmpty {
332- details. append ( " Nightscout: \( nightscoutSettings. url) " )
333- }
334- if !dexcomSettings. userName. isEmpty {
335- details. append ( " Dexcom: \( dexcomSettings. userName) " )
336- }
337- if remoteSettings. remoteType != . none {
338- details. append ( " Remote: \( remoteSettings. remoteType. rawValue) " )
339- }
340- if !alarmSettings. alarms. isEmpty {
341- details. append ( " Alarms: \( alarmSettings. alarms. count) alarm(s) " )
342- }
343-
344- self . exportSuccessDetails = details
345- self . exportSuccessMessage = " Settings saved to iCloud "
346- self . showExportSuccessAlert = true
347- self . qrCodeErrorMessage = " "
348-
349- LogManager . shared. log ( category: . general, message: " All settings exported to CloudKit successfully " )
350- }
351- }
352- }
292+ if !nightscoutSettings. url. isEmpty {
293+ details. append ( " Nightscout: \( nightscoutSettings. url) " )
294+ }
295+ if !dexcomSettings. userName. isEmpty {
296+ details. append ( " Dexcom: \( dexcomSettings. userName) " )
353297 }
298+ if remoteSettings. remoteType != . none {
299+ details. append ( " Remote: \( remoteSettings. remoteType. rawValue) " )
300+ }
301+ if !alarmSettings. alarms. isEmpty {
302+ details. append ( " Alarms: \( alarmSettings. alarms. count) alarm(s) " )
303+ }
304+
305+ exportSuccessDetails = details
306+ exportSuccessMessage = " Settings saved to iCloud "
307+ showExportSuccessAlert = true
308+ qrCodeErrorMessage = " "
309+
310+ LogManager . shared. log ( category: . general, message: " All settings exported to iCloud Key-Value Storage successfully " )
354311 }
355312
356313 func importFromiCloud( ) {
357- LogManager . shared. log ( category: . general, message: " Attempting to import settings from CloudKit " )
314+ LogManager . shared. log ( category: . general, message: " Attempting to import settings from iCloud Key-Value Storage " )
358315
359- checkCloudKitAvailability { [ weak self] available, errorMessage in
360- guard let self = self else { return }
316+ guard isICloudAvailable ( ) else {
317+ importNotFoundMessage = " iCloud is not available. \n \n Please sign in to iCloud in Settings. "
318+ showImportNotFoundAlert = true
319+ LogManager . shared. log ( category: . general, message: " iCloud not available for import " )
320+ return
321+ }
361322
362- if !available {
363- self . importNotFoundMessage = errorMessage ?? " iCloud is not available. "
364- self . showImportNotFoundAlert = true
365- LogManager . shared. log ( category: . general, message: " CloudKit not available for import: \( errorMessage ?? " Unknown " ) " )
366- return
367- }
323+ let store = NSUbiquitousKeyValueStore . default
368324
369- let privateDatabase = CKContainer . default ( ) . privateCloudDatabase
370-
371- privateDatabase. fetch ( withRecordID: self . cloudKitRecordID) { [ weak self] record, error in
372- DispatchQueue . main. async {
373- guard let self = self else { return }
374-
375- if let error = error {
376- if let ckError = error as? CKError , ckError. code == . unknownItem {
377- self . importNotFoundMessage = " No settings file found in iCloud. \n \n Make sure you have previously exported settings to iCloud from this app. "
378- self . showImportNotFoundAlert = true
379- LogManager . shared. log ( category: . general, message: " No CloudKit record found " )
380- } else {
381- self . qrCodeErrorMessage = " Failed to import from iCloud: \( error. localizedDescription) "
382- LogManager . shared. log ( category: . general, message: " CloudKit fetch failed: \( error. localizedDescription) " )
383- }
384- return
385- }
386-
387- guard let record = record,
388- let jsonString = record [ " settingsJSON " ] as? String ,
389- let jsonData = jsonString. data ( using: . utf8) else {
390- self . importNotFoundMessage = " No settings file found in iCloud. \n \n Make sure you have previously exported settings to iCloud from this app. "
391- self . showImportNotFoundAlert = true
392- return
393- }
394-
395- LogManager . shared. log ( category: . general, message: " Settings record found in CloudKit, attempting to decode " )
396-
397- guard let settings = SettingsMigrationManager . migrateSettings ( jsonData) else {
398- self . qrCodeErrorMessage = " Failed to decode settings from iCloud "
399- return
400- }
401-
402- // Check version compatibility
403- if !SettingsMigrationManager. isCompatibleVersion ( settings. appVersion) {
404- self . qrCodeErrorMessage = SettingsMigrationManager . getCompatibilityMessage ( for: settings. appVersion)
405- }
406-
407- // Store settings and create preview for confirmation
408- self . pendingImportSettings = settings
409- self . pendingImportSource = " iCloud "
410- self . createImportPreview ( from: settings)
411- }
412- }
325+ // Synchronize to get latest from iCloud
326+ store. synchronize ( )
327+
328+ guard let jsonString = store. string ( forKey: iCloudSettingsKey) ,
329+ let jsonData = jsonString. data ( using: . utf8) else {
330+ importNotFoundMessage = " No settings file found in iCloud. \n \n Make sure you have previously exported settings to iCloud from this app. "
331+ showImportNotFoundAlert = true
332+ LogManager . shared. log ( category: . general, message: " No settings found in iCloud Key-Value Storage " )
333+ return
334+ }
335+
336+ LogManager . shared. log ( category: . general, message: " Settings found in iCloud Key-Value Storage, attempting to decode " )
337+
338+ guard let settings = SettingsMigrationManager . migrateSettings ( jsonData) else {
339+ qrCodeErrorMessage = " Failed to decode settings from iCloud "
340+ return
341+ }
342+
343+ // Check version compatibility
344+ if !SettingsMigrationManager. isCompatibleVersion ( settings. appVersion) {
345+ qrCodeErrorMessage = SettingsMigrationManager . getCompatibilityMessage ( for: settings. appVersion)
413346 }
347+
348+ // Store settings and create preview for confirmation
349+ pendingImportSettings = settings
350+ pendingImportSource = " iCloud "
351+ createImportPreview ( from: settings)
414352 }
415353
416354 private func createImportPreview( from settings: CombinedSettingsExport ) {
0 commit comments