Screen recordings are videos captured by iOS screen recording and are
almost never wanted in a photo backup. They are now excluded from all
counts and backup queues unless explicitly enabled.
Changes:
- BackupFilter.includeScreenRecordings (default: false) added
- PHAssetMediaSubtype.videoScreenRecording predicate applied in both
fetchAssets() and fetchResultForReconciliation() — excluded at the
PHFetchRequest level before enumeration
- LocalPhotoIndex.Record.isScreenRecording populated via makeRecord()
so the fast-path countSafe/count also respects the toggle
- LocalPhotoIndex.passes() checks includeScreenRecordings
- Settings "Screen Recordings" toggle added below Screenshots
This also resolves the transient count flash: screen recordings were
being included in the "need backup" tally on the initial fast-path
reconcile, then dropping when the filter was fully applied.
Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>
Replace full [PhotoAsset] array enumeration with PHFetchResult batch
enumeration (autoreleasepool + Task.yield per batch) to keep memory
bounded during reconciliation. Introduce ManifestIndex with two O(1)
Set<String> lookups (localIdentifier + lowercased filename) instead of
O(n×m) linear scans. Scope manifest Data+struct inside buildManifestIndex
so they are released by ARC before the comparison loop begins. Add
UIApplication.didReceiveMemoryWarningNotification handler to cancel
in-flight tasks under memory pressure. Separate debounceTask from
refreshTask to avoid cancelling long-running reconciles on every photo
library event. fetchResultForReconciliation returns PHFetchResult
directly — no [PhotoAsset] array is ever allocated during reconciliation.
Co-Authored-By: Kutesir <kutesir@provoc.ug>
Co-Authored-By: Sentry <sentry@provoc.ug>
- Rename app to Kisani in all UI text and Face ID prompt
- Replace flat 2-state RootView with 5-step flow: ConnectView →
LoginView → FolderSetupView → PhotoPermissionView → MainTabView
- Remove NavigationStack from LoginView (was causing nested-stack crash);
drive navigation via ConnectionStore.isSessionActive
- Add FolderSetupView and PhotoPermissionView onboarding screens with
step indicator (2/3, 3/3), spring entrance animations, and UGreen
connection chip
- Fix dark mode button invisibility: PrimaryButtonStyle and PillButtonStyle
now use AppTheme.inkInverse; GhostButtonStyle border uses ink.opacity(0.25)
- Add AppTheme.inkInverse adaptive token (dark bg ink on dark, white on light)
- Add ConnectionStore.isSessionActive (non-persisted) and
onboardingPhotoShown (UserDefaults-persisted)
- Add os_log logging in LoginViewModel at auth start/success/failure
- Remove dead Help button from ConnectView
- UGreenCompatibilityBadge, KeychainStore, SavedConnections, extensions,
PrivacyInfo.xcprivacy, unit test target and test stubs
- AppTheme: full UIColor dynamic provider tokens for dark/light adaptive color
- AppearanceMode enum + segmented picker in SettingsView
- BackupView: enlarged ring, removed options card and linear progress bar
- HistoryView: duration and bytes formatting, improved typography hierarchy
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>