소스 검색

Merge branch 'develop'

marinofaggiana 2 년 전
부모
커밋
e2e52363b0
100개의 변경된 파일1509개의 추가작업 그리고 721개의 파일을 삭제
  1. 6 4
      .github/workflows/lint.yml
  2. 4 2
      .github/workflows/xcode.yml
  3. 7 12
      .swiftlint.yml
  4. 1 1
      Cartfile
  5. 1 1
      Cartfile.resolved
  6. 5 3
      File Provider Extension/FileProviderItem.swift
  7. 216 72
      Nextcloud.xcodeproj/project.pbxproj
  8. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme
  9. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme
  10. 1 1
      Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme
  11. 136 0
      NextcloudTests/SharePermissionTest.swift
  12. 64 0
      NextcloudTests/UserAgentTests.swift
  13. 9 16
      Share/NCShareExtension+Files.swift
  14. 10 26
      Share/NCShareExtension.swift
  15. 5 53
      iOSClient/Activity/NCActivity.storyboard
  16. 20 47
      iOSClient/Activity/NCActivity.swift
  17. 59 0
      iOSClient/Activity/NCActivityCommentView.swift
  18. 60 0
      iOSClient/Activity/NCActivityCommentView.xib
  19. 66 61
      iOSClient/AppDelegate.swift
  20. 9 11
      iOSClient/Brand/Intro/NCIntroCollectionViewCell.xib
  21. 2 0
      iOSClient/Brand/Intro/NCIntroViewController.swift
  22. 9 9
      iOSClient/Brand/LaunchScreen.storyboard
  23. 13 1
      iOSClient/Brand/NCBrand.swift
  24. 0 12
      iOSClient/Brand/iOSClient.entitlements
  25. 36 5
      iOSClient/Brand/iOSClient.plist
  26. 17 3
      iOSClient/Data/NCDatabase.swift
  27. 2 1
      iOSClient/Data/NCElementsJSON.swift
  28. 15 0
      iOSClient/Data/NCManageDatabase+Account.swift
  29. 15 3
      iOSClient/Data/NCManageDatabase+Activity.swift
  30. 51 4
      iOSClient/Data/NCManageDatabase+Metadata.swift
  31. 152 0
      iOSClient/Data/NCManageDatabase+Video.swift
  32. 37 127
      iOSClient/Data/NCManageDatabase.swift
  33. 53 9
      iOSClient/Diagnostics/NCCapabilitiesViewController.storyboard
  34. 16 0
      iOSClient/Diagnostics/NCCapabilitiesViewController.swift
  35. 33 0
      iOSClient/Extensions/DateFormatter+Extension.swift
  36. 6 1
      iOSClient/Extensions/String+Extensions.swift
  37. 91 0
      iOSClient/Extensions/UIAlertController+Extension.swift
  38. 1 1
      iOSClient/Extensions/UIApplication+Orientation.swift
  39. 37 0
      iOSClient/Extensions/UIDevice+Extensions.swift
  40. 31 0
      iOSClient/Extensions/UIFont+Extension.swift
  41. 77 0
      iOSClient/Extensions/UIToolbar+Extension.swift
  42. BIN
      iOSClient/Font/Inconsolata/Inconsolata-Black.ttf
  43. BIN
      iOSClient/Font/Inconsolata/Inconsolata-Bold.ttf
  44. BIN
      iOSClient/Font/Inconsolata/Inconsolata-ExtraBold.ttf
  45. BIN
      iOSClient/Font/Inconsolata/Inconsolata-ExtraLight.ttf
  46. BIN
      iOSClient/Font/Inconsolata/Inconsolata-Light.ttf
  47. BIN
      iOSClient/Font/Inconsolata/Inconsolata-Medium.ttf
  48. BIN
      iOSClient/Font/Inconsolata/Inconsolata-Regular.ttf
  49. BIN
      iOSClient/Font/Inconsolata/Inconsolata-SemiBold.ttf
  50. 1 1
      iOSClient/Images.xcassets/captions.bubble.imageset/Contents.json
  51. 1 1
      iOSClient/Images.xcassets/captions.bubble.imageset/subtitles-outline.svg
  52. 0 0
      iOSClient/Images.xcassets/circle_fill.imageset/Contents.json
  53. 0 0
      iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf
  54. 0 15
      iOSClient/Images.xcassets/closeVideo.imageset/Contents.json
  55. BIN
      iOSClient/Images.xcassets/closeVideo.imageset/closeVideo.pdf
  56. 0 15
      iOSClient/Images.xcassets/edit.imageset/Contents.json
  57. BIN
      iOSClient/Images.xcassets/edit.imageset/edit.pdf
  58. 1 1
      iOSClient/Images.xcassets/eye.imageset/Contents.json
  59. 1 0
      iOSClient/Images.xcassets/eye.imageset/eye.svg
  60. 0 0
      iOSClient/Images.xcassets/lock_open.imageset/Contents.json
  61. 0 0
      iOSClient/Images.xcassets/lock_open.imageset/lock-open-variant-outline.svg
  62. 1 1
      iOSClient/Images.xcassets/moreLock.imageset/Contents.json
  63. 65 0
      iOSClient/Images.xcassets/moreLock.imageset/menu-locked-filled.svg
  64. 0 1
      iOSClient/Images.xcassets/pdf-vertical.imageset/swap-vertical-variant.svg
  65. 0 23
      iOSClient/Images.xcassets/photoEditorCancel.imageset/Contents.json
  66. BIN
      iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel.png
  67. BIN
      iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel@2x.png
  68. BIN
      iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel@3x.png
  69. 0 23
      iOSClient/Images.xcassets/photoEditorClear.imageset/Contents.json
  70. BIN
      iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear.png
  71. BIN
      iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear@2x.png
  72. BIN
      iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear@3x.png
  73. 0 23
      iOSClient/Images.xcassets/photoEditorCrop.imageset/Contents.json
  74. BIN
      iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop.png
  75. BIN
      iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop@2x.png
  76. BIN
      iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop@3x.png
  77. 0 23
      iOSClient/Images.xcassets/photoEditorDone.imageset/Contents.json
  78. BIN
      iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone.png
  79. BIN
      iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone@2x.png
  80. BIN
      iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone@3x.png
  81. 0 23
      iOSClient/Images.xcassets/photoEditorDraw.imageset/Contents.json
  82. BIN
      iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw.png
  83. BIN
      iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw@2x.png
  84. BIN
      iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw@3x.png
  85. 0 23
      iOSClient/Images.xcassets/photoEditorText.imageset/Contents.json
  86. BIN
      iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText.png
  87. BIN
      iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText@2x.png
  88. BIN
      iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText@3x.png
  89. 0 15
      iOSClient/Images.xcassets/tabBarFavorites.imageset/Contents.json
  90. BIN
      iOSClient/Images.xcassets/tabBarFavorites.imageset/tabBarFavorites.pdf
  91. 0 15
      iOSClient/Images.xcassets/tabBarMedia.imageset/Contents.json
  92. BIN
      iOSClient/Images.xcassets/tabBarMedia.imageset/tabBarMedia.pdf
  93. BIN
      iOSClient/Images.xcassets/userStatusOnline.imageset/online.pdf
  94. 0 23
      iOSClient/Images.xcassets/visiblePassword.imageset/Contents.json
  95. BIN
      iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword.png
  96. BIN
      iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword@2x.png
  97. BIN
      iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword@3x.png
  98. 3 4
      iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift
  99. 38 3
      iOSClient/Main/Collection Common/NCCollectionViewCommon.swift
  100. 23 0
      iOSClient/Main/Collection Common/NCGridCell.swift

+ 6 - 4
.github/workflows/lint.yml

@@ -9,16 +9,18 @@ on:
       - master
       - develop
   pull_request:
+    types: [synchronize, opened, reopened, ready_for_review]
     branches:
       - master
-      - develop  
+      - develop
 
 jobs:
   Lint:
     runs-on: ubuntu-latest
-    
+    if: github.event.pull_request.draft == false
+
     steps:
      - uses: actions/checkout@v2
-       
+
      - name: GitHub Action for SwiftLint
-       uses: norio-nomura/action-swiftlint@3.1.0
+       uses: norio-nomura/action-swiftlint@3.1.0

+ 4 - 2
.github/workflows/xcode.yml

@@ -1,11 +1,12 @@
 name: Build
 
-on: 
+on:
   push:
-    branches: 
+    branches:
       - master
       - develop
   pull_request:
+    types: [synchronize, opened, reopened, ready_for_review]
     branches: 
       - master
       - develop
@@ -13,6 +14,7 @@ on:
 jobs:
   XCBuild:
     runs-on: macOS-11
+    if: github.event.pull_request.draft == false
     env:
       PROJECT: Nextcloud.xcodeproj
       DESTINATION: platform=iOS Simulator,name=iPhone 11

+ 7 - 12
.swiftlint.yml

@@ -10,10 +10,14 @@ empty_count:
   severity: warning
 
 line_length:
-  # warning: 120
+  # warning: 120, error: 200
   warning: 250
   error: 250
 
+function_body_length:
+  # warning: 40
+  warning: 60
+
 type_body_length:
   # error: 350
   error: 500
@@ -48,7 +52,8 @@ excluded:
   - iOSClient/Data/NCManageDatabase+Account.swift
   - iOSClient/Data/NCManageDatabase+Activity.swift
   - iOSClient/Data/NCManageDatabase.swift
-  - iOSClient/Data/NCManageDatabse+Metadata.swift
+  - iOSClient/Data/NCManageDatabase+Metadata.swift
+  - iOSClient/Data/NCManageDatabase+Video.swift
   - iOSClient/Diagnostics/NCCapabilitiesViewController.swift
   - iOSClient/EmptyView/NCEmptyDataSet.swift
   - iOSClient/Extensions/UIColor+Extensions.swift
@@ -105,16 +110,8 @@ excluded:
   - iOSClient/Select/NCSelect.swift
   - iOSClient/Settings/NCEndToEndInitialize.swift
   - iOSClient/Settings/NCManageAutoUploadFileName.swift
-  - iOSClient/Share/NCShare.swift
-  - iOSClient/Share/NCShareCommentsCell.swift
   - iOSClient/Share/NCShareCommon.swift
-  - iOSClient/Share/NCShareLinkCell.swift
-  - iOSClient/Share/NCShareLinkMenuView.swift
   - iOSClient/Share/NCShareNetworking.swift
-  - iOSClient/Share/NCSharePaging.swift
-  - iOSClient/Share/NCShareQuickStatusMenu.swift
-  - iOSClient/Share/NCShareUserCell.swift
-  - iOSClient/Share/NCShareUserMenuView.swift
   - iOSClient/Shares/NCShares.swift
   - iOSClient/Transfers/NCTransferCell.swift
   - iOSClient/Transfers/NCTransfers.swift
@@ -130,13 +127,11 @@ excluded:
   - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayer.swift
   - iOSClient/Viewer/NCViewerMedia/NCPlayer/NCPlayerToolBar.swift
   - iOSClient/Viewer/NCViewerMedia/NCViewerMedia.swift
-  - iOSClient/Viewer/NCViewerMedia/NCViewerMediaDetailView.swift
   - iOSClient/Viewer/NCViewerMedia/NCViewerMediaPage.swift
   - iOSClient/Viewer/NCViewerNextcloudText/NCViewerNextcloudText.swift
   - iOSClient/Viewer/NCViewerPDF/NCViewerPDF.swift
   - iOSClient/Viewer/NCViewerPDF/NCViewerPDFSearch.swift
   - iOSClient/Viewer/NCViewerProviderContextMenu.swift
-  - iOSClient/Viewer/NCViewerQuickLook/NCViewerQuickLook.swift
   - iOSClient/Viewer/NCViewerRichdocument/NCViewerRichdocument.swift
 
 

+ 1 - 1
Cartfile

@@ -1,3 +1,3 @@
-github "https://github.com/marinofaggiana/KTVHTTPCache" "2.0.2"
+github "https://github.com/marinofaggiana/KTVHTTPCache" "2.0.5"
 github "https://github.com/marinofaggiana/TOPasscodeViewController" "master"
 github "krzyzanowskim/OpenSSL"

+ 1 - 1
Cartfile.resolved

@@ -1,3 +1,3 @@
 github "krzyzanowskim/OpenSSL" "1.1.1300"
-github "marinofaggiana/KTVHTTPCache" "2.0.2"
+github "marinofaggiana/KTVHTTPCache" "2.0.5"
 github "marinofaggiana/TOPasscodeViewController" "a1b9d1058b2648e636525fc368e220a0cfddb42a"

+ 5 - 3
File Provider Extension/FileProviderItem.swift

@@ -60,11 +60,13 @@ class FileProviderItem: NSObject, NSFileProviderItem {
     }
 
     var capabilities: NSFileProviderItemCapabilities {
-        if metadata.directory {
+        guard !metadata.directory else {
             return [ .allowsAddingSubItems, .allowsContentEnumerating, .allowsReading, .allowsDeleting, .allowsRenaming ]
-        } else {
-            return [ .allowsWriting, .allowsReading, .allowsDeleting, .allowsRenaming, .allowsReparenting ]
         }
+        guard !metadata.lock else {
+            return [ .allowsReading ]
+        }
+        return [ .allowsWriting, .allowsReading, .allowsDeleting, .allowsRenaming, .allowsReparenting ]
     }
 
     var isTrashed: Bool {

+ 216 - 72
Nextcloud.xcodeproj/project.pbxproj

@@ -18,6 +18,8 @@
 		371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 371B5A2D23D0B04500FAFAE9 /* NCMenu.swift */; };
 		3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */; };
 		8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */; };
+		AF1A9B6427D0CA1E00F17A9E /* UIAlertController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */; };
+		AF1A9B6527D0CC0500F17A9E /* UIAlertController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */; };
 		AF22B206277B4E4C00DAB0CC /* NCCreateFormUploadConflict.swift in Sources */ = {isa = PBXBuildFile; fileRef = F704B5E42430AA8000632F5F /* NCCreateFormUploadConflict.swift */; };
 		AF22B207277B4E4C00DAB0CC /* NCCreateFormUploadConflict.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F704B5E22430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard */; };
 		AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F704B5E82430C0B800632F5F /* NCCreateFormUploadConflictCell.swift */; };
@@ -29,21 +31,25 @@
 		AF2D7C7E2742559100ADF566 /* NCShareUserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */; };
 		AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF36077027BFA4E8001A243D /* ParallelWorker.swift */; };
 		AF36077627BFB019001A243D /* ParallelWorkerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF36077527BFB019001A243D /* ParallelWorkerTest.swift */; };
+		AF3F909A28213BEA0048A93E /* UserAgentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF3F909928213BEA0048A93E /* UserAgentTests.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 */; };
 		AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */; };
-		AF4BF61927562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; };
-		AF4BF61A27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; };
-		AF4BF61B27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; };
-		AF4BF61C27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */; };
+		AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
+		AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
+		AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
+		AF4BF61C27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */; };
 		AF4BF61E27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
 		AF4BF61F27562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
 		AF4BF62027562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
 		AF4BF62127562B3F0081CEEF /* NCManageDatabase+Activity.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */; };
+		AF56C1DC2784856200D8BAE2 /* NCActivityCommentView.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF56C1DB2784856200D8BAE2 /* NCActivityCommentView.xib */; };
 		AF68326A27BE65A90010BF0B /* NCMenuAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF68326927BE65A90010BF0B /* NCMenuAction.swift */; };
+		AF70C14D27F3484D00E13DF2 /* SharePermissionTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */; };
+		AF730AF827834B1400B7520E /* NCShare+NCCellDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */; };
 		AF730AFA27843E4C00B7520E /* NCShareExtension+NCDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF730AF927843E4C00B7520E /* NCShareExtension+NCDelegate.swift */; };
 		AF7E504E27A2D8FF00B5E4AF /* UIBarButton+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */; };
 		AF7E505027A2D92300B5E4AF /* NCSelectableNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF7E504F27A2D92300B5E4AF /* NCSelectableNavigationView.swift */; };
@@ -53,7 +59,20 @@
 		AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */; };
 		AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */; };
 		AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */; };
+		AF93471227E2341B002537EE /* NCShare+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471127E2341B002537EE /* NCShare+Menu.swift */; };
+		AF93471927E2361E002537EE /* NCShareAdvancePermissionFooter.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */; };
+		AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471527E2361E002537EE /* NCShareAdvancePermissionHeader.swift */; };
+		AF93471B27E2361E002537EE /* NCShareAdvancePermission.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471627E2361E002537EE /* NCShareAdvancePermission.swift */; };
+		AF93471C27E2361E002537EE /* NCShareAdvancePermissionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = AF93471727E2361E002537EE /* NCShareAdvancePermissionHeader.xib */; };
+		AF93471D27E2361E002537EE /* NCShareAdvancePermissionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93471827E2361E002537EE /* NCShareAdvancePermissionFooter.swift */; };
+		AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93474B27E34120002537EE /* NCUtility+Image.swift */; };
+		AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */; };
 		AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */; };
+		AFA2AC8527849604008E1EA7 /* NCActivityCommentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA2AC8427849604008E1EA7 /* NCActivityCommentView.swift */; };
+		AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */; };
+		AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; };
+		AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; };
+		AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; };
 		AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */; };
 		D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; };
 		D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; };
@@ -142,6 +161,7 @@
 		F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */ = {isa = PBXBuildFile; fileRef = F72D404823D2082500A97FD0 /* NCViewerNextcloudText.swift */; };
 		F72D7EB7263B1207000B3DFC /* MarkdownKit in Frameworks */ = {isa = PBXBuildFile; productRef = F72D7EB6263B1207000B3DFC /* MarkdownKit */; };
 		F72DA9B425F53E4E00B87DB1 /* SwiftRichString in Frameworks */ = {isa = PBXBuildFile; productRef = F72DA9B325F53E4E00B87DB1 /* SwiftRichString */; };
+		F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */ = {isa = PBXBuildFile; fileRef = F732D23227CF8AED000B0F1B /* NCPlayerToolBar.xib */; };
 		F733598125C1C188002ABA72 /* NCAskAuthorization.swift in Sources */ = {isa = PBXBuildFile; fileRef = F733598025C1C188002ABA72 /* NCAskAuthorization.swift */; };
 		F7362A1F220C853A005101B5 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7362A1E220C853A005101B5 /* LaunchScreen.storyboard */; };
 		F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7381EDA218218C9000B1560 /* NCOffline.swift */; };
@@ -188,6 +208,7 @@
 		F74E7720277A2EF40013B958 /* XLForm in Frameworks */ = {isa = PBXBuildFile; productRef = F74E771F277A2EF40013B958 /* XLForm */; };
 		F7501C322212E57500FB1415 /* NCMedia.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7501C302212E57400FB1415 /* NCMedia.storyboard */; };
 		F7501C332212E57500FB1415 /* NCMedia.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7501C312212E57400FB1415 /* NCMedia.swift */; };
+		F753BA93281FD8020015BFB6 /* EasyTipView in Frameworks */ = {isa = PBXBuildFile; productRef = F753BA92281FD8020015BFB6 /* EasyTipView */; };
 		F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F755BD9A20594AC7008C5FBB /* NCService.swift */; };
 		F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7581D1925EFDA60004DC699 /* NCLoginWeb+Menu.swift */; };
 		F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */; };
@@ -219,10 +240,7 @@
 		F76673F022C90434007ED366 /* FileProviderUtility.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76673EF22C90433007ED366 /* FileProviderUtility.swift */; };
 		F7682FE023C36B0500983A04 /* NCMainTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7682FDF23C36B0500983A04 /* NCMainTabBar.swift */; };
 		F769453C22E9CFFF000A798A /* NCShareUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F769453B22E9CFFF000A798A /* NCShareUserCell.xib */; };
-		F769453E22E9E97E000A798A /* NCShareUserMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F769453D22E9E97D000A798A /* NCShareUserMenuView.xib */; };
 		F769454022E9F077000A798A /* NCSharePaging.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769453F22E9F077000A798A /* NCSharePaging.swift */; };
-		F769454222E9F0EE000A798A /* NCShareLinkMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454122E9F0EE000A798A /* NCShareLinkMenuView.swift */; };
-		F769454422E9F142000A798A /* NCShareUserMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454322E9F142000A798A /* NCShareUserMenuView.swift */; };
 		F769454622E9F1B0000A798A /* NCShareCommon.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454522E9F1B0000A798A /* NCShareCommon.swift */; };
 		F769454822E9F20D000A798A /* NCShareNetworking.swift in Sources */ = {isa = PBXBuildFile; fileRef = F769454722E9F20D000A798A /* NCShareNetworking.swift */; };
 		F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */ = {isa = PBXBuildFile; fileRef = F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */; };
@@ -239,7 +257,6 @@
 		F76DA963277B760E0082465B /* Queuer in Frameworks */ = {isa = PBXBuildFile; productRef = F76DA962277B760E0082465B /* Queuer */; };
 		F76DA966277B76F30082465B /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = F76DA965277B76F30082465B /* UICKeyChainStore */; };
 		F76DA969277B77EA0082465B /* DropDown in Frameworks */ = {isa = PBXBuildFile; productRef = F76DA968277B77EA0082465B /* DropDown */; };
-		F76DA96C277B78400082465B /* FSCalendar in Frameworks */ = {isa = PBXBuildFile; productRef = F76DA96B277B78400082465B /* FSCalendar */; };
 		F76DA96F277B78AE0082465B /* TLPhotoPicker in Frameworks */ = {isa = PBXBuildFile; productRef = F76DA96E277B78AE0082465B /* TLPhotoPicker */; };
 		F7707687263A853700A1BA94 /* NCContentPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = F765608E23BF813500765969 /* NCContentPresenter.swift */; };
 		F7707689263A896A00A1BA94 /* UIImage+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */; };
@@ -254,7 +271,7 @@
 		F771E3F820E239B500AFB62D /* FileProviderExtension+Thumbnail.swift in Sources */ = {isa = PBXBuildFile; fileRef = F771E3F520E239B400AFB62D /* FileProviderExtension+Thumbnail.swift */; };
 		F7725A60251F33BB00D125E0 /* NCFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7725A5E251F33BB00D125E0 /* NCFiles.swift */; };
 		F7725A61251F33BB00D125E0 /* NCFiles.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7725A5F251F33BB00D125E0 /* NCFiles.storyboard */; };
-		F774264A22EB4D0000B23912 /* NCShareUserDropDownCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F774264822EB4D0000B23912 /* NCShareUserDropDownCell.xib */; };
+		F774264A22EB4D0000B23912 /* NCSearchUserDropDownCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F774264822EB4D0000B23912 /* NCSearchUserDropDownCell.xib */; };
 		F77444F522281649000D5EB0 /* NCGridMediaCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77444F322281649000D5EB0 /* NCGridMediaCell.swift */; };
 		F77444F622281649000D5EB0 /* NCGridMediaCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F77444F422281649000D5EB0 /* NCGridMediaCell.xib */; };
 		F77444F8222816D5000D5EB0 /* NCPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77444F7222816D5000D5EB0 /* NCPickerViewController.swift */; };
@@ -269,7 +286,6 @@
 		F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */ = {isa = PBXBuildFile; fileRef = F7ACE42B1BAC0268006C0017 /* Acknowledgements.rtf */; };
 		F77B0F631D118A16002130FE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = F7E70DE91A24DE4100E1B66A /* Localizable.strings */; };
 		F77B0F7D1D118A16002130FE /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = F7F67BB81A24D27800EE80DA /* Images.xcassets */; };
