Add IndieAbout + IndieBackup, TestFlight release pipeline
IndieAbout: About section in iOS Settings and macOS About window; LICENSE
switched to the portfolio-standard ISC text (reflowed for in-app rendering).
IndieBackup: files-only backup/restore of the iCloud container documents
('.notesbackup' document type on both platforms), SwiftData cache rebuilt
via SyncEngine.rebuildCache() after restore, monitors suspended during the
file swap, onOpenURL import with pre-launch queueing.
Release pipeline: Scripts/release.sh (ios|mac|all) archives and uploads via
xcodebuild + ASC API key; platform-partitioned build numbers (iOS even,
macOS odd) since both targets share one bundle ID and build sequence.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import Foundation
|
||||
import IndieBackup
|
||||
|
||||
/// Backup configuration for IndieBackup (files-only).
|
||||
///
|
||||
/// IndieBackup backs up the entire iCloud container `Documents` folder
|
||||
/// (`backupRoot`, the package default) — exactly where the source of truth
|
||||
/// lives (`Records/`, `Stubs/`). The SwiftData cache is rebuildable and not
|
||||
/// part of the backup; it's regenerated from the restored files via
|
||||
/// `rebuildCacheAfterRestore`.
|
||||
struct NotesBackupConfiguration: BackupConfiguration {
|
||||
/// The sync engine whose observers are suspended during restore and whose
|
||||
/// cache is rebuilt afterwards.
|
||||
let syncEngine: SyncEngine
|
||||
|
||||
var backupFileExtension: String { "notesbackup" }
|
||||
var backupDisplayName: String { "Notes Backup" }
|
||||
|
||||
/// Suspend the metadata observers for the whole restore so the bulk file
|
||||
/// replacement isn't processed as a flood of live sync events.
|
||||
func prepareForRestore() async {
|
||||
await syncEngine.suspendForRestore()
|
||||
}
|
||||
|
||||
/// Restart fresh observers once the restored files have settled — a new
|
||||
/// NSMetadataQuery re-baselines on gather, so nothing replays.
|
||||
func finishRestore() async {
|
||||
await syncEngine.resumeAfterRestore()
|
||||
}
|
||||
|
||||
/// Rebuild the SwiftData cache so it exactly mirrors the restored files.
|
||||
func rebuildCacheAfterRestore(progress: @escaping (Double, String) -> Void) async throws {
|
||||
progress(0.0, "Rebuilding notes…")
|
||||
await syncEngine.rebuildCache()
|
||||
progress(1.0, "Rebuilt")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user