Add Recently Deleted + screenshot sizes to cleanup page
- loadCleanupData() fetches Recently Deleted (by title) and Screenshots smart albums, estimates GB from asset counts - Page 2 breakdown adds Recently Deleted row (red) and uses real screenshotsGB value; reordered: backed-up, deleted, screenshots, duplicates, large videos - totalFreeableGB includes backed-up + deleted + screenshots - Clean sheet adds toggleable Recently Deleted row with trash icon; unchecked by default, turns red when selected Co-Authored-By: Kutesir <kutesir@provoc.ug> Co-Authored-By: Sentry <sentry@provoc.ug>
This commit is contained in:
@@ -23,6 +23,9 @@ struct BackupView: View {
|
||||
@State private var showCleanConfirm = false
|
||||
@State private var showCleanSheet = false
|
||||
@State private var cleanScreenshotDays: Int? = nil
|
||||
@State private var cleanDeletedPhotos: Bool = false
|
||||
@State private var deletedPhotosGB: Double = 0
|
||||
@State private var screenshotsGB: Double = 0
|
||||
@State private var pullProgress: CGFloat = 0
|
||||
@State private var rippleScale: CGFloat = 0.88
|
||||
@State private var rippleOpacity: Double = 0
|
||||
@@ -124,6 +127,7 @@ struct BackupView: View {
|
||||
.task {
|
||||
coordinator.onActive()
|
||||
loadDeviceStorage()
|
||||
loadCleanupData()
|
||||
}
|
||||
.onChange(of: scenePhase) { phase in
|
||||
// Re-check every time the app returns to the foreground.
|
||||
@@ -857,7 +861,26 @@ struct BackupView: View {
|
||||
private var usedFraction: CGFloat { CGFloat(deviceUsedGB / max(1, deviceTotalGB)) }
|
||||
private var safeFraction: CGFloat { CGFloat(min(junkGB, deviceTotalGB) / max(1, deviceTotalGB)) }
|
||||
private var backedUpPhotosGB: Double { Double(alreadySafeDisplayCount) * 3.5 / 1000 }
|
||||
private var totalFreeableGB: Double { backedUpPhotosGB }
|
||||
private var totalFreeableGB: Double { backedUpPhotosGB + deletedPhotosGB + screenshotsGB }
|
||||
|
||||
private func loadCleanupData() {
|
||||
// Recently Deleted — fetch by title since the subtype isn't public
|
||||
let delOpts = PHFetchOptions()
|
||||
delOpts.predicate = NSPredicate(format: "localizedTitle = 'Recently Deleted'")
|
||||
let delCollections = PHAssetCollection.fetchAssetCollections(
|
||||
with: .smartAlbum, subtype: .any, options: delOpts)
|
||||
if let col = delCollections.firstObject {
|
||||
let assets = PHAsset.fetchAssets(in: col, options: nil)
|
||||
deletedPhotosGB = Double(assets.count) * 3.5 / 1000
|
||||
}
|
||||
// Screenshots
|
||||
let ssCollections = PHAssetCollection.fetchAssetCollections(
|
||||
with: .smartAlbum, subtype: .smartAlbumScreenshots, options: nil)
|
||||
if let col = ssCollections.firstObject {
|
||||
let assets = PHAsset.fetchAssets(in: col, options: nil)
|
||||
screenshotsGB = Double(assets.count) * 1.5 / 1000
|
||||
}
|
||||
}
|
||||
|
||||
private func loadDeviceStorage() {
|
||||
let attrs = try? FileManager.default.attributesOfFileSystem(forPath: NSHomeDirectory())
|
||||
@@ -905,11 +928,13 @@ struct BackupView: View {
|
||||
VStack(spacing: 0) {
|
||||
cleanupRow(label: "Backed-up photos", sizeGB: backedUpPhotosGB, color: AppTheme.positive)
|
||||
Divider().opacity(0.25).padding(.leading, AppTheme.hPad)
|
||||
cleanupRow(label: "Duplicates", sizeGB: 0, color: AppTheme.interactive)
|
||||
cleanupRow(label: "Recently Deleted", sizeGB: deletedPhotosGB, color: AppTheme.destructive)
|
||||
Divider().opacity(0.25).padding(.leading, AppTheme.hPad)
|
||||
cleanupRow(label: "Screenshots", sizeGB: 0,
|
||||
cleanupRow(label: "Screenshots", sizeGB: screenshotsGB,
|
||||
color: Color(red: 1.0, green: 0.58, blue: 0.0))
|
||||
Divider().opacity(0.25).padding(.leading, AppTheme.hPad)
|
||||
cleanupRow(label: "Duplicates", sizeGB: 0, color: AppTheme.interactive)
|
||||
Divider().opacity(0.25).padding(.leading, AppTheme.hPad)
|
||||
cleanupRow(label: "Large videos", sizeGB: 0, color: AppTheme.inkQuaternary)
|
||||
}
|
||||
.padding(.horizontal, AppTheme.hPad)
|
||||
@@ -1033,6 +1058,45 @@ struct BackupView: View {
|
||||
.padding(.horizontal, AppTheme.hPad)
|
||||
.padding(.bottom, 12)
|
||||
|
||||
// Recently Deleted toggle
|
||||
Button {
|
||||
withAnimation(.spring(response: 0.3, dampingFraction: 0.8)) {
|
||||
cleanDeletedPhotos.toggle()
|
||||
}
|
||||
} label: {
|
||||
HStack(spacing: 12) {
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill((cleanDeletedPhotos ? AppTheme.destructive : AppTheme.inkQuaternary).opacity(0.12))
|
||||
.frame(width: 36, height: 36)
|
||||
Image(systemName: "trash")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(cleanDeletedPhotos ? AppTheme.destructive : AppTheme.inkTertiary)
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("Recently Deleted")
|
||||
.font(.system(size: 14, weight: .medium))
|
||||
.foregroundStyle(AppTheme.ink)
|
||||
Text(deletedPhotosGB > 0.01
|
||||
? String(format: "~%.1f GB · iPhone trash", deletedPhotosGB)
|
||||
: "Empty · iPhone trash")
|
||||
.font(.system(size: 11))
|
||||
.foregroundStyle(AppTheme.inkTertiary)
|
||||
}
|
||||
Spacer()
|
||||
Image(systemName: cleanDeletedPhotos ? "checkmark.circle.fill" : "circle")
|
||||
.font(.system(size: 18))
|
||||
.foregroundStyle(cleanDeletedPhotos ? AppTheme.destructive : AppTheme.inkQuaternary)
|
||||
}
|
||||
.padding(.horizontal, AppTheme.hPad)
|
||||
.padding(.vertical, 14)
|
||||
.background(AppTheme.surfaceSunken)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous))
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.padding(.horizontal, AppTheme.hPad)
|
||||
.padding(.bottom, 12)
|
||||
|
||||
// Screenshots section
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
HStack(spacing: 12) {
|
||||
|
||||
Reference in New Issue
Block a user