Marino Faggiana 1 سال پیش
والد
کامیت
cc5e176cce
54فایلهای تغییر یافته به همراه713 افزوده شده و 809 حذف شده
  1. 0 4
      .swiftlint.yml
  2. 32 30
      Nextcloud.xcodeproj/project.pbxproj
  3. 29 3
      Share/NCShareExtension+DataSource.swift
  4. 1 15
      Share/NCShareExtension+NCDelegate.swift
  5. 1 4
      Share/NCShareExtension.swift
  6. 0 129
      iOSClient/EmptyView/NCEmptyDataSet.swift
  7. 0 71
      iOSClient/EmptyView/NCEmptyView.xib
  8. 2 2
      iOSClient/Favorites/NCFavorite.swift
  9. 2 2
      iOSClient/Files/NCFiles.swift
  10. 2 2
      iOSClient/Groupfolders/NCGroupfolders.swift
  11. 0 9
      iOSClient/Images.xcassets/Image.imageset/Contents.json
  12. 0 10
      iOSClient/Images.xcassets/Image.imageset/folder_link.svg
  13. 0 0
      iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift
  14. 0 0
      iOSClient/Main/Collection Common/Cell/NCGridCell.swift
  15. 8 0
      iOSClient/Main/Collection Common/Cell/NCGridCell.xib
  16. 0 0
      iOSClient/Main/Collection Common/Cell/NCListCell.swift
  17. 0 0
      iOSClient/Main/Collection Common/Cell/NCListCell.xib
  18. 63 56
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  19. 0 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionFooter.xib
  20. 0 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeader.xib
  21. 113 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderEmptyData.swift
  22. 127 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderEmptyData.xib
  23. 0 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.swift
  24. 0 0
      iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.xib
  25. 8 18
      iOSClient/Main/NCMainTabBar.swift
  26. 4 30
      iOSClient/Media/Cell/NCGridMediaCell.swift
  27. 0 11
      iOSClient/Media/Cell/NCGridMediaCell.xib
  28. 2 3
      iOSClient/Media/NCMedia+Command.swift
  29. 50 31
      iOSClient/Media/NCMedia.swift
  30. 2 2
      iOSClient/Media/NCMediaDataSource.swift
  31. 1 1
      iOSClient/Media/NCMediaDownloadThumbnaill.swift
  32. 11 0
      iOSClient/Media/NCMediaLayout.swift
  33. 12 2
      iOSClient/NCGlobal.swift
  34. 1 1
      iOSClient/Networking/E2EE/NCEndToEndMetadata.swift
  35. 64 74
      iOSClient/Networking/NCNetworkingProcess.swift
  36. 0 1
      iOSClient/Networking/NCService.swift
  37. 1 22
      iOSClient/Notification/NCNotification.swift
  38. 4 2
      iOSClient/Offline/NCOffline.swift
  39. 10 3
      iOSClient/PrivacyInfo.xcprivacy
  40. 2 2
      iOSClient/Recent/NCRecent.swift
  41. 0 4
      iOSClient/Rename file/NCRenameFile.swift
  42. 41 47
      iOSClient/Select/NCSelect.swift
  43. 2 2
      iOSClient/Shares/NCShares.swift
  44. BIN
      iOSClient/Supporting Files/de.lproj/Localizable.strings
  45. BIN
      iOSClient/Supporting Files/eu.lproj/Localizable.strings
  46. BIN
      iOSClient/Supporting Files/ru.lproj/Localizable.strings
  47. 10 17
      iOSClient/Transfers/NCTransfers.swift
  48. 59 0
      iOSClient/Trash/Cell/NCTrashCellProtocol.swift
  49. 8 90
      iOSClient/Trash/Cell/NCTrashGridCell.swift
  50. 8 34
      iOSClient/Trash/Cell/NCTrashGridCell.xib
  51. 8 48
      iOSClient/Trash/Cell/NCTrashListCell.swift
  52. 23 10
      iOSClient/Trash/NCTrash+CollectionView.swift
  53. 2 13
      iOSClient/Trash/NCTrash.swift
  54. 0 4
      iOSClient/Utility/NCCameraRoll.swift

+ 0 - 4
.swiftlint.yml

@@ -1,14 +1,10 @@
 opt_in_rules: # some rules are turned off by default, so you need to opt-in
  - empty_collection_literal
- - empty_count
  - empty_string
  - explicit_init
  - unneeded_parentheses_in_closure_argument
  - operator_usage_whitespace
 
-empty_count:
-  severity: warning
-
 line_length:
   warning: 1000
   error: 5000

+ 32 - 30
Nextcloud.xcodeproj/project.pbxproj

@@ -29,7 +29,6 @@
 		AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */; };
 		AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF36077027BFA4E8001A243D /* ParallelWorker.swift */; };
 		AF3FDCC22796ECC300710F60 /* NCTrash+CollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3FDCC12796ECC300710F60 /* NCTrash+CollectionView.swift */; };
-		AF3FDCC32796F3FB00710F60 /* NCTrashListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD4821903F850088454D /* NCTrashListCell.swift */; };
 		AF4BF614275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
 		AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
 		AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
@@ -191,7 +190,6 @@
 		F714804F262ED4F900693E51 /* NCGridCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4521903D010088454D /* NCGridCell.xib */; };
 		F7148054262ED51000693E51 /* NCListCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD4321903CF20088454D /* NCListCell.xib */; };
 		F714805E262ED52900693E51 /* NCSectionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = F78ACD53219047D40088454D /* NCSectionFooter.xib */; };
-		F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7239876253D86D300257F49 /* NCEmptyView.xib */; };
 		F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F717402B24F699A5000C87D5 /* NCFavorite.storyboard */; };
 		F717402E24F699A5000C87D5 /* NCFavorite.swift in Sources */ = {isa = PBXBuildFile; fileRef = F717402C24F699A5000C87D5 /* NCFavorite.swift */; };
 		F7183BD42AEBDCD6000CD020 /* NCKeychain.swift in Sources */ = {isa = PBXBuildFile; fileRef = F760DE162AE66F350027D78A /* NCKeychain.swift */; };
@@ -213,8 +211,6 @@
 		F71F6D0D2B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */; };
 		F7226EDC1EE4089300EBECB1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7226EDB1EE4089300EBECB1 /* Main.storyboard */; };
 		F723985C253C95CE00257F49 /* NCViewerRichdocument.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F723985B253C95CE00257F49 /* NCViewerRichdocument.storyboard */; };
-		F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7239870253D86B600257F49 /* NCEmptyDataSet.swift */; };
-		F7239877253D86D300257F49 /* NCEmptyView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7239876253D86D300257F49 /* NCEmptyView.xib */; };
 		F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */; };
 		F72408332B8A27C900F128E2 /* NCMedia+Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72408322B8A27C900F128E2 /* NCMedia+Command.swift */; };
 		F72429362AFE39860040AEF3 /* NCLivePhoto.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70968A324212C4E00ED60E5 /* NCLivePhoto.swift */; };
@@ -676,6 +672,7 @@
 		F7A76DC8256A71CD00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
 		F7A76DCD256A71CE00119AB3 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extension.swift */; };
 		F7A7FA6329265CF4000603EF /* NCManageE2EE.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */; };
+		F7A846DE2BB01ACB0024816F /* NCTrashCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */; };
 		F7A8D72428F1771B008BBE1C /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72328F1771B008BBE1C /* NextcloudKit */; };
 		F7A8D72828F17728008BBE1C /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = F7A8D72728F17728008BBE1C /* RealmSwift */; };
 		F7A8D73528F17E16008BBE1C /* NCManageDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */; };
@@ -751,6 +748,10 @@
 		F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */; };
 		F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB68992541676B0050EC94 /* NCMore.storyboard */; };
 		F7CB68A0254169530050EC94 /* NCSettings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7CB689F254169530050EC94 /* NCSettings.storyboard */; };
+		F7CBC1232BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */; };
+		F7CBC1242BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */; };
+		F7CBC1252BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */; };
+		F7CBC1262BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */; };
 		F7CBC31C24F78E79004D3812 /* NCSortMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */; };
 		F7CEE6002BA9A5C9003EFD89 /* NCTrashGridCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7CEE5FE2BA9A5C9003EFD89 /* NCTrashGridCell.xib */; };
 		F7CEE6012BA9A5C9003EFD89 /* NCTrashGridCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CEE5FF2BA9A5C9003EFD89 /* NCTrashGridCell.swift */; };
@@ -785,7 +786,6 @@
 		F7E98C1827E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
 		F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
 		F7ED547C25EEA65400956C55 /* QRCodeReader in Frameworks */ = {isa = PBXBuildFile; productRef = F7ED547B25EEA65400956C55 /* QRCodeReader */; };
-		F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7239870253D86B600257F49 /* NCEmptyDataSet.swift */; };
 		F7EDE4D1262D7B8400414FE6 /* NCDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7C1EEA425053A9C00866ACC /* NCDataSource.swift */; };
 		F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78ACD4121903CE00088454D /* NCListCell.swift */; };
 		F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 370D26AE248A3D7A00121797 /* NCCellProtocol.swift */; };
@@ -1105,8 +1105,6 @@
 		F71F6D062B6A6A5E00F1EB15 /* ThreadSafeArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSafeArray.swift; sourceTree = "<group>"; };
 		F7226EDB1EE4089300EBECB1 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = "<group>"; };
 		F723985B253C95CE00257F49 /* NCViewerRichdocument.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCViewerRichdocument.storyboard; sourceTree = "<group>"; };
-		F7239870253D86B600257F49 /* NCEmptyDataSet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEmptyDataSet.swift; sourceTree = "<group>"; };
-		F7239876253D86D300257F49 /* NCEmptyView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCEmptyView.xib; sourceTree = "<group>"; };
 		F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareCommentsCell.xib; sourceTree = "<group>"; };
 		F72408322B8A27C900F128E2 /* NCMedia+Command.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMedia+Command.swift"; sourceTree = "<group>"; };
 		F7245923289BB50B00474787 /* ThreadSafeDictionary.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThreadSafeDictionary.swift; sourceTree = "<group>"; };
@@ -1337,6 +1335,7 @@
 		F7A60F84292D215000FCE1F2 /* NCShareAccounts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAccounts.swift; sourceTree = "<group>"; };
 		F7A60F85292D215000FCE1F2 /* NCShareAccounts.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCShareAccounts.storyboard; sourceTree = "<group>"; };
 		F7A7FA6229265CF4000603EF /* NCManageE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCManageE2EE.swift; sourceTree = "<group>"; };
+		F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrashCellProtocol.swift; sourceTree = "<group>"; };
 		F7A8D72228F176B6008BBE1C /* WidgetDashboardIntentHandler-Brinding-header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WidgetDashboardIntentHandler-Brinding-header.h"; sourceTree = "<group>"; };
 		F7AA41B827C7CF4600494705 /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		F7AA41B927C7CF4B00494705 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
@@ -1478,6 +1477,8 @@
 		F7CA212C25F1333200826ABB /* NCAccountRequest.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCAccountRequest.storyboard; sourceTree = "<group>"; };
 		F7CB68992541676B0050EC94 /* NCMore.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCMore.storyboard; sourceTree = "<group>"; };
 		F7CB689F254169530050EC94 /* NCSettings.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCSettings.storyboard; sourceTree = "<group>"; };
+		F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSectionHeaderEmptyData.xib; sourceTree = "<group>"; };
+		F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSectionHeaderEmptyData.swift; sourceTree = "<group>"; };
 		F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSortMenu.swift; sourceTree = "<group>"; };
 		F7CC04E61F5AD50D00378CEF /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
 		F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Nextcloud.app; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -1822,9 +1823,7 @@
 			isa = PBXGroup;
 			children = (
 				F7DFB7E9219C5A0500680748 /* Create cloud */,
-				F78ACD50219046AC0088454D /* Section Header Footer */,
 				F7603298252F0E550015A421 /* Collection Common */,
-				370D26AE248A3D7A00121797 /* NCCellProtocol.swift */,
 				F7226EDB1EE4089300EBECB1 /* Main.storyboard */,
 				F7682FDF23C36B0500983A04 /* NCMainTabBar.swift */,
 				F75B0ABC244C4DBB00E58DCA /* NCActionCenter.swift */,
@@ -1927,15 +1926,6 @@
 			path = NCViewerQuickLook;
 			sourceTree = "<group>";
 		};
