Skip to content

Commit 0fa68e1

Browse files
searchmedia-fix (nextcloud#3957)
* clean Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * fix Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> --------- Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com>
1 parent 1f2d6b3 commit 0fa68e1

7 files changed

Lines changed: 131 additions & 77 deletions

‎iOSClient/Media/Cell/NCMediaCell.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class NCMediaCell: UICollectionViewCell {
3131
@IBOutlet weak var imageStatus: UIImageView!
3232

3333
var ocId: String = ""
34-
var datePhotosOriginal: Date?
34+
var date: Date?
3535

3636
override func awakeFromNib() {
3737
super.awakeFromNib()

‎iOSClient/Media/NCMedia+CollectionViewDataSource.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ extension NCMedia: UICollectionViewDataSource {
6262
let imageCache = imageCache.getImageCache(ocId: metadata.ocId, etag: metadata.etag, ext: ext)
6363

6464
cell.imageItem.image = imageCache
65-
cell.datePhotosOriginal = metadata.datePhotosOriginal as Date
65+
cell.date = metadata.date
6666
cell.ocId = metadata.ocId
6767
cell.imageStatus.image = nil
6868

‎iOSClient/Media/NCMedia+Command.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ extension NCMedia {
3737
let sortedAttributes = layoutAttributes.sorted { $0.frame.minY < $1.frame.minY || ($0.frame.minY == $1.frame.minY && $0.frame.minX < $1.frame.minX) }
3838

3939
if let firstAttribute = sortedAttributes.first, let metadata = dataSource.getMetadata(indexPath: firstAttribute.indexPath) {
40-
titleDate?.text = utility.getTitleFromDate(metadata.datePhotosOriginal as Date)
40+
titleDate?.text = utility.getTitleFromDate(metadata.date)
4141
return
4242
}
4343
}

‎iOSClient/Media/NCMedia+Netwoking.swift‎

Lines changed: 87 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import Alamofire
88

99
extension NCMedia {
1010
func searchMediaAsync(path: String = "",
11-
lessDate: Any,
12-
greaterDate: Any,
13-
elementDate: String,
11+
lessDate: Date,
12+
greaterDate: Date,
1413
limit: Int,
1514
account: String,
1615
options: NKRequestOptions = NKRequestOptions(),
@@ -19,25 +18,33 @@ extension NCMedia {
1918
guard let nkSession = NextcloudKit.shared.nkCommonInstance.nksessions.session(forAccount: account) else {
2019
return (account, nil, .urlError)
2120
}
21+
let capabilities = await NKCapabilities.shared.getCapabilities(for: account)
2222
let files: [NKFile] = []
23-
let elementDate = elementDate + "/"
24-
var greaterDateString: String?, lessDateString: String?
2523
let href = "/files/" + nkSession.userId + path
26-
if let lessDate = lessDate as? Date {
24+
25+
let elementDate: String
26+
var lessDateString: String
27+
var greaterDateString: String
28+
29+
if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture {
30+
elementDate = "nc:metadata-photos-original_date_time"
31+
lessDateString = String(lessDate.timeIntervalSince1970)
32+
greaterDateString = String(greaterDate.timeIntervalSince1970)
33+
} else {
34+
elementDate = "d:getlastmodified"
2735
lessDateString = lessDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ")
28-
} else if let lessDate = lessDate as? Int {
29-
lessDateString = String(lessDate)
30-
}
31-
if let greaterDate = greaterDate as? Date {
3236
greaterDateString = greaterDate.formatted(using: "yyyy-MM-dd'T'HH:mm:ssZZZZZ")
33-
} else if let greaterDate = greaterDate as? Int {
34-
greaterDateString = String(greaterDate)
35-
}
36-
guard let lessDateString, let greaterDateString else {
37-
return (account, files, .invalidDate)
3837
}
3938

40-
let httpBodyString = String(format: getRequestBodySearchMedia(createProperties: options.createProperties, removeProperties: options.removeProperties), href, elementDate, elementDate, lessDateString, elementDate, greaterDateString, String(limit))
39+
let httpBodyString = String(format: getRequestBodySearchMedia(
40+
createProperties: options.createProperties,
41+
removeProperties: options.removeProperties,
42+
href: href,
43+
elementDate: elementDate,
44+
lessDate: lessDateString,
45+
greaterDate: greaterDateString,
46+
limit: String(limit))
47+
)
4148

4249
guard let httpBody = httpBodyString.data(using: .utf8) else {
4350
return (account, files, .invalidData)
@@ -48,65 +55,101 @@ extension NCMedia {
4855
return(results.account, results.files, results.error)
4956
}
5057

51-
func getRequestBodySearchMedia(createProperties: [NKProperties]?, removeProperties: [NKProperties] = []) -> String {
58+
func getRequestBodySearchMedia(createProperties: [NKProperties]?,
59+
removeProperties: [NKProperties] = [],
60+
href: String,
61+
elementDate: String,
62+
lessDate: String,
63+
greaterDate: String,
64+
limit: String) -> String {
65+
// Build the DAV property list (merged create/remove rules)
66+
let properties = NKProperties.properties(createProperties: createProperties, removeProperties: removeProperties)
67+
5268
let request = """
5369
<?xml version=\"1.0\"?>
5470
<d:searchrequest xmlns:d=\"DAV:\" xmlns:oc=\"http://owncloud.org/ns\" xmlns:nc=\"http://nextcloud.org/ns\">
55-
<d:basicsearch>
56-
<d:select>
57-
<d:prop>
58-
""" + NKProperties.properties(createProperties: createProperties, removeProperties: removeProperties) + """
59-
</d:prop>
60-
</d:select>
71+
<d:basicsearch>
72+
73+
<!-- ====================================================== -->
74+
<!-- SELECT: properties returned for each matching resource -->
75+
<!-- ====================================================== -->
76+
77+
<d:select>
78+
<d:prop>\(properties)</d:prop>
79+
</d:select>
80+
81+
<!-- ===================================================== -->
82+
<!-- FROM: recursive search starting from the given href -->
83+
<!-- ===================================================== -->
6184
<d:from>
6285
<d:scope>
63-
<d:href>%@</d:href>
86+
<d:href>\(href)</d:href>
6487
<d:depth>infinity</d:depth>
6588
</d:scope>
6689
</d:from>
90+
91+
<!-- ===================================================== -->
92+
<!-- ORDER BY: -->
93+
<!-- Primary sort on elementDate (descending) -->
94+
<!-- Secondary sort on displayname for deterministic order -->
95+
<!-- ===================================================== -->
6796
<d:orderby>
6897
<d:order>
69-
<d:prop><%@></d:prop>
98+
<d:prop><\(elementDate)/></d:prop>
7099
<d:descending/>
71100
</d:order>
72101
<d:order>
73102
<d:prop><d:displayname/></d:prop>
74103
<d:descending/>
75104
</d:order>
76105
</d:orderby>
106+
107+
<!-- ===================================================== -->
108+
<!-- WHERE: -->
109+
<!-- 1) Filter only image and video content types -->
110+
<!-- 2) Apply a numeric/date range on elementDate -->
111+
<!-- ===================================================== -->
77112
<d:where>
78113
<d:and>
79-
<d:or>
80-
<d:like>
81-
<d:prop><d:getcontenttype/></d:prop>
82-
<d:literal>image/%%</d:literal>
83-
</d:like>
84-
<d:like>
85-
<d:prop><d:getcontenttype/></d:prop>
86-
<d:literal>video/%%</d:literal>
87-
</d:like>
88-
</d:or>
89-
<d:or>
114+
115+
<!-- Media type filter -->
116+
<d:or>
117+
<d:like>
118+
<d:prop><d:getcontenttype/></d:prop>
119+
<d:literal>image/%%</d:literal>
120+
</d:like>
121+
<d:like>
122+
<d:prop><d:getcontenttype/></d:prop>
123+
<d:literal>video/%%</d:literal>
124+
</d:like>
125+
</d:or>
126+
127+
<!-- Date / numeric range filter -->
90128
<d:and>
91129
<d:lt>
92-
<d:prop><%@></d:prop>
93-
<d:literal>%@</d:literal>
130+
<d:prop><\(elementDate)/></d:prop>
131+
<d:literal>\(lessDate)</d:literal>
94132
</d:lt>
95133
<d:gt>
96-
<d:prop><%@></d:prop>
97-
<d:literal>%@</d:literal>
134+
<d:prop><\(elementDate)/></d:prop>
135+
<d:literal>\(greaterDate)</d:literal>
98136
</d:gt>
99137
</d:and>
100-
</d:or>
138+
101139
</d:and>
102140
</d:where>
141+
142+
<!-- ===================================================== -->
143+
<!-- LIMIT: maximum number of results returned -->
144+
<!-- ===================================================== -->
103145
<d:limit>
104-
<d:nresults>%@</d:nresults>
146+
<d:nresults>\(limit)</d:nresults>
105147
</d:limit>
106-
</d:basicsearch>
148+
149+
</d:basicsearch>
107150
</d:searchrequest>
108151
"""
109-
return request
152+
return request
110153
}
111154
}
112155

‎iOSClient/Media/NCMediaDataSource.swift‎

Lines changed: 38 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,19 @@ extension NCMedia {
1111
guard let tblAccount = await self.database.getTableAccountAsync(predicate: NSPredicate(format: "account == %@", self.session.account)) else {
1212
return
1313
}
14+
let capabilities = await NKCapabilities.shared.getCapabilities(for: self.session.account)
1415
let mediaPredicate = self.imageCache.getMediaPredicate(session: self.session,
1516
mediaPath: tblAccount.mediaPath,
1617
showOnlyImages: self.showOnlyImages,
1718
showOnlyVideos: self.showOnlyVideos)
18-
if let metadatas = await self.database.getMetadatasAsync(predicate: mediaPredicate, sortedByKeyPath: "datePhotosOriginal", ascending: false) {
19+
var sortedByKeyPath: String
20+
if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture {
21+
sortedByKeyPath = "datePhotosOriginal"
22+
} else {
23+
sortedByKeyPath = "date"
24+
}
25+
26+
if let metadatas = await self.database.getMetadatasAsync(predicate: mediaPredicate, sortedByKeyPath: sortedByKeyPath, ascending: false) {
1927
self.database.filterAndNormalizeLivePhotos(from: metadatas) { metadatas in
2028
Task { @MainActor in
2129
self.dataSource = NCMediaDataSource(metadatas: metadatas)
@@ -97,54 +105,39 @@ extension NCMedia {
97105
}
98106

99107
visibleCells = visibleCells.sorted {
100-
guard let date1 = $0.datePhotosOriginal, let date2 = $1.datePhotosOriginal else {
108+
guard let date1 = $0.date, let date2 = $1.date else {
101109
return false
102110
}
103111
return date1 > date2
104112
}
105113

106114
if !visibleCells.isEmpty, !distant {
107-
let firstCellDate = visibleCells.first?.datePhotosOriginal
108-
let lastCellDate = visibleCells.last?.datePhotosOriginal
115+
let firstCellDate = visibleCells.first?.date
116+
let lastCellDate = visibleCells.last?.date
109117

110118
if collectionView.contentOffset.y <= 0 {
111119
lessDate = .distantFuture
112120
} else {
113121
lessDate = Calendar.current.date(byAdding: .second, value: 1, to: firstCellDate ?? .distantFuture) ?? .distantFuture
114122
}
115123

116-
if lastCellDate == self.dataSource.metadatas.last?.datePhotosOriginal {
124+
if lastCellDate == self.dataSource.metadatas.last?.date {
117125
greaterDate = .distantPast
118126
} else {
119127
greaterDate = Calendar.current.date(byAdding: .second, value: -1, to: lastCellDate ?? .distantPast) ?? .distantPast
120128
}
121129
}
122130
}
123131

124-
let elementDate: String
125-
var lessDateAny: Any
126-
var greaterDateAny: Any
127-
128-
if capabilities.serverVersionMajor >= self.global.nextcloudVersion31 {
129-
elementDate = "nc:metadata-photos-original_date_time"
130-
lessDateAny = Int(lessDate.timeIntervalSince1970)
131-
greaterDateAny = Int(greaterDate.timeIntervalSince1970)
132-
} else {
133-
elementDate = "d:getlastmodified"
134-
lessDateAny = lessDate
135-
greaterDateAny = greaterDate
136-
}
137-
138132
let limit = await MainActor.run {
139133
max(self.collectionView.visibleCells.count * 3, 300)
140134
}
141135

142136
let options = NKRequestOptions(timeout: 180, taskDescription: self.global.taskDescriptionRetrievesProperties, queue: NextcloudKit.shared.nkCommonInstance.backgroundQueue)
143137

144138
let result = await searchMediaAsync(path: tblAccount.mediaPath,
145-
lessDate: lessDateAny,
146-
greaterDate: greaterDateAny,
147-
elementDate: elementDate,
139+
lessDate: lessDate,
140+
greaterDate: greaterDate,
148141
limit: limit,
149142
account: self.session.account,
150143
options: options) { task in
@@ -181,10 +174,19 @@ extension NCMedia {
181174
mediaPath: tblAccount.mediaPath,
182175
showOnlyImages: self.showOnlyImages,
183176
showOnlyVideos: self.showOnlyVideos)
184-
let predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
185-
NSPredicate(format: "datePhotosOriginal >= %@ AND datePhotosOriginal <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate),
177+
178+
var predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
179+
NSPredicate(format: "date >= %@ AND date <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate),
186180
mediaPredicate
187181
])
182+
183+
if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture {
184+
predicate = NSCompoundPredicate(andPredicateWithSubpredicates: [
185+
NSPredicate(format: "datePhotosOriginal >= %@ AND datePhotosOriginal <= %@ AND mediaSearch == true", greaterDate as NSDate, lessDate as NSDate),
186+
mediaPredicate
187+
])
188+
}
189+
188190
let localMetadatas = await self.database.getMetadatasAsync(predicate: predicate)
189191

190192
await MainActor.run {
@@ -206,22 +208,22 @@ extension NCMedia {
206208
@MainActor
207209
public class NCMediaDataSource: NSObject {
208210
public class Metadata: NSObject {
209-
let datePhotosOriginal: Date
211+
let date: Date
210212
let etag: String
211213
let imageSize: CGSize
212214
let isImage: Bool
213215
let isLivePhoto: Bool
214216
let isVideo: Bool
215217
let ocId: String
216218

217-
init(datePhotosOriginal: Date,
219+
init(date: Date,
218220
etag: String,
219221
imageSize: CGSize,
220222
isImage: Bool,
221223
isLivePhoto: Bool,
222224
isVideo: Bool,
223225
ocId: String) {
224-
self.datePhotosOriginal = datePhotosOriginal
226+
self.date = date
225227
self.etag = etag
226228
self.imageSize = imageSize
227229
self.isImage = isImage
@@ -245,7 +247,7 @@ public class NCMediaDataSource: NSObject {
245247

246248
private func insertInMetadatas(metadata: Metadata) {
247249
for i in 0..<self.metadatas.count {
248-
if (metadata.datePhotosOriginal as Date) > self.metadatas[i].datePhotosOriginal {
250+
if (metadata.date) > self.metadatas[i].date {
249251
self.metadatas.insert(metadata, at: i)
250252
return
251253
}
@@ -255,7 +257,14 @@ public class NCMediaDataSource: NSObject {
255257
}
256258

257259
private func getMetadataFromTableMetadata(_ metadata: tableMetadata) -> Metadata {
258-
return Metadata(datePhotosOriginal: metadata.datePhotosOriginal as Date,
260+
let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
261+
let date: Date
262+
if capabilities.serverVersionMajor >= self.global.nextcloudVersionFuture {
263+
date = metadata.datePhotosOriginal as Date
264+
} else {
265+
date = metadata.date as Date
266+
}
267+
return Metadata(date: date,
259268
etag: metadata.etag,
260269
imageSize: CGSize(width: metadata.width, height: metadata.height),
261270
isImage: metadata.classFile == NKTypeClassFile.image.rawValue,

‎iOSClient/NCGlobal.swift‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ final class NCGlobal: Sendable {
5252
let nextcloudVersion28: Int = 28
5353
let nextcloudVersion30: Int = 30
5454
let nextcloudVersion31: Int = 31
55+
let nextcloudVersionFuture: Int = 99999
56+
5557

5658
// Nextcloud unsupported
5759
//

‎iOSClient/NCImageCache.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ final class NCImageCache: @unchecked Sendable {
5656

5757
// MEDIA
5858
let predicate = self.getMediaPredicate(session: session, mediaPath: tblAccount.mediaPath, showOnlyImages: false, showOnlyVideos: false)
59-
guard let metadatas = await self.database.getMetadatasAsync(predicate: predicate, sortedByKeyPath: "datePhotosOriginal", limit: self.countLimit) else {
59+
guard let metadatas = await self.database.getMetadatasAsync(predicate: predicate, sortedByKeyPath: "date", limit: self.countLimit) else {
6060
return
6161
}
6262

0 commit comments

Comments
 (0)