Browse Source

Merge pull request #2112 from nextcloud/fix/441

fix activity
Marino Faggiana 2 years ago
parent
commit
a2da5aa67d

+ 1 - 1
Nextcloud.xcodeproj/project.pbxproj

@@ -3281,7 +3281,7 @@
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/nextcloud/ios-communication-library/";
 			requirement = {
-				branch = develop;
+				branch = improve/activity;
 				kind = branch;
 			};
 		};

+ 14 - 10
iOSClient/Activity/NCActivity.swift

@@ -420,11 +420,10 @@ extension NCActivity {
 
     /// Check if most recent activivities are loaded, if not trigger reload
     func checkRecentActivity(disptachGroup: DispatchGroup) {
-        let recentActivityId = NCManageDatabase.shared.getLatestActivityId(account: appDelegate.account)
-
-        guard recentActivityId > 0, metadata == nil, hasActivityToLoad else {
+        guard let result = NCManageDatabase.shared.getLatestActivityId(account: appDelegate.account), metadata == nil, hasActivityToLoad else {
             return self.loadActivity(idActivity: 0, disptachGroup: disptachGroup)
         }
+        let resultActivityId = max(result.activityFirstKnown, result.activityLastGiven)
 
         disptachGroup.enter()
 
@@ -433,25 +432,26 @@ extension NCActivity {
             limit: 1,
             objectId: nil,
             objectType: objectType,
-            previews: true) { account, activities, errorCode, _ in
+            previews: true) { account, _, activityFirstKnown, activityLastGiven, errorCode, _ in
                 defer { disptachGroup.leave() }
 
+                let largestActivityId = max(activityFirstKnown, activityLastGiven)
                 guard errorCode == 0,
                       account == self.appDelegate.account,
-                      let activity = activities.first,
-                      activity.idActivity > recentActivityId
+                      largestActivityId > resultActivityId
                 else {
                     self.hasActivityToLoad = errorCode == 304 ? false : self.hasActivityToLoad
                     return
                 }
 
-                self.loadActivity(idActivity: 0, limit: activity.idActivity - recentActivityId, disptachGroup: disptachGroup)
+                self.loadActivity(idActivity: 0, limit: largestActivityId - resultActivityId, disptachGroup: disptachGroup)
             }
     }
 
     func loadActivity(idActivity: Int, limit: Int = 200, disptachGroup: DispatchGroup) {
         guard hasActivityToLoad else { return }
 
+        var resultActivityId = 0
         disptachGroup.enter()
 
         NCCommunication.shared.getActivity(
@@ -459,7 +459,7 @@ extension NCActivity {
             limit: min(limit, 200),
             objectId: metadata?.fileId,
             objectType: objectType,
-            previews: true) { account, activities, errorCode, _ in
+            previews: true) { account, activities, activityFirstKnown, activityLastGiven, errorCode, _ in
                 defer { disptachGroup.leave() }
                 guard errorCode == 0,
                       account == self.appDelegate.account,
@@ -471,8 +471,12 @@ extension NCActivity {
                 NCManageDatabase.shared.addActivity(activities, account: account)
 
                 // update most recently loaded activity only when all activities are loaded (not filtered)
-                if self.metadata == nil {
-                    NCManageDatabase.shared.updateLatestActivityId(activities, account: account)
+                let largestActivityId = max(activityFirstKnown, activityLastGiven)
+                if let result = NCManageDatabase.shared.getLatestActivityId(account: self.appDelegate.account) {
+                    resultActivityId = max(result.activityFirstKnown, result.activityLastGiven)
+                }
+                if self.metadata == nil, largestActivityId > resultActivityId {
+                    NCManageDatabase.shared.updateLatestActivityId(activityFirstKnown: activityFirstKnown, activityLastGiven: activityLastGiven, account: account)
                 }
             }
     }

+ 5 - 7
iOSClient/Activity/NCActivityTableViewCell.swift

@@ -29,6 +29,8 @@ class NCActivityCollectionViewCell: UICollectionViewCell {
 
     @IBOutlet weak var imageView: UIImageView!
 
+    var fileId = ""
+
     override func awakeFromNib() {
         super.awakeFromNib()
     }
@@ -220,7 +222,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
                         cell.imageView.image = image
                     }
                 } else {
-                     cell.imageView.image = UIImage(named: "file")
+                     cell.imageView.image = UIImage(named: "file_photo")
                 }
             }
 
@@ -236,7 +238,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
                             cell.imageView.image = image
                         }
                     } else {
-                        cell.imageView.image = UIImage(named: "file")
+                        cell.imageView.image = UIImage(named: "file_photo")
                     }
                 }
 
