Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
150 commits
Select commit Hold shift + click to select a range
25d8e85
Refactor media viewer paging and playback architecture
marinofaggiana May 22, 2026
af48bc0
Refactor media viewer comments
marinofaggiana May 22, 2026
2a0175e
Clean up media viewer helpers
marinofaggiana May 22, 2026
7ca1519
Refactor the media viewer paging and playback architecture.
marinofaggiana May 23, 2026
bd8fe9b
Remove video playback fallback timeout
marinofaggiana May 24, 2026
7587bfb
Update NCVideoPlaybackController.swift
marinofaggiana May 24, 2026
ecd5053
cleaning
marinofaggiana May 24, 2026
c566818
Isolate video progress control area
marinofaggiana May 25, 2026
6166ec7
Guard paging index updates during layout changes
marinofaggiana May 25, 2026
e5a3951
Reduce media viewer loader logs
marinofaggiana May 25, 2026
c36a120
Remove media viewer failed download overlay
marinofaggiana May 25, 2026
c7539d0
cleaning messagge internal log
marinofaggiana May 25, 2026
9fc1b8a
lint
marinofaggiana May 25, 2026
62d886f
Enable VisionKit only for full images
marinofaggiana May 25, 2026
ece7a76
Pass audio preview to audio viewer
marinofaggiana May 25, 2026
8e49e08
Avoid standalone preview for audio pages
marinofaggiana May 25, 2026
6242678
Audio GUI improvements
marinofaggiana May 25, 2026
d311864
cleaning code
marinofaggiana May 26, 2026
e90892d
Add fullscreen video transition overlay
marinofaggiana May 26, 2026
a2332e8
Reduce media loader optional-path logs
marinofaggiana May 26, 2026
c617bcc
Remove unused media viewer loader error
marinofaggiana May 26, 2026
1b0875e
cleaning
marinofaggiana May 26, 2026
7f2e30b
Lighten media detail value styling
marinofaggiana May 27, 2026
4ebe158
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana May 27, 2026
b505b24
Fix cached video routing and clean media viewer details
marinofaggiana May 27, 2026
4ad6341
Preserve local URL during video prefetch
marinofaggiana May 27, 2026
055dcdc
Hide video resolver errors from logs and UI
marinofaggiana May 27, 2026
86db0eb
Clean video playback VLC fallback
marinofaggiana May 27, 2026
fc8d5db
source improvements
marinofaggiana May 27, 2026
b9cbaf7
cleaning
marinofaggiana May 27, 2026
0a26743
rename class
marinofaggiana May 27, 2026
a0abfc5
cleaning source
marinofaggiana May 27, 2026
8c60add
Fix AVPlayer controls after PiP return
marinofaggiana May 27, 2026
e52c2c4
Protect slider from page swipe gestures
marinofaggiana May 27, 2026
175f0ab
Remove swipe inhibition logic
marinofaggiana May 27, 2026
88822a4
fix
marinofaggiana May 27, 2026
e6da6cd
Improve video controls scrub handling
marinofaggiana May 27, 2026
8282e9c
Clean up unused video controls
marinofaggiana May 27, 2026
02dd9ad
Constrain - close pan gesture filtering
marinofaggiana May 27, 2026
487c1e5
Media viewer: refine video playback cover and chrome-aware background…
marinofaggiana May 29, 2026
8f3fc45
Media viewer: refine video playback cover and chrome-aware background…
marinofaggiana May 29, 2026
d4d3135
Documentation
marinofaggiana May 29, 2026
c4118f3
clean
marinofaggiana May 29, 2026
c1f5c9a
Remove artificial video selection debounce before preparing playback
marinofaggiana May 29, 2026
91ebb8e
fix autolpay button state
marinofaggiana May 29, 2026
497b220
Align VLC play pause button state with requested playback state
marinofaggiana May 29, 2026
a5ac7fb
fix color
marinofaggiana May 29, 2026
4f878a9
fix
marinofaggiana May 29, 2026
10609bc
close fix
marinofaggiana May 29, 2026
3088c67
Video Playback Engine
marinofaggiana May 29, 2026
352643f
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana May 29, 2026
a00f01e
fix
marinofaggiana May 29, 2026
f248165
fix
marinofaggiana May 30, 2026
0691d4c
Prefetch local audio pages before selection
marinofaggiana May 30, 2026
cfb1f71
cleaning
marinofaggiana May 30, 2026
e1c3841
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana May 30, 2026
d8cbf2f
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana May 31, 2026
db8411b
AirPlay
marinofaggiana May 31, 2026
ee2f438
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 3, 2026
42ad8cc
presentViewController
marinofaggiana Jun 3, 2026
ce4bb4f
share
marinofaggiana Jun 3, 2026
4eb8044
share - sender
marinofaggiana Jun 3, 2026
01a5d3d
controls glass
marinofaggiana Jun 4, 2026
8ddd66c
glass
marinofaggiana Jun 4, 2026
a3f17eb
color controls
marinofaggiana Jun 4, 2026
017c073
color
marinofaggiana Jun 4, 2026
fe5a046
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 6, 2026
8f18ef0
glass
marinofaggiana Jun 6, 2026
082c453
glass
marinofaggiana Jun 6, 2026
557f8b9
NCMediaViewerThumbnail
marinofaggiana Jun 8, 2026
1e95400
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 8, 2026
8dfbfe2
Remove permanent failed metadata tracking from thumbnail strip
marinofaggiana Jun 8, 2026
5c5a213
added queue
marinofaggiana Jun 8, 2026
81bfb09
Recenter thumbnail strip after bounds changes
marinofaggiana Jun 8, 2026
5b65bc3
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 8, 2026
352a9af
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 9, 2026
afdd444
cleaning
marinofaggiana Jun 9, 2026
908a014
Add subtle haptic feedback while scrolling thumbnails
marinofaggiana Jun 9, 2026
eccdf04
Add external image analysis control to image viewer content
marinofaggiana Jun 9, 2026
c0e6573
Handle missing thumbnail metadata with broken-image placeholder
marinofaggiana Jun 9, 2026
964a065
Remove failed metadata thumbnail blocking
marinofaggiana Jun 9, 2026
1cc410b
chenge color
marinofaggiana Jun 9, 2026
9b1efca
Use loader-backed preview URL for thumbnails
marinofaggiana Jun 10, 2026
d495a54
refreshThumbnailIfVisible
marinofaggiana Jun 10, 2026
6d0ac48
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 10, 2026
73e283a
Update audio viewer background handling
marinofaggiana Jun 10, 2026
f0125ab
WIP
mpivchev Jun 10, 2026
0619bb6
Detail view design improvements
mpivchev Jun 10, 2026
11e9ca7
Improvements
mpivchev Jun 10, 2026
a1e4c4f
Refactor
mpivchev Jun 10, 2026
e0efe35
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 11, 2026
7ff8a09
Clean up Live Photo media download flow
marinofaggiana Jun 11, 2026
44afac0
mediaDownload improvements
marinofaggiana Jun 14, 2026
2f91c08
Update NCNextcloudMediaViewerLoader.swift
marinofaggiana Jun 14, 2026
b504273
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 15, 2026
18dcaa0
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 15, 2026
565cfce
menu
marinofaggiana Jun 16, 2026
fb69a72
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 17, 2026
6a46c12
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 17, 2026
b8bb2ab
reload
marinofaggiana Jun 17, 2026
5dee885
reload
marinofaggiana Jun 17, 2026
7d28178
menu
marinofaggiana Jun 17, 2026
0b71663
wip
marinofaggiana Jun 17, 2026
2bb6e23
cod
marinofaggiana Jun 17, 2026
1df5287
refactory
marinofaggiana Jun 17, 2026
7193af6
menu
marinofaggiana Jun 17, 2026
cc7c91a
lint
marinofaggiana Jun 17, 2026
8954e9c
test
marinofaggiana Jun 17, 2026
71e5fee
test
marinofaggiana Jun 17, 2026
921d71c
test
marinofaggiana Jun 17, 2026
6e52ef0
test
marinofaggiana Jun 17, 2026
f67d66b
test
marinofaggiana Jun 17, 2026
70ce4a9
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 18, 2026
8a2fcff
Placeholders
marinofaggiana Jun 18, 2026
c2f2493
Placeholders
marinofaggiana Jun 18, 2026
e367add
Placeholders
marinofaggiana Jun 18, 2026
adff694
Placeholders
marinofaggiana Jun 18, 2026
39ea4cb
placeholder
marinofaggiana Jun 18, 2026
1a2172f
Placeholders
marinofaggiana Jun 18, 2026
b3783fa
cleaning
marinofaggiana Jun 18, 2026
8a9240f
cleaning
marinofaggiana Jun 18, 2026
c9be04b
improved
marinofaggiana Jun 18, 2026
76c585e
placeholder
marinofaggiana Jun 18, 2026
1a94617
placeholder
marinofaggiana Jun 18, 2026
7607166
Placeholder
marinofaggiana Jun 18, 2026
91c68be
placeholder
marinofaggiana Jun 18, 2026
ad33b14
placeholder
marinofaggiana Jun 18, 2026
d57e1e7
placeholder
marinofaggiana Jun 19, 2026
9118dbd
cleaning
marinofaggiana Jun 19, 2026
96919fb
refact
marinofaggiana Jun 19, 2026
6e95f46
refact
marinofaggiana Jun 19, 2026
b2aa8a5
refactor
marinofaggiana Jun 19, 2026
05f3b4d
refactor
marinofaggiana Jun 19, 2026
9d6daff
fix
marinofaggiana Jun 19, 2026
d7c5dd7
cleaning
marinofaggiana Jun 19, 2026
d22570d
improved
marinofaggiana Jun 19, 2026
ccbdef5
clean
marinofaggiana Jun 19, 2026
07578af
fix
marinofaggiana Jun 19, 2026
38bcb22
cleaning
marinofaggiana Jun 19, 2026
23f3117
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 19, 2026
8a554bc
rename
marinofaggiana Jun 19, 2026
6d75b8e
Update NCMediaViewerHostingController.swift
marinofaggiana Jun 19, 2026
cbe4076
refactor
marinofaggiana Jun 20, 2026
a85c0d8
refactor
marinofaggiana Jun 20, 2026
28b7614
lint
marinofaggiana Jun 20, 2026
cee3005
Share - update metadata
marinofaggiana Jun 20, 2026
2940abd
Merge remote-tracking branch 'origin/master' into MediaViewer
marinofaggiana Jun 20, 2026
43eec51
Update metadata placeholder
marinofaggiana Jun 20, 2026
95d486e
improved
marinofaggiana Jun 20, 2026
0a6dc1d
rename class
marinofaggiana Jun 20, 2026
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
2 changes: 1 addition & 1 deletion Brand/Database.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ import Foundation
//
let databaseName = "nextcloud.realm"
let tableAccountBackup = "tableAccountBackup.json"
let databaseSchemaVersion: UInt64 = 409
let databaseSchemaVersion: UInt64 = 410
276 changes: 219 additions & 57 deletions Nextcloud.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