-		F723986F253D867900257F49 /* EmptyView */ = {
-			isa = PBXGroup;
-			children = (
-				F7239870253D86B600257F49 /* NCEmptyDataSet.swift */,
-				F7239876253D86D300257F49 /* NCEmptyView.xib */,
-			);
-			path = EmptyView;
-			sourceTree = "<group>";
-		};
 		F728CE741BF6322C00E69702 /* Share */ = {
 			isa = PBXGroup;
 			children = (
@@ -2078,18 +2068,28 @@
 			path = Intent;
 			sourceTree = "<group>";
 		};
+		F75FE06B2BB01D0D00A0EFEF /* Cell */ = {
+			isa = PBXGroup;
+			children = (
+				370D26AE248A3D7A00121797 /* NCCellProtocol.swift */,
+				F78ACD3F21903CC20088454D /* NCGridCell.swift */,
+				F78ACD4521903D010088454D /* NCGridCell.xib */,
+				F78ACD4121903CE00088454D /* NCListCell.swift */,
+				F78ACD4321903CF20088454D /* NCListCell.xib */,
+			);
+			path = Cell;
+			sourceTree = "<group>";
+		};
 		F7603298252F0E550015A421 /* Collection Common */ = {
 			isa = PBXGroup;
 			children = (
+				F75FE06B2BB01D0D00A0EFEF /* Cell */,
+				F78ACD50219046AC0088454D /* Section Header Footer */,
 				F70D7C3525FFBF81002B9E34 /* NCCollectionViewCommon.swift */,
 				F36E64F62B9245210085ABB5 /* NCCollectionViewCommon+SelectTabBarDelegate.swift */,
 				F38F71242B6BBDC300473CDC /* NCCollectionViewCommonSelectTabBar.swift */,
 				F7E7AEA42BA32C6500512E52 /* NCCollectionViewDownloadThumbnail.swift */,
 				F7E7AEA62BA32D0000512E52 /* NCCollectionViewUnifiedSearch.swift */,
-				F78ACD3F21903CC20088454D /* NCGridCell.swift */,
-				F78ACD4521903D010088454D /* NCGridCell.xib */,
-				F78ACD4121903CE00088454D /* NCListCell.swift */,
-				F78ACD4321903CF20088454D /* NCListCell.xib */,
 			);
 			path = "Collection Common";
 			sourceTree = "<group>";
@@ -2191,6 +2191,7 @@
 		F78ACD4721903F850088454D /* Cell */ = {
 			isa = PBXGroup;
 			children = (
+				F7A846DD2BB01ACB0024816F /* NCTrashCellProtocol.swift */,
 				F7CEE5FF2BA9A5C9003EFD89 /* NCTrashGridCell.swift */,
 				F7CEE5FE2BA9A5C9003EFD89 /* NCTrashGridCell.xib */,
 				F78ACD4821903F850088454D /* NCTrashListCell.swift */,
@@ -2204,6 +2205,8 @@
 			children = (
 				F78ACD53219047D40088454D /* NCSectionFooter.xib */,
 				F7FF2CB02842159500EBB7A1 /* NCSectionHeader.xib */,
+				F7CBC1222BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift */,
+				F7CBC1212BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib */,
 				F7B398412A6A91D5007538D6 /* NCSectionHeaderMenu.xib */,
 				F78ACD51219046DC0088454D /* NCSectionHeaderMenu.swift */,
 			);
@@ -2657,7 +2660,6 @@
 				F70B866A2642A21300ED5349 /* Color */,
 				F7BAAD951ED5A63D00B7EAD4 /* Data */,
 				F73FAEE224D2CA830090692E /* Diagnostics */,
-				F723986F253D867900257F49 /* EmptyView */,
 				F7A0D14E259229FA008F8A13 /* Extensions */,
 				F7A3214D1E9E2A070069AD1B /* Favorites */,
 				F7725A5D251F33BB00D125E0 /* Files */,
@@ -3338,8 +3340,8 @@
 				F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */,
 				F7E4022C2BA85D1D007E5609 /* PrivacyInfo.xcprivacy in Resources */,
 				AF22B209277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.xib in Resources */,
+				F7CBC1242BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */,
 				F7B398432A6A91D5007538D6 /* NCSectionHeaderMenu.xib in Resources */,
-				F7148063262ED66200693E51 /* NCEmptyView.xib in Resources */,
 				AF22B207277B4E4C00DAB0CC /* NCCreateFormUploadConflict.storyboard in Resources */,
 				F7145A231D12E3B700CAFEEC /* Localizable.strings in Resources */,
 				F746EC51273906C40052598D /* NCViewCertificateDetails.storyboard in Resources */,
@@ -3420,13 +3422,13 @@
 				F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */,
 				AF93471927E2361E002537EE /* NCShareAdvancePermissionFooter.xib in Resources */,
 				F7725A61251F33BB00D125E0 /* NCFiles.storyboard in Resources */,
+				F7CBC1232BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.xib in Resources */,
 				F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */,
 				F787704F22E7019900F287A9 /* NCShareLinkCell.xib in Resources */,
 				F70753F72542A9C000972D44 /* NCViewerMediaPage.storyboard in Resources */,
 				F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */,
 				F7AC934A296193050002BC0F /* Reasons to use Nextcloud.pdf in Resources */,
 				F7A60F87292D215000FCE1F2 /* NCShareAccounts.storyboard in Resources */,
-				F7239877253D86D300257F49 /* NCEmptyView.xib in Resources */,
 				F761856A29E98543006EB3B0 /* NCIntro.storyboard in Resources */,
 				F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */,
 				F7651A8A23A2A3F2001403D2 /* NCCreateFormUploadDocuments.storyboard in Resources */,
@@ -3677,6 +3679,7 @@
 				F7817CFB29801A3500FFBC65 /* Data+Extension.swift in Sources */,
 				F72429362AFE39860040AEF3 /* NCLivePhoto.swift in Sources */,
 				AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */,
+				F7CBC1262BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */,
 				F7A0D1362591FBC5008F8A13 /* String+Extension.swift in Sources */,
 				F7EDE4D6262D7B9600414FE6 /* NCListCell.swift in Sources */,
 				F7327E372B73AEDE00A462C7 /* NCNetworking+LivePhoto.swift in Sources */,
@@ -3695,12 +3698,10 @@
 				F79B646126CA661600838ACA /* UIControl+Extension.swift in Sources */,
 				F77C973A2953143A00FDDD09 /* NCCameraRoll.swift in Sources */,
 				F740BEF02A35C2AD00E9B6D5 /* UILabel+Extension.swift in Sources */,
-				F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */,
 				F7C30E01291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */,
 				AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				F798F0E225880608000DAFFD /* UIColor+Extension.swift in Sources */,
-				AF3FDCC32796F3FB00710F60 /* NCTrashListCell.swift in Sources */,
 				F7327E3F2B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */,
 				F7C9B9202B582F550064EA91 /* NCManageDatabase+SecurityGuard.swift in Sources */,
 				AF817EF2274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
@@ -3986,6 +3987,7 @@
 				F77A697D250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift in Sources */,
 				F7BF9D822934CA21009EE9A6 /* NCManageDatabase+LayoutForView.swift in Sources */,
 				AF7E504E27A2D8FF00B5E4AF /* UIBarButton+Extension.swift in Sources */,
+				F7A846DE2BB01ACB0024816F /* NCTrashCellProtocol.swift in Sources */,
 				F78A10BF29322E8A008499B8 /* NCManageDatabase+Directory.swift in Sources */,
 				F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F7327E3D2B73B92800A462C7 /* NCNetworking+Synchronization.swift in Sources */,
@@ -3998,6 +4000,7 @@
 				F76673ED22C901F6007ED366 /* FileProviderDomain.swift in Sources */,
 				F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */,
 				F77B0E4F1D118A16002130FE /* CCManageAutoUpload.m in Sources */,
+				F7CBC1252BAC8B0000EC1D55 /* NCSectionHeaderEmptyData.swift in Sources */,
 				F75C0C4823D1FAE300163CC8 /* NCRichWorkspaceCommon.swift in Sources */,
 				F78ACD4A21903F850088454D /* NCTrashListCell.swift in Sources */,
 				F757CC8D29E82D0500F31428 /* NCGroupfolders.swift in Sources */,
@@ -4022,7 +4025,6 @@
 				F7C30E00291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */,
 				F7651A8B23A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift in Sources */,
 				F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
-				F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */,
 				AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */,
 				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				F73EF7BF2B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */,
@@ -5063,7 +5065,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.2.3;
+				MARKETING_VERSION = 5.2.4;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
@@ -5125,7 +5127,7 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 5.2.3;
+				MARKETING_VERSION = 5.2.4;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;

+ 29 - 3
Share/NCShareExtension+DataSource.swift

@@ -39,6 +39,34 @@ extension NCShareExtension: UICollectionViewDelegate {
         reloadDatasource(withLoadFolder: true)
         setNavigationBar(navigationTitle: metadata.fileNameView)
     }
+
+    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+        if kind == UICollectionView.elementKindSectionHeader {
+            guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderEmptyData", for: indexPath) as? NCSectionHeaderEmptyData else { return NCSectionHeaderEmptyData() }
+            if self.dataSourceTask?.state == .running {
+                header.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
+                header.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
+                header.emptyDescription.text = ""
+            } else {
+                header.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
+                header.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
+                header.emptyDescription.text = ""
+            }
+            return header
+        } else {
+            return UICollectionReusableView()
+        }
+    }
+}
+
+extension NCShareExtension: UICollectionViewDelegateFlowLayout {
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+        var height: CGFloat = 0
+        if dataSource.getMetadataSourceForAllSections().isEmpty {
+            height = NCGlobal.shared.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -50)
+        }
+        return CGSize(width: collectionView.frame.width, height: height)
+    }
 }
 
 extension NCShareExtension: UICollectionViewDataSource {
@@ -48,9 +76,7 @@ extension NCShareExtension: UICollectionViewDataSource {
     }
 
     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        let numberOfItems = dataSource.numberOfItemsInSection(section)
-        emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section)
-        return numberOfItems
+        return dataSource.numberOfItemsInSection(section)
     }
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {

+ 1 - 15
Share/NCShareExtension+NCDelegate.swift

@@ -24,21 +24,7 @@
 import NextcloudKit
 import UIKit
 
-extension NCShareExtension: NCEmptyDataSetDelegate, NCAccountRequestDelegate {
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-
-        if self.dataSourceTask?.state == .running {
-            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
-            view.emptyDescription.text = ""
-        } else {
-            view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
-            view.emptyDescription.text = ""
-        }
-    }
+extension NCShareExtension: NCAccountRequestDelegate {
 
     // MARK: - Account
 

+ 1 - 4
Share/NCShareExtension.swift

@@ -54,7 +54,6 @@ class NCShareExtension: UIViewController {
     var filesName: [String] = []
     // -------------------------------------------------------------
 
-    var emptyDataSet: NCEmptyDataSet?
     let keyLayout = NCGlobal.shared.layoutViewShareExtension
     var metadataFolder: tableMetadata?
     var dataSourceTask: URLSessionTask?
@@ -82,6 +81,7 @@ class NCShareExtension: UIViewController {
 
         self.navigationController?.navigationBar.prefersLargeTitles = false
 
+        collectionView.register(UINib(nibName: "NCSectionHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderEmptyData")
         collectionView.register(UINib(nibName: "NCListCell", bundle: nil), forCellWithReuseIdentifier: "listCell")
         collectionView.collectionViewLayout = NCListLayout()
 
@@ -265,10 +265,7 @@ class NCShareExtension: UIViewController {
         if filesName.count <= 3 {
             self.tableView.isScrollEnabled = false
         }
-        // Label upload button
         uploadLabel.text = NSLocalizedString("_upload_", comment: "") + " \(filesName.count) " + NSLocalizedString("_files_", comment: "")
-        // Empty
-        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: -50 * counter, delegate: self)
         self.tableView.reloadData()
     }
 

+ 0 - 129
iOSClient/EmptyView/NCEmptyDataSet.swift

@@ -1,129 +0,0 @@
-//
-//  NCEmptyDataSet.swift
-//  Nextcloud
-//
-//  Created by Marino Faggiana on 19/10/2020.
-//  Copyright © 2020 Marino Faggiana. All rights reserved.
-//
-//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
-//
-//  This program is free software: you can redistribute it and/or modify
-//  it under the terms of the GNU General Public License as published by
-//  the Free Software Foundation, either version 3 of the License, or
-//  (at your option) any later version.
-//
-//  This program is distributed in the hope that it will be useful,
-//  but WITHOUT ANY WARRANTY; without even the implied warranty of
-//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-//  GNU General Public License for more details.
-//
-//  You should have received a copy of the GNU General Public License
-//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
-//
-
-import UIKit
-
-public protocol NCEmptyDataSetDelegate: AnyObject {
-    func emptyDataSetView(_ view: NCEmptyView)
-}
-
-// optional func
-public extension NCEmptyDataSetDelegate {
-    func emptyDataSetView(_ view: NCEmptyView) {}
-}
-
-class NCEmptyDataSet: NSObject {
-
-    private var emptyView: NCEmptyView?
-    private var timer: Timer?
-    private var numberItemsForSections: Int = 0
-    private weak var delegate: NCEmptyDataSetDelegate?
-
-    private var fillBackgroundName: String = ""
-    private var fillBackgroundView = UIImageView()
-
-    private var centerXAnchor: NSLayoutConstraint?
-    private var centerYAnchor: NSLayoutConstraint?
-
-    init(view: UIView, offset: CGFloat = 0, delegate: NCEmptyDataSetDelegate?) {
-        super.init()
-
-        guard let emptyView = NCEmptyView.fromNib().instantiate(withOwner: self, options: nil).first as? NCEmptyView else { return }
-
-        self.delegate = delegate
-        self.emptyView = emptyView
-
-        emptyView.isHidden = true
-        emptyView.translatesAutoresizingMaskIntoConstraints = false
-
-        view.addSubview(emptyView)
-
-        emptyView.widthAnchor.constraint(equalToConstant: 350).isActive = true
-        emptyView.heightAnchor.constraint(equalToConstant: 250).isActive = true
-
-        if let view = view.superview {
-            centerXAnchor = emptyView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
-            centerYAnchor = emptyView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset)
-        } else {
-            centerXAnchor = emptyView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
-            centerYAnchor = emptyView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset)
-        }
-
-        centerXAnchor?.isActive = true
-        centerYAnchor?.isActive = true
-
-    }
-
-    func setOffset(_ offset: CGFloat) {
-
-        centerYAnchor?.constant = offset
-    }
-
-    func numberOfItemsInSection(_ num: Int, section: Int) {
-
-        if section == 0 {
-            numberItemsForSections = num
-        } else {
-            numberItemsForSections += num
-        }
-
-        if let emptyView = emptyView {
-
-            self.delegate?.emptyDataSetView(emptyView)
-
-            if !(timer?.isValid ?? false) && emptyView.isHidden == true {
-                timer = Timer.scheduledTimer(timeInterval: 0.3, target: self, selector: #selector(timerHandler(_:)), userInfo: nil, repeats: false)
-            }
-
-            if numberItemsForSections > 0 {
-                self.emptyView?.isHidden = true
-            }
-        }
-    }
-
-    @objc func timerHandler(_ timer: Timer) {
-
-        if numberItemsForSections == 0 {
-            self.emptyView?.isHidden = false
-        } else {
-            self.emptyView?.isHidden = true
-        }
-    }
-}
-
-public class NCEmptyView: UIView {
-
-    @IBOutlet weak var emptyImage: UIImageView!
-    @IBOutlet weak var emptyTitle: UILabel!
-    @IBOutlet weak var emptyDescription: UILabel!
-
-    static func fromNib() -> UINib {
-        return UINib(nibName: "NCEmptyView", bundle: nil)
-    }
-
-    public override func awakeFromNib() {
-        super.awakeFromNib()
-
-        emptyTitle.textColor = .label
-    }
-}

+ 0 - 71
iOSClient/EmptyView/NCEmptyView.xib

@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
-    <device id="retina6_72" orientation="landscape" appearance="light"/>
-    <dependencies>
-        <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
-        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
-        <capability name="System colors in document resources" minToolsVersion="11.0"/>
-        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
-    </dependencies>
-    <objects>
-        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
-        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
-        <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="NCEmptyView" customModule="Nextcloud" customModuleProvider="target">
-            <rect key="frame" x="0.0" y="0.0" width="422" height="475"/>
-            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-            <subviews>
-                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="W3d-Us-kU4">
-                    <rect key="frame" x="136" y="20" width="150" height="75"/>
-                    <constraints>
-                        <constraint firstAttribute="height" constant="150" id="A8B-y7-Fre">
-                            <variation key="heightClass=compact" constant="75"/>
-                        </constraint>
-                        <constraint firstAttribute="width" constant="150" id="g0C-P6-l3d"/>
-                    </constraints>
-                </imageView>
-                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="D4p-sI-mNB">
-                    <rect key="frame" x="79" y="135" width="264" height="17"/>
-                    <constraints>
-                        <constraint firstAttribute="height" relation="lessThanOrEqual" constant="50" id="u7B-jW-bWI"/>
-                    </constraints>
-                    <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="14"/>
-                    <color key="textColor" systemColor="systemGrayColor"/>
-                    <nil key="highlightedColor"/>
-                </label>
-                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="crs-DO-owR">
-                    <rect key="frame" x="79" y="103" width="264" height="24"/>
-                    <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
-                    <color key="textColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                    <nil key="highlightedColor"/>
-                </label>
-            </subviews>
-            <viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
-            <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-            <constraints>
-                <constraint firstItem="crs-DO-owR" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="CMU-Tp-bUM"/>
-                <constraint firstItem="D4p-sI-mNB" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" constant="20" id="egV-G4-wax"/>
-                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="crs-DO-owR" secondAttribute="trailing" constant="20" id="hHl-iN-Gev"/>
-                <constraint firstItem="crs-DO-owR" firstAttribute="top" secondItem="W3d-Us-kU4" secondAttribute="bottom" constant="8" id="hLN-L6-0gH"/>
-                <constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="D4p-sI-mNB" secondAttribute="trailing" constant="20" id="imv-AK-mqu"/>
-                <constraint firstItem="W3d-Us-kU4" firstAttribute="centerX" secondItem="vUN-kp-3ea" secondAttribute="centerX" id="kma-1Q-c3Q"/>
-                <constraint firstItem="W3d-Us-kU4" firstAttribute="top" secondItem="vUN-kp-3ea" secondAttribute="top" id="uOy-F7-KNu">
-                    <variation key="heightClass=compact" constant="20"/>
-                </constraint>
-                <constraint firstItem="D4p-sI-mNB" firstAttribute="top" secondItem="crs-DO-owR" secondAttribute="bottom" constant="8" id="zbi-5P-raN"/>
-            </constraints>
-            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
-            <connections>
-                <outlet property="emptyDescription" destination="D4p-sI-mNB" id="4Rw-TK-oGc"/>
-                <outlet property="emptyImage" destination="W3d-Us-kU4" id="xtd-nV-OUc"/>
-                <outlet property="emptyTitle" destination="crs-DO-owR" id="IkU-6d-P64"/>
-            </connections>
-            <point key="canvasLocation" x="-86.956521739130437" y="111.49553571428571"/>
-        </view>
-    </objects>
-    <resources>
-        <systemColor name="systemGrayColor">
-            <color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
-    </resources>
-</document>

+ 2 - 2
iOSClient/Favorites/NCFavorite.swift

@@ -26,8 +26,6 @@ import NextcloudKit
 
 class NCFavorite: NCCollectionViewCommon {
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -40,6 +38,8 @@ class NCFavorite: NCCollectionViewCommon {
         emptyDescription = "_tutorial_favorite_view_"
     }
 
+    // MARK: - View Life Cycle
+
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
 

+ 2 - 2
iOSClient/Files/NCFiles.swift

@@ -30,8 +30,6 @@ class NCFiles: NCCollectionViewCommon {
     internal var fileNameBlink: String?
     internal var fileNameOpen: String?
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -45,6 +43,8 @@ class NCFiles: NCCollectionViewCommon {
         emptyDescription = "_no_file_pull_down_"
     }
 
+    // MARK: - View Life Cycle
+
     override func viewDidLoad() {
         super.viewDidLoad()
 

+ 2 - 2
iOSClient/Groupfolders/NCGroupfolders.swift

@@ -26,8 +26,6 @@ import NextcloudKit
 
 class NCGroupfolders: NCCollectionViewCommon {
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -40,6 +38,8 @@ class NCGroupfolders: NCCollectionViewCommon {
         emptyDescription = "_tutorial_groupfolders_view_"
     }
 
+    // MARK: - View Life Cycle
+
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
 

+ 0 - 9
iOSClient/Images.xcassets/Image.imageset/Contents.json

@@ -1,9 +0,0 @@
-{
-  "images" : [
-
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}

+ 0 - 10
iOSClient/Images.xcassets/Image.imageset/folder_link.svg

@@ -1,10 +0,0 @@
-<svg width="96" height="96" viewBox="0 0 96 96" fill="none" xmlns="http://www.w3.org/2000/svg">
-<g clip-path="url(#clip0_1_3)">
-<path fill-rule="evenodd" clip-rule="evenodd" d="M16 16H40L48 24H80C84.4 24 88 27.6 88 32V72C88 76.4 84.4 80 80 80H16C11.6 80 8 76.4 8 72L8.04 24C8.04 19.6 11.6 16 16 16ZM38.9583 46.4042C35.8946 46.4042 33.4042 48.8946 33.4042 51.9583C33.4042 55.0221 35.8946 57.5125 38.9583 57.5125H46.125V60.9167H38.9583C34.0133 60.9167 30 56.9033 30 51.9583C30 47.0133 34.0133 43 38.9583 43H46.125V46.4042H38.9583ZM55.0833 53.75H40.75V50.1667H55.0833V53.75ZM49.7083 43H56.875C61.82 43 65.8333 47.0133 65.8333 51.9583C65.8333 56.9033 61.82 60.9167 56.875 60.9167H49.7083V57.5125H56.875C59.9388 57.5125 62.4292 55.0221 62.4292 51.9583C62.4292 48.8946 59.9388 46.4042 56.875 46.4042H49.7083V43Z" fill="#00679E"/>
-</g>
-<defs>
-<clipPath id="clip0_1_3">
-<rect width="96" height="96" fill="white"/>
-</clipPath>
-</defs>
-</svg>

+ 0 - 0
iOSClient/Main/NCCellProtocol.swift → iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift


+ 0 - 0
iOSClient/Main/Collection Common/NCGridCell.swift → iOSClient/Main/Collection Common/Cell/NCGridCell.swift


+ 8 - 0
iOSClient/Main/Collection Common/NCGridCell.xib → iOSClient/Main/Collection Common/Cell/NCGridCell.xib

@@ -145,6 +145,14 @@
                     <exclude reference="cgB-lu-t0g"/>
                     <exclude reference="W0L-HY-al1"/>
                 </mask>
+                <mask key="constraints">
+                    <exclude reference="0mO-lw-JH1"/>
+                    <exclude reference="6tC-PK-fYX"/>
+                    <exclude reference="Py6-0z-K3t"/>
+                    <exclude reference="VMW-0Y-aOH"/>
+                    <exclude reference="jI9-M1-Nl8"/>
+                    <exclude reference="q5r-Pz-Tnq"/>
+                </mask>
             </variation>
             <connections>
                 <outlet property="buttonMore" destination="EJs-Ro-nbe" id="BdI-ay-LuX"/>

+ 0 - 0
iOSClient/Main/Collection Common/NCListCell.swift → iOSClient/Main/Collection Common/Cell/NCListCell.swift


+ 0 - 0
iOSClient/Main/Collection Common/NCListCell.xib → iOSClient/Main/Collection Common/Cell/NCListCell.xib


+ 63 - 56
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -27,7 +27,7 @@ import NextcloudKit
 import EasyTipView
 import JGProgressHUD
 
-class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCSectionFooterDelegate, UIAdaptivePresentationControllerDelegate, NCEmptyDataSetDelegate, UIContextMenuInteractionDelegate, NCAccountRequestDelegate {
+class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UISearchResultsUpdating, UISearchControllerDelegate, UISearchBarDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCSectionFooterDelegate, NCSectionHeaderEmptyDataDelegate, UIAdaptivePresentationControllerDelegate, UIContextMenuInteractionDelegate, NCAccountRequestDelegate {
 
     @IBOutlet weak var collectionView: UICollectionView!
 
@@ -42,7 +42,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     let utility = NCUtility()
     let refreshControl = UIRefreshControl()
     var searchController: UISearchController?
-    var emptyDataSet: NCEmptyDataSet?
     var backgroundImageView = UIImageView()
     var serverUrl: String = ""
     var isEditMode = false
@@ -76,6 +75,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     var emptyImage: UIImage?
     var emptyTitle: String = ""
     var emptyDescription: String = ""
+    var emptyDataPortaitOffset: CGFloat = 0
+    var emptyDataLandscapeOffset: CGFloat = -20
 
     private var showDescription: Bool {
         !headerRichWorkspaceDisable && NCKeychain().showDescription
@@ -122,6 +123,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         // Header
         collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu")
         collectionView.register(UINib(nibName: "NCSectionHeader", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeader")
+        collectionView.register(UINib(nibName: "NCSectionHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderEmptyData")
 
         // Footer
         collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter")
@@ -134,9 +136,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
             self.reloadDataSourceNetwork()
         }
 
-        // Empty
-        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: getHeaderHeight(), delegate: self)
-
         // Long Press on CollectionView
         let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPressCollecationView(_:)))
         longPressedGesture.minimumPressDuration = 0.5
@@ -792,36 +791,6 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         return userAlias
     }
 
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-
-        self.emptyDataSet?.setOffset(getHeaderHeight())
-        if isSearchingMode {
-            view.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            if self.dataSourceTask?.state == .running {
-                view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
-            } else {
-                view.emptyTitle.text = NSLocalizedString("_search_no_record_found_", comment: "")
-            }
-            view.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "")
-        } else if self.dataSourceTask?.state == .running {
-            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
-            view.emptyDescription.text = ""
-        } else {
-            if serverUrl.isEmpty {
-                view.emptyImage.image = emptyImage
-                view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "")
-                view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "")
-            } else {
-                view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
-                view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "")
-                view.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "")
-            }
-        }
-    }
-
     // MARK: - SEARCH
 
     func updateSearchResults(for searchController: UISearchController) {
@@ -1330,11 +1299,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
     }
 
     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-
-        let numberItems = dataSource.numberOfItemsInSection(section)
-        emptyDataSet?.numberOfItemsInSection(numberItems, section: section)
-
-        return numberItems
+        return dataSource.numberOfItemsInSection(section)
     }
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
@@ -1583,9 +1548,47 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
         if kind == UICollectionView.elementKindSectionHeader {
 
-            if indexPath.section == 0 {
+            if dataSource.getMetadataSourceForAllSections().isEmpty {
+
+                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderEmptyData", for: indexPath) as? NCSectionHeaderEmptyData else { return NCSectionHeaderEmptyData() }
+                header.delegate = self
+
+                if !isSearchingMode, headerMenuTransferView, let ocId = NCNetworking.shared.transferInForegorund?.ocId {
+                    let text = String(format: NSLocalizedString("_upload_foreground_msg_", comment: ""), NCBrandOptions.shared.brand)
+                    header.setViewTransfer(isHidden: false, ocId: ocId, text: text, progress: NCNetworking.shared.transferInForegorund?.progress)
+                } else {
+                    header.setViewTransfer(isHidden: true)
+                }
+
+                if isSearchingMode {
+                    header.emptyImage.image = UIImage(named: "search")?.image(color: .gray, size: UIScreen.main.bounds.width)
+                    if self.dataSourceTask?.state == .running {
+                        header.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
+                    } else {
+                        header.emptyTitle.text = NSLocalizedString("_search_no_record_found_", comment: "")
+                    }
+                    header.emptyDescription.text = NSLocalizedString("_search_instruction_", comment: "")
+                } else if self.dataSourceTask?.state == .running {
+                    header.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
+                    header.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
+                    header.emptyDescription.text = ""
+                } else {
+                    if serverUrl.isEmpty {
+                        header.emptyImage.image = emptyImage
+                        header.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "")
+                        header.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "")
+                    } else {
+                        header.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
+                        header.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "")
+                        header.emptyDescription.text = NSLocalizedString("_no_file_pull_down_", comment: "")
+                    }
+                }
+
+                return header
+
+            } else if indexPath.section == 0 {
 
-                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu else { return UICollectionReusableView() }
+                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu else { return NCSectionHeaderMenu() }
                 let (_, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: indexPath.section)
 
                 self.headerMenu = header
@@ -1614,7 +1617,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
             } else {
 
-                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeader", for: indexPath) as? NCSectionHeader else { return UICollectionReusableView() }
+                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeader", for: indexPath) as? NCSectionHeader else { return NCSectionHeader() }
 
                 header.labelSection.text = self.dataSource.getSectionValueLocalization(indexPath: indexPath)
                 header.labelSection.textColor = .label
@@ -1624,7 +1627,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
         } else {
 
-            guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return UICollectionReusableView() }
+            guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return NCSectionFooter() }
             let sections = dataSource.numberOfSections()
             let section = indexPath.section
             let metadataForSection = self.dataSource.getMetadataForSection(indexPath.section)
