Skip to content

Commit f02f58d

Browse files
committed
feat: add option to export camera roll, and group albums/smart albums
1 parent df3fe1a commit f02f58d

File tree

3 files changed

+125
-12
lines changed

3 files changed

+125
-12
lines changed

Localizable.xcstrings

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5172,6 +5172,46 @@
51725172
}
51735173
}
51745174
},
5175+
"Camera roll" : {
5176+
"localizations" : {
5177+
"de" : {
5178+
"stringUnit" : {
5179+
"state" : "translated",
5180+
"value" : "Kamerarolle"
5181+
}
5182+
},
5183+
"es" : {
5184+
"stringUnit" : {
5185+
"state" : "translated",
5186+
"value" : "Carrete"
5187+
}
5188+
},
5189+
"it" : {
5190+
"stringUnit" : {
5191+
"state" : "translated",
5192+
"value" : "Rullino foto"
5193+
}
5194+
},
5195+
"nl" : {
5196+
"stringUnit" : {
5197+
"state" : "translated",
5198+
"value" : "Fotorol"
5199+
}
5200+
},
5201+
"uk" : {
5202+
"stringUnit" : {
5203+
"state" : "translated",
5204+
"value" : "Плівка"
5205+
}
5206+
},
5207+
"zh-Hans" : {
5208+
"stringUnit" : {
5209+
"state" : "translated",
5210+
"value" : "相机胶卷"
5211+
}
5212+
}
5213+
}
5214+
},
51755215
"Cancel" : {
51765216
"localizations" : {
51775217
"de" : {
@@ -24156,6 +24196,46 @@
2415624196
}
2415724197
}
2415824198
},
24199+
"Smart albums" : {
24200+
"localizations" : {
24201+
"de" : {
24202+
"stringUnit" : {
24203+
"state" : "translated",
24204+
"value" : "Intelligente Alben"
24205+
}
24206+
},
24207+
"es" : {
24208+
"stringUnit" : {
24209+
"state" : "translated",
24210+
"value" : "Álbumes inteligentes"
24211+
}
24212+
},
24213+
"it" : {
24214+
"stringUnit" : {
24215+
"state" : "translated",
24216+
"value" : "Album intelligenti"
24217+
}
24218+
},
24219+
"nl" : {
24220+
"stringUnit" : {
24221+
"state" : "translated",
24222+
"value" : "Slimme albums"
24223+
}
24224+
},
24225+
"uk" : {
24226+
"stringUnit" : {
24227+
"state" : "translated",
24228+
"value" : "Розумні альбоми"
24229+
}
24230+
},
24231+
"zh-Hans" : {
24232+
"stringUnit" : {
24233+
"state" : "translated",
24234+
"value" : "智能相册"
24235+
}
24236+
}
24237+
}
24238+
},
2415924239
"Start" : {
2416024240
"localizations" : {
2416124241
"de" : {

Sushitrain/PhotoBackup.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ enum PhotoSyncProgress {
164164
}
165165

166166
@MainActor class PhotoBackup: ObservableObject {
167+
static nonisolated let allPhotosAlbumIdentifier = "_SUSHITRAIN_ALL_PHOTOS"
168+
167169
// These settings are prefixed 'photoSync' because that is what the feature used to be called
168170
@AppStorage("photoSyncSelectedAlbumID") var selectedAlbumID: String = ""
169171
@AppStorage("photoSyncFolderID") var selectedFolderID: String = ""
@@ -315,7 +317,14 @@ enum PhotoSyncProgress {
315317
}
316318

317319
let folderURL = URL(fileURLWithPath: folderPath)
318-
let fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [selectedAlbumID], options: nil)
320+
let fetchResult: PHFetchResult<PHAssetCollection>
321+
if selectedAlbumID == PhotoBackup.allPhotosAlbumIdentifier {
322+
fetchResult = PHAssetCollection.fetchAssetCollections(
323+
with: .smartAlbum, subtype: .smartAlbumUserLibrary, options: nil)
324+
}
325+
else {
326+
fetchResult = PHAssetCollection.fetchAssetCollections(withLocalIdentifiers: [selectedAlbumID], options: nil)
327+
}
319328
guard let album = fetchResult.firstObject else {
320329
DispatchQueue.main.async { self.progress = .error(String(localized: "Could not find selected album")) }
321330
return

Sushitrain/PhotoBackupView.swift

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,33 @@ struct PhotoBackupStatusView: View {
8787

8888
struct PhotoBackupSettingsView: View {
8989
@Environment(AppState.self) private var appState
90+
91+
@ObservedObject var photoBackup: PhotoBackup
92+
9093
@State private var authorizationStatus: PHAuthorizationStatus = .notDetermined
9194
@State private var albumPickerShown = false
92-
@ObservedObject var photoBackup: PhotoBackup
9395
@State private var folders: [SushitrainFolder] = []
96+
@State private var albums: [PHAssetCollection] = []
97+
@State private var smartAlbums: [PHAssetCollection] = []
9498

9599
var body: some View {
96-
let albums = self.authorizationStatus == .authorized ? self.loadAlbums() : []
97-
98100
Form {
99101
Section {
100102
if authorizationStatus == .authorized {
101103
Picker("From album", selection: $photoBackup.selectedAlbumID) {
102104
Text("None").tag("")
103-
ForEach(albums, id: \.localIdentifier) { album in
104-
Text(album.localizedTitle ?? "Unknown album").tag(
105-
album.localIdentifier)
105+
Text("Camera roll").tag(PhotoBackup.allPhotosAlbumIdentifier)
106+
107+
Section("Albums") {
108+
ForEach(albums, id: \.localIdentifier) { album in
109+
Text(album.localizedTitle ?? "Unknown album").tag(album.localIdentifier)
110+
}
111+
}
112+
113+
Section("Smart albums") {
114+
ForEach(smartAlbums, id: \.localIdentifier) { album in
115+
Text(album.localizedTitle ?? "Unknown album").tag(album.localIdentifier)
116+
}
106117
}
107118
}
108119
.pickerStyle(.menu)
@@ -322,12 +333,23 @@ struct PhotoBackupSettingsView: View {
322333
.navigationBarTitleDisplayMode(.inline)
323334
#endif
324335
.task {
325-
authorizationStatus = PHPhotoLibrary.authorizationStatus()
326-
self.folders = await appState.folders().filter({ $0.isSuitablePhotoBackupDestination }).sorted()
336+
await self.update()
337+
}
338+
}
339+
340+
private func update() async {
341+
authorizationStatus = PHPhotoLibrary.authorizationStatus()
342+
self.folders = await appState.folders().filter({ $0.isSuitablePhotoBackupDestination }).sorted()
343+
if self.authorizationStatus == .authorized {
344+
self.loadAlbums()
345+
}
346+
else {
347+
self.albums = []
348+
self.smartAlbums = []
327349
}
328350
}
329351

330-
func loadAlbums() -> [PHAssetCollection] {
352+
private func loadAlbums() {
331353
var albums: [PHAssetCollection] = []
332354
let options = PHFetchOptions()
333355
options.sortDescriptors = [NSSortDescriptor(key: "localizedTitle", ascending: true)]
@@ -336,15 +358,17 @@ struct PhotoBackupSettingsView: View {
336358
userAlbums.enumerateObjects { (collection, _, _) in
337359
albums.append(collection)
338360
}
361+
self.albums = albums
339362

340363
// Fetch system albums, including 'Recents'
364+
var smartAlbums: [PHAssetCollection] = []
341365
let systemAlbumsOptions = PHFetchOptions()
342366
let systemAlbums = PHAssetCollection.fetchAssetCollections(
343367
with: .smartAlbum, subtype: .any, options: systemAlbumsOptions)
344368
systemAlbums.enumerateObjects { (collection, _, _) in
345-
albums.append(collection)
369+
smartAlbums.append(collection)
346370
}
347-
return albums
371+
self.smartAlbums = smartAlbums
348372
}
349373

350374
#if os(iOS)

0 commit comments

Comments
 (0)