-		F77EFC0C26D6751F00806ED6 /* NCShareQuickStatusMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = F77EFC0B26D6751F00806ED6 /* NCShareQuickStatusMenu.swift */; };
 		F78071091EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m in Sources */ = {isa = PBXBuildFile; fileRef = F78071081EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m */; };
 		F780710A1EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m in Sources */ = {isa = PBXBuildFile; fileRef = F78071081EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m */; };
 		F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */ = {isa = PBXBuildFile; fileRef = F70CAE391F8CF31A008125FD /* NCEndToEndEncryption.m */; };
@@ -299,8 +315,6 @@
 		F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F78F74332163757000C2ADAD /* NCTrash.storyboard */; };
 		F78F74362163781100C2ADAD /* NCTrash.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78F74352163781100C2ADAD /* NCTrash.swift */; };
 		F790110E21415BF600D7B136 /* NCViewerRichdocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = F790110D21415BF600D7B136 /* NCViewerRichdocument.swift */; };
-		F79728D422F96F2E003CACA7 /* NCShareLinkFolderMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F79728D322F96F2D003CACA7 /* NCShareLinkFolderMenuView.xib */; };
-		F79728D622F9A0B1003CACA7 /* NCShareUserFolderMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F79728D522F9A0B0003CACA7 /* NCShareUserFolderMenuView.xib */; };
 		F798F0E225880608000DAFFD /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */; };
 		F798F0E725880609000DAFFD /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */; };
 		F798F0EC2588060A000DAFFD /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */; };
@@ -356,7 +370,6 @@
 		F7D57C8B26317BDE00DE301D /* NCAccountRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7CA212B25F1333200826ABB /* NCAccountRequest.swift */; };
 		F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7D96FCB246ED7E100536D73 /* NCNetworkingCheckRemoteUser.swift */; };
 		F7DBC37C23325E02001A85BA /* NCAppConfigView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DBC37B23325E01001A85BA /* NCAppConfigView.swift */; };
-		F7DFAA8A22E22EF100FC4527 /* NCShareLinkMenuView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7DFAA8922E22EF100FC4527 /* NCShareLinkMenuView.xib */; };
 		F7DFB7F0219C5B8000680748 /* NCCreateFormUploadAssets.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DFB7EF219C5B8000680748 /* NCCreateFormUploadAssets.swift */; };
 		F7DFB7F4219C5CA800680748 /* NCCreateFormUploadScanDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7DFB7F3219C5CA800680748 /* NCCreateFormUploadScanDocument.swift */; };
 		F7E0CDCF265CE8610044854E /* NCUserStatus.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = F7E0CDCE265CE8610044854E /* NCUserStatus.storyboard */; };
@@ -364,6 +377,10 @@
 		F7E572FD278F146C00F8C99E /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = F70B86802642CF5400ED5349 /* OpenSSL.xcframework */; };
 		F7E572FE278F146C00F8C99E /* OpenSSL.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = F70B86802642CF5400ED5349 /* OpenSSL.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		F7E57302278F14FF00F8C99E /* OpenSSL.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = F70B86802642CF5400ED5349 /* OpenSSL.xcframework */; };
+		F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
+		F7E98C1727E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */; };
+		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 */; };
 		F7EBCDCF277B81FF00A4EF67 /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = F7EBCDCE277B81FF00A4EF67 /* UICKeyChainStore */; };
 		F7EBCDD1277B820D00A4EF67 /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = F7EBCDD0277B820D00A4EF67 /* UICKeyChainStore */; };
 		F7EBCDD3277B821700A4EF67 /* UICKeyChainStore in Frameworks */ = {isa = PBXBuildFile; productRef = F7EBCDD2277B821700A4EF67 /* UICKeyChainStore */; };
@@ -384,6 +401,18 @@
 		F7EFC0C6256BC77700461AAD /* NCMoreUserCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7EFC0C5256BC77700461AAD /* NCMoreUserCell.xib */; };
 		F7EFC0CD256BF8DD00461AAD /* NCUserStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7EFC0CC256BF8DD00461AAD /* NCUserStatus.swift */; };
 		F7F1E54C2492369A00E42386 /* NCMediaCommandView.xib in Resources */ = {isa = PBXBuildFile; fileRef = F7F1E54B2492369A00E42386 /* NCMediaCommandView.xib */; };
+		F7F4F0F727ECDBA4008676F9 /* NCSubtitles.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F0F327ECDBA4008676F9 /* NCSubtitles.swift */; };
+		F7F4F0F927ECDBA4008676F9 /* NCSubtitlePlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F0F527ECDBA4008676F9 /* NCSubtitlePlayer.swift */; };
+		F7F4F10527ECDBDB008676F9 /* Inconsolata-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F0FD27ECDBDB008676F9 /* Inconsolata-SemiBold.ttf */; };
+		F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F0FE27ECDBDB008676F9 /* Inconsolata-Medium.ttf */; };
+		F7F4F10727ECDBDB008676F9 /* Inconsolata-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F0FF27ECDBDB008676F9 /* Inconsolata-Black.ttf */; };
+		F7F4F10827ECDBDB008676F9 /* Inconsolata-ExtraLight.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10027ECDBDB008676F9 /* Inconsolata-ExtraLight.ttf */; };
+		F7F4F10927ECDBDB008676F9 /* Inconsolata-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10127ECDBDB008676F9 /* Inconsolata-Bold.ttf */; };
+		F7F4F10A27ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10227ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf */; };
+		F7F4F10B27ECDBDB008676F9 /* Inconsolata-Light.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10327ECDBDB008676F9 /* Inconsolata-Light.ttf */; };
+		F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */; };
+		F7F4F11027ECDC4A008676F9 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F10F27ECDC4A008676F9 /* UIDevice+Extensions.swift */; };
+		F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */; };
 		F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */; };
 		F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */; };
@@ -465,6 +494,7 @@
 		371B5A3223D0BD5500FAFAE9 /* FloatingPanel.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = FloatingPanel.framework; path = Carthage/Build/iOS/FloatingPanel.framework; sourceTree = "<group>"; };
 		3781B9AF23DB2B7E006B4B1D /* AppDelegate+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AppDelegate+Menu.swift"; sourceTree = "<group>"; };
 		8491B1CC273BBA82001C8C5B /* UIViewController+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Menu.swift"; sourceTree = "<group>"; };
+		AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIAlertController+Extension.swift"; sourceTree = "<group>"; };
 		AF22B20B277C6F4D00DAB0CC /* NCShareCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCell.swift; sourceTree = "<group>"; };
 		AF22B215277D196700DAB0CC /* NCShareExtension+DataSource.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCShareExtension+DataSource.swift"; sourceTree = "<group>"; };
 		AF22B216277D196700DAB0CC /* NCShareExtension+Files.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCShareExtension+Files.swift"; sourceTree = "<group>"; };
@@ -472,11 +502,15 @@
 		AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareUserCell.swift; sourceTree = "<group>"; };
 		AF36077027BFA4E8001A243D /* ParallelWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelWorker.swift; sourceTree = "<group>"; };
 		AF36077527BFB019001A243D /* ParallelWorkerTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParallelWorkerTest.swift; sourceTree = "<group>"; };
+		AF3F909928213BEA0048A93E /* UserAgentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserAgentTests.swift; sourceTree = "<group>"; };
 		AF3FDCC12796ECC300710F60 /* NCTrash+CollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCTrash+CollectionView.swift"; sourceTree = "<group>"; };
 		AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Account.swift"; sourceTree = "<group>"; };
-		AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabse+Metadata.swift"; sourceTree = "<group>"; };
+		AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Metadata.swift"; sourceTree = "<group>"; };
 		AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Activity.swift"; sourceTree = "<group>"; };
+		AF56C1DB2784856200D8BAE2 /* NCActivityCommentView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCActivityCommentView.xib; sourceTree = "<group>"; };
 		AF68326927BE65A90010BF0B /* NCMenuAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMenuAction.swift; sourceTree = "<group>"; };
+		AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharePermissionTest.swift; sourceTree = "<group>"; };
+		AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+NCCellDelegate.swift"; sourceTree = "<group>"; };
 		AF730AF927843E4C00B7520E /* NCShareExtension+NCDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShareExtension+NCDelegate.swift"; sourceTree = "<group>"; };
 		AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIBarButton+Extension.swift"; sourceTree = "<group>"; };
 		AF7E504F27A2D92300B5E4AF /* NCSelectableNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSelectableNavigationView.swift; sourceTree = "<group>"; };
@@ -484,7 +518,20 @@
 		AF8ED1F92757821000B8DBC4 /* NextcloudTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 		AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudTests.swift; sourceTree = "<group>"; };
 		AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCGlobalTests.swift; sourceTree = "<group>"; };
+		AF93471127E2341B002537EE /* NCShare+Menu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Menu.swift"; sourceTree = "<group>"; };
+		AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareAdvancePermissionFooter.xib; sourceTree = "<group>"; };
+		AF93471527E2361E002537EE /* NCShareAdvancePermissionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAdvancePermissionHeader.swift; sourceTree = "<group>"; };
+		AF93471627E2361E002537EE /* NCShareAdvancePermission.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAdvancePermission.swift; sourceTree = "<group>"; };
+		AF93471727E2361E002537EE /* NCShareAdvancePermissionHeader.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareAdvancePermissionHeader.xib; sourceTree = "<group>"; };
+		AF93471827E2361E002537EE /* NCShareAdvancePermissionFooter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareAdvancePermissionFooter.swift; sourceTree = "<group>"; };
+		AF93474B27E34120002537EE /* NCUtility+Image.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCUtility+Image.swift"; sourceTree = "<group>"; };
+		AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareNewUserAddComment.swift; sourceTree = "<group>"; };
 		AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMenu+FloatingPanel.swift"; sourceTree = "<group>"; };
+		AFA2AC8427849604008E1EA7 /* NCActivityCommentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityCommentView.swift; sourceTree = "<group>"; };
+		AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIToolbar+Extension.swift"; sourceTree = "<group>"; };
+		AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = "<group>"; };
+		AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = "<group>"; };
+		AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = "<group>"; };
 		AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Orientation.swift"; sourceTree = "<group>"; };
 		D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
@@ -610,6 +657,7 @@
 		F72E0B9C21AD60BC00898D7B /* WeScan.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WeScan.framework; path = Carthage/Build/iOS/WeScan.framework; sourceTree = "<group>"; };
 		F7320934201B812F008A0888 /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
 		F732093B201B81E4008A0888 /* es-419 */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-419"; path = "es-419.lproj/Localizable.strings"; sourceTree = "<group>"; };
+		F732D23227CF8AED000B0F1B /* NCPlayerToolBar.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCPlayerToolBar.xib; sourceTree = "<group>"; };
 		F733598025C1C188002ABA72 /* NCAskAuthorization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAskAuthorization.swift; sourceTree = "<group>"; };
 		F733B65121997CC1001C1FFA /* TLPhotoPicker.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = TLPhotoPicker.framework; path = Carthage/Build/iOS/TLPhotoPicker.framework; sourceTree = "<group>"; };
 		F7362A1E220C853A005101B5 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
@@ -682,10 +730,7 @@
 		F76673EF22C90433007ED366 /* FileProviderUtility.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileProviderUtility.swift; sourceTree = "<group>"; };
 		F7682FDF23C36B0500983A04 /* NCMainTabBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMainTabBar.swift; sourceTree = "<group>"; };
 		F769453B22E9CFFF000A798A /* NCShareUserCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserCell.xib; sourceTree = "<group>"; };
-		F769453D22E9E97D000A798A /* NCShareUserMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserMenuView.xib; sourceTree = "<group>"; };
 		F769453F22E9F077000A798A /* NCSharePaging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSharePaging.swift; sourceTree = "<group>"; };
-		F769454122E9F0EE000A798A /* NCShareLinkMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareLinkMenuView.swift; sourceTree = "<group>"; };
-		F769454322E9F142000A798A /* NCShareUserMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareUserMenuView.swift; sourceTree = "<group>"; };
 		F769454522E9F1B0000A798A /* NCShareCommon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommon.swift; sourceTree = "<group>"; };
 		F769454722E9F20D000A798A /* NCShareNetworking.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareNetworking.swift; sourceTree = "<group>"; };
 		F76B3CCD1EAE01BD00921AC9 /* NCBrand.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCBrand.swift; sourceTree = "<group>"; };
@@ -706,7 +751,7 @@
 		F7725A5E251F33BB00D125E0 /* NCFiles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCFiles.swift; sourceTree = "<group>"; };
 		F7725A5F251F33BB00D125E0 /* NCFiles.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = NCFiles.storyboard; sourceTree = "<group>"; };
 		F774264022EB3F7300B23912 /* DropDown.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DropDown.framework; path = Carthage/Build/iOS/DropDown.framework; sourceTree = "<group>"; };
-		F774264822EB4D0000B23912 /* NCShareUserDropDownCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserDropDownCell.xib; sourceTree = "<group>"; };
+		F774264822EB4D0000B23912 /* NCSearchUserDropDownCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSearchUserDropDownCell.xib; sourceTree = "<group>"; };
 		F77438EB1FCD694900662C46 /* ka-GE */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ka-GE"; path = "ka-GE.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F77438F21FCD69D300662C46 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
 		F77438F91FCD6A0D00662C46 /* zh-Hant-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant-TW"; path = "zh-Hant-TW.lproj/Localizable.strings"; sourceTree = "<group>"; };
@@ -731,7 +776,6 @@
 		F77910A425DD517B00CEDB9E /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = "<group>"; };
 		F77910AA25DD53C700CEDB9E /* NCSettingsBundleHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCSettingsBundleHelper.swift; sourceTree = "<group>"; };
 		F77A697C250A0FBC00FF1708 /* NCCollectionViewCommon+Menu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NCCollectionViewCommon+Menu.swift"; sourceTree = "<group>"; };
-		F77EFC0B26D6751F00806ED6 /* NCShareQuickStatusMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareQuickStatusMenu.swift; sourceTree = "<group>"; };
 		F78071071EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSNotificationCenter+MainThread.h"; sourceTree = "<group>"; };
 		F78071081EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSNotificationCenter+MainThread.m"; sourceTree = "<group>"; };
 		F785EE9C246196DF00B3F945 /* NCNetworkingE2EE.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCNetworkingE2EE.swift; sourceTree = "<group>"; };
@@ -755,8 +799,6 @@
 		F78F74352163781100C2ADAD /* NCTrash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCTrash.swift; sourceTree = "<group>"; };
 		F790110D21415BF600D7B136 /* NCViewerRichdocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewerRichdocument.swift; sourceTree = "<group>"; };
 		F79018A424092EF4007C9B6D /* ATGMediaBrowser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ATGMediaBrowser.framework; path = Carthage/Build/iOS/ATGMediaBrowser.framework; sourceTree = "<group>"; };
-		F79728D322F96F2D003CACA7 /* NCShareLinkFolderMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareLinkFolderMenuView.xib; sourceTree = "<group>"; };
-		F79728D522F9A0B0003CACA7 /* NCShareUserFolderMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareUserFolderMenuView.xib; sourceTree = "<group>"; };
 		F79918A021997F9000C2E308 /* UICKeyChainStore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UICKeyChainStore.framework; path = Carthage/Build/iOS/UICKeyChainStore.framework; sourceTree = "<group>"; };
 		F79918A72199840500C2E308 /* Sheeeeeeeeet.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sheeeeeeeeet.framework; path = Carthage/Build/iOS/Sheeeeeeeeet.framework; sourceTree = "<group>"; };
 		F79A65C22191D90F00FF6DCC /* NCSelect.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCSelect.storyboard; sourceTree = "<group>"; };
@@ -875,13 +917,13 @@
 		F7DBC37B23325E01001A85BA /* NCAppConfigView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCAppConfigView.swift; sourceTree = "<group>"; };
 		F7DBD82B23E46A4700ECB7C6 /* MarkdownKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MarkdownKit.framework; path = Carthage/Build/iOS/MarkdownKit.framework; sourceTree = "<group>"; };
 		F7DE9AB01F482FA5008DFE10 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Localizable.strings; sourceTree = "<group>"; };
-		F7DFAA8922E22EF100FC4527 /* NCShareLinkMenuView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCShareLinkMenuView.xib; sourceTree = "<group>"; };
 		F7DFB7EF219C5B8000680748 /* NCCreateFormUploadAssets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadAssets.swift; sourceTree = "<group>"; };
 		F7DFB7F3219C5CA800680748 /* NCCreateFormUploadScanDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadScanDocument.swift; sourceTree = "<group>"; };
 		F7E0CDCE265CE8610044854E /* NCUserStatus.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCUserStatus.storyboard; sourceTree = "<group>"; };
 		F7E45E6D21E75BF200579249 /* ja-JP */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ja-JP"; path = "ja-JP.lproj/Localizable.strings"; sourceTree = "<group>"; };
 		F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCommentsCell.swift; sourceTree = "<group>"; };
 		F7E856182351D7BE009A3330 /* SwiftyXMLParser.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftyXMLParser.framework; path = Carthage/Build/iOS/SwiftyXMLParser.framework; sourceTree = "<group>"; };
+		F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCManageDatabase+Video.swift"; sourceTree = "<group>"; };
 		F7EDE508262DA9D600414FE6 /* NCSelectCommandViewSelect.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCSelectCommandViewSelect.xib; sourceTree = "<group>"; };
 		F7EDE513262DC2CD00414FE6 /* NCSelectCommandViewSelect+CreateFolder.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = "NCSelectCommandViewSelect+CreateFolder.xib"; sourceTree = "<group>"; };
 		F7EDE51A262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NCSelectCommandViewCopyMove.xib; sourceTree = "<group>"; };
@@ -890,6 +932,18 @@
 		F7EFC0CC256BF8DD00461AAD /* NCUserStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCUserStatus.swift; sourceTree = "<group>"; };
 		F7F1E54B2492369A00E42386 /* NCMediaCommandView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCMediaCommandView.xib; sourceTree = "<group>"; };
 		F7F35B592578FB63003F5589 /* CollaboraOnlineWebViewKeyboardManager.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CollaboraOnlineWebViewKeyboardManager.framework; path = Carthage/Build/iOS/CollaboraOnlineWebViewKeyboardManager.framework; sourceTree = "<group>"; };
+		F7F4F0F327ECDBA4008676F9 /* NCSubtitles.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSubtitles.swift; sourceTree = "<group>"; };
+		F7F4F0F527ECDBA4008676F9 /* NCSubtitlePlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCSubtitlePlayer.swift; sourceTree = "<group>"; };
+		F7F4F0FD27ECDBDB008676F9 /* Inconsolata-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-SemiBold.ttf"; sourceTree = "<group>"; };
+		F7F4F0FE27ECDBDB008676F9 /* Inconsolata-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Medium.ttf"; sourceTree = "<group>"; };
+		F7F4F0FF27ECDBDB008676F9 /* Inconsolata-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Black.ttf"; sourceTree = "<group>"; };
+		F7F4F10027ECDBDB008676F9 /* Inconsolata-ExtraLight.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-ExtraLight.ttf"; sourceTree = "<group>"; };
+		F7F4F10127ECDBDB008676F9 /* Inconsolata-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Bold.ttf"; sourceTree = "<group>"; };
+		F7F4F10227ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-ExtraBold.ttf"; sourceTree = "<group>"; };
+		F7F4F10327ECDBDB008676F9 /* Inconsolata-Light.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Light.ttf"; sourceTree = "<group>"; };
+		F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Inconsolata-Regular.ttf"; sourceTree = "<group>"; };
+		F7F4F10F27ECDC4A008676F9 /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = "<group>"; };
+		F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIFont+Extension.swift"; sourceTree = "<group>"; };
 		F7F67BB81A24D27800EE80DA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
 		F7F878AD1FB9E3B900599E4F /* NCEndToEndMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCEndToEndMetadata.swift; sourceTree = "<group>"; };
 		F7F9D1BA25397CE000D9BFF5 /* NCViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCViewer.swift; sourceTree = "<group>"; };
@@ -964,6 +1018,7 @@
 				F758A01227A7F03E0069468B /* JGProgressHUD in Frameworks */,
 				F76DA96F277B78AE0082465B /* TLPhotoPicker in Frameworks */,
 				F76DA966277B76F30082465B /* UICKeyChainStore in Frameworks */,
+				F753BA93281FD8020015BFB6 /* EasyTipView in Frameworks */,
 				F76DA95B277B75A90082465B /* TOPasscodeViewController.xcframework in Frameworks */,
 				F76DA963277B760E0082465B /* Queuer in Frameworks */,
 				F75E57BD25BF0EC1002B72C2 /* SVGKit in Frameworks */,
@@ -974,7 +1029,6 @@
 				F72DA9B425F53E4E00B87DB1 /* SwiftRichString in Frameworks */,
 				F74E7720277A2EF40013B958 /* XLForm in Frameworks */,
 				F73ADD1C265546890069EA0D /* SwiftEntryKit in Frameworks */,
-				F76DA96C277B78400082465B /* FSCalendar in Frameworks */,
 				F76DA93F277B75870082465B /* KTVCocoaHTTPServer.xcframework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -1005,6 +1059,7 @@
 				F7581D2325EFDDDF004DC699 /* NCMedia+Menu.swift */,
 				F7CBC31B24F78E79004D3812 /* NCSortMenu.swift */,
 				F75D19E225EFE09000D74598 /* NCTrash+Menu.swift */,
+				AF93471127E2341B002537EE /* NCShare+Menu.swift */,
 				F710D2012405826100A6033D /* NCViewer+Menu.swift */,
 			);
 			path = Menu;
@@ -1015,11 +1070,27 @@
 			children = (
 				AF8ED2022757822700B8DBC4 /* NCGlobalTests.swift */,
 				AF36077527BFB019001A243D /* ParallelWorkerTest.swift */,
+				AF70C14C27F3484D00E13DF2 /* SharePermissionTest.swift */,
+				AF3F909928213BEA0048A93E /* UserAgentTests.swift */,
 				AF8ED1FB2757821000B8DBC4 /* NextcloudTests.swift */,
 			);
 			path = NextcloudTests;
 			sourceTree = "<group>";
 		};