@@ -1674,14 +1677,17 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
 extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
 
-    func getHeaderHeight() -> CGFloat {
+    func isHeaderMenuTransferViewEnabled() -> Bool {
+        if headerMenuTransferView, let metadata = NCManageDatabase.shared.getMetadataFromOcId(NCNetworking.shared.transferInForegorund?.ocId), metadata.isTransferInForeground {
+            return true
+        }
+        return false
+    }
 
+    func getHeaderHeight() -> CGFloat {
         var size: CGFloat = 0
 
-        // transfer in progress
-        if headerMenuTransferView,
-           let metadata = NCManageDatabase.shared.getMetadataFromOcId(NCNetworking.shared.transferInForegorund?.ocId),
-            metadata.isTransferInForeground {
+        if isHeaderMenuTransferViewEnabled() {
             if !isSearchingMode {
                 size += NCGlobal.shared.heightHeaderTransfer
             }
@@ -1693,7 +1699,6 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
     }
 
     func getHeaderHeight(section: Int) -> (heightHeaderCommands: CGFloat, heightHeaderRichWorkspace: CGFloat, heightHeaderSection: CGFloat) {
-
         var headerRichWorkspace: CGFloat = 0
 
         if let richWorkspaceText = richWorkspaceText, showDescription {
@@ -1715,15 +1720,17 @@ extension NCCollectionViewCommon: UICollectionViewDelegateFlowLayout {
     }
 
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
-
-        let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section)
-        let heightHeader = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection
-
-        return CGSize(width: collectionView.frame.width, height: heightHeader)
+        var height: CGFloat = 0
+        if dataSource.getMetadataSourceForAllSections().isEmpty {
+            height = NCGlobal.shared.getHeightHeaderEmptyData(view: view, portraitOffset: emptyDataPortaitOffset, landscapeOffset: emptyDataLandscapeOffset, isHeaderMenuTransferViewEnabled: isHeaderMenuTransferViewEnabled())
+        } else {
+            let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section)
+            height = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection
+        }
+        return CGSize(width: collectionView.frame.width, height: height)
     }
 
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-
         let sections = dataSource.numberOfSections()
         let metadataForSection = self.dataSource.getMetadataForSection(section)
         let isPaginated = metadataForSection?.lastSearchResult?.isPaginated ?? false

+ 0 - 0
iOSClient/Main/Section Header Footer/NCSectionFooter.xib → iOSClient/Main/Collection Common/Section Header Footer/NCSectionFooter.xib


+ 0 - 0
iOSClient/Main/Section Header Footer/NCSectionHeader.xib → iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeader.xib


+ 113 - 0
iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderEmptyData.swift

@@ -0,0 +1,113 @@
+//
+//  NCSectionHeaderEmptyData.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 09/10/2018.
+//  Copyright © 2018 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+import MarkdownKit
+
+protocol NCSectionHeaderEmptyDataDelegate: AnyObject {
+    func tapButtonTransfer(_ sender: Any)
+}
+
+class NCSectionHeaderEmptyData: UICollectionReusableView {
+
+    @IBOutlet weak var viewTransfer: UIView!
+    @IBOutlet weak var viewTransferHeightConstraint: NSLayoutConstraint!
+    @IBOutlet weak var buttonTransfer: UIButton!
+    @IBOutlet weak var imageButtonTransfer: UIImageView!
+    @IBOutlet weak var labelTransfer: UILabel!
+    @IBOutlet weak var progressTransfer: UIProgressView!
+    @IBOutlet weak var transferSeparatorBottom: UIView!
+    @IBOutlet weak var transferSeparatorBottomHeightConstraint: NSLayoutConstraint!
+
+    @IBOutlet weak var emptyImage: UIImageView!
+    @IBOutlet weak var emptyTitle: UILabel!
+    @IBOutlet weak var emptyDescription: UILabel!
+
+    weak var delegate: NCSectionHeaderEmptyDataDelegate?
+
+    override func awakeFromNib() {
+        super.awakeFromNib()
+        initHeader()
+    }
+
+    override func prepareForReuse() {
+        super.prepareForReuse()
+        initHeader()
+    }
+
+    func initHeader() {
+        viewTransferHeightConstraint.constant = 0
+        viewTransfer.isHidden = true
+        buttonTransfer.backgroundColor = .clear
+        buttonTransfer.setImage(nil, for: .normal)
+        buttonTransfer.layer.cornerRadius = 6
+        buttonTransfer.layer.masksToBounds = true
+        imageButtonTransfer.image = UIImage(systemName: "stop.circle")
+        imageButtonTransfer.tintColor = .white
+        labelTransfer.text = ""
+        progressTransfer.progress = 0
+        progressTransfer.tintColor = NCBrandColor.shared.brand
+        progressTransfer.trackTintColor = NCBrandColor.shared.brand.withAlphaComponent(0.2)
+        transferSeparatorBottom.backgroundColor = .separator
+        transferSeparatorBottomHeightConstraint.constant = 0.5
+        emptyImage.image = nil
+        emptyTitle.text = ""
+        emptyDescription.text = ""
+    }
+
+    // MARK: - Action
+
+    @IBAction func touchUpTransfer(_ sender: Any) {
+       delegate?.tapButtonTransfer(sender)
+    }
+
+    // MARK: - Transfer
+
+    func setViewTransfer(isHidden: Bool, ocId: String? = nil, text: String? = nil, progress: Float? = nil) {
+
+        labelTransfer.text = text
+        viewTransfer.isHidden = isHidden
+        progressTransfer.progress = 0
+
+        if isHidden {
+            viewTransferHeightConstraint.constant = 0
+        } else {
+            var image: UIImage?
+            if let ocId,
+               let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) {
+                image = NCUtility().createFilePreviewImage(ocId: metadata.ocId, etag: metadata.etag, fileNameView: metadata.fileNameView, classFile: metadata.classFile, status: metadata.status, createPreviewMedia: true)?.darken()
+                if image == nil {
+                    image = UIImage(named: metadata.iconName)
+                    buttonTransfer.backgroundColor = .lightGray
+                } else {
+                    buttonTransfer.backgroundColor = .clear
+                }
+                buttonTransfer.setImage(image, for: .normal)
+            }
+            viewTransferHeightConstraint.constant = NCGlobal.shared.heightHeaderTransfer
+            if let progress {
+                progressTransfer.progress = progress
+            }
+        }
+    }
+}

+ 127 - 0
iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderEmptyData.xib

@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
+        <capability name="System colors in document resources" minToolsVersion="11.0"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <collectionReusableView opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" reuseIdentifier="sectionHeaderEmptyData" id="tys-A2-nDX" customClass="NCSectionHeaderEmptyData" customModule="Nextcloud" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="656" height="623"/>
+            <autoresizingMask key="autoresizingMask"/>
+            <subviews>
+                <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="zUM-hu-F2q" userLabel="View Transfer">
+                    <rect key="frame" x="0.0" y="0.0" width="656" height="50"/>
+                    <subviews>
+                        <button opaque="NO" contentMode="scaleAspectFit" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="WXd-b2-peB">
+                            <rect key="frame" x="10" y="8" width="30" height="30"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="30" id="XXN-Fh-pZA"/>
+                                <constraint firstAttribute="width" constant="30" id="aDd-Gy-ZUl"/>
+                            </constraints>
+                            <connections>
+                                <action selector="touchUpTransfer:" destination="tys-A2-nDX" eventType="touchUpInside" id="AXk-oo-ObR"/>
+                            </connections>
+                        </button>
+                        <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="stop.circle" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="RAx-NP-nJe">
+                            <rect key="frame" x="15" y="13.5" width="20" height="19"/>
+                            <constraints>
+                                <constraint firstAttribute="width" constant="20" id="Bl3-T8-Pdl"/>
+                                <constraint firstAttribute="height" constant="20" id="s0j-tE-jVf"/>
+                            </constraints>
+                        </imageView>
+                        <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="text" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ct8-na-XmL">
+                            <rect key="frame" x="50" y="14" width="596" height="18"/>
+                            <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                            <nil key="textColor"/>
+                            <nil key="highlightedColor"/>
+                        </label>
+                        <progressView opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="y5t-ha-Gtf">
+                            <rect key="frame" x="-1" y="46" width="658" height="4"/>
+                        </progressView>
+                        <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MaD-hz-Xqk">
+                            <rect key="frame" x="0.0" y="49" width="656" height="1"/>
+                            <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <color key="tintColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                            <constraints>
+                                <constraint firstAttribute="height" constant="1" id="5cZ-q1-A41"/>
+                            </constraints>
+                        </view>
+                    </subviews>
+                    <constraints>
+                        <constraint firstAttribute="bottom" secondItem="y5t-ha-Gtf" secondAttribute="bottom" id="57H-lE-zHz"/>
+                        <constraint firstAttribute="bottom" secondItem="MaD-hz-Xqk" secondAttribute="bottom" id="5sX-km-4Ub"/>
+                        <constraint firstAttribute="trailing" secondItem="y5t-ha-Gtf" secondAttribute="trailing" constant="-1" id="9ku-TY-Zyl"/>
+                        <constraint firstItem="ct8-na-XmL" firstAttribute="centerY" secondItem="WXd-b2-peB" secondAttribute="centerY" id="Cpf-37-q0p"/>
+                        <constraint firstItem="RAx-NP-nJe" firstAttribute="centerX" secondItem="WXd-b2-peB" secondAttribute="centerX" id="CrF-Ta-Oe9"/>
+                        <constraint firstItem="WXd-b2-peB" firstAttribute="leading" secondItem="zUM-hu-F2q" secondAttribute="leading" constant="10" id="Dco-mu-Xs3"/>
+                        <constraint firstItem="MaD-hz-Xqk" firstAttribute="leading" secondItem="zUM-hu-F2q" secondAttribute="leading" id="Lrn-J7-BTG"/>
+                        <constraint firstAttribute="trailing" secondItem="ct8-na-XmL" secondAttribute="trailing" constant="10" id="SoT-SI-mWf"/>
+                        <constraint firstItem="ct8-na-XmL" firstAttribute="leading" secondItem="WXd-b2-peB" secondAttribute="trailing" constant="10" id="XsP-Hj-SY1"/>
+                        <constraint firstItem="y5t-ha-Gtf" firstAttribute="leading" secondItem="zUM-hu-F2q" secondAttribute="leading" constant="-1" id="cCo-9f-f6h"/>
+                        <constraint firstItem="RAx-NP-nJe" firstAttribute="centerY" secondItem="WXd-b2-peB" secondAttribute="centerY" id="hcY-hJ-ts9"/>
+                        <constraint firstAttribute="height" constant="50" id="nYi-uS-B2B"/>
+                        <constraint firstItem="WXd-b2-peB" firstAttribute="centerY" secondItem="zUM-hu-F2q" secondAttribute="centerY" constant="-2" id="wbe-GA-Te5"/>
+                        <constraint firstAttribute="trailing" secondItem="MaD-hz-Xqk" secondAttribute="trailing" id="wqU-PH-omv"/>
+                    </constraints>
+                </view>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Mdn-Ii-iP0">
+                    <rect key="frame" x="290.5" y="481" width="75" height="75"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="75" id="keD-Xa-hdD"/>
+                        <constraint firstAttribute="height" constant="75" id="mes-V2-hpo"/>
+                    </constraints>
+                </imageView>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Iks-dv-Ur1">
+                    <rect key="frame" x="20" y="564" width="616" height="24"/>
+                    <fontDescription key="fontDescription" type="boldSystem" pointSize="20"/>
+                    <nil key="textColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mgR-8K-A50">
+                    <rect key="frame" x="20" y="596" width="616" height="17"/>
+                    <fontDescription key="fontDescription" name=".AppleSystemUIFont" family=".AppleSystemUIFont" pointSize="14"/>
+                    <color key="textColor" systemColor="systemGrayColor"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <constraints>
+                <constraint firstItem="mgR-8K-A50" firstAttribute="leading" secondItem="tys-A2-nDX" secondAttribute="leading" constant="20" id="3jn-gZ-ChU"/>
+                <constraint firstItem="Iks-dv-Ur1" firstAttribute="leading" secondItem="tys-A2-nDX" secondAttribute="leading" constant="20" id="CPf-Sq-YDK"/>
+                <constraint firstItem="zUM-hu-F2q" firstAttribute="leading" secondItem="tys-A2-nDX" secondAttribute="leading" id="N4e-Ld-8tC"/>
+                <constraint firstAttribute="trailing" secondItem="Iks-dv-Ur1" secondAttribute="trailing" constant="20" id="OGO-mp-915"/>
+                <constraint firstItem="mgR-8K-A50" firstAttribute="top" secondItem="Iks-dv-Ur1" secondAttribute="bottom" constant="8" id="WL5-5S-Hkd"/>
+                <constraint firstItem="Mdn-Ii-iP0" firstAttribute="centerX" secondItem="tys-A2-nDX" secondAttribute="centerX" id="aIS-cr-P61"/>
+                <constraint firstAttribute="bottom" secondItem="mgR-8K-A50" secondAttribute="bottom" constant="10" id="c2I-Kl-eE5"/>
+                <constraint firstAttribute="trailing" secondItem="mgR-8K-A50" secondAttribute="trailing" constant="20" id="gGN-Pf-lhJ"/>
+                <constraint firstItem="Iks-dv-Ur1" firstAttribute="top" secondItem="Mdn-Ii-iP0" secondAttribute="bottom" constant="8" id="mF2-cA-vXb"/>
+                <constraint firstItem="zUM-hu-F2q" firstAttribute="top" secondItem="tys-A2-nDX" secondAttribute="top" id="mhK-vt-QKJ"/>
+                <constraint firstAttribute="trailing" secondItem="zUM-hu-F2q" secondAttribute="trailing" id="u11-TM-Yum"/>
+            </constraints>
+            <connections>
+                <outlet property="buttonTransfer" destination="WXd-b2-peB" id="WBa-uP-DM7"/>
+                <outlet property="emptyDescription" destination="mgR-8K-A50" id="QkP-LV-O5N"/>
+                <outlet property="emptyImage" destination="Mdn-Ii-iP0" id="u8Q-jq-yIl"/>
+                <outlet property="emptyTitle" destination="Iks-dv-Ur1" id="M6q-pi-RJw"/>
+                <outlet property="imageButtonTransfer" destination="RAx-NP-nJe" id="1pI-J2-9KR"/>
+                <outlet property="labelTransfer" destination="ct8-na-XmL" id="0nf-xJ-QtA"/>
+                <outlet property="progressTransfer" destination="y5t-ha-Gtf" id="TY3-I9-hoh"/>
+                <outlet property="transferSeparatorBottom" destination="MaD-hz-Xqk" id="eoJ-9k-9pn"/>
+                <outlet property="transferSeparatorBottomHeightConstraint" destination="5cZ-q1-A41" id="MYw-L0-Ucc"/>
+                <outlet property="viewTransfer" destination="zUM-hu-F2q" id="3Dw-3e-z3Y"/>
+                <outlet property="viewTransferHeightConstraint" destination="nYi-uS-B2B" id="9yh-dp-ZdP"/>
+            </connections>
+            <point key="canvasLocation" x="296" y="111.99400299850076"/>
+        </collectionReusableView>
+    </objects>
+    <resources>
+        <image name="stop.circle" catalog="system" width="128" height="123"/>
+        <systemColor name="systemGrayColor">
+            <color red="0.55686274509803924" green="0.55686274509803924" blue="0.57647058823529407" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+        </systemColor>
+    </resources>
+</document>

+ 0 - 0
iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.swift → iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.swift


+ 0 - 0
iOSClient/Main/Section Header Footer/NCSectionHeaderMenu.xib → iOSClient/Main/Collection Common/Section Header Footer/NCSectionHeaderMenu.xib


+ 8 - 18
iOSClient/Main/NCMainTabBar.swift

@@ -45,7 +45,7 @@ class NCMainTabBar: UITabBar {
         appDelegate.mainTabBar = self
 
         NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
-        NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(updateBadgeNumber(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
 
         changeTheming()
     }
@@ -199,23 +199,13 @@ class NCMainTabBar: UITabBar {
         self.addSubview(centerButton)
     }
 
-    @objc func updateBadgeNumber() {
-
-        DispatchQueue.global().async {
-
-            var counterDownload = 0
-            var counterUpload = 0
-
-            if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status < 0")) {
-                counterDownload = results.count
-            }
-            if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "status > 0")) {
-                counterUpload = results.count
-            }
-
-            DispatchQueue.main.async {
-                self.updateBadgeNumberUI(counterDownload: counterDownload, counterUpload: counterUpload)
-            }
+    @objc func updateBadgeNumber(_ notification: NSNotification) {
+        DispatchQueue.main.async {
+            guard let userInfo = notification.userInfo as NSDictionary?,
+                  let counterDownload = userInfo["counterDownload"] as? Int,
+                  let counterUpload = userInfo["counterUpload"] as? Int
+            else { return }
+            self.updateBadgeNumberUI(counterDownload: counterDownload, counterUpload: counterUpload)
         }
     }
 

+ 4 - 30
iOSClient/Media/Cell/NCGridMediaCell.swift

@@ -23,43 +23,17 @@
 
 import UIKit
 
-class NCGridMediaCell: UICollectionViewCell, NCCellProtocol {
+class NCGridMediaCell: UICollectionViewCell {
 
     @IBOutlet weak var imageItem: UIImageView!
     @IBOutlet weak var imageVisualEffect: UIVisualEffectView!
     @IBOutlet weak var imageSelect: UIImageView!
     @IBOutlet weak var imageStatus: UIImageView!
-    @IBOutlet weak var label: UILabel!
 
-    private var objectId: String = ""
-    private var user: String = ""
+    var ocId: String = ""
+    var user: String = ""
     var indexPath = IndexPath()
-    private var date: Date?
-
-    var filePreviewImageView: UIImageView? {
-        get { return imageItem }
-        set {}
-    }
-
-    var fileObjectId: String? {
-        get { return objectId }
-        set { objectId = newValue ?? "" }
-    }
-
-    var fileUser: String? {
-        get { return user }
-        set { user = newValue ?? "" }
-    }
-
-    var fileDate: Date? {
-        get { return date }
-        set {
-            date = newValue
-            if let date {
-                label.text = NCUtility().getTitleFromDate(date)
-            }
-        }
-    }
+    var date: Date?
 
     override func awakeFromNib() {
         super.awakeFromNib()

+ 0 - 11
iOSClient/Media/Cell/NCGridMediaCell.xib

@@ -42,22 +42,13 @@
                             <constraint firstAttribute="width" constant="20" id="PqO-qT-gfs"/>
                         </constraints>
                     </imageView>
-                    <label hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QAA-9f-xaN">
-                        <rect key="frame" x="0.0" y="203" width="220" height="17"/>
-                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                        <nil key="textColor"/>
-                        <nil key="highlightedColor"/>
-                    </label>
                 </subviews>
             </view>
             <constraints>
                 <constraint firstAttribute="trailing" secondItem="r1K-4X-gNd" secondAttribute="trailing" id="1Hu-GT-dJv"/>
                 <constraint firstItem="DHy-Up-3Bh" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" constant="5" id="1T3-8p-uIW"/>
-                <constraint firstItem="QAA-9f-xaN" firstAttribute="trailing" secondItem="vf1-Kf-9uL" secondAttribute="trailing" id="1dV-Sb-7U8"/>
                 <constraint firstAttribute="bottom" secondItem="a0p-rj-jnV" secondAttribute="bottom" constant="5" id="2IN-4o-XSp"/>
                 <constraint firstItem="r1K-4X-gNd" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" id="3bv-Dh-iih"/>
-                <constraint firstItem="QAA-9f-xaN" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" id="BlV-Di-gR1"/>
                 <constraint firstItem="a0p-rj-jnV" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" constant="5" id="DYA-5M-RZ8"/>
                 <constraint firstItem="DHy-Up-3Bh" firstAttribute="top" secondItem="vf1-Kf-9uL" secondAttribute="top" constant="5" id="ESV-qE-tbO"/>
                 <constraint firstItem="5Ci-V1-hf5" firstAttribute="top" secondItem="vf1-Kf-9uL" secondAttribute="top" id="Ouj-ZD-UFm"/>
@@ -65,7 +56,6 @@
                 <constraint firstItem="r1K-4X-gNd" firstAttribute="top" secondItem="vf1-Kf-9uL" secondAttribute="top" id="Rou-vT-GPt"/>
                 <constraint firstAttribute="trailing" secondItem="5Ci-V1-hf5" secondAttribute="trailing" id="cHT-cP-NN6"/>
                 <constraint firstAttribute="bottom" secondItem="5Ci-V1-hf5" secondAttribute="bottom" id="eEC-eB-alE"/>
-                <constraint firstItem="QAA-9f-xaN" firstAttribute="bottom" secondItem="vf1-Kf-9uL" secondAttribute="bottom" id="mcM-m0-XST"/>
                 <constraint firstItem="5Ci-V1-hf5" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" id="qT3-WD-iTV"/>
             </constraints>
             <size key="customSize" width="220" height="260"/>
@@ -74,7 +64,6 @@
                 <outlet property="imageSelect" destination="DHy-Up-3Bh" id="mo9-rP-P4I"/>
                 <outlet property="imageStatus" destination="a0p-rj-jnV" id="6Dg-tf-evd"/>
                 <outlet property="imageVisualEffect" destination="r1K-4X-gNd" id="uf3-P1-F4o"/>
-                <outlet property="label" destination="QAA-9f-xaN" id="PZV-b1-tgG"/>
             </connections>
             <point key="canvasLocation" x="86.956521739130437" y="141.03260869565219"/>
         </collectionViewCell>

+ 2 - 3
iOSClient/Media/NCMedia+Command.swift

@@ -52,7 +52,7 @@ extension NCMedia {
             let point = CGPoint(x: offset, y: top + contentOffsetY)
             if let indexPath = collectionView.indexPathForItem(at: point) {
                 let cell = self.collectionView(collectionView, cellForItemAt: indexPath) as? NCGridMediaCell
-                if let date = cell?.fileDate {
+                if let date = cell?.date {
                     self.titleDate?.text = utility.getTitleFromDate(date)
                 }
             } else {
@@ -85,8 +85,7 @@ extension NCMedia {
         let layoutTitle = (layout == NCGlobal.shared.mediaLayoutRatio) ? NSLocalizedString("_media_square_", comment: "") : NSLocalizedString("_media_ratio_", comment: "")
         let layoutImage = (layout == NCGlobal.shared.mediaLayoutRatio) ? UIImage(systemName: "square.grid.3x3") : UIImage(systemName: "rectangle.grid.3x2")
 
-        if UIDevice.current.userInterfaceIdiom == .phone,
-           (UIDevice.current.orientation == .landscapeLeft || UIDevice.current.orientation == .landscapeRight) {
+        if UIDevice.current.userInterfaceIdiom == .phone, UIDevice.current.orientation.isLandscape {
             columnCount += 2
         }
 

+ 50 - 31
iOSClient/Media/NCMedia.swift

@@ -25,7 +25,7 @@ import UIKit
 import NextcloudKit
 import RealmSwift
 
-class NCMedia: UIViewController, NCEmptyDataSetDelegate {
+class NCMedia: UIViewController {
 
     @IBOutlet weak var collectionView: UICollectionView!
     @IBOutlet weak var titleDate: UILabel!
@@ -36,8 +36,8 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate {
     @IBOutlet weak var menuButton: UIButton!
     @IBOutlet weak var gradientView: UIView!
 
+    let layout = NCMediaLayout()
     var activeAccount = tableAccount()
-    var emptyDataSet: NCEmptyDataSet?
     var documentPickerViewController: NCDocumentPickerViewController?
     var tabBarSelect: NCMediaSelectTabBar!
     let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
@@ -72,19 +72,17 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate {
 
         view.backgroundColor = .systemBackground
 
+        collectionView.register(UINib(nibName: "NCSectionHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: collectionViewMediaElementKindSectionHeader, withReuseIdentifier: "sectionHeaderEmptyData")
         collectionView.register(UINib(nibName: "NCGridMediaCell", bundle: nil), forCellWithReuseIdentifier: "gridCell")
         collectionView.alwaysBounceVertical = true
         collectionView.contentInset = UIEdgeInsets(top: insetsTop, left: 0, bottom: 50, right: 0)
         collectionView.backgroundColor = .systemBackground
         collectionView.prefetchDataSource = self
 
-        let layout = NCMediaLayout()
         layout.sectionInset = UIEdgeInsets(top: 0, left: 2, bottom: 0, right: 2)
         layout.mediaViewController = self
         collectionView.collectionViewLayout = layout
 
-        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: 0, delegate: self)
-
         tabBarSelect = NCMediaSelectTabBar(tabBarController: self.tabBarController, delegate: self)
 
         livePhotoImage = utility.loadImage(named: "livephoto", color: .white)
@@ -228,17 +226,6 @@ class NCMedia: UIViewController, NCEmptyDataSetDelegate {
     @objc func enterForeground(_ notification: NSNotification) {
         startTimer()
     }
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-        view.emptyImage.image = UIImage(named: "media")?.image(color: .gray, size: UIScreen.main.bounds.width)
-        if loadingTask != nil || imageCache.createMediaCacheInProgress {
-            view.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
-        } else {
-            view.emptyTitle.text = NSLocalizedString("_tutorial_photo_view_", comment: "")
-        }
-        view.emptyDescription.text = ""
-    }
 
     // MARK: - Image
 
@@ -288,7 +275,7 @@ extension NCMedia: UICollectionViewDelegate {
         if let metadata = self.metadatas?[indexPath.row] {
             if let visibleCells = self.collectionView?.indexPathsForVisibleItems.compactMap({ self.collectionView?.cellForItem(at: $0) }) {
                 for case let cell as NCGridMediaCell in visibleCells {
-                    if cell.fileObjectId == metadata.ocId {
+                    if cell.ocId == metadata.ocId {
                         mediaCell = cell
                     }
                 }
@@ -342,6 +329,21 @@ extension NCMedia: UICollectionViewDataSourcePrefetching {
 }
 
 extension NCMedia: UICollectionViewDataSource {
+    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
+        if kind == "collectionViewMediaElementKindSectionHeader" {
+            guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderEmptyData", for: indexPath) as? NCSectionHeaderEmptyData else { return NCSectionHeaderEmptyData() }
+            header.emptyImage.image = UIImage(named: "media")?.image(color: .gray, size: UIScreen.main.bounds.width)
+            if loadingTask != nil || imageCache.createMediaCacheInProgress {
+                header.emptyTitle.text = NSLocalizedString("_search_in_progress_", comment: "")
+            } else {
+                header.emptyTitle.text = NSLocalizedString("_tutorial_photo_view_", comment: "")
+            }
+            header.emptyDescription.text = ""
+            return header
+        }
+        return UICollectionReusableView()
+    }
+
     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
         var numberOfItemsInSection = 0
         if let metadatas { numberOfItemsInSection = metadatas.count }
@@ -360,9 +362,7 @@ extension NCMedia: UICollectionViewDataSource {
             activityIndicatorTrailing.constant = 150
         }
 
-        emptyDataSet?.numberOfItemsInSection(numberOfItemsInSection, section: section)
         DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { self.setTitleDate() }
-
         return numberOfItemsInSection
     }
 
@@ -383,12 +383,15 @@ extension NCMedia: UICollectionViewDataSource {
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
         guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridMediaCell,
               let metadatas = self.metadatas,
-              let metadata = metadatas[indexPath.row] else { return UICollectionViewCell() }
+              let metadata = metadatas[indexPath.row]
+        else {
+            return NCGridMediaCell()
+        }
 
-        cell.fileDate = metadata.date as Date
-        cell.fileObjectId = metadata.ocId
+        cell.date = metadata.date as Date
+        cell.ocId = metadata.ocId
         cell.indexPath = indexPath
-        cell.fileUser = metadata.ownerId
+        cell.user = metadata.ownerId
         cell.imageStatus.image = nil
         cell.imageItem.contentMode = .scaleAspectFill
 
@@ -429,19 +432,35 @@ extension NCMedia: UICollectionViewDataSource {
 
 // MARK: -
 
-extension NCMedia: UICollectionViewDelegateFlowLayout {
-    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
-        return CGSize(width: collectionView.frame.width, height: 0)
+extension NCMedia: NCMediaLayoutDelegate {
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, heightForHeaderInSection section: Int) -> Float {
+        var height: Double = 0
+        if metadatas?.count ?? 0 == 0 {
+            height = NCGlobal.shared.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -20)
+        }
+        return Float(height)
     }
 
-    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-        return CGSize(width: collectionView.frame.width, height: 0)
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, heightForFooterInSection section: Int) -> Float {
+        return .zero
     }
-}
 
-// MARK: -
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForSection section: Int) -> UIEdgeInsets {
+        return .zero
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForHeaderInSection section: Int) -> UIEdgeInsets {
+        return .zero
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForFooterInSection section: Int) -> UIEdgeInsets {
+        return .zero
+    }
+
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, minimumInteritemSpacingForSection section: Int) -> Float {
+        return .zero
+    }
 
-extension NCMedia: NCMediaLayoutDelegate {
     func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath, columnCount: Int, mediaLayout: String) -> CGSize {
         let size = CGSize(width: collectionView.frame.width / CGFloat(columnCount), height: collectionView.frame.width / CGFloat(columnCount))
         if mediaLayout == NCGlobal.shared.mediaLayoutRatio {

+ 2 - 2
iOSClient/Media/NCMediaDataSource.swift

@@ -56,7 +56,7 @@ extension NCMedia {
         }
 
         // first date
-        let firstCellDate = (visibleCells.first as? NCGridMediaCell)?.fileDate
+        let firstCellDate = (visibleCells.first as? NCGridMediaCell)?.date
         if firstCellDate == firstMetadataDate {
             lessDate = Date.distantFuture
         } else {
@@ -67,7 +67,7 @@ extension NCMedia {
             }
         }
         // last date
-        let lastCellDate = (visibleCells.last as? NCGridMediaCell)?.fileDate
+        let lastCellDate = (visibleCells.last as? NCGridMediaCell)?.date
         if lastCellDate == lastMetadataDate {
             greaterDate = Date.distantPast
         } else {

+ 1 - 1
iOSClient/Media/NCMediaDownloadThumbnaill.swift

@@ -66,7 +66,7 @@ class NCMediaDownloadThumbnaill: ConcurrentOperation {
                 DispatchQueue.main.async {
                     if let visibleCells = self.media.collectionView?.indexPathsForVisibleItems.sorted(by: { $0.row < $1.row }).compactMap({ self.media.collectionView?.cellForItem(at: $0) }) {
                         for case let cell as NCGridMediaCell in visibleCells {
-                            if cell.fileObjectId == self.metadata.ocId, let filePreviewImageView = cell.filePreviewImageView {
+                            if cell.ocId == self.metadata.ocId, let filePreviewImageView = cell.imageItem {
                                 UIView.transition(with: filePreviewImageView,
                                                   duration: 0.75,
                                                   options: .transitionCrossDissolve,

+ 11 - 0
iOSClient/Media/NCMediaLayout.swift

@@ -26,6 +26,12 @@ public let collectionViewMediaElementKindSectionFooter = "collectionViewMediaEle
 
 protocol NCMediaLayoutDelegate: UICollectionViewDelegate {
     func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath, columnCount: Int, mediaLayout: String) -> CGSize
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, heightForHeaderInSection section: Int) -> Float
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, heightForFooterInSection section: Int) -> Float
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForSection section: Int) -> UIEdgeInsets
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForHeaderInSection section: Int) -> UIEdgeInsets
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, insetForFooterInSection section: Int) -> UIEdgeInsets
+    func collectionView(_ collectionView: UICollectionView, layout: UICollectionViewLayout, minimumInteritemSpacingForSection section: Int) -> Float
 }
 
 public class NCMediaLayout: UICollectionViewLayout {
@@ -137,12 +143,17 @@ public class NCMediaLayout: UICollectionViewLayout {
             /*
             * 1. Get section-specific metrics (minimumInteritemSpacing, sectionInset)
             */
+            let minimumInteritemSpacing: Float = delegate.collectionView(collectionView, layout: self, minimumInteritemSpacingForSection: section)
+            let sectionInset: UIEdgeInsets = delegate.collectionView(collectionView, layout: self, insetForSection: section)
             let width = Float(collectionView.frame.size.width - sectionInset.left - sectionInset.right)
             let itemWidth = floorf((width - Float(columnCount - 1) * Float(minimumColumnSpacing)) / Float(columnCount))
 
             /*
             * 2. Section header
             */
+            let headerHeight: Float = delegate.collectionView(collectionView, layout: self, heightForHeaderInSection: section)
+            let headerInset: UIEdgeInsets = delegate.collectionView(collectionView, layout: self, insetForHeaderInSection: section)
+
             top += Float(headerInset.top)
 
             if headerHeight > 0 {

+ 12 - 2
iOSClient/NCGlobal.swift

@@ -54,6 +54,16 @@ class NCGlobal: NSObject {
         return NCBrandColor.shared.userColors[userColorIx]
     }
 
+    func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat, isHeaderMenuTransferViewEnabled: Bool = false) -> CGFloat {
+        var height: CGFloat = 0
+        if UIDevice.current.orientation.isPortrait {
+            height = (view.frame.height / 2) - (view.safeAreaInsets.top / 2) + portraitOffset
+        } else {
+            height = (view.frame.height / 2) + landscapeOffset + CGFloat(isHeaderMenuTransferViewEnabled ? 35 : 0)
+        }
+        return height
+    }
+
     // Convert a string to an integer evenly
     // hash is hex string
     static func hashToInt(hash: String, maximum: Int) -> Int {
@@ -116,7 +126,7 @@ class NCGlobal: NSObject {
 
     // Varie size GUI
     //
-    @objc let heightCellSettings: CGFloat = 50
+    @objc let heightCellSettings: CGFloat           = 50
 
     // Avatar & Preview size
     //
@@ -367,7 +377,7 @@ class NCGlobal: NSObject {
 
     let notificationCenterProgressTask                          = "progressTask"                    // userInfo: account, ocId, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected
 
-    let notificationCenterUpdateBadgeNumber                     = "updateBadgeNumber"
+    let notificationCenterUpdateBadgeNumber                     = "updateBadgeNumber"               // userInfo: counterDownload, counterUpload
 
     let notificationCenterCreateFolder                          = "createFolder"                    // userInfo: ocId, serverUrl, account, withPush
     let notificationCenterDeleteFile                            = "deleteFile"                      // userInfo: [ocId], onlyLocalCache, error

+ 1 - 1
iOSClient/Networking/E2EE/NCEndToEndMetadata.swift

@@ -66,7 +66,7 @@ class NCEndToEndMetadata: NSObject {
         } else if (try? JSONDecoder().decode(E2eeV20.self, from: data)) != nil && NCGlobal.shared.e2eeVersions.contains(NCGlobal.shared.e2eeVersionV20) {
             return decodeMetadataV20(metadata, signature: signature, serverUrl: serverUrl, account: account, ocIdServerUrl: directory.ocId, urlBase: urlBase, userId: userId)
         } else {
-            return NKError(errorCode: NCGlobal.shared.errorE2EEVersion, errorDescription: "Server E2EE version " + NCGlobal.shared.capabilityE2EEApiVersion + ", not compatible")
+            return NKError(errorCode: NCGlobal.shared.errorE2EEVersion, errorDescription: "Unable to decode the metadata file")
         }
     }
 }

+ 64 - 74
iOSClient/Networking/NCNetworkingProcess.swift

@@ -43,12 +43,15 @@ class NCNetworkingProcess: NSObject {
 
     func startTimer() {
         self.timerProcess?.invalidate()
-        self.timerProcess = Timer.scheduledTimer(withTimeInterval: 5, repeats: true, block: { _ in
-            if !self.pauseProcess, !self.appDelegate.account.isEmpty {
+        self.timerProcess = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { _ in
+            guard !self.appDelegate.account.isEmpty, !self.pauseProcess else { return }
+            if NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "account == %@ AND status != %d", self.appDelegate.account, NCGlobal.shared.metadataStatusNormal)).isEmpty {
+                NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil, userInfo: ["counterDownload": 0, "counterUpload": 0])
+            } else {
                 Task {
                     let results = await self.start()
-                    print("[INFO] PROCESS (TIMER) Download: \(results.counterDownload) Upload: \(results.counterUpload)")
-                    NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil)
+                    print("[INFO] PROCESS Download: \(results.counterDownload) Upload: \(results.counterUpload)")
+                    NotificationCenter.default.post(name: Notification.Name(rawValue: NCGlobal.shared.notificationCenterUpdateBadgeNumber), object: nil, userInfo: ["counterDownload": results.counterDownload, "counterUpload": results.counterUpload])
                 }
             }
         })
@@ -225,90 +228,77 @@ class NCNetworkingProcess: NSObject {
 
     // MARK: -
 
-    func verifyZombie() {
-        Task {
-            var notificationCenter: Bool = false
+    func verifyZombie() async {
+        // selectorUploadFileShareExtension (FOREGROUND)
+        if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND sessionSelector == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.selectorUploadFileShareExtension)) {
+            for metadata in results {
+                NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
+                utilityFileSystem.removeFile(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
+            }
+        }
 
-            // selectorUploadFileShareExtension (FOREGROUND)
-            if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND sessionSelector == %@", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.selectorUploadFileShareExtension)) {
-                for metadata in results {
-                    NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
-                    utilityFileSystem.removeFile(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId))
-                    notificationCenter = true
+        // metadataStatusUploading (FOREGROUND)
+        if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.metadataStatusUploading)) {
+            if results.isEmpty { NCNetworking.shared.transferInForegorund = nil }
+            for metadata in results {
+                let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+                if NCNetworking.shared.uploadRequest[fileNameLocalPath] == nil {
+                    NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
+                                                               status: NCGlobal.shared.metadataStatusWaitUpload)
                 }
             }
+        }
 
-            // metadataStatusUploading (FOREGROUND)
-            if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierUpload, NCGlobal.shared.metadataStatusUploading)) {
-                if results.isEmpty { NCNetworking.shared.transferInForegorund = nil }
-                for metadata in results {
-                    let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
-                    if NCNetworking.shared.uploadRequest[fileNameLocalPath] == nil {
-                        NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
-                                                                   status: NCGlobal.shared.metadataStatusWaitUpload)
-                        notificationCenter = true
-                    }
-                }
+        // metadataStatusDownloading (FOREGROUND)
+        if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, NCGlobal.shared.metadataStatusDownloading)) {
+            for metadata in results {
+                NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
+                                                           session: "",
+                                                           sessionError: "",
+                                                           selector: "",
+                                                           status: NCGlobal.shared.metadataStatusNormal)
             }
+        }
 
-            // metadataStatusDownloading (FOREGROUND)
-            if let results = NCManageDatabase.shared.getResultsMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, NCGlobal.shared.metadataStatusDownloading)) {
-                for metadata in results {
+        // metadataStatusUploading (BACKGROUND)
+        let resultsUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "(session == %@ OR session == %@ OR session == %@) AND status == %d", NCNetworking.shared.sessionUploadBackground, NCNetworking.shared.sessionUploadBackgroundWWan, NCNetworking.shared.sessionUploadBackgroundExtension, NCGlobal.shared.metadataStatusUploading))
+        for metadata in resultsUpload {
+            var taskUpload: URLSessionTask?
+            var session: URLSession?
+            if metadata.session == NCNetworking.shared.sessionUploadBackground {
+                session = NCNetworking.shared.sessionManagerUploadBackground
+            } else if metadata.session == NCNetworking.shared.sessionUploadBackgroundWWan {
+                session = NCNetworking.shared.sessionManagerUploadBackgroundWWan
+            }
+            if let tasks = await session?.allTasks {
+                for task in tasks {
+                    if task.taskIdentifier == metadata.sessionTaskIdentifier { taskUpload = task }
+                }
+                if taskUpload == nil, let metadata = NCManageDatabase.shared.getResultMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusUploading)) {
                     NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
-                                                               session: "",
+                                                               session: NCNetworking.shared.sessionUploadBackground,
                                                                sessionError: "",
-                                                               selector: "",
-                                                               status: NCGlobal.shared.metadataStatusNormal)
-                    notificationCenter = true
+                                                               status: NCGlobal.shared.metadataStatusWaitUpload)
                 }
             }
+        }
 
-            // metadataStatusUploading (BACKGROUND)
-            let resultsUpload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "(session == %@ OR session == %@ OR session == %@) AND status == %d", NCNetworking.shared.sessionUploadBackground, NCNetworking.shared.sessionUploadBackgroundWWan, NCNetworking.shared.sessionUploadBackgroundExtension, NCGlobal.shared.metadataStatusUploading))
-            for metadata in resultsUpload {
-                var taskUpload: URLSessionTask?
-                var session: URLSession?
-                if metadata.session == NCNetworking.shared.sessionUploadBackground {
-                    session = NCNetworking.shared.sessionManagerUploadBackground
-                } else if metadata.session == NCNetworking.shared.sessionUploadBackgroundWWan {
-                    session = NCNetworking.shared.sessionManagerUploadBackgroundWWan
+        // metadataStatusDowloading (BACKGROUND)
+        let resultsDownload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NCNetworking.shared.sessionDownloadBackground, NCGlobal.shared.metadataStatusDownloading))
+        for metadata in resultsDownload {
+            var taskDownload: URLSessionTask?
+            let session: URLSession? = NCNetworking.shared.sessionManagerDownloadBackground
+            if let tasks = await session?.allTasks {
+                for task in tasks {
+                    if task.taskIdentifier == metadata.sessionTaskIdentifier { taskDownload = task }
                 }
-                if let tasks = await session?.allTasks {
-                    for task in tasks {
-                        if task.taskIdentifier == metadata.sessionTaskIdentifier { taskUpload = task }
-                    }
-                    if taskUpload == nil, let metadata = NCManageDatabase.shared.getResultMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusUploading)) {
-                        NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
-                                                                   session: NCNetworking.shared.sessionUploadBackground,
-                                                                   sessionError: "",
-                                                                   status: NCGlobal.shared.metadataStatusWaitUpload)
-                        notificationCenter = true
-                    }
-                }
-            }
-
-            // metadataStatusDowloading (BACKGROUND)
-            let resultsDownload = NCManageDatabase.shared.getMetadatas(predicate: NSPredicate(format: "session == %@ AND status == %d", NCNetworking.shared.sessionDownloadBackground, NCGlobal.shared.metadataStatusDownloading))
-            for metadata in resultsDownload {
-                var taskDownload: URLSessionTask?
-                let session: URLSession? = NCNetworking.shared.sessionManagerDownloadBackground
-                if let tasks = await session?.allTasks {
-                    for task in tasks {
-                        if task.taskIdentifier == metadata.sessionTaskIdentifier { taskDownload = task }
-                    }
-                    if taskDownload == nil, let metadata = NCManageDatabase.shared.getResultMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusDownloading)) {
-                        NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
-                                                                   session: NCNetworking.shared.sessionDownloadBackground,
-                                                                   sessionError: "",
-                                                                   status: NCGlobal.shared.metadataStatusWaitDownload)
-                        notificationCenter = true
-                    }
+                if taskDownload == nil, let metadata = NCManageDatabase.shared.getResultMetadata(predicate: NSPredicate(format: "ocId == %@ AND status == %d", metadata.ocId, NCGlobal.shared.metadataStatusDownloading)) {
+                    NCManageDatabase.shared.setMetadataSession(ocId: metadata.ocId,
+                                                               session: NCNetworking.shared.sessionDownloadBackground,
+                                                               sessionError: "",
+                                                               status: NCGlobal.shared.metadataStatusWaitDownload)
                 }
             }
-
-            if notificationCenter {
-                NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
-            }
         }
     }
 }

+ 0 - 1
iOSClient/Networking/NCService.swift

@@ -50,7 +50,6 @@ class NCService: NSObject {
                 requestServerCapabilities()
                 requestDashboardWidget()
                 NCNetworkingE2EE().unlockAll(account: account)
-                NCNetworkingProcess.shared.verifyZombie()
                 sendClientDiagnosticsRemoteOperation(account: account)
             }
         }

+ 1 - 22
iOSClient/Notification/NCNotification.swift

@@ -27,13 +27,12 @@ import NextcloudKit
 import SwiftyJSON
 import JGProgressHUD
 
-class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmptyDataSetDelegate {
+class NCNotification: UITableViewController, NCNotificationCellDelegate {
 
     let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     let utilityFileSystem = NCUtilityFileSystem()
     let utility = NCUtility()
     var notifications: [NKNotifications] = []
-    var emptyDataSet: NCEmptyDataSet?
     var dataSourceTask: URLSessionTask?
 
     // MARK: - View Life Cycle
@@ -57,10 +56,6 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
                 self?.dismiss(animated: true)
             })
         }
-
-        // Empty
-        let offset = (self.navigationController?.navigationBar.bounds.height ?? 0) - 20
-        emptyDataSet = NCEmptyDataSet(view: tableView, offset: -offset, delegate: self)
     }
 
     override func viewWillAppear(_ animated: Bool) {
@@ -78,25 +73,9 @@ class NCNotification: UITableViewController, NCNotificationCellDelegate, NCEmpty
         self.dismiss(animated: true, completion: nil)
     }
 
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-
-        if self.dataSourceTask?.state == .running {
-            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
-            view.emptyDescription.text = ""
-        } else {
-            view.emptyImage.image = utility.loadImage(named: "bell", color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_no_notification_", comment: "")
-            view.emptyDescription.text = ""
-        }
-    }
-
     // MARK: - Table
 
     override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
