Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto upload from specific Albums #3257

Open
wants to merge 34 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
a67c5b6
WIP
mpivchev Nov 7, 2024
c1ba690
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Nov 20, 2024
e9ced63
WIP
mpivchev Nov 26, 2024
8c4b56d
WIP
mpivchev Dec 12, 2024
b169b65
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 12, 2024
dde85de
WIP
mpivchev Dec 12, 2024
6fae362
WIP
mpivchev Dec 12, 2024
e6f83bf
WIP
mpivchev Dec 12, 2024
f964a7e
WIP
mpivchev Dec 16, 2024
1b6614b
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 17, 2024
18fd8b2
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 18, 2024
be8acf9
WIP
mpivchev Dec 18, 2024
d65b994
WIP
mpivchev Dec 19, 2024
c1e2e3a
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 19, 2024
f158776
WIP
mpivchev Dec 20, 2024
bf544c1
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 20, 2024
ade3dad
WIP
mpivchev Dec 23, 2024
c4d8d0a
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Dec 27, 2024
0694b39
Fix build
mpivchev Dec 27, 2024
cfc2a8c
WIP
mpivchev Dec 27, 2024
45cb383
WIP
mpivchev Dec 30, 2024
f557d84
Fix stateobject redrawing
mpivchev Dec 30, 2024
e862893
WIP
mpivchev Jan 2, 2025
1f4c221
WIP
mpivchev Jan 9, 2025
f7d5b96
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Jan 9, 2025
7eb1f5b
Finish
mpivchev Jan 16, 2025
44f0bde
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Jan 16, 2025
97fc278
Apply suggestions from code review
mpivchev Jan 27, 2025
b6285dd
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Jan 27, 2025
81920e9
PR reviews
mpivchev Jan 27, 2025
525b7a1
PR suggestions
mpivchev Jan 27, 2025
3457565
Merge branch 'develop' of https://github.com/nextcloud/ios into auto-…
mpivchev Feb 6, 2025
681c7c9
PR fixes
mpivchev Feb 6, 2025
4fa208d
PR fixes
mpivchev Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 34 additions & 6 deletions Nextcloud.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
LastUpgradeVersion = "1620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
2 changes: 1 addition & 1 deletion Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
2 changes: 1 addition & 1 deletion Nextcloud.xcodeproj/xcshareddata/xcschemes/Widget.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1520"
LastUpgradeVersion = "1620"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
Expand Down
8 changes: 5 additions & 3 deletions iOSClient/DeepLink/NCDeepLinkHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,11 @@ class NCDeepLinkHandler {
controller.selectedIndex = ControllerConstants.moreIndex
guard let navigationController = controller.viewControllers?[controller.selectedIndex] as? UINavigationController else { return }

let autoUploadView = NCAutoUploadView(model: NCAutoUploadModel(controller: controller))
let autoUploadController = UIHostingController(rootView: autoUploadView)
navigationController.pushViewController(autoUploadController, animated: true)
Task { @MainActor in
let autoUploadView = NCAutoUploadView(model: NCAutoUploadModel(controller: controller), albumModel: AlbumModel(controller: controller))
let autoUploadController = UIHostingController(rootView: autoUploadView)
navigationController.pushViewController(autoUploadController, animated: true)
}
}

private func navigateAppUpdate() {
Expand Down
31 changes: 31 additions & 0 deletions iOSClient/Extensions/PHAssetCollection+Extension.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2024 Milen Pivchev
// SPDX-License-Identifier: GPL-3.0-or-later

import Photos

extension PHAssetCollection {
var assetCount: Int {
let fetchOptions = PHFetchOptions()
let result = PHAsset.fetchAssets(in: self, options: fetchOptions)
return result.count
}

static var allAlbums: [PHAssetCollection] {
let smartAlbumAssetCollections = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: .any, options: nil)
var smartAlbums: [PHAssetCollection] = []

smartAlbumAssetCollections.enumerateObjects { collection, _, _ in
smartAlbums.append(collection)
}

let userAlbumAssetCollections = PHAssetCollection.fetchAssetCollections(with: .album, subtype: .any, options: nil)
var userAlbums: [PHAssetCollection] = []

userAlbumAssetCollections.enumerateObjects { collection, _, _ in
userAlbums.append(collection)
}

return smartAlbums + userAlbums
}
}
6 changes: 1 addition & 5 deletions iOSClient/Main/NCMainNavigationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,7 @@ class NCMainNavigationController: UINavigationController, UINavigationController
}

