1.6.0 #9: auto-backup programado a iCloud Drive/Archivos

El BackupService (export JSON v3 lossless a local + iCloud ubiquity, retención,
restore, premium-gated) ya existía de 1.1.0 pero solo era manual. Añadido lo automático:
- BackupService.runScheduledBackupIfNeeded() (config vía UserDefaults, gate por
  backupsEnabled+premium, respeta frecuencia).
- Disparo en foreground (scenePhase .active) en background queue.
- Frecuencia Off/Diario/Semanal/Mensual + fecha del último backup en Settings
  (SettingsViewModel.autoBackupFrequencyDays + updateAutoBackupFrequency).
- Strings en 7 idiomas.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L2p3gUZRNWW388rWFRjiU7
This commit is contained in:
alexandrev-tibco
2026-07-25 17:31:53 +02:00
parent 6887d05b01
commit 648c2bd805
11 changed files with 121 additions and 0 deletions
@@ -85,6 +85,30 @@ class BackupService {
return records.sorted { $0.date > $1.date }
}
/// Runs an automatic backup if auto-backup is enabled and the configured
/// interval has elapsed since the last one. Call on app foreground. Reads its
/// config from UserDefaults so it needs no coupling to the Settings VM. The
/// backup content is the lossless JSON v3 export (goals, contributions, journal).
@discardableResult
func runScheduledBackupIfNeeded() -> Bool {
let d = UserDefaults.standard
// `backupsEnabled` is only settable by Premium users, so it also gates this.
guard d.bool(forKey: "backupsEnabled") else { return false }
let frequencyDays = d.integer(forKey: "autoBackupFrequencyDays") // 0 = off
guard frequencyDays > 0 else { return false }
if let last = d.object(forKey: "lastAutoBackupDate") as? Date,
dateProvider().timeIntervalSince(last) < Double(frequencyDays) * 86_400 {
return false
}
let retention = (d.object(forKey: "backupRetentionCount") as? Int) ?? 10
let includeICloud = d.bool(forKey: "cloudSyncEnabled")
_ = createBackup(retentionCount: retention, includeICloud: includeICloud)
d.set(dateProvider(), forKey: "lastAutoBackupDate")
return true
}
func listAllBackups(includeICloud: Bool) -> [BackupRecord] {
var records: [BackupRecord] = []
if let localDir = backupDirectory() {