+		AF93471327E235EB002537EE /* Advanced */ = {
+			isa = PBXGroup;
+			children = (
+				AF93471627E2361E002537EE /* NCShareAdvancePermission.swift */,
+				AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */,
+				AF93471827E2361E002537EE /* NCShareAdvancePermissionFooter.swift */,
+				AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */,
+				AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */,
+				AF93471527E2361E002537EE /* NCShareAdvancePermissionHeader.swift */,
+				AF93471727E2361E002537EE /* NCShareAdvancePermissionHeader.xib */,
+			);
+			path = Advanced;
+			sourceTree = "<group>";
+		};
 		F70211F31BAC56E9003FC03E /* Main */ = {
 			isa = PBXGroup;
 			children = (
@@ -1153,24 +1224,20 @@
 			children = (
 				F700510022DF63AC003A3356 /* NCShare.storyboard */,
 				F700510422DF6A89003A3356 /* NCShare.swift */,
+				AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */,
+				AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */,
+				AF93471327E235EB002537EE /* Advanced */,
 				F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */,
 				F7E4D9C322ED929B003675FD /* NCShareCommentsCell.swift */,
 				F769454522E9F1B0000A798A /* NCShareCommon.swift */,
 				F73CB3B122E072A000AD728E /* NCShareHeaderView.xib */,
 				F787704E22E7019900F287A9 /* NCShareLinkCell.xib */,
 				AF2D7C7B2742556F00ADF566 /* NCShareLinkCell.swift */,
-				F79728D322F96F2D003CACA7 /* NCShareLinkFolderMenuView.xib */,
-				F769454122E9F0EE000A798A /* NCShareLinkMenuView.swift */,
-				F7DFAA8922E22EF100FC4527 /* NCShareLinkMenuView.xib */,
 				F769454722E9F20D000A798A /* NCShareNetworking.swift */,
 				F769453F22E9F077000A798A /* NCSharePaging.swift */,
-				F77EFC0B26D6751F00806ED6 /* NCShareQuickStatusMenu.swift */,
+				F774264822EB4D0000B23912 /* NCSearchUserDropDownCell.xib */,
 				F769453B22E9CFFF000A798A /* NCShareUserCell.xib */,
 				AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */,
-				F774264822EB4D0000B23912 /* NCShareUserDropDownCell.xib */,
-				F79728D522F9A0B0003CACA7 /* NCShareUserFolderMenuView.xib */,
-				F769453D22E9E97D000A798A /* NCShareUserMenuView.xib */,
-				F769454322E9F142000A798A /* NCShareUserMenuView.swift */,
 			);
 			path = Share;
 			sourceTree = "<group>";
@@ -1377,7 +1444,9 @@
 		F79EDA9E26B004980007D134 /* NCPlayer */ = {
 			isa = PBXGroup;
 			children = (
+				F7F4F0F227ECDBA4008676F9 /* NCSubtitle */,
 				F79EDAA126B004980007D134 /* NCPlayer.swift */,
+				F732D23227CF8AED000B0F1B /* NCPlayerToolBar.xib */,
 				F79EDA9F26B004980007D134 /* NCPlayerToolBar.swift */,
 				F716B75E26F09DF600D37EFC /* NCKTVHTTPCache.swift */,
 			);
@@ -1392,11 +1461,16 @@
 				F78071071EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.h */,
 				F78071081EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m */,
 				F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */,
+				AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */,
+				AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */,
+				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
+				AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */,
+				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
 				F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extensions.swift */,
-				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
+				F7F4F10F27ECDC4A008676F9 /* UIDevice+Extensions.swift */,
+				F7F4F11127ECDC52008676F9 /* UIFont+Extension.swift */,
 				F713FEFE2472764000214AF6 /* UIImage+animatedGIF.h */,
-				AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */,
 				F713FEFF2472764100214AF6 /* UIImage+animatedGIF.m */,
 				F7B7504A2397D38E004E13EC /* UIImage+Extensions.swift */,
 			);
@@ -1416,7 +1490,9 @@
 			isa = PBXGroup;
 			children = (
 				F7C9555221F0C4CA0024296E /* NCActivity.storyboard */,
+				AF56C1DB2784856200D8BAE2 /* NCActivityCommentView.xib */,
 				F7C9555421F0C5470024296E /* NCActivity.swift */,
+				AFA2AC8427849604008E1EA7 /* NCActivityCommentView.swift */,
 				D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */,
 			);
 			path = Activity;
@@ -1473,7 +1549,8 @@
 				F7BAADB51ED5A87C00B7EAD4 /* NCManageDatabase.swift */,
 				AF4BF61D27562B3F0081CEEF /* NCManageDatabase+Activity.swift */,
 				AF4BF613275629E20081CEEF /* NCManageDatabase+Account.swift */,
-				AF4BF61827562A4B0081CEEF /* NCManageDatabse+Metadata.swift */,
+				AF4BF61827562A4B0081CEEF /* NCManageDatabase+Metadata.swift */,
+				F7E98C1527E0D0FC001F9F19 /* NCManageDatabase+Video.swift */,
 				F73D5E46246DE09200DF6467 /* NCElementsJSON.swift */,
 			);
 			path = Data;
@@ -1503,6 +1580,7 @@
 				F70968A324212C4E00ED60E5 /* NCLivePhoto.swift */,
 				F707C26421A2DC5200F6181E /* NCStoreReview.swift */,
 				F70BFC7320E0FA7C00C67599 /* NCUtility.swift */,
+				AF93474B27E34120002537EE /* NCUtility+Image.swift */,
 				AF817EF0274BC781009ED85B /* NCUserBaseUrl.swift */,
 				F74AF3A3247FB6AE00AC767B /* NCUtilityFileSystem.swift */,
 				AF36077027BFA4E8001A243D /* ParallelWorker.swift */,
@@ -1642,6 +1720,38 @@
 			path = UserStatus;
 			sourceTree = "<group>";
 		};
+		F7F4F0F227ECDBA4008676F9 /* NCSubtitle */ = {
+			isa = PBXGroup;
+			children = (
+				F7F4F0F327ECDBA4008676F9 /* NCSubtitles.swift */,
+				F7F4F0F527ECDBA4008676F9 /* NCSubtitlePlayer.swift */,
+			);
+			path = NCSubtitle;
+			sourceTree = "<group>";
+		};
+		F7F4F0FB27ECDBDA008676F9 /* Font */ = {
+			isa = PBXGroup;
+			children = (
+				F7F4F0FC27ECDBDB008676F9 /* Inconsolata */,
+			);
+			path = Font;
+			sourceTree = "<group>";
+		};
+		F7F4F0FC27ECDBDB008676F9 /* Inconsolata */ = {
+			isa = PBXGroup;
+			children = (
+				F7F4F0FD27ECDBDB008676F9 /* Inconsolata-SemiBold.ttf */,
+				F7F4F0FE27ECDBDB008676F9 /* Inconsolata-Medium.ttf */,
+				F7F4F0FF27ECDBDB008676F9 /* Inconsolata-Black.ttf */,
+				F7F4F10027ECDBDB008676F9 /* Inconsolata-ExtraLight.ttf */,
+				F7F4F10127ECDBDB008676F9 /* Inconsolata-Bold.ttf */,
+				F7F4F10227ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf */,
+				F7F4F10327ECDBDB008676F9 /* Inconsolata-Light.ttf */,
+				F7F4F10427ECDBDB008676F9 /* Inconsolata-Regular.ttf */,
+			);
+			path = Inconsolata;
+			sourceTree = "<group>";
+		};
 		F7F67B9F1A24D27800EE80DA = {
 			isa = PBXGroup;
 			children = (
@@ -1673,6 +1783,7 @@
 				F7BAAD951ED5A63D00B7EAD4 /* Data */,
 				F73FAEE224D2CA830090692E /* Diagnostics */,
 				F723986F253D867900257F49 /* EmptyView */,
+				F7A0D14E259229FA008F8A13 /* Extensions */,
 				F7A3214D1E9E2A070069AD1B /* Favorites */,
 				F7725A5D251F33BB00D125E0 /* Files */,
 				F7A80BC7252624C100C7CD01 /* FileViewInFolder */,
@@ -1696,7 +1807,6 @@
 				F7E9C41320F4CA870040CF18 /* Transfers */,
 				F78F74322163753B00C2ADAD /* Trash */,
 				F7EFC0CB256BF89300461AAD /* UserStatus */,
-				F7A0D14E259229FA008F8A13 /* Extensions */,
 				F7BFFA991A24D7BB0044ED85 /* Utility */,
 				F79630EC215526B60015EEA5 /* Viewer */,
 			);
@@ -1706,6 +1816,7 @@
 		F7F67BAB1A24D27800EE80DA /* Supporting Files */ = {
 			isa = PBXGroup;
 			children = (
+				F7F4F0FB27ECDBDA008676F9 /* Font */,
 				F72B60941A24F04E004EF66F /* Localizations */,
 				F7D154271E2392A300202FD9 /* Nextcloud-Bridging-Header.h */,
 			);
@@ -1970,13 +2081,13 @@
 				F76DA962277B760E0082465B /* Queuer */,
 				F76DA965277B76F30082465B /* UICKeyChainStore */,
 				F76DA968277B77EA0082465B /* DropDown */,
-				F76DA96B277B78400082465B /* FSCalendar */,
 				F76DA96E277B78AE0082465B /* TLPhotoPicker */,
 				F710FC79277B7D0000AA9FBF /* Realm */,
 				F710FC7B277B7D0000AA9FBF /* RealmSwift */,
 				F7233B3927835FA400F40A43 /* ChromaColorPicker */,
 				F7BB7E4627A18C56009B9F29 /* Parchment */,
 				F758A01127A7F03E0069468B /* JGProgressHUD */,
+				F753BA92281FD8020015BFB6 /* EasyTipView */,
 			);
 			productName = "Crypto Cloud";
 			productReference = F7CE8AFA1DC1F8D8009CAE48 /* Nextcloud.app */;
@@ -1989,7 +2100,7 @@
 			isa = PBXProject;
 			attributes = {
 				LastSwiftUpdateCheck = 1310;
-				LastUpgradeCheck = 1320;
+				LastUpgradeCheck = 1330;
 				ORGANIZATIONNAME = "Marino Faggiana";
 				TargetAttributes = {
 					2C33C47E23E2C475005F963B = {
@@ -2098,12 +2209,12 @@
 				F76DA961277B760E0082465B /* XCRemoteSwiftPackageReference "Queuer" */,
 				F76DA964277B76F10082465B /* XCRemoteSwiftPackageReference "UICKeyChainStore" */,
 				F76DA967277B77E90082465B /* XCRemoteSwiftPackageReference "DropDown" */,
-				F76DA96A277B78400082465B /* XCRemoteSwiftPackageReference "FSCalendar" */,
 				F76DA96D277B78AE0082465B /* XCRemoteSwiftPackageReference "TLPhotoPicker" */,
 				F710FC78277B7CFF00AA9FBF /* XCRemoteSwiftPackageReference "realm-swift" */,
 				F7233B3827835FA300F40A43 /* XCRemoteSwiftPackageReference "ChromaColorPicker" */,
 				F7BB7E4527A18C56009B9F29 /* XCRemoteSwiftPackageReference "Parchment" */,
 				F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */,
+				F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */,
 			);
 			productRefGroup = F7F67B9F1A24D27800EE80DA;
 			projectDirPath = "";
@@ -2167,13 +2278,15 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				F79728D422F96F2E003CACA7 /* NCShareLinkFolderMenuView.xib in Resources */,
 				F7362A1F220C853A005101B5 /* LaunchScreen.storyboard in Resources */,
 				F77444F622281649000D5EB0 /* NCGridMediaCell.xib in Resources */,
 				F78ACD4421903CF20088454D /* NCListCell.xib in Resources */,
+				F7F4F10727ECDBDB008676F9 /* Inconsolata-Black.ttf in Resources */,
 				F78ACD4621903D010088454D /* NCGridCell.xib in Resources */,
+				F7F4F10827ECDBDB008676F9 /* Inconsolata-ExtraLight.ttf in Resources */,
 				F72685E727C78E490019EF5E /* InfoPlist.strings in Resources */,
 				F769453C22E9CFFF000A798A /* NCShareUserCell.xib in Resources */,
+				F7F4F10927ECDBDB008676F9 /* Inconsolata-Bold.ttf in Resources */,
 				F7A80BCA252624C100C7CD01 /* NCFileViewInFolder.storyboard in Resources */,
 				F76D3CF52428D0C1005DFA87 /* NCViewerPDF.storyboard in Resources */,
 				F700222C1EC479840080073F /* Custom.xcassets in Resources */,
@@ -2188,48 +2301,54 @@
 				F7226EDC1EE4089300EBECB1 /* Main.storyboard in Resources */,
 				F7EFC0C6256BC77700461AAD /* NCMoreUserCell.xib in Resources */,
 				F702F2E725EE5C86008F8E80 /* NCAudioRecorderViewController.storyboard in Resources */,
+				AF56C1DC2784856200D8BAE2 /* NCActivityCommentView.xib in Resources */,
 				F7632FBF21832F8700721B71 /* NCTrashSectionHeaderMenu.xib in Resources */,
+				F7F4F10B27ECDBDB008676F9 /* Inconsolata-Light.ttf in Resources */,
 				3704EB2A23D5A58400455C5B /* NCMenu.storyboard in Resources */,
+				AF93471C27E2361E002537EE /* NCShareAdvancePermissionHeader.xib in Resources */,
 				F7D0F33E264144FC0097D4A3 /* Background.xcassets in Resources */,
 				F7F1E54C2492369A00E42386 /* NCMediaCommandView.xib in Resources */,
 				F710E8111EF95C9C00DC2427 /* ImagesIntro.xcassets in Resources */,
 				F76032A0252F0F8E0015A421 /* NCTransferCell.xib in Resources */,
+				F7F4F10527ECDBDB008676F9 /* Inconsolata-SemiBold.ttf in Resources */,
 				F74C0437253F1CDC009762AB /* NCShares.storyboard in Resources */,
+				F7F4F10C27ECDBDB008676F9 /* Inconsolata-Regular.ttf in Resources */,
 				F7B8B83025681C3400967775 /* GoogleService-Info.plist in Resources */,
 				F7381EE5218218C9000B1560 /* NCOffline.storyboard in Resources */,
 				F7E0CDCF265CE8610044854E /* NCUserStatus.storyboard in Resources */,
 				F76D3CF32428B94E005DFA87 /* NCViewerPDFSearchCell.xib in Resources */,
-				F769453E22E9E97E000A798A /* NCShareUserMenuView.xib in Resources */,
 				F7CA212E25F1333300826ABB /* NCAccountRequest.storyboard in Resources */,
 				F749C10E23C4A5340027D966 /* NCIntroCollectionViewCell.xib in Resources */,
 				F717402D24F699A5000C87D5 /* NCFavorite.storyboard in Resources */,
 				F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */,
 				F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */,
+				AF93471927E2361E002537EE /* NCShareAdvancePermissionFooter.xib in Resources */,
 				F7725A61251F33BB00D125E0 /* NCFiles.storyboard in Resources */,
 				F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */,
 				F787704F22E7019900F287A9 /* NCShareLinkCell.xib in Resources */,
 				F70753F72542A9C000972D44 /* NCViewerMediaPage.storyboard in Resources */,
 				F70A58C024D0545100DED00D /* NCCapabilitiesViewController.storyboard in Resources */,
+				F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */,
 				F749C10D23C4A5340027D966 /* NCIntro.storyboard in Resources */,
 				F7239877253D86D300257F49 /* NCEmptyView.xib in Resources */,
 				F747BA1F22354D2000971601 /* NCCreateFormUploadVoiceNote.storyboard in Resources */,
 				F7651A8A23A2A3F2001403D2 /* NCCreateFormUploadDocuments.storyboard in Resources */,
+				F7F4F10A27ECDBDB008676F9 /* Inconsolata-ExtraBold.ttf in Resources */,
 				F704B5E72430C06700632F5F /* NCCreateFormUploadConflictCell.xib in Resources */,
-				F79728D622F9A0B1003CACA7 /* NCShareUserFolderMenuView.xib in Resources */,
-				F7DFAA8A22E22EF100FC4527 /* NCShareLinkMenuView.xib in Resources */,
 				F7C9555321F0C4CA0024296E /* NCActivity.storyboard in Resources */,
 				F7BC287E26663F6C004D46C5 /* NCViewCertificateDetails.storyboard in Resources */,
 				F78ACD54219047D40088454D /* NCSectionFooter.xib in Resources */,
 				F704B5E32430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard in Resources */,
 				F77B0F611D118A16002130FE /* Acknowledgements.rtf in Resources */,
 				F7EDE509262DA9D600414FE6 /* NCSelectCommandViewSelect.xib in Resources */,
+				F732D23327CF8AED000B0F1B /* NCPlayerToolBar.xib in Resources */,
 				F73D11FA253C5F4800DF9BEC /* NCViewerNextcloudText.storyboard in Resources */,
 				F7EDE51B262DD0C400414FE6 /* NCSelectCommandViewCopyMove.xib in Resources */,
 				F73B422B2476764F00A30FD3 /* NCNotification.storyboard in Resources */,
 				F7D1612023CF19E30039EBBF /* NCViewerRichWorkspace.storyboard in Resources */,
 				F77B0F631D118A16002130FE /* Localizable.strings in Resources */,
 				F7632FC1218353AA00721B71 /* NCTrashSectionFooter.xib in Resources */,
-				F774264A22EB4D0000B23912 /* NCShareUserDropDownCell.xib in Resources */,
+				F774264A22EB4D0000B23912 /* NCSearchUserDropDownCell.xib in Resources */,
 				F7CB689A2541676B0050EC94 /* NCMore.storyboard in Resources */,
 				F70B866D2642A21300ED5349 /* NCBackgroundImageColor.storyboard in Resources */,
 				F77B0F7D1D118A16002130FE /* Images.xcassets in Resources */,
@@ -2297,13 +2416,14 @@
 				F702F2D225EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F7707689263A896A00A1BA94 /* UIImage+Extensions.swift in Sources */,
 				2C1D5D7523E2DE3300334ABB /* NCDatabase.swift in Sources */,
+				F7E98C1927E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				2C1D5D7623E2DE3300334ABB /* NCManageDatabase.swift in Sources */,
 				2C33C48223E2C475005F963B /* NotificationService.swift in Sources */,
 				AF4BF617275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */,
 				F73D5E4A246DE09200DF6467 /* NCElementsJSON.swift in Sources */,
 				F79B646326CA661600838ACA /* UIControl+Extensions.swift in Sources */,
-				AF4BF61C27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */,
+				AF4BF61C27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				AF817EF4274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				F798F0EC2588060A000DAFFD /* UIColor+Extensions.swift in Sources */,
 				2CB7D1CA23E2EDCB00376EF9 /* NCPushNotificationEncryption.m in Sources */,
@@ -2315,6 +2435,8 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				AF70C14D27F3484D00E13DF2 /* SharePermissionTest.swift in Sources */,
+				AF3F909A28213BEA0048A93E /* UserAgentTests.swift in Sources */,
 				AF36077627BFB019001A243D /* ParallelWorkerTest.swift in Sources */,
 				AF8ED1FC2757821000B8DBC4 /* NextcloudTests.swift in Sources */,
 				AF8ED2032757822700B8DBC4 /* NCGlobalTests.swift in Sources */,
@@ -2336,15 +2458,17 @@
 				F70460532499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F70BFC7520E0FA7D00C67599 /* NCUtility.swift in Sources */,
 				AF22B20C277C6F4D00DAB0CC /* NCShareCell.swift in Sources */,
+				F7E98C1727E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F79B646126CA661600838ACA /* UIControl+Extensions.swift in Sources */,
 				F7EDE4CC262D7B6F00414FE6 /* NCEmptyDataSet.swift in Sources */,
-				AF4BF61A27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */,
+				AF4BF61A27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				AF4BF615275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				F798F0E225880608000DAFFD /* UIColor+Extensions.swift in Sources */,
 				AF3FDCC32796F3FB00710F60 /* NCTrashListCell.swift in Sources */,
 				AF817EF2274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				F78295311F962EFA00A572F5 /* NCEndToEndEncryption.m in Sources */,
 				F74AF3A5247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
+				AF1A9B6527D0CC0500F17A9E /* UIAlertController+Extension.swift in Sources */,
 				AF22B206277B4E4C00DAB0CC /* NCCreateFormUploadConflict.swift in Sources */,
 				F7BD71E62636EAFC00643C34 /* NCNetworkingE2EE.swift in Sources */,
 				F7F878AF1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
@@ -2387,8 +2511,9 @@
 				AF4BF616275629E20081CEEF /* NCManageDatabase+Account.swift in Sources */,
 				F7434B3620E23FE000417916 /* NCManageDatabase.swift in Sources */,
 				F798F0E725880609000DAFFD /* UIColor+Extensions.swift in Sources */,
-				AF4BF61B27562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */,
+				AF4BF61B27562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				F70460542499095400BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
+				F7E98C1827E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
 				F785EEA42461A4A600B3F945 /* NCUtility.swift in Sources */,
 				F79B646226CA661600838ACA /* UIControl+Extensions.swift in Sources */,
 				AF817EF3274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
@@ -2417,6 +2542,7 @@
 				370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */,
 				F77B0DF51D118A16002130FE /* CCUtility.m in Sources */,
 				F70D87D025EE6E58008CBBBD /* NCRenameFile.swift in Sources */,
+				F7F4F0F727ECDBA4008676F9 /* NCSubtitles.swift in Sources */,
 				F790110E21415BF600D7B136 /* NCViewerRichdocument.swift in Sources */,
 				F70B866E2642A21300ED5349 /* NCBackgroundImageColor.swift in Sources */,
 				F78ACD4021903CC20088454D /* NCGridCell.swift in Sources */,
@@ -2429,7 +2555,9 @@
 				F73F537F1E929C8500F8678D /* NCMore.swift in Sources */,
 				F702F2CF25EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
 				F72CD63A25C19EBF00F46F9A /* NCAutoUpload.swift in Sources */,
+				AF93471D27E2361E002537EE /* NCShareAdvancePermissionFooter.swift in Sources */,
 				F7DFB7F0219C5B8000680748 /* NCCreateFormUploadAssets.swift in Sources */,
+				AF1A9B6427D0CA1E00F17A9E /* UIAlertController+Extension.swift in Sources */,
 				F73B422C2476764F00A30FD3 /* NCNotification.swift in Sources */,
 				371B5A2E23D0B04500FAFAE9 /* NCMenu.swift in Sources */,
 				F79EDAA326B004980007D134 /* NCPlayerToolBar.swift in Sources */,
@@ -2441,9 +2569,11 @@
 				F7A80BCB252624C100C7CD01 /* NCFileViewInFolder.swift in Sources */,
 				F78A18B823CDE2B300F681F3 /* NCViewerRichWorkspace.swift in Sources */,
 				F77910AB25DD53C700CEDB9E /* NCSettingsBundleHelper.swift in Sources */,
-				AF4BF61927562A4B0081CEEF /* NCManageDatabse+Metadata.swift in Sources */,
+				AF4BF61927562A4B0081CEEF /* NCManageDatabase+Metadata.swift in Sources */,
 				F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */,
+				AFA2AC8527849604008E1EA7 /* NCActivityCommentView.swift in Sources */,
 				F716B75F26F09DF600D37EFC /* NCKTVHTTPCache.swift in Sources */,
+				AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */,
 				AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */,
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
@@ -2455,9 +2585,9 @@
 				F72928A0253B0937009CA4FD /* NCMainNavigationController.swift in Sources */,
 				F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */,
+				AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */,
 				F700510522DF6A89003A3356 /* NCShare.swift in Sources */,
 				F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */,
-				F769454222E9F0EE000A798A /* NCShareLinkMenuView.swift in Sources */,
 				F785EE9D246196DF00B3F945 /* NCNetworkingE2EE.swift in Sources */,
 				F76673ED22C901F6007ED366 /* FileProviderDomain.swift in Sources */,
 				F7A321AD1E9E6AD50069AD1B /* CCAdvanced.m in Sources */,
@@ -2472,16 +2602,22 @@
 				F7A0D1352591FBC5008F8A13 /* String+Extensions.swift in Sources */,
 				F77B0E5F1D118A16002130FE /* NCSettings.m in Sources */,
 				F7F9D1BB25397CE000D9BFF5 /* NCViewer.swift in Sources */,
+				AF730AF827834B1400B7520E /* NCShare+NCCellDelegate.swift in Sources */,
 				F70460522499061800BB98A7 /* NotificationCenter+MainThread.swift in Sources */,
 				F78F74362163781100C2ADAD /* NCTrash.swift in Sources */,
 				AF817EF1274BC781009ED85B /* NCUserBaseUrl.swift in Sources */,
 				AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */,
+				F7F4F0F927ECDBA4008676F9 /* NCSubtitlePlayer.swift in Sources */,
 				F7651A8B23A2A3F2001403D2 /* NCCreateFormUploadDocuments.swift in Sources */,
 				F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
 				F7417DB3216CE925007D05F5 /* NCTrashSectionHeaderFooter.swift in Sources */,
 				F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */,
+				AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */,
 				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				F702F2F725EE5CED008F8E80 /* NCLogin.swift in Sources */,
+				F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
+				F7F4F11227ECDC52008676F9 /* UIFont+Extension.swift in Sources */,
+				AF93471A27E2361E002537EE /* NCShareAdvancePermissionHeader.swift in Sources */,
 				F7F878AE1FB9E3B900599E4F /* NCEndToEndMetadata.swift in Sources */,
 				F7DBC37C23325E02001A85BA /* NCAppConfigView.swift in Sources */,
 				3781B9B023DB2B7E006B4B1D /* AppDelegate+Menu.swift in Sources */,
@@ -2494,6 +2630,7 @@
 				F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
 				F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */,
 				F749C10B23C4A5340027D966 /* NCIntroCollectionViewCell.swift in Sources */,
+				AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */,
 				F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */,
 				F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */,
 				F78071091EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m in Sources */,
@@ -2501,12 +2638,13 @@
 				F7CA212D25F1333300826ABB /* NCAccountRequest.swift in Sources */,
 				F765F73125237E3F00391DBE /* NCRecent.swift in Sources */,
 				F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
-				F769454422E9F142000A798A /* NCShareUserMenuView.swift in Sources */,
 				F7581D2425EFDDDF004DC699 /* NCMedia+Menu.swift in Sources */,
 				F738D4902756740100CD1D38 /* NCLoginNavigationController.swift in Sources */,
 				F77B0E981D118A16002130FE /* CCManageAccount.m in Sources */,
-				F77EFC0C26D6751F00806ED6 /* NCShareQuickStatusMenu.swift in Sources */,
+				AF93474C27E34120002537EE /* NCUtility+Image.swift in Sources */,
 				F702F30125EE5D2C008F8E80 /* NYMnemonic.m in Sources */,
+				AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */,
+				AF93471227E2341B002537EE /* NCShare+Menu.swift in Sources */,
 				F7EFA47825ADBA500083159A /* NCViewerProviderContextMenu.swift in Sources */,
 				F755BD9B20594AC7008C5FBB /* NCService.swift in Sources */,
 				AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */,
@@ -2522,6 +2660,7 @@
 				F79A65C62191D95E00FF6DCC /* NCSelect.swift in Sources */,
 				F75D19E325EFE09000D74598 /* NCTrash+Menu.swift in Sources */,
 				F70CAE3A1F8CF31A008125FD /* NCEndToEndEncryption.m in Sources */,
+				AF93471B27E2361E002537EE /* NCShareAdvancePermission.swift in Sources */,
 				F70753EB2542A99800972D44 /* NCViewerMediaPage.swift in Sources */,
 				F74C0436253F1CDC009762AB /* NCShares.swift in Sources */,
 				F7AE00F5230D5F9E007ACF8A /* NCLoginWeb.swift in Sources */,
@@ -2543,6 +2682,7 @@
 				F7C7B489245EBA4100D93E60 /* NCViewerQuickLook.swift in Sources */,
 				F758B45E212C569D00515F55 /* NCScanCell.swift in Sources */,
 				F7581D1A25EFDA61004DC699 /* NCLoginWeb+Menu.swift in Sources */,
+				F7F4F11027ECDC4A008676F9 /* UIDevice+Extensions.swift in Sources */,
 				F77B0ED11D118A16002130FE /* Acknowledgements.m in Sources */,
 				F70D8D8124A4A9BF000A5756 /* NCNetworkingProcessUpload.swift in Sources */,
 				F7D96FCC246ED7E200536D73 /* NCNetworkingCheckRemoteUser.swift in Sources */,
@@ -2843,6 +2983,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2865,9 +3006,9 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 0;
+				CURRENT_PROJECT_VERSION = 18;
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
-				ENABLE_BITCODE = NO;
+				ENABLE_BITCODE = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -2888,11 +3029,12 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.3.1;
+				MARKETING_VERSION = 4.4.0;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) NC";
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};
@@ -2902,6 +3044,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
+				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				CLANG_ENABLE_OBJC_WEAK = YES;
@@ -2924,9 +3067,9 @@
 				CLANG_WARN_UNREACHABLE_CODE = YES;
 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
 				COPY_PHASE_STRIP = NO;
-				CURRENT_PROJECT_VERSION = 0;
+				CURRENT_PROJECT_VERSION = 18;
 				DEVELOPMENT_TEAM = 6JLRKY9ZV7;
-				ENABLE_BITCODE = NO;
+				ENABLE_BITCODE = YES;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_PREPROCESSOR_DEFINITIONS = (
@@ -2945,11 +3088,12 @@
 					"@executable_path/Frameworks",
 					"@executable_path/../../Frameworks",
 				);
-				MARKETING_VERSION = 4.3.1;
+				MARKETING_VERSION = 4.4.0;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "";
 				SDKROOT = iphoneos;
 				SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG NC";
+				SWIFT_COMPILATION_MODE = wholemodule;
 				SWIFT_OPTIMIZATION_LEVEL = "-O";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2";
@@ -3072,12 +3216,20 @@
 				minimumVersion = 4.0.0;
 			};
 		};