@@ -254,11 +256,7 @@ extension NCActivityTableViewCell: UICollectionViewDataSource {
 
                     } else {
 
-                        NCCommunication.shared.downloadPreview(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, widthPreview: 0, heightPreview: 0, etag: nil, useInternalEndpoint: false) { _, imagePreview, _, _, _, errorCode, _ in
-                            if errorCode == 0 && imagePreview != nil {
-                                self.collectionView.reloadData()
-                            }
-                        }
+                        NCOperationQueue.shared.downloadThumbnailActivity(fileNamePathOrFileId: activityPreview.source, fileNamePreviewLocalPath: fileNamePath, fileId: fileId, cell: cell, collectionView: collectionView)
                     }
                 }
             }

+ 2 - 1
iOSClient/Data/NCDatabase.swift

@@ -134,7 +134,8 @@ class tableActivity: Object, DateCompareable {
 
 class tableActivityLatestId: Object {
     @objc dynamic var account = ""
-    @objc dynamic var mostRecentlyLoadedActivityId: Int = 0
+    @objc dynamic var activityFirstKnown: Int = 0
+    @objc dynamic var activityLastGiven: Int = 0
     override static func primaryKey() -> String {
         return "account"
     }

+ 5 - 15
iOSClient/Data/NCManageDatabase+Activity.swift

@@ -166,19 +166,14 @@ extension NCManageDatabase {
         return results
     }
 
-    @objc func updateLatestActivityId(_ activities: [NCCommunicationActivity], account: String) {
+   func updateLatestActivityId(activityFirstKnown: Int, activityLastGiven: Int, account: String) {
         let realm = try! Realm()
-        let previousRecentId = getLatestActivityId(account: account)
 
         do {
             try realm.write {
-                guard
-                    let mostRecentActivityId = activities.map({ $0.idActivity }).max(),
-                    mostRecentActivityId > previousRecentId
-                else { return }
-
                 let newRecentActivity = tableActivityLatestId()
-                newRecentActivity.mostRecentlyLoadedActivityId = mostRecentActivityId
+                newRecentActivity.activityFirstKnown = activityFirstKnown
+                newRecentActivity.activityLastGiven = activityLastGiven
                 newRecentActivity.account = account
                 realm.add(newRecentActivity, update: .all)
             }
@@ -187,15 +182,10 @@ extension NCManageDatabase {
         }
     }
 
-    @objc func getLatestActivityId(account: String) -> Int {
+    func getLatestActivityId(account: String) -> tableActivityLatestId? {
 
         let realm = try! Realm()
-        guard let maxId = realm.objects(tableActivityLatestId.self)
-                .filter("account == %@", account)
-                .map({ $0.mostRecentlyLoadedActivityId }).max()
-        else { return 0 }
-
-        return maxId
+        return realm.objects(tableActivityLatestId.self).filter("account == %@", account).first
     }
     
     // MARK: -

+ 7 - 0
iOSClient/Data/NCManageDatabase.swift

@@ -164,6 +164,13 @@ class NCManageDatabase: NSObject {
                         migration.deleteData(forType: tableTrash.className())
                     }
 
+                    if oldSchemaVersion < 237 {
+                        migration.deleteData(forType: tableActivity.className())
+                        migration.deleteData(forType: tableActivityLatestId.className())
+                        migration.deleteData(forType: tableActivityPreview.className())
+                        migration.deleteData(forType: tableActivitySubjectRich.className())
+                    }
+
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
 
                     // totalBytes refers to the size of the file on disk in bytes (data + free space)

+ 1 - 1
iOSClient/NCGlobal.swift

@@ -113,7 +113,7 @@ class NCGlobal: NSObject {
     // Database Realm
     //
     let databaseDefault                             = "nextcloud.realm"
-    let databaseSchemaVersion: UInt64               = 235
+    let databaseSchemaVersion: UInt64               = 237
 
     // Intro selector
     //

+ 123 - 59
iOSClient/Networking/NCOperationQueue.swift

@@ -37,6 +37,7 @@ import NCCommunication
     private let copyMoveQueue = Queuer(name: "copyMoveQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
     private let synchronizationQueue = Queuer(name: "synchronizationQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
     private let downloadThumbnailQueue = Queuer(name: "downloadThumbnailQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
+    private let downloadThumbnailActivityQueue = Queuer(name: "downloadThumbnailActivityQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
     private let downloadAvatarQueue = Queuer(name: "downloadAvatarQueue", maxConcurrentOperationCount: 10, qualityOfService: .default)
     private let unifiedSearchQueue = Queuer(name: "unifiedSearchQueue", maxConcurrentOperationCount: 1, qualityOfService: .default)
 
@@ -48,6 +49,7 @@ import NCCommunication
         copyMoveCancelAll()
         synchronizationCancelAll()
         downloadThumbnailCancelAll()
+        downloadThumbnailActivityCancelAll()
         downloadAvatarCancelAll()
         unifiedSearchCancelAll()
     }
@@ -55,118 +57,132 @@ import NCCommunication
     // MARK: - Download file
 
     func download(metadata: tableMetadata, selector: String) {
-        for operation in downloadQueue.operations as! [NCOperationDownload] {
-            if operation.metadata.ocId == metadata.ocId {
-                return
-            }
+        for case let operation as NCOperationDownload in downloadQueue.operations where operation.metadata.ocId == metadata.ocId {
+            return
         }
         downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: selector))
     }
-    @objc func downloadCancelAll() {
+
+    func downloadCancelAll() {
         downloadQueue.cancelAll()
     }
-    @objc func downloadQueueCount() -> Int {
+
+    func downloadQueueCount() -> Int {
         return downloadQueue.operationCount
     }
-    @objc func downloadExists(metadata: tableMetadata) -> Bool {
-        for operation in downloadQueue.operations as! [NCOperationDownload] {
-            if operation.metadata.ocId == metadata.ocId {
-                return true
-            }
+
+    func downloadExists(metadata: tableMetadata) -> Bool {
+        for case let operation as NCOperationDownload in downloadQueue.operations where operation.metadata.ocId == metadata.ocId {
+            return true
         }
         return false
     }
 
     // MARK: - Delete file
 
-    @objc func delete(metadata: tableMetadata, onlyLocalCache: Bool) {
+    func delete(metadata: tableMetadata, onlyLocalCache: Bool) {
 
         let isFolderEncrypted = CCUtility.isFolderEncrypted(metadata.serverUrl, e2eEncrypted: metadata.e2eEncrypted, account: metadata.account, urlBase: metadata.urlBase)
         if isFolderEncrypted {
-            for operation in deleteQueueE2EE.operations as! [NCOperationDelete] {
-                if operation.metadata.ocId == metadata.ocId {
-                    return
-                }
+            for case let operation as NCOperationDelete in deleteQueueE2EE.operations where operation.metadata.ocId == metadata.ocId {
+                return
             }
             deleteQueueE2EE.addOperation(NCOperationDelete(metadata: metadata, onlyLocalCache: onlyLocalCache))
         } else {
-            for operation in deleteQueue.operations as! [NCOperationDelete] {
-                if operation.metadata.ocId == metadata.ocId {
-                    return
-                }
+            for case let operation as NCOperationDelete in deleteQueue.operations where operation.metadata.ocId == metadata.ocId {
+                return
             }
             deleteQueue.addOperation(NCOperationDelete(metadata: metadata, onlyLocalCache: onlyLocalCache))
         }
     }
 
-    @objc func deleteCancelAll() {
+    func deleteCancelAll() {
         deleteQueue.cancelAll()
     }
 
     // MARK: - Copy Move file
 
-    @objc func copyMove(metadata: tableMetadata, serverUrl: String, overwrite: Bool, move: Bool) {
-        for operation in copyMoveQueue.operations as! [NCOperationCopyMove] {
-            if operation.metadata.ocId == metadata.ocId {
-                return
-            }
+    func copyMove(metadata: tableMetadata, serverUrl: String, overwrite: Bool, move: Bool) {
+        for case let operation as NCOperationCopyMove in copyMoveQueue.operations where operation.metadata.ocId == metadata.ocId {
+            return
         }
         copyMoveQueue.addOperation(NCOperationCopyMove(metadata: metadata, serverUrlTo: serverUrl, overwrite: overwrite, move: move))
     }
-    @objc func copyMoveCancelAll() {
+
+    func copyMoveCancelAll() {
         copyMoveQueue.cancelAll()
     }
 
     // MARK: - Synchronization
 
-    @objc func synchronizationMetadata(_ metadata: tableMetadata, selector: String) {
-        for operation in synchronizationQueue.operations as! [NCOperationSynchronization] {
-            if operation.metadata.ocId == metadata.ocId {
-                return
-            }
+    func synchronizationMetadata(_ metadata: tableMetadata, selector: String) {
+        for case let operation as NCOperationSynchronization in synchronizationQueue.operations where operation.metadata.ocId == metadata.ocId {
+            return
         }
         synchronizationQueue.addOperation(NCOperationSynchronization(metadata: metadata, selector: selector))
     }
-    @objc func synchronizationCancelAll() {
+
+    func synchronizationCancelAll() {
         synchronizationQueue.cancelAll()
     }
 
     // MARK: - Download Thumbnail
 
-    @objc func downloadThumbnail(metadata: tableMetadata, placeholder: Bool, cell: UIView?, view: UIView?) {
+    func downloadThumbnail(metadata: tableMetadata, placeholder: Bool, cell: UIView?, view: UIView?) {
 
         let cell: NCCellProtocol? = cell as? NCCellProtocol
 
         if placeholder {
-            if metadata.iconName.count > 0 {
-                cell?.filePreviewImageView?.image = UIImage(named: metadata.iconName)
-            } else {
+            if metadata.iconName.isEmpty {
                 cell?.filePreviewImageView?.image = NCBrandColor.cacheImages.file
+            } else {
+                cell?.filePreviewImageView?.image = UIImage(named: metadata.iconName)
             }
         }
 
         if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && (!CCUtility.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag)) {
-            for operation in downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] {
-                if operation.metadata.ocId == metadata.ocId {
-                    return
-                }
+            for case let operation as NCOperationDownloadThumbnail in downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId {
+                return
             }
             downloadThumbnailQueue.addOperation(NCOperationDownloadThumbnail(metadata: metadata, cell: cell, view: view))
         }
     }
 
     func cancelDownloadThumbnail(metadata: tableMetadata) {
-        for operation in  downloadThumbnailQueue.operations as! [NCOperationDownloadThumbnail] {
-            if operation.metadata.ocId == metadata.ocId {
-                operation.cancel()
-            }
+        for case let operation as NCOperationDownloadThumbnail in downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId {
+            operation.cancel()
         }
     }
 
-    @objc func downloadThumbnailCancelAll() {
+    func downloadThumbnailCancelAll() {
         downloadThumbnailQueue.cancelAll()
     }
 
+    // MARK: - Download Thumbnail Activity
+
+    func downloadThumbnailActivity(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell, collectionView: UICollectionView?) {
+
+        cell.imageView?.image = UIImage(named: "file_photo")
+        cell.fileId = fileId
+
+        if !FileManager.default.fileExists(atPath: fileNamePreviewLocalPath) {
+            for case let operation as NCOperationDownloadThumbnailActivity in downloadThumbnailActivityQueue.operations where operation.fileId == fileId {
+                return
+            }
+            downloadThumbnailActivityQueue.addOperation(NCOperationDownloadThumbnailActivity(fileNamePathOrFileId: fileNamePathOrFileId, fileNamePreviewLocalPath: fileNamePreviewLocalPath, fileId: fileId, cell: cell, collectionView: collectionView))
+        }
+    }
+
+    func cancelDownloadThumbnailActivity(fileId: String) {
+        for case let operation as NCOperationDownloadThumbnailActivity in downloadThumbnailActivityQueue.operations where operation.fileId == fileId {
+            operation.cancel()
+        }
+    }
+
+    func downloadThumbnailActivityCancelAll() {
+        downloadThumbnailActivityQueue.cancelAll()
+    }
+
     // MARK: - Download Avatar
 
     func downloadAvatar(user: String, dispalyName: String?, fileName: String, cell: NCCellProtocol, view: UIView?, cellImageView: UIImageView?) {
@@ -186,23 +202,19 @@ import NCCommunication
                    userBaseUrl: account)
         }
 
-        for operation in downloadAvatarQueue.operations as! [NCOperationDownloadAvatar] {
-            if operation.fileName == fileName {
-                return
-            }
+        for case let operation as NCOperationDownloadAvatar in downloadAvatarQueue.operations where operation.fileName == fileName {
+            return
         }
         downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: user, fileName: fileName, fileNameLocalPath: fileNameLocalPath, cell: cell, view: view, cellImageView: cellImageView))
     }
 
     func cancelDownloadAvatar(user: String) {
-        for operation in  downloadAvatarQueue.operations as! [NCOperationDownloadAvatar] {
-            if operation.user == user {
-                operation.cancel()
-            }
+        for case let operation as NCOperationDownloadAvatar in downloadAvatarQueue.operations where operation.user == user {
+            operation.cancel()
         }
     }
 
-    @objc func downloadAvatarCancelAll() {
+    func downloadAvatarCancelAll() {
         downloadAvatarQueue.cancelAll()
     }
 
@@ -212,7 +224,7 @@ import NCCommunication
         unifiedSearchQueue.addOperation(NCOperationUnifiedSearch.init(collectionViewCommon: collectionViewCommon, metadatas: metadatas, searchResult: searchResult))
     }
 
-    @objc func unifiedSearchCancelAll() {
+    func unifiedSearchCancelAll() {
         unifiedSearchQueue.cancelAll()
     }
 }
@@ -418,9 +430,9 @@ class NCOperationDownloadThumbnail: ConcurrentOperation {
     var metadata: tableMetadata
     var cell: NCCellProtocol?
     var view: UIView?
-    var fileNamePath: String = ""
-    var fileNamePreviewLocalPath: String = ""
-    var fileNameIconLocalPath: String = ""
+    var fileNamePath: String
+    var fileNamePreviewLocalPath: String
+    var fileNameIconLocalPath: String
 
     init(metadata: tableMetadata, cell: NCCellProtocol?, view: UIView?) {
         self.metadata = tableMetadata.init(value: metadata)
@@ -477,6 +489,58 @@ class NCOperationDownloadThumbnail: ConcurrentOperation {
 
 // MARK: -
 
+class NCOperationDownloadThumbnailActivity: ConcurrentOperation {
+
+    var cell: NCActivityCollectionViewCell?
+    var collectionView: UICollectionView?
+    var fileNamePathOrFileId: String
+    var fileNamePreviewLocalPath: String
+    var fileId: String
+
+    init(fileNamePathOrFileId: String, fileNamePreviewLocalPath: String, fileId: String, cell: NCActivityCollectionViewCell?, collectionView: UICollectionView?) {
+        self.fileNamePathOrFileId = fileNamePathOrFileId
+        self.fileNamePreviewLocalPath = fileNamePreviewLocalPath
+        self.fileId = fileId
+        self.cell = cell
+        self.collectionView = collectionView
+    }
+
+    override func start() {
+
+        if isCancelled {
+            self.finish()
+        } else {
+
+            NCCommunication.shared.downloadPreview(
+                fileNamePathOrFileId: fileNamePathOrFileId,
+                fileNamePreviewLocalPath: fileNamePreviewLocalPath,
+                widthPreview: 0,
+                heightPreview: 0,
+                etag: nil,
+                useInternalEndpoint: false,
+                queue: NCCommunicationCommon.shared.backgroundQueue) { _, imagePreview, _, _, _, errorCode, _ in
+
+                    if errorCode == 0, let imagePreview = imagePreview {
+                        DispatchQueue.main.async {
+                            if self.fileId == self.cell?.fileId, let imageView = self.cell?.imageView {
+                                UIView.transition(with: imageView,
+                                                  duration: 0.75,
+                                                  options: .transitionCrossDissolve,
+                                                  animations: { imageView.image = imagePreview },
+                                                  completion: nil)
+                            } else {
+                                self.collectionView?.reloadData()
+                            }
+                        }
+                    }
+                    self.finish()
+                }
+        }
+    }
+}
+
+// MARK: -
+
 class NCOperationDownloadAvatar: ConcurrentOperation {
 
     var user: String