func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if viewController is NCMore || viewController is UIHostingController<Nextcloud.NCSettingsView> {
setGroupAppearance()
} else {
setNavigationBarAppearance()
}
setNavigationBarAppearance()
}

func setNavigationLeftItems() { }
Expand Down
4 changes: 4 additions & 0 deletions iOSClient/More/NCMoreNavigationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,4 +62,8 @@ class NCMoreNavigationController: NCMainNavigationController {
self.tabBarController?.tabBar.isHidden = true
}
}

override func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
setGroupAppearance()
}
}
89 changes: 56 additions & 33 deletions iOSClient/Networking/NCAutoUpload.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,17 @@
return completion(0)
}

NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in
NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { [self] hasPermission in
guard hasPermission else {
self.database.setAccountAutoUploadProperty("autoUpload", state: false)
return completion(0)
}

self.uploadAssetsNewAndFull(controller: controller, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload", account: account) { num in
let albumIds = NCKeychain().getAutoUploadAlbumIds(account: account)

let selectedAlbums = PHAssetCollection.allAlbums.filter({albumIds.contains($0.localIdentifier)})

self.uploadAssetsNewAndFull(controller: controller, assetCollections: selectedAlbums, selector: NCGlobal.shared.selectorUploadAutoUpload, log: "Init Auto Upload", account: account) { num in
completion(num)
}
}
Expand All @@ -67,29 +71,29 @@
})
}