+		F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/marinofaggiana/EasyTipView";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 2.0.0;
+			};
+		};
 		F75E57A725BF0D61002B72C2 /* XCRemoteSwiftPackageReference "SVGKit" */ = {
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/SVGKit/SVGKit.git";
 			requirement = {
-				branch = 3.x;
-				kind = branch;
+				kind = upToNextMinorVersion;
+				minimumVersion = 3.0.0;
 			};
 		};
 		F75EAED626D2552E00F4320E /* XCRemoteSwiftPackageReference "MarqueeLabel" */ = {
@@ -3112,14 +3264,6 @@
 				kind = branch;
 			};
 		};
-		F76DA96A277B78400082465B /* XCRemoteSwiftPackageReference "FSCalendar" */ = {
-			isa = XCRemoteSwiftPackageReference;
-			repositoryURL = "https://github.com/WenchaoD/FSCalendar";
-			requirement = {
-				kind = upToNextMajorVersion;
-				minimumVersion = 2.0.0;
-			};
-		};
 		F76DA96D277B78AE0082465B /* XCRemoteSwiftPackageReference "TLPhotoPicker" */ = {
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/tilltue/TLPhotoPicker";
@@ -3141,7 +3285,7 @@
 			repositoryURL = "https://github.com/nextcloud/ios-communication-library/";
 			requirement = {
 				kind = exactVersion;
-				version = 0.99.5;
+				version = 0.99.6;
 			};
 		};
 		F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {
@@ -3256,6 +3400,11 @@
 			package = F74E771E277A2EF40013B958 /* XCRemoteSwiftPackageReference "XLForm" */;
 			productName = XLForm;
 		};
+		F753BA92281FD8020015BFB6 /* EasyTipView */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = F753BA91281FD8010015BFB6 /* XCRemoteSwiftPackageReference "EasyTipView" */;
+			productName = EasyTipView;
+		};
 		F758A01127A7F03E0069468B /* JGProgressHUD */ = {
 			isa = XCSwiftPackageProductDependency;
 			package = F72CD01027A7E92400E59476 /* XCRemoteSwiftPackageReference "JGProgressHUD" */;
@@ -3301,11 +3450,6 @@
 			package = F76DA967277B77E90082465B /* XCRemoteSwiftPackageReference "DropDown" */;
 			productName = DropDown;
 		};
-		F76DA96B277B78400082465B /* FSCalendar */ = {
-			isa = XCSwiftPackageProductDependency;
-			package = F76DA96A277B78400082465B /* XCRemoteSwiftPackageReference "FSCalendar" */;
-			productName = FSCalendar;
-		};
 		F76DA96E277B78AE0082465B /* TLPhotoPicker */ = {
 			isa = XCSwiftPackageProductDependency;
 			package = F76DA96D277B78AE0082465B /* XCRemoteSwiftPackageReference "TLPhotoPicker" */;

+ 1 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/File Provider Extension.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1320"
+   LastUpgradeVersion = "1330"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    <BuildAction

+ 1 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/Nextcloud.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1320"
+   LastUpgradeVersion = "1330"
    version = "1.7">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
Nextcloud.xcodeproj/xcshareddata/xcschemes/Share.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "1320"
+   LastUpgradeVersion = "1330"
    wasCreatedForAppExtension = "YES"
    version = "2.0">
    <BuildAction

+ 136 - 0
NextcloudTests/SharePermissionTest.swift

@@ -0,0 +1,136 @@
+//
+//  SharePermissionTest.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 29.03.22.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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/>.
+//
+
+@testable import Nextcloud
+import XCTest
+import NCCommunication
+
+class SharePermissionTest: XCTestCase {
+    override func setUp() {
+        let json =
+        """
+        {"ocs":{"data":{"capabilities":{"files_sharing":{"default_permissions":31}}}}}
+        """.data(using: .utf8)!
+        NCManageDatabase.shared.addCapabilitiesJSon(json, account: "")
+    }
+
+    func testShareCellPermissionCell() throws {
+        let share = NCTableShareOptions(sharee: NCCommunicationSharee(), metadata: tableMetadata(), password: nil)
+        let shareConfig = NCShareConfig(parentMetadata: tableMetadata(), share: share)
+
+        for row in 0..<shareConfig.permissions.count {
+            guard let cell = shareConfig.config(for: IndexPath(row: row, section: 0)) as? NCToggleCellConfig else {
+                XCTFail("Invalid share permission cell")
+                continue
+            }
+            XCTAssertFalse(cell.isOn(for: share))
+        }
+
+        let meta = tableMetadata()
+        meta.sharePermissionsCollaborationServices = 31
+        let fullShare = NCTableShareOptions(sharee: NCCommunicationSharee(), metadata: meta, password: nil)
+        let shareFullConfig = NCShareConfig(parentMetadata: meta, share: fullShare)
+
+        for row in 0..<shareFullConfig.permissions.count {
+            guard let cell = shareConfig.config(for: IndexPath(row: row, section: 0)) as? NCToggleCellConfig else {
+                XCTFail("Invalid share permission cell")
+                continue
+            }
+            XCTAssertTrue(cell.isOn(for: fullShare))
+        }
+    }
+
+    func testSharePermission() throws {
+        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 15))
+        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 11))
+        XCTAssertTrue(NCLinkPermission.allowEdit.hasResharePermission(for: 7))
+        XCTAssertFalse(NCLinkPermission.allowEdit.hasResharePermission(for: 13))
+        XCTAssertFalse(NCLinkPermission.allowEdit.hasResharePermission(for: 1))
+
+        XCTAssertTrue(NCLinkPermission.viewOnly.hasResharePermission(for: 25))
+        XCTAssertTrue(NCLinkPermission.viewOnly.hasResharePermission(for: 17))
+        XCTAssertFalse(NCLinkPermission.viewOnly.hasResharePermission(for: 12))
+        XCTAssertFalse(NCLinkPermission.viewOnly.hasResharePermission(for: 2))
+
+        XCTAssertTrue(NCLinkPermission.fileDrop.hasResharePermission(for: 4))
+        XCTAssertFalse(NCLinkPermission.fileDrop.hasResharePermission(for: 27))
+
+        XCTAssertTrue(NCUserPermission.create.hasResharePermission(for: 4))
+        XCTAssertFalse(NCUserPermission.create.hasResharePermission(for: 27))
+
+        XCTAssertTrue(NCUserPermission.edit.hasResharePermission(for: 2))
+        XCTAssertFalse(NCUserPermission.edit.hasResharePermission(for: 29))
+
+        XCTAssertTrue(NCUserPermission.reshare.hasResharePermission(for: 16))
+        XCTAssertFalse(NCUserPermission.reshare.hasResharePermission(for: 15))
+    }
+
+    func testFileShare() throws {
+        let meta = tableMetadata()
+        meta.directory = false
+        let share = NCTableShareOptions.shareLink(metadata: meta, password: nil)
+        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
+        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forLink)
+        XCTAssertEqual(fileConfig.permissions as? [NCLinkPermission], NCLinkPermission.forFile)
+
+        meta.directory = true
+        let folderConfig = NCShareConfig(parentMetadata: meta, share: share)
+        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forLink)
+        XCTAssertEqual(folderConfig.permissions as? [NCLinkPermission], NCLinkPermission.forDirectory)
+    }
+
+    func testUserShare() throws {
+        let meta = tableMetadata()
+        meta.directory = false
+        let sharee = NCCommunicationSharee()
+        let share = NCTableShareOptions(sharee: sharee, metadata: meta, password: nil)
+        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
+        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forUser)
+        XCTAssertEqual(fileConfig.permissions as? [NCUserPermission], NCUserPermission.forFile)
+
+        meta.directory = true
+        let folderConfig = NCShareConfig(parentMetadata: meta, share: share)
+        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forUser)
+        XCTAssertEqual(folderConfig.permissions as? [NCUserPermission], NCUserPermission.forDirectory)
+    }
+
+    func testResharePermission() throws {
+        let meta = tableMetadata()
+        let permissionReadShare = NCGlobal.shared.permissionShareShare + NCGlobal.shared.permissionReadShare
+        meta.sharePermissionsCollaborationServices = permissionReadShare
+        meta.directory = false
+        let share = NCTableShareOptions.shareLink(metadata: meta, password: nil)
+        let fileConfig = NCShareConfig(parentMetadata: meta, share: share)
+        XCTAssertEqual(fileConfig.resharePermission, meta.sharePermissionsCollaborationServices)
+        XCTAssertEqual(fileConfig.advanced, NCShareDetails.forLink)
+        XCTAssertEqual(fileConfig.permissions as? [NCLinkPermission], NCLinkPermission.forFile)
+
+        meta.directory = true
+        let sharee = NCCommunicationSharee()
+        let folderShare = NCTableShareOptions(sharee: sharee, metadata: meta, password: nil)
+        let folderConfig = NCShareConfig(parentMetadata: meta, share: folderShare)
+        XCTAssertEqual(folderConfig.resharePermission, meta.sharePermissionsCollaborationServices)
+        XCTAssertEqual(folderConfig.advanced, NCShareDetails.forUser)
+        XCTAssertEqual(folderConfig.permissions as? [NCUserPermission], NCUserPermission.forDirectory)
+    }
+}

+ 64 - 0
NextcloudTests/UserAgentTests.swift

@@ -0,0 +1,64 @@
+//
+//  UserAgentTests.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 03.05.22.
+//  Copyright © 2022 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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/>.
+//
+
+@testable import Nextcloud
+import XCTest
+
+class UserAgentTests: XCTestCase {
+    // https://github.com/nextcloud/server/blob/fc826e98115b510313ddacbf6fef4ce8d041e373/lib/public/IRequest.php#L83
+    let ncServerUARegex = "^Mozilla\\/5\\.0 \\(iOS\\) (ownCloud|Nextcloud)\\-iOS.*$"
+
+    // https://github.com/ProseMirror/prosemirror-view/blob/427d278aaaacde422ed1f2b8c84bb53337162775/src/browser.js#L18-L22
+    let proseMirrorWebKitUARegex = "\\bAppleWebKit\\/(\\d+)"
+    let proseMirroriOSUARegex = "Mobile\\/\\w+"
+
+    func testDefaultUserAgent() throws {
+        let userAgent: String = CCUtility.getUserAgent()
+        let match = try matches(for: ncServerUARegex, in: userAgent).first
+        XCTAssertNotNil(match)
+    }
+
+    func testTextUserAgent() throws {
+        let userAgent: String = NCUtility.shared.getCustomUserAgentNCText()
+        let match = try matches(for: ncServerUARegex, in: userAgent).first
+        XCTAssertNotNil(match)
+
+        let iOSMatch = try matches(for: proseMirroriOSUARegex, in: userAgent).first
+        XCTAssertNotNil(iOSMatch)
+
+        // https://github.com/ProseMirror/prosemirror-view/blob/8f246f320801f8e3cac92c97f71ac91e3e327f2f/src/input.js#L521-L522
+        let webKitMatch = try matches(for: proseMirrorWebKitUARegex, in: userAgent).first
+        XCTAssertNotNil(webKitMatch)
+        XCTAssertEqual(webKitMatch!.numberOfRanges, 2)
+        let versionRange = webKitMatch!.range(at: 1)
+        let versionString = userAgent[Range(versionRange, in: userAgent)!]
+        let webkitVersion = Int(versionString) ?? 0
+        XCTAssertGreaterThanOrEqual(webkitVersion, 604)
+    }
+
+    func matches(for regex: String, in text: String) throws -> [NSTextCheckingResult] {
+        let range = NSRange(location: 0, length: text.utf16.count)
+        let regex = try NSRegularExpression(pattern: regex)
+        return regex.matches(in: text, range: range)
+    }
+}

+ 9 - 16
Share/NCShareExtension+Files.swift

@@ -47,22 +47,15 @@ extension NCShareExtension {
         collectionView.reloadData()
     }
 
-    func createFolder(with fileName: String) {
-
-        NCNetworking.shared.createFolder(fileName: fileName, serverUrl: serverUrl, account: activeAccount.account, urlBase: activeAccount.urlBase) { errorCode, errorDescription in
-
-            DispatchQueue.main.async {
-                if errorCode == 0 {
-
-                    self.serverUrl += "/" + fileName
-                    self.reloadDatasource(withLoadFolder: true)
-                    self.setNavigationBar(navigationTitle: fileName)
-
-                } else {
-                    self.showAlert(title: "_error_createsubfolders_upload_", description: errorDescription)
-                }
-            }
-        }
+    @objc func didCreateFolder(_ notification: NSNotification) {
+        guard let userInfo = notification.userInfo as NSDictionary?,
+              let ocId = userInfo["ocId"] as? String,
+              let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId)
+        else { return }
+
+        self.serverUrl += "/" + metadata.fileName
+        self.reloadDatasource(withLoadFolder: true)
+        self.setNavigationBar(navigationTitle: metadata.fileName)
     }
 
     func loadFolder() {

+ 10 - 26
Share/NCShareExtension.swift

@@ -132,6 +132,7 @@ class NCShareExtension: UIViewController {
         }
 
         NotificationCenter.default.addObserver(self, selector: #selector(triggerProgressTask(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterProgressTask), object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(didCreateFolder(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterCreateFolder), object: nil)
     }
 
     override func viewWillAppear(_ animated: Bool) {
@@ -216,10 +217,7 @@ class NCShareExtension: UIViewController {
             }
         }
 
-        let image = NCUtility.shared.loadUserImage(
-            for: activeAccount.user,
-               displayName: activeAccount.displayName,
-               userBaseUrl: activeAccount)
+        let image = NCUtility.shared.loadUserImage(for: activeAccount.user, displayName: activeAccount.displayName, userBaseUrl: activeAccount)
         let profileButton = UIButton(type: .custom)
         profileButton.setImage(image, for: .normal)
 
@@ -277,25 +275,11 @@ class NCShareExtension: UIViewController {
     }
 
     @objc func actionCreateFolder() {
-
-        let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: "", preferredStyle: .alert)
-
-        alertController.addTextField { textField in
-            textField.autocapitalizationType = UITextAutocapitalizationType.words
-        }
-
-        let actionSave = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default) { _ in
-            if let fileName = alertController.textFields?.first?.text {
-                self.createFolder(with: fileName)
-            }
+        let alertController = UIAlertController.createFolder(serverUrl: serverUrl, urlBase: activeAccount) { errorCode, errorDescription in
+            guard errorCode != 0 else { return }
+            self.showAlert(title: "_error_createsubfolders_upload_", description: errorDescription)
         }
-
-        let actionCancel = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)
-
-        alertController.addAction(actionSave)
-        alertController.addAction(actionCancel)
-
-        self.present(alertController, animated: true, completion: nil)
+        self.present(alertController, animated: true)
     }
 }
 