7 changes: 3 additions & 4 deletions iOSClient/Data/NCManageDatabase+CreateMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import NextcloudKit
import Photos

final class NCManageDatabaseCreateMetadata {
func convertFileToMetadataAsync(_ file: NKFile, mediaSearch: Bool = false, isDirectoryE2EE: Bool? = nil) async -> tableMetadata {
func convertFileToMetadataAsync(_ file: NKFile, isDirectoryE2EE: Bool? = nil) async -> tableMetadata {
let metadata = self.createMetadata(file)
let e2eEncryptedDirectory: Bool
if let value = isDirectoryE2EE {
Expand Down Expand Up @@ -40,7 +40,6 @@ final class NCManageDatabaseCreateMetadata {
metadata.iconName = results.iconName
metadata.classFile = results.classFile
metadata.typeIdentifier = results.typeIdentifier
metadata.mediaSearch = mediaSearch
}

return metadata.detachedCopy()
Expand Down Expand Up @@ -76,7 +75,7 @@ final class NCManageDatabaseCreateMetadata {
completion(metadata)
}

func convertFilesToMetadatasAsync(_ files: [NKFile], serverUrlMetadataFolder: String? = nil, mediaSearch: Bool = false) async -> (metadataFolder: tableMetadata, metadatas: [tableMetadata]) {
func convertFilesToMetadatasAsync(_ files: [NKFile], serverUrlMetadataFolder: String? = nil) async -> (metadataFolder: tableMetadata, metadatas: [tableMetadata]) {
var counter: Int = 0
var isDirectoryE2EE: Bool = false
var listServerUrl: [String: Bool] = [:]
Expand All @@ -93,7 +92,7 @@ final class NCManageDatabaseCreateMetadata {
}
#endif

let metadata = await convertFileToMetadataAsync(file, mediaSearch: mediaSearch, isDirectoryE2EE: isDirectoryE2EE)
let metadata = await convertFileToMetadataAsync(file, isDirectoryE2EE: isDirectoryE2EE)

if serverUrlMetadataFolder == metadata.serverUrlFileName || metadata.fileName == NextcloudKit.shared.nkCommonInstance.rootFileName {
metadataFolder = metadata
Expand Down
219 changes: 181 additions & 38 deletions iOSClient/Data/NCManageDatabase+Metadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class tableMetadata: Object {
@objc public var lockOwnerDisplayName = ""
@objc public var lockTime: Date?
@objc public var lockTimeOut: Date?
@objc dynamic var mediaSearch: Bool = false
@objc dynamic var placeholder: Bool = false
@objc dynamic var path = ""
@objc dynamic var permissions = ""
@objc dynamic var placePhotos: String?
Expand Down Expand Up @@ -696,46 +696,51 @@ extension NCManageDatabase {
}
}

/// Asynchronously updates a list of `tableMetadata` entries in Realm for a given account and server URL.
/// Asynchronously refreshes the `tableMetadata` entries stored in Realm for the specified account and server URL.
///
/// This function performs the following steps:
/// 1. Skips all entries with `status != metadataStatusNormal`.
/// 2. Deletes existing metadata entries with `status == metadataStatusNormal` that are not in the skip list.
/// 3. Copies matching `mediaSearch` from previously deleted metadata to the incoming list.
/// 4. Inserts or updates new metadata entries into Realm, except those in the skip list.
/// 1. Collects all metadata entries with `status != metadataStatusNormal` and protects them from refresh.
/// 2. Deletes existing normal metadata entries for the specified account and server URL, excluding the root entry.
/// 3. Skips incoming metadata entries whose `ocId` belongs to a protected non-normal metadata entry.
/// 4. Inserts or updates the remaining incoming metadata entries into Realm.
///
/// - Parameters:
/// - metadatas: An array of incoming detached `tableMetadata` objects to insert or update.
/// - serverUrl: The server URL associated with the metadata entries.
/// - account: The account identifier used to scope the metadata update.
func updateMetadatasFilesAsync(_ metadatas: [tableMetadata], serverUrl: String, account: String) async {
/// - serverUrl: The server URL used to scope the metadata refresh.
/// - account: The account identifier used to scope the metadata refresh.
func updateMetadatasFilesAsync(
_ metadatas: [tableMetadata],
serverUrl: String,
account: String
) async {
await core.performRealmWriteAsync { realm in
// Collect metadata currently involved in non-normal operations.
// These entries must not be deleted or overwritten by the refresh.
let ocIdsToSkip = Set(
realm.objects(tableMetadata.self)
.filter("status != %d", NCGlobal.shared.metadataStatusNormal)
.map(\.ocId)
)

// Delete current normal metadata for this account and server URL,
// excluding the root entry and protected non-normal entries.
let resultsToDelete = realm.objects(tableMetadata.self)
.filter("account == %@ AND serverUrl == %@ AND status == %d AND fileName != %@", account, serverUrl, NCGlobal.shared.metadataStatusNormal, NextcloudKit.shared.nkCommonInstance.rootFileName)
.filter(
"account == %@ AND serverUrl == %@ AND status == %d AND fileName != %@",
account,
serverUrl,
NCGlobal.shared.metadataStatusNormal,
NextcloudKit.shared.nkCommonInstance.rootFileName
)
.filter { !ocIdsToSkip.contains($0.ocId) }

// Cache mediaSearch (and anything else needed) before deletion, keyed by ocId.
let metadatasByOcId: [String: tableMetadata] = Dictionary(
uniqueKeysWithValues: resultsToDelete.map { object in
(object.ocId, tableMetadata(value: object))
}
)

realm.delete(resultsToDelete)

// Insert the refreshed metadata list, skipping protected entries.
for metadata in metadatas {
guard !ocIdsToSkip.contains(metadata.ocId) else {
continue
}
if let previous = metadatasByOcId[metadata.ocId] {
metadata.mediaSearch = previous.mediaSearch
}

realm.add(metadata.detachedCopy(), update: .all)
}
Expand Down Expand Up @@ -846,34 +851,109 @@ extension NCManageDatabase {
}
}

/// Syncs the remote and local metadata.
/// Returns true if there were changes (additions or deletions), false if everything was already up-to-date.
func mergeRemoteMetadatasAsync(remoteMetadatas: [tableMetadata], localMetadatas: [tableMetadata]) async -> Bool {
// Set of ocId
let remoteOcIds = Set(remoteMetadatas.map { $0.ocId })
let localOcIds = Set(localMetadatas.map { $0.ocId })
func syncPlaceholderMetadatasAsync(
files: [NKFile],
metadatas: [tableMetadata]
) async -> (inserted: Int, updated: Int, deleted: [tableMetadata]) {
guard !files.isEmpty else {
return (0, 0, [])
}

// Build lookup maps for fast diffing.
// Using merge strategy avoids crashes when duplicated ocIds are present.
let filesByOcId: [String: NKFile] = Dictionary(
files.map { ($0.ocId, $0) },
uniquingKeysWith: { _, new in new }
)

// Store detached copies because returned metadata objects must remain usable
// outside the Realm lifecycle.
let metadatasByOcId: [String: tableMetadata] = Dictionary(
metadatas.map { ($0.ocId, $0.detachedCopy()) },
uniquingKeysWith: { _, new in new }
)

let fileOcIds = Set(filesByOcId.keys)
let metadataOcIds = Set(metadatasByOcId.keys)

// INSERT: Remote files that are not present in the local date-window metadata list.
let toInsertOcIds = fileOcIds.subtracting(metadataOcIds)

// DELETE CANDIDATES: Local metadata entries that are no longer present
// in the current remote date-window result.
// They are returned to the caller and must be validated/deleted outside this function.
let toDeleteOcIds = metadataOcIds.subtracting(fileOcIds)

let deletedMetadatas: [tableMetadata] = toDeleteOcIds.compactMap { ocId in
metadatasByOcId[ocId]
}

// UPDATE: Existing placeholder metadata entries whose etag changed.
let toUpdateOcIds: [String] = Array(fileOcIds.intersection(metadataOcIds)).filter { ocId in
guard let file = filesByOcId[ocId],
let metadata = metadatasByOcId[ocId] else {
return false
}

return file.etag != metadata.etag
}

// Calculate diffs
let toDeleteOcIds = localOcIds.subtracting(remoteOcIds)
let toAddOcIds = remoteOcIds.subtracting(localOcIds)
let hasChanges = !toInsertOcIds.isEmpty ||
!toUpdateOcIds.isEmpty

guard !toDeleteOcIds.isEmpty || !toAddOcIds.isEmpty else {
return false // No changes needed
guard hasChanges else {
return (
inserted: 0,
updated: 0,
deleted: deletedMetadatas
)
}

let toDeleteKeys = Array(toDeleteOcIds)
let createMetadata = NCManageDatabaseCreateMetadata()

await core.performRealmWriteAsync { realm in
let toAdd = remoteMetadatas.filter { toAddOcIds.contains($0.ocId) }
let toDelete = toDeleteKeys.compactMap {
realm.object(ofType: tableMetadata.self, forPrimaryKey: $0)
// MODIFY: Update lightweight fields for existing placeholder metadata entries.
if !toUpdateOcIds.isEmpty {
let resultsToModify = realm.objects(tableMetadata.self)
.filter("ocId IN %@", Array(toUpdateOcIds))

for metadata in resultsToModify {
guard let file = filesByOcId[metadata.ocId] else {
continue
}

metadata.etag = file.etag
metadata.date = file.date as NSDate

if let date = file.creationDate as? NSDate {
metadata.creationDate = date
}
}
}

realm.delete(toDelete)
realm.add(toAdd, update: .modified)
// INSERT: Add placeholder metadata entries for files not currently present in the local date-window metadata list.
if !toInsertOcIds.isEmpty {
let insertedMetadatas: [tableMetadata] = toInsertOcIds.compactMap { ocId in
guard let file = filesByOcId[ocId] else {
return nil
}

let metadata = createMetadata.createMetadata(file)
metadata.placeholder = true
return metadata
}

if !insertedMetadatas.isEmpty {
realm.add(insertedMetadatas, update: .modified)
}
}
}

return true
return (
inserted: toInsertOcIds.count,
updated: toUpdateOcIds.count,
deleted: deletedMetadatas
)
}

// MARK: - Realm Read
Expand Down Expand Up @@ -1014,6 +1094,31 @@ extension NCManageDatabase {
} ?? []
}

/// Returns the ocIds that do not have a matching `tableMetadata` object in the local Realm database.
///
/// - Parameter ocIds: The ocId strings to verify against the local Realm database.
/// - Returns: A set containing the ocIds that were not found locally. Returns an empty set when all ocIds exist locally.
func getMissingLocalMetadataOcIdsAsync(_ ocIds: [String]) async -> Set<String> {
let requestedOcIds = Set(ocIds)

guard !requestedOcIds.isEmpty else {
return []
}

let existingOcIdsArray: [String] = await core.performRealmReadAsync { realm in
let results = realm.objects(tableMetadata.self)
.where {
$0.ocId.in(Array(requestedOcIds))
}

return Array(results.map { $0.ocId })
} ?? []

let existingOcIds = Set(existingOcIdsArray)

return requestedOcIds.subtracting(existingOcIds)
}

func getMetadataFromOcIdAndocIdTransferAsync(_ ocId: String?) async -> tableMetadata? {
guard let ocId else {
return nil
Expand Down Expand Up @@ -1067,6 +1172,24 @@ extension NCManageDatabase {
}
}

/// Returns `true` if at least one metadata entry for the specified account and server URL is marked as placeholder.
///
/// - Parameters:
/// - account: The account identifier used to scope the metadata lookup.
/// - serverUrl: The server URL used to scope the metadata lookup.
/// - Returns: `true` if at least one matching placeholder metadata exists; otherwise `false`.
func getMetadataFolderPlaceholderAsync(account: String, serverUrl: String) async -> Bool {
return await core.performRealmReadAsync { realm in
!realm.objects(tableMetadata.self)
.filter(
"account == %@ AND serverUrl == %@ AND placeholder == true",
account,
serverUrl
)
.isEmpty
} ?? false
}

func getMetadataLivePhoto(metadata: tableMetadata) -> tableMetadata? {
guard metadata.isLivePhoto else {
return nil
Expand Down Expand Up @@ -1371,6 +1494,26 @@ extension NCManageDatabase {
} ?? 0
}

/// Returns only the ocIds that still have a matching metadata row in Realm.
///
/// - Parameter ocIds: Candidate media ocIds used by the media viewer.
/// - Returns: Valid ocIds preserving the original input order.
func getValidMetadataOcIdsAsync(_ ocIds: [String]) async -> [String] {
guard !ocIds.isEmpty else {
return []
}

return await core.performRealmReadAsync { realm in
let existingOcIds = Set(
realm.objects(tableMetadata.self)
.filter("ocId IN %@", ocIds)
.map(\.ocId)
)

return ocIds.filter { existingOcIds.contains($0) }
} ?? []
}

func metadataExistsAsync(predicate: NSPredicate) async -> Bool {
await core.performRealmReadAsync { realm in
realm.objects(tableMetadata.self)
Expand Down
1 change: 0 additions & 1 deletion iOSClient/Data/NCMetadataTranfersSuccess.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ actor NCMetadataTranfersSuccess {
etag: String?,
ownerId: String? = nil,
permissions: String? = nil) async {
let status = metadata.status
metadata.ocId = ocId
metadata.uploadDate = (date as? NSDate) ?? NSDate()
metadata.etag = etag ?? ""
Expand Down
Loading
Loading