-        emptyDataSet?.numberOfItemsInSection(notifications.count, section: section)
         return notifications.count
     }
 

+ 4 - 2
iOSClient/Offline/NCOffline.swift

@@ -26,8 +26,6 @@ import NextcloudKit
 
 class NCOffline: NCCollectionViewCommon {
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -38,8 +36,12 @@ class NCOffline: NCCollectionViewCommon {
         emptyImage = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
         emptyTitle = "_files_no_files_"
         emptyDescription = "_tutorial_offline_view_"
+        emptyDataPortaitOffset = 30
+        emptyDataLandscapeOffset = 20
     }
 
+    // MARK: - View Life Cycle
+
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         reloadDataSource()

+ 10 - 3
iOSClient/PrivacyInfo.xcprivacy

@@ -9,7 +9,6 @@
 			<string>NSPrivacyAccessedAPICategorySystemBootTime</string>
 			<key>NSPrivacyAccessedAPITypeReasons</key>
 			<array>
-				<string>C617.1</string>
 				<string>35F9.1</string>
 			</array>
 		</dict>
@@ -18,7 +17,7 @@
 			<string>NSPrivacyAccessedAPICategoryUserDefaults</string>
 			<key>NSPrivacyAccessedAPITypeReasons</key>
 			<array>
-				<string>C617.1</string>
+				<string>1C8F.1</string>
 			</array>
 		</dict>
 		<dict>
@@ -34,9 +33,17 @@
 			<string>NSPrivacyAccessedAPICategoryDiskSpace</string>
 			<key>NSPrivacyAccessedAPITypeReasons</key>
 			<array>
-				<string>C617.1</string>
+				<string>E174.1</string>
 			</array>
 		</dict>
+        <dict>
+            <key>NSPrivacyAccessedAPIType</key>
+            <string>NSPrivacyAccessedAPICategoryActiveKeyboards</string>
+            <key>NSPrivacyAccessedAPITypeReasons</key>
+            <array>
+                <string>54BD.1</string>
+            </array>
+        </dict>
 	</array>
 </dict>
 </plist>

+ 2 - 2
iOSClient/Recent/NCRecent.swift

@@ -26,8 +26,6 @@ import NextcloudKit
 
 class NCRecent: NCCollectionViewCommon {
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -40,6 +38,8 @@ class NCRecent: NCCollectionViewCommon {
         emptyDescription = ""
     }
 
+    // MARK: - View Life Cycle
+
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         reloadDataSourceNetwork()

+ 0 - 4
iOSClient/Rename file/NCRenameFile.swift

@@ -152,8 +152,6 @@ class NCRenameFile: UIViewController, UITextFieldDelegate {
 
     @IBAction func renameFile(_ sender: Any) {
 
-        // swiftlint:disable empty_count
-
         var fileNameNoExtensionNew = ""
         var extNew = ""
         var fileNameNew = ""
@@ -220,8 +218,6 @@ class NCRenameFile: UIViewController, UITextFieldDelegate {
                 self.delegate?.rename(fileName: fileName, fileNameNew: fileNameNew)
             }
         }
-
-        // swiftlint:enable empty_count
     }
 
     // MARK: - Networking

+ 41 - 47
iOSClient/Select/NCSelect.swift

@@ -29,7 +29,7 @@ import NextcloudKit
     @objc func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool)
 }
 