@@ -359,16 +343,16 @@ extension NCShareExtension {
         hud.show(in: self.view)
 
         NCNetworking.shared.upload(metadata: metadata) { } completion: { errorCode, _ in
-            if errorCode == 0 {
-                self.counterUploaded += 1
-                self.upload()
-            } else {
+            if errorCode != 0 {
                 let path = CCUtility.getDirectoryProviderStorageOcId(metadata.ocId)!
                 NCManageDatabase.shared.deleteMetadata(predicate: NSPredicate(format: "ocId == %@", metadata.ocId))
                 NCManageDatabase.shared.deleteChunks(account: metadata.account, ocId: metadata.ocId)
                 NCUtilityFileSystem.shared.deleteFile(filePath: path)
                 self.uploadErrors.append(metadata)
             }
+
+            self.counterUploaded += 1
+            self.upload()
         }
     }
 

+ 5 - 53
iOSClient/Activity/NCActivity.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19455" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="nhT-TJ-YvX">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="nhT-TJ-YvX">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19454"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -17,7 +17,7 @@
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
                             <tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="20" sectionFooterHeight="1" translatesAutoresizingMaskIntoConstraints="NO" id="X49-xg-JXO">
-                                <rect key="frame" x="0.0" y="100" width="414" height="762"/>
+                                <rect key="frame" x="0.0" y="44" width="414" height="818"/>
                                 <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                 <prototypes>
                                     <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" preservesSuperviewLayoutMargins="YES" selectionStyle="default" indentationWidth="10" reuseIdentifier="tableCell" rowHeight="120" id="ggj-aE-fnh" customClass="NCActivityTableViewCell" customModule="Nextcloud" customModuleProvider="target">
@@ -113,66 +113,18 @@
                                     <outlet property="prefetchDataSource" destination="nhT-TJ-YvX" id="317-AD-uQe"/>
                                 </connections>
                             </tableView>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="sG1-7f-3rF">
-                                <rect key="frame" x="0.0" y="0.0" width="414" height="100"/>
-                                <subviews>
-                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="hVn-Fn-7td">
-                                        <rect key="frame" x="10" y="10" width="40" height="40"/>
-                                        <constraints>
-                                            <constraint firstAttribute="height" constant="40" id="eRU-q6-wZT"/>
-                                            <constraint firstAttribute="width" constant="40" id="nee-e2-atl"/>
-                                        </constraints>
-                                    </imageView>
-                                    <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="Wz7-gw-foA">
-                                        <rect key="frame" x="60" y="60" width="344" height="30"/>
-                                        <constraints>
-                                            <constraint firstAttribute="height" constant="30" id="4ni-Qx-ber"/>
-                                        </constraints>
-                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                        <textInputTraits key="textInputTraits"/>
-                                        <connections>
-                                            <action selector="newCommentFieldDidEndOnExitWithTextField:" destination="nhT-TJ-YvX" eventType="editingDidEndOnExit" id="vPB-Eu-qkb"/>
-                                        </connections>
-                                    </textField>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="user" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="YRy-AS-CMk">
-                                        <rect key="frame" x="60" y="21.5" width="344" height="17"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                        <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                </subviews>
-                                <constraints>
-                                    <constraint firstItem="YRy-AS-CMk" firstAttribute="centerY" secondItem="hVn-Fn-7td" secondAttribute="centerY" id="CBB-vi-6Z1"/>
-                                    <constraint firstAttribute="trailing" secondItem="Wz7-gw-foA" secondAttribute="trailing" constant="10" id="CuV-5o-sFz"/>
-                                    <constraint firstItem="hVn-Fn-7td" firstAttribute="leading" secondItem="sG1-7f-3rF" secondAttribute="leading" constant="10" id="NWH-NK-FjI"/>
-                                    <constraint firstAttribute="height" constant="100" id="SfP-Sr-vbR"/>
-                                    <constraint firstItem="Wz7-gw-foA" firstAttribute="leading" secondItem="hVn-Fn-7td" secondAttribute="trailing" constant="10" id="baP-t5-Kut"/>
-                                    <constraint firstItem="Wz7-gw-foA" firstAttribute="top" secondItem="hVn-Fn-7td" secondAttribute="bottom" constant="10" id="bsh-yh-NR2"/>
-                                    <constraint firstItem="YRy-AS-CMk" firstAttribute="leading" secondItem="hVn-Fn-7td" secondAttribute="trailing" constant="10" id="chn-JO-eYr"/>
-                                    <constraint firstAttribute="bottom" secondItem="Wz7-gw-foA" secondAttribute="bottom" constant="10" id="e8b-hy-WHK"/>
-                                    <constraint firstAttribute="trailing" secondItem="YRy-AS-CMk" secondAttribute="trailing" constant="10" id="uaN-5Y-k6V"/>
-                                    <constraint firstItem="hVn-Fn-7td" firstAttribute="top" secondItem="sG1-7f-3rF" secondAttribute="top" constant="10" id="yLz-68-e22"/>
-                                </constraints>
-                            </view>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="USa-eR-a1s"/>
                         <constraints>
-                            <constraint firstItem="sG1-7f-3rF" firstAttribute="top" secondItem="vOO-VC-ekK" secondAttribute="top" id="0Wu-9f-jFf"/>
                             <constraint firstItem="X49-xg-JXO" firstAttribute="trailing" secondItem="USa-eR-a1s" secondAttribute="trailing" id="5we-Fh-GVu"/>
+                            <constraint firstItem="X49-xg-JXO" firstAttribute="top" secondItem="USa-eR-a1s" secondAttribute="top" id="E1U-4Q-6uu"/>
                             <constraint firstItem="USa-eR-a1s" firstAttribute="bottom" secondItem="X49-xg-JXO" secondAttribute="bottom" id="aHq-g4-dUG"/>
-                            <constraint firstItem="X49-xg-JXO" firstAttribute="top" secondItem="sG1-7f-3rF" secondAttribute="bottom" id="eeu-9y-t1U"/>
-                            <constraint firstItem="sG1-7f-3rF" firstAttribute="trailing" secondItem="vOO-VC-ekK" secondAttribute="trailing" id="htz-S1-01v"/>
-                            <constraint firstItem="sG1-7f-3rF" firstAttribute="leading" secondItem="vOO-VC-ekK" secondAttribute="leading" id="lLm-NY-aXQ"/>
                             <constraint firstItem="X49-xg-JXO" firstAttribute="leading" secondItem="USa-eR-a1s" secondAttribute="leading" id="pfF-ag-f7x"/>
                         </constraints>
                     </view>
                     <connections>
-                        <outlet property="commentView" destination="sG1-7f-3rF" id="Nip-au-Ilu"/>
-                        <outlet property="imageItem" destination="hVn-Fn-7td" id="tqx-nV-WfA"/>
-                        <outlet property="labelUser" destination="YRy-AS-CMk" id="ijz-je-fBV"/>
-                        <outlet property="newCommentField" destination="Wz7-gw-foA" id="PDr-8b-iQY"/>
                         <outlet property="tableView" destination="X49-xg-JXO" id="GUb-8b-mIS"/>
-                        <outlet property="viewContainerConstraint" destination="0Wu-9f-jFf" id="TGF-fh-T7Y"/>
+                        <outlet property="viewContainerConstraint" destination="E1U-4Q-6uu" id="NpJ-Iz-DtL"/>
                     </connections>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="UOE-pW-DRy" userLabel="First Responder" sceneMemberID="firstResponder"/>

+ 20 - 47
iOSClient/Activity/NCActivity.swift

@@ -26,14 +26,12 @@ import UIKit
 import SwiftRichString
 import NCCommunication
 
-class NCActivity: UIViewController {
+class NCActivity: UIViewController, NCSharePagingContent {
 
     @IBOutlet weak var tableView: UITableView!
 
-    @IBOutlet weak var commentView: UIView!
-    @IBOutlet weak var imageItem: UIImageView!
-    @IBOutlet weak var labelUser: UILabel!
-    @IBOutlet weak var newCommentField: UITextField!
+    var commentView: NCActivityCommentView?
+    var textField: UITextField? { commentView?.newCommentField }
 
     @IBOutlet weak var viewContainerConstraint: NSLayoutConstraint!
     var height: CGFloat = 0
@@ -76,46 +74,34 @@ class NCActivity: UIViewController {
 
         if showComments {
             setupComments()
-        } else {
-            commentView.isHidden = true
         }
     }
 
     func setupComments() {
-        tableView.register(UINib(nibName: "NCShareCommentsCell", bundle: nil), forCellReuseIdentifier: "cell")
-
-        newCommentField.placeholder = NSLocalizedString("_new_comment_", comment: "")
-        viewContainerConstraint.constant = height
-
         // Display Name & Quota
         guard let activeAccount = NCManageDatabase.shared.getActiveAccount(), height > 0 else {
-            commentView.isHidden = true
             return
         }
 
-        let fileName = appDelegate.userBaseUrl + "-" + appDelegate.user + ".png"
-        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
-        if let image = UIImage(contentsOfFile: fileNameLocalPath) {
-            imageItem.image = image
-        } else {
-            imageItem.image = UIImage(named: "avatar")
-        }
-
-        if activeAccount.displayName.isEmpty {
-            labelUser.text = activeAccount.user
-        } else {
-            labelUser.text = activeAccount.displayName
+        tableView.register(UINib(nibName: "NCShareCommentsCell", bundle: nil), forCellReuseIdentifier: "cell")
+        commentView = Bundle.main.loadNibNamed("NCActivityCommentView", owner: self, options: nil)?.first as? NCActivityCommentView
+        commentView?.setup(urlBase: appDelegate, account: activeAccount) { newComment in
+            guard let newComment = newComment, !newComment.isEmpty, let metadata = self.metadata else { return }
+            NCCommunication.shared.putComments(fileId: metadata.fileId, message: newComment) { _, errorCode, errorDescription in
+                if errorCode == 0 {
+                    self.commentView?.newCommentField.text?.removeAll()
+                    self.loadComments()
+                } else {
+                    NCContentPresenter.shared.messageNotification("_share_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
+                }
+            }
         }
-        labelUser.textColor = NCBrandColor.shared.label
     }
 
     override func viewWillAppear(_ animated: Bool) {
         super.viewWillAppear(animated)
-
         appDelegate.activeViewController = self
-
         NotificationCenter.default.addObserver(self, selector: #selector(initialize), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterInitialize), object: nil)
-
         initialize()
     }
 
@@ -127,6 +113,10 @@ class NCActivity: UIViewController {
     override func viewWillLayoutSubviews() {
         super.viewWillLayoutSubviews()
         tableView.tableFooterView = makeTableFooterView()
+        tableView.tableHeaderView = commentView
+        commentView?.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
+        commentView?.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
+        viewContainerConstraint.constant = height
     }
 
     // MARK: - NotificationCenter
@@ -140,23 +130,6 @@ class NCActivity: UIViewController {
         tableView.reloadData()
     }
 
-    @IBAction func newCommentFieldDidEndOnExit(textField: UITextField) {
-        guard
-            let message = textField.text,
-            !message.isEmpty,
-            let metadata = self.metadata
-        else { return }
-
-        NCCommunication.shared.putComments(fileId: metadata.fileId, message: message) { _, errorCode, errorDescription in
-            if errorCode == 0 {
-                self.newCommentField.text = ""
-                self.loadComments()
-            } else {
-                NCContentPresenter.shared.messageNotification("_share_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
-            }
-        }
-    }
-
     func makeTableFooterView() -> UIView {
         let view = UIView(frame: CGRect(x: 0, y: 0, width: tableView.frame.width, height: 100))
         view.backgroundColor = .clear
@@ -525,7 +498,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
         actions.append(
             NCMenuAction(
                 title: NSLocalizedString("_edit_comment_", comment: ""),
-                icon: UIImage(named: "edit")!.image(color: NCBrandColor.shared.gray, size: 50),
+                icon: UIImage(named: "pencil")!.image(color: NCBrandColor.shared.gray, size: 50),
                 action: { _ in
                     guard let metadata = self.metadata, let tableComments = tableComments else { return }
 

+ 59 - 0
iOSClient/Activity/NCActivityCommentView.swift

@@ -0,0 +1,59 @@
+//
+//  NCActivityCommentView.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 04.01.22.
+//  Copyright © 2021 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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
+
+class NCActivityCommentView: UIView, UITextFieldDelegate {
+    @IBOutlet weak var imageItem: UIImageView!
+    @IBOutlet weak var labelUser: UILabel!
+    @IBOutlet weak var newCommentField: UITextField!
+
+    var completionHandler: ((String?) -> Void)?
+
+    func setup(urlBase: NCUserBaseUrl, account: tableAccount, completionHandler: @escaping (String?) -> Void) {
+        self.completionHandler = completionHandler
+        newCommentField.placeholder = NSLocalizedString("_new_comment_", comment: "")
+        newCommentField.delegate = self
+
+        let fileName = urlBase.userBaseUrl + "-" + urlBase.user + ".png"
+        let fileNameLocalPath = String(CCUtility.getDirectoryUserData()) + "/" + fileName
+        if let image = UIImage(contentsOfFile: fileNameLocalPath) {
+            imageItem.image = image
+        } else {
+            imageItem.image = UIImage(named: "avatar")
+        }
+
+        if account.displayName.isEmpty {
+            labelUser.text = account.user
+        } else {
+            labelUser.text = account.displayName
+        }
+        labelUser.textColor = NCBrandColor.shared.label
+    }
+
+    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+        textField.resignFirstResponder()
+        completionHandler?(textField.text)
+        return true
+    }
+}

+ 60 - 0
iOSClient/Activity/NCActivityCommentView.xib

@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+    <device id="retina6_1" orientation="portrait" appearance="light"/>
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.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" translatesAutoresizingMaskIntoConstraints="NO" id="GuF-Pi-nHv" customClass="NCActivityCommentView" customModule="Nextcloud" customModuleProvider="target">
+            <rect key="frame" x="0.0" y="0.0" width="269" height="100"/>
+            <subviews>
+                <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="YXy-gE-g7y">
+                    <rect key="frame" x="10" y="10" width="40" height="40"/>
+                    <constraints>
+                        <constraint firstAttribute="width" constant="40" id="kUz-t2-bFL"/>
+                        <constraint firstAttribute="height" constant="40" id="yRS-7c-bMw"/>
+                    </constraints>
+                </imageView>
+                <textField opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" clearButtonMode="always" translatesAutoresizingMaskIntoConstraints="NO" id="5pv-VB-vbL">
+                    <rect key="frame" x="60" y="60" width="199" height="30"/>
+                    <constraints>
+                        <constraint firstAttribute="height" constant="30" id="OLX-lD-EIH"/>
+                    </constraints>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <textInputTraits key="textInputTraits"/>
+                </textField>
+                <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="user" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="0Ja-ik-S0n">
+                    <rect key="frame" x="60" y="21.5" width="199" height="17"/>
+                    <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                    <color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                    <nil key="highlightedColor"/>
+                </label>
+            </subviews>
+            <viewLayoutGuide key="safeArea" id="Y5x-Vi-PYA"/>
+            <constraints>
+                <constraint firstItem="YXy-gE-g7y" firstAttribute="top" secondItem="GuF-Pi-nHv" secondAttribute="top" constant="10" id="26g-rF-Ags"/>
+                <constraint firstAttribute="trailing" secondItem="0Ja-ik-S0n" secondAttribute="trailing" constant="10" id="7ue-4o-ZT2"/>
+                <constraint firstAttribute="height" constant="100" id="IsL-V9-dXU"/>
+                <constraint firstItem="0Ja-ik-S0n" firstAttribute="centerY" secondItem="YXy-gE-g7y" secondAttribute="centerY" id="NxM-vu-j06"/>
+                <constraint firstItem="5pv-VB-vbL" firstAttribute="leading" secondItem="YXy-gE-g7y" secondAttribute="trailing" constant="10" id="Oza-Za-mDZ"/>
+                <constraint firstItem="5pv-VB-vbL" firstAttribute="top" secondItem="YXy-gE-g7y" secondAttribute="bottom" constant="10" id="iie-Nv-YUr"/>
+                <constraint firstItem="0Ja-ik-S0n" firstAttribute="leading" secondItem="YXy-gE-g7y" secondAttribute="trailing" constant="10" id="j0L-NP-Z4H"/>
+                <constraint firstAttribute="trailing" secondItem="5pv-VB-vbL" secondAttribute="trailing" constant="10" id="oXJ-ov-XCK"/>
+                <constraint firstItem="YXy-gE-g7y" firstAttribute="leading" secondItem="GuF-Pi-nHv" secondAttribute="leading" constant="10" id="t5p-fd-swt"/>
+                <constraint firstAttribute="bottom" secondItem="5pv-VB-vbL" secondAttribute="bottom" constant="10" id="yEr-QL-mtD"/>
+            </constraints>
+            <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
+            <connections>
+                <outlet property="imageItem" destination="YXy-gE-g7y" id="yWc-3P-gIU"/>
+                <outlet property="labelUser" destination="0Ja-ik-S0n" id="GkS-TV-2ic"/>
+                <outlet property="newCommentField" destination="5pv-VB-vbL" id="8vL-Mt-0rZ"/>
+            </connections>
+            <point key="canvasLocation" x="-231.15942028985509" y="-99.776785714285708"/>
+        </view>
+    </objects>
+</document>

+ 66 - 61
iOSClient/AppDelegate.swift

@@ -188,12 +188,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
     // L' applicazione entrerà in primo piano (attivo sempre)
     func applicationDidBecomeActive(_ application: UIApplication) {
-        
-        // Privacy
-        hidePrivacyProtectionWindow()
-        
-        NCSettingsBundleHelper.setVersionAndBuildNumber()
-        
+
+        if !NCAskAuthorization.shared.isRequesting {
+            // Privacy
+            hidePrivacyProtectionWindow()
+        }
+
         NCSettingsBundleHelper.setVersionAndBuildNumber()
 
         if account == "" { return }
@@ -245,9 +245,11 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
 
         if account == "" { return }
 
-        // Privacy
-        showPrivacyProtectionWindow()
-                
+        if CCUtility.getPrivacyScreenEnabled() {
+            // Privacy
+            showPrivacyProtectionWindow()
+        }
+
         // Clear operation queue
         NCOperationQueue.shared.cancelAllQueue()
         // Clear download
@@ -266,20 +268,20 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     func applicationDidEnterBackground(_ application: UIApplication) {
 
         if account == "" { return }
-        
+
         // STOP TIMER UPLOAD PROCESS
         if NCUtility.shared.isSimulator() {
             networkingProcessUpload?.stopTimer()
         }
-                
+
         if #available(iOS 13.0, *) {
             scheduleAppRefresh()
             scheduleBackgroundProcessing()
         }
-        
+
         // Passcode
         presentPasscode { }
-        
+
         NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterApplicationDidEnterBackground)
     }
 
@@ -297,7 +299,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if account == "" { return }
 
         NCCommunicationCommon.shared.writeLog("initialize Main")
-                
+
         // Registeration push notification
         NCPushNotification.shared().pushNotification()
 
@@ -362,7 +364,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         NCAutoUpload.shared.initAutoUpload(viewController: nil) { _ in
             DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
                 NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateBadgeNumber)
-                NCCommunicationCommon.shared.writeLog("Completition handler refresh task with %lu uploads [Auto upload]")
+                NCCommunicationCommon.shared.writeLog("Completition handler refresh task with [Auto upload]")
                 task.setTaskCompleted(success: true)
             }
         }
@@ -606,6 +608,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         if serverVersionMajor > 0 {
             NCCommunicationCommon.shared.setup(nextcloudVersion: serverVersionMajor)
         }
+        NCKTVHTTPCache.shared.restartProxy(user: user, password: password)
     }
 
     @objc func deleteAccount(_ account: String, wipe: Bool) {
@@ -654,17 +657,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     // MARK: - Account Request
 
     func accountRequestChangeAccount(account: String) {
-
         changeAccount(account)
     }
     
     func requestAccount() {
-              
+
         if isPasscodePresented() { return }
         if !CCUtility.getAccountRequest() { return }
-        
+
         let accounts = NCManageDatabase.shared.getAllAccount()
-        
+
         if accounts.count > 1 {
             
             if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
@@ -691,30 +693,21 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
     }
 
     // MARK: - Passcode
-    
-    func presentPasscode(completion: @escaping ()->()) {
+
+    func presentPasscode(completion: @escaping () -> ()) {
 
         let laContext = LAContext()
         var error: NSError?
 
-        defer {
-            self.requestAccount()
-        }
-
-        guard !account.isEmpty, CCUtility.isPasscodeAtStartEnabled() else { return }
-        
-        // If activated hide the privacy protection
-        hidePrivacyProtectionWindow()
+        defer { self.requestAccount() }
 
-        // Dismiss present window?.rootViewController? [ONLY PASSCODE]
         let presentedViewController = window?.rootViewController?.presentedViewController
-        if presentedViewController is NCLoginNavigationController {
-            return
-        } else {
-            presentedViewController?.dismiss(animated: false)
-        }
+        guard !account.isEmpty, CCUtility.isPasscodeAtStartEnabled(), !(presentedViewController is NCLoginNavigationController) else { return }
 
-        let passcodeViewController = TOPasscodeViewController.init(passcodeType: .sixDigits, allowCancel: false)
+        // Make sure we have a privacy window (in case it's not enabled)
+        showPrivacyProtectionWindow()
+
+        let passcodeViewController = TOPasscodeViewController(passcodeType: .sixDigits, allowCancel: false)
         passcodeViewController.delegate = self
         passcodeViewController.keypadButtonShowLettering = false
         if CCUtility.getEnableTouchFaceID() && laContext.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error) {
@@ -728,38 +721,40 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
                 passcodeViewController.automaticallyPromptForBiometricValidation = false
             }
         }
-        
-        window?.rootViewController?.present(passcodeViewController, animated: true, completion: {
+
+        // show passcode on top of privacy window
+        privacyProtectionWindow?.rootViewController?.present(passcodeViewController, animated: true, completion: {
             completion()
         })
     }
-    
+
     func isPasscodePresented() -> Bool {
-        return window?.rootViewController?.presentedViewController is TOPasscodeViewController
+        return privacyProtectionWindow?.rootViewController?.presentedViewController is TOPasscodeViewController
     }
-    
-    func enableTouchFaceID() {
 
+    func enableTouchFaceID() {
         guard !account.isEmpty,
               CCUtility.getEnableTouchFaceID(),
               CCUtility.isPasscodeAtStartEnabled(),
-              let passcodeViewController = window?.rootViewController?.presentedViewController as? TOPasscodeViewController
+              let passcodeViewController = privacyProtectionWindow?.rootViewController?.presentedViewController as? TOPasscodeViewController
         else { return }
 
         LAContext().evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: NCBrandOptions.shared.brand) { (success, error) in
             if success {
                 DispatchQueue.main.async {
                     passcodeViewController.dismiss(animated: true) {
+                        self.hidePrivacyProtectionWindow()
                         self.requestAccount()
                     }
                 }
             }
         }
     }
-    
+
     func didInputCorrectPasscode(in passcodeViewController: TOPasscodeViewController) {
         DispatchQueue.main.async {
             passcodeViewController.dismiss(animated: true) {
+                self.hidePrivacyProtectionWindow()
                 self.requestAccount()
             }
         }
@@ -769,27 +764,37 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
         return code == CCUtility.getPasscode()
     }
 
+    func didPerformBiometricValidationRequest(in passcodeViewController: TOPasscodeViewController) {
+        enableTouchFaceID()
+    }
+
     // MARK: - Privacy Protection
-       
+
     private func showPrivacyProtectionWindow() {
-        
-        guard CCUtility.getPrivacyScreenEnabled() else { return }
-        
+        guard privacyProtectionWindow == nil else {
+            privacyProtectionWindow?.isHidden = false
+            return
+        }
+
         privacyProtectionWindow = UIWindow(frame: UIScreen.main.bounds)
-          
+
         let storyboard = UIStoryboard(name: "LaunchScreen", bundle: nil)
         let initialViewController = storyboard.instantiateInitialViewController()
 
         self.privacyProtectionWindow?.rootViewController = initialViewController
-        
+
         privacyProtectionWindow?.windowLevel = .alert + 1
         privacyProtectionWindow?.makeKeyAndVisible()
     }
 
-    private func hidePrivacyProtectionWindow() {
-        
-        privacyProtectionWindow?.isHidden = true
-        privacyProtectionWindow = nil
+    func hidePrivacyProtectionWindow() {
+        guard !(privacyProtectionWindow?.rootViewController?.presentedViewController is TOPasscodeViewController) else { return }
+        UIWindow.animate(withDuration: 0.25) {
+            self.privacyProtectionWindow?.alpha = 0
+        } completion: { _ in
+            self.privacyProtectionWindow?.isHidden = true
+            self.privacyProtectionWindow = nil
+        }
     }
     
     // MARK: - Open URL
@@ -873,13 +878,13 @@ extension AppDelegate: NCAudioRecorderViewControllerDelegate {
 
     func didFinishRecording(_ viewController: NCAudioRecorderViewController, fileName: String) {
 
-        guard let navigationController = UIStoryboard(name: "NCCreateFormUploadVoiceNote", bundle: nil).instantiateInitialViewController() else { return }
-        navigationController.modalPresentationStyle = UIModalPresentationStyle.formSheet
-        let appDelegate = UIApplication.shared.delegate as! AppDelegate
-
-        let viewController = (navigationController as! UINavigationController).topViewController as! NCCreateFormUploadVoiceNote
-        viewController.setup(serverUrl: appDelegate.activeServerUrl, fileNamePath: NSTemporaryDirectory() + fileName, fileName: fileName)
-        appDelegate.window?.rootViewController?.present(navigationController, animated: true, completion: nil)
+        guard
+            let navigationController = UIStoryboard(name: "NCCreateFormUploadVoiceNote", bundle: nil).instantiateInitialViewController() as? UINavigationController,
+                let viewController = navigationController.topViewController as? NCCreateFormUploadVoiceNote
+        else { return }
+        navigationController.modalPresentationStyle = .formSheet
+        viewController.setup(serverUrl: activeServerUrl, fileNamePath: NSTemporaryDirectory() + fileName, fileName: fileName)
+        window?.rootViewController?.present(navigationController, animated: true)
     }
 
     func didFinishWithoutRecording(_ viewController: NCAudioRecorderViewController, fileName: String) {

+ 9 - 11
iOSClient/Brand/Intro/NCIntroCollectionViewCell.xib

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15702" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15704"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -18,32 +18,30 @@
                 <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
                 <subviews>
                     <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="bZc-Ai-h3y">
-                        <rect key="frame" x="8" y="426" width="321" height="28"/>
-                        <constraints>
-                            <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="28" id="bXT-nO-EeQ"/>
-                        </constraints>
+                        <rect key="frame" x="8" y="426.5" width="321" height="27.5"/>
                         <fontDescription key="fontDescription" type="system" pointSize="23"/>
                         <nil key="textColor"/>
                         <nil key="highlightedColor"/>
                     </label>
                     <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" image="intro1" translatesAutoresizingMaskIntoConstraints="NO" id="f3T-nC-cwA">
-                        <rect key="frame" x="93.5" y="8" width="150" height="410"/>
+                        <rect key="frame" x="93.5" y="156" width="150" height="150"/>
                         <constraints>
                             <constraint firstAttribute="width" relation="lessThanOrEqual" constant="150" id="jne-Xj-IAh"/>
+                            <constraint firstAttribute="width" secondItem="f3T-nC-cwA" secondAttribute="height" multiplier="1:1" id="mhZ-Cn-42Q"/>
                         </constraints>
                     </imageView>
                 </subviews>
             </view>
+            <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
             <color key="backgroundColor" red="1" green="0.57637232540000005" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
             <constraints>
                 <constraint firstItem="f3T-nC-cwA" firstAttribute="centerX" secondItem="gTV-IL-0wX" secondAttribute="centerX" id="4le-ih-K34"/>
-                <constraint firstItem="bZc-Ai-h3y" firstAttribute="top" secondItem="f3T-nC-cwA" secondAttribute="bottom" constant="8" id="AWt-Zg-Blt"/>
-                <constraint firstItem="f3T-nC-cwA" firstAttribute="top" secondItem="gTV-IL-0wX" secondAttribute="top" constant="8" id="Eh0-Bq-FKp"/>
                 <constraint firstAttribute="bottom" secondItem="bZc-Ai-h3y" secondAttribute="bottom" constant="8" id="YBJ-eg-EmZ"/>
+                <constraint firstItem="bZc-Ai-h3y" firstAttribute="top" relation="greaterThanOrEqual" secondItem="f3T-nC-cwA" secondAttribute="bottom" constant="16" id="av5-zS-GLQ"/>
                 <constraint firstItem="bZc-Ai-h3y" firstAttribute="leading" secondItem="gTV-IL-0wX" secondAttribute="leading" constant="8" id="eNj-fx-een"/>
+                <constraint firstItem="f3T-nC-cwA" firstAttribute="centerY" secondItem="gTV-IL-0wX" secondAttribute="centerY" priority="250" id="haX-eS-EOe"/>
                 <constraint firstAttribute="trailing" secondItem="bZc-Ai-h3y" secondAttribute="trailing" constant="8" id="uif-cW-sAI"/>
             </constraints>
-            <viewLayoutGuide key="safeArea" id="ZTg-uK-7eu"/>
             <size key="customSize" width="337" height="428"/>
             <connections>
                 <outlet property="imageView" destination="f3T-nC-cwA" id="aRR-4x-Dwk"/>
@@ -53,6 +51,6 @@
         </collectionViewCell>
     </objects>
     <resources>
-        <image name="intro1" width="200" height="200"/>
+        <image name="intro1" width="256" height="128"/>
     </resources>
 </document>

+ 2 - 0
iOSClient/Brand/Intro/NCIntroViewController.swift

@@ -89,6 +89,8 @@ class NCIntroViewController: UIViewController, UICollectionViewDataSource, UICol
         buttonSignUp.layer.borderWidth = 1.0
         buttonSignUp.setTitleColor(textColor, for: .normal)
         buttonSignUp.backgroundColor = NCBrandColor.shared.customer
+        buttonSignUp.titleLabel?.adjustsFontSizeToFitWidth = true
+        buttonSignUp.titleEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10)
         buttonSignUp.setTitle(NSLocalizedString("_sign_up_", comment: ""), for: .normal)
 
         buttonHost.layer.cornerRadius = 20

+ 9 - 9
iOSClient/Brand/LaunchScreen.storyboard

@@ -1,11 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
-    <device id="retina4_7" orientation="portrait">
-        <adaptation id="fullscreen"/>
-    </device>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="19529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
+    <device id="retina4_7" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
         <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
@@ -18,16 +16,18 @@
                         <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
-                            <imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo" translatesAutoresizingMaskIntoConstraints="NO" id="7UE-Dr-Fma">
-                                <rect key="frame" x="134" y="306" width="107" height="75"/>
+                            <imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="logo" translatesAutoresizingMaskIntoConstraints="NO" id="7UE-Dr-Fma">
+                                <rect key="frame" x="59.5" y="269.5" width="256" height="128"/>
                             </imageView>
                         </subviews>
+                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                         <color key="backgroundColor" red="0.0" green="0.50980392156862742" blue="0.78823529411764703" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                         <constraints>
+                            <constraint firstItem="7UE-Dr-Fma" firstAttribute="width" relation="lessThanOrEqual" secondItem="6Tk-OE-BBY" secondAttribute="width" id="8ik-eB-po8"/>
+                            <constraint firstItem="7UE-Dr-Fma" firstAttribute="height" relation="lessThanOrEqual" secondItem="6Tk-OE-BBY" secondAttribute="height" id="G3L-l7-lxv"/>
                             <constraint firstItem="7UE-Dr-Fma" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="XdS-tM-D9I"/>
                             <constraint firstItem="7UE-Dr-Fma" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="ZR5-ct-Gg8"/>
                         </constraints>
-                        <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
                     </view>
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
@@ -36,6 +36,6 @@
         </scene>
     </scenes>
     <resources>
-        <image name="logo" width="107" height="75.599998474121094"/>
+        <image name="logo" width="256" height="128"/>
     </resources>
 </document>

+ 13 - 1
iOSClient/Brand/NCBrand.swift

@@ -47,7 +47,7 @@ import UIKit
 
     @objc public var brand: String = "Nextcloud"
     // @objc public var mailMe:                            String = "ios@nextcloud.com"                              // Deprecated
-    @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Liquid for iOS %@ © 2021"
+    @objc public var textCopyrightNextcloudiOS: String = "Nextcloud Liquid for iOS %@ © 2022"
     @objc public var textCopyrightNextcloudServer: String = "Nextcloud Server %@"
     @objc public var loginBaseUrl: String = "https://cloud.nextcloud.com"
     @objc public var pushNotificationServerProxy: String = "https://push-notifications.nextcloud.com"
@@ -137,6 +137,7 @@ class NCBrandColor: NSObject {
 
         static var buttonMore = UIImage()
         static var buttonStop = UIImage()
+        static var buttonMoreLock = UIImage()
         static var buttonRestore = UIImage()
     }
 
@@ -215,6 +216,16 @@ class NCBrandColor: NSObject {
         }
     }
 
+    @objc public var secondaryLabel: UIColor {
+        get {
+            if #available(iOS 13, *) {
+                return .secondaryLabel
+            } else {
+                return UIColor(red: 0.24, green: 0.24, blue: 0.26, alpha: 0.6)
+            }
+        }
+    }
+
     @objc public var separator: UIColor {
         get {
             if #available(iOS 13, *) {
@@ -345,6 +356,7 @@ class NCBrandColor: NSObject {
 
         cacheImages.buttonMore = UIImage(named: "more")!.image(color: gray, size: 50)
         cacheImages.buttonStop = UIImage(named: "stop")!.image(color: gray, size: 50)
+        cacheImages.buttonMoreLock = UIImage(named: "moreLock")!.image(color: gray, size: 50)
         cacheImages.buttonRestore = UIImage(named: "restore")!.image(color: gray, size: 50)
     }
 

+ 0 - 12
iOSClient/Brand/iOSClient.entitlements

@@ -4,18 +4,6 @@
 <dict>
 	<key>aps-environment</key>
 	<string>development</string>
-	<key>com.apple.developer.icloud-container-identifiers</key>
-	<array>
-		<string>iCloud.$(CFBundleIdentifier)</string>
-	</array>
-	<key>com.apple.developer.icloud-services</key>
-	<array>
-		<string>CloudDocuments</string>
-	</array>
-	<key>com.apple.developer.ubiquity-container-identifiers</key>
-	<array>
-		<string>iCloud.$(CFBundleIdentifier)</string>
-	</array>
 	<key>com.apple.security.application-groups</key>
 	<array>
 		<string>group.it.twsweb.Crypto-Cloud</string>

+ 36 - 5
iOSClient/Brand/iOSClient.plist

@@ -64,17 +64,29 @@
 	<key>NSFaceIDUsageDescription</key>
 	<string>Face ID is required to authenticate using face recognition.</string>
 	<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll, continued use of GPS running in the background can dramatically decrease battery life.</string>
+	<string>GPS is used to detect new photos from camera roll. Continued use of GPS running in the background can dramatically decrease battery life.</string>
 	<key>NSLocationAlwaysUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll, continued use of GPS running in the background can dramatically decrease battery life.</string>
+	<string>GPS is used to detect new photos from camera roll. Continued use of GPS running in the background can dramatically decrease battery life.</string>
 	<key>NSLocationWhenInUseUsageDescription</key>
-	<string>GPS is used to detect new photos from camera roll on background, the use of GPS only when the App is in use is useless.</string>
+	<string>GPS is used to detect new photos from camera roll on background. It is useless to use GPS only while using the app.</string>
 	<key>NSMicrophoneUsageDescription</key>
 	<string>Microphone access is required to create voice notes.</string>
 	<key>NSPhotoLibraryAddUsageDescription</key>
 	<string>Photo library access is required to upload your photos and videos to your cloud.</string>
 	<key>NSPhotoLibraryUsageDescription</key>
 	<string>Photo library access is required to upload your photos and videos to your cloud.</string>
+	<key>UIAppFonts</key>
+	<array>
+		<string>Inconsolata-Light.ttf</string>
+		<string>Inconsolata-Regular.ttf</string>
+		<string>Inconsolata-ExtraLight.ttf</string>
+		<string>Inconsolata-Medium.ttf</string>
+		<string>Inconsolata-Bold.ttf</string>
+		<string>Inconsolata-ExtraBold.ttf</string>
+		<string>Inconsolata-Black.ttf</string>
+	</array>
+	<key>PHPhotoLibraryPreventAutomaticLimitedAccessAlert</key>
+	<true/>
 	<key>UIBackgroundModes</key>
 	<array>
 		<string>audio</string>
@@ -105,8 +117,6 @@
 		<string>UIInterfaceOrientationLandscapeRight</string>
 		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 	</array>
-	<key>UISupportsDocumentBrowser</key>
-	<true/>
 	<key>UIViewControllerBasedStatusBarAppearance</key>
 	<true/>
 	<key>UTExportedTypeDeclarations</key>
@@ -132,6 +142,27 @@
 				</array>
 			</dict>
 		</dict>
+		<dict>
+			<key>UTTypeConformsTo</key>
+			<array>
+				<string>public.text</string>
+			</array>
+			<key>UTTypeDescription</key>
+			<string>SRT Subtitle Format</string>
+			<key>UTTypeIconFiles</key>
+			<array/>
+			<key>UTTypeIdentifier</key>
+			<string>com.company.srt</string>
+			<key>UTTypeReferenceURL</key>
+			<string></string>
+			<key>UTTypeTagSpecification</key>
+			<dict>
+				<key>public.filename-extension</key>
+				<array>
+					<string>srt</string>
+				</array>
+			</dict>
+		</dict>
 	</array>
 </dict>
 </plist>

+ 17 - 3
iOSClient/Data/NCDatabase.swift

@@ -37,9 +37,7 @@ class tableAccount: Object, NCUserBaseUrl {
     @objc dynamic var address = ""
     @objc dynamic var alias = ""
     @objc dynamic var autoUpload: Bool = false
-    @objc dynamic var autoUploadBackground: Bool = false
     @objc dynamic var autoUploadCreateSubfolder: Bool = false
-    @objc dynamic var autoUploadDeleteAssetLocalIdentifier: Bool = false
     @objc dynamic var autoUploadDirectory = ""
     @objc dynamic var autoUploadFileName = ""
     @objc dynamic var autoUploadFull: Bool = false
@@ -384,6 +382,13 @@ class tableMetadata: Object, NCUserBaseUrl {
     @objc dynamic var ocId = ""
     @objc dynamic var ownerId = ""
     @objc dynamic var ownerDisplayName = ""
+    @objc public var lock = false
+    @objc public var lockOwner = ""
+    @objc public var lockOwnerEditor = ""
+    @objc public var lockOwnerType = 0
+    @objc public var lockOwnerDisplayName = ""
+    @objc public var lockTime: Date?
+    @objc public var lockTimeOut: Date?
     @objc dynamic var path = ""
     @objc dynamic var permissions = ""
     @objc dynamic var quotaUsedBytes: Int64 = 0
@@ -420,6 +425,11 @@ extension tableMetadata {
     var isPrintable: Bool {
         classFile == NCCommunicationCommon.typeClassFile.image.rawValue || ["application/pdf", "com.adobe.pdf"].contains(contentType) || contentType.hasPrefix("text/")
     }
+
+    /// Returns false if the user is lokced out of the file. I.e. The file is locked but by somone else
+    func canUnlock(as user: String) -> Bool {
+        return !lock || (lockOwner == user && lockOwnerType == 0)
+    }
 }
 
 class tablePhotoLibrary: Object {
@@ -493,6 +503,11 @@ class tableTag: Object {
     }
 }
 
+class tableTip: Object {
+
+    @Persisted(primaryKey: true) var tipName = ""
+}
+
 class tableTrash: Object {
 
     @objc dynamic var account = ""
@@ -539,7 +554,6 @@ class tableVideo: Object {
     @objc dynamic var codecNameAudio: String?
     @objc dynamic var codecAudioChannelLayout: String?
     @objc dynamic var codecAudioLanguage: String?
-    @objc dynamic var codecSubtitleLanguage: String?
     @objc dynamic var codecMaxCompatibility: Bool = false
     @objc dynamic var codecQuality: String?
 

+ 2 - 1
iOSClient/Data/NCElementsJSON.swift

@@ -58,7 +58,8 @@ import UIKit
     @objc public let capabilitiesNotification: Array = ["ocs", "data", "capabilities", "notifications", "ocs-endpoints"]
 
     @objc public let capabilitiesFilesUndelete: Array = ["ocs", "data", "capabilities", "files", "undelete"]
-    @objc public let capabilitiesFilesComments: Array = ["ocs", "data", "capabilities", "files", "comments"]                                            // NC 20
+    @objc public let capabilitiesFilesLockVersion: Array = ["ocs", "data", "capabilities", "files", "locking"] // NC 24
+    @objc public let capabilitiesFilesComments: Array = ["ocs", "data", "capabilities", "files", "comments"] // NC 20
 
     @objc public let capabilitiesHWCEnabled: Array = ["ocs", "data", "capabilities", "handwerkcloud", "enabled"]
 

+ 15 - 0
iOSClient/Data/NCManageDatabase+Account.swift

@@ -5,6 +5,21 @@
 //  Created by Henrik Storch on 30.11.21.
 //  Copyright © 2021 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 Foundation
 import RealmSwift

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

@@ -5,6 +5,21 @@
 //  Created by Henrik Storch on 30.11.21.
 //  Copyright © 2021 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 Foundation
 import RealmSwift
@@ -13,9 +28,6 @@ import SwiftyJSON
 
 extension NCManageDatabase {
     
-    // MARK: -
-    // MARK: Table Activity
-
     @objc func addActivity(_ activities: [NCCommunicationActivity], account: String) {
 
         let realm = try! Realm()

+ 51 - 4
iOSClient/Data/NCManageDatabse+Metadata.swift → iOSClient/Data/NCManageDatabase+Metadata.swift

@@ -1,10 +1,25 @@
 //
-//  NCManageDatabse+Metadata.swift
+//  NCManageDatabase+Metadata.swift
 //  Nextcloud
 //
 //  Created by Henrik Storch on 30.11.21.
 //  Copyright © 2021 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 Foundation
 import RealmSwift
@@ -49,6 +64,13 @@ extension NCManageDatabase {
         metadata.ocId = file.ocId
         metadata.ownerId = file.ownerId
         metadata.ownerDisplayName = file.ownerDisplayName
+        metadata.lock = file.lock
+        metadata.lockOwner = file.lockOwner
+        metadata.lockOwnerEditor = file.lockOwnerEditor
+        metadata.lockOwnerType = file.lockOwnerType
+        metadata.lockOwnerDisplayName = file.lockOwnerDisplayName
+        metadata.lockTime = file.lockTime
+        metadata.lockTimeOut = file.lockTimeOut
         metadata.path = file.path
         metadata.permissions = file.permissions
         metadata.quotaUsedBytes = file.quotaUsedBytes
@@ -65,6 +87,10 @@ extension NCManageDatabase {
         }
         metadata.size = file.size
         metadata.classFile = file.classFile
+        //FIXME: iOS 12.0,* don't detect UTI "text/markdown"
+        if metadata.contentType == "text/markdown" && metadata.classFile == NCCommunicationCommon.typeClassFile.unknow.rawValue {
+            metadata.classFile = NCCommunicationCommon.typeClassFile.document.rawValue
+        }
         if let date = file.uploadDate {
             metadata.uploadDate = date
         } else {
@@ -166,6 +192,10 @@ extension NCManageDatabase {
         metadata.urlBase = urlBase
         metadata.user = user
         metadata.userId = userId
+        
+        if !metadata.urlBase.isEmpty, metadata.serverUrl.hasPrefix(metadata.urlBase) {
+            metadata.path = String(metadata.serverUrl.dropFirst(metadata.urlBase.count)) + "/"
+        }
 
         return metadata
     }
@@ -300,7 +330,9 @@ extension NCManageDatabase {
 
                     if let result = metadatasResult.first(where: { $0.ocId == metadata.ocId }) {
                         // update
-                        if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview || result.note != metadata.note) {
+                        // Workaround: check lock bc no etag changes if lock runs out in directory
+                        // https://github.com/nextcloud/server/issues/8477
+                        if result.status == NCGlobal.shared.metadataStatusNormal && (result.etag != metadata.etag || result.fileNameView != metadata.fileNameView || result.date != metadata.date || result.permissions != metadata.permissions || result.hasPreview != metadata.hasPreview || result.note != metadata.note || result.lock != metadata.lock) {
                             ocIdsUdate.append(metadata.ocId)
                             realm.add(tableMetadata.init(value: metadata), update: .all)
                         } else if result.status == NCGlobal.shared.metadataStatusNormal && addCompareLivePhoto && result.livePhoto != metadata.livePhoto {
@@ -676,14 +708,14 @@ extension NCManageDatabase {
         }
     }
 
-    @objc func getAssetLocalIdentifiersUploaded(account: String, sessionSelector: String) -> [String] {
+    @objc func getAssetLocalIdentifiersUploaded(account: String) -> [String] {
 
         let realm = try! Realm()
         realm.refresh()
 
         var assetLocalIdentifiers: [String] = []
 
-        let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true AND sessionSelector == %@", account, sessionSelector)
+        let results = realm.objects(tableMetadata.self).filter("account == %@ AND assetLocalIdentifier != '' AND deleteAssetLocalIdentifier == true", account)
         for result in results {
             assetLocalIdentifiers.append(result.assetLocalIdentifier)
         }
@@ -788,4 +820,19 @@ extension NCManageDatabase {
         }
         return getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileNameView == %@", account, serverUrl, fileNameConflict))
     }
+
+    func getSubtitles(account: String, serverUrl: String, fileName: String) -> (all:[tableMetadata], existing:[tableMetadata]) {
+
+        let realm = try! Realm()
+        let nameOnly = (fileName as NSString).deletingPathExtension + "."
+        var metadatas: [tableMetadata] = []
+
+        let results = realm.objects(tableMetadata.self).filter("account == %@ AND serverUrl == %@ AND fileName BEGINSWITH[c] %@ AND fileName ENDSWITH[c] '.srt'", account, serverUrl, nameOnly)
+        for result in results {
+            if CCUtility.fileProviderStorageExists(result) {
+                metadatas.append(result)
+            }
+        }
+        return(Array(results.map { tableMetadata.init(value: $0) }), Array(metadatas.map { tableMetadata.init(value: $0) }))
+    }
 }

+ 152 - 0
iOSClient/Data/NCManageDatabase+Video.swift

@@ -0,0 +1,152 @@
+//
+//  NCManageDatabase+Video.swift
+//  Nextcloud
+//
+//  Created by Marino Faggiana on 15/03/22.
+//  Copyright © 2022 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 Foundation
+import RealmSwift
+import NCCommunication
+
+extension NCManageDatabase {
+
+    func addVideoTime(metadata: tableMetadata, time: CMTime?, durationTime: CMTime?) {
+
+        if metadata.livePhoto { return }
+        let realm = try! Realm()
+
+        do {
+            try realm.safeWrite {
+                if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
+
+                    if let durationTime = durationTime {
+                        result.duration = durationTime.convertScale(1000, method: .default).value
+                    }
+                    if let time = time {
+                        result.time = time.convertScale(1000, method: .default).value
+                    }
+                    realm.add(result, update: .all)
+
+                } else {
+
+                    let addObject = tableVideo()
+
+                    addObject.account = metadata.account
+                    if let durationTime = durationTime {
+                        addObject.duration = durationTime.convertScale(1000, method: .default).value
+                    }
+                    addObject.ocId = metadata.ocId
+                    if let time = time {
+                        addObject.time = time.convertScale(1000, method: .default).value
+                    }
+                    realm.add(addObject, update: .all)
+                }
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func addVideoCodec(metadata: tableMetadata, codecNameVideo: String?, codecNameAudio: String?, codecAudioChannelLayout: String?, codecAudioLanguage: String?, codecMaxCompatibility: Bool, codecQuality: String?) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.safeWrite {
+                if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
+                    if let codecNameVideo = codecNameVideo { result.codecNameVideo = codecNameVideo }
+                    if let codecNameAudio = codecNameAudio { result.codecNameAudio = codecNameAudio }
+                    if let codecAudioChannelLayout = codecAudioChannelLayout { result.codecAudioChannelLayout = codecAudioChannelLayout }
+                    if let codecAudioLanguage = codecAudioLanguage { result.codecAudioLanguage = codecAudioLanguage }
+                    result.codecMaxCompatibility = codecMaxCompatibility
+                    if let codecQuality = codecQuality { result.codecQuality = codecQuality }
+                    realm.add(result, update: .all)
+                } else {
+                    let addObject = tableVideo()
+                    addObject.account = metadata.account
+                    addObject.ocId = metadata.ocId
+                    addObject.codecNameVideo = codecNameVideo
+                    addObject.codecNameAudio = codecNameAudio
+                    addObject.codecAudioChannelLayout = codecAudioChannelLayout
+                    addObject.codecAudioLanguage = codecAudioLanguage
+                    addObject.codecMaxCompatibility = codecMaxCompatibility
+                    addObject.codecQuality = codecQuality
+                    realm.add(addObject, update: .all)
+                }
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+
+    func getVideo(metadata: tableMetadata?) -> tableVideo? {
+        guard let metadata = metadata else { return nil }
+
+        let realm = try! Realm()
+        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
+            return nil
+        }
+
+        return tableVideo.init(value: result)
+    }
+
+    func getVideoDurationTime(metadata: tableMetadata?) -> CMTime? {
+        guard let metadata = metadata else { return nil }
+
+        if metadata.livePhoto { return nil }
+        let realm = try! Realm()
+
+        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
+            return nil
+        }
+
+        if result.duration == 0 { return nil }
+        let duration = CMTimeMake(value: result.duration, timescale: 1000)
+        return duration
+    }
+
+    func getVideoTime(metadata: tableMetadata) -> CMTime? {
+
+        if metadata.livePhoto { return nil }
+        let realm = try! Realm()
+
+        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
+            return nil
+        }
+
+        if result.time == 0 { return nil }
+        let time = CMTimeMake(value: result.time, timescale: 1000)
+        return time
+    }
+
+    func deleteVideo(metadata: tableMetadata) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.safeWrite {
+                let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId)
+                realm.delete(result)
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+}

+ 37 - 127
iOSClient/Data/NCManageDatabase.swift

@@ -149,6 +149,11 @@ class NCManageDatabase: NSObject {
                         }
                     }
 
+                    if oldSchemaVersion < 222 && NCUtility.shared.SYSTEM_VERSION_LESS_THAN(version: "13") {
+                        migration.deleteData(forType: tableMetadata.className())
+                        migration.deleteData(forType: tableDirectory.className())
+                    }
+
                 }, shouldCompactOnLaunch: { totalBytes, usedBytes in
 
                     // totalBytes refers to the size of the file on disk in bytes (data + free space)
@@ -245,6 +250,7 @@ class NCManageDatabase: NSObject {
         self.clearTable(tablePhotoLibrary.self, account: account)
         self.clearTable(tableShare.self, account: account)
         self.clearTable(tableTag.self, account: account)
+        self.clearTable(tableTip.self)
         self.clearTable(tableTrash.self, account: account)
         self.clearTable(tableUserStatus.self, account: account)
         self.clearTable(tableVideo.self, account: account)
@@ -1546,6 +1552,37 @@ class NCManageDatabase: NSObject {
         return tableTag.init(value: result)
     }
 
+    // MARK: -
+    // MARK: Table Tip
+
+    @objc func tipExists(_ tipName: String) -> Bool {
+
+        let realm = try! Realm()
+
+        guard (realm.objects(tableTip.self).where {
+            $0.tipName == tipName
+        }.first) == nil else {
+            return true
+        }
+
+        return false
+    }
+
+    @objc func addTip(_ tipName: String) {
+
+        let realm = try! Realm()
+
+        do {
+            try realm.safeWrite {
+                let addObject = tableTip()
+                addObject.tipName = tipName
+                realm.add(addObject, update: .all)
+            }
+        } catch let error {
+            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
+        }
+    }
+
     // MARK: -
     // MARK: Table Trash
 
@@ -1682,133 +1719,6 @@ class NCManageDatabase: NSObject {
             NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
         }
     }
-    // MARK: -
-    // MARK: Table Video
-
-    func addVideoTime(metadata: tableMetadata, time: CMTime?, durationTime: CMTime?) {
-
-        if metadata.livePhoto { return }
-        let realm = try! Realm()
-
-        do {
-            try realm.safeWrite {
-                if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
-
-                    if let durationTime = durationTime {
-                        result.duration = durationTime.convertScale(1000, method: .default).value
-                    }
-                    if let time = time {
-                        result.time = time.convertScale(1000, method: .default).value
-                    }
-                    realm.add(result, update: .all)
-
-                } else {
-
-                    let addObject = tableVideo()
-
-                    addObject.account = metadata.account
-                    if let durationTime = durationTime {
-                        addObject.duration = durationTime.convertScale(1000, method: .default).value
-                    }
-                    addObject.ocId = metadata.ocId
-                    if let time = time {
-                        addObject.time = time.convertScale(1000, method: .default).value
-                    }
-                    realm.add(addObject, update: .all)
-                }
-            }
-        } catch let error {
-            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
-        }
-    }
-    
-    func addVideoCodec(metadata: tableMetadata, codecNameVideo: String?, codecNameAudio: String?, codecAudioChannelLayout: String?, codecAudioLanguage: String?, codecSubtitleLanguage: String?, codecMaxCompatibility: Bool, codecQuality: String?) {
-
-        let realm = try! Realm()
-
-        do {
-            try realm.safeWrite {
-                if let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first {
-                    if let codecNameVideo = codecNameVideo { result.codecNameVideo = codecNameVideo }
-                    if let codecNameAudio = codecNameAudio { result.codecNameAudio = codecNameAudio }
-                    if let codecAudioChannelLayout = codecAudioChannelLayout { result.codecAudioChannelLayout = codecAudioChannelLayout }
-                    if let codecAudioLanguage = codecAudioLanguage { result.codecAudioLanguage = codecAudioLanguage }
-                    if let codecSubtitleLanguage = codecSubtitleLanguage { result.codecSubtitleLanguage = codecSubtitleLanguage }
-                    result.codecMaxCompatibility = codecMaxCompatibility
-                    if let codecQuality = codecQuality { result.codecQuality = codecQuality }
-                    realm.add(result, update: .all)
-                } else {
-                    let addObject = tableVideo()
-                    addObject.account = metadata.account
-                    addObject.ocId = metadata.ocId
-                    addObject.codecNameVideo = codecNameVideo
-                    addObject.codecNameAudio = codecNameAudio
-                    addObject.codecAudioChannelLayout = codecAudioChannelLayout
-                    addObject.codecAudioLanguage = codecAudioLanguage
-                    addObject.codecSubtitleLanguage = codecSubtitleLanguage
-                    addObject.codecMaxCompatibility = codecMaxCompatibility
-                    addObject.codecQuality = codecQuality
-                    realm.add(addObject, update: .all)
-                }
-            }
-        } catch let error {
-            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
-        }
-    }
-    
-    func getVideo(metadata: tableMetadata?) -> tableVideo? {
-        guard let metadata = metadata else { return nil }
-        
-        let realm = try! Realm()
-        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
-            return nil
-        }
-        
-        return tableVideo.init(value: result)
-    }
-
-    func getVideoDurationTime(metadata: tableMetadata?) -> CMTime? {
-        guard let metadata = metadata else { return nil }
-
-        if metadata.livePhoto { return nil }
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
-            return nil
-        }
-
-        if result.duration == 0 { return nil }
-        let duration = CMTimeMake(value: result.duration, timescale: 1000)
-        return duration
-    }
-
-    func getVideoTime(metadata: tableMetadata) -> CMTime? {
-
-        if metadata.livePhoto { return nil }
-        let realm = try! Realm()
-
-        guard let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId).first else {
-            return nil
-        }
-
-        if result.time == 0 { return nil }
-        let time = CMTimeMake(value: result.time, timescale: 1000)
-        return time
-    }
-
-    func deleteVideo(metadata: tableMetadata) {
-
-        let realm = try! Realm()
-
-        do {
-            try realm.safeWrite {
-                let result = realm.objects(tableVideo.self).filter("account == %@ AND ocId == %@", metadata.account, metadata.ocId)
-                realm.delete(result)
-            }
-        } catch let error {
-            NCCommunicationCommon.shared.writeLog("Could not write to database: \(error)")
-        }
-    }
 }
 
 // MARK: -

+ 53 - 9
iOSClient/Diagnostics/NCCapabilitiesViewController.storyboard

@@ -1,9 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="vTK-Er-kbZ">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="20037" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="vTK-Er-kbZ">
     <device id="retina6_1" orientation="portrait" appearance="light"/>
     <dependencies>
         <deployment identifier="iOS"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="20020"/>
         <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"/>
@@ -21,7 +21,7 @@
                                 <rect key="frame" x="0.0" y="88" width="414" height="774"/>
                                 <subviews>
                                     <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Sms-Ez-fLO" userLabel="View Capabilities">
-                                        <rect key="frame" x="5" y="5" width="404" height="550"/>
+                                        <rect key="frame" x="5" y="5" width="404" height="600"/>
                                         <subviews>
                                             <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="jdW-oZ-cH8" userLabel="FileSharing">
                                                 <rect key="frame" x="0.0" y="0.0" width="404" height="50"/>
@@ -455,26 +455,68 @@
                                                     <constraint firstAttribute="trailing" secondItem="lVT-MG-7kN" secondAttribute="trailing" constant="5" id="zCZ-du-XT5"/>
                                                 </constraints>
                                             </view>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="npG-0C-m3A" userLabel="Lock">
+                                                <rect key="frame" x="0.0" y="550" width="404" height="50"/>
+                                                <subviews>
+                                                    <imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="lock" translatesAutoresizingMaskIntoConstraints="NO" id="eAC-Li-gKO">
+                                                        <rect key="frame" x="0.0" y="10" width="30" height="30"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" constant="30" id="JsP-Q6-6yG"/>
+                                                            <constraint firstAttribute="width" constant="30" id="WUk-lh-3Vb"/>
+                                                        </constraints>
+                                                    </imageView>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Lock file" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="SCj-6t-sXN">
+                                                        <rect key="frame" x="40" y="16" width="57.5" height="18"/>
+                                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                        <nil key="textColor"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Available" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="db5-st-O6M">
+                                                        <rect key="frame" x="279" y="12.5" width="120" height="25"/>
+                                                        <color key="backgroundColor" systemColor="systemGray4Color"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="width" constant="120" id="Vfm-Rm-l7N"/>
+                                                            <constraint firstAttribute="height" constant="25" id="oam-XV-KqH"/>
+                                                        </constraints>
+                                                        <fontDescription key="fontDescription" type="system" pointSize="12"/>
+                                                        <nil key="textColor"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                                                <constraints>
+                                                    <constraint firstItem="db5-st-O6M" firstAttribute="centerY" secondItem="npG-0C-m3A" secondAttribute="centerY" id="0X7-Jw-OjP"/>
+                                                    <constraint firstItem="eAC-Li-gKO" firstAttribute="leading" secondItem="npG-0C-m3A" secondAttribute="leading" id="1yz-QU-lXY"/>
+                                                    <constraint firstAttribute="height" constant="50" id="6GQ-cE-Nz3"/>
+                                                    <constraint firstItem="SCj-6t-sXN" firstAttribute="centerY" secondItem="npG-0C-m3A" secondAttribute="centerY" id="Ocs-LT-OYb"/>
+                                                    <constraint firstItem="eAC-Li-gKO" firstAttribute="centerY" secondItem="npG-0C-m3A" secondAttribute="centerY" id="SlK-BL-Nba"/>
+                                                    <constraint firstAttribute="trailing" secondItem="db5-st-O6M" secondAttribute="trailing" constant="5" id="Upi-tI-m1R"/>
+                                                    <constraint firstItem="SCj-6t-sXN" firstAttribute="leading" secondItem="eAC-Li-gKO" secondAttribute="trailing" constant="10" id="dgu-xW-E8T"/>
+                                                </constraints>
+                                            </view>
                                         </subviews>
                                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                         <constraints>
                                             <constraint firstItem="lGp-bh-Ysz" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="0qE-PV-O2f"/>
                                             <constraint firstAttribute="trailing" secondItem="8nf-zJ-Qas" secondAttribute="trailing" id="0vv-HQ-Qqx"/>
-                                            <constraint firstAttribute="height" constant="550" id="6nU-Cb-MzH"/>
+                                            <constraint firstAttribute="height" constant="600" id="6nU-Cb-MzH"/>
                                             <constraint firstItem="mSC-JU-xuk" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="9Nq-du-3ah"/>
                                             <constraint firstItem="S24-Wc-fps" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="Aad-cm-E1T"/>
                                             <constraint firstAttribute="trailing" secondItem="S24-Wc-fps" secondAttribute="trailing" id="Ajf-er-GBr"/>
                                             <constraint firstItem="ZNB-jF-9zg" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="GdE-lt-vZC"/>
                                             <constraint firstAttribute="trailing" secondItem="nVq-4i-FNy" secondAttribute="trailing" id="HSG-Ia-fYc"/>
+                                            <constraint firstItem="npG-0C-m3A" firstAttribute="top" secondItem="S24-Wc-fps" secondAttribute="bottom" constant="2" id="IQe-Xv-U7D"/>
                                             <constraint firstItem="S24-Wc-fps" firstAttribute="top" secondItem="2Pp-Kb-YMc" secondAttribute="bottom" constant="-2" id="ML8-GT-9hb"/>
                                             <constraint firstAttribute="trailing" secondItem="2Pp-Kb-YMc" secondAttribute="trailing" id="NG8-Nu-ic6"/>
                                             <constraint firstItem="LTt-2C-rPb" firstAttribute="top" secondItem="dhs-06-3RT" secondAttribute="bottom" id="Nm6-NH-AC9"/>
+                                            <constraint firstItem="npG-0C-m3A" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="QH1-s3-UQ7"/>
                                             <constraint firstItem="UPC-L1-VKj" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="QcN-sd-pHM"/>
                                             <constraint firstItem="LTt-2C-rPb" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="SUy-Mo-oAO"/>
                                             <constraint firstItem="jdW-oZ-cH8" firstAttribute="top" secondItem="Sms-Ez-fLO" secondAttribute="top" id="UBW-Mx-NTs"/>
                                             <constraint firstItem="8nf-zJ-Qas" firstAttribute="top" secondItem="UPC-L1-VKj" secondAttribute="bottom" id="UqS-Lx-6mL"/>
                                             <constraint firstItem="dhs-06-3RT" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="UwG-6b-pEk"/>
                                             <constraint firstItem="nVq-4i-FNy" firstAttribute="top" secondItem="mSC-JU-xuk" secondAttribute="bottom" id="VfU-sj-S9y"/>
+                                            <constraint firstAttribute="trailing" secondItem="npG-0C-m3A" secondAttribute="trailing" id="bLv-wr-d5v"/>
                                             <constraint firstAttribute="trailing" secondItem="lGp-bh-Ysz" secondAttribute="trailing" id="bUd-8w-D8k"/>
                                             <constraint firstItem="UPC-L1-VKj" firstAttribute="top" secondItem="lGp-bh-Ysz" secondAttribute="bottom" id="br5-nz-w7h"/>
                                             <constraint firstItem="8nf-zJ-Qas" firstAttribute="leading" secondItem="Sms-Ez-fLO" secondAttribute="leading" id="dsm-XA-dZD"/>
@@ -495,7 +537,7 @@
                                         </constraints>
                                     </view>
                                     <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ogC-ph-Xdr" userLabel="View Link">
-                                        <rect key="frame" x="5" y="550" width="404" height="40"/>
+                                        <rect key="frame" x="5" y="620" width="404" height="40"/>
                                         <subviews>
                                             <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Home server" textAlignment="natural" lineBreakMode="characterWrap" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="PD5-8h-ZLm">
                                                 <rect key="frame" x="40" y="0.0" width="359" height="40"/>
@@ -525,7 +567,7 @@
                                         </constraints>
                                     </view>
                                     <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="OO4-N7-9vp" userLabel="View JSON">
-                                        <rect key="frame" x="0.0" y="600" width="414" height="40.5"/>
+                                        <rect key="frame" x="0.0" y="670" width="414" height="40.5"/>
                                         <subviews>
                                             <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" scrollEnabled="NO" editable="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="RIO-6X-GG1">
                                                 <rect key="frame" x="5" y="5" width="404" height="30.5"/>
@@ -545,8 +587,8 @@
                                     </view>
                                 </subviews>
                                 <constraints>
-                                    <constraint firstItem="ogC-ph-Xdr" firstAttribute="top" secondItem="hTE-ys-qsF" secondAttribute="top" constant="550" id="9yP-Qs-EjJ"/>
-                                    <constraint firstItem="OO4-N7-9vp" firstAttribute="top" secondItem="hTE-ys-qsF" secondAttribute="top" constant="600" id="A9O-TK-Vz6" userLabel="View JSON.top = top + 550"/>
+                                    <constraint firstItem="ogC-ph-Xdr" firstAttribute="top" secondItem="hTE-ys-qsF" secondAttribute="top" constant="620" id="9yP-Qs-EjJ"/>
+                                    <constraint firstItem="OO4-N7-9vp" firstAttribute="top" secondItem="hTE-ys-qsF" secondAttribute="top" constant="670" id="A9O-TK-Vz6" userLabel="View JSON.top = top + 550"/>
                                     <constraint firstAttribute="trailing" secondItem="ogC-ph-Xdr" secondAttribute="trailing" constant="5" id="JLe-vC-Oyq"/>
                                     <constraint firstAttribute="bottom" secondItem="OO4-N7-9vp" secondAttribute="bottom" id="MpX-OZ-MDh"/>
                                     <constraint firstItem="OO4-N7-9vp" firstAttribute="width" secondItem="hTE-ys-qsF" secondAttribute="width" id="PWW-C3-Qcw"/>
@@ -579,6 +621,7 @@
                         <outlet property="imageEndToEndEncryption" destination="S7m-5Z-ktw" id="0Pv-Yt-YJB"/>
                         <outlet property="imageExternalSite" destination="JWO-C0-32L" id="JKi-n1-5IQ"/>
                         <outlet property="imageFileSharing" destination="G9c-Nd-Ikl" id="Wha-2g-8o0"/>
+                        <outlet property="imageLockFile" destination="eAC-Li-gKO" id="hHH-Pl-uOW"/>
                         <outlet property="imageNotification" destination="cgb-3g-trc" id="fa5-99-76C"/>
                         <outlet property="imageOnlyOffice" destination="xvv-h0-9bM" id="tw2-is-KHy"/>
                         <outlet property="imageText" destination="iCB-2A-phO" id="uit-Ku-oOF"/>
@@ -590,6 +633,7 @@
                         <outlet property="statusEndToEndEncryption" destination="M82-8U-M4Q" id="S9e-h3-GpF"/>
                         <outlet property="statusExternalSite" destination="ivv-te-kaP" id="qzS-eo-Dq3"/>
                         <outlet property="statusFileSharing" destination="SbT-rU-lJ8" id="zqA-0V-TLr"/>
+                        <outlet property="statusLockFile" destination="db5-st-O6M" id="dRt-zm-Qd7"/>
                         <outlet property="statusNotification" destination="WAg-Hw-sQS" id="T5C-Ch-11o"/>
                         <outlet property="statusOnlyOffice" destination="ucV-YG-5ht" id="11e-La-p9K"/>
                         <outlet property="statusText" destination="uiz-H8-p3D" id="wLb-D2-MNS"/>
@@ -626,7 +670,7 @@
         <image name="comments" width="425" height="425"/>
         <image name="delete" width="425" height="425"/>
         <image name="externalsites" width="425" height="425"/>
-        <image name="home" width="425" height="425"/>
+        <image name="home" width="120" height="120"/>
         <image name="lock" width="24" height="24"/>
         <image name="notification" width="512" height="512"/>
         <image name="onlyoffice" width="425" height="425"/>

+ 16 - 0
iOSClient/Diagnostics/NCCapabilitiesViewController.swift

@@ -64,6 +64,9 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr
     @IBOutlet weak var homeImage: UIImageView!
     @IBOutlet weak var homeServer: UILabel!
 
+    @IBOutlet weak var imageLockFile: UIImageView!
+    @IBOutlet weak var statusLockFile: UILabel!
+
     private let appDelegate = UIApplication.shared.delegate as! AppDelegate
     private var documentController: UIDocumentInteractionController?
     private var account: String = ""
@@ -139,6 +142,11 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr
         statusComments.layer.borderColor = UIColor.gray.cgColor
         statusComments.layer.masksToBounds = true
 
+        statusLockFile.layer.cornerRadius = 12.5
+        statusLockFile.layer.borderWidth = 0.5
+        statusLockFile.layer.borderColor = UIColor.gray.cgColor
+        statusLockFile.layer.masksToBounds = true
+
         imageFileSharing.image = UIImage(named: "share")!.image(color: NCBrandColor.shared.gray, size: 50)
         imageExternalSite.image = NCUtility.shared.loadImage(named: "network", color: NCBrandColor.shared.gray)
         imageEndToEndEncryption.image = NCUtility.shared.loadImage(named: "lock", color: NCBrandColor.shared.gray)
@@ -150,6 +158,7 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr
         imageOnlyOffice.image = UIImage(named: "onlyoffice")!.image(color: NCBrandColor.shared.gray, size: 50)
         imageUserStatus.image = UIImage(named: "userStatusAway")!.image(color: NCBrandColor.shared.gray, size: 50)
         imageComments.image = UIImage(named: "comments")!.image(color: NCBrandColor.shared.gray, size: 50)
+        imageLockFile.image = UIImage(named: "lock")!.image(color: NCBrandColor.shared.gray, size: 50)
 
         guard let activeAccount = NCManageDatabase.shared.getActiveAccount() else { return }
         self.account = activeAccount.account
@@ -315,6 +324,13 @@ class NCCapabilitiesViewController: UIViewController, UIDocumentInteractionContr
             statusComments.text = NSLocalizedString("_not_available_", comment: "")
         }
 
+        let hasLockCapability = NCManageDatabase.shared.getCapabilitiesServerInt(account: appDelegate.account, elements: NCElementsJSON.shared.capabilitiesFilesLockVersion) >= 1
+        if hasLockCapability {
+            statusLockFile.text = "✓ " + NSLocalizedString("_available_", comment: "")
+        } else {
+            statusLockFile.text = NSLocalizedString("_not_available_", comment: "")
+        }
+
         print("end.")
     }
 }

+ 33 - 0
iOSClient/Extensions/DateFormatter+Extension.swift

@@ -0,0 +1,33 @@
+//
+//  DateFormatter+Extension.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 18.03.22.
+//  Copyright © 2022 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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 Foundation
+
+extension DateFormatter {
+    static let shareExpDate: DateFormatter = {
+        let dateFormatter = DateFormatter()
+        dateFormatter.formatterBehavior = .behavior10_4
+        dateFormatter.dateStyle = .medium
+        return dateFormatter
+    }()
+}

+ 6 - 1
iOSClient/Extensions/String+Extensions.swift

@@ -26,6 +26,11 @@ import UIKit
 import CommonCrypto
 
 extension String {
+
+    var alphanumeric: String {
+        return self.components(separatedBy: CharacterSet.alphanumerics.inverted).joined().lowercased()
+    }
+
     public var uppercaseInitials: String? {
         let initials = self.components(separatedBy: .whitespaces)
             .reduce("", {
@@ -49,7 +54,7 @@ extension String {
         //https://stackoverflow.com/a/32166735/9506784
 
         let length = Int(CC_MD5_DIGEST_LENGTH)
-        let messageData = self.data(using: .utf8)!
+        let messageData = self.data(using: .utf8) ?? Data()
         var digestData = Data(count: length)
 
         _ = digestData.withUnsafeMutableBytes { digestBytes -> UInt8 in

+ 91 - 0
iOSClient/Extensions/UIAlertController+Extension.swift

@@ -0,0 +1,91 @@
+//
+//  UIAlertController+Extension.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 27.01.22.
+//  Copyright © 2022 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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
+
+extension UIAlertController {
+    /// Creates a alert controller with a textfield, asking to create a new folder
+    /// - Parameters:
+    ///   - serverUrl: Server url of the location where the folder should be created
+    ///   - urlBase: UrlBase object
+    ///   - completion: If not` nil` it overrides the default behavior which shows an error using `NCContentPresenter`
+    /// - Returns: The presentable alert controller
+    static func createFolder(serverUrl: String, urlBase: NCUserBaseUrl, completion: ((_ errorCode: Int, _ errorDescription: String) -> Void)? = nil) -> UIAlertController {
+        let alertController = UIAlertController(title: NSLocalizedString("_create_folder_", comment: ""), message: nil, preferredStyle: .alert)
+
+        let okAction = UIAlertAction(title: NSLocalizedString("_save_", comment: ""), style: .default, handler: { _ in
+            guard let fileNameFolder = alertController.textFields?.first?.text else { return }
+            NCNetworking.shared.createFolder(fileName: fileNameFolder, serverUrl: serverUrl, account: urlBase.account, urlBase: urlBase.urlBase, overwrite: false) { errorCode, errorDescription in
+                if let completion = completion {
+                    completion(errorCode, errorDescription)
+                } else if errorCode != 0 {
+                    NCContentPresenter.shared.messageNotification("_error_", description: errorDescription, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error, errorCode: errorCode)
+                } // else: successful, no action
+            }
+        })
+
+        // text field is initially empty, no action
+        okAction.isEnabled = false
+        let cancelAction = UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel)
+
+        alertController.addTextField { textField in
+            textField.autocapitalizationType = .words
+        }
+
+        // only allow saving if folder name exists
+        NotificationCenter.default.addObserver(
+            forName: UITextField.textDidChangeNotification,
+            object: alertController.textFields?.first,
+            queue: .main) { _ in
+                guard let text = alertController.textFields?.first?.text,
+                      let folderName = CCUtility.removeForbiddenCharactersServer(text)?.trimmingCharacters(in: .whitespaces) else { return }
+                okAction.isEnabled = !folderName.isEmpty && folderName != "." && folderName != ".."
+            }
+
+        alertController.addAction(cancelAction)
+        alertController.addAction(okAction)
+        return alertController
+    }
+
+    static func withTextField(titleKey: String, textFieldConfiguration: ((UITextField) -> Void)?, completion: @escaping (String?) -> Void) -> UIAlertController {
+        let alertController = UIAlertController(title: NSLocalizedString(titleKey, comment: ""), message: "", preferredStyle: .alert)
+        alertController.addTextField { textField in
+            textFieldConfiguration?(textField)
+        }
+        alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default) { _ in })
+        let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { _ in
+            completion(alertController.textFields?.first?.text)
+        }
+
+        alertController.addAction(okAction)
+        return alertController
+    }
+
+    static func password(titleKey: String, completion: @escaping (String?) -> Void) -> UIAlertController {
+        return .withTextField(titleKey: titleKey, textFieldConfiguration: { textField in
+            textField.isSecureTextEntry = true
+            textField.placeholder = NSLocalizedString("_password_", comment: "")
+        }, completion: completion)
+
+    }
+}

+ 1 - 1
iOSClient/Extensions/UIApplication+Orientation.swift

@@ -20,7 +20,7 @@
 //  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 Foundation
+import UIKit
 
 extension UIApplication {
     // indicates if current device is in landscape orientation

+ 37 - 0
iOSClient/Extensions/UIDevice+Extensions.swift

@@ -0,0 +1,37 @@
+//
+//  UIDevice+Extensions.swift
+//  Nextcloud
+//
+//  Created by Federico Malagoni on 23/02/22.
+//  Copyright © 2022 Federico Malagoni. All rights reserved.
+//
+//  Author Federico Malagoni <federico.malagoni@astrairidium.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 Foundation
+extension UIDevice {
+
+    var hasNotch: Bool {
+        if #available(iOS 11.0, *) {
+            if UIApplication.shared.windows.isEmpty { return false }
+            let top = UIApplication.shared.windows[0].safeAreaInsets.top
+            return top > 20
+        } else {
+            // Fallback on earlier versions
+            return false
+        }
+    }
+}

+ 31 - 0
iOSClient/Extensions/UIFont+Extension.swift

@@ -0,0 +1,31 @@
+//
+//  UIFont+Extensions.swift
+//  Nextcloud
+//
+//  Created by Federico Malagoni on 23/02/22.
+//  Copyright © 2022 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
+
+extension UIFont {
+
+    static func incosolataMedium(size: CGFloat) -> UIFont {
+        return UIFont(name: "Inconsolata-Medium", size: size)!
+    }
+}

+ 77 - 0
iOSClient/Extensions/UIToolbar+Extension.swift

@@ -0,0 +1,77 @@
+//
+//  UIToolbar+Extension.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 18.03.22.
+//  Copyright © 2022 Henrik Storch. All rights reserved.
+//
+//  Author Henrik Storch <henrik.storch@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
+
+extension UIToolbar {
+    static func toolbar(onClear: (() -> Void)?, completion: @escaping () -> Void) -> UIToolbar {
+        let toolbar = UIToolbar()
+        toolbar.sizeToFit()
+        var buttons: [UIBarButtonItem] = []
+
+        if let onClear = onClear {
+            let clearButton = UIBarButtonItem(title: NSLocalizedString("_clear_", comment: ""), style: .plain) {
+                onClear()
+            }
+            buttons.append(clearButton)
+        }
+        buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
+        let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
+            completion()
+        }
+        buttons.append(doneButton)
+        toolbar.setItems(buttons, animated: false)
+        return toolbar
+    }
+
+    // by default inputAccessoryView does not respect safeArea
+    var wrappedSafeAreaContainer: UIView {
+        let view = InputBarWrapper()
+        view.addSubview(self)
+        self.translatesAutoresizingMaskIntoConstraints = false
+        NSLayoutConstraint.activate([
+            self.topAnchor.constraint(equalTo: view.topAnchor),
+            self.leftAnchor.constraint(equalTo: view.leftAnchor),
+            self.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
+            self.rightAnchor.constraint(equalTo: view.rightAnchor)
+        ])
+        return view
+    }
+}
+
+// https://stackoverflow.com/a/67985180/9506784
+class InputBarWrapper: UIView {
+
+    var desiredHeight: CGFloat = 0 {
+        didSet { invalidateIntrinsicContentSize() }
+    }
+
+    override var intrinsicContentSize: CGSize { CGSize(width: 0, height: desiredHeight) }
+
+    required init?(coder aDecoder: NSCoder) { fatalError() }
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        autoresizingMask = .flexibleHeight
+    }
+}

BIN
iOSClient/Font/Inconsolata/Inconsolata-Black.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-Bold.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-ExtraBold.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-ExtraLight.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-Light.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-Medium.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-Regular.ttf


BIN
iOSClient/Font/Inconsolata/Inconsolata-SemiBold.ttf


+ 1 - 1
iOSClient/Images.xcassets/pdf-vertical.imageset/Contents.json → iOSClient/Images.xcassets/captions.bubble.imageset/Contents.json

@@ -1,7 +1,7 @@
 {
   "images" : [
     {
-      "filename" : "swap-vertical-variant.svg",
+      "filename" : "subtitles-outline.svg",
       "idiom" : "universal"
     }
   ],

+ 1 - 1
iOSClient/Images.xcassets/pdf-horizontal.imageset/swap-horizontal-variant.svg → iOSClient/Images.xcassets/captions.bubble.imageset/subtitles-outline.svg

@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M4,6L8,10V7H16A2,2 0 0,1 18,9A2,2 0 0,1 16,11H8A4,4 0 0,0 4,15A4,4 0 0,0 8,19H16V22L20,18L16,14V17H8A2,2 0 0,1 6,15A2,2 0 0,1 8,13H16A4,4 0 0,0 20,9A4,4 0 0,0 16,5H8V2L4,6Z" /></svg>
+<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M20,4A2,2 0 0,1 22,6V18A2,2 0 0,1 20,20H4A2,2 0 0,1 2,18V6A2,2 0 0,1 4,4H20M20,18V6H4V18H20M6,10H8V12H6V10M6,14H14V16H6V14M16,14H18V16H16V14M10,10H18V12H10V10Z" /></svg>

+ 0 - 0
iOSClient/Images.xcassets/circle.fill.imageset/Contents.json → iOSClient/Images.xcassets/circle_fill.imageset/Contents.json


+ 0 - 0
iOSClient/Images.xcassets/circle.fill.imageset/circle.pdf → iOSClient/Images.xcassets/circle_fill.imageset/circle.pdf


+ 0 - 15
iOSClient/Images.xcassets/closeVideo.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "closeVideo.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/closeVideo.imageset/closeVideo.pdf


+ 0 - 15
iOSClient/Images.xcassets/edit.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "edit.pdf"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/edit.imageset/edit.pdf


+ 1 - 1
iOSClient/Images.xcassets/userStatusOnline.imageset/Contents.json → iOSClient/Images.xcassets/eye.imageset/Contents.json

@@ -1,7 +1,7 @@
 {
   "images" : [
     {
-      "filename" : "online.pdf",
+      "filename" : "eye.svg",
       "idiom" : "universal"
     }
   ],

+ 1 - 0
iOSClient/Images.xcassets/eye.imageset/eye.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 15.06"><path d="M12.004 15.06q1.774 0 3.351-.426 1.576-.425 2.911-1.124 1.334-.698 2.393-1.541 1.058-.843 1.804-1.69.747-.848 1.142-1.572Q24 7.982 24 7.535q0-.448-.395-1.173-.395-.724-1.142-1.572-.746-.847-1.804-1.69-1.059-.843-2.398-1.541Q16.922.861 15.346.435 13.769.009 12.004.009q-1.747 0-3.315.426-1.567.426-2.906 1.124-1.34.698-2.406 1.541-1.067.843-1.823 1.69Q.799 5.638.4 6.362 0 7.087 0 7.535q0 .447.4 1.172.399.724 1.154 1.572.756.847 1.818 1.69 1.063.843 2.402 1.541 1.339.699 2.907 1.124 1.567.426 3.323.426Zm0-1.387q-1.449 0-2.783-.36-1.335-.36-2.503-.953-1.168-.593-2.116-1.295-.949-.703-1.638-1.392-.69-.689-1.058-1.26-.369-.571-.369-.878 0-.264.369-.808.368-.545 1.058-1.243.689-.698 1.638-1.409.948-.712 2.116-1.322 1.168-.61 2.503-.984 1.334-.373 2.783-.373 1.441 0 2.771.373 1.33.374 2.498.984 1.168.61 2.121 1.322.953.711 1.638 1.409.685.698 1.058 1.243.373.544.373.808 0 .307-.373.878t-1.058 1.26q-.685.689-1.638 1.392-.953.702-2.121 1.295-1.168.593-2.498.953-1.33.36-2.771.36Zm0-1.221q1.019 0 1.915-.386.895-.387 1.572-1.067.676-.681 1.058-1.572t.382-1.892q0-1.028-.382-1.924-.382-.895-1.058-1.567-.677-.672-1.572-1.049-.896-.378-1.915-.378-1.036 0-1.932.378-.895.377-1.571 1.049-.677.672-1.059 1.567-.382.896-.382 1.924.009 1.001.391 1.892t1.058 1.572q.676.68 1.568 1.067.891.386 1.927.386Zm0-3.284q-.685 0-1.168-.483-.483-.483-.483-1.15 0-.677.483-1.155.483-.479 1.168-.479.677 0 1.16.479.483.478.483 1.155 0 .667-.483 1.15-.483.483-1.16.483Z"/></svg>

+ 0 - 0
iOSClient/Images.xcassets/lock.open.imageset/Contents.json → iOSClient/Images.xcassets/lock_open.imageset/Contents.json


+ 0 - 0
iOSClient/Images.xcassets/lock.open.imageset/lock-open-variant-outline.svg → iOSClient/Images.xcassets/lock_open.imageset/lock-open-variant-outline.svg


+ 1 - 1
iOSClient/Images.xcassets/pdf-horizontal.imageset/Contents.json → iOSClient/Images.xcassets/moreLock.imageset/Contents.json

@@ -1,7 +1,7 @@
 {
   "images" : [
     {
-      "filename" : "swap-horizontal-variant.svg",
+      "filename" : "menu-locked-filled.svg",
       "idiom" : "universal"
     }
   ],

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 65 - 0
iOSClient/Images.xcassets/moreLock.imageset/menu-locked-filled.svg


+ 0 - 1
iOSClient/Images.xcassets/pdf-vertical.imageset/swap-vertical-variant.svg

@@ -1 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M18,4L14,8H17V16A2,2 0 0,1 15,18A2,2 0 0,1 13,16V8A4,4 0 0,0 9,4A4,4 0 0,0 5,8V16H2L6,20L10,16H7V8A2,2 0 0,1 9,6A2,2 0 0,1 11,8V16A4,4 0 0,0 15,20A4,4 0 0,0 19,16V8H22L18,4Z" /></svg>

+ 0 - 23
iOSClient/Images.xcassets/photoEditorCancel.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCancel.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCancel@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCancel@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel.png


BIN
iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel@2x.png


BIN
iOSClient/Images.xcassets/photoEditorCancel.imageset/photoEditorCancel@3x.png


+ 0 - 23
iOSClient/Images.xcassets/photoEditorClear.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorClear.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorClear@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorClear@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear.png


BIN
iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear@2x.png


BIN
iOSClient/Images.xcassets/photoEditorClear.imageset/photoEditorClear@3x.png


+ 0 - 23
iOSClient/Images.xcassets/photoEditorCrop.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCrop.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCrop@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorCrop@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop.png


BIN
iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop@2x.png


BIN
iOSClient/Images.xcassets/photoEditorCrop.imageset/photoEditorCrop@3x.png


+ 0 - 23
iOSClient/Images.xcassets/photoEditorDone.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDone.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDone@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDone@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone.png


BIN
iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone@2x.png


BIN
iOSClient/Images.xcassets/photoEditorDone.imageset/photoEditorDone@3x.png


+ 0 - 23
iOSClient/Images.xcassets/photoEditorDraw.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDraw.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDraw@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorDraw@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw.png


BIN
iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw@2x.png


BIN
iOSClient/Images.xcassets/photoEditorDraw.imageset/photoEditorDraw@3x.png


+ 0 - 23
iOSClient/Images.xcassets/photoEditorText.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorText.png",
-      "scale" : "1x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorText@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "photoEditorText@3x.png",
-      "scale" : "3x"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText.png


BIN
iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText@2x.png


BIN
iOSClient/Images.xcassets/photoEditorText.imageset/photoEditorText@3x.png


+ 0 - 15
iOSClient/Images.xcassets/tabBarFavorites.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "tabBarFavorites.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/tabBarFavorites.imageset/tabBarFavorites.pdf


+ 0 - 15
iOSClient/Images.xcassets/tabBarMedia.imageset/Contents.json

@@ -1,15 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "tabBarMedia.pdf",
-      "idiom" : "universal"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  },
-  "properties" : {
-    "preserves-vector-representation" : true
-  }
-}

BIN
iOSClient/Images.xcassets/tabBarMedia.imageset/tabBarMedia.pdf


BIN
iOSClient/Images.xcassets/userStatusOnline.imageset/online.pdf


+ 0 - 23
iOSClient/Images.xcassets/visiblePassword.imageset/Contents.json

@@ -1,23 +0,0 @@
-{
-  "images" : [
-    {
-      "idiom" : "universal",
-      "scale" : "1x",
-      "filename" : "visiblePassword.png"
-    },
-    {
-      "idiom" : "universal",
-      "filename" : "visiblePassword@2x.png",
-      "scale" : "2x"
-    },
-    {
-      "idiom" : "universal",
-      "scale" : "3x",
-      "filename" : "visiblePassword@3x.png"
-    }
-  ],
-  "info" : {
-    "version" : 1,
-    "author" : "xcode"
-  }
-}

BIN
iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword.png


BIN
iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword@2x.png


BIN
iOSClient/Images.xcassets/visiblePassword.imageset/visiblePassword@3x.png


+ 3 - 4
iOSClient/Main/AudioRecorder/NCAudioRecorderViewController.swift

@@ -93,7 +93,6 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate {
 
         if recording.state == .record {
 
-            startDate = Date()
             recording.stop()
             voiceRecordHUD.update(0.0)
 
@@ -105,6 +104,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate {
 
             do {
                 try recording.record()
+                startDate = Date()
                 startStopLabel.text = NSLocalizedString("_voice_memo_stop_", comment: "")
             } catch {
                 print(error)
@@ -188,8 +188,8 @@ open class NCAudioRecorder: NSObject {
 
     // MARK: - Initializers
 
-    public init(to: String) {
-        url = URL(fileURLWithPath: NCAudioRecorder.directory).appendingPathComponent(to)
+    public init(to fileName: String) {
+        url = URL(fileURLWithPath: NCAudioRecorder.directory).appendingPathComponent(fileName)
         super.init()
 
         do {
@@ -278,7 +278,6 @@ open class NCAudioRecorder: NSObject {
     }
 
     fileprivate func stopMetering() {
-
         link?.invalidate()
         link = nil
     }

+ 38 - 3
iOSClient/Main/Collection Common/NCCollectionViewCommon.swift

@@ -44,7 +44,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
     internal var metadataFolder: tableMetadata?
     internal var dataSource = NCDataSource()
     internal var richWorkspaceText: String?
-    internal var header: UIView?
+    internal var header: NCSectionHeaderMenu?
 
     internal var layoutForView: NCGlobal.layoutForViewType?
 
@@ -615,7 +615,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
         button.action(for: .touchUpInside) { _ in
             
             let accounts = NCManageDatabase.shared.getAllAccountOrderAlias()
-            if accounts.count > 0 {
+            if accounts.count > 0 && !NCBrandOptions.shared.disable_multiaccount && !NCBrandOptions.shared.disable_manage_account {
                 
                 if let vcAccountRequest = UIStoryboard(name: "NCAccountRequest", bundle: nil).instantiateInitialViewController() as? NCAccountRequest {
                     
@@ -741,6 +741,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
         if collectionView.collectionViewLayout == gridLayout {
             // list layout
+            header?.buttonSwitch.accessibilityLabel = NSLocalizedString("_grid_view_", comment: "")
             UIView.animate(withDuration: 0.0, animations: {
                 self.collectionView.collectionViewLayout.invalidateLayout()
                 self.collectionView.setCollectionViewLayout(self.listLayout, animated: false, completion: { _ in
@@ -751,6 +752,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
             NCUtility.shared.setLayoutForView(key: layoutKey, serverUrl: serverUrl, layout: layoutForView?.layout)
         } else {
             // grid layout
+            header?.buttonSwitch.accessibilityLabel = NSLocalizedString("_list_view_", comment: "")
             UIView.animate(withDuration: 0.0, animations: {
                 self.collectionView.collectionViewLayout.invalidateLayout()
                 self.collectionView.setCollectionViewLayout(self.gridLayout, animated: false, completion: { _ in
@@ -789,7 +791,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS
 
         guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(objectId) else { return }
 
-        if namedButtonMore == NCGlobal.shared.buttonMoreMore {
+        if namedButtonMore == NCGlobal.shared.buttonMoreMore || namedButtonMore == NCGlobal.shared.buttonMoreLock {
             toggleMenu(metadata: metadata, imageIcon: image)
         } else if namedButtonMore == NCGlobal.shared.buttonMoreStop {
             NCNetworking.shared.cancelTransferMetadata(metadata) { }
@@ -1267,8 +1269,10 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
             if collectionView.collectionViewLayout == gridLayout {
                 header.buttonSwitch.setImage(UIImage(named: "switchList")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal)
+                header.buttonSwitch.accessibilityLabel = NSLocalizedString("_list_view_", comment: "")
             } else {
                 header.buttonSwitch.setImage(UIImage(named: "switchGrid")!.image(color: NCBrandColor.shared.gray, size: 50), for: .normal)
+                header.buttonSwitch.accessibilityLabel = NSLocalizedString("_grid_view_", comment: "")
             }
 
             header.delegate = self
@@ -1388,6 +1392,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 progress = progressType.progress
                 totalBytes = progressType.totalBytes
             }
+
             if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.progressView.isHidden = false
                 cell.progressView.progress = progress
@@ -1396,6 +1401,11 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 cell.progressView.progress = 0.0
             }
 
+            var a11yValues: [String] = []
+            if metadata.ownerId != appDelegate.userId, appDelegate.account == metadata.account {
+                a11yValues.append(NSLocalizedString("_shared_with_you_by_", comment: "") + " " + metadata.ownerDisplayName)
+            }
+
             if metadata.directory {
 
                 if metadata.e2eEncrypted {
@@ -1428,6 +1438,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
                 // image local
                 if dataSource.metadataOffLine.contains(metadata.ocId) {
+                    a11yValues.append(NSLocalizedString("_offline_", comment: ""))
                     cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag
                 } else if CCUtility.fileProviderStorageExists(metadata) {
                     cell.imageLocal.image = NCBrandColor.cacheImages.local
@@ -1437,6 +1448,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             // image Favorite
             if metadata.favorite {
                 cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
+                a11yValues.append(NSLocalizedString("_favorite_", comment: ""))
             }
 
             // Share image
@@ -1455,6 +1467,9 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
 
             if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+            } else if metadata.lock == true {
+                cell.setButtonMore(named: NCGlobal.shared.buttonMoreLock, image: NCBrandColor.cacheImages.buttonMoreLock)
+                a11yValues.append(String(format: NSLocalizedString("_locked_by_", comment: ""), metadata.lockOwnerDisplayName))
             } else {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore)
             }
@@ -1490,9 +1505,12 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 break
             }
 
+            cell.accessibilityLabel = metadata.fileNameView + ", " + (cell.labelInfo.text ?? "")
+
             // Live Photo
             if metadata.livePhoto {
                 cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
+                a11yValues.append(NSLocalizedString("_upload_mov_livephoto_", comment: ""))
             }
 
             // E2EE
@@ -1514,12 +1532,14 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 cell.selectMode(true)
                 if selectOcId.contains(metadata.ocId) {
                     cell.selected(true)
+                    a11yValues.append(NSLocalizedString("_selected_", comment: ""))
                 } else {
                     cell.selected(false)
                 }
             } else {
                 cell.selectMode(false)
             }
+            cell.accessibilityValue = a11yValues.joined(separator: ", ")
 
             // Disable Share Button
             if appDelegate.disableSharesView {
@@ -1559,9 +1579,16 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             if metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.progressView.isHidden = false
                 cell.progressView.progress = progress
+                cell.accessibilityLabel = metadata.fileNameView + ", \(Int(progress * 100))%"
             } else {
                 cell.progressView.isHidden = true
                 cell.progressView.progress = 0.0
+                cell.accessibilityLabel = metadata.fileNameView
+            }
+
+            var a11yValues: [String] = []
+            if metadata.ownerId != appDelegate.userId, appDelegate.account == metadata.account {
+                a11yValues.append(NSLocalizedString("_shared_with_you_by_", comment: "") + " " + metadata.ownerDisplayName)
             }
 
             if metadata.directory {
@@ -1597,6 +1624,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 // image Local
                 if dataSource.metadataOffLine.contains(metadata.ocId) {
                     cell.imageLocal.image = NCBrandColor.cacheImages.offlineFlag
+                    a11yValues.append(NSLocalizedString("_offline_", comment: ""))
                 } else if CCUtility.fileProviderStorageExists(metadata) {
                     cell.imageLocal.image = NCBrandColor.cacheImages.local
                 }
@@ -1605,11 +1633,15 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             // image Favorite
             if metadata.favorite {
                 cell.imageFavorite.image = NCBrandColor.cacheImages.favorite
+                a11yValues.append(NSLocalizedString("_favorite_", comment: ""))
             }
 
             // Transfer
             if metadata.status == NCGlobal.shared.metadataStatusInDownload || metadata.status == NCGlobal.shared.metadataStatusDownloading || metadata.status == NCGlobal.shared.metadataStatusInUpload || metadata.status == NCGlobal.shared.metadataStatusUploading {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCBrandColor.cacheImages.buttonStop)
+            } else if metadata.lock == true {
+                cell.setButtonMore(named: NCGlobal.shared.buttonMoreLock, image: NCBrandColor.cacheImages.buttonMoreLock)
+                a11yValues.append(String(format: NSLocalizedString("_locked_by_", comment: ""), metadata.lockOwnerDisplayName))
             } else {
                 cell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCBrandColor.cacheImages.buttonMore)
             }
@@ -1617,6 +1649,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
             // Live Photo
             if metadata.livePhoto {
                 cell.imageStatus.image = NCBrandColor.cacheImages.livePhoto
+                a11yValues.append(NSLocalizedString("_upload_mov_livephoto_", comment: ""))
             }
 
             // Edit mode
@@ -1624,12 +1657,14 @@ extension NCCollectionViewCommon: UICollectionViewDataSource {
                 cell.selectMode(true)
                 if selectOcId.contains(metadata.ocId) {
                     cell.selected(true)
+                    a11yValues.append(NSLocalizedString("_selected_", comment: ""))
                 } else {
                     cell.selected(false)
                 }
             } else {
                 cell.selectMode(false)
             }
+            cell.accessibilityValue = a11yValues.joined(separator: ", ")
 
             return cell
         }

+ 23 - 0
iOSClient/Main/Collection Common/NCGridCell.swift

@@ -72,6 +72,12 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     override func awakeFromNib() {
         super.awakeFromNib()
 
+        // use entire cell as accessibility element
+        accessibilityHint = nil
+        accessibilityLabel = nil
+        accessibilityValue = nil
+        isAccessibilityElement = true
+
         imageItem.layer.cornerRadius = 6
         imageItem.layer.masksToBounds = true
 
@@ -99,6 +105,9 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     override func prepareForReuse() {
         super.prepareForReuse()
         imageItem.backgroundColor = nil
+        accessibilityHint = nil
+        accessibilityLabel = nil
+        accessibilityValue = nil
     }
 
     @IBAction func touchUpInsideMore(_ sender: Any) {
@@ -113,9 +122,21 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
         delegate?.longPressGridItem(with: objectId, gestureRecognizer: gestureRecognizer)
     }
 
+    fileprivate func setA11yActions() {
+        let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_"
+        
+        self.accessibilityCustomActions = [
+            UIAccessibilityCustomAction(
+                name: NSLocalizedString(moreName, comment: ""),
+                target: self,
+                selector: #selector(touchUpInsideMore))
+        ]
+    }
+    
     func setButtonMore(named: String, image: UIImage) {
         namedButtonMore = named
         buttonMore.setImage(image, for: .normal)
+        setA11yActions()
     }
 
     func hideButtonMore(_ status: Bool) {
@@ -125,9 +146,11 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto
     func selectMode(_ status: Bool) {
         if status {
             imageSelect.isHidden = false
+            accessibilityCustomActions = nil
         } else {
             imageSelect.isHidden = true
             imageVisualEffect.isHidden = true
+            setA11yActions()
         }
     }
 

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.