func autoUploadFullPhotos(controller: NCMainTabBarController?, log: String, account: String) {
func autoUploadSelectedAlbums(controller: NCMainTabBarController?, assetCollections: [PHAssetCollection], log: String, account: String) {
applicationState = UIApplication.shared.applicationState
hud.initHudRing(view: controller?.view, text: nil, detailText: nil, tapToCancelDetailText: false)

NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in
guard hasPermission else { return }
DispatchQueue.global().async {
self.uploadAssetsNewAndFull(controller: controller, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log, account: account) { _ in
self.uploadAssetsNewAndFull(controller: controller, assetCollections: assetCollections, selector: NCGlobal.shared.selectorUploadAutoUploadAll, log: log, account: account) { _ in
self.hud.dismiss()
}
}
}
}

private func uploadAssetsNewAndFull(controller: NCMainTabBarController?, selector: String, log: String, account: String, completion: @escaping (_ num: Int) -> Void) {
private func uploadAssetsNewAndFull(controller: NCMainTabBarController?, assetCollections: [PHAssetCollection] = [], selector: String, log: String, account: String, completion: @escaping (_ num: Int) -> Void) {
guard let tableAccount = self.database.getTableAccount(predicate: NSPredicate(format: "account == %@", account)) else {
return completion(0)
}
let session = NCSession.shared.getSession(account: account)
let autoUploadPath = self.database.getAccountAutoUploadPath(session: session)
var metadatas: [tableMetadata] = []

self.getCameraRollAssets(controller: controller, selector: selector, alignPhotoLibrary: false, account: account) { assets in
self.getCameraRollAssets(controller: controller, assetCollections: assetCollections, selector: selector, alignPhotoLibrary: false, account: account) { assets in
guard let assets, !assets.isEmpty else {
NextcloudKit.shared.nkCommonInstance.writeLog("[INFO] Automatic upload, no new assets found [" + log + "]")
return completion(0)
Expand Down Expand Up @@ -210,19 +214,49 @@
}
}

private func getCameraRollAssets(controller: NCMainTabBarController?, selector: String, alignPhotoLibrary: Bool, account: String, completion: @escaping (_ assets: [PHAsset]?) -> Void) {
NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in
func processAssets(_ assetCollection: PHAssetCollection, _ fetchOptions: PHFetchOptions, _ tableAccount: tableAccount, _ selector: String, _ account: String) -> [PHAsset] {
let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: assetCollection, options: fetchOptions)
var assetResult: [PHAsset] = []

if selector == NCGlobal.shared.selectorUploadAutoUpload,
let idAssets = self.database.getPhotoLibraryIdAsset(image: tableAccount.autoUploadImage, video: tableAccount.autoUploadVideo, account: account) {
assets.enumerateObjects { asset, _, _ in
var creationDateString = ""
if let creationDate = asset.creationDate {
creationDateString = String(describing: creationDate)
}
let idAsset = account + asset.localIdentifier + creationDateString
if !idAssets.contains(idAsset) {
if (asset.isFavorite && tableAccount.autoUploadFavoritesOnly) || !tableAccount.autoUploadFavoritesOnly {
assetResult.append(asset)
}
}
}
} else {
assets.enumerateObjects { asset, _, _ in
if (asset.isFavorite && tableAccount.autoUploadFavoritesOnly) || !tableAccount.autoUploadFavoritesOnly {
assetResult.append(asset)
}
}
}

return assetResult
}

Check warning on line 245 in iOSClient/Networking/NCAutoUpload.swift

View workflow job for this annotation

GitHub Actions / Lint

Trailing Whitespace Violation: Lines should not have trailing whitespace (trailing_whitespace)
private func getCameraRollAssets(controller: NCMainTabBarController?, assetCollections: [PHAssetCollection] = [], selector: String, alignPhotoLibrary: Bool, account: String, completion: @escaping (_ assets: [PHAsset]?) -> Void) {
NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { [self] hasPermission in
guard hasPermission,
let tableAccount = self.database.getTableAccount(predicate: NSPredicate(format: "account == %@", account)) else {
return completion(nil)
}
let assetCollection = PHAssetCollection.fetchAssetCollections(with: PHAssetCollectionType.smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil)
guard let assetCollection = assetCollection.firstObject else { return completion(nil) }

var newAssets: [PHAsset] = []

let fetchOptions = PHFetchOptions()

let predicateImage = NSPredicate(format: "mediaType == %i", PHAssetMediaType.image.rawValue)
let predicateVideo = NSPredicate(format: "mediaType == %i", PHAssetMediaType.video.rawValue)
var predicate: NSPredicate?
let fetchOptions = PHFetchOptions()
var newAssets: [PHAsset] = []

if alignPhotoLibrary || (tableAccount.autoUploadImage && tableAccount.autoUploadVideo) {
predicate = NSCompoundPredicate(orPredicateWithSubpredicates: [predicateImage, predicateVideo])
Expand All @@ -235,30 +269,19 @@
}

fetchOptions.predicate = predicate
let assets: PHFetchResult<PHAsset> = PHAsset.fetchAssets(in: assetCollection, options: fetchOptions)

if selector == NCGlobal.shared.selectorUploadAutoUpload,
let idAssets = self.database.getPhotoLibraryIdAsset(image: tableAccount.autoUploadImage, video: tableAccount.autoUploadVideo, account: account) {
assets.enumerateObjects { asset, _, _ in
var creationDateString = ""
if let creationDate = asset.creationDate {
creationDateString = String(describing: creationDate)
}
let idAsset = account + asset.localIdentifier + creationDateString
if !idAssets.contains(idAsset) {
if (asset.isFavorite && tableAccount.autoUploadFavoritesOnly) || !tableAccount.autoUploadFavoritesOnly {
newAssets.append(asset)
}
}
}

if assetCollections.isEmpty {
let assetCollection = PHAssetCollection.fetchAssetCollections(with: .smartAlbum, subtype: PHAssetCollectionSubtype.smartAlbumUserLibrary, options: nil)
guard let assetCollection = assetCollection.firstObject else { return completion(nil) }
mpivchev marked this conversation as resolved.
Show resolved Hide resolved

newAssets += processAssets(assetCollection, fetchOptions, tableAccount, selector, account)
} else {
assets.enumerateObjects { asset, _, _ in
if (asset.isFavorite && tableAccount.autoUploadFavoritesOnly) || !tableAccount.autoUploadFavoritesOnly {
newAssets.append(asset)
}
for assetCollection in assetCollections {
newAssets += processAssets(assetCollection, fetchOptions, tableAccount, selector, account)
}

completion(newAssets)
}
completion(newAssets)
}
}
}
1 change: 1 addition & 0 deletions iOSClient/Settings/Advanced/NCSettingsAdvancedView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ struct NCSettingsAdvancedView: View {
})
}
.navigationBarTitle(NSLocalizedString("_advanced_", comment: ""))
.navigationBarTitleDisplayMode(.inline)
.defaultViewModifier(model)
}

Expand Down
9 changes: 9 additions & 0 deletions iOSClient/Settings/AutoUpload/Albums.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2024 Milen Pivchev
// SPDX-License-Identifier: GPL-3.0-or-later

import Photos

class Albums: ObservableObject {
@Published var smartAlbums: [PHAssetCollection] = []
}
18 changes: 14 additions & 4 deletions iOSClient/Settings/AutoUpload/NCAutoUploadModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,6 @@ import NextcloudKit
class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
/// A state variable that indicates whether auto upload is enabled or not
@Published var autoUpload: Bool = false
/// A state variable that indicates whether to open NCSelect View or not
@Published var autoUploadFolder: Bool = false
/// A state variable that indicates whether auto upload for photos is enabled or not
@Published var autoUploadImage: Bool = false
/// A state variable that indicates whether auto upload for photos is restricted to Wi-Fi only or not
Expand All @@ -57,6 +55,7 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
@Published var error: String = ""
let database = NCManageDatabase.shared
@Published var autoUploadPath = "\(NCManageDatabase.shared.getAccountAutoUploadFileName())"

/// Root View Controller
var controller: NCMainTabBarController?
/// A variable user for change the auto upload directory
Expand Down Expand Up @@ -164,10 +163,11 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
}

/// Updates the auto-upload full content setting.
func handleAutoUploadFullChange(newValue: Bool) {
func handleAutoUploadChange(newValue: Bool, assetCollections: [PHAssetCollection]) {
updateAccountProperty(\.autoUploadFull, value: newValue)

if newValue {
NCAutoUpload.shared.autoUploadFullPhotos(controller: self.controller, log: "Auto upload full", account: session.account)
NCAutoUpload.shared.autoUploadSelectedAlbums(controller: self.controller, assetCollections: assetCollections, log: "Auto upload selected albums", account: session.account)
} else {
self.database.clearMetadatasUpload(account: session.account)
}
Expand Down Expand Up @@ -214,8 +214,18 @@ class NCAutoUploadModel: ObservableObject, ViewOnAppearHandling {
self.database.setAccountAutoUploadDirectory(path, session: session)
}
}

onViewAppear()
}

func createAlbumTitle(autoUploadAlbumIds: Set<String>) -> String {
if autoUploadAlbumIds.count == 1 {
let album = PHAssetCollection.allAlbums.first(where: { autoUploadAlbumIds.first == $0.localIdentifier })
return (album?.assetCollectionSubtype == .smartAlbumUserLibrary) ? NSLocalizedString("_camera_roll_", comment: "") : (album?.localizedTitle ?? "")
} else {
return NSLocalizedString("_multiple_albums_", comment: "")
}
}
}

/// An enum that represents the granularity of the subfolders for auto upload
Expand Down
Loading
Loading