-class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresentationControllerDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate, NCEmptyDataSetDelegate {
+class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresentationControllerDelegate, NCListCellDelegate, NCGridCellDelegate, NCSectionHeaderMenuDelegate {
 
     @IBOutlet private var collectionView: UICollectionView!
     @IBOutlet private var buttonCancel: UIBarButtonItem!
@@ -62,7 +62,6 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
     // -------------------------------------------------------------
 
     private var dataSourceTask: URLSessionTask?
-    private var emptyDataSet: NCEmptyDataSet?
     private var serverUrlPush = ""
     private var metadataFolder = tableMetadata()
     private var overwrite = true
@@ -93,6 +92,7 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         collectionView.collectionViewLayout = NCListLayout()
 
         // Header
+        collectionView.register(UINib(nibName: "NCSectionHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderEmptyData")
         collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu")
 
         // Footer
@@ -101,12 +101,8 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         collectionView.backgroundColor = .systemBackground
 
         buttonCancel.title = NSLocalizedString("_cancel_", comment: "")
-
         bottomContraint?.constant = window?.rootViewController?.view.safeAreaInsets.bottom ?? 0
 
-        // Empty
-        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: NCGlobal.shared.heightButtonsView, delegate: self)
-
         // Type of command view
         if typeOfCommandView == .select || typeOfCommandView == .selectCreateFolder {
             if typeOfCommandView == .select {
@@ -190,25 +186,6 @@ class NCSelect: UIViewController, UIGestureRecognizerDelegate, UIAdaptivePresent
         pushMetadata(metadata)
     }
 
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-
-        if self.dataSourceTask?.state == .running {
-            view.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
-            view.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
-            view.emptyDescription.text = ""
-        } else {
-            view.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
-            if includeImages {
-                view.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "")
-            } else {
-                view.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
-            }
-            view.emptyDescription.text = ""
-        }
-    }
-
     // MARK: ACTION
 
     @IBAction func actionCancel(_ sender: UIBarButtonItem) {
@@ -324,9 +301,7 @@ extension NCSelect: UICollectionViewDataSource {
     }
 
     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        let numberOfItems = dataSource.numberOfItemsInSection(section)
-        emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section)
-        return numberOfItems
+        return dataSource.numberOfItemsInSection(section)
     }
 
     func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
