From 1d0e3bc98e7e0aa87b3c8d8d8920f7ad5249b027 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 16:05:10 +0800 Subject: [PATCH 01/26] Move all sharing components for FileProviderUIExt into a Sharing folder Signed-off-by: Claudio Cambra --- .../{ => Sharing}/ShareController.swift | 0 .../{ => Sharing}/ShareOptionsView.swift | 0 .../{ => Sharing}/ShareTableItemView.swift | 0 .../{ => Sharing}/ShareTableItemView.xib | 0 .../ShareTableViewDataSource.swift | 0 .../{ => Sharing}/ShareViewController.swift | 0 .../{ => Sharing}/ShareViewController.xib | 0 .../ShareViewDataSourceUIDelegate.swift | 0 .../ShareeSuggestionsDataSource.swift | 0 .../project.pbxproj | 26 ++++++++++++------- 10 files changed, 17 insertions(+), 9 deletions(-) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareController.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareOptionsView.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareTableItemView.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareTableItemView.xib (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareTableViewDataSource.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareViewController.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareViewController.xib (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareViewDataSourceUIDelegate.swift (100%) rename shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/{ => Sharing}/ShareeSuggestionsDataSource.swift (100%) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareController.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareController.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareController.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareOptionsView.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareOptionsView.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareOptionsView.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableItemView.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableItemView.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableItemView.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableItemView.xib rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableItemView.xib diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableViewDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareTableViewDataSource.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewController.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewController.xib rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewController.xib diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewDataSourceUIDelegate.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewDataSourceUIDelegate.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareViewDataSourceUIDelegate.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareViewDataSourceUIDelegate.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareeSuggestionsDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareeSuggestionsDataSource.swift similarity index 100% rename from shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/ShareeSuggestionsDataSource.swift rename to shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareeSuggestionsDataSource.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index 7162acf23..cc7bde0a6 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -280,6 +280,22 @@ path = Extensions; sourceTree = ""; }; + 537BD6772C58D0C400446ED0 /* Sharing */ = { + isa = PBXGroup; + children = ( + 5374FD432B95EE1400C78D54 /* ShareController.swift */, + 53651E452BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift */, + 53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */, + 53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */, + 531522812B8E01C6002E31BE /* ShareTableItemView.xib */, + 53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */, + 537630922B85F4B00026BFAB /* ShareViewController.swift */, + 537630902B85F4980026BFAB /* ShareViewController.xib */, + 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */, + ); + path = Sharing; + sourceTree = ""; + }; 538E396827F4765000FA63D5 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -321,16 +337,8 @@ isa = PBXGroup; children = ( 5376307B2B85E2E00026BFAB /* Extensions */, + 537BD6772C58D0C400446ED0 /* Sharing */, 53B979802B84C81F002DA742 /* DocumentActionViewController.swift */, - 5374FD432B95EE1400C78D54 /* ShareController.swift */, - 53651E452BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift */, - 53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */, - 53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */, - 531522812B8E01C6002E31BE /* ShareTableItemView.xib */, - 53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */, - 537630922B85F4B00026BFAB /* ShareViewController.swift */, - 537630902B85F4980026BFAB /* ShareViewController.xib */, - 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */, 53B979852B84C81F002DA742 /* Info.plist */, ); From 73674bf6331764dafd94e8ce33759812d1088020 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 16:18:58 +0800 Subject: [PATCH 02/26] Add basic LockViewController components Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 16 ++++++++++++++++ .../Locking/LockViewController.xib | 19 +++++++++++++++++++ .../project.pbxproj | 16 ++++++++++++++++ 3 files changed, 51 insertions(+) create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift new file mode 100644 index 000000000..99eee3080 --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -0,0 +1,16 @@ +// +// LockViewController.swift +// FileProviderUIExt +// +// Created by Claudio Cambra on 30/7/24. +// + +import AppKit +import FileProvider +import NextcloudKit +import OSLog +import QuickLookThumbnailing + +class LockViewController: NSViewController { + +} diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib new file mode 100644 index 000000000..0f40790ec --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index cc7bde0a6..0a6e23366 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ 537630952B860D560026BFAB /* FPUIExtensionServiceSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */; }; 537630972B860D920026BFAB /* FPUIExtensionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537630962B860D920026BFAB /* FPUIExtensionService.swift */; }; 537630982B8612F00026BFAB /* FPUIExtensionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537630962B860D920026BFAB /* FPUIExtensionService.swift */; }; + 537BD67A2C58D67800446ED0 /* LockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD6792C58D67800446ED0 /* LockViewController.swift */; }; + 537BD67C2C58D7B700446ED0 /* LockViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537BD67B2C58D7B700446ED0 /* LockViewController.xib */; }; 538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; }; 538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; }; 538E397627F4765000FA63D5 /* FileProviderExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 538E396727F4765000FA63D5 /* FileProviderExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -163,6 +165,8 @@ 537630922B85F4B00026BFAB /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionServiceSource.swift; sourceTree = ""; }; 537630962B860D920026BFAB /* FPUIExtensionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionService.swift; sourceTree = ""; }; + 537BD6792C58D67800446ED0 /* LockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockViewController.swift; sourceTree = ""; }; + 537BD67B2C58D7B700446ED0 /* LockViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LockViewController.xib; sourceTree = ""; }; 538E396727F4765000FA63D5 /* FileProviderExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderExt.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = ""; }; @@ -296,6 +300,15 @@ path = Sharing; sourceTree = ""; }; + 537BD6782C58D0FC00446ED0 /* Locking */ = { + isa = PBXGroup; + children = ( + 537BD6792C58D67800446ED0 /* LockViewController.swift */, + 537BD67B2C58D7B700446ED0 /* LockViewController.xib */, + ); + path = Locking; + sourceTree = ""; + }; 538E396827F4765000FA63D5 /* Frameworks */ = { isa = PBXGroup; children = ( @@ -337,6 +350,7 @@ isa = PBXGroup; children = ( 5376307B2B85E2E00026BFAB /* Extensions */, + 537BD6782C58D0FC00446ED0 /* Locking */, 537BD6772C58D0C400446ED0 /* Sharing */, 53B979802B84C81F002DA742 /* DocumentActionViewController.swift */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */, @@ -625,6 +639,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 537BD67C2C58D7B700446ED0 /* LockViewController.xib in Resources */, 531522822B8E01C6002E31BE /* ShareTableItemView.xib in Resources */, 537630912B85F4980026BFAB /* ShareViewController.xib in Resources */, ); @@ -702,6 +717,7 @@ 537630932B85F4B00026BFAB /* ShareViewController.swift in Sources */, 53FE14672B8F78B6006C4193 /* ShareOptionsView.swift in Sources */, 53651E462BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift in Sources */, + 537BD67A2C58D67800446ED0 /* LockViewController.swift in Sources */, 53FE14652B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift in Sources */, 53B979812B84C81F002DA742 /* DocumentActionViewController.swift in Sources */, 5374FD442B95EE1400C78D54 /* ShareController.swift in Sources */, From 501c1c4d6267f83f268324585efb114e8445c8cb Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 16:19:29 +0800 Subject: [PATCH 03/26] Add lock/unlock actions in FileProviderUIExt info plist Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Info.plist | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist index 85f108b15..3f843aaed 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist @@ -2,16 +2,32 @@ - CFBundleName - $(PRODUCT_NAME) - CFBundleDisplayName - $(OC_APPLICATION_NAME) File Provider UI Extension - CFBundleIdentifier - $(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME) + CFBundleName + $(PRODUCT_NAME) + CFBundleDisplayName + $(OC_APPLICATION_NAME) File Provider UI Extension + CFBundleIdentifier + $(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME) NSExtension NSExtensionFileProviderActions + + NSExtensionFileProviderActionIdentifier + com.nextcloud.desktopclient.FileProviderUIExt.UnlockFileAction + NSExtensionFileProviderActionName + Unlock file + NSExtensionFileProviderActionActivationRule + SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo."isUnlockable" == YES ).@count > 0 + + + NSExtensionFileProviderActionActivationRule + SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo."isLockable" == YES ).@count > 0 + NSExtensionFileProviderActionName + Lock file + NSExtensionFileProviderActionIdentifier + com.nextcloud.desktopclient.FileProviderUIExt.LockFileAction + NSExtensionFileProviderActionActivationRule TRUEPREDICATE From ec66bcd19b4a7b5475375d93e81a8c8b34f71fff Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 16:20:10 +0800 Subject: [PATCH 04/26] Handle new locking action identifiers in document action view controller of FileProviderUIExt Signed-off-by: Claudio Cambra --- .../DocumentActionViewController.swift | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift index 96363e962..d14c3dd3e 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift @@ -36,17 +36,21 @@ class DocumentActionViewController: FPUIActionExtensionViewController { ) { Logger.actionViewController.info("Preparing action: \(actionIdentifier, privacy: .public)") - if actionIdentifier == "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction" { + switch (actionIdentifier) { + case "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction": prepare(childViewController: ShareViewController(itemIdentifiers)) + case "com.nextcloud.desktopclient.FileProviderUIExt.LockFileAction": + prepare(childViewController: LockViewController(itemIdentifiers)) + case "com.nextcloud.desktopclient.FileProviderUIExt.UnlockFileAction": + prepare(childViewController: LockViewController(itemIdentifiers)) + default: + return } - } override func prepare(forError error: Error) { Logger.actionViewController.info( - """ - Preparing for error: \(error.localizedDescription, privacy: .public) - """ + "Preparing for error: \(error.localizedDescription, privacy: .public)" ) } From e3b6cd993575051395b111a6fea9569ce0f5454b Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 17:15:43 +0800 Subject: [PATCH 05/26] Add basic properties to lock view controller Signed-off-by: Claudio Cambra --- .../DocumentActionViewController.swift | 4 ++-- .../Locking/LockViewController.swift | 11 +++++++++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift index d14c3dd3e..dfff3bf34 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/DocumentActionViewController.swift @@ -40,9 +40,9 @@ class DocumentActionViewController: FPUIActionExtensionViewController { case "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction": prepare(childViewController: ShareViewController(itemIdentifiers)) case "com.nextcloud.desktopclient.FileProviderUIExt.LockFileAction": - prepare(childViewController: LockViewController(itemIdentifiers)) + prepare(childViewController: LockViewController(itemIdentifiers, locking: true)) case "com.nextcloud.desktopclient.FileProviderUIExt.UnlockFileAction": - prepare(childViewController: LockViewController(itemIdentifiers)) + prepare(childViewController: LockViewController(itemIdentifiers, locking: false)) default: return } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 99eee3080..71f318715 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -12,5 +12,16 @@ import OSLog import QuickLookThumbnailing class LockViewController: NSViewController { + let itemIdentifiers: [NSFileProviderItemIdentifier] + let locking: Bool + init(_ itemIdentifiers: [NSFileProviderItemIdentifier], locking: Bool) { + self.itemIdentifiers = itemIdentifiers + self.locking = locking + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } } From 10f37d3af1da2e2738ba24e9cc9c13ac67c9cae4 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 17:42:39 +0800 Subject: [PATCH 06/26] Design lock view in file provider ui Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 6 + .../Locking/LockViewController.xib | 107 +++++++++++++++++- 2 files changed, 108 insertions(+), 5 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 71f318715..03a7b184a 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -15,6 +15,12 @@ class LockViewController: NSViewController { let itemIdentifiers: [NSFileProviderItemIdentifier] let locking: Bool + @IBOutlet weak var fileNameIcon: NSImageView! + @IBOutlet weak var fileNameLabel: NSTextField! + @IBOutlet weak var descriptionLabel: NSTextField! + @IBOutlet weak var closeButton: NSButton! + @IBOutlet weak var loadingIndicator: NSProgressIndicator! + init(_ itemIdentifiers: [NSFileProviderItemIdentifier], locking: Bool) { self.itemIdentifiers = itemIdentifiers self.locking = locking diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index 0f40790ec..61843b01c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -3,17 +3,114 @@ + - + + + + + + + + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 4edbb4b50d1b124298d20cfdb33e0fa86c5a6488 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 17:43:39 +0800 Subject: [PATCH 07/26] Add close action to lock view controller Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 8 ++++++++ .../FileProviderUIExt/Locking/LockViewController.xib | 3 +++ 2 files changed, 11 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 03a7b184a..2d7b47357 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -21,6 +21,10 @@ class LockViewController: NSViewController { @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var loadingIndicator: NSProgressIndicator! + var actionViewController: DocumentActionViewController! { + return parent as? DocumentActionViewController + } + init(_ itemIdentifiers: [NSFileProviderItemIdentifier], locking: Bool) { self.itemIdentifiers = itemIdentifiers self.locking = locking @@ -30,4 +34,8 @@ class LockViewController: NSViewController { required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } + + @IBAction func closeAction(_ sender: Any) { + actionViewController.extensionContext.completeRequest() + } } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index 61843b01c..0a583a09c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -80,6 +80,9 @@ + + + From 624b72bd80213d8dee8a4c6bb9cc21da2f5f4bba Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:16:06 +0800 Subject: [PATCH 08/26] Move service connection fetcher method into a utils file Signed-off-by: Claudio Cambra --- .../FileProviderCommunication.swift | 31 +++++++++++++++++++ .../Sharing/ShareTableViewDataSource.swift | 23 ++------------ .../project.pbxproj | 4 +++ 3 files changed, 38 insertions(+), 20 deletions(-) create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/FileProviderCommunication.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/FileProviderCommunication.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/FileProviderCommunication.swift new file mode 100644 index 000000000..111e282dc --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/FileProviderCommunication.swift @@ -0,0 +1,31 @@ +// +// FileProviderCommunication.swift +// FileProviderUIExt +// +// Created by Claudio Cambra on 30/7/24. +// + +import FileProvider + +enum FileProviderCommunicationError: Error { + case serviceNotFound + case remoteProxyObjectInvalid +} + +func serviceConnection( + url: URL, interruptionHandler: @escaping () -> Void +) async throws -> FPUIExtensionService { + let services = try await FileManager().fileProviderServicesForItem(at: url) + guard let service = services[fpUiExtensionServiceName] else { + throw FileProviderCommunicationError.serviceNotFound + } + let connection: NSXPCConnection + connection = try await service.fileProviderConnection() + connection.remoteObjectInterface = NSXPCInterface(with: FPUIExtensionService.self) + connection.interruptionHandler = interruptionHandler + connection.resume() + guard let proxy = connection.remoteObjectProxy as? FPUIExtensionService else { + throw FileProviderCommunicationError.remoteProxyObjectInvalid + } + return proxy +} diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift index 3cca1d1a9..f0d0baf99 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift @@ -84,7 +84,9 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele } do { - let connection = try await serviceConnection(url: itemURL) + let connection = try await serviceConnection(url: itemURL, interruptionHandler: { + Logger.sharesDataSource.error("Service connection interrupted") + }) guard let serverPath = await connection.itemServerPath(identifier: itemIdentifier), let credentials = await connection.credentials() as? Dictionary, let convertedAccount = Account(dictionary: credentials), @@ -118,25 +120,6 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele } } - private func serviceConnection(url: URL) async throws -> FPUIExtensionService { - let services = try await FileManager().fileProviderServicesForItem(at: url) - guard let service = services[fpUiExtensionServiceName] else { - Logger.sharesDataSource.error("Couldn't get service, required service not present") - throw NSFileProviderError(.providerNotFound) - } - let connection: NSXPCConnection - connection = try await service.fileProviderConnection() - connection.remoteObjectInterface = NSXPCInterface(with: FPUIExtensionService.self) - connection.interruptionHandler = { - Logger.sharesDataSource.error("Service connection interrupted") - } - connection.resume() - guard let proxy = connection.remoteObjectProxy as? FPUIExtensionService else { - throw NSFileProviderError(.serverUnreachable) - } - return proxy - } - private func fetch( itemIdentifier: NSFileProviderItemIdentifier, itemRelativePath: String ) async -> [NKShare] { diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index 0a6e23366..ff6aa0624 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 537630982B8612F00026BFAB /* FPUIExtensionService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537630962B860D920026BFAB /* FPUIExtensionService.swift */; }; 537BD67A2C58D67800446ED0 /* LockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD6792C58D67800446ED0 /* LockViewController.swift */; }; 537BD67C2C58D7B700446ED0 /* LockViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537BD67B2C58D7B700446ED0 /* LockViewController.xib */; }; + 537BD6802C58F01B00446ED0 /* FileProviderCommunication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */; }; 538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; }; 538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; }; 538E397627F4765000FA63D5 /* FileProviderExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 538E396727F4765000FA63D5 /* FileProviderExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -167,6 +168,7 @@ 537630962B860D920026BFAB /* FPUIExtensionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionService.swift; sourceTree = ""; }; 537BD6792C58D67800446ED0 /* LockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockViewController.swift; sourceTree = ""; }; 537BD67B2C58D7B700446ED0 /* LockViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LockViewController.xib; sourceTree = ""; }; + 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderCommunication.swift; sourceTree = ""; }; 538E396727F4765000FA63D5 /* FileProviderExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderExt.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = ""; }; @@ -353,6 +355,7 @@ 537BD6782C58D0FC00446ED0 /* Locking */, 537BD6772C58D0C400446ED0 /* Sharing */, 53B979802B84C81F002DA742 /* DocumentActionViewController.swift */, + 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */, 53B979852B84C81F002DA742 /* Info.plist */, ); @@ -725,6 +728,7 @@ 53FE14592B8E3F6C006C4193 /* ShareTableItemView.swift in Sources */, 5376307D2B85E2ED0026BFAB /* Logger+Extensions.swift in Sources */, 53FE14502B8E0658006C4193 /* ShareTableViewDataSource.swift in Sources */, + 537BD6802C58F01B00446ED0 /* FileProviderCommunication.swift in Sources */, 537630982B8612F00026BFAB /* FPUIExtensionService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From 81566eec09746f55b42669b2e089a7d0a841572e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:47:38 +0800 Subject: [PATCH 09/26] Move item metadata fetch into util file in FileProviderUIExt Signed-off-by: Claudio Cambra --- .../Extensions/Logger+Extensions.swift | 1 + .../FileProviderUIExt/MetadataProvider.swift | 45 +++++++++++++++++ .../Sharing/ShareTableViewDataSource.swift | 49 ++++--------------- .../project.pbxproj | 4 ++ 4 files changed, 59 insertions(+), 40 deletions(-) create mode 100644 shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/MetadataProvider.swift diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift index 960171034..64836328b 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift @@ -11,6 +11,7 @@ extension Logger { private static var subsystem = Bundle.main.bundleIdentifier! static let actionViewController = Logger(subsystem: subsystem, category: "actionViewController") + static let metadataProvider = Logger(subsystem: subsystem, category: "metadataProvider") static let shareCapabilities = Logger(subsystem: subsystem, category: "shareCapabilities") static let shareController = Logger(subsystem: subsystem, category: "shareController") static let shareeDataSource = Logger(subsystem: subsystem, category: "shareeDataSource") diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/MetadataProvider.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/MetadataProvider.swift new file mode 100644 index 000000000..890c32065 --- /dev/null +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/MetadataProvider.swift @@ -0,0 +1,45 @@ +// +// MetadataProvider.swift +// FileProviderUIExt +// +// Created by Claudio Cambra on 30/7/24. +// + +import Foundation +import NextcloudKit +import OSLog + +func fetchItemMetadata(itemRelativePath: String, kit: NextcloudKit) async -> NKFile? { + func slashlessPath(_ string: String) -> String { + var strCopy = string + if strCopy.hasPrefix("/") { + strCopy.removeFirst() + } + if strCopy.hasSuffix("/") { + strCopy.removeLast() + } + return strCopy + } + + let nkCommon = kit.nkCommonInstance + let urlBase = slashlessPath(nkCommon.urlBase) + let davSuffix = slashlessPath(nkCommon.dav) + let userId = nkCommon.userId + let itemRelPath = slashlessPath(itemRelativePath) + + let itemFullServerPath = "\(urlBase)/\(davSuffix)/files/\(userId)/\(itemRelPath)" + return await withCheckedContinuation { continuation in + kit.readFileOrFolder(serverUrlFileName: itemFullServerPath, depth: "0") { + account, files, data, error in + guard error == .success else { + Logger.metadataProvider.error( + "Error getting item metadata: \(error.errorDescription)" + ) + continuation.resume(returning: nil) + return + } + Logger.metadataProvider.info("Successfully retrieved item metadata") + continuation.resume(returning: files.first) + } + } +} diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift index f0d0baf99..826711f0c 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift @@ -66,7 +66,14 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele } func reload() async { - guard let itemURL = itemURL else { return } + guard let itemURL else { + presentError("No item URL, cannot reload data!") + return + } + guard let kit else { + presentError("NextcloudKit instance is unavailable, cannot reload data!") + return + } guard let itemIdentifier = await withCheckedContinuation({ (continuation: CheckedContinuation) -> Void in NSFileProviderManager.getIdentifierForUserVisibleFile( @@ -106,7 +113,7 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele presentError("Server does not support shares.") return } - itemMetadata = await fetchItemMetadata(itemRelativePath: serverPathString) + itemMetadata = await fetchItemMetadata(itemRelativePath: serverPathString, kit: kit) guard itemMetadata?.permissions.contains("R") == true else { presentError("This file cannot be shared.") return @@ -163,44 +170,6 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele } } - private func fetchItemMetadata(itemRelativePath: String) async -> NKFile? { - guard let kit = kit else { - presentError("Could not fetch item metadata as NextcloudKit instance is unavailable") - return nil - } - - func slashlessPath(_ string: String) -> String { - var strCopy = string - if strCopy.hasPrefix("/") { - strCopy.removeFirst() - } - if strCopy.hasSuffix("/") { - strCopy.removeLast() - } - return strCopy - } - - let nkCommon = kit.nkCommonInstance - let urlBase = slashlessPath(nkCommon.urlBase) - let davSuffix = slashlessPath(nkCommon.dav) - let userId = nkCommon.userId - let itemRelPath = slashlessPath(itemRelativePath) - - let itemFullServerPath = "\(urlBase)/\(davSuffix)/files/\(userId)/\(itemRelPath)" - return await withCheckedContinuation { continuation in - kit.readFileOrFolder(serverUrlFileName: itemFullServerPath, depth: "0") { - account, files, data, error in - guard error == .success else { - self.presentError("Error getting item metadata: \(error.errorDescription)") - continuation.resume(returning: nil) - return - } - Logger.sharesDataSource.info("Successfully retrieved item metadata") - continuation.resume(returning: files.first) - } - } - } - private func presentError(_ errorString: String) { Logger.sharesDataSource.error("\(errorString, privacy: .public)") Task { @MainActor in self.uiDelegate?.showError(errorString) } diff --git a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj index ff6aa0624..b2613dddd 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj +++ b/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj/project.pbxproj @@ -28,6 +28,7 @@ 537BD67A2C58D67800446ED0 /* LockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD6792C58D67800446ED0 /* LockViewController.swift */; }; 537BD67C2C58D7B700446ED0 /* LockViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537BD67B2C58D7B700446ED0 /* LockViewController.xib */; }; 537BD6802C58F01B00446ED0 /* FileProviderCommunication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */; }; + 537BD6822C58F72E00446ED0 /* MetadataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537BD6812C58F72E00446ED0 /* MetadataProvider.swift */; }; 538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; }; 538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; }; 538E397627F4765000FA63D5 /* FileProviderExt.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 538E396727F4765000FA63D5 /* FileProviderExt.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; @@ -169,6 +170,7 @@ 537BD6792C58D67800446ED0 /* LockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LockViewController.swift; sourceTree = ""; }; 537BD67B2C58D7B700446ED0 /* LockViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = LockViewController.xib; sourceTree = ""; }; 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderCommunication.swift; sourceTree = ""; }; + 537BD6812C58F72E00446ED0 /* MetadataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MetadataProvider.swift; sourceTree = ""; }; 538E396727F4765000FA63D5 /* FileProviderExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderExt.appex; sourceTree = BUILT_PRODUCTS_DIR; }; 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; }; 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = ""; }; @@ -356,6 +358,7 @@ 537BD6772C58D0C400446ED0 /* Sharing */, 53B979802B84C81F002DA742 /* DocumentActionViewController.swift */, 537BD67F2C58F01B00446ED0 /* FileProviderCommunication.swift */, + 537BD6812C58F72E00446ED0 /* MetadataProvider.swift */, 53FE14572B8E3A7C006C4193 /* FileProviderUIExt.entitlements */, 53B979852B84C81F002DA742 /* Info.plist */, ); @@ -717,6 +720,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 537BD6822C58F72E00446ED0 /* MetadataProvider.swift in Sources */, 537630932B85F4B00026BFAB /* ShareViewController.swift in Sources */, 53FE14672B8F78B6006C4193 /* ShareOptionsView.swift in Sources */, 53651E462BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift in Sources */, From 05e5793f062b98e11bac1136146a6b5306ceaa52 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:48:11 +0800 Subject: [PATCH 10/26] Add convenience method to present and log errors in lock view controller Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 2d7b47357..ae113bee7 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -38,4 +38,9 @@ class LockViewController: NSViewController { @IBAction func closeAction(_ sender: Any) { actionViewController.extensionContext.completeRequest() } + + private func presentError(_ error: String) { + Logger.lockViewController.error("Error: \(error, privacy: .public)") + descriptionLabel.stringValue = "Error: \(error)" + } } From fdbc52b83ba251fa213273f4bc5147b3bd73c1fd Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:51:10 +0800 Subject: [PATCH 11/26] Add method to simply provide file details in locking view Signed-off-by: Claudio Cambra --- .../Extensions/Logger+Extensions.swift | 1 + .../Locking/LockViewController.swift | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift index 64836328b..d2e38c3cc 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Extensions/Logger+Extensions.swift @@ -11,6 +11,7 @@ extension Logger { private static var subsystem = Bundle.main.bundleIdentifier! static let actionViewController = Logger(subsystem: subsystem, category: "actionViewController") + static let lockViewController = Logger(subsystem: subsystem, category: "lockViewController") static let metadataProvider = Logger(subsystem: subsystem, category: "metadataProvider") static let shareCapabilities = Logger(subsystem: subsystem, category: "shareCapabilities") static let shareController = Logger(subsystem: subsystem, category: "shareController") diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index ae113bee7..369ac0256 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -43,4 +43,31 @@ class LockViewController: NSViewController { Logger.lockViewController.error("Error: \(error, privacy: .public)") descriptionLabel.stringValue = "Error: \(error)" } + + private func updateFileDetailsDisplay(itemUrl: URL) async { + let lockAction = locking ? "Locking" : "Unlocking" + fileNameLabel.stringValue = "\(lockAction) file \(itemUrl.lastPathComponent)…" + + let request = QLThumbnailGenerator.Request( + fileAt: itemUrl, + size: CGSize(width: 48, height: 48), + scale: 1.0, + representationTypes: .icon + ) + let generator = QLThumbnailGenerator.shared + let fileThumbnail = await withCheckedContinuation { continuation in + generator.generateRepresentations(for: request) { thumbnail, type, error in + if thumbnail == nil || error != nil { + Logger.lockViewController.error( + "Could not get thumbnail: \(error, privacy: .public)" + ) + } + continuation.resume(returning: thumbnail) + } + } + + fileNameIcon.image = + fileThumbnail?.nsImage ?? + NSImage(systemSymbolName: "doc", accessibilityDescription: "doc") + } } From 3b33b2651ba464b069109934c9f9837a1aec04db Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:51:48 +0800 Subject: [PATCH 12/26] Process target item on init of lock view controller Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 369ac0256..4116ff7bc 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -29,6 +29,16 @@ class LockViewController: NSViewController { self.itemIdentifiers = itemIdentifiers self.locking = locking super.init(nibName: nil, bundle: nil) + + guard let firstItem = itemIdentifiers.first else { + Logger.shareViewController.error("called without items") + closeAction(self) + return + } + + Task { + await processItemIdentifier(firstItem) + } } required init?(coder: NSCoder) { @@ -44,6 +54,27 @@ class LockViewController: NSViewController { descriptionLabel.stringValue = "Error: \(error)" } + private func processItemIdentifier(_ itemIdentifier: NSFileProviderItemIdentifier) async { + guard let manager = NSFileProviderManager(for: actionViewController.domain) else { + fatalError("NSFileProviderManager isn't expected to fail") + } + + do { + let itemUrl = try await manager.getUserVisibleURL(for: itemIdentifier) + guard itemUrl.startAccessingSecurityScopedResource() else { + Logger.lockViewController.error("Could not access scoped resource for item url!") + return + } + await updateFileDetailsDisplay(itemUrl: itemUrl) + itemUrl.stopAccessingSecurityScopedResource() + } catch let error { + let errorString = "Error processing item: \(error)" + Logger.lockViewController.error("\(errorString, privacy: .public)") + fileNameLabel.stringValue = "Could not lock unknown item…" + descriptionLabel.stringValue = errorString + } + } + private func updateFileDetailsDisplay(itemUrl: URL) async { let lockAction = locking ? "Locking" : "Unlocking" fileNameLabel.stringValue = "\(lockAction) file \(itemUrl.lastPathComponent)…" From c7d2ed3fcbe172db7900916076dceb66ad44b039 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Tue, 30 Jul 2024 18:52:06 +0800 Subject: [PATCH 13/26] Perform lock/unlock procedure in lock view controller Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 4116ff7bc..0916041f6 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -7,6 +7,7 @@ import AppKit import FileProvider +import NextcloudFileProviderKit import NextcloudKit import OSLog import QuickLookThumbnailing @@ -67,6 +68,7 @@ class LockViewController: NSViewController { } await updateFileDetailsDisplay(itemUrl: itemUrl) itemUrl.stopAccessingSecurityScopedResource() + await lockOrUnlockFile(localItemUrl: itemUrl) } catch let error { let errorString = "Error processing item: \(error)" Logger.lockViewController.error("\(errorString, privacy: .public)") @@ -101,4 +103,88 @@ class LockViewController: NSViewController { fileThumbnail?.nsImage ?? NSImage(systemSymbolName: "doc", accessibilityDescription: "doc") } + + private func lockOrUnlockFile(localItemUrl: URL) async { + descriptionLabel.stringValue = "Fetching file details…" + + guard let itemIdentifier = await withCheckedContinuation({ + (continuation: CheckedContinuation) -> Void in + NSFileProviderManager.getIdentifierForUserVisibleFile( + at: localItemUrl + ) { identifier, domainIdentifier, error in + defer { continuation.resume(returning: identifier) } + guard error == nil else { + self.presentError("No item with identifier: \(error.debugDescription)") + return + } + } + }) else { + presentError("Could not get identifier for item, no shares can be acquired.") + return + } + + do { + let connection = try await serviceConnection(url: localItemUrl, interruptionHandler: { + Logger.lockViewController.error("Service connection interrupted") + }) + guard let serverPath = await connection.itemServerPath(identifier: itemIdentifier), + let credentials = await connection.credentials() as? Dictionary, + let account = Account(dictionary: credentials), + !account.password.isEmpty + else { + presentError("Failed to get details from File Provider Extension.") + return + } + let serverPathString = serverPath as String + let itemServerRelativePath = serverPathString + let kit = NextcloudKit() + kit.setup( + user: account.username, + userId: account.username, + password: account.password, + urlBase: account.serverUrl + ) + // guard let capabilities = await fetchCapabilities() else { + guard let itemMetadata = await fetchItemMetadata( + itemRelativePath: serverPathString, kit: kit + ) else { + presentError("Could not get item metadata.") + return + } + + // Run lock state checks + if locking { + guard !itemMetadata.lock else { + presentError("File is already locked.") + return + } + } else { + guard itemMetadata.lock else { + presentError("File is already unlocked.") + return + } + } + + descriptionLabel.stringValue = + "Communicating with server, \(locking ? "locking" : "unlocking") file…" + + await withCheckedContinuation { continuation in + kit.lockUnlockFile( + serverUrlFileName: itemServerRelativePath, + shouldLock: locking, + completion: { account, error in + if error == .success { + self.descriptionLabel.stringValue = + "File \(self.locking ? "locked" : "unlocked")!" + continuation.resume() + } else { + self.presentError("Could not lock file: \(error).") + } + } + ) + } + } catch let error { + presentError("Could not lock file: \(error).") + } + } } From 65e4297e12b580c7b095752b44a616642028a86e Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 15:15:57 +0800 Subject: [PATCH 14/26] Add convenience function to stop/hide loading indicator in lock view controller Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 0916041f6..cdb341653 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -50,6 +50,11 @@ class LockViewController: NSViewController { actionViewController.extensionContext.completeRequest() } + private func stopIndicatingLoading() { + loadingIndicator.stopAnimation(self) + loadingIndicator.isHidden = true + } + private func presentError(_ error: String) { Logger.lockViewController.error("Error: \(error, privacy: .public)") descriptionLabel.stringValue = "Error: \(error)" From 516fc7cc10c469af88298117178cc480e7541760 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 15:16:08 +0800 Subject: [PATCH 15/26] Stop loading indicator when presenting error Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index cdb341653..d261c0955 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -58,6 +58,7 @@ class LockViewController: NSViewController { private func presentError(_ error: String) { Logger.lockViewController.error("Error: \(error, privacy: .public)") descriptionLabel.stringValue = "Error: \(error)" + stopIndicatingLoading() } private func processItemIdentifier(_ itemIdentifier: NSFileProviderItemIdentifier) async { From d312d009f7547591195fa875ec7c2e8dfcd24489 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 15:16:59 +0800 Subject: [PATCH 16/26] Pull out error handling from completionHandler for nckit lockunlock Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index d261c0955..d170fc26b 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -174,21 +174,20 @@ class LockViewController: NSViewController { descriptionLabel.stringValue = "Communicating with server, \(locking ? "locking" : "unlocking") file…" - await withCheckedContinuation { continuation in + let error = await withCheckedContinuation { continuation in kit.lockUnlockFile( serverUrlFileName: itemServerRelativePath, shouldLock: locking, - completion: { account, error in - if error == .success { - self.descriptionLabel.stringValue = - "File \(self.locking ? "locked" : "unlocked")!" - continuation.resume() - } else { - self.presentError("Could not lock file: \(error).") - } + completion: { _, error in + continuation.resume(returning: error) } ) } + if error == .success { + descriptionLabel.stringValue = "File \(self.locking ? "locked" : "unlocked")!" + } else { + presentError("Could not lock file: \(error.errorDescription).") + } } catch let error { presentError("Could not lock file: \(error).") } From 7ae9f833aa661f63acb3e708b13d26f26127d54d Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 15:17:09 +0800 Subject: [PATCH 17/26] Once finished locking/unlocking, stop loading indicator Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index d170fc26b..3acbfcf17 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -185,6 +185,7 @@ class LockViewController: NSViewController { } if error == .success { descriptionLabel.stringValue = "File \(self.locking ? "locked" : "unlocked")!" + stopIndicatingLoading() } else { presentError("Could not lock file: \(error.errorDescription).") } From f3e341c860d526cc2befde7ee43c49b3aba94145 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 15:33:08 +0800 Subject: [PATCH 18/26] Make sure not to check for kit before we should in shares table view data source Signed-off-by: Claudio Cambra --- .../Sharing/ShareTableViewDataSource.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift index 826711f0c..31d9b578f 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Sharing/ShareTableViewDataSource.swift @@ -70,10 +70,6 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele presentError("No item URL, cannot reload data!") return } - guard let kit else { - presentError("NextcloudKit instance is unavailable, cannot reload data!") - return - } guard let itemIdentifier = await withCheckedContinuation({ (continuation: CheckedContinuation) -> Void in NSFileProviderManager.getIdentifierForUserVisibleFile( @@ -113,6 +109,10 @@ class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDele presentError("Server does not support shares.") return } + guard let kit else { + presentError("NextcloudKit instance is unavailable, cannot reload data!") + return + } itemMetadata = await fetchItemMetadata(itemRelativePath: serverPathString, kit: kit) guard itemMetadata?.permissions.contains("R") == true else { presentError("This file cannot be shared.") From 4dbfbc3d96651e7d4ad0d3d344390707085bf2fc Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 16:55:24 +0800 Subject: [PATCH 19/26] Fix file lock server url in lockviewcontroller Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 3acbfcf17..af24b5ea5 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -142,7 +142,6 @@ class LockViewController: NSViewController { return } let serverPathString = serverPath as String - let itemServerRelativePath = serverPathString let kit = NextcloudKit() kit.setup( user: account.username, @@ -173,10 +172,18 @@ class LockViewController: NSViewController { descriptionLabel.stringValue = "Communicating with server, \(locking ? "locking" : "unlocking") file…" - + + let serverUrlFileName = itemMetadata.serverUrl + "/" + itemMetadata.fileName + Logger.lockViewController.info( + """ + Locking file: \(serverUrlFileName, privacy: .public) + \(self.locking ? "locking" : "unlocking", privacy: .public) + """ + ) + let error = await withCheckedContinuation { continuation in kit.lockUnlockFile( - serverUrlFileName: itemServerRelativePath, + serverUrlFileName: serverUrlFileName, shouldLock: locking, completion: { _, error in continuation.resume(returning: error) From 616ac2e50cc9a9817e9d6c8d0159253e503f8287 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 18:17:54 +0800 Subject: [PATCH 20/26] Fix XIB initialisation in LockViewController Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 21 +++++++++++++++---- .../Locking/LockViewController.xib | 1 + 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index af24b5ea5..4e033740a 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -22,6 +22,10 @@ class LockViewController: NSViewController { @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var loadingIndicator: NSProgressIndicator! + public override var nibName: NSNib.Name? { + return NSNib.Name(self.className) + } + var actionViewController: DocumentActionViewController! { return parent as? DocumentActionViewController } @@ -30,22 +34,31 @@ class LockViewController: NSViewController { self.itemIdentifiers = itemIdentifiers self.locking = locking super.init(nibName: nil, bundle: nil) + } + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { guard let firstItem = itemIdentifiers.first else { Logger.shareViewController.error("called without items") closeAction(self) return } + Logger.lockViewController.info( + """ + Locking \(self.locking ? "enabled" : "disabled", privacy: .public) for items: + \(firstItem.rawValue, privacy: .public) + """ + ) + Task { await processItemIdentifier(firstItem) } } - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - @IBAction func closeAction(_ sender: Any) { actionViewController.extensionContext.completeRequest() } diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index 0a583a09c..33c88d33e 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -14,6 +14,7 @@ + From 4348869684964f9dad443f27a98706f59f887aa0 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Wed, 31 Jul 2024 19:54:02 +0800 Subject: [PATCH 21/26] Fix internal layouting of lock view by simply using a nsview rather than fumbling with a stack view Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.xib | 78 +++++++++---------- 1 file changed, 37 insertions(+), 41 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index 33c88d33e..cf0a91eed 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -14,35 +14,34 @@ - + - - - + + - - + + - - + + - + - - + + - - + + @@ -50,7 +49,7 @@ - + @@ -59,7 +58,10 @@ - + + + + @@ -70,8 +72,8 @@ - - - - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + From 19c9c199a66c83212c1a3d80ae04b75834a77ca9 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Aug 2024 15:32:07 +0800 Subject: [PATCH 22/26] Add warn image to locking view if there is an error Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 2 ++ .../FileProviderUIExt/Locking/LockViewController.xib | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 4e033740a..3b49c097d 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -21,6 +21,7 @@ class LockViewController: NSViewController { @IBOutlet weak var descriptionLabel: NSTextField! @IBOutlet weak var closeButton: NSButton! @IBOutlet weak var loadingIndicator: NSProgressIndicator! + @IBOutlet weak var warnImage: NSImageView! public override var nibName: NSNib.Name? { return NSNib.Name(self.className) @@ -66,6 +67,7 @@ class LockViewController: NSViewController { private func stopIndicatingLoading() { loadingIndicator.stopAnimation(self) loadingIndicator.isHidden = true + warnImage.isHidden = false } private func presentError(_ error: String) { diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib index cf0a91eed..6df0fea32 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.xib @@ -15,6 +15,7 @@ + @@ -29,6 +30,10 @@ + @@ -90,19 +95,23 @@ + + + + @@ -111,6 +120,7 @@ + From 419035c275169d03770e6ff88878c70635f77521 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Aug 2024 15:34:35 +0800 Subject: [PATCH 23/26] Fix NSExtensionFileProviderActionActivationRules for locking menu items Signed-off-by: Claudio Cambra --- .../MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist index 3f843aaed..31930b762 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Info.plist @@ -18,11 +18,11 @@ NSExtensionFileProviderActionName Unlock file NSExtensionFileProviderActionActivationRule - SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo."isUnlockable" == YES ).@count > 0 + SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo.locked != nil && !($fileproviderItem.contentType.identifier UTI-CONFORMS-TO "public.folder") ).@count > 0 NSExtensionFileProviderActionActivationRule - SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo."isLockable" == YES ).@count > 0 + SUBQUERY ( fileproviderItems, $fileproviderItem, $fileproviderItem.userInfo.locked == nil && !($fileproviderItem.contentType.identifier UTI-CONFORMS-TO "public.folder") ).@count > 0 NSExtensionFileProviderActionName Lock file NSExtensionFileProviderActionIdentifier From 7413cf67350afeb5e61a5b4f39f0d62273f11d6c Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Aug 2024 15:59:03 +0800 Subject: [PATCH 24/26] Display checkmark when file lock completed Signed-off-by: Claudio Cambra --- .../FileProviderUIExt/Locking/LockViewController.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index 3b49c097d..d7070fc9d 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -207,6 +207,10 @@ class LockViewController: NSViewController { } if error == .success { descriptionLabel.stringValue = "File \(self.locking ? "locked" : "unlocked")!" + warnImage.image = NSImage( + systemSymbolName: "checkmark.circle.fill", + accessibilityDescription: "checkmark.circle.fill" + ) stopIndicatingLoading() } else { presentError("Could not lock file: \(error.errorDescription).") From 4012d43bb9d505c1148f2543873598b5c42487fa Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Aug 2024 16:21:01 +0800 Subject: [PATCH 25/26] Do not provide items if account is not set up correctly Signed-off-by: Claudio Cambra --- .../FileProviderExt/FileProviderExtension.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift index fd3670a38..db5eda2d5 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderExt/FileProviderExtension.swift @@ -104,7 +104,15 @@ import OSLog request _: NSFileProviderRequest, completionHandler: @escaping (NSFileProviderItem?, Error?) -> Void ) -> Progress { - if let item = Item.storedItem(identifier: identifier, remoteInterface: ncKit) { + if ncAccount == nil { + Logger.fileProviderExtension.error( + """ + Not fetching item for identifier: \(identifier.rawValue, privacy: .public) + as account not set up yet. + """ + ) + completionHandler(nil, NSFileProviderError(.notAuthenticated)) + } else if let item = Item.storedItem(identifier: identifier, remoteInterface: ncKit) { completionHandler(item, nil) } else { completionHandler(nil, NSFileProviderError(.noSuchItem)) From 94a783c48268d02b3f4ccae9fa5b01989caba905 Mon Sep 17 00:00:00 2001 From: Claudio Cambra Date: Thu, 1 Aug 2024 17:36:35 +0800 Subject: [PATCH 26/26] Signal enumeration of locked/unlocked file Signed-off-by: Claudio Cambra --- .../Locking/LockViewController.swift | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift index d7070fc9d..f7347848a 100644 --- a/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift +++ b/shell_integration/MacOSX/NextcloudIntegration/FileProviderUIExt/Locking/LockViewController.swift @@ -212,6 +212,18 @@ class LockViewController: NSViewController { accessibilityDescription: "checkmark.circle.fill" ) stopIndicatingLoading() + if let manager = NSFileProviderManager(for: actionViewController.domain) { + do { + try await manager.signalEnumerator(for: itemIdentifier) + } catch let error { + presentError( + """ + Could not signal lock state change in virtual file. + Changes may take a while to be reflected on your Mac. + Error: \(error.localizedDescription) + """) + } + } } else { presentError("Could not lock file: \(error.errorDescription).") }