diff --git a/iOSClient/Media/Cell/NCMediaCell.swift b/iOSClient/Media/Cell/NCMediaCell.swift index cf4824cdba..1575f21f6d 100644 --- a/iOSClient/Media/Cell/NCMediaCell.swift +++ b/iOSClient/Media/Cell/NCMediaCell.swift @@ -31,7 +31,7 @@ class NCMediaCell: UICollectionViewCell { @IBOutlet weak var imageStatus: UIImageView! var ocId: String = "" - var datePhotosOriginal: Date? + var date: Date? override func awakeFromNib() { super.awakeFromNib() diff --git a/iOSClient/Media/NCMedia+CollectionViewDataSource.swift b/iOSClient/Media/NCMedia+CollectionViewDataSource.swift index eee99e776e..c6d951dbe4 100644 --- a/iOSClient/Media/NCMedia+CollectionViewDataSource.swift +++ b/iOSClient/Media/NCMedia+CollectionViewDataSource.swift @@ -62,7 +62,7 @@ extension NCMedia: UICollectionViewDataSource { let imageCache = imageCache.getImageCache(ocId: metadata.ocId, etag: metadata.etag, ext: ext) cell.imageItem.image = imageCache - cell.datePhotosOriginal = metadata.datePhotosOriginal as Date + cell.date = metadata.date cell.ocId = metadata.ocId cell.imageStatus.image = nil diff --git a/iOSClient/Media/NCMedia+Command.swift b/iOSClient/Media/NCMedia+Command.swift index 560804ea76..28e70f9136 100644 --- a/iOSClient/Media/NCMedia+Command.swift +++ b/iOSClient/Media/NCMedia+Command.swift @@ -37,7 +37,7 @@ extension NCMedia { let sortedAttributes = layoutAttributes.sorted { $0.frame.minY < $1.frame.minY || ($0.frame.minY == $1.frame.minY && $0.frame.minX < $1.frame.minX) } if let firstAttribute = sortedAttributes.first, let metadata = dataSource.getMetadata(indexPath: firstAttribute.indexPath) { - titleDate?.text = utility.getTitleFromDate(metadata.datePhotosOriginal as Date) + titleDate?.text = utility.getTitleFromDate(metadata.date) return } } diff --git a/iOSClient/Media/NCMedia+Netwoking.swift b/iOSClient/Media/NCMedia+Netwoking.swift index dbe8e8b9d7..f64ad08fd5 100644 --- a/iOSClient/Media/NCMedia+Netwoking.swift +++ b/iOSClient/Media/NCMedia+Netwoking.swift @@ -8,9 +8,8 @@ import Alamofire extension NCMedia { func searchMediaAsync(path: String = "", - lessDate: Any, - greaterDate: Any, - elementDate: String, + lessDate: Date, + greaterDate: Date, limit: Int, account: String, options: NKRequestOptions = NKRequestOptions(), @@ -19,25 +18,33 @@ extension NCMedia { guard let nkSession = NextcloudKit.shared.nkCommonInstance.nksessions.session(forAccount: account) else { return (account, nil, .urlError) } + let capabilities = await NKCapabilities.shared.getCapabilities(for: account) let files: [NKFile] = [] - let elementDate = elementDate + "/" - var greaterDateString: String?, lessDateString: String? let href = "/files/" + nkSession.userId + path - if let lessDate = lessDate as? Date { + + let elementDate: String + var lessDateString: String + var greaterDateString: String + + if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { + elementDate = "nc:metadata-photos-original_date_time" + lessDateString = String(lessDate.timeIntervalSince1970) + greaterDateString = String(greaterDate.timeIntervalSince1970) + } else { + elementDate = "d:getlastmodified" lessDateString = lessDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") - } else if let lessDate = lessDate as? Int { - lessDateString = String(lessDate) - } - if let greaterDate = greaterDate as? Date { greaterDateString = greaterDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ") - } else if let greaterDate = greaterDate as? Int { - greaterDateString = String(greaterDate) - } - guard let lessDateString, let greaterDateString else { - return (account, files, .invalidDate) } - let httpBodyString = String(format: getRequestBodySearchMedia(createProperties: options.createProperties, removeProperties: options.removeProperties), href, elementDate, elementDate, lessDateString, elementDate, greaterDateString, String(limit)) + let httpBodyString = String(format: getRequestBodySearchMedia( + createProperties: options.createProperties, + removeProperties: options.removeProperties, + href: href, + elementDate: elementDate, + lessDate: lessDateString, + greaterDate: greaterDateString, + limit: String(limit)) + ) guard let httpBody = httpBodyString.data(using: .utf8) else { return (account, files, .invalidData) @@ -48,25 +55,47 @@ extension NCMedia { return(results.account, results.files, results.error) } - func getRequestBodySearchMedia(createProperties: [NKProperties]?, removeProperties: [NKProperties] = []) -> String { + func getRequestBodySearchMedia(createProperties: [NKProperties]?, + removeProperties: [NKProperties] = [], + href: String, + elementDate: String, + lessDate: String, + greaterDate: String, + limit: String) -> String { + // Build the DAV property list (merged create/remove rules) + let properties = NKProperties.properties(createProperties: createProperties, removeProperties: removeProperties) + let request = """ - - - - """ + NKProperties.properties(createProperties: createProperties, removeProperties: removeProperties) + """ - - + + + + + + + + \(properties) + + + + + - %@ + \(href) infinity + + + + + + - <%@> + <\(elementDate)/> @@ -74,39 +103,53 @@ extension NCMedia { + + + + + + - - - - image/%% - - - - video/%% - - - + + + + + + image/%% + + + + video/%% + + + + - <%@> - %@ + <\(elementDate)/> + \(lessDate) - <%@> - %@ + <\(elementDate)/> + \(greaterDate) - + + + + + - %@ + \(limit) - + + """ - return request + return request } } diff --git a/iOSClient/Media/NCMediaDataSource.swift b/iOSClient/Media/NCMediaDataSource.swift index b51100090e..ecbc2a9d6c 100644 --- a/iOSClient/Media/NCMediaDataSource.swift +++ b/iOSClient/Media/NCMediaDataSource.swift @@ -11,11 +11,19 @@ extension NCMedia { guard let tblAccount = await self.database.getTableAccountAsync(predicate: NSPredicate(format: "account == %@", self.session.account)) else { return } + let capabilities = await NKCapabilities.shared.getCapabilities(for: self.session.account) let mediaPredicate = self.imageCache.getMediaPredicate(session: self.session, mediaPath: tblAccount.mediaPath, showOnlyImages: self.showOnlyImages, showOnlyVideos: self.showOnlyVideos) - if let metadatas = await self.database.getMetadatasAsync(predicate: mediaPredicate, sortedByKeyPath: "datePhotosOriginal", ascending: false) { + var sortedByKeyPath: String + if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { + sortedByKeyPath = "datePhotosOriginal" + } else { + sortedByKeyPath = "date" + } + + if let metadatas = await self.database.getMetadatasAsync(predicate: mediaPredicate, sortedByKeyPath: sortedByKeyPath, ascending: false) { self.database.filterAndNormalizeLivePhotos(from: metadatas) { metadatas in Task { @MainActor in self.dataSource = NCMediaDataSource(metadatas: metadatas) @@ -97,15 +105,15 @@ extension NCMedia { } visibleCells = visibleCells.sorted { - guard let date1 = $0.datePhotosOriginal, let date2 = $1.datePhotosOriginal else { + guard let date1 = $0.date, let date2 = $1.date else { return false } return date1 > date2 } if !visibleCells.isEmpty, !distant { - let firstCellDate = visibleCells.first?.datePhotosOriginal - let lastCellDate = visibleCells.last?.datePhotosOriginal + let firstCellDate = visibleCells.first?.date + let lastCellDate = visibleCells.last?.date if collectionView.contentOffset.y <= 0 { lessDate = .distantFuture @@ -113,7 +121,7 @@ extension NCMedia { lessDate = Calendar.current.date(byAdding: .second, value: 1, to: firstCellDate ?? .distantFuture) ?? .distantFuture } - if lastCellDate == self.dataSource.metadatas.last?.datePhotosOriginal { + if lastCellDate == self.dataSource.metadatas.last?.date { greaterDate = .distantPast } else { greaterDate = Calendar.current.date(byAdding: .second, value: -1, to: lastCellDate ?? .distantPast) ?? .distantPast @@ -121,20 +129,6 @@ extension NCMedia { } } - let elementDate: String - var lessDateAny: Any - var greaterDateAny: Any - - if capabilities.serverVersionMajor >= self.global.nextcloudVersion31 { - elementDate = "nc:metadata-photos-original_date_time" - lessDateAny = Int(lessDate.timeIntervalSince1970) - greaterDateAny = Int(greaterDate.timeIntervalSince1970) - } else { - elementDate = "d:getlastmodified" - lessDateAny = lessDate - greaterDateAny = greaterDate - } - let limit = await MainActor.run { max(self.collectionView.visibleCells.count * 3, 300) } @@ -142,9 +136,8 @@ extension NCMedia { let options = NKRequestOptions(timeout: 180, taskDescription: self.global.taskDescriptionRetrievesProperties, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue) let result = await searchMediaAsync(path: tblAccount.mediaPath, - lessDate: lessDateAny, - greaterDate: greaterDateAny, - elementDate: elementDate, + lessDate: lessDate, + greaterDate: greaterDate, limit: limit, account: self.session.account, options: options) { task in @@ -181,10 +174,19 @@ extension NCMedia { mediaPath: tblAccount.mediaPath, showOnlyImages: self.showOnlyImages, showOnlyVideos: self.showOnlyVideos) - let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ - NSPredicate(format: "datePhotosOriginal >= %@ AND datePhotosOriginal <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate), + + var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ + NSPredicate(format: "date >= %@ AND date <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate), mediaPredicate ]) + + if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { + predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [ + NSPredicate(format: "datePhotosOriginal >= %@ AND datePhotosOriginal <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate), + mediaPredicate + ]) + } + let localMetadatas = await self.database.getMetadatasAsync(predicate: predicate) await MainActor.run { @@ -206,7 +208,7 @@ extension NCMedia { @MainActor public class NCMediaDataSource: NSObject { public class Metadata: NSObject { - let datePhotosOriginal: Date + let date: Date let etag: String let imageSize: CGSize let isImage: Bool @@ -214,14 +216,14 @@ public class NCMediaDataSource: NSObject { let isVideo: Bool let ocId: String - init(datePhotosOriginal: Date, + init(date: Date, etag: String, imageSize: CGSize, isImage: Bool, isLivePhoto: Bool, isVideo: Bool, ocId: String) { - self.datePhotosOriginal = datePhotosOriginal + self.date = date self.etag = etag self.imageSize = imageSize self.isImage = isImage @@ -245,7 +247,7 @@ public class NCMediaDataSource: NSObject { private func insertInMetadatas(metadata: Metadata) { for i in 0.. self.metadatas[i].datePhotosOriginal { + if (metadata.date) > self.metadatas[i].date { self.metadatas.insert(metadata, at: i) return } @@ -255,7 +257,14 @@ public class NCMediaDataSource: NSObject { } private func getMetadataFromTableMetadata(_ metadata: tableMetadata) -> Metadata { - return Metadata(datePhotosOriginal: metadata.datePhotosOriginal as Date, + let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities() + let date: Date + if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture { + date = metadata.datePhotosOriginal as Date + } else { + date = metadata.date as Date + } + return Metadata(date: date, etag: metadata.etag, imageSize: CGSize(width: metadata.width, height: metadata.height), isImage: metadata.classFile == NKTypeClassFile.image.rawValue, diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 1b84d949ed..93aa8c217d 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -52,6 +52,8 @@ final class NCGlobal: Sendable { let nextcloudVersion28: Int = 28 let nextcloudVersion30: Int = 30 let nextcloudVersion31: Int = 31 + let nextcloudVersionFuture: Int = 99999 + // Nextcloud unsupported // diff --git a/iOSClient/NCImageCache.swift b/iOSClient/NCImageCache.swift index 3579e08129..ee3512e750 100644 --- a/iOSClient/NCImageCache.swift +++ b/iOSClient/NCImageCache.swift @@ -56,7 +56,7 @@ final class NCImageCache: @unchecked Sendable { // MEDIA let predicate = self.getMediaPredicate(session: session, mediaPath: tblAccount.mediaPath, showOnlyImages: false, showOnlyVideos: false) - guard let metadatas = await self.database.getMetadatasAsync(predicate: predicate, sortedByKeyPath: "datePhotosOriginal", limit: self.countLimit) else { + guard let metadatas = await self.database.getMetadatasAsync(predicate: predicate, sortedByKeyPath: "date", limit: self.countLimit) else { return }