@@ -426,21 +401,41 @@ extension NCSelect: UICollectionViewDataSource {
 
         if kind == UICollectionView.elementKindSectionHeader {
 
-            guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu else { return UICollectionReusableView() }
-            let (_, heightHeaderRichWorkspace, _) = getHeaderHeight(section: indexPath.section)
+            if dataSource.getMetadataSourceForAllSections().isEmpty {
+
+                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderEmptyData", for: indexPath) as? NCSectionHeaderEmptyData else { return NCSectionHeaderEmptyData() }
+                if self.dataSourceTask?.state == .running {
+                    header.emptyImage.image = UIImage(named: "networkInProgress")?.image(color: .gray, size: UIScreen.main.bounds.width)
+                    header.emptyTitle.text = NSLocalizedString("_request_in_progress_", comment: "")
+                    header.emptyDescription.text = ""
+                } else {
+                    header.emptyImage.image = UIImage(named: "folder")?.image(color: NCBrandColor.shared.brandElement, size: UIScreen.main.bounds.width)
+                    if includeImages {
+                        header.emptyTitle.text = NSLocalizedString("_files_no_files_", comment: "")
+                    } else {
+                        header.emptyTitle.text = NSLocalizedString("_files_no_folders_", comment: "")
+                    }
+                    header.emptyDescription.text = ""
+                }
+                return header
+
+            } else {
+
+                guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu else { return NCSectionHeaderMenu() }
+                let (_, heightHeaderRichWorkspace, _) = getHeaderHeight(section: indexPath.section)
 
-            self.headerMenu = header
+                self.headerMenu = header
 
-            header.delegate = self
-//            header.setButtonsView(height: 0)
-            header.setRichWorkspaceHeight(heightHeaderRichWorkspace)
-            header.setRichWorkspaceText(richWorkspaceText)
-            header.setViewTransfer(isHidden: true)
-            return header
+                header.delegate = self
+                header.setRichWorkspaceHeight(heightHeaderRichWorkspace)
+                header.setRichWorkspaceText(richWorkspaceText)
+                header.setViewTransfer(isHidden: true)
+                return header
+            }
 
         } else {
 
-            guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return UICollectionReusableView() }
+            guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return NCSectionFooter() }
             let sections = dataSource.numberOfSections()
             let section = indexPath.section
 
