mirror of
https://github.com/nextcloud/desktop.git
synced 2024-11-22 21:15:55 +03:00
Merge pull request #6614 from nextcloud/feature/file-provider-sharing
File sharing for macOS VFS (File Provider Module)
This commit is contained in:
commit
3afa861f91
22 changed files with 2392 additions and 5 deletions
|
@ -35,7 +35,20 @@ if(APPLE)
|
||||||
COMMENT building macOS File Provider extension
|
COMMENT building macOS File Provider extension
|
||||||
VERBATIM)
|
VERBATIM)
|
||||||
|
|
||||||
add_dependencies(mac_overlayplugin mac_fileproviderplugin nextcloud) # for the ownCloud.icns to be generated
|
add_custom_target( mac_fileprovideruiplugin ALL
|
||||||
|
xcodebuild ARCHS=${CMAKE_OSX_ARCHITECTURES} ONLY_ACTIVE_ARCH=NO
|
||||||
|
-project ${CMAKE_SOURCE_DIR}/shell_integration/MacOSX/NextcloudIntegration/NextcloudIntegration.xcodeproj
|
||||||
|
-target FileProviderUIExt -configuration ${XCODE_TARGET_CONFIGURATION} "SYMROOT=${CMAKE_CURRENT_BINARY_DIR}"
|
||||||
|
"OC_APPLICATION_EXECUTABLE_NAME=${APPLICATION_EXECUTABLE}"
|
||||||
|
"OC_APPLICATION_VENDOR=${APPLICATION_VENDOR}"
|
||||||
|
"OC_APPLICATION_NAME=${APPLICATION_NAME}"
|
||||||
|
"OC_APPLICATION_REV_DOMAIN=${APPLICATION_REV_DOMAIN}"
|
||||||
|
"OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX=${SOCKETAPI_TEAM_IDENTIFIER_PREFIX}"
|
||||||
|
DEPENDS mac_fileproviderplugin
|
||||||
|
COMMENT building macOS File Provider UI extension
|
||||||
|
VERBATIM)
|
||||||
|
|
||||||
|
add_dependencies(mac_overlayplugin mac_fileproviderplugin mac_fileprovideruiplugin nextcloud) # for the ownCloud.icns to be generated
|
||||||
else()
|
else()
|
||||||
add_dependencies(mac_overlayplugin nextcloud) # for the ownCloud.icns to be generated
|
add_dependencies(mac_overlayplugin nextcloud) # for the ownCloud.icns to be generated
|
||||||
endif()
|
endif()
|
||||||
|
@ -55,6 +68,10 @@ if(APPLE)
|
||||||
install(DIRECTORY ${OSX_PLUGINS_BINARY_DIR}/FileProviderExt.appex
|
install(DIRECTORY ${OSX_PLUGINS_BINARY_DIR}/FileProviderExt.appex
|
||||||
DESTINATION ${OSX_PLUGINS_INSTALL_DIR}
|
DESTINATION ${OSX_PLUGINS_INSTALL_DIR}
|
||||||
USE_SOURCE_PERMISSIONS)
|
USE_SOURCE_PERMISSIONS)
|
||||||
|
|
||||||
|
install(DIRECTORY ${OSX_PLUGINS_BINARY_DIR}/FileProviderUIExt.appex
|
||||||
|
DESTINATION ${OSX_PLUGINS_INSTALL_DIR}
|
||||||
|
USE_SOURCE_PERMISSIONS)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -19,12 +19,15 @@ extension Logger {
|
||||||
|
|
||||||
static let desktopClientConnection = Logger(
|
static let desktopClientConnection = Logger(
|
||||||
subsystem: subsystem, category: "desktopclientconnection")
|
subsystem: subsystem, category: "desktopclientconnection")
|
||||||
|
static let fpUiExtensionService = Logger(subsystem: subsystem, category: "fpUiExtensionService")
|
||||||
static let enumeration = Logger(subsystem: subsystem, category: "enumeration")
|
static let enumeration = Logger(subsystem: subsystem, category: "enumeration")
|
||||||
static let fileProviderExtension = Logger(
|
static let fileProviderExtension = Logger(
|
||||||
subsystem: subsystem, category: "fileproviderextension")
|
subsystem: subsystem, category: "fileproviderextension")
|
||||||
static let fileTransfer = Logger(subsystem: subsystem, category: "filetransfer")
|
static let fileTransfer = Logger(subsystem: subsystem, category: "filetransfer")
|
||||||
static let localFileOps = Logger(subsystem: subsystem, category: "localfileoperations")
|
static let localFileOps = Logger(subsystem: subsystem, category: "localfileoperations")
|
||||||
static let ncFilesDatabase = Logger(subsystem: subsystem, category: "nextcloudfilesdatabase")
|
static let ncFilesDatabase = Logger(subsystem: subsystem, category: "nextcloudfilesdatabase")
|
||||||
|
static let shares = Logger(subsystem: subsystem, category: "shares")
|
||||||
|
static let ncAccount = Logger(subsystem: subsystem, category: "ncAccount")
|
||||||
static let materialisedFileHandling = Logger(
|
static let materialisedFileHandling = Logger(
|
||||||
subsystem: subsystem, category: "materialisedfilehandling"
|
subsystem: subsystem, category: "materialisedfilehandling"
|
||||||
)
|
)
|
||||||
|
|
|
@ -39,7 +39,8 @@ extension FileProviderExtension: NSFileProviderServicing {
|
||||||
) -> Progress {
|
) -> Progress {
|
||||||
Logger.desktopClientConnection.debug("Serving supported service sources")
|
Logger.desktopClientConnection.debug("Serving supported service sources")
|
||||||
let clientCommService = ClientCommunicationService(fpExtension: self)
|
let clientCommService = ClientCommunicationService(fpExtension: self)
|
||||||
let services = [clientCommService]
|
let fpuiExtService = FPUIExtensionServiceSource(fpExtension: self)
|
||||||
|
let services: [NSFileProviderServiceSource] = [clientCommService, fpuiExtService]
|
||||||
completionHandler(services, nil)
|
completionHandler(services, nil)
|
||||||
let progress = Progress()
|
let progress = Progress()
|
||||||
progress.cancellationHandler = {
|
progress.cancellationHandler = {
|
||||||
|
|
|
@ -15,6 +15,12 @@
|
||||||
import FileProvider
|
import FileProvider
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
|
let ncAccountDictUsernameKey = "usernameKey"
|
||||||
|
let ncAccountDictPasswordKey = "passwordKey"
|
||||||
|
let ncAccountDictNcKitAccountKey = "ncKitAccountKey"
|
||||||
|
let ncAccountDictServerUrlKey = "serverUrlKey"
|
||||||
|
let ncAccountDictDavFilesUrlKey = "davFilesUrlKey"
|
||||||
|
|
||||||
struct NextcloudAccount: Equatable {
|
struct NextcloudAccount: Equatable {
|
||||||
static let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
|
static let webDavFilesUrlSuffix: String = "/remote.php/dav/files/"
|
||||||
let username, password, ncKitAccount, serverUrl, davFilesUrl: String
|
let username, password, ncKitAccount, serverUrl, davFilesUrl: String
|
||||||
|
@ -26,4 +32,31 @@ struct NextcloudAccount: Equatable {
|
||||||
self.serverUrl = serverUrl
|
self.serverUrl = serverUrl
|
||||||
davFilesUrl = serverUrl + NextcloudAccount.webDavFilesUrlSuffix + user
|
davFilesUrl = serverUrl + NextcloudAccount.webDavFilesUrlSuffix + user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
init?(dictionary: Dictionary<String, String>) {
|
||||||
|
guard let username = dictionary[ncAccountDictUsernameKey],
|
||||||
|
let password = dictionary[ncAccountDictPasswordKey],
|
||||||
|
let ncKitAccount = dictionary[ncAccountDictNcKitAccountKey],
|
||||||
|
let serverUrl = dictionary[ncAccountDictServerUrlKey],
|
||||||
|
let davFilesUrl = dictionary[ncAccountDictDavFilesUrlKey]
|
||||||
|
else {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
self.username = username
|
||||||
|
self.password = password
|
||||||
|
self.ncKitAccount = ncKitAccount
|
||||||
|
self.serverUrl = serverUrl
|
||||||
|
self.davFilesUrl = davFilesUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
func dictionary() -> Dictionary<String, String> {
|
||||||
|
return [
|
||||||
|
ncAccountDictUsernameKey: username,
|
||||||
|
ncAccountDictPasswordKey: password,
|
||||||
|
ncAccountDictNcKitAccountKey: ncKitAccount,
|
||||||
|
ncAccountDictServerUrlKey: serverUrl,
|
||||||
|
ncAccountDictDavFilesUrlKey: davFilesUrl
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// FPUIExtensionCommunicationProtocol.swift
|
||||||
|
// FileProviderExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 21/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import FileProvider
|
||||||
|
import NextcloudKit
|
||||||
|
|
||||||
|
let fpUiExtensionServiceName = NSFileProviderServiceName(
|
||||||
|
"com.nextcloud.desktopclient.FPUIExtensionService"
|
||||||
|
)
|
||||||
|
|
||||||
|
@objc protocol FPUIExtensionService {
|
||||||
|
func credentials() async -> NSDictionary
|
||||||
|
func itemServerPath(identifier: NSFileProviderItemIdentifier) async -> NSString?
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// FPUIExtensionCommunicationService.swift
|
||||||
|
// FileProviderExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 21/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import FileProvider
|
||||||
|
import Foundation
|
||||||
|
import NextcloudKit
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
class FPUIExtensionServiceSource: NSObject, NSFileProviderServiceSource, NSXPCListenerDelegate, FPUIExtensionService {
|
||||||
|
let listener = NSXPCListener.anonymous()
|
||||||
|
let serviceName = fpUiExtensionServiceName
|
||||||
|
let fpExtension: FileProviderExtension
|
||||||
|
|
||||||
|
init(fpExtension: FileProviderExtension) {
|
||||||
|
Logger.fpUiExtensionService.debug("Instantiating FPUIExtensionService service")
|
||||||
|
self.fpExtension = fpExtension
|
||||||
|
super.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeListenerEndpoint() throws -> NSXPCListenerEndpoint {
|
||||||
|
listener.delegate = self
|
||||||
|
listener.resume()
|
||||||
|
return listener.endpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
func listener(
|
||||||
|
_ listener: NSXPCListener,
|
||||||
|
shouldAcceptNewConnection newConnection: NSXPCConnection
|
||||||
|
) -> Bool {
|
||||||
|
newConnection.exportedInterface = NSXPCInterface(with: FPUIExtensionService.self)
|
||||||
|
newConnection.exportedObject = self
|
||||||
|
newConnection.resume()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: - FPUIExtensionService protocol methods
|
||||||
|
|
||||||
|
func credentials() async -> NSDictionary {
|
||||||
|
return (fpExtension.ncAccount?.dictionary() ?? [:]) as NSDictionary
|
||||||
|
}
|
||||||
|
|
||||||
|
func itemServerPath(identifier: NSFileProviderItemIdentifier) async -> NSString? {
|
||||||
|
let rawIdentifier = identifier.rawValue
|
||||||
|
Logger.shares.info("Fetching shares for item \(rawIdentifier, privacy: .public)")
|
||||||
|
|
||||||
|
guard let baseUrl = fpExtension.ncAccount?.davFilesUrl else {
|
||||||
|
Logger.shares.error("Could not fetch shares as ncAccount on parent extension is nil")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let dbManager = NextcloudFilesDatabaseManager.shared
|
||||||
|
guard let item = dbManager.itemMetadataFromFileProviderItemIdentifier(identifier) else {
|
||||||
|
Logger.shares.error("No item \(rawIdentifier, privacy: .public) in db, no shares.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let completePath = item.serverUrl + "/" + item.fileName
|
||||||
|
return completePath.replacingOccurrences(of: baseUrl, with: "") as NSString
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// DocumentActionViewController.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 20/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import FileProviderUI
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
class DocumentActionViewController: FPUIActionExtensionViewController {
|
||||||
|
var domain: NSFileProviderDomain {
|
||||||
|
guard let identifier = extensionContext.domainIdentifier else {
|
||||||
|
fatalError("not expected to be called with default domain")
|
||||||
|
}
|
||||||
|
return NSFileProviderDomain(
|
||||||
|
identifier: NSFileProviderDomainIdentifier(rawValue: identifier.rawValue),
|
||||||
|
displayName: ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func prepare(childViewController: NSViewController) {
|
||||||
|
addChild(childViewController)
|
||||||
|
view.addSubview(childViewController.view)
|
||||||
|
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
view.leadingAnchor.constraint(equalTo: childViewController.view.leadingAnchor),
|
||||||
|
view.trailingAnchor.constraint(equalTo: childViewController.view.trailingAnchor),
|
||||||
|
view.topAnchor.constraint(equalTo: childViewController.view.topAnchor),
|
||||||
|
view.bottomAnchor.constraint(equalTo: childViewController.view.bottomAnchor)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepare(
|
||||||
|
forAction actionIdentifier: String, itemIdentifiers: [NSFileProviderItemIdentifier]
|
||||||
|
) {
|
||||||
|
Logger.actionViewController.info("Preparing for action: \(actionIdentifier)")
|
||||||
|
|
||||||
|
if actionIdentifier == "com.nextcloud.desktopclient.FileProviderUIExt.ShareAction" {
|
||||||
|
prepare(childViewController: ShareViewController(itemIdentifiers))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepare(forError error: Error) {
|
||||||
|
Logger.actionViewController.info("Preparing for error: \(error.localizedDescription)")
|
||||||
|
}
|
||||||
|
|
||||||
|
override public func loadView() {
|
||||||
|
self.view = NSView()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
//
|
||||||
|
// Logger+Extensions.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 21/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
extension Logger {
|
||||||
|
private static var subsystem = Bundle.main.bundleIdentifier!
|
||||||
|
|
||||||
|
static let actionViewController = Logger(subsystem: subsystem, category: "actionViewController")
|
||||||
|
static let shareCapabilities = Logger(subsystem: subsystem, category: "shareCapabilities")
|
||||||
|
static let shareController = Logger(subsystem: subsystem, category: "shareController")
|
||||||
|
static let shareeDataSource = Logger(subsystem: subsystem, category: "shareeDataSource")
|
||||||
|
static let sharesDataSource = Logger(subsystem: subsystem, category: "sharesDataSource")
|
||||||
|
static let shareOptionsView = Logger(subsystem: subsystem, category: "shareOptionsView")
|
||||||
|
static let shareViewController = Logger(subsystem: subsystem, category: "shareViewController")
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,130 @@
|
||||||
|
//
|
||||||
|
// NKShare+Extensions.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 28/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import NextcloudKit
|
||||||
|
|
||||||
|
extension NKShare {
|
||||||
|
enum ShareType: Int {
|
||||||
|
case user = 0
|
||||||
|
case group = 1
|
||||||
|
case publicLink = 3
|
||||||
|
case email = 4
|
||||||
|
case federatedCloud = 6
|
||||||
|
case circle = 7
|
||||||
|
case talkConversation = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PermissionValues: Int {
|
||||||
|
case readShare = 1
|
||||||
|
case updateShare = 2
|
||||||
|
case createShare = 4
|
||||||
|
case deleteShare = 8
|
||||||
|
case shareShare = 16
|
||||||
|
case all = 31
|
||||||
|
}
|
||||||
|
|
||||||
|
var typeImage: NSImage? {
|
||||||
|
var image: NSImage?
|
||||||
|
switch shareType {
|
||||||
|
case ShareType.user.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "person.circle.fill",
|
||||||
|
accessibilityDescription: "User share icon"
|
||||||
|
)
|
||||||
|
case ShareType.group.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "person.2.circle.fill",
|
||||||
|
accessibilityDescription: "Group share icon"
|
||||||
|
)
|
||||||
|
case ShareType.publicLink.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "link.circle.fill",
|
||||||
|
accessibilityDescription: "Public link share icon"
|
||||||
|
)
|
||||||
|
case ShareType.email.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "envelope.circle.fill",
|
||||||
|
accessibilityDescription: "Email share icon"
|
||||||
|
)
|
||||||
|
case ShareType.federatedCloud.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "cloud.circle.fill",
|
||||||
|
accessibilityDescription: "Federated cloud share icon"
|
||||||
|
)
|
||||||
|
case ShareType.circle.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "circle.circle.fill",
|
||||||
|
accessibilityDescription: "Circle share icon"
|
||||||
|
)
|
||||||
|
case ShareType.talkConversation.rawValue:
|
||||||
|
image = NSImage(
|
||||||
|
systemSymbolName: "message.circle.fill",
|
||||||
|
accessibilityDescription: "Talk conversation share icon"
|
||||||
|
)
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var config = NSImage.SymbolConfiguration(textStyle: .body, scale: .large)
|
||||||
|
if #available(macOS 12.0, *) {
|
||||||
|
config = config.applying(
|
||||||
|
.init(paletteColors: [.controlBackgroundColor, .controlAccentColor])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return image?.withSymbolConfiguration(config)
|
||||||
|
}
|
||||||
|
|
||||||
|
var displayString: String {
|
||||||
|
if label != "" {
|
||||||
|
return label
|
||||||
|
}
|
||||||
|
|
||||||
|
switch shareType {
|
||||||
|
case ShareType.user.rawValue:
|
||||||
|
return "User share (\(shareWith))"
|
||||||
|
case ShareType.group.rawValue:
|
||||||
|
return "Group share (\(shareWith))"
|
||||||
|
case ShareType.publicLink.rawValue:
|
||||||
|
return "Public link share"
|
||||||
|
case ShareType.email.rawValue:
|
||||||
|
return "Email share (\(shareWith))"
|
||||||
|
case ShareType.federatedCloud.rawValue:
|
||||||
|
return "Federated cloud share (\(shareWith))"
|
||||||
|
case ShareType.circle.rawValue:
|
||||||
|
return "Circle share (\(shareWith))"
|
||||||
|
case ShareType.talkConversation.rawValue:
|
||||||
|
return "Talk conversation share (\(shareWith))"
|
||||||
|
default:
|
||||||
|
return "Unknown share"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var expirationDateString: String? {
|
||||||
|
guard let date = expirationDate else { return nil }
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
|
||||||
|
return dateFormatter.string(from: date as Date)
|
||||||
|
}
|
||||||
|
|
||||||
|
var shareesCanEdit: Bool {
|
||||||
|
get { (permissions & PermissionValues.updateShare.rawValue) != 0 }
|
||||||
|
set {
|
||||||
|
if newValue {
|
||||||
|
permissions |= NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
} else {
|
||||||
|
permissions &= ~NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func formattedDateString(date: Date) -> String {
|
||||||
|
let dateFormatter = DateFormatter()
|
||||||
|
dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
|
||||||
|
return dateFormatter.string(from: date)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
|
||||||
|
</array>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>com.apple.security.app-sandbox</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.application-groups</key>
|
||||||
|
<array>
|
||||||
|
<string>$(OC_SOCKETAPI_TEAM_IDENTIFIER_PREFIX)$(OC_APPLICATION_REV_DOMAIN)</string>
|
||||||
|
</array>
|
||||||
|
<key>com.apple.security.network.client</key>
|
||||||
|
<true/>
|
||||||
|
<key>com.apple.security.network.server</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>NSExtension</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionFileProviderActions</key>
|
||||||
|
<array>
|
||||||
|
<dict>
|
||||||
|
<key>NSExtensionFileProviderActionActivationRule</key>
|
||||||
|
<string>TRUEPREDICATE</string>
|
||||||
|
<key>NSExtensionFileProviderActionIdentifier</key>
|
||||||
|
<string>com.nextcloud.desktopclient.FileProviderUIExt.ShareAction</string>
|
||||||
|
<key>NSExtensionFileProviderActionName</key>
|
||||||
|
<string>Share options</string>
|
||||||
|
</dict>
|
||||||
|
</array>
|
||||||
|
<key>NSExtensionPrincipalClass</key>
|
||||||
|
<string>$(PRODUCT_MODULE_NAME).DocumentActionViewController</string>
|
||||||
|
<key>NSExtensionPointIdentifier</key>
|
||||||
|
<string>com.apple.fileprovider-actionsui</string>
|
||||||
|
</dict>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -0,0 +1,131 @@
|
||||||
|
//
|
||||||
|
// ShareController.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 4/3/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import NextcloudKit
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
class ShareController: ObservableObject {
|
||||||
|
@Published private(set) var share: NKShare
|
||||||
|
private let kit: NextcloudKit
|
||||||
|
|
||||||
|
static func create(
|
||||||
|
kit: NextcloudKit,
|
||||||
|
shareType: NKShare.ShareType,
|
||||||
|
itemServerRelativePath: String,
|
||||||
|
shareWith: String?,
|
||||||
|
password: String? = nil,
|
||||||
|
expireDate: String? = nil,
|
||||||
|
permissions: Int = 1,
|
||||||
|
publicUpload: Bool = false,
|
||||||
|
note: String? = nil,
|
||||||
|
label: String? = nil,
|
||||||
|
hideDownload: Bool,
|
||||||
|
attributes: String? = nil,
|
||||||
|
options: NKRequestOptions = NKRequestOptions()
|
||||||
|
) async -> NKError? {
|
||||||
|
Logger.shareController.info("Creating share: \(itemServerRelativePath)")
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
if shareType == .publicLink {
|
||||||
|
kit.createShareLink(
|
||||||
|
path: itemServerRelativePath,
|
||||||
|
hideDownload: hideDownload,
|
||||||
|
publicUpload: publicUpload,
|
||||||
|
password: password,
|
||||||
|
permissions: permissions,
|
||||||
|
options: options
|
||||||
|
) { account, share, data, error in
|
||||||
|
defer { continuation.resume(returning: error) }
|
||||||
|
guard error == .success else {
|
||||||
|
Logger.shareController.error("Error creating link share: \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
guard let shareWith = shareWith else {
|
||||||
|
let errorString = "No recipient for share!"
|
||||||
|
Logger.shareController.error("\(errorString)")
|
||||||
|
let error = NKError(statusCode: 0, fallbackDescription: errorString)
|
||||||
|
continuation.resume(returning: error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
kit.createShare(
|
||||||
|
path: itemServerRelativePath,
|
||||||
|
shareType: shareType.rawValue,
|
||||||
|
shareWith: shareWith,
|
||||||
|
password: password,
|
||||||
|
permissions: permissions,
|
||||||
|
options: options,
|
||||||
|
attributes: attributes
|
||||||
|
) { account, share, data, error in
|
||||||
|
defer { continuation.resume(returning: error) }
|
||||||
|
guard error == .success else {
|
||||||
|
Logger.shareController.error("Error creating share: \(error)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init(share: NKShare, kit: NextcloudKit) {
|
||||||
|
self.share = share
|
||||||
|
self.kit = kit
|
||||||
|
}
|
||||||
|
|
||||||
|
func save(
|
||||||
|
password: String? = nil,
|
||||||
|
expireDate: String? = nil,
|
||||||
|
permissions: Int = 1,
|
||||||
|
publicUpload: Bool = false,
|
||||||
|
note: String? = nil,
|
||||||
|
label: String? = nil,
|
||||||
|
hideDownload: Bool,
|
||||||
|
attributes: String? = nil,
|
||||||
|
options: NKRequestOptions = NKRequestOptions()
|
||||||
|
) async -> NKError? {
|
||||||
|
Logger.shareController.info("Saving share: \(self.share.url)")
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
kit.updateShare(
|
||||||
|
idShare: share.idShare,
|
||||||
|
password: password,
|
||||||
|
expireDate: expireDate,
|
||||||
|
permissions: permissions,
|
||||||
|
publicUpload: publicUpload,
|
||||||
|
note: note,
|
||||||
|
label: label,
|
||||||
|
hideDownload: hideDownload,
|
||||||
|
attributes: attributes,
|
||||||
|
options: options
|
||||||
|
) { account, share, data, error in
|
||||||
|
Logger.shareController.info("Received update response: \(share?.url ?? "")")
|
||||||
|
defer { continuation.resume(returning: error) }
|
||||||
|
guard error == .success, let share = share else {
|
||||||
|
Logger.shareController.error("Error updating save: \(error.errorDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
self.share = share
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func delete() async -> NKError? {
|
||||||
|
Logger.shareController.info("Deleting share: \(self.share.url)")
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
kit.deleteShare(idShare: share.idShare) { account, error in
|
||||||
|
Logger.shareController.info("Received delete response: \(self.share.url)")
|
||||||
|
defer { continuation.resume(returning: error) }
|
||||||
|
guard error == .success else {
|
||||||
|
Logger.shareController.error("Error deleting save: \(error.errorDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,353 @@
|
||||||
|
//
|
||||||
|
// ShareOptionsView.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 28/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import Combine
|
||||||
|
import NextcloudKit
|
||||||
|
import OSLog
|
||||||
|
import SuggestionsTextFieldKit
|
||||||
|
|
||||||
|
class ShareOptionsView: NSView {
|
||||||
|
@IBOutlet private weak var optionsTitleTextField: NSTextField!
|
||||||
|
@IBOutlet private weak var shareRecipientTextField: NSTextField! // Hide if public link share
|
||||||
|
@IBOutlet private weak var labelTextField: NSTextField!
|
||||||
|
@IBOutlet private weak var uploadEditPermissionCheckbox: NSButton!
|
||||||
|
@IBOutlet private weak var hideDownloadCheckbox: NSButton!
|
||||||
|
@IBOutlet private weak var passwordProtectCheckbox: NSButton!
|
||||||
|
@IBOutlet private weak var passwordSecureField: NSSecureTextField!
|
||||||
|
@IBOutlet private weak var expirationDateCheckbox: NSButton!
|
||||||
|
@IBOutlet private weak var expirationDatePicker: NSDatePicker!
|
||||||
|
@IBOutlet private weak var noteForRecipientCheckbox: NSButton!
|
||||||
|
@IBOutlet private weak var noteTextField: NSTextField!
|
||||||
|
@IBOutlet private weak var saveButton: NSButton!
|
||||||
|
@IBOutlet private weak var deleteButton: NSButton!
|
||||||
|
@IBOutlet private weak var shareTypePicker: NSPopUpButton!
|
||||||
|
@IBOutlet private weak var publicLinkShareMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet private weak var userShareMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet private weak var groupShareMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet private weak var emailShareMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet private weak var federatedCloudShareMenuItem: NSMenuItem!
|
||||||
|
@IBOutlet private weak var circleShare: NSMenuItem!
|
||||||
|
@IBOutlet private weak var talkConversationShare: NSMenuItem!
|
||||||
|
|
||||||
|
var kit: NextcloudKit? {
|
||||||
|
didSet {
|
||||||
|
Logger.shareOptionsView.info("Setting up the kit.")
|
||||||
|
guard let kit = kit else {
|
||||||
|
Logger.shareOptionsView.error("Could not configure suggestions data source.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestionsTextFieldDelegate.suggestionsDataSource = ShareeSuggestionsDataSource(
|
||||||
|
kit: kit
|
||||||
|
)
|
||||||
|
suggestionsTextFieldDelegate.confirmationHandler = { suggestion in
|
||||||
|
guard let sharee = suggestion?.data as? NKSharee else { return }
|
||||||
|
self.shareRecipientTextField.stringValue = sharee.shareWith
|
||||||
|
Logger.shareOptionsView.debug("Chose sharee \(sharee.shareWith, privacy: .public)")
|
||||||
|
}
|
||||||
|
suggestionsTextFieldDelegate.targetTextField = shareRecipientTextField
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dataSource: ShareTableViewDataSource?
|
||||||
|
var controller: ShareController? {
|
||||||
|
didSet {
|
||||||
|
guard controller != nil else { return }
|
||||||
|
optionsTitleTextField.stringValue = "Share options"
|
||||||
|
deleteButton.title = "Delete"
|
||||||
|
deleteButton.image = NSImage(
|
||||||
|
systemSymbolName: "trash", accessibilityDescription: "Delete trash icon"
|
||||||
|
)
|
||||||
|
deleteButton.bezelColor = NSColor.systemRed
|
||||||
|
cancellable?.cancel()
|
||||||
|
createMode = false
|
||||||
|
update()
|
||||||
|
cancellable = controller.publisher.sink { _ in self.update() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var createMode = false {
|
||||||
|
didSet {
|
||||||
|
Logger.shareOptionsView.info("Create mode set: \(self.createMode)")
|
||||||
|
shareTypePicker.isHidden = !createMode
|
||||||
|
shareRecipientTextField.isHidden = !createMode
|
||||||
|
labelTextField.isHidden = createMode // Cannot set label on create API call
|
||||||
|
guard createMode else { return }
|
||||||
|
optionsTitleTextField.stringValue = "Create new share"
|
||||||
|
deleteButton.title = "Cancel"
|
||||||
|
deleteButton.image = NSImage(
|
||||||
|
systemSymbolName: "xmark.bin", accessibilityDescription: "Cancel create icon"
|
||||||
|
)
|
||||||
|
deleteButton.bezelColor = NSColor.controlColor
|
||||||
|
cancellable?.cancel()
|
||||||
|
cancellable = nil
|
||||||
|
controller = nil
|
||||||
|
reset()
|
||||||
|
setupCreateForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private var cancellable: AnyCancellable?
|
||||||
|
private var suggestionsWindowController = SuggestionsWindowController()
|
||||||
|
private var suggestionsTextFieldDelegate = SuggestionsTextFieldDelegate()
|
||||||
|
|
||||||
|
private func update() {
|
||||||
|
guard let share = controller?.share else {
|
||||||
|
reset()
|
||||||
|
setAllFields(enabled: false)
|
||||||
|
saveButton.isEnabled = false
|
||||||
|
deleteButton.isEnabled = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteButton.isEnabled = share.canDelete
|
||||||
|
saveButton.isEnabled = share.canEdit
|
||||||
|
|
||||||
|
if share.canEdit {
|
||||||
|
setAllFields(enabled: true)
|
||||||
|
labelTextField.stringValue = share.label
|
||||||
|
uploadEditPermissionCheckbox.state = share.shareesCanEdit ? .on : .off
|
||||||
|
hideDownloadCheckbox.state = share.hideDownload ? .on : .off
|
||||||
|
passwordProtectCheckbox.state = share.password.isEmpty ? .off : .on
|
||||||
|
passwordSecureField.isHidden = passwordProtectCheckbox.state == .off
|
||||||
|
expirationDateCheckbox.state = share.expirationDate == nil ? .off : .on
|
||||||
|
expirationDatePicker.isHidden = expirationDateCheckbox.state == .off
|
||||||
|
noteForRecipientCheckbox.state = share.note.isEmpty ? .off : .on
|
||||||
|
noteTextField.isHidden = noteForRecipientCheckbox.state == .off
|
||||||
|
} else {
|
||||||
|
setAllFields(enabled: false)
|
||||||
|
reset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func reset() {
|
||||||
|
shareRecipientTextField.stringValue = ""
|
||||||
|
labelTextField.stringValue = ""
|
||||||
|
uploadEditPermissionCheckbox.state = .off
|
||||||
|
hideDownloadCheckbox.state = .off
|
||||||
|
passwordProtectCheckbox.state = .off
|
||||||
|
passwordSecureField.isHidden = true
|
||||||
|
passwordSecureField.stringValue = ""
|
||||||
|
expirationDateCheckbox.state = .off
|
||||||
|
expirationDatePicker.isHidden = true
|
||||||
|
expirationDatePicker.dateValue = NSDate.now
|
||||||
|
expirationDatePicker.minDate = NSDate.now
|
||||||
|
expirationDatePicker.maxDate = nil
|
||||||
|
noteForRecipientCheckbox.state = .off
|
||||||
|
noteTextField.isHidden = true
|
||||||
|
noteTextField.stringValue = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setupCreateForm() {
|
||||||
|
guard createMode else { return }
|
||||||
|
|
||||||
|
setAllFields(enabled: true)
|
||||||
|
|
||||||
|
let type = pickedShareType()
|
||||||
|
shareRecipientTextField.isHidden = type == .publicLink
|
||||||
|
|
||||||
|
if let caps = dataSource?.capabilities?.filesSharing {
|
||||||
|
uploadEditPermissionCheckbox.state =
|
||||||
|
caps.defaultPermissions & NKShare.PermissionValues.updateShare.rawValue != 0
|
||||||
|
? .on : .off
|
||||||
|
|
||||||
|
switch type {
|
||||||
|
case .publicLink:
|
||||||
|
passwordProtectCheckbox.isHidden = false
|
||||||
|
passwordProtectCheckbox.state = caps.publicLink?.passwordEnforced == true ? .on : .off
|
||||||
|
passwordProtectCheckbox.isEnabled = caps.publicLink?.passwordEnforced == false
|
||||||
|
expirationDateCheckbox.state = caps.publicLink?.expireDateEnforced == true ? .on : .off
|
||||||
|
expirationDateCheckbox.isEnabled = caps.publicLink?.expireDateEnforced == false
|
||||||
|
expirationDatePicker.dateValue = Date(
|
||||||
|
timeIntervalSinceNow:
|
||||||
|
TimeInterval((caps.publicLink?.expireDateDays ?? 1) * 24 * 60 * 60)
|
||||||
|
)
|
||||||
|
if caps.publicLink?.expireDateEnforced == true {
|
||||||
|
expirationDatePicker.maxDate = expirationDatePicker.dateValue
|
||||||
|
}
|
||||||
|
case .email:
|
||||||
|
passwordProtectCheckbox.isHidden = caps.email?.passwordEnabled == false
|
||||||
|
passwordProtectCheckbox.state = caps.email?.passwordEnforced == true ? .on : .off
|
||||||
|
default:
|
||||||
|
passwordProtectCheckbox.isHidden = true
|
||||||
|
passwordProtectCheckbox.state = .off
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
passwordSecureField.isHidden = passwordProtectCheckbox.state == .off
|
||||||
|
expirationDatePicker.isHidden = expirationDateCheckbox.state == .off
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setAllFields(enabled: Bool) {
|
||||||
|
shareTypePicker.isEnabled = enabled
|
||||||
|
shareRecipientTextField.isEnabled = enabled
|
||||||
|
labelTextField.isEnabled = enabled
|
||||||
|
uploadEditPermissionCheckbox.isEnabled = enabled
|
||||||
|
hideDownloadCheckbox.isEnabled = enabled
|
||||||
|
passwordProtectCheckbox.isEnabled = enabled
|
||||||
|
passwordSecureField.isEnabled = enabled
|
||||||
|
expirationDateCheckbox.isEnabled = enabled
|
||||||
|
expirationDatePicker.isEnabled = enabled
|
||||||
|
noteForRecipientCheckbox.isEnabled = enabled
|
||||||
|
noteTextField.isEnabled = enabled
|
||||||
|
saveButton.isEnabled = enabled
|
||||||
|
deleteButton.isEnabled = enabled
|
||||||
|
}
|
||||||
|
|
||||||
|
private func pickedShareType() -> NKShare.ShareType {
|
||||||
|
let selectedShareTypeItem = shareTypePicker.selectedItem
|
||||||
|
var selectedShareType = NKShare.ShareType.publicLink
|
||||||
|
if selectedShareTypeItem == publicLinkShareMenuItem {
|
||||||
|
selectedShareType = .publicLink
|
||||||
|
} else if selectedShareTypeItem == userShareMenuItem {
|
||||||
|
selectedShareType = .user
|
||||||
|
} else if selectedShareTypeItem == groupShareMenuItem {
|
||||||
|
selectedShareType = .group
|
||||||
|
} else if selectedShareTypeItem == emailShareMenuItem {
|
||||||
|
selectedShareType = .email
|
||||||
|
} else if selectedShareTypeItem == federatedCloudShareMenuItem {
|
||||||
|
selectedShareType = .federatedCloud
|
||||||
|
} else if selectedShareTypeItem == circleShare {
|
||||||
|
selectedShareType = .circle
|
||||||
|
} else if selectedShareTypeItem == talkConversationShare {
|
||||||
|
selectedShareType = .talkConversation
|
||||||
|
}
|
||||||
|
return selectedShareType
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func shareTypePickerAction(_ sender: Any) {
|
||||||
|
if createMode {
|
||||||
|
setupCreateForm()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func passwordCheckboxAction(_ sender: Any) {
|
||||||
|
passwordSecureField.isHidden = passwordProtectCheckbox.state == .off
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func expirationDateCheckboxAction(_ sender: Any) {
|
||||||
|
expirationDatePicker.isHidden = expirationDateCheckbox.state == .off
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func noteForRecipientCheckboxAction(_ sender: Any) {
|
||||||
|
noteTextField.isHidden = noteForRecipientCheckbox.state == .off
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func save(_ sender: Any) {
|
||||||
|
Task { @MainActor in
|
||||||
|
let password = passwordProtectCheckbox.state == .on
|
||||||
|
? passwordSecureField.stringValue
|
||||||
|
: ""
|
||||||
|
let expireDate = expirationDateCheckbox.state == .on
|
||||||
|
? NKShare.formattedDateString(date: expirationDatePicker.dateValue)
|
||||||
|
: ""
|
||||||
|
let note = noteForRecipientCheckbox.state == .on
|
||||||
|
? noteTextField.stringValue
|
||||||
|
: ""
|
||||||
|
let label = labelTextField.stringValue
|
||||||
|
let hideDownload = hideDownloadCheckbox.state == .on
|
||||||
|
let uploadAndEdit = uploadEditPermissionCheckbox.state == .on
|
||||||
|
|
||||||
|
guard !createMode else {
|
||||||
|
Logger.shareOptionsView.info("Creating new share!")
|
||||||
|
|
||||||
|
guard let dataSource = dataSource,
|
||||||
|
let kit = kit,
|
||||||
|
let itemServerRelativePath = dataSource.itemServerRelativePath
|
||||||
|
else {
|
||||||
|
Logger.shareOptionsView.error("Cannot create new share due to missing data.")
|
||||||
|
Logger.shareOptionsView.error("dataSource: \(self.dataSource)")
|
||||||
|
Logger.shareOptionsView.error("kit: \(self.kit)")
|
||||||
|
Logger.shareOptionsView.error(
|
||||||
|
"path: \(self.dataSource?.itemServerRelativePath ?? "")"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let selectedShareType = pickedShareType()
|
||||||
|
let shareWith = shareRecipientTextField.stringValue
|
||||||
|
|
||||||
|
var permissions = NKShare.PermissionValues.all.rawValue
|
||||||
|
permissions = uploadAndEdit
|
||||||
|
? permissions | NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
: permissions & ~NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
|
||||||
|
setAllFields(enabled: false)
|
||||||
|
deleteButton.isEnabled = false
|
||||||
|
saveButton.isEnabled = false
|
||||||
|
let error = await ShareController.create(
|
||||||
|
kit: kit,
|
||||||
|
shareType: selectedShareType,
|
||||||
|
itemServerRelativePath: itemServerRelativePath,
|
||||||
|
shareWith: shareWith,
|
||||||
|
password: password,
|
||||||
|
expireDate: expireDate,
|
||||||
|
permissions: permissions,
|
||||||
|
note: note,
|
||||||
|
label: label,
|
||||||
|
hideDownload: hideDownload
|
||||||
|
)
|
||||||
|
if let error = error, error != .success {
|
||||||
|
dataSource.uiDelegate?.showError("Error creating: \(error.errorDescription)")
|
||||||
|
setAllFields(enabled: true)
|
||||||
|
} else {
|
||||||
|
dataSource.uiDelegate?.hideOptions(self)
|
||||||
|
await dataSource.reload()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.shareOptionsView.info("Editing existing share!")
|
||||||
|
|
||||||
|
guard let controller = controller else {
|
||||||
|
Logger.shareOptionsView.error("No valid share controller, cannot edit share.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let share = controller.share
|
||||||
|
let permissions = uploadAndEdit
|
||||||
|
? share.permissions | NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
: share.permissions & ~NKShare.PermissionValues.updateShare.rawValue
|
||||||
|
|
||||||
|
setAllFields(enabled: false)
|
||||||
|
deleteButton.isEnabled = false
|
||||||
|
saveButton.isEnabled = false
|
||||||
|
let error = await controller.save(
|
||||||
|
password: password,
|
||||||
|
expireDate: expireDate,
|
||||||
|
permissions: permissions,
|
||||||
|
note: note,
|
||||||
|
label: label,
|
||||||
|
hideDownload: hideDownload
|
||||||
|
)
|
||||||
|
if let error = error, error != .success {
|
||||||
|
dataSource?.uiDelegate?.showError("Error updating share: \(error.errorDescription)")
|
||||||
|
setAllFields(enabled: true)
|
||||||
|
} else {
|
||||||
|
dataSource?.uiDelegate?.hideOptions(self)
|
||||||
|
await dataSource?.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func delete(_ sender: Any) {
|
||||||
|
Task { @MainActor in
|
||||||
|
guard !createMode else {
|
||||||
|
dataSource?.uiDelegate?.hideOptions(self)
|
||||||
|
reset()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
setAllFields(enabled: false)
|
||||||
|
deleteButton.isEnabled = false
|
||||||
|
saveButton.isEnabled = false
|
||||||
|
let error = await controller?.delete()
|
||||||
|
if let error = error, error != .success {
|
||||||
|
dataSource?.uiDelegate?.showError("Error deleting share: \(error.errorDescription)")
|
||||||
|
}
|
||||||
|
await dataSource?.reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// ShareTableItemView.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 28/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import NextcloudKit
|
||||||
|
|
||||||
|
class ShareTableItemView: NSTableCellView {
|
||||||
|
@IBOutlet private weak var typeImageView: NSImageView!
|
||||||
|
@IBOutlet private weak var label: NSTextField!
|
||||||
|
@IBOutlet private weak var copyLinkButton: NSButton!
|
||||||
|
private var originalCopyImage: NSImage?
|
||||||
|
private var copiedButtonImage: NSImage?
|
||||||
|
private var tempButtonTimer: Timer?
|
||||||
|
|
||||||
|
var share: NKShare? {
|
||||||
|
didSet {
|
||||||
|
guard let share = share else {
|
||||||
|
prepareForReuse()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
typeImageView.image = share.typeImage
|
||||||
|
label.stringValue = share.displayString
|
||||||
|
copyLinkButton.isHidden = share.shareType != NKShare.ShareType.publicLink.rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
typeImageView.image = nil
|
||||||
|
label.stringValue = ""
|
||||||
|
copyLinkButton.isHidden = false
|
||||||
|
super.prepareForReuse()
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func copyShareLink(sender: Any) {
|
||||||
|
guard let share = share else { return }
|
||||||
|
let pasteboard = NSPasteboard.general
|
||||||
|
pasteboard.declareTypes([.string], owner: nil)
|
||||||
|
pasteboard.setString(share.url, forType: .string)
|
||||||
|
|
||||||
|
guard tempButtonTimer == nil else { return }
|
||||||
|
|
||||||
|
originalCopyImage = copyLinkButton.image
|
||||||
|
copiedButtonImage = NSImage(
|
||||||
|
systemSymbolName: "checkmark.circle.fill",
|
||||||
|
accessibilityDescription: "Public link has been copied icon"
|
||||||
|
)
|
||||||
|
var config = NSImage.SymbolConfiguration(scale: .medium)
|
||||||
|
if #available(macOS 12.0, *) {
|
||||||
|
config = config.applying(.init(hierarchicalColor: .systemGreen))
|
||||||
|
}
|
||||||
|
copiedButtonImage = copiedButtonImage?.withSymbolConfiguration(config)
|
||||||
|
copyLinkButton.image = copiedButtonImage
|
||||||
|
tempButtonTimer = Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { timer in
|
||||||
|
self.copyLinkButton.image = self.originalCopyImage
|
||||||
|
self.copiedButtonImage = nil
|
||||||
|
self.tempButtonTimer?.invalidate()
|
||||||
|
self.tempButtonTimer = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22505" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22505"/>
|
||||||
|
<capability name="Image references" minToolsVersion="12.0"/>
|
||||||
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner"/>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<tableCellView id="WWf-Il-fKw" customClass="ShareTableItemView" customModule="FileProviderUIExt" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="322" height="42"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wdu-Dj-FUn">
|
||||||
|
<rect key="frame" x="5" y="5" width="312" height="32"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="Ex8-CB-iNc">
|
||||||
|
<rect key="frame" x="0.0" y="-5" width="32" height="43"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" secondItem="Ex8-CB-iNc" secondAttribute="height" multiplier="1:1" id="5ak-dc-HzR"/>
|
||||||
|
<constraint firstAttribute="height" constant="32" id="Cus-qI-uen"/>
|
||||||
|
</constraints>
|
||||||
|
<imageCell key="cell" controlSize="large" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" id="0Xf-Au-QjJ">
|
||||||
|
<imageReference key="image" image="link.circle.fill" catalog="system" symbolScale="large"/>
|
||||||
|
</imageCell>
|
||||||
|
<color key="contentTintColor" name="AccentColor"/>
|
||||||
|
</imageView>
|
||||||
|
<textField focusRingType="none" horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="MwZ-er-vB4">
|
||||||
|
<rect key="frame" x="38" y="8" width="236" height="16"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" alignment="left" title="Share link" id="Bcz-ws-5yW">
|
||||||
|
<font key="font" metaFont="systemMedium" size="13"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button horizontalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="y6i-wm-BtQ">
|
||||||
|
<rect key="frame" x="280" y="0.0" width="32" height="32"/>
|
||||||
|
<buttonCell key="cell" type="inline" title="Copy share link" bezelStyle="inline" image="doc.on.doc.fill" catalog="system" imagePosition="only" alignment="center" controlSize="large" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="ram-fe-8Pt">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="smallSystemBold"/>
|
||||||
|
</buttonCell>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" secondItem="y6i-wm-BtQ" secondAttribute="height" multiplier="1:1" id="BlJ-WU-1y5"/>
|
||||||
|
</constraints>
|
||||||
|
<connections>
|
||||||
|
<action selector="copyShareLinkWithSender:" target="WWf-Il-fKw" id="dgW-8v-wfd"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="Ex8-CB-iNc" firstAttribute="top" secondItem="wdu-Dj-FUn" secondAttribute="top" id="2x8-EU-gHs"/>
|
||||||
|
<constraint firstItem="y6i-wm-BtQ" firstAttribute="top" secondItem="wdu-Dj-FUn" secondAttribute="top" id="BjV-lg-nyL"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="Ex8-CB-iNc" secondAttribute="bottom" id="dd0-Vh-Pbi"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="y6i-wm-BtQ" secondAttribute="bottom" id="ha0-oR-OxV"/>
|
||||||
|
<constraint firstItem="MwZ-er-vB4" firstAttribute="centerY" secondItem="Ex8-CB-iNc" secondAttribute="centerY" id="m3A-Tu-qMJ"/>
|
||||||
|
<constraint firstItem="Ex8-CB-iNc" firstAttribute="leading" secondItem="wdu-Dj-FUn" secondAttribute="leading" id="o1t-TB-uhe"/>
|
||||||
|
</constraints>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="wdu-Dj-FUn" firstAttribute="top" secondItem="WWf-Il-fKw" secondAttribute="top" constant="5" id="HIY-8X-dM2"/>
|
||||||
|
<constraint firstItem="wdu-Dj-FUn" firstAttribute="leading" secondItem="WWf-Il-fKw" secondAttribute="leading" constant="5" id="g7a-hl-t5g"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="wdu-Dj-FUn" secondAttribute="bottom" constant="5" id="gAZ-x8-C4K"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="wdu-Dj-FUn" secondAttribute="trailing" constant="5" id="grc-5X-tMi"/>
|
||||||
|
</constraints>
|
||||||
|
<connections>
|
||||||
|
<outlet property="copyLinkButton" destination="y6i-wm-BtQ" id="8bc-yO-Txo"/>
|
||||||
|
<outlet property="label" destination="MwZ-er-vB4" id="Gba-jf-C8H"/>
|
||||||
|
<outlet property="typeImageView" destination="Ex8-CB-iNc" id="T7o-zd-qOo"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="128" y="-22"/>
|
||||||
|
</tableCellView>
|
||||||
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<image name="doc.on.doc.fill" catalog="system" width="17" height="19"/>
|
||||||
|
<image name="link.circle.fill" catalog="system" width="20" height="20"/>
|
||||||
|
<namedColor name="AccentColor">
|
||||||
|
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</namedColor>
|
||||||
|
</resources>
|
||||||
|
</document>
|
|
@ -0,0 +1,254 @@
|
||||||
|
//
|
||||||
|
// ShareTableViewDataSource.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 27/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import FileProvider
|
||||||
|
import NextcloudKit
|
||||||
|
import NextcloudCapabilitiesKit
|
||||||
|
import OSLog
|
||||||
|
|
||||||
|
class ShareTableViewDataSource: NSObject, NSTableViewDataSource, NSTableViewDelegate {
|
||||||
|
private let shareItemViewIdentifier = NSUserInterfaceItemIdentifier("ShareTableItemView")
|
||||||
|
private let shareItemViewNib = NSNib(nibNamed: "ShareTableItemView", bundle: nil)
|
||||||
|
private let reattemptInterval: TimeInterval = 3.0
|
||||||
|
|
||||||
|
var uiDelegate: ShareViewDataSourceUIDelegate?
|
||||||
|
var sharesTableView: NSTableView? {
|
||||||
|
didSet {
|
||||||
|
sharesTableView?.register(shareItemViewNib, forIdentifier: shareItemViewIdentifier)
|
||||||
|
sharesTableView?.rowHeight = 42.0 // Height of view in ShareTableItemView XIB
|
||||||
|
sharesTableView?.dataSource = self
|
||||||
|
sharesTableView?.delegate = self
|
||||||
|
sharesTableView?.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var capabilities: Capabilities?
|
||||||
|
var itemMetadata: NKFile?
|
||||||
|
|
||||||
|
private(set) var kit: NextcloudKit?
|
||||||
|
private(set) var itemURL: URL?
|
||||||
|
private(set) var itemServerRelativePath: String?
|
||||||
|
private(set) var shares: [NKShare] = [] {
|
||||||
|
didSet { Task { @MainActor in sharesTableView?.reloadData() } }
|
||||||
|
}
|
||||||
|
private var account: NextcloudAccount? {
|
||||||
|
didSet {
|
||||||
|
guard let account = account else { return }
|
||||||
|
kit = NextcloudKit()
|
||||||
|
kit?.setup(
|
||||||
|
user: account.username,
|
||||||
|
userId: account.username,
|
||||||
|
password: account.password,
|
||||||
|
urlBase: account.serverUrl
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadItem(url: URL) {
|
||||||
|
itemServerRelativePath = nil
|
||||||
|
itemURL = url
|
||||||
|
Task {
|
||||||
|
await reload()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func reattempt() {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
Timer.scheduledTimer(withTimeInterval: self.reattemptInterval, repeats: false) { _ in
|
||||||
|
Task { await self.reload() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func reload() async {
|
||||||
|
guard let itemURL = itemURL else { return }
|
||||||
|
guard let itemIdentifier = await withCheckedContinuation({
|
||||||
|
(continuation: CheckedContinuation<NSFileProviderItemIdentifier?, Never>) -> Void in
|
||||||
|
NSFileProviderManager.getIdentifierForUserVisibleFile(
|
||||||
|
at: itemURL
|
||||||
|
) { 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: itemURL)
|
||||||
|
guard let serverPath = await connection.itemServerPath(identifier: itemIdentifier),
|
||||||
|
let credentials = await connection.credentials() as? Dictionary<String, String>,
|
||||||
|
let convertedAccount = NextcloudAccount(dictionary: credentials),
|
||||||
|
!convertedAccount.password.isEmpty
|
||||||
|
else {
|
||||||
|
presentError("Failed to get details from File Provider Extension. Retrying.")
|
||||||
|
reattempt()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let serverPathString = serverPath as String
|
||||||
|
itemServerRelativePath = serverPathString
|
||||||
|
account = convertedAccount
|
||||||
|
await sharesTableView?.deselectAll(self)
|
||||||
|
capabilities = await fetchCapabilities()
|
||||||
|
guard capabilities?.filesSharing?.apiEnabled == true else {
|
||||||
|
presentError("Server does not support shares.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
itemMetadata = await fetchItemMetadata(itemRelativePath: serverPathString)
|
||||||
|
guard itemMetadata?.permissions.contains("R") == true else {
|
||||||
|
presentError("This file cannot be shared.")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
shares = await fetch(
|
||||||
|
itemIdentifier: itemIdentifier, itemRelativePath: serverPathString
|
||||||
|
)
|
||||||
|
} catch let error {
|
||||||
|
presentError("Could not reload data: \(error), will try again.")
|
||||||
|
reattempt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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] {
|
||||||
|
Task { @MainActor in uiDelegate?.fetchStarted() }
|
||||||
|
defer { Task { @MainActor in uiDelegate?.fetchFinished() } }
|
||||||
|
|
||||||
|
let rawIdentifier = itemIdentifier.rawValue
|
||||||
|
Logger.sharesDataSource.info("Fetching shares for item \(rawIdentifier, privacy: .public)")
|
||||||
|
|
||||||
|
guard let kit = kit else {
|
||||||
|
self.presentError("NextcloudKit instance is unavailable, cannot fetch shares!")
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
let parameter = NKShareParameter(path: itemRelativePath)
|
||||||
|
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
kit.readShares(parameters: parameter) { account, shares, data, error in
|
||||||
|
let shareCount = shares?.count ?? 0
|
||||||
|
Logger.sharesDataSource.info("Received \(shareCount, privacy: .public) shares")
|
||||||
|
defer { continuation.resume(returning: shares ?? []) }
|
||||||
|
guard error == .success else {
|
||||||
|
self.presentError("Error fetching shares: \(error.errorDescription)")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func fetchCapabilities() async -> Capabilities? {
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
kit?.getCapabilities { account, capabilitiesJson, error in
|
||||||
|
guard error == .success, let capabilitiesJson = capabilitiesJson else {
|
||||||
|
self.presentError("Error getting server caps: \(error.errorDescription)")
|
||||||
|
continuation.resume(returning: nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
Logger.sharesDataSource.info("Successfully retrieved server share capabilities")
|
||||||
|
continuation.resume(returning: Capabilities(data: capabilitiesJson))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - NSTableViewDataSource protocol methods
|
||||||
|
|
||||||
|
@objc func numberOfRows(in tableView: NSTableView) -> Int {
|
||||||
|
shares.count
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - NSTableViewDelegate protocol methods
|
||||||
|
|
||||||
|
@objc func tableView(
|
||||||
|
_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int
|
||||||
|
) -> NSView? {
|
||||||
|
let share = shares[row]
|
||||||
|
guard let view = tableView.makeView(
|
||||||
|
withIdentifier: shareItemViewIdentifier, owner: self
|
||||||
|
) as? ShareTableItemView else {
|
||||||
|
Logger.sharesDataSource.error("Acquired item view from table is not a share item view!")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
view.share = share
|
||||||
|
return view
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func tableViewSelectionDidChange(_ notification: Notification) {
|
||||||
|
guard let selectedRow = sharesTableView?.selectedRow, selectedRow >= 0 else {
|
||||||
|
Task { @MainActor in uiDelegate?.hideOptions(self) }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let share = shares[selectedRow]
|
||||||
|
Task { @MainActor in uiDelegate?.showOptions(share: share) }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,176 @@
|
||||||
|
//
|
||||||
|
// ShareViewController.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 21/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import AppKit
|
||||||
|
import FileProvider
|
||||||
|
import NextcloudKit
|
||||||
|
import OSLog
|
||||||
|
import QuickLookThumbnailing
|
||||||
|
|
||||||
|
class ShareViewController: NSViewController, ShareViewDataSourceUIDelegate {
|
||||||
|
let shareDataSource = ShareTableViewDataSource()
|
||||||
|
let itemIdentifiers: [NSFileProviderItemIdentifier]
|
||||||
|
|
||||||
|
@IBOutlet weak var fileNameIcon: NSImageView!
|
||||||
|
@IBOutlet weak var fileNameLabel: NSTextField!
|
||||||
|
@IBOutlet weak var descriptionLabel: NSTextField!
|
||||||
|
@IBOutlet weak var createButton: NSButton!
|
||||||
|
@IBOutlet weak var closeButton: NSButton!
|
||||||
|
@IBOutlet weak var tableView: NSTableView!
|
||||||
|
@IBOutlet weak var optionsView: ShareOptionsView!
|
||||||
|
@IBOutlet weak var splitView: NSSplitView!
|
||||||
|
@IBOutlet weak var loadingEffectView: NSVisualEffectView!
|
||||||
|
@IBOutlet weak var loadingIndicator: NSProgressIndicator!
|
||||||
|
@IBOutlet weak var errorMessageStackView: NSStackView!
|
||||||
|
@IBOutlet weak var errorTextLabel: NSTextField!
|
||||||
|
@IBOutlet weak var noSharesLabel: NSTextField!
|
||||||
|
|
||||||
|
public override var nibName: NSNib.Name? {
|
||||||
|
return NSNib.Name(self.className)
|
||||||
|
}
|
||||||
|
|
||||||
|
var actionViewController: DocumentActionViewController! {
|
||||||
|
return parent as? DocumentActionViewController
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ itemIdentifiers: [NSFileProviderItemIdentifier]) {
|
||||||
|
self.itemIdentifiers = itemIdentifiers
|
||||||
|
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) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
dismissError(self)
|
||||||
|
hideOptions(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func closeAction(_ sender: Any) {
|
||||||
|
actionViewController.extensionContext.completeRequest()
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
await updateDisplay(itemUrl: itemUrl)
|
||||||
|
shareDataSource.uiDelegate = self
|
||||||
|
shareDataSource.sharesTableView = tableView
|
||||||
|
shareDataSource.loadItem(url: itemUrl)
|
||||||
|
optionsView.dataSource = shareDataSource
|
||||||
|
} catch let error {
|
||||||
|
let errorString = "Error processing item: \(error)"
|
||||||
|
Logger.shareViewController.error("\(errorString)")
|
||||||
|
fileNameLabel.stringValue = "Unknown item"
|
||||||
|
descriptionLabel.stringValue = errorString
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateDisplay(itemUrl: URL) async {
|
||||||
|
fileNameLabel.stringValue = itemUrl.lastPathComponent
|
||||||
|
|
||||||
|
let request = QLThumbnailGenerator.Request(
|
||||||
|
fileAt: itemUrl,
|
||||||
|
size: CGSize(width: 128, height: 128),
|
||||||
|
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.shareViewController.error("Could not get thumbnail: \(error)")
|
||||||
|
}
|
||||||
|
continuation.resume(returning: thumbnail)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fileNameIcon.image = fileThumbnail?.nsImage
|
||||||
|
|
||||||
|
let resourceValues = try? itemUrl.resourceValues(
|
||||||
|
forKeys: [.fileSizeKey, .contentModificationDateKey]
|
||||||
|
)
|
||||||
|
var sizeDesc = "Unknown size"
|
||||||
|
var modDesc = "Unknown modification date"
|
||||||
|
if let fileSize = resourceValues?.fileSize {
|
||||||
|
sizeDesc = ByteCountFormatter().string(fromByteCount: Int64(fileSize))
|
||||||
|
}
|
||||||
|
if let modificationDate = resourceValues?.contentModificationDate {
|
||||||
|
let modDateString = DateFormatter.localizedString(
|
||||||
|
from: modificationDate, dateStyle: .short, timeStyle: .short
|
||||||
|
)
|
||||||
|
modDesc = "Last modified: \(modDateString)"
|
||||||
|
}
|
||||||
|
descriptionLabel.stringValue = "\(sizeDesc) · \(modDesc)"
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func dismissError(_ sender: Any) {
|
||||||
|
errorMessageStackView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func createShare(_ sender: Any) {
|
||||||
|
guard let kit = shareDataSource.kit else { return }
|
||||||
|
optionsView.kit = kit
|
||||||
|
optionsView.createMode = true
|
||||||
|
tableView.deselectAll(self)
|
||||||
|
if !splitView.arrangedSubviews.contains(optionsView) {
|
||||||
|
splitView.addArrangedSubview(optionsView)
|
||||||
|
optionsView.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchStarted() {
|
||||||
|
loadingEffectView.isHidden = false
|
||||||
|
loadingIndicator.startAnimation(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func fetchFinished() {
|
||||||
|
noSharesLabel.isHidden = !shareDataSource.shares.isEmpty
|
||||||
|
loadingEffectView.isHidden = true
|
||||||
|
loadingIndicator.stopAnimation(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func hideOptions(_ sender: Any) {
|
||||||
|
if sender as? ShareTableViewDataSource == shareDataSource, optionsView.createMode {
|
||||||
|
// Do not hide options if the table view has had everything deselected when we set the
|
||||||
|
// options view to be in create mode
|
||||||
|
return
|
||||||
|
}
|
||||||
|
splitView.removeArrangedSubview(optionsView)
|
||||||
|
optionsView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
func showOptions(share: NKShare) {
|
||||||
|
guard let kit = shareDataSource.kit else { return }
|
||||||
|
optionsView.kit = kit
|
||||||
|
optionsView.controller = ShareController(share: share, kit: kit)
|
||||||
|
if !splitView.arrangedSubviews.contains(optionsView) {
|
||||||
|
splitView.addArrangedSubview(optionsView)
|
||||||
|
optionsView.isHidden = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func showError(_ errorString: String) {
|
||||||
|
errorMessageStackView.isHidden = false
|
||||||
|
errorTextLabel.stringValue = errorString
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,532 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22689"/>
|
||||||
|
<capability name="Image references" minToolsVersion="12.0"/>
|
||||||
|
<capability name="Named colors" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="ShareViewController" customModule="FileProviderUIExt" customModuleProvider="target">
|
||||||
|
<connections>
|
||||||
|
<outlet property="closeButton" destination="aDA-n9-Zly" id="niR-Ad-FEa"/>
|
||||||
|
<outlet property="createButton" destination="BMA-BP-wHc" id="HEq-bN-i9V"/>
|
||||||
|
<outlet property="descriptionLabel" destination="gX0-nE-MrU" id="RoY-u1-1on"/>
|
||||||
|
<outlet property="errorMessageStackView" destination="dFs-Gh-2WQ" id="kkQ-Uq-xk7"/>
|
||||||
|
<outlet property="errorTextLabel" destination="770-HW-oC7" id="gfn-SV-TNM"/>
|
||||||
|
<outlet property="fileNameIcon" destination="zSV-DV-Ray" id="336-e0-CEo"/>
|
||||||
|
<outlet property="fileNameLabel" destination="slV-H6-zJ3" id="DPp-sN-Yff"/>
|
||||||
|
<outlet property="loadingEffectView" destination="1ud-mC-gQV" id="HMT-Sb-Axl"/>
|
||||||
|
<outlet property="loadingIndicator" destination="acb-Yu-Zpm" id="9Jf-dE-7LE"/>
|
||||||
|
<outlet property="noSharesLabel" destination="K3D-6U-Cbr" id="zDP-E4-9bg"/>
|
||||||
|
<outlet property="optionsView" destination="EXb-m8-yzj" id="uAb-lv-EZ4"/>
|
||||||
|
<outlet property="splitView" destination="91w-SP-6sl" id="20T-gQ-SPY"/>
|
||||||
|
<outlet property="tableView" destination="vb0-a6-eeH" id="KQo-eg-dba"/>
|
||||||
|
<outlet property="view" destination="Jw6-da-U8j" id="5Ek-F1-w7C"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<view translatesAutoresizingMaskIntoConstraints="NO" id="Jw6-da-U8j">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="500" height="829"/>
|
||||||
|
<subviews>
|
||||||
|
<splitView arrangesAllSubviews="NO" dividerStyle="thin" translatesAutoresizingMaskIntoConstraints="NO" id="91w-SP-6sl">
|
||||||
|
<rect key="frame" x="10" y="10" width="480" height="809"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wGI-UV-bB3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView distribution="fill" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9kj-aB-aJh">
|
||||||
|
<rect key="frame" x="0.0" y="437" width="480" height="43"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="zSV-DV-Ray">
|
||||||
|
<rect key="frame" x="0.0" y="-3.5" width="43" height="50"/>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="width" secondItem="zSV-DV-Ray" secondAttribute="height" multiplier="1:1" id="NSH-gA-7lL"/>
|
||||||
|
</constraints>
|
||||||
|
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyUpOrDown" image="doc" catalog="system" id="laO-OA-5sJ"/>
|
||||||
|
</imageView>
|
||||||
|
<stackView distribution="fill" orientation="vertical" alignment="leading" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oSY-fV-uws">
|
||||||
|
<rect key="frame" x="51" y="0.0" width="375" height="43"/>
|
||||||
|
<subviews>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="slV-H6-zJ3">
|
||||||
|
<rect key="frame" x="-2" y="24" width="78" height="19"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" title="File name" id="Uuo-1j-to8">
|
||||||
|
<font key="font" metaFont="systemBold" size="16"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gX0-nE-MrU">
|
||||||
|
<rect key="frame" x="-2" y="0.0" width="146" height="16"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" title="File size · Last modified" id="1GC-Gr-x29">
|
||||||
|
<font key="font" usesAppearanceFont="YES"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
</subviews>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
<button translatesAutoresizingMaskIntoConstraints="NO" id="BMA-BP-wHc">
|
||||||
|
<rect key="frame" x="434" y="-3.5" width="18.5" height="51"/>
|
||||||
|
<buttonCell key="cell" type="bevel" title="Create share" bezelStyle="regularSquare" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="cdh-AC-lt4">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<imageReference key="image" image="plus" catalog="system" symbolScale="large"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="createShare:" target="-2" id="NLV-ZM-y1w"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button translatesAutoresizingMaskIntoConstraints="NO" id="aDA-n9-Zly">
|
||||||
|
<rect key="frame" x="460" y="-5" width="20" height="54"/>
|
||||||
|
<buttonCell key="cell" type="bevel" title="Close" bezelStyle="rounded" imagePosition="only" alignment="center" imageScaling="proportionallyDown" inset="2" id="zNR-DC-3xZ">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<imageReference key="image" image="xmark.circle.fill" catalog="system" symbolScale="large"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="closeAction:" target="-2" id="D9k-gc-AcN"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="height" constant="43" id="C79-af-CZw"/>
|
||||||
|
<constraint firstItem="oSY-fV-uws" firstAttribute="height" secondItem="9kj-aB-aJh" secondAttribute="height" id="I6w-n6-pgZ"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="BMA-BP-wHc" secondAttribute="bottom" id="RE6-Rg-yv9"/>
|
||||||
|
<constraint firstItem="zSV-DV-Ray" firstAttribute="height" secondItem="9kj-aB-aJh" secondAttribute="height" id="X4V-Vr-Q7m"/>
|
||||||
|
<constraint firstItem="BMA-BP-wHc" firstAttribute="top" secondItem="9kj-aB-aJh" secondAttribute="top" id="hrc-la-YmY"/>
|
||||||
|
<constraint firstItem="aDA-n9-Zly" firstAttribute="height" secondItem="9kj-aB-aJh" secondAttribute="height" id="qCh-8Z-jcN"/>
|
||||||
|
</constraints>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
<stackView distribution="fillProportionally" orientation="horizontal" alignment="top" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" verticalCompressionResistancePriority="1000" detachesHiddenViews="YES" id="dFs-Gh-2WQ">
|
||||||
|
<rect key="frame" x="0.0" y="308" width="480" height="40"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="770-HW-oC7">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="411" height="40"/>
|
||||||
|
<textFieldCell key="cell" selectable="YES" borderStyle="border" alignment="left" title="A long error message that provides detail about why some operations with the shares failed" drawsBackground="YES" id="Jvl-L9-x8K">
|
||||||
|
<font key="font" metaFont="systemSemibold" size="13"/>
|
||||||
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
|
||||||
|
<color key="backgroundColor" name="systemRedColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button translatesAutoresizingMaskIntoConstraints="NO" id="qfq-F1-w0b">
|
||||||
|
<rect key="frame" x="416" y="-4" width="67" height="47"/>
|
||||||
|
<buttonCell key="cell" type="bevel" title="Dismiss" bezelStyle="regularSquare" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="dLP-yX-dyk">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<color key="bezelColor" name="systemRedColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="dismissError:" target="-2" id="qLa-KM-cYK"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="770-HW-oC7" firstAttribute="top" secondItem="dFs-Gh-2WQ" secondAttribute="top" id="2Y8-H2-wTQ"/>
|
||||||
|
<constraint firstItem="qfq-F1-w0b" firstAttribute="centerY" secondItem="dFs-Gh-2WQ" secondAttribute="centerY" id="e6n-1Y-kUh"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="770-HW-oC7" secondAttribute="bottom" id="fHi-My-Qyc"/>
|
||||||
|
</constraints>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
<scrollView autohidesScrollers="YES" horizontalLineScroll="17" horizontalPageScroll="10" verticalLineScroll="17" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZzY-1Z-3xa">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="480" height="300"/>
|
||||||
|
<clipView key="contentView" drawsBackground="NO" id="Ixg-th-Nw0">
|
||||||
|
<rect key="frame" x="1" y="1" width="478" height="298"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" columnReordering="NO" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" typeSelect="NO" rowSizeStyle="automatic" viewBased="YES" id="vb0-a6-eeH">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="478" height="298"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<size key="intercellSpacing" width="17" height="0.0"/>
|
||||||
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<tableColumns>
|
||||||
|
<tableColumn identifier="AutomaticTableColumnIdentifier.0" width="466" minWidth="40" maxWidth="1000" id="3Eb-aD-Ueu">
|
||||||
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||||
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</tableHeaderCell>
|
||||||
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="mEe-4r-5cx">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
|
</tableColumn>
|
||||||
|
</tableColumns>
|
||||||
|
</tableView>
|
||||||
|
</subviews>
|
||||||
|
<nil key="backgroundColor"/>
|
||||||
|
</clipView>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="height" constant="300" id="FAW-Ws-zy7"/>
|
||||||
|
</constraints>
|
||||||
|
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="hQs-hA-bDq">
|
||||||
|
<rect key="frame" x="1" y="284" width="478" height="15"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</scroller>
|
||||||
|
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="ryi-jk-XFM">
|
||||||
|
<rect key="frame" x="224" y="17" width="15" height="102"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</scroller>
|
||||||
|
</scrollView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="ZzY-1Z-3xa" firstAttribute="leading" secondItem="wGI-UV-bB3" secondAttribute="leading" id="528-fv-ZfM"/>
|
||||||
|
<constraint firstItem="9kj-aB-aJh" firstAttribute="top" secondItem="wGI-UV-bB3" secondAttribute="top" id="EOP-84-2ZH"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="ZzY-1Z-3xa" secondAttribute="trailing" id="Kt7-wJ-gb5"/>
|
||||||
|
<constraint firstItem="9kj-aB-aJh" firstAttribute="leading" secondItem="wGI-UV-bB3" secondAttribute="leading" id="UyT-D1-Awv"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="9kj-aB-aJh" secondAttribute="trailing" id="kua-OU-nbq"/>
|
||||||
|
</constraints>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
<view translatesAutoresizingMaskIntoConstraints="NO" id="EXb-m8-yzj" customClass="ShareOptionsView" customModule="FileProviderUIExt" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="481" width="480" height="328"/>
|
||||||
|
<subviews>
|
||||||
|
<stackView distribution="fill" orientation="vertical" alignment="leading" spacing="5" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="T4D-9c-PyA">
|
||||||
|
<rect key="frame" x="10" y="10" width="460" height="308"/>
|
||||||
|
<subviews>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" verticalCompressionResistancePriority="749" translatesAutoresizingMaskIntoConstraints="NO" id="AWy-Qo-wHH">
|
||||||
|
<rect key="frame" x="-2" y="292" width="464" height="16"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="Share options" id="fzf-0v-uHo">
|
||||||
|
<font key="font" metaFont="systemBold"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="aRB-vw-b4r">
|
||||||
|
<rect key="frame" x="-3" y="263" width="467" height="25"/>
|
||||||
|
<popUpButtonCell key="cell" type="push" title="Public link share" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="JhA-rv-1xy" id="S60-Qi-URJ">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="menu"/>
|
||||||
|
<menu key="menu" id="yag-Vc-J7Y">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Public link share" state="on" id="JhA-rv-1xy"/>
|
||||||
|
<menuItem title="User share" id="CpL-qc-lAA"/>
|
||||||
|
<menuItem title="Group share" id="bnp-aV-ZvE"/>
|
||||||
|
<menuItem title="Email share" id="5DB-JD-Ij0">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Federated cloud share" id="RZP-ME-baz">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Circle share" id="yDE-lS-rJZ">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
<menuItem title="Talk conversation share" id="aHo-Mr-vTn">
|
||||||
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
|
</menuItem>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="shareTypePickerAction:" target="EXb-m8-yzj" id="LN7-TC-RvV"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="f8k-Ae-oQc">
|
||||||
|
<rect key="frame" x="0.0" y="240" width="460" height="22"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Share recipient" bezelStyle="round" id="Ahi-gU-lmO">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="CXW-ZO-B2f">
|
||||||
|
<rect key="frame" x="0.0" y="213" width="460" height="22"/>
|
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Share label" bezelStyle="round" id="ZsJ-zc-mFT">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="luZ-Vf-V24">
|
||||||
|
<rect key="frame" x="-2" y="191" width="175" height="18"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Allow upload and editing" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="vOP-1k-c75">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
</button>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="2TN-96-apv">
|
||||||
|
<rect key="frame" x="-2" y="170" width="117" height="18"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Hide download" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="6Eu-NS-uZ7">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
</button>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="ylD-hi-7Oq">
|
||||||
|
<rect key="frame" x="-2" y="149" width="132" height="18"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Password protect" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="MWC-hf-0pc">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="passwordCheckboxAction:" target="EXb-m8-yzj" id="QMn-RM-jdf"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<secureTextField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="pkv-9L-nhv">
|
||||||
|
<rect key="frame" x="0.0" y="123" width="460" height="22"/>
|
||||||
|
<secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Enter a new password" usesSingleLineMode="YES" bezelStyle="round" id="hcA-we-oYG">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<allowedInputSourceLocales>
|
||||||
|
<string>NSAllRomanInputSourcesLocaleIdentifier</string>
|
||||||
|
</allowedInputSourceLocales>
|
||||||
|
</secureTextFieldCell>
|
||||||
|
</secureTextField>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="HaL-4Z-csA">
|
||||||
|
<rect key="frame" x="-2" y="101" width="117" height="18"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Expiration date" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="r1a-iX-8Xo">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="expirationDateCheckboxAction:" target="EXb-m8-yzj" id="KHG-U0-rsG"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<datePicker verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="46m-5F-ME5">
|
||||||
|
<rect key="frame" x="0.0" y="73" width="463" height="28"/>
|
||||||
|
<datePickerCell key="cell" borderStyle="bezel" alignment="left" useCurrentDate="YES" id="EHU-Gu-Dfh">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<date key="date" timeIntervalSinceReferenceDate="734115148.45631897">
|
||||||
|
<!--2024-04-06 16:52:28 +0000-->
|
||||||
|
</date>
|
||||||
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</datePickerCell>
|
||||||
|
</datePicker>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="c10-ub-U31">
|
||||||
|
<rect key="frame" x="-2" y="51" width="132" height="18"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Note for recipient" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="oLA-Nu-fzO">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="noteForRecipientCheckboxAction:" target="EXb-m8-yzj" id="j7a-Tc-uiu"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="io6-Kg-fLl">
|
||||||
|
<rect key="frame" x="0.0" y="25" width="460" height="22"/>
|
||||||
|
<textFieldCell key="cell" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="Note for the recipient" bezelStyle="round" id="z5W-BH-NnM">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<stackView distribution="fillEqually" orientation="horizontal" alignment="bottom" horizontalStackHuggingPriority="249.99998474121094" verticalStackHuggingPriority="249.99998474121094" detachesHiddenViews="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mWb-eX-nfh">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="460" height="20"/>
|
||||||
|
<subviews>
|
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bmf-yY-Y7V">
|
||||||
|
<rect key="frame" x="-7" y="-7" width="240" height="32"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Delete" bezelStyle="rounded" image="trash.fill" catalog="system" imagePosition="leading" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Kb4-Qg-9Ag">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<color key="bezelColor" name="systemRedColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="delete:" target="EXb-m8-yzj" id="PZq-SH-QVa"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button horizontalHuggingPriority="249" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="PaV-TL-cbq">
|
||||||
|
<rect key="frame" x="227" y="-7" width="240" height="32"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Save" bezelStyle="rounded" image="arrow.up.square.fill" catalog="system" imagePosition="trailing" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="O1I-T0-iRC">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<color key="bezelColor" name="AccentColor"/>
|
||||||
|
<connections>
|
||||||
|
<action selector="save:" target="EXb-m8-yzj" id="O4N-dj-SlN"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="46m-5F-ME5" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="5LB-gI-S8e"/>
|
||||||
|
<constraint firstItem="io6-Kg-fLl" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="94h-0I-pw6"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="pkv-9L-nhv" secondAttribute="trailing" id="IFt-uJ-etl"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="CXW-ZO-B2f" secondAttribute="trailing" id="Uvk-cg-D23"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="aRB-vw-b4r" secondAttribute="trailing" id="Zp9-vZ-oxU"/>
|
||||||
|
<constraint firstItem="pkv-9L-nhv" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="bFe-9X-gFR"/>
|
||||||
|
<constraint firstItem="AWy-Qo-wHH" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="dyr-SA-Kmy"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="46m-5F-ME5" secondAttribute="trailing" id="gV6-Jx-VH4"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="mWb-eX-nfh" secondAttribute="bottom" id="iLe-Zw-oO2"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="io6-Kg-fLl" secondAttribute="trailing" id="mkY-UE-SAy"/>
|
||||||
|
<constraint firstItem="AWy-Qo-wHH" firstAttribute="top" secondItem="T4D-9c-PyA" secondAttribute="top" id="ndl-52-MnV"/>
|
||||||
|
<constraint firstItem="CXW-ZO-B2f" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="oWL-JR-HTk"/>
|
||||||
|
<constraint firstItem="mWb-eX-nfh" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="wiX-kw-Ohy"/>
|
||||||
|
<constraint firstItem="aRB-vw-b4r" firstAttribute="leading" secondItem="T4D-9c-PyA" secondAttribute="leading" id="xPY-Ll-QCz"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="mWb-eX-nfh" secondAttribute="trailing" id="yUj-je-uXE"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="AWy-Qo-wHH" secondAttribute="trailing" id="zxC-eX-HrE"/>
|
||||||
|
</constraints>
|
||||||
|
<visibilityPriorities>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
<integer value="1000"/>
|
||||||
|
</visibilityPriorities>
|
||||||
|
<customSpacing>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
<real value="3.4028234663852886e+38"/>
|
||||||
|
</customSpacing>
|
||||||
|
</stackView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="T4D-9c-PyA" firstAttribute="leading" secondItem="EXb-m8-yzj" secondAttribute="leading" constant="10" id="Dhe-wL-ygv"/>
|
||||||
|
<constraint firstItem="T4D-9c-PyA" firstAttribute="top" secondItem="EXb-m8-yzj" secondAttribute="top" constant="10" id="JrC-o6-So3"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="T4D-9c-PyA" secondAttribute="trailing" constant="10" id="gs6-zf-D6h"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="T4D-9c-PyA" secondAttribute="bottom" constant="10" id="r5C-pm-lv4"/>
|
||||||
|
</constraints>
|
||||||
|
<connections>
|
||||||
|
<outlet property="circleShare" destination="yDE-lS-rJZ" id="yHV-25-RJd"/>
|
||||||
|
<outlet property="deleteButton" destination="Bmf-yY-Y7V" id="Wd0-LR-DV5"/>
|
||||||
|
<outlet property="emailShareMenuItem" destination="5DB-JD-Ij0" id="LD5-P8-V2l"/>
|
||||||
|
<outlet property="expirationDateCheckbox" destination="HaL-4Z-csA" id="vIf-I8-e3i"/>
|
||||||
|
<outlet property="expirationDatePicker" destination="46m-5F-ME5" id="eGk-fe-IIf"/>
|
||||||
|
<outlet property="federatedCloudShareMenuItem" destination="RZP-ME-baz" id="quL-N2-y1z"/>
|
||||||
|
<outlet property="groupShareMenuItem" destination="bnp-aV-ZvE" id="8iU-IP-YXK"/>
|
||||||
|
<outlet property="hideDownloadCheckbox" destination="2TN-96-apv" id="OPr-4x-aiK"/>
|
||||||
|
<outlet property="labelTextField" destination="CXW-ZO-B2f" id="otQ-jh-Psr"/>
|
||||||
|
<outlet property="noteForRecipientCheckbox" destination="c10-ub-U31" id="aG6-4P-cBv"/>
|
||||||
|
<outlet property="noteTextField" destination="io6-Kg-fLl" id="JKm-A1-SqR"/>
|
||||||
|
<outlet property="optionsTitleTextField" destination="AWy-Qo-wHH" id="BjX-oW-0Lp"/>
|
||||||
|
<outlet property="passwordProtectCheckbox" destination="ylD-hi-7Oq" id="qdw-aF-uh2"/>
|
||||||
|
<outlet property="passwordSecureField" destination="pkv-9L-nhv" id="992-i5-CPF"/>
|
||||||
|
<outlet property="publicLinkShareMenuItem" destination="JhA-rv-1xy" id="usv-L6-M7k"/>
|
||||||
|
<outlet property="saveButton" destination="PaV-TL-cbq" id="OvF-Le-oQj"/>
|
||||||
|
<outlet property="shareRecipientTextField" destination="f8k-Ae-oQc" id="bfc-Vn-Zu9"/>
|
||||||
|
<outlet property="shareTypePicker" destination="aRB-vw-b4r" id="Dfx-Dw-zEM"/>
|
||||||
|
<outlet property="talkConversationShare" destination="aHo-Mr-vTn" id="hxF-qw-VQO"/>
|
||||||
|
<outlet property="uploadEditPermissionCheckbox" destination="luZ-Vf-V24" id="ojW-WP-98U"/>
|
||||||
|
<outlet property="userShareMenuItem" destination="CpL-qc-lAA" id="R2q-dc-og5"/>
|
||||||
|
</connections>
|
||||||
|
</view>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="EXb-m8-yzj" secondAttribute="trailing" id="9yJ-jE-Iin"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="EXb-m8-yzj" secondAttribute="bottom" id="IDB-la-fxl"/>
|
||||||
|
<constraint firstItem="EXb-m8-yzj" firstAttribute="leading" secondItem="91w-SP-6sl" secondAttribute="leading" id="imf-Yj-oUg"/>
|
||||||
|
</constraints>
|
||||||
|
<holdingPriorities>
|
||||||
|
<real value="250"/>
|
||||||
|
<real value="250"/>
|
||||||
|
</holdingPriorities>
|
||||||
|
</splitView>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="K3D-6U-Cbr">
|
||||||
|
<rect key="frame" x="8" y="474" width="484" height="31"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="clipping" alignment="center" title="No shares" id="byC-34-Vtu">
|
||||||
|
<font key="font" textStyle="largeTitle" name=".SFNS-Regular"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<visualEffectView blendingMode="withinWindow" material="HUDWindow" state="followsWindowActiveState" translatesAutoresizingMaskIntoConstraints="NO" id="1ud-mC-gQV">
|
||||||
|
<rect key="frame" x="10" y="339" width="480" height="300"/>
|
||||||
|
<subviews>
|
||||||
|
<progressIndicator wantsLayer="YES" maxValue="100" indeterminate="YES" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="acb-Yu-Zpm">
|
||||||
|
<rect key="frame" x="224" y="134" width="32" height="32"/>
|
||||||
|
</progressIndicator>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="acb-Yu-Zpm" firstAttribute="centerY" secondItem="1ud-mC-gQV" secondAttribute="centerY" id="Dhf-yv-2Wr"/>
|
||||||
|
<constraint firstItem="acb-Yu-Zpm" firstAttribute="centerX" secondItem="1ud-mC-gQV" secondAttribute="centerX" id="Kzb-iw-xCx"/>
|
||||||
|
</constraints>
|
||||||
|
</visualEffectView>
|
||||||
|
</subviews>
|
||||||
|
<constraints>
|
||||||
|
<constraint firstItem="1ud-mC-gQV" firstAttribute="bottom" secondItem="ZzY-1Z-3xa" secondAttribute="bottom" id="HTR-Xt-ACu"/>
|
||||||
|
<constraint firstItem="1ud-mC-gQV" firstAttribute="top" secondItem="ZzY-1Z-3xa" secondAttribute="top" id="Hjv-Wk-Rk1"/>
|
||||||
|
<constraint firstItem="91w-SP-6sl" firstAttribute="top" secondItem="Jw6-da-U8j" secondAttribute="top" constant="10" id="JFe-jp-e9y"/>
|
||||||
|
<constraint firstAttribute="width" constant="500" id="KBX-aG-ZDU"/>
|
||||||
|
<constraint firstItem="1ud-mC-gQV" firstAttribute="trailing" secondItem="ZzY-1Z-3xa" secondAttribute="trailing" id="Kpk-6o-ao7"/>
|
||||||
|
<constraint firstAttribute="height" relation="greaterThanOrEqual" constant="380" id="LND-hR-7Co"/>
|
||||||
|
<constraint firstAttribute="trailing" secondItem="91w-SP-6sl" secondAttribute="trailing" constant="10" id="XrV-hl-kxC"/>
|
||||||
|
<constraint firstAttribute="bottom" secondItem="91w-SP-6sl" secondAttribute="bottom" constant="10" id="Z4B-85-NR5"/>
|
||||||
|
<constraint firstItem="1ud-mC-gQV" firstAttribute="height" secondItem="ZzY-1Z-3xa" secondAttribute="height" id="dfF-9z-iG9"/>
|
||||||
|
<constraint firstItem="91w-SP-6sl" firstAttribute="leading" secondItem="Jw6-da-U8j" secondAttribute="leading" constant="10" id="elm-Nc-tc0"/>
|
||||||
|
<constraint firstItem="1ud-mC-gQV" firstAttribute="leading" secondItem="ZzY-1Z-3xa" secondAttribute="leading" id="kSz-tV-EFM"/>
|
||||||
|
<constraint firstItem="K3D-6U-Cbr" firstAttribute="leading" secondItem="ZzY-1Z-3xa" secondAttribute="leading" id="lut-va-B3T"/>
|
||||||
|
<constraint firstItem="K3D-6U-Cbr" firstAttribute="trailing" secondItem="ZzY-1Z-3xa" secondAttribute="trailing" id="vRC-IM-ovt"/>
|
||||||
|
<constraint firstItem="K3D-6U-Cbr" firstAttribute="centerY" secondItem="ZzY-1Z-3xa" secondAttribute="centerY" id="wFD-ph-Bsp"/>
|
||||||
|
</constraints>
|
||||||
|
<point key="canvasLocation" x="-270" y="79"/>
|
||||||
|
</view>
|
||||||
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<image name="arrow.up.square.fill" catalog="system" width="15" height="14"/>
|
||||||
|
<image name="doc" catalog="system" width="14" height="16"/>
|
||||||
|
<image name="plus" catalog="system" width="18" height="17"/>
|
||||||
|
<image name="trash.fill" catalog="system" width="15" height="17"/>
|
||||||
|
<image name="xmark.circle.fill" catalog="system" width="20" height="20"/>
|
||||||
|
<namedColor name="AccentColor">
|
||||||
|
<color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
|
</namedColor>
|
||||||
|
</resources>
|
||||||
|
</document>
|
|
@ -0,0 +1,17 @@
|
||||||
|
//
|
||||||
|
// ShareViewDataSourceUIDelegate.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 28/2/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import NextcloudKit
|
||||||
|
|
||||||
|
protocol ShareViewDataSourceUIDelegate {
|
||||||
|
func fetchStarted()
|
||||||
|
func fetchFinished()
|
||||||
|
func hideOptions(_ sender: Any)
|
||||||
|
func showOptions(share: NKShare)
|
||||||
|
func showError(_ errorString: String)
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// ShareeSuggestionsDataSource.swift
|
||||||
|
// FileProviderUIExt
|
||||||
|
//
|
||||||
|
// Created by Claudio Cambra on 2/4/24.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import NextcloudKit
|
||||||
|
import OSLog
|
||||||
|
import SuggestionsTextFieldKit
|
||||||
|
|
||||||
|
class ShareeSuggestionsDataSource: SuggestionsDataSource {
|
||||||
|
let kit: NextcloudKit
|
||||||
|
var suggestions: [Suggestion] = []
|
||||||
|
var inputString: String = "" {
|
||||||
|
didSet { Task { await updateSuggestions() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
init(kit: NextcloudKit) {
|
||||||
|
self.kit = kit
|
||||||
|
}
|
||||||
|
|
||||||
|
private func updateSuggestions() async {
|
||||||
|
let sharees = await fetchSharees(search: inputString)
|
||||||
|
Logger.shareeDataSource.info("Fetched \(sharees.count, privacy: .public) sharees.")
|
||||||
|
suggestions = suggestionsFromSharees(sharees)
|
||||||
|
NotificationCenter.default.post(name: SuggestionsChangedNotificationName, object: self)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func fetchSharees(search: String) async -> [NKSharee] {
|
||||||
|
Logger.shareeDataSource.debug("Searching sharees with: \(search, privacy: .public)")
|
||||||
|
return await withCheckedContinuation { continuation in
|
||||||
|
kit.searchSharees(
|
||||||
|
search: inputString,
|
||||||
|
page: 1,
|
||||||
|
perPage: 20,
|
||||||
|
completion: { account, sharees, data, error in
|
||||||
|
defer { continuation.resume(returning: sharees ?? []) }
|
||||||
|
guard error == .success else {
|
||||||
|
Logger.shareeDataSource.error(
|
||||||
|
"Error fetching sharees: \(error.description, privacy: .public)"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func suggestionsFromSharees(_ sharees: [NKSharee]) -> [Suggestion] {
|
||||||
|
return sharees.map {
|
||||||
|
Suggestion(
|
||||||
|
imageName: "person.fill",
|
||||||
|
displayText: $0.label.isEmpty ? $0.name : $0.label,
|
||||||
|
data: $0
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@
|
||||||
5307A6E82965DAD8001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E72965DAD8001E0C6A /* NextcloudKit */; };
|
5307A6E82965DAD8001E0C6A /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6E72965DAD8001E0C6A /* NextcloudKit */; };
|
||||||
5307A6EB2965DB8D001E0C6A /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6EA2965DB8D001E0C6A /* RealmSwift */; };
|
5307A6EB2965DB8D001E0C6A /* RealmSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 5307A6EA2965DB8D001E0C6A /* RealmSwift */; };
|
||||||
5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */; };
|
5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */; };
|
||||||
|
531522822B8E01C6002E31BE /* ShareTableItemView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 531522812B8E01C6002E31BE /* ShareTableItemView.xib */; };
|
||||||
5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */; };
|
5318AD9129BF42FB00CBB71C /* NextcloudItemMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */; };
|
||||||
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */; };
|
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */; };
|
||||||
5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */; };
|
5318AD9729BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */; };
|
||||||
|
@ -20,9 +21,19 @@
|
||||||
5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */; };
|
5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36729DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift */; };
|
||||||
5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */; };
|
5352B36C29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */; };
|
||||||
5352E85B29B7BFE6002CE85C /* Progress+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */; };
|
5352E85B29B7BFE6002CE85C /* Progress+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */; };
|
||||||
|
5358F2B92BAA0F5300E3C729 /* NextcloudCapabilitiesKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5358F2B82BAA0F5300E3C729 /* NextcloudCapabilitiesKit */; };
|
||||||
535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */; };
|
535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */; };
|
||||||
|
53651E442BBC0CA300ECAC29 /* SuggestionsTextFieldKit in Frameworks */ = {isa = PBXBuildFile; productRef = 53651E432BBC0CA300ECAC29 /* SuggestionsTextFieldKit */; };
|
||||||
|
53651E462BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53651E452BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift */; };
|
||||||
536EFBF7295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */; };
|
536EFBF7295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */; };
|
||||||
536EFC36295E3C1100F4CB13 /* NextcloudAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */; };
|
536EFC36295E3C1100F4CB13 /* NextcloudAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */; };
|
||||||
|
5374FD442B95EE1400C78D54 /* ShareController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5374FD432B95EE1400C78D54 /* ShareController.swift */; };
|
||||||
|
5376307D2B85E2ED0026BFAB /* Logger+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5376307C2B85E2ED0026BFAB /* Logger+Extensions.swift */; };
|
||||||
|
537630912B85F4980026BFAB /* ShareViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 537630902B85F4980026BFAB /* ShareViewController.xib */; };
|
||||||
|
537630932B85F4B00026BFAB /* ShareViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 537630922B85F4B00026BFAB /* ShareViewController.swift */; };
|
||||||
|
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 */; };
|
||||||
538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; };
|
538E396A27F4765000FA63D5 /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 538E396927F4765000FA63D5 /* UniformTypeIdentifiers.framework */; };
|
||||||
538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; };
|
538E396D27F4765000FA63D5 /* FileProviderExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396C27F4765000FA63D5 /* FileProviderExtension.swift */; };
|
||||||
538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396E27F4765000FA63D5 /* FileProviderItem.swift */; };
|
538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 538E396E27F4765000FA63D5 /* FileProviderItem.swift */; };
|
||||||
|
@ -39,11 +50,19 @@
|
||||||
53903D352956184400D0B308 /* LocalSocketClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 539158B127BE891500816F56 /* LocalSocketClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
53903D352956184400D0B308 /* LocalSocketClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 539158B127BE891500816F56 /* LocalSocketClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
53903D37295618A400D0B308 /* LineProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 53903D36295618A400D0B308 /* LineProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
53903D37295618A400D0B308 /* LineProcessor.h in Headers */ = {isa = PBXBuildFile; fileRef = 53903D36295618A400D0B308 /* LineProcessor.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||||
539158AC27BE71A900816F56 /* FinderSyncSocketLineProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */; };
|
539158AC27BE71A900816F56 /* FinderSyncSocketLineProcessor.m in Sources */ = {isa = PBXBuildFile; fileRef = 539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */; };
|
||||||
|
53B979812B84C81F002DA742 /* DocumentActionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53B979802B84C81F002DA742 /* DocumentActionViewController.swift */; };
|
||||||
53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D056302970594F00988392 /* LocalFilesUtils.swift */; };
|
53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D056302970594F00988392 /* LocalFilesUtils.swift */; };
|
||||||
53D666612B70C9A70042C03D /* FileProviderConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D666602B70C9A70042C03D /* FileProviderConfig.swift */; };
|
53D666612B70C9A70042C03D /* FileProviderConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53D666602B70C9A70042C03D /* FileProviderConfig.swift */; };
|
||||||
53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */; };
|
53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */; };
|
||||||
53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */; };
|
53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */; };
|
||||||
53ED473029C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */; };
|
53ED473029C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */; };
|
||||||
|
53FE14502B8E0658006C4193 /* ShareTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */; };
|
||||||
|
53FE14542B8E1219006C4193 /* NextcloudKit in Frameworks */ = {isa = PBXBuildFile; productRef = 53FE14532B8E1219006C4193 /* NextcloudKit */; };
|
||||||
|
53FE14552B8E28E9006C4193 /* NextcloudAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */; };
|
||||||
|
53FE14592B8E3F6C006C4193 /* ShareTableItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */; };
|
||||||
|
53FE145B2B8F1305006C4193 /* NKShare+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */; };
|
||||||
|
53FE14652B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */; };
|
||||||
|
53FE14672B8F78B6006C4193 /* ShareOptionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */; };
|
||||||
C2B573BA1B1CD91E00303B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
|
C2B573BA1B1CD91E00303B36 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
|
||||||
C2B573D21B1CD94B00303B36 /* main.m in Resources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
|
C2B573D21B1CD94B00303B36 /* main.m in Resources */ = {isa = PBXBuildFile; fileRef = C2B573B91B1CD91E00303B36 /* main.m */; };
|
||||||
C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573DD1B1CD9CE00303B36 /* FinderSync.m */; };
|
C2B573DE1B1CD9CE00303B36 /* FinderSync.m in Sources */ = {isa = PBXBuildFile; fileRef = C2B573DD1B1CD9CE00303B36 /* FinderSync.m */; };
|
||||||
|
@ -143,6 +162,7 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudFilesDatabaseManager.swift; sourceTree = "<group>"; };
|
5307A6F129675346001E0C6A /* NextcloudFilesDatabaseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudFilesDatabaseManager.swift; sourceTree = "<group>"; };
|
||||||
|
531522812B8E01C6002E31BE /* ShareTableItemView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ShareTableItemView.xib; sourceTree = "<group>"; };
|
||||||
5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudItemMetadataTable.swift; sourceTree = "<group>"; };
|
5318AD9029BF42FB00CBB71C /* NextcloudItemMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudItemMetadataTable.swift; sourceTree = "<group>"; };
|
||||||
5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = "<group>"; };
|
5318AD9429BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudLocalFileMetadataTable.swift; sourceTree = "<group>"; };
|
||||||
5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = "<group>"; };
|
5318AD9629BF493600CBB71C /* FileProviderMaterialisedEnumerationObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderMaterialisedEnumerationObserver.swift; sourceTree = "<group>"; };
|
||||||
|
@ -155,8 +175,16 @@
|
||||||
5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = "<group>"; };
|
5352B36B29DC44B50011CE03 /* FileProviderExtension+Thumbnailing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+Thumbnailing.swift"; sourceTree = "<group>"; };
|
||||||
5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+Extensions.swift"; sourceTree = "<group>"; };
|
5352E85A29B7BFE6002CE85C /* Progress+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Progress+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
|
535AE30D29C0A2CC0042A9BA /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
53651E452BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareeSuggestionsDataSource.swift; sourceTree = "<group>"; };
|
||||||
536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderSocketLineProcessor.swift; sourceTree = "<group>"; };
|
536EFBF6295CF58100F4CB13 /* FileProviderSocketLineProcessor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderSocketLineProcessor.swift; sourceTree = "<group>"; };
|
||||||
536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudAccount.swift; sourceTree = "<group>"; };
|
536EFC35295E3C1100F4CB13 /* NextcloudAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NextcloudAccount.swift; sourceTree = "<group>"; };
|
||||||
|
5374FD432B95EE1400C78D54 /* ShareController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareController.swift; sourceTree = "<group>"; };
|
||||||
|
5376307C2B85E2ED0026BFAB /* Logger+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Logger+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
5376307E2B85E5650026BFAB /* FileProviderUIExt.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = FileProviderUIExt.entitlements; sourceTree = "<group>"; };
|
||||||
|
537630902B85F4980026BFAB /* ShareViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareViewController.xib; sourceTree = "<group>"; };
|
||||||
|
537630922B85F4B00026BFAB /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = "<group>"; };
|
||||||
|
537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionServiceSource.swift; sourceTree = "<group>"; };
|
||||||
|
537630962B860D920026BFAB /* FPUIExtensionService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUIExtensionService.swift; sourceTree = "<group>"; };
|
||||||
538E396727F4765000FA63D5 /* FileProviderExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderExt.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
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; };
|
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 = "<group>"; };
|
538E396C27F4765000FA63D5 /* FileProviderExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderExtension.swift; sourceTree = "<group>"; };
|
||||||
|
@ -172,11 +200,20 @@
|
||||||
539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FinderSyncSocketLineProcessor.m; sourceTree = "<group>"; };
|
539158AB27BE71A900816F56 /* FinderSyncSocketLineProcessor.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FinderSyncSocketLineProcessor.m; sourceTree = "<group>"; };
|
||||||
539158B127BE891500816F56 /* LocalSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalSocketClient.h; sourceTree = "<group>"; };
|
539158B127BE891500816F56 /* LocalSocketClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LocalSocketClient.h; sourceTree = "<group>"; };
|
||||||
539158B227BEC98A00816F56 /* LocalSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalSocketClient.m; sourceTree = "<group>"; };
|
539158B227BEC98A00816F56 /* LocalSocketClient.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LocalSocketClient.m; sourceTree = "<group>"; };
|
||||||
|
53B9797E2B84C81F002DA742 /* FileProviderUIExt.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = FileProviderUIExt.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
53B979802B84C81F002DA742 /* DocumentActionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentActionViewController.swift; sourceTree = "<group>"; };
|
||||||
|
53B979852B84C81F002DA742 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
53D056302970594F00988392 /* LocalFilesUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFilesUtils.swift; sourceTree = "<group>"; };
|
53D056302970594F00988392 /* LocalFilesUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalFilesUtils.swift; sourceTree = "<group>"; };
|
||||||
53D666602B70C9A70042C03D /* FileProviderConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderConfig.swift; sourceTree = "<group>"; };
|
53D666602B70C9A70042C03D /* FileProviderConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileProviderConfig.swift; sourceTree = "<group>"; };
|
||||||
53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderEnumerator+SyncEngine.swift"; sourceTree = "<group>"; };
|
53ED471F29C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderEnumerator+SyncEngine.swift"; sourceTree = "<group>"; };
|
||||||
53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudItemMetadataTable+NKFile.swift"; sourceTree = "<group>"; };
|
53ED472729C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NextcloudItemMetadataTable+NKFile.swift"; sourceTree = "<group>"; };
|
||||||
53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+ClientInterface.swift"; sourceTree = "<group>"; };
|
53ED472F29C9CE0B00795DB1 /* FileProviderExtension+ClientInterface.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FileProviderExtension+ClientInterface.swift"; sourceTree = "<group>"; };
|
||||||
|
53FE144F2B8E0658006C4193 /* ShareTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableViewDataSource.swift; sourceTree = "<group>"; };
|
||||||
|
53FE14572B8E3A7C006C4193 /* FileProviderUIExtRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = FileProviderUIExtRelease.entitlements; sourceTree = "<group>"; };
|
||||||
|
53FE14582B8E3F6C006C4193 /* ShareTableItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareTableItemView.swift; sourceTree = "<group>"; };
|
||||||
|
53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NKShare+Extensions.swift"; sourceTree = "<group>"; };
|
||||||
|
53FE14642B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewDataSourceUIDelegate.swift; sourceTree = "<group>"; };
|
||||||
|
53FE14662B8F78B6006C4193 /* ShareOptionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareOptionsView.swift; sourceTree = "<group>"; };
|
||||||
C2B573B11B1CD91E00303B36 /* desktopclient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktopclient.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
C2B573B11B1CD91E00303B36 /* desktopclient.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = desktopclient.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
C2B573B51B1CD91E00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
C2B573B51B1CD91E00303B36 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
C2B573B91B1CD91E00303B36 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
|
@ -211,6 +248,16 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
53B9797B2B84C81F002DA742 /* Frameworks */ = {
|
||||||
|
isa = PBXFrameworksBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
5358F2B92BAA0F5300E3C729 /* NextcloudCapabilitiesKit in Frameworks */,
|
||||||
|
53651E442BBC0CA300ECAC29 /* SuggestionsTextFieldKit in Frameworks */,
|
||||||
|
53FE14542B8E1219006C4193 /* NextcloudKit in Frameworks */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
C2B573AE1B1CD91E00303B36 /* Frameworks */ = {
|
C2B573AE1B1CD91E00303B36 /* Frameworks */ = {
|
||||||
isa = PBXFrameworksBuildPhase;
|
isa = PBXFrameworksBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -249,6 +296,8 @@
|
||||||
children = (
|
children = (
|
||||||
5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */,
|
5350E4E72B0C514400F276CB /* ClientCommunicationProtocol.h */,
|
||||||
5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */,
|
5350E4E82B0C534A00F276CB /* ClientCommunicationService.swift */,
|
||||||
|
537630962B860D920026BFAB /* FPUIExtensionService.swift */,
|
||||||
|
537630942B860D560026BFAB /* FPUIExtensionServiceSource.swift */,
|
||||||
);
|
);
|
||||||
path = Services;
|
path = Services;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -263,6 +312,15 @@
|
||||||
path = Extensions;
|
path = Extensions;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
5376307B2B85E2E00026BFAB /* Extensions */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5376307C2B85E2ED0026BFAB /* Logger+Extensions.swift */,
|
||||||
|
53FE145A2B8F1305006C4193 /* NKShare+Extensions.swift */,
|
||||||
|
);
|
||||||
|
path = Extensions;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
538E396827F4765000FA63D5 /* Frameworks */ = {
|
538E396827F4765000FA63D5 /* Frameworks */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -306,12 +364,34 @@
|
||||||
path = NCDesktopClientSocketKit;
|
path = NCDesktopClientSocketKit;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
53B9797F2B84C81F002DA742 /* FileProviderUIExt */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
5376307B2B85E2E00026BFAB /* Extensions */,
|
||||||
|
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 */,
|
||||||
|
5376307E2B85E5650026BFAB /* FileProviderUIExt.entitlements */,
|
||||||
|
53FE14572B8E3A7C006C4193 /* FileProviderUIExtRelease.entitlements */,
|
||||||
|
53B979852B84C81F002DA742 /* Info.plist */,
|
||||||
|
);
|
||||||
|
path = FileProviderUIExt;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
C2B573941B1CD88000303B36 = {
|
C2B573941B1CD88000303B36 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
C2B573B31B1CD91E00303B36 /* desktopclient */,
|
C2B573B31B1CD91E00303B36 /* desktopclient */,
|
||||||
C2B573D81B1CD9CE00303B36 /* FinderSyncExt */,
|
C2B573D81B1CD9CE00303B36 /* FinderSyncExt */,
|
||||||
538E396B27F4765000FA63D5 /* FileProviderExt */,
|
538E396B27F4765000FA63D5 /* FileProviderExt */,
|
||||||
|
53B9797F2B84C81F002DA742 /* FileProviderUIExt */,
|
||||||
53903D0D2956164F00D0B308 /* NCDesktopClientSocketKit */,
|
53903D0D2956164F00D0B308 /* NCDesktopClientSocketKit */,
|
||||||
538E396827F4765000FA63D5 /* Frameworks */,
|
538E396827F4765000FA63D5 /* Frameworks */,
|
||||||
C2B573B21B1CD91E00303B36 /* Products */,
|
C2B573B21B1CD91E00303B36 /* Products */,
|
||||||
|
@ -325,6 +405,7 @@
|
||||||
C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */,
|
C2B573D71B1CD9CE00303B36 /* FinderSyncExt.appex */,
|
||||||
538E396727F4765000FA63D5 /* FileProviderExt.appex */,
|
538E396727F4765000FA63D5 /* FileProviderExt.appex */,
|
||||||
53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */,
|
53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */,
|
||||||
|
53B9797E2B84C81F002DA742 /* FileProviderUIExt.appex */,
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -430,6 +511,29 @@
|
||||||
productReference = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */;
|
productReference = 53903D0C2956164F00D0B308 /* NCDesktopClientSocketKit.framework */;
|
||||||
productType = "com.apple.product-type.framework";
|
productType = "com.apple.product-type.framework";
|
||||||
};
|
};
|
||||||
|
53B9797D2B84C81F002DA742 /* FileProviderUIExt */ = {
|
||||||
|
isa = PBXNativeTarget;
|
||||||
|
buildConfigurationList = 53B979882B84C820002DA742 /* Build configuration list for PBXNativeTarget "FileProviderUIExt" */;
|
||||||
|
buildPhases = (
|
||||||
|
53B9797A2B84C81F002DA742 /* Sources */,
|
||||||
|
53B9797B2B84C81F002DA742 /* Frameworks */,
|
||||||
|
53B9797C2B84C81F002DA742 /* Resources */,
|
||||||
|
);
|
||||||
|
buildRules = (
|
||||||
|
);
|
||||||
|
dependencies = (
|
||||||
|
53FE14522B8E1213006C4193 /* PBXTargetDependency */,
|
||||||
|
);
|
||||||
|
name = FileProviderUIExt;
|
||||||
|
packageProductDependencies = (
|
||||||
|
53FE14532B8E1219006C4193 /* NextcloudKit */,
|
||||||
|
5358F2B82BAA0F5300E3C729 /* NextcloudCapabilitiesKit */,
|
||||||
|
53651E432BBC0CA300ECAC29 /* SuggestionsTextFieldKit */,
|
||||||
|
);
|
||||||
|
productName = FileProviderUIExt;
|
||||||
|
productReference = 53B9797E2B84C81F002DA742 /* FileProviderUIExt.appex */;
|
||||||
|
productType = "com.apple.product-type.app-extension";
|
||||||
|
};
|
||||||
C2B573B01B1CD91E00303B36 /* desktopclient */ = {
|
C2B573B01B1CD91E00303B36 /* desktopclient */ = {
|
||||||
isa = PBXNativeTarget;
|
isa = PBXNativeTarget;
|
||||||
buildConfigurationList = C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */;
|
buildConfigurationList = C2B573CC1B1CD91E00303B36 /* Build configuration list for PBXNativeTarget "desktopclient" */;
|
||||||
|
@ -482,7 +586,7 @@
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
BuildIndependentTargetsInParallel = YES;
|
BuildIndependentTargetsInParallel = YES;
|
||||||
LastSwiftUpdateCheck = 1420;
|
LastSwiftUpdateCheck = 1520;
|
||||||
LastUpgradeCheck = 1240;
|
LastUpgradeCheck = 1240;
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
538E396627F4765000FA63D5 = {
|
538E396627F4765000FA63D5 = {
|
||||||
|
@ -492,6 +596,9 @@
|
||||||
CreatedOnToolsVersion = 14.2;
|
CreatedOnToolsVersion = 14.2;
|
||||||
ProvisioningStyle = Manual;
|
ProvisioningStyle = Manual;
|
||||||
};
|
};
|
||||||
|
53B9797D2B84C81F002DA742 = {
|
||||||
|
CreatedOnToolsVersion = 15.2;
|
||||||
|
};
|
||||||
C2B573B01B1CD91E00303B36 = {
|
C2B573B01B1CD91E00303B36 = {
|
||||||
CreatedOnToolsVersion = 6.3.1;
|
CreatedOnToolsVersion = 6.3.1;
|
||||||
DevelopmentTeam = 9B5WD74GWJ;
|
DevelopmentTeam = 9B5WD74GWJ;
|
||||||
|
@ -522,6 +629,8 @@
|
||||||
packageReferences = (
|
packageReferences = (
|
||||||
5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */,
|
5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */,
|
||||||
5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */,
|
5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */,
|
||||||
|
5358F2B72BAA045E00E3C729 /* XCRemoteSwiftPackageReference "NextcloudCapabilitiesKit" */,
|
||||||
|
53651E422BBC0C7F00ECAC29 /* XCRemoteSwiftPackageReference "SuggestionsTextFieldKit" */,
|
||||||
);
|
);
|
||||||
productRefGroup = C2B573B21B1CD91E00303B36 /* Products */;
|
productRefGroup = C2B573B21B1CD91E00303B36 /* Products */;
|
||||||
projectDirPath = "";
|
projectDirPath = "";
|
||||||
|
@ -530,6 +639,7 @@
|
||||||
C2B573B01B1CD91E00303B36 /* desktopclient */,
|
C2B573B01B1CD91E00303B36 /* desktopclient */,
|
||||||
C2B573D61B1CD9CE00303B36 /* FinderSyncExt */,
|
C2B573D61B1CD9CE00303B36 /* FinderSyncExt */,
|
||||||
538E396627F4765000FA63D5 /* FileProviderExt */,
|
538E396627F4765000FA63D5 /* FileProviderExt */,
|
||||||
|
53B9797D2B84C81F002DA742 /* FileProviderUIExt */,
|
||||||
53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */,
|
53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -550,6 +660,15 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
53B9797C2B84C81F002DA742 /* Resources */ = {
|
||||||
|
isa = PBXResourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
531522822B8E01C6002E31BE /* ShareTableItemView.xib in Resources */,
|
||||||
|
537630912B85F4980026BFAB /* ShareViewController.xib in Resources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
C2B573AF1B1CD91E00303B36 /* Resources */ = {
|
C2B573AF1B1CD91E00303B36 /* Resources */ = {
|
||||||
isa = PBXResourcesBuildPhase;
|
isa = PBXResourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -603,9 +722,11 @@
|
||||||
53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */,
|
53ED472029C5E64200795DB1 /* FileProviderEnumerator+SyncEngine.swift in Sources */,
|
||||||
5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */,
|
5318AD9929BF58D000CBB71C /* NKError+Extensions.swift in Sources */,
|
||||||
53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */,
|
53ED472829C88E7000795DB1 /* NextcloudItemMetadataTable+NKFile.swift in Sources */,
|
||||||
|
537630972B860D920026BFAB /* FPUIExtensionService.swift in Sources */,
|
||||||
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */,
|
5318AD9529BF438F00CBB71C /* NextcloudLocalFileMetadataTable.swift in Sources */,
|
||||||
535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */,
|
535AE30E29C0A2CC0042A9BA /* Logger+Extensions.swift in Sources */,
|
||||||
5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */,
|
5307A6F229675346001E0C6A /* NextcloudFilesDatabaseManager.swift in Sources */,
|
||||||
|
537630952B860D560026BFAB /* FPUIExtensionServiceSource.swift in Sources */,
|
||||||
53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */,
|
53D056312970594F00988392 /* LocalFilesUtils.swift in Sources */,
|
||||||
538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */,
|
538E396F27F4765000FA63D5 /* FileProviderItem.swift in Sources */,
|
||||||
5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */,
|
5352B36829DC17D60011CE03 /* NextcloudFilesDatabaseManager+LocalFiles.swift in Sources */,
|
||||||
|
@ -626,6 +747,25 @@
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
53B9797A2B84C81F002DA742 /* Sources */ = {
|
||||||
|
isa = PBXSourcesBuildPhase;
|
||||||
|
buildActionMask = 2147483647;
|
||||||
|
files = (
|
||||||
|
537630932B85F4B00026BFAB /* ShareViewController.swift in Sources */,
|
||||||
|
53FE14672B8F78B6006C4193 /* ShareOptionsView.swift in Sources */,
|
||||||
|
53651E462BBC0D9500ECAC29 /* ShareeSuggestionsDataSource.swift in Sources */,
|
||||||
|
53FE14652B8F6700006C4193 /* ShareViewDataSourceUIDelegate.swift in Sources */,
|
||||||
|
53B979812B84C81F002DA742 /* DocumentActionViewController.swift in Sources */,
|
||||||
|
5374FD442B95EE1400C78D54 /* ShareController.swift in Sources */,
|
||||||
|
53FE145B2B8F1305006C4193 /* NKShare+Extensions.swift in Sources */,
|
||||||
|
53FE14592B8E3F6C006C4193 /* ShareTableItemView.swift in Sources */,
|
||||||
|
53FE14552B8E28E9006C4193 /* NextcloudAccount.swift in Sources */,
|
||||||
|
5376307D2B85E2ED0026BFAB /* Logger+Extensions.swift in Sources */,
|
||||||
|
53FE14502B8E0658006C4193 /* ShareTableViewDataSource.swift in Sources */,
|
||||||
|
537630982B8612F00026BFAB /* FPUIExtensionService.swift in Sources */,
|
||||||
|
);
|
||||||
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
};
|
||||||
C2B573AD1B1CD91E00303B36 /* Sources */ = {
|
C2B573AD1B1CD91E00303B36 /* Sources */ = {
|
||||||
isa = PBXSourcesBuildPhase;
|
isa = PBXSourcesBuildPhase;
|
||||||
buildActionMask = 2147483647;
|
buildActionMask = 2147483647;
|
||||||
|
@ -666,6 +806,10 @@
|
||||||
target = 53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */;
|
target = 53903D0B2956164F00D0B308 /* NCDesktopClientSocketKit */;
|
||||||
targetProxy = 53903D322956173F00D0B308 /* PBXContainerItemProxy */;
|
targetProxy = 53903D322956173F00D0B308 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
53FE14522B8E1213006C4193 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
productRef = 53FE14512B8E1213006C4193 /* NextcloudKit */;
|
||||||
|
};
|
||||||
C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */ = {
|
C2B573E01B1CD9CE00303B36 /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
target = C2B573D61B1CD9CE00303B36 /* FinderSyncExt */;
|
target = C2B573D61B1CD9CE00303B36 /* FinderSyncExt */;
|
||||||
|
@ -910,6 +1054,130 @@
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
53B979862B84C81F002DA742 /* Debug */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = FileProviderUIExt/FileProviderUIExt.entitlements;
|
||||||
|
CODE_SIGN_STYLE = Automatic;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
|
GCC_PREPROCESSOR_DEFINITIONS = (
|
||||||
|
"DEBUG=1",
|
||||||
|
"$(inherited)",
|
||||||
|
);
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = FileProviderUIExt/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = FileProviderUIExt;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
INFOPLIST_OUTPUT_FORMAT = "same-as-input";
|
||||||
|
INFOPLIST_PREPROCESS = NO;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.2;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
ONLY_ACTIVE_ARCH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = macosx;
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = macOS;
|
||||||
|
};
|
||||||
|
name = Debug;
|
||||||
|
};
|
||||||
|
53B979872B84C81F002DA742 /* Release */ = {
|
||||||
|
isa = XCBuildConfiguration;
|
||||||
|
buildSettings = {
|
||||||
|
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||||
|
ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
|
||||||
|
CLANG_ANALYZER_NONNULL = YES;
|
||||||
|
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
|
||||||
|
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
|
||||||
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_ENABLE_OBJC_ARC = YES;
|
||||||
|
CLANG_ENABLE_OBJC_WEAK = YES;
|
||||||
|
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
|
||||||
|
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
|
||||||
|
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
|
||||||
|
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
|
||||||
|
CODE_SIGN_ENTITLEMENTS = FileProviderUIExt/FileProviderUIExtRelease.entitlements;
|
||||||
|
CODE_SIGN_INJECT_BASE_ENTITLEMENTS = NO;
|
||||||
|
CODE_SIGN_STYLE = Manual;
|
||||||
|
COPY_PHASE_STRIP = NO;
|
||||||
|
CURRENT_PROJECT_VERSION = 1;
|
||||||
|
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||||
|
DEVELOPMENT_TEAM = "";
|
||||||
|
ENABLE_NS_ASSERTIONS = NO;
|
||||||
|
ENABLE_USER_SCRIPT_SANDBOXING = YES;
|
||||||
|
GCC_C_LANGUAGE_STANDARD = gnu17;
|
||||||
|
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
|
||||||
|
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
|
||||||
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
|
INFOPLIST_FILE = FileProviderUIExt/Info.plist;
|
||||||
|
INFOPLIST_KEY_CFBundleDisplayName = FileProviderUIExt;
|
||||||
|
INFOPLIST_KEY_NSHumanReadableCopyright = "";
|
||||||
|
INFOPLIST_OUTPUT_FORMAT = "same-as-input";
|
||||||
|
INFOPLIST_PREPROCESS = NO;
|
||||||
|
IPHONEOS_DEPLOYMENT_TARGET = 17.2;
|
||||||
|
LD_RUNPATH_SEARCH_PATHS = (
|
||||||
|
"$(inherited)",
|
||||||
|
"@executable_path/Frameworks",
|
||||||
|
"@executable_path/../../Frameworks",
|
||||||
|
);
|
||||||
|
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
|
||||||
|
MACOSX_DEPLOYMENT_TARGET = 11.0;
|
||||||
|
MARKETING_VERSION = 1.0;
|
||||||
|
MTL_ENABLE_DEBUG_INFO = NO;
|
||||||
|
MTL_FAST_MATH = YES;
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "$(OC_APPLICATION_REV_DOMAIN).$(PRODUCT_NAME)";
|
||||||
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
SDKROOT = macosx;
|
||||||
|
SKIP_INSTALL = YES;
|
||||||
|
SUPPORTED_PLATFORMS = macosx;
|
||||||
|
SUPPORTS_MACCATALYST = NO;
|
||||||
|
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||||
|
SWIFT_COMPILATION_MODE = wholemodule;
|
||||||
|
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||||
|
SWIFT_VERSION = 5.0;
|
||||||
|
TARGETED_DEVICE_FAMILY = macOS;
|
||||||
|
VALIDATE_PRODUCT = YES;
|
||||||
|
};
|
||||||
|
name = Release;
|
||||||
|
};
|
||||||
C2B573991B1CD88000303B36 /* Debug */ = {
|
C2B573991B1CD88000303B36 /* Debug */ = {
|
||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
|
@ -1216,6 +1484,15 @@
|
||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
|
53B979882B84C820002DA742 /* Build configuration list for PBXNativeTarget "FileProviderUIExt" */ = {
|
||||||
|
isa = XCConfigurationList;
|
||||||
|
buildConfigurations = (
|
||||||
|
53B979862B84C81F002DA742 /* Debug */,
|
||||||
|
53B979872B84C81F002DA742 /* Release */,
|
||||||
|
);
|
||||||
|
defaultConfigurationIsVisible = 0;
|
||||||
|
defaultConfigurationName = Release;
|
||||||
|
};
|
||||||
C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "NextcloudIntegration" */ = {
|
C2B573981B1CD88000303B36 /* Build configuration list for PBXProject "NextcloudIntegration" */ = {
|
||||||
isa = XCConfigurationList;
|
isa = XCConfigurationList;
|
||||||
buildConfigurations = (
|
buildConfigurations = (
|
||||||
|
@ -1250,8 +1527,8 @@
|
||||||
isa = XCRemoteSwiftPackageReference;
|
isa = XCRemoteSwiftPackageReference;
|
||||||
repositoryURL = "https://github.com/nextcloud/NextcloudKit.git";
|
repositoryURL = "https://github.com/nextcloud/NextcloudKit.git";
|
||||||
requirement = {
|
requirement = {
|
||||||
branch = develop;
|
kind = upToNextMajorVersion;
|
||||||
kind = branch;
|
minimumVersion = 2.5.9;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */ = {
|
5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */ = {
|
||||||
|
@ -1262,6 +1539,22 @@
|
||||||
version = 10.33.0;
|
version = 10.33.0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
5358F2B72BAA045E00E3C729 /* XCRemoteSwiftPackageReference "NextcloudCapabilitiesKit" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/claucambra/NextcloudCapabilitiesKit.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 2.0.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
53651E422BBC0C7F00ECAC29 /* XCRemoteSwiftPackageReference "SuggestionsTextFieldKit" */ = {
|
||||||
|
isa = XCRemoteSwiftPackageReference;
|
||||||
|
repositoryURL = "https://github.com/claucambra/SuggestionsTextFieldKit.git";
|
||||||
|
requirement = {
|
||||||
|
kind = upToNextMajorVersion;
|
||||||
|
minimumVersion = 1.0.0;
|
||||||
|
};
|
||||||
|
};
|
||||||
/* End XCRemoteSwiftPackageReference section */
|
/* End XCRemoteSwiftPackageReference section */
|
||||||
|
|
||||||
/* Begin XCSwiftPackageProductDependency section */
|
/* Begin XCSwiftPackageProductDependency section */
|
||||||
|
@ -1280,6 +1573,26 @@
|
||||||
package = 5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */;
|
package = 5307A6E92965DB57001E0C6A /* XCRemoteSwiftPackageReference "realm-swift" */;
|
||||||
productName = RealmSwift;
|
productName = RealmSwift;
|
||||||
};
|
};
|
||||||
|
5358F2B82BAA0F5300E3C729 /* NextcloudCapabilitiesKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 5358F2B72BAA045E00E3C729 /* XCRemoteSwiftPackageReference "NextcloudCapabilitiesKit" */;
|
||||||
|
productName = NextcloudCapabilitiesKit;
|
||||||
|
};
|
||||||
|
53651E432BBC0CA300ECAC29 /* SuggestionsTextFieldKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 53651E422BBC0C7F00ECAC29 /* XCRemoteSwiftPackageReference "SuggestionsTextFieldKit" */;
|
||||||
|
productName = SuggestionsTextFieldKit;
|
||||||
|
};
|
||||||
|
53FE14512B8E1213006C4193 /* NextcloudKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */;
|
||||||
|
productName = NextcloudKit;
|
||||||
|
};
|
||||||
|
53FE14532B8E1219006C4193 /* NextcloudKit */ = {
|
||||||
|
isa = XCSwiftPackageProductDependency;
|
||||||
|
package = 5307A6E42965C6FA001E0C6A /* XCRemoteSwiftPackageReference "NextcloudKit" */;
|
||||||
|
productName = NextcloudKit;
|
||||||
|
};
|
||||||
/* End XCSwiftPackageProductDependency section */
|
/* End XCSwiftPackageProductDependency section */
|
||||||
};
|
};
|
||||||
rootObject = C2B573951B1CD88000303B36 /* Project object */;
|
rootObject = C2B573951B1CD88000303B36 /* Project object */;
|
||||||
|
|
Loading…
Reference in a new issue