@@ -467,28 +462,27 @@ extension NCSelect: UICollectionViewDelegateFlowLayout {
 
         if let richWorkspaceText = richWorkspaceText {
             let trimmed = richWorkspaceText.trimmingCharacters(in: .whitespaces)
-            // swiftlint:disable empty_count
             if trimmed.count > 0 {
                 headerRichWorkspace = UIScreen.main.bounds.size.height / 6
             }
-            // swiftlint:enable empty_count
         }
 
         return (0, headerRichWorkspace, 0)
     }
 
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
-
-        let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section)
-        let heightHeader = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection
-
-        return CGSize(width: collectionView.frame.width, height: heightHeader)
+        var height: CGFloat = 0
+        if dataSource.getMetadataSourceForAllSections().isEmpty {
+            height = NCGlobal.shared.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -20)
+        } else {
+            let (heightHeaderCommands, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: section)
+            height = heightHeaderCommands + heightHeaderRichWorkspace + heightHeaderSection
+        }
+        return CGSize(width: collectionView.frame.width, height: height)
     }
 
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
-
         let sections = dataSource.numberOfSections()
-
         if section == sections - 1 {
             return CGSize(width: collectionView.frame.width, height: NCGlobal.shared.endHeightFooter)
         } else {

+ 2 - 2
iOSClient/Shares/NCShares.swift

@@ -26,8 +26,6 @@ import NextcloudKit
 
 class NCShares: NCCollectionViewCommon {
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -40,6 +38,8 @@ class NCShares: NCCollectionViewCommon {
         emptyDescription = "_tutorial_list_shares_view_"
     }
 
+    // MARK: - View Life Cycle
+
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
         if dataSource.metadatas.isEmpty {

BIN
iOSClient/Supporting Files/de.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/eu.lproj/Localizable.strings


BIN
iOSClient/Supporting Files/ru.lproj/Localizable.strings


+ 10 - 17
iOSClient/Transfers/NCTransfers.swift

@@ -29,8 +29,6 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
 
     var metadataTemp: tableMetadata?
 
-    // MARK: - View Life Cycle
-
     required init?(coder aDecoder: NSCoder) {
         super.init(coder: aDecoder)
 
@@ -44,6 +42,8 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
         emptyDescription = "_no_transfer_sub_"
     }
 
+    // MARK: - View Life Cycle
+
     override func viewDidLoad() {
         super.viewDidLoad()
 
@@ -99,15 +99,6 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
         notificationReloadDataSource += 1
     }
 
-    // MARK: - Empty
-
-    override func emptyDataSetView(_ view: NCEmptyView) {
-        self.emptyDataSet?.setOffset(getHeaderHeight())
-        view.emptyImage.image = emptyImage
-        view.emptyTitle.text = NSLocalizedString(emptyTitle, comment: "")
-        view.emptyDescription.text = NSLocalizedString(emptyDescription, comment: "")
-    }
-
     // MARK: TAP EVENT
 
     override func longPressMoreListItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {
@@ -265,14 +256,16 @@ class NCTransfers: NCCollectionViewCommon, NCTransferCellDelegate {
     }
 
     override func reloadDataSource(withQueryDB: Bool = true) {
-        super.reloadDataSource(withQueryDB: withQueryDB)
-
-        NCNetworkingProcess.shared.verifyZombie()
+        Task {
+            await NCNetworkingProcess.shared.verifyZombie()
+            super.reloadDataSource(withQueryDB: withQueryDB)
+        }
     }
 
     override func reloadDataSourceNetwork() {
-        super.reloadDataSourceNetwork()
-
-        reloadDataSource()
+        Task {
+            await NCNetworkingProcess.shared.verifyZombie()
+            super.reloadDataSource(withQueryDB: true)
+        }
     }
 }

+ 59 - 0
iOSClient/Trash/Cell/NCTrashCellProtocol.swift

@@ -0,0 +1,59 @@
+//
+//  NCTrashCellProtocol.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 24/03/24.
+//  Copyright © 2024 Marino Faggiana. All rights reserved.
+//
+//  Author Marino Faggiana <marino.faggiana@nextcloud.com>
+//
+//  This program is free software: you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation, either version 3 of the License, or
+//  (at your option) any later version.
+//
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//
+//  You should have received a copy of the GNU General Public License
+//  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+//
+
+import UIKit
+
+protocol NCTrashCellProtocol {
+    var objectId: String { get set }
+    var labelTitle: UILabel! { get set }
+    var labelInfo: UILabel! { get set }
+    var imageItem: UIImageView! { get set }
+    var indexPath: IndexPath { get set }
+
+    func selectMode(_ status: Bool)
+    func selected(_ status: Bool)
+}
+
+extension NCTrashCellProtocol where Self: UICollectionViewCell {
+    mutating func setupCellUI(tableTrash: tableTrash, image: UIImage?) {
+        self.objectId = tableTrash.fileId
+        self.labelTitle.text = tableTrash.trashbinFileName
+        self.labelTitle.textColor = .label
+        if self is NCTrashListCell {
+            self.labelInfo?.text = NCUtility().dateDiff(tableTrash.date as Date)
+        } else {
+            let dateFormatter = DateFormatter()
+            dateFormatter.dateStyle = .short
+            dateFormatter.timeStyle = .none
+            dateFormatter.locale = Locale.current
+            self.labelInfo?.text = dateFormatter.string(from: tableTrash.date as Date)
+        }
+        if tableTrash.directory {
+            self.imageItem.image = NCImageCache.images.folder
+        } else {
+            self.imageItem.image = image
+            self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size)
+        }
+        self.accessibilityLabel = tableTrash.trashbinFileName + ", " + (self.labelInfo?.text ?? "")
+    }
+}

+ 8 - 90
iOSClient/Trash/Cell/NCTrashGridCell.swift

@@ -23,67 +23,26 @@
 
 import UIKit
 
-class NCTrashGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProtocol, NCTrashCellProtocol {
+protocol NCTrashGridCellDelegate: AnyObject {
+    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any)
+}
+
+class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
 
     @IBOutlet weak var imageItem: UIImageView!
     @IBOutlet weak var imageSelect: UIImageView!
-    @IBOutlet weak var imageStatus: UIImageView!
-    @IBOutlet weak var imageFavorite: UIImageView!
-    @IBOutlet weak var imageLocal: UIImageView!
     @IBOutlet weak var labelTitle: UILabel!
     @IBOutlet weak var labelInfo: UILabel!
     @IBOutlet weak var labelSubinfo: UILabel!
     @IBOutlet weak var buttonMore: UIButton!
     @IBOutlet weak var imageVisualEffect: UIVisualEffectView!
 
+    weak var delegate: NCTrashGridCellDelegate?
     var objectId = ""
     var indexPath = IndexPath()
-    private var user = ""
-
-    weak var gridCellDelegate: NCTrashGridCellDelegate?
+    var user = ""
     var namedButtonMore = ""
 
-    var fileObjectId: String? {
-        get { return objectId }
-        set { objectId = newValue ?? "" }
-    }
-    var filePreviewImageView: UIImageView? {
-        get { return imageItem }
-        set { imageItem = newValue }
-    }
-    var fileUser: String? {
-        get { return user }
-        set { user = newValue ?? "" }
-    }
-    var fileTitleLabel: UILabel? {
-        get { return labelTitle }
-        set { labelTitle = newValue }
-    }
-    var fileInfoLabel: UILabel? {
-        get { return labelInfo }
-        set { labelInfo = newValue }
-    }
-    var fileSubinfoLabel: UILabel? {
-        get { return labelSubinfo }
-        set { labelSubinfo = newValue }
-    }
-    var fileSelectImage: UIImageView? {
-        get { return imageSelect }
-        set { imageSelect = newValue }
-    }
-    var fileStatusImage: UIImageView? {
-        get { return imageStatus }
-        set { imageStatus = newValue }
-    }
-    var fileLocalImage: UIImageView? {
-        get { return imageLocal }
-        set { imageLocal = newValue }
-    }
-    var fileFavoriteImage: UIImageView? {
-        get { return imageFavorite }
-        set { imageFavorite = newValue }
-    }
-
     override func awakeFromNib() {
         super.awakeFromNib()
 
@@ -100,18 +59,6 @@ class NCTrashGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCell
         imageVisualEffect.clipsToBounds = true
         imageVisualEffect.alpha = 0.5
 
-        let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPress(gestureRecognizer:)))
-        longPressedGesture.minimumPressDuration = 0.5
-        longPressedGesture.delegate = self
-        longPressedGesture.delaysTouchesBegan = true
-        self.addGestureRecognizer(longPressedGesture)
-
-        let longPressedGestureMore = UILongPressGestureRecognizer(target: self, action: #selector(longPressInsideMore(gestureRecognizer:)))
-        longPressedGestureMore.minimumPressDuration = 0.5
-        longPressedGestureMore.delegate = self
-        longPressedGestureMore.delaysTouchesBegan = true
-        buttonMore.addGestureRecognizer(longPressedGestureMore)
-
         labelTitle.text = ""
         labelInfo.text = ""
         labelSubinfo.text = ""
@@ -130,15 +77,7 @@ class NCTrashGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCell
     }
 
     @IBAction func touchUpInsideMore(_ sender: Any) {
-        gridCellDelegate?.tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, indexPath: indexPath, sender: sender)
-    }
-
-    @objc func longPressInsideMore(gestureRecognizer: UILongPressGestureRecognizer) {
-        gridCellDelegate?.longPressMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
-    }
-
-    @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) {
-        gridCellDelegate?.longPressGridItem(with: objectId, indexPath: indexPath, gestureRecognizer: gestureRecognizer)
+        delegate?.tapMoreGridItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, indexPath: indexPath, sender: sender)
     }
 
     fileprivate func setA11yActions() {
@@ -207,27 +146,6 @@ class NCTrashGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCell
         accessibilityLabel = label
         accessibilityValue = value
     }
-
-    func setIconOutlines() {
-        if imageStatus.image != nil {
-            imageStatus.makeCircularBackground(withColor: .systemBackground)
-        } else {
-            imageStatus.backgroundColor = .clear
-        }
-    }
-}
-
-protocol NCTrashGridCellDelegate: AnyObject {
-    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any)
-    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
-    func longPressGridItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer)
-}
-
-// optional func
-extension NCTrashGridCellDelegate {
-    func tapMoreGridItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any) {}
-    func longPressMoreGridItem(with objectId: String, namedButtonMore: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
-    func longPressGridItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) {}
 }
 
 // MARK: - Grid Layout

+ 8 - 34
iOSClient/Trash/Cell/NCTrashGridCell.xib

@@ -55,28 +55,6 @@
                             <constraint firstAttribute="height" constant="26" id="dat-R5-5vy"/>
                         </constraints>
                     </imageView>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="star.fill" catalog="system" translatesAutoresizingMaskIntoConstraints="NO" id="AYs-f2-vve" userLabel="imageFavorite">
-                        <rect key="frame" x="391" y="24.5" width="20" height="20"/>
-                        <color key="tintColor" systemColor="separatorColor"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="20" id="ZjS-Hv-JNm"/>
-                            <constraint firstAttribute="width" constant="20" id="kDr-15-VeJ"/>
-                        </constraints>
-                    </imageView>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="a0p-rj-jnV" userLabel="imageStatus">
-                        <rect key="frame" x="5" y="414" width="20" height="20"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="20" id="gq1-0a-eLC"/>
-                            <constraint firstAttribute="width" constant="20" id="uJE-4b-Qt7"/>
-                        </constraints>
-                    </imageView>
-                    <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="81G-wH-fjN" userLabel="imageLocal">
-                        <rect key="frame" x="391" y="414" width="20" height="20"/>
-                        <constraints>
-                            <constraint firstAttribute="height" constant="20" id="NTa-Gi-uzY"/>
-                            <constraint firstAttribute="width" constant="20" id="xLe-lb-N1p"/>
-                        </constraints>
-                    </imageView>
                     <visualEffectView hidden="YES" opaque="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="W0L-HY-al1">
                         <rect key="frame" x="0.0" y="20" width="416" height="419"/>
                         <view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" insetsLayoutMarginsFromSafeArea="NO" id="0m6-A2-SwD">
@@ -111,7 +89,6 @@
             <constraints>
                 <constraint firstItem="cgB-lu-t0g" firstAttribute="top" secondItem="5Ci-V1-hf5" secondAttribute="top" constant="1.5" id="0mO-lw-JH1"/>
                 <constraint firstItem="DHy-Up-3Bh" firstAttribute="leading" secondItem="VXh-sQ-LeX" secondAttribute="leading" constant="5" id="1T3-8p-uIW"/>
-                <constraint firstItem="AYs-f2-vve" firstAttribute="leading" secondItem="5Ci-V1-hf5" secondAttribute="trailing" constant="-25" id="3e3-0A-NSl"/>
                 <constraint firstItem="W0L-HY-al1" firstAttribute="leading" secondItem="VXh-sQ-LeX" secondAttribute="leading" id="6tC-PK-fYX"/>
                 <constraint firstItem="2po-8g-XeS" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" constant="25" id="9JI-KS-d7J"/>
                 <constraint firstItem="DHy-Up-3Bh" firstAttribute="top" secondItem="VXh-sQ-LeX" secondAttribute="top" constant="5" id="ESV-qE-tbO"/>
@@ -120,9 +97,7 @@
                 <constraint firstItem="5Ci-V1-hf5" firstAttribute="top" secondItem="VXh-sQ-LeX" secondAttribute="top" id="Ouj-ZD-UFm"/>
                 <constraint firstItem="W0L-HY-al1" firstAttribute="top" secondItem="VXh-sQ-LeX" secondAttribute="top" id="Py6-0z-K3t"/>
                 <constraint firstItem="2po-8g-XeS" firstAttribute="centerX" secondItem="vf1-Kf-9uL" secondAttribute="centerX" id="TTW-HT-yEO"/>
-                <constraint firstItem="5Ci-V1-hf5" firstAttribute="leading" secondItem="a0p-rj-jnV" secondAttribute="trailing" constant="-25" id="UtQ-6D-cYc"/>
                 <constraint firstItem="VXh-sQ-LeX" firstAttribute="trailing" secondItem="W0L-HY-al1" secondAttribute="trailing" id="VMW-0Y-aOH"/>
-                <constraint firstItem="81G-wH-fjN" firstAttribute="top" secondItem="5Ci-V1-hf5" secondAttribute="bottom" constant="-25" id="aEb-vq-8sk"/>
                 <constraint firstItem="VXh-sQ-LeX" firstAttribute="trailing" secondItem="5Ci-V1-hf5" secondAttribute="trailing" id="cHT-cP-NN6"/>
                 <constraint firstItem="VRH-IZ-lXO" firstAttribute="top" secondItem="5Ci-V1-hf5" secondAttribute="bottom" constant="8" id="cj5-Ez-3cy"/>
                 <constraint firstItem="VRH-IZ-lXO" firstAttribute="leading" secondItem="vf1-Kf-9uL" secondAttribute="leading" constant="5" id="dTF-dl-Awr"/>
@@ -131,12 +106,9 @@
                 <constraint firstItem="12P-pO-DHO" firstAttribute="top" secondItem="2po-8g-XeS" secondAttribute="bottom" constant="3" id="hbc-KL-fRj"/>
                 <constraint firstItem="VXh-sQ-LeX" firstAttribute="bottom" secondItem="W0L-HY-al1" secondAttribute="bottom" constant="90" id="jI9-M1-Nl8"/>
                 <constraint firstItem="EJs-Ro-nbe" firstAttribute="trailing" secondItem="5Ci-V1-hf5" secondAttribute="trailing" id="l6Z-DK-OZi"/>
-                <constraint firstItem="81G-wH-fjN" firstAttribute="leading" secondItem="5Ci-V1-hf5" secondAttribute="trailing" constant="-25" id="nFH-Pc-end"/>
                 <constraint firstItem="EJs-Ro-nbe" firstAttribute="top" secondItem="VRH-IZ-lXO" secondAttribute="bottom" constant="9" id="o5n-Oi-Uh7"/>
                 <constraint firstItem="5Ci-V1-hf5" firstAttribute="trailing" secondItem="cgB-lu-t0g" secondAttribute="trailing" constant="2" id="q5r-Pz-Tnq"/>
                 <constraint firstItem="5Ci-V1-hf5" firstAttribute="leading" secondItem="VXh-sQ-LeX" secondAttribute="leading" id="qT3-WD-iTV"/>
-                <constraint firstItem="5Ci-V1-hf5" firstAttribute="top" secondItem="AYs-f2-vve" secondAttribute="bottom" constant="-25" id="rLL-6g-ypv"/>
-                <constraint firstItem="a0p-rj-jnV" firstAttribute="top" secondItem="5Ci-V1-hf5" secondAttribute="bottom" constant="-25" id="upV-Ov-WWd"/>
                 <constraint firstItem="12P-pO-DHO" firstAttribute="centerX" secondItem="vf1-Kf-9uL" secondAttribute="centerX" id="xhm-Np-2Ua"/>
             </constraints>
             <size key="customSize" width="416" height="524"/>
@@ -145,14 +117,19 @@
                     <exclude reference="cgB-lu-t0g"/>
                     <exclude reference="W0L-HY-al1"/>
                 </mask>
+                <mask key="constraints">
+                    <exclude reference="6tC-PK-fYX"/>
+                    <exclude reference="Py6-0z-K3t"/>
+                    <exclude reference="VMW-0Y-aOH"/>
+                    <exclude reference="jI9-M1-Nl8"/>
+                    <exclude reference="q5r-Pz-Tnq"/>
+                    <exclude reference="0mO-lw-JH1"/>
+                </mask>
             </variation>
             <connections>
                 <outlet property="buttonMore" destination="EJs-Ro-nbe" id="BdI-ay-LuX"/>
-                <outlet property="imageFavorite" destination="AYs-f2-vve" id="UeH-R7-bZr"/>
                 <outlet property="imageItem" destination="5Ci-V1-hf5" id="xky-Nw-NUb"/>
-                <outlet property="imageLocal" destination="81G-wH-fjN" id="bqj-wQ-CBV"/>
                 <outlet property="imageSelect" destination="DHy-Up-3Bh" id="mo9-rP-P4I"/>
-                <outlet property="imageStatus" destination="a0p-rj-jnV" id="6Dg-tf-evd"/>
                 <outlet property="imageVisualEffect" destination="W0L-HY-al1" id="WDW-2d-Npa"/>
                 <outlet property="labelInfo" destination="2po-8g-XeS" id="FJ4-wI-9cW"/>
                 <outlet property="labelSubinfo" destination="12P-pO-DHO" id="K6d-7r-FGh"/>
@@ -164,9 +141,6 @@
     <resources>
         <image name="ellipsis" catalog="system" width="128" height="37"/>
         <image name="star.fill" catalog="system" width="128" height="116"/>
-        <systemColor name="separatorColor">
-            <color red="0.23529411764705882" green="0.23529411764705882" blue="0.2627450980392157" alpha="0.28999999999999998" colorSpace="custom" customColorSpace="sRGB"/>
-        </systemColor>
         <systemColor name="systemGray2Color">
             <color red="0.68235294117647061" green="0.68235294117647061" blue="0.69803921568627447" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
         </systemColor>

+ 8 - 48
iOSClient/Trash/Cell/NCTrashListCell.swift

@@ -25,26 +25,26 @@
 
 import UIKit
 
+protocol NCTrashListCellDelegate: AnyObject {
+    func tapRestoreListItem(with objectId: String, image: UIImage?, sender: Any)
+    func tapMoreListItem(with objectId: String, image: UIImage?, sender: Any)
+}
+
 class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
 
     @IBOutlet weak var imageItem: UIImageView!
     @IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint!
     @IBOutlet weak var imageSelect: UIImageView!
-
     @IBOutlet weak var labelTitle: UILabel!
     @IBOutlet weak var labelInfo: UILabel!
-
     @IBOutlet weak var imageRestore: UIImageView!
     @IBOutlet weak var imageMore: UIImageView!
-
     @IBOutlet weak var buttonMore: UIButton!
     @IBOutlet weak var buttonRestore: UIButton!
-
     @IBOutlet weak var separator: UIView!
     @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint!
 
-    weak var listCellDelegate: NCTrashListCellDelegate?
-
+    weak var delegate: NCTrashListCellDelegate?
     var objectId = ""
     var indexPath = IndexPath()
 
@@ -79,11 +79,11 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
     }
 
     @IBAction func touchUpInsideMore(_ sender: Any) {
-        listCellDelegate?.tapMoreListItem(with: objectId, image: imageItem.image, sender: sender)
+        delegate?.tapMoreListItem(with: objectId, image: imageItem.image, sender: sender)
     }
 
     @IBAction func touchUpInsideRestore(_ sender: Any) {
-        listCellDelegate?.tapRestoreListItem(with: objectId, image: imageItem.image, sender: sender)
+        delegate?.tapRestoreListItem(with: objectId, image: imageItem.image, sender: sender)
     }
 
     func selectMode(_ status: Bool) {
@@ -130,43 +130,3 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
         }
     }
 }
-
-protocol NCTrashListCellDelegate: AnyObject {
-    func tapRestoreListItem(with objectId: String, image: UIImage?, sender: Any)
-    func tapMoreListItem(with objectId: String, image: UIImage?, sender: Any)
-}
-
-protocol NCTrashCellProtocol {
-    var objectId: String { get set }
-    var labelTitle: UILabel! { get set }
-    var labelInfo: UILabel! { get set }
-    var imageItem: UIImageView! { get set }
-    var indexPath: IndexPath { get set }
-
-    func selectMode(_ status: Bool)
-    func selected(_ status: Bool)
-}
-
-extension NCTrashCellProtocol where Self: UICollectionViewCell {
-    mutating func setupCellUI(tableTrash: tableTrash, image: UIImage?) {
-        self.objectId = tableTrash.fileId
-        self.labelTitle.text = tableTrash.trashbinFileName
-        self.labelTitle.textColor = .label
-        if self is NCTrashListCell {
-            self.labelInfo?.text = NCUtility().dateDiff(tableTrash.date as Date)
-        } else {
-            let dateFormatter = DateFormatter()
-            dateFormatter.dateStyle = .short
-            dateFormatter.timeStyle = .none
-            dateFormatter.locale = Locale.current
-            self.labelInfo?.text = dateFormatter.string(from: tableTrash.date as Date)
-        }
-        if tableTrash.directory {
-            self.imageItem.image = NCImageCache.images.folder
-        } else {
-            self.imageItem.image = image
-            self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size)
-        }
-        self.accessibilityLabel = tableTrash.trashbinFileName + ", " + (self.labelInfo?.text ?? "")
-    }
-}

+ 23 - 10
iOSClient/Trash/NCTrash+CollectionView.swift

@@ -52,7 +52,6 @@ extension NCTrash: UICollectionViewDelegate {
 // MARK: UICollectionViewDataSource
 extension NCTrash: UICollectionViewDataSource {
     func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
-        emptyDataSet?.numberOfItemsInSection(datasource.count, section: section)
         return datasource.count
     }
 
@@ -78,12 +77,12 @@ extension NCTrash: UICollectionViewDataSource {
 
         if layoutForView?.layout == NCGlobal.shared.layoutList {
             guard let listCell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? NCTrashListCell else { return NCTrashListCell() }
-            listCell.listCellDelegate = self
+            listCell.delegate = self
             cell = listCell
         } else {
             guard let gridCell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCTrashGridCell else { return NCTrashGridCell() }
             gridCell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.images.buttonMore)
-            gridCell.gridCellDelegate = self
+            gridCell.delegate = self
             cell = gridCell
         }
 
@@ -136,18 +135,32 @@ extension NCTrash: UICollectionViewDataSource {
     }
 
     func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
-        guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter
-        else { return UICollectionReusableView() }
-
-        footer.setTitleLabel(setTextFooter(datasource: datasource))
-        footer.separatorIsHidden(true)
-
-        return footer
+        if kind == UICollectionView.elementKindSectionHeader {
+            guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderEmptyData", for: indexPath) as? NCSectionHeaderEmptyData
+            else { return NCSectionHeaderEmptyData() }
+            header.emptyImage.image = UIImage(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width)
+            header.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "")
+            header.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "")
+            return header
+        } else {
+            guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter
+            else { return NCSectionFooter() }
+            footer.setTitleLabel(setTextFooter(datasource: datasource))
+            footer.separatorIsHidden(true)
+            return footer
+        }
     }
 }
 
 // MARK: UICollectionViewDelegateFlowLayout
 extension NCTrash: UICollectionViewDelegateFlowLayout {
+    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize {
+        var height: Double = 0
+        if datasource.isEmpty {
+            height = NCGlobal.shared.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: 0)
+        }
+        return CGSize(width: collectionView.frame.width, height: height)
+    }
     func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize {
         return CGSize(width: collectionView.frame.width, height: NCGlobal.shared.endHeightFooter)
     }

+ 2 - 13
iOSClient/Trash/NCTrash.swift

@@ -27,14 +27,13 @@ import Realm
 import UIKit
 import NextcloudKit
 
-class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCEmptyDataSetDelegate {
+class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate {
 
     @IBOutlet weak var collectionView: UICollectionView!
 
     var filePath = ""
     var titleCurrentFolder = NSLocalizedString("_trash_view_", comment: "")
     var blinkFileId: String?
-    var emptyDataSet: NCEmptyDataSet?
     var dataSourceTask: URLSessionTask?
     let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
     let utilityFileSystem = NCUtilityFileSystem()
@@ -60,11 +59,10 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat
         view.backgroundColor = .systemBackground
         self.navigationController?.navigationBar.prefersLargeTitles = true
 
-        // Cell
         collectionView.register(UINib(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell")
         collectionView.register(UINib(nibName: "NCTrashGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell")
 
-        // Footer
+        collectionView.register(UINib(nibName: "NCSectionHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderEmptyData")
         collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter")
 
         collectionView.alwaysBounceVertical = true
@@ -78,7 +76,6 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat
         refreshControl.tintColor = .gray
         refreshControl.addTarget(self, action: #selector(loadListingTrash), for: .valueChanged)
 
-        emptyDataSet = NCEmptyDataSet(view: collectionView, offset: NCGlobal.shared.heightButtonsView, delegate: self)
         setNavigationRightItems()
 
         NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil)
@@ -167,14 +164,6 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat
         }
     }
 
-    // MARK: - Empty
-
-    func emptyDataSetView(_ view: NCEmptyView) {
-        view.emptyImage.image = UIImage(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width)
-        view.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "")
-        view.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "")
-    }
-
     // MARK: TAP EVENT
 
     func tapRestoreListItem(with ocId: String, image: UIImage?, sender: Any) {

+ 0 - 4
iOSClient/Utility/NCCameraRoll.swift

@@ -73,7 +73,6 @@ class NCCameraRoll: NSObject {
                 let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
                 self.utilityFileSystem.moveFile(atPath: fileNamePath, toPath: toPath)
                 let fetchAssets = PHAsset.fetchAssets(withLocalIdentifiers: [metadataSource.assetLocalIdentifier], options: nil)
-                // swiftlint:disable empty_count
                 if metadata.isLivePhoto, fetchAssets.count > 0 {
                     self.createMetadataLivePhoto(metadata: metadata, asset: fetchAssets.firstObject) { metadata in
                         if let metadata = metadata, let metadata = NCManageDatabase.shared.addMetadata(metadata) {
@@ -84,7 +83,6 @@ class NCCameraRoll: NSObject {
                 } else {
                     completition(metadatas)
                 }
-                // swiftlint:enable empty_count
             } else {
                 completition(metadatas)
             }
@@ -136,11 +134,9 @@ class NCCameraRoll: NSObject {
         }
 
         let fetchAssets = PHAsset.fetchAssets(withLocalIdentifiers: [metadata.assetLocalIdentifier], options: nil)
-        // swiftlint:disable empty_count
         guard fetchAssets.count > 0, let asset = fetchAssets.firstObject else {
             return callCompletionWithError()
         }
-        // swiftlint:enable empty_count
 
         let extensionAsset = asset.originalFilename.pathExtension.uppercased()
         let creationDate = asset.creationDate ?? Date()