From 969f8ef2ff2e2978994dc1185abdd73c14991e42 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 2 Apr 2025 15:00:46 +0200 Subject: [PATCH 01/29] Add read permission indicator + refactor Signed-off-by: Milen Pivchev --- .../Advanced/NCShareAdvancePermission.swift | 2 +- iOSClient/Share/Advanced/NCShareCells.swift | 66 ++++++++++++------- iOSClient/Share/NCPermissions.swift | 4 +- .../en.lproj/Localizable.strings | 12 ++-- 4 files changed, 55 insertions(+), 29 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index a57e926429..dc6160c933 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -172,7 +172,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { if section == 0 { - return NSLocalizedString("_permissions_", comment: "") + return NSLocalizedString("_custom_permissions_", comment: "") } else if section == 1 { return NSLocalizedString("_advanced_", comment: "") } else { return nil } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index b898b1e22b..bb229bd0c6 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -22,6 +22,7 @@ // import UIKit +import OSLog protocol NCShareCellConfig { var title: String { get } @@ -48,22 +49,29 @@ protocol NCPermission: NCToggleCellConfig { static var forDirectory: [Self] { get } static var forFile: [Self] { get } static func forDirectoryE2EE(account: String) -> [NCPermission] - func hasResharePermission(for parentPermission: Int) -> Bool - func hasDownload() -> Bool + func hasPermission(for parentPermission: Int) -> Bool + func hasDownloadPermission() -> Bool + func hasReadPermission() -> Bool } enum NCUserPermission: CaseIterable, NCPermission { - func hasResharePermission(for parentPermission: Int) -> Bool { + func hasPermission(for parentPermission: Int) -> Bool { + Logger().info("hasResharePermission \(parentPermission)") if self == .download { return true } return ((permissionBitFlag & parentPermission) != 0) } - func hasDownload() -> Bool { + func hasDownloadPermission() -> Bool { return self == .download } + func hasReadPermission() -> Bool { + return self == .read + } + var permissionBitFlag: Int { switch self { + case .read: return NCPermissions().permissionReadShare case .reshare: return NCPermissions().permissionShareShare case .edit: return NCPermissions().permissionUpdateShare case .create: return NCPermissions().permissionCreateShare @@ -95,12 +103,13 @@ enum NCUserPermission: CaseIterable, NCPermission { return [] } - case reshare, edit, create, delete, download + case read, reshare, edit, create, delete, download static let forDirectory: [NCUserPermission] = NCUserPermission.allCases - static let forFile: [NCUserPermission] = [.reshare, .edit] + static let forFile: [NCUserPermission] = [.read, .reshare, .edit] var title: String { switch self { + case .read: return NSLocalizedString("_share_can_read_", comment: "") case .reshare: return NSLocalizedString("_share_can_reshare_", comment: "") case .edit: return NSLocalizedString("_share_can_change_", comment: "") case .create: return NSLocalizedString("_share_can_create_", comment: "") @@ -111,6 +120,10 @@ enum NCUserPermission: CaseIterable, NCPermission { } enum NCLinkPermission: NCPermission { + func hasReadPermission() -> Bool { + return true + } + func didChange(_ share: Shareable, to newValue: Bool) { guard self != .allowEdit || newValue else { share.permissions = NCPermissions().permissionReadShare @@ -119,11 +132,11 @@ enum NCLinkPermission: NCPermission { share.permissions = permissionValue } - func hasResharePermission(for parentPermission: Int) -> Bool { + func hasPermission(for parentPermission: Int) -> Bool { permissionValue & parentPermission == permissionValue } - func hasDownload() -> Bool { + func hasDownloadPermission() -> Bool { return false } @@ -250,11 +263,11 @@ enum NCShareDetails: CaseIterable, NCShareCellConfig { struct NCShareConfig { let permissions: [NCPermission] let advanced: [NCShareDetails] - let share: Shareable + let shareable: Shareable let resharePermission: Int init(parentMetadata: tableMetadata, share: Shareable) { - self.share = share + self.shareable = share self.resharePermission = parentMetadata.sharePermissionsCollaborationServices let type: NCPermission.Type = share.shareType == NCShareCommon().SHARE_TYPE_LINK ? NCLinkPermission.self : NCUserPermission.self self.permissions = parentMetadata.directory ? (parentMetadata.e2eEncrypted ? type.forDirectoryE2EE(account: parentMetadata.account) : type.forDirectory) : type.forFile @@ -277,9 +290,18 @@ struct NCShareConfig { func cellFor(indexPath: IndexPath) -> UITableViewCell? { let cellConfig = config(for: indexPath) - let cell = cellConfig?.getCell(for: share) + let cell = cellConfig?.getCell(for: shareable) cell?.textLabel?.text = cellConfig?.title - if let cellConfig = cellConfig as? NCPermission, !cellConfig.hasResharePermission(for: resharePermission), !cellConfig.hasDownload() { + Logger().info("\(cellConfig?.title ?? "")") + + if let cellConfig = cellConfig as? NCPermission, + !cellConfig.hasPermission(for: resharePermission), + !cellConfig.hasDownloadPermission() { + cell?.isUserInteractionEnabled = false + cell?.textLabel?.isEnabled = false + } + + if let cellConfig = cellConfig as? NCPermission, cellConfig.hasReadPermission() { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } @@ -287,15 +309,15 @@ struct NCShareConfig { } func didSelectRow(at indexPath: IndexPath) { - let cellConfig = config(for: indexPath) - cellConfig?.didSelect(for: share) - } + let cellConfig = config(for: indexPath) + cellConfig?.didSelect(for: shareable) + } - func config(for indexPath: IndexPath) -> NCShareCellConfig? { - if indexPath.section == 0, indexPath.row < permissions.count { - return permissions[indexPath.row] - } else if indexPath.section == 1, indexPath.row < advanced.count { - return advanced[indexPath.row] - } else { return nil } + func config(for indexPath: IndexPath) -> NCShareCellConfig? { + if indexPath.section == 0, indexPath.row < permissions.count { + return permissions[indexPath.row] + } else if indexPath.section == 1, indexPath.row < advanced.count { + return advanced[indexPath.row] + } else { return nil } + } } -} diff --git a/iOSClient/Share/NCPermissions.swift b/iOSClient/Share/NCPermissions.swift index 1e7d348f49..5e591f42b8 100644 --- a/iOSClient/Share/NCPermissions.swift +++ b/iOSClient/Share/NCPermissions.swift @@ -50,7 +50,9 @@ class NCPermissions: NSObject { let permissionMaxFolderShare: Int = 31 let permissionDefaultFileRemoteShareNoSupportShareOption: Int = 3 let permissionDefaultFolderRemoteShareNoSupportShareOption: Int = 15 - // ATTRIBUTES + + // Additional attributes. This also includes the permission to download. + // Check https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html#share-attributes let permissionDownloadShare: Int = 0 func isPermissionToRead(_ permission: Int) -> Bool { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 985f4b635e..8824db7003 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -229,6 +229,7 @@ "_select_offline_warning_" = "Making multiple files and folders available offline may take a while and use a lot of memory while doing so."; "_advanced_" = "Advanced"; "_permissions_" = "Permissions"; +"_custom_permissions_" = "Custom permissions"; "_disable_files_app_" = "Disable Files App integration"; "_disable_files_app_footer_" = "Do not permit the access of files via the iOS Files application."; "_time_remaining_" = "%@ remaining"; @@ -389,11 +390,12 @@ "_share_expiration_date_" = "Set expiration date"; "_share_note_recipient_" = "Note to recipient"; "_share_add_sharelink_" = "Add another link"; -"_share_can_reshare_" = "Allow resharing"; -"_share_can_create_" = "Allow creating"; -"_share_can_change_" = "Allow editing"; -"_share_can_delete_" = "Allow deleting"; -"_share_can_download_" = "Allow download"; +"_share_can_read_" = "Read"; +"_share_can_reshare_" = "Share"; +"_share_can_create_" = "Create"; +"_share_can_change_" = "Edit"; +"_share_can_delete_" = "Delete"; +"_share_can_download_" = "Download"; "_share_unshare_" = "Unshare"; "_share_internal_link_" = "Internal link"; "_share_internal_link_des_" = "Only works for users with access to this file/folder."; From e92ac493723869b5afe2a72ed531b2f7a946f942 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 8 Apr 2025 13:24:27 +0200 Subject: [PATCH 02/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Menu/NCShare+Menu.swift | 18 ++++++++++------- iOSClient/Share/Advanced/NCShareCells.swift | 22 +++++++++++---------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index b9f1abcc58..991c43e1e4 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -96,8 +96,8 @@ extension NCShare { var actions = [NCMenuAction]() let permissions = NCPermissions() - actions.append( - NCMenuAction( + actions.append(contentsOf: + [NCMenuAction( title: NSLocalizedString("_share_read_only_", comment: ""), icon: utility.loadImage(named: "eye", colors: [NCBrandColor.shared.iconImageColor]), selected: tableShare.permissions == (permissions.permissionReadShare + permissions.permissionShareShare) || tableShare.permissions == permissions.permissionReadShare, @@ -107,10 +107,7 @@ extension NCShare { let permissions = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canShare, isDirectory: isDirectory) self.updateSharePermissions(share: tableShare, permissions: permissions) } - ) - ) - - actions.append( + ), NCMenuAction( title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""), icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]), @@ -121,7 +118,14 @@ extension NCShare { let permissions = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canShare, isDirectory: isDirectory) self.updateSharePermissions(share: tableShare, permissions: permissions) } - ) + ), + NCMenuAction( + title: NSLocalizedString("_custom_permissions_", comment: ""), + icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]), + action: { _ in + + } + )] ) self.presentMenu(with: actions) diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index bb229bd0c6..3332da521e 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -301,23 +301,25 @@ struct NCShareConfig { cell?.textLabel?.isEnabled = false } + // Read permission is always enabled and we show it as a non-interactable permissoin for brevity. if let cellConfig = cellConfig as? NCPermission, cellConfig.hasReadPermission() { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } + return cell } func didSelectRow(at indexPath: IndexPath) { - let cellConfig = config(for: indexPath) - cellConfig?.didSelect(for: shareable) - } + let cellConfig = config(for: indexPath) + cellConfig?.didSelect(for: shareable) + } - func config(for indexPath: IndexPath) -> NCShareCellConfig? { - if indexPath.section == 0, indexPath.row < permissions.count { - return permissions[indexPath.row] - } else if indexPath.section == 1, indexPath.row < advanced.count { - return advanced[indexPath.row] - } else { return nil } - } + func config(for indexPath: IndexPath) -> NCShareCellConfig? { + if indexPath.section == 0, indexPath.row < permissions.count { + return permissions[indexPath.row] + } else if indexPath.section == 1, indexPath.row < advanced.count { + return advanced[indexPath.row] + } else { return nil } } +} From b473eb3bc4c45e83a7ca8296274b9b9617091648 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 9 Apr 2025 13:44:38 +0200 Subject: [PATCH 03/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Menu/NCShare+Menu.swift | 26 ++++++++++++++------ iOSClient/Share/NCShare+NCCellDelegate.swift | 2 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index 991c43e1e4..6ecfa95101 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -92,7 +92,7 @@ extension NCShare { self.presentMenu(with: actions) } - func toggleUserPermissionMenu(isDirectory: Bool, tableShare: tableShare) { + func toggleUserPermissionMenu(isDirectory: Bool, share: tableShare) { var actions = [NCMenuAction]() let permissions = NCPermissions() @@ -100,30 +100,42 @@ extension NCShare { [NCMenuAction( title: NSLocalizedString("_share_read_only_", comment: ""), icon: utility.loadImage(named: "eye", colors: [NCBrandColor.shared.iconImageColor]), - selected: tableShare.permissions == (permissions.permissionReadShare + permissions.permissionShareShare) || tableShare.permissions == permissions.permissionReadShare, + selected: share.permissions == (permissions.permissionReadShare + permissions.permissionShareShare) || share.permissions == permissions.permissionReadShare, on: false, action: { _ in - let canShare = permissions.isPermissionToCanShare(tableShare.permissions) + let canShare = permissions.isPermissionToCanShare(share.permissions) let permissions = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canShare, isDirectory: isDirectory) - self.updateSharePermissions(share: tableShare, permissions: permissions) + self.updateSharePermissions(share: share, permissions: permissions) } ), NCMenuAction( title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""), icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]), - selected: hasUploadPermission(tableShare: tableShare), + selected: hasUploadPermission(tableShare: share), on: false, action: { _ in - let canShare = permissions.isPermissionToCanShare(tableShare.permissions) + let canShare = permissions.isPermissionToCanShare(share.permissions) let permissions = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canShare, isDirectory: isDirectory) - self.updateSharePermissions(share: tableShare, permissions: permissions) + self.updateSharePermissions(share: share, permissions: permissions) } ), NCMenuAction( title: NSLocalizedString("_custom_permissions_", comment: ""), icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]), action: { _ in + guard + let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission, + let navigationController = self.navigationController, !share.isInvalidated else { return } + advancePermission.networking = self.networking + advancePermission.share = tableShare(value: share) + advancePermission.oldTableShare = tableShare(value: share) + advancePermission.metadata = self.metadata + + if let downloadLimit = try? self.database.getDownloadLimit(byAccount: self.metadata.account, shareToken: share.token) { + advancePermission.downloadLimit = .limited(limit: downloadLimit.limit, count: downloadLimit.count) + } + navigationController.pushViewController(advancePermission, animated: true) } )] ) diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift index dd05de5484..4d128ce875 100644 --- a/iOSClient/Share/NCShare+NCCellDelegate.swift +++ b/iOSClient/Share/NCShare+NCCellDelegate.swift @@ -64,6 +64,6 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate { guard let tableShare, let metadata, tableShare.shareType != NCPermissions().permissionDefaultFileRemoteShareNoSupportShareOption else { return } - self.toggleUserPermissionMenu(isDirectory: metadata.directory, tableShare: tableShare) + self.toggleUserPermissionMenu(isDirectory: metadata.directory, share: tableShare) } } From fefa2428e1c1d9819c02e158347635b07f047110 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 9 Apr 2025 13:46:53 +0200 Subject: [PATCH 04/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Share/Advanced/NCShareCells.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 3332da521e..4808eaf64d 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -264,11 +264,11 @@ struct NCShareConfig { let permissions: [NCPermission] let advanced: [NCShareDetails] let shareable: Shareable - let resharePermission: Int + let sharePermission: Int init(parentMetadata: tableMetadata, share: Shareable) { self.shareable = share - self.resharePermission = parentMetadata.sharePermissionsCollaborationServices + self.sharePermission = parentMetadata.sharePermissionsCollaborationServices let type: NCPermission.Type = share.shareType == NCShareCommon().SHARE_TYPE_LINK ? NCLinkPermission.self : NCUserPermission.self self.permissions = parentMetadata.directory ? (parentMetadata.e2eEncrypted ? type.forDirectoryE2EE(account: parentMetadata.account) : type.forDirectory) : type.forFile @@ -295,7 +295,7 @@ struct NCShareConfig { Logger().info("\(cellConfig?.title ?? "")") if let cellConfig = cellConfig as? NCPermission, - !cellConfig.hasPermission(for: resharePermission), + !cellConfig.hasPermission(for: sharePermission), !cellConfig.hasDownloadPermission() { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false From f8a77eae9a14cb2df7d804299473a7394a46b2e8 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 9 Apr 2025 18:47:52 +0200 Subject: [PATCH 05/29] Download and sync in advanced Signed-off-by: Milen Pivchev --- .../Advanced/NCShareAdvancePermission.swift | 6 ++- iOSClient/Share/Advanced/NCShareCells.swift | 8 +++- iOSClient/Share/Shareable.swift | 42 ++++++++++++++++++- iOSClient/Share/TransientShare.swift | 2 + .../en.lproj/Localizable.strings | 2 +- 5 files changed, 54 insertions(+), 6 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index dc6160c933..9cf6a5bd1e 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -186,7 +186,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg if section == 0 { // check reshare permission, if restricted add note let maxPermission = metadata.directory ? NCPermissions().permissionMaxFolderShare : NCPermissions().permissionMaxFileShare - return shareConfig.resharePermission != maxPermission ? shareConfig.permissions.count + 1 : shareConfig.permissions.count + return shareConfig.sharePermission != maxPermission ? shareConfig.permissions.count + 1 : shareConfig.permissions.count } else if section == 1 { return shareConfig.advanced.count } else { return 0 } @@ -259,6 +259,10 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg tableView.reloadData() } self.present(alertController, animated: true) + case .downloadAndSync: + share.downloadAndSync.toggle() + tableView.reloadData() +// NCManageDatabase.shared.setAttibuteDownload(state: value) } } } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 4808eaf64d..327281f113 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -217,6 +217,7 @@ enum NCShareDetails: CaseIterable, NCShareCellConfig { case .password: return case .note: return case .label: return + case .downloadAndSync: return } } @@ -241,6 +242,8 @@ enum NCShareDetails: CaseIterable, NCShareCellConfig { let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareLabel") cell.detailTextLabel?.text = share.label return cell + case .downloadAndSync: + return NCShareToggleCell(isOn: share.downloadAndSync) } } @@ -252,12 +255,13 @@ enum NCShareDetails: CaseIterable, NCShareCellConfig { case .password: return NSLocalizedString("_share_password_protect_", comment: "") case .note: return NSLocalizedString("_share_note_recipient_", comment: "") case .label: return NSLocalizedString("_share_link_name_", comment: "") + case .downloadAndSync: return NSLocalizedString("_share_can_download_", comment: "") } } - case label, hideDownload, limitDownload, expirationDate, password, note + case label, hideDownload, limitDownload, expirationDate, password, note, downloadAndSync static let forLink: [NCShareDetails] = NCShareDetails.allCases - static let forUser: [NCShareDetails] = [.expirationDate, .note] + static let forUser: [NCShareDetails] = [.expirationDate, .note, .downloadAndSync] } struct NCShareConfig { diff --git a/iOSClient/Share/Shareable.swift b/iOSClient/Share/Shareable.swift index bbcad82c71..3d66ce6109 100644 --- a/iOSClient/Share/Shareable.swift +++ b/iOSClient/Share/Shareable.swift @@ -16,6 +16,7 @@ protocol Shareable: AnyObject { var password: String { get set } var label: String { get set } var note: String { get set } + var downloadAndSync: Bool { get set } var expirationDate: NSDate? { get set } var shareWithDisplayname: String { get set } var attributes: String? { get set } @@ -54,8 +55,45 @@ extension Shareable { // MARK: - tableShare Extension -extension tableShare: Shareable {} +extension tableShare: Shareable { + var downloadAndSync: Bool { + get { + NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes) + } + set { + attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) + } + } + +} // MARK: - NKShare Extension -extension NKShare: Shareable {} +extension NKShare: Shareable { + var downloadAndSync: Bool { + get { + NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes) + } + set { + attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) + } + } +} + +private func isAttributeDownloadEnabled(attributes: String?) -> Bool { + if let attributes = attributes, let data = attributes.data(using: .utf8) { + do { + if let json = try JSONSerialization.jsonObject(with: data) as? [Dictionary] { + for sub in json { + let key = sub["key"] as? String + let enabled = sub["enabled"] as? Bool + let scope = sub["scope"] as? String + if key == "download", scope == "permissions", let enabled = enabled { + return enabled + } + } + } + } catch let error as NSError { print(error) } + } + return true +} diff --git a/iOSClient/Share/TransientShare.swift b/iOSClient/Share/TransientShare.swift index e332bdc927..ece4563028 100644 --- a/iOSClient/Share/TransientShare.swift +++ b/iOSClient/Share/TransientShare.swift @@ -10,6 +10,7 @@ import NextcloudKit /// The persisted counterpart is ``tableShare``. /// class TransientShare: Shareable { + var shareType: Int var permissions: Int @@ -22,6 +23,7 @@ class TransientShare: Shareable { var note: String = "" var expirationDate: NSDate? var shareWithDisplayname: String = "" + var downloadAndSync = false var attributes: String? diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 8670af9a87..4ac6f92d03 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -395,7 +395,7 @@ "_share_can_create_" = "Create"; "_share_can_change_" = "Edit"; "_share_can_delete_" = "Delete"; -"_share_can_download_" = "Download"; +"_share_can_download_" = "Download and Sync"; "_share_unshare_" = "Unshare"; "_share_internal_link_" = "Internal link"; "_share_internal_link_des_" = "Only works for users with access to this file/folder."; From d6adbb2a96ca73917f24661039546ee94899c815 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 9 Apr 2025 19:06:33 +0200 Subject: [PATCH 06/29] Make download and sync button work Signed-off-by: Milen Pivchev --- iOSClient/Data/NCManageDatabase+Share.swift | 10 +++++----- iOSClient/Share/Advanced/NCShareCells.swift | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Share.swift b/iOSClient/Data/NCManageDatabase+Share.swift index bb51089730..ad419994a0 100644 --- a/iOSClient/Data/NCManageDatabase+Share.swift +++ b/iOSClient/Data/NCManageDatabase+Share.swift @@ -252,9 +252,9 @@ extension NCManageDatabase { // There is currently only one share attribute “download” from the scope “permissions”. This attribute is only valid for user and group shares, not for public link shares. func setAttibuteDownload(state: Bool) -> String? { if state { - return nil + return "[{\"scope\":\"permissions\",\"key\":\"download\",\"value\":true}]" } else { - return "[{\"scope\":\"permissions\",\"key\":\"download\",\"enabled\":false}]" + return "[{\"scope\":\"permissions\",\"key\":\"download\",\"value\":null}]" } } @@ -264,10 +264,10 @@ extension NCManageDatabase { if let json = try JSONSerialization.jsonObject(with: data) as? [Dictionary] { for sub in json { let key = sub["key"] as? String - let enabled = sub["enabled"] as? Bool + let enabled = sub["value"] as? Bool let scope = sub["scope"] as? String - if key == "download", scope == "permissions", let enabled = enabled { - return enabled + if key == "download", scope == "permissions" { + return enabled ?? false } } } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 327281f113..5c68e78218 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -82,7 +82,7 @@ enum NCUserPermission: CaseIterable, NCPermission { func didChange(_ share: Shareable, to newValue: Bool) { if self == .download { - share.attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) +// share.attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) } else { share.permissions ^= permissionBitFlag } From 935fdcfcefb0ccbfee39ebc08ba960a427ea53cd Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Thu, 10 Apr 2025 15:19:58 +0200 Subject: [PATCH 07/29] Remove download from normal permissions Signed-off-by: Milen Pivchev --- .../Advanced/NCShareAdvancePermission.swift | 2 +- iOSClient/Share/Advanced/NCShareCells.swift | 45 +++++-------------- iOSClient/Share/Shareable.swift | 1 - 3 files changed, 12 insertions(+), 36 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index 9cf6a5bd1e..b078592189 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -208,7 +208,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) guard let cellConfig = shareConfig.config(for: indexPath) else { return } - guard let cellConfig = cellConfig as? NCShareDetails else { + guard let cellConfig = cellConfig as? NCAdvancedPermission else { cellConfig.didSelect(for: share) tableView.reloadData() return diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 5c68e78218..df83db128a 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -50,21 +50,14 @@ protocol NCPermission: NCToggleCellConfig { static var forFile: [Self] { get } static func forDirectoryE2EE(account: String) -> [NCPermission] func hasPermission(for parentPermission: Int) -> Bool - func hasDownloadPermission() -> Bool func hasReadPermission() -> Bool } enum NCUserPermission: CaseIterable, NCPermission { func hasPermission(for parentPermission: Int) -> Bool { - Logger().info("hasResharePermission \(parentPermission)") - if self == .download { return true } return ((permissionBitFlag & parentPermission) != 0) } - func hasDownloadPermission() -> Bool { - return self == .download - } - func hasReadPermission() -> Bool { return self == .read } @@ -76,24 +69,15 @@ enum NCUserPermission: CaseIterable, NCPermission { case .edit: return NCPermissions().permissionUpdateShare case .create: return NCPermissions().permissionCreateShare case .delete: return NCPermissions().permissionDeleteShare - case .download: return NCPermissions().permissionDownloadShare } } func didChange(_ share: Shareable, to newValue: Bool) { - if self == .download { -// share.attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) - } else { - share.permissions ^= permissionBitFlag - } + share.permissions ^= permissionBitFlag } func isOn(for share: Shareable) -> Bool { - if self == .download { - return NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: share.attributes) - } else { - return (share.permissions & permissionBitFlag) != 0 - } + return (share.permissions & permissionBitFlag) != 0 } static func forDirectoryE2EE(account: String) -> [NCPermission] { @@ -103,7 +87,7 @@ enum NCUserPermission: CaseIterable, NCPermission { return [] } - case read, reshare, edit, create, delete, download + case read, reshare, edit, create, delete static let forDirectory: [NCUserPermission] = NCUserPermission.allCases static let forFile: [NCUserPermission] = [.read, .reshare, .edit] @@ -114,7 +98,6 @@ enum NCUserPermission: CaseIterable, NCPermission { case .edit: return NSLocalizedString("_share_can_change_", comment: "") case .create: return NSLocalizedString("_share_can_create_", comment: "") case .delete: return NSLocalizedString("_share_can_delete_", comment: "") - case .download: return NSLocalizedString("_share_can_download_", comment: "") } } } @@ -136,10 +119,6 @@ enum NCLinkPermission: NCPermission { permissionValue & parentPermission == permissionValue } - func hasDownloadPermission() -> Bool { - return false - } - var permissionValue: Int { switch self { case .allowEdit: @@ -208,7 +187,7 @@ enum NCLinkPermission: NCPermission { /// /// Individual aspects of share. /// -enum NCShareDetails: CaseIterable, NCShareCellConfig { +enum NCAdvancedPermission: CaseIterable, NCShareCellConfig { func didSelect(for share: Shareable) { switch self { case .hideDownload: share.hideDownload.toggle() @@ -260,13 +239,13 @@ enum NCShareDetails: CaseIterable, NCShareCellConfig { } case label, hideDownload, limitDownload, expirationDate, password, note, downloadAndSync - static let forLink: [NCShareDetails] = NCShareDetails.allCases - static let forUser: [NCShareDetails] = [.expirationDate, .note, .downloadAndSync] + static let forLink: [NCAdvancedPermission] = [.expirationDate, .hideDownload, .label, .limitDownload, .note, .password] + static let forUser: [NCAdvancedPermission] = [.expirationDate, .note, .downloadAndSync] } struct NCShareConfig { let permissions: [NCPermission] - let advanced: [NCShareDetails] + let advanced: [NCAdvancedPermission] let shareable: Shareable let sharePermission: Int @@ -283,12 +262,12 @@ struct NCShareConfig { .capabilityFileSharingDownloadLimit if parentMetadata.isDirectory || hasDownloadLimitCapability == false { - self.advanced = NCShareDetails.forLink.filter { $0 != .limitDownload } + self.advanced = NCAdvancedPermission.forLink.filter { $0 != .limitDownload } } else { - self.advanced = NCShareDetails.forLink + self.advanced = NCAdvancedPermission.forLink } } else { - self.advanced = NCShareDetails.forUser + self.advanced = NCAdvancedPermission.forUser } } @@ -298,9 +277,7 @@ struct NCShareConfig { cell?.textLabel?.text = cellConfig?.title Logger().info("\(cellConfig?.title ?? "")") - if let cellConfig = cellConfig as? NCPermission, - !cellConfig.hasPermission(for: sharePermission), - !cellConfig.hasDownloadPermission() { + if let cellConfig = cellConfig as? NCPermission, !cellConfig.hasPermission(for: sharePermission) { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } diff --git a/iOSClient/Share/Shareable.swift b/iOSClient/Share/Shareable.swift index 3d66ce6109..2425abdbad 100644 --- a/iOSClient/Share/Shareable.swift +++ b/iOSClient/Share/Shareable.swift @@ -64,7 +64,6 @@ extension tableShare: Shareable { attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue) } } - } // MARK: - NKShare Extension From c2b8fd1a4d0e239720fa877d325b66d365220d12 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 11 Apr 2025 10:05:48 +0200 Subject: [PATCH 08/29] Remove unneeded db param Signed-off-by: Milen Pivchev --- iOSClient/Data/NCManageDatabase+Metadata.swift | 9 +++------ iOSClient/Data/NCManageDatabase+Share.swift | 2 +- iOSClient/Supporting Files/en.lproj/Localizable.strings | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Metadata.swift b/iOSClient/Data/NCManageDatabase+Metadata.swift index b9a48061c4..8491632e6b 100644 --- a/iOSClient/Data/NCManageDatabase+Metadata.swift +++ b/iOSClient/Data/NCManageDatabase+Metadata.swift @@ -51,8 +51,7 @@ class tableMetadata: Object { self.altitude == object.altitude, self.status == object.status, Array(self.tags).elementsEqual(Array(object.tags)), - Array(self.shareType).elementsEqual(Array(object.shareType)), - Array(self.sharePermissionsCloudMesh).elementsEqual(Array(object.sharePermissionsCloudMesh)) { + Array(self.shareType).elementsEqual(Array(object.shareType)) { return true } else { return false @@ -118,8 +117,8 @@ class tableMetadata: Object { @objc dynamic var sessionError = "" @objc dynamic var sessionSelector = "" @objc dynamic var sessionTaskIdentifier: Int = 0 + /// The integer for sharing permissions. @objc dynamic var sharePermissionsCollaborationServices: Int = 0 - let sharePermissionsCloudMesh = List() let shareType = List() @objc dynamic var size: Int64 = 0 @objc dynamic var status: Int = 0 @@ -395,9 +394,7 @@ extension NCManageDatabase { metadata.serverUrl = file.serverUrl metadata.serveUrlFileName = file.serverUrl + "/" + file.fileName metadata.sharePermissionsCollaborationServices = file.sharePermissionsCollaborationServices - for element in file.sharePermissionsCloudMesh { - metadata.sharePermissionsCloudMesh.append(element) - } + for element in file.shareType { metadata.shareType.append(element) } diff --git a/iOSClient/Data/NCManageDatabase+Share.swift b/iOSClient/Data/NCManageDatabase+Share.swift index ad419994a0..1a44561f19 100644 --- a/iOSClient/Data/NCManageDatabase+Share.swift +++ b/iOSClient/Data/NCManageDatabase+Share.swift @@ -264,7 +264,7 @@ extension NCManageDatabase { if let json = try JSONSerialization.jsonObject(with: data) as? [Dictionary] { for sub in json { let key = sub["key"] as? String - let enabled = sub["value"] as? Bool + let enabled = (sub["value"] as? Bool) /* >= NC 30 */ ?? sub["enabled"] as? Bool // /* < NC 29 */ let scope = sub["scope"] as? String if key == "download", scope == "permissions" { return enabled ?? false diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 4ac6f92d03..694236b022 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -395,8 +395,8 @@ "_share_can_create_" = "Create"; "_share_can_change_" = "Edit"; "_share_can_delete_" = "Delete"; -"_share_can_download_" = "Download and Sync"; -"_share_unshare_" = "Unshare"; +"_share_can_download_" = "Allow download and sync"; +"_share_unshare_" = "Delete share"; "_share_internal_link_" = "Internal link"; "_share_internal_link_des_" = "Only works for users with access to this file/folder."; "_share_reshare_disabled_" = "You are not allowed to reshare this file/folder."; From 5889f64f36ba7dcdf1a0484526285fb29c597409 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 14 Apr 2025 13:11:35 +0200 Subject: [PATCH 09/29] Fix view only, allow edit, custom permissions Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 4 +-- iOSClient/Menu/NCShare+Menu.swift | 8 ++--- iOSClient/Share/Advanced/NCShareCells.swift | 17 ++++----- iOSClient/Share/NCPermissions.swift | 38 +++++++++++++-------- iOSClient/Share/NCShare.swift | 1 + iOSClient/Share/NCShareUserCell.swift | 20 ++++++----- 6 files changed, 47 insertions(+), 41 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 05654d1b07..473c9cdb16 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -6211,8 +6211,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/scenee/FloatingPanel"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; + kind = exactVersion; + version = 2.8.6; }; }; F77333862927A72100466E35 /* XCRemoteSwiftPackageReference "OpenSSL" */ = { diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index 6ecfa95101..fd98697d68 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -103,19 +103,17 @@ extension NCShare { selected: share.permissions == (permissions.permissionReadShare + permissions.permissionShareShare) || share.permissions == permissions.permissionReadShare, on: false, action: { _ in - let canShare = permissions.isPermissionToCanShare(share.permissions) - let permissions = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canShare, isDirectory: isDirectory) + let permissions = permissions.getPermissionValue(canCreate: false, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory) self.updateSharePermissions(share: share, permissions: permissions) } ), NCMenuAction( - title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""), + title: NSLocalizedString("_share_editing_", comment: ""), icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]), selected: hasUploadPermission(tableShare: share), on: false, action: { _ in - let canShare = permissions.isPermissionToCanShare(share.permissions) - let permissions = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canShare, isDirectory: isDirectory) + let permissions = permissions.getPermissionValue(canCreate: true, canEdit: true, canDelete: true, canShare: true, isDirectory: isDirectory) self.updateSharePermissions(share: share, permissions: permissions) } ), diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index df83db128a..9df13a5300 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -66,7 +66,7 @@ enum NCUserPermission: CaseIterable, NCPermission { switch self { case .read: return NCPermissions().permissionReadShare case .reshare: return NCPermissions().permissionShareShare - case .edit: return NCPermissions().permissionUpdateShare + case .edit: return NCPermissions().permissionEditShare case .create: return NCPermissions().permissionCreateShare case .delete: return NCPermissions().permissionDeleteShare } @@ -122,28 +122,25 @@ enum NCLinkPermission: NCPermission { var permissionValue: Int { switch self { case .allowEdit: - return NCPermissions().getPermission( - canEdit: true, + return NCPermissions().getPermissionValue( canCreate: true, - canChange: true, + canEdit: true, canDelete: true, canShare: false, isDirectory: false) case .viewOnly: - return NCPermissions().getPermission( - canEdit: false, + return NCPermissions().getPermissionValue( canCreate: false, - canChange: false, + canEdit: false, canDelete: false, // not possible to create "read-only" shares without reshare option // https://github.com/nextcloud/server/blame/f99876997a9119518fe5f7ad3a3a51d33459d4cc/apps/files_sharing/lib/Controller/ShareAPIController.php#L1104-L1107 canShare: true, isDirectory: true) case .uploadEdit: - return NCPermissions().getPermission( - canEdit: true, + return NCPermissions().getPermissionValue( canCreate: true, - canChange: true, + canEdit: true, canDelete: true, canShare: false, isDirectory: true) diff --git a/iOSClient/Share/NCPermissions.swift b/iOSClient/Share/NCPermissions.swift index 5e591f42b8..7ea51c8137 100644 --- a/iOSClient/Share/NCPermissions.swift +++ b/iOSClient/Share/NCPermissions.swift @@ -39,7 +39,7 @@ class NCPermissions: NSObject { // permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all // let permissionReadShare: Int = 1 - let permissionUpdateShare: Int = 2 + let permissionEditShare: Int = 2 let permissionCreateShare: Int = 4 let permissionDeleteShare: Int = 8 let permissionShareShare: Int = 16 @@ -58,41 +58,48 @@ class NCPermissions: NSObject { func isPermissionToRead(_ permission: Int) -> Bool { return ((permission & permissionReadShare) > 0) } + func isPermissionToCanDelete(_ permission: Int) -> Bool { return ((permission & permissionDeleteShare) > 0) } + func isPermissionToCanCreate(_ permission: Int) -> Bool { return ((permission & permissionCreateShare) > 0) } - func isPermissionToCanChange(_ permission: Int) -> Bool { - return ((permission & permissionUpdateShare) > 0) + + func isPermissionToCanEdit(_ permission: Int) -> Bool { + return ((permission & permissionEditShare) > 0) } + func isPermissionToCanShare(_ permission: Int) -> Bool { return ((permission & permissionShareShare) > 0) } + func isAnyPermissionToEdit(_ permission: Int) -> Bool { let canCreate = isPermissionToCanCreate(permission) - let canChange = isPermissionToCanChange(permission) + let canEdit = isPermissionToCanEdit(permission) let canDelete = isPermissionToCanDelete(permission) - return canCreate || canChange || canDelete + return canCreate || canEdit || canDelete } - func isPermissionToReadCreateUpdate(_ permission: Int) -> Bool { + + /// "Can edit" means it has can read, create, edit, and delete. + func canEdit(_ permission: Int, isDirectory: Bool) -> Bool { let canRead = isPermissionToRead(permission) - let canCreate = isPermissionToCanCreate(permission) - let canChange = isPermissionToCanChange(permission) - return canCreate && canChange && canRead + let canCreate = isDirectory ? isPermissionToCanCreate(permission) : true + let canEdit = isPermissionToCanEdit(permission) + let canDelete = isDirectory ? isPermissionToCanDelete(permission) : true + return canCreate && canEdit && canRead && canDelete } - func getPermission(canEdit: Bool, canCreate: Bool, canChange: Bool, canDelete: Bool, canShare: Bool, isDirectory: Bool) -> Int { + + /// Read permission is always true for a share, hence why it's not here. + func getPermissionValue(canCreate: Bool, canEdit: Bool, canDelete: Bool, canShare: Bool, isDirectory: Bool) -> Int { var permission = permissionReadShare - if canEdit && !isDirectory { - permission = permission + permissionUpdateShare - } if canCreate && isDirectory { permission = permission + permissionCreateShare } - if canChange && isDirectory { - permission = permission + permissionUpdateShare + if canEdit { + permission = permission + permissionEditShare } if canDelete && isDirectory { permission = permission + permissionDeleteShare @@ -100,6 +107,7 @@ class NCPermissions: NSObject { if canShare { permission = permission + permissionShareShare } + return permission } } diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 0745a56025..35fd6a06eb 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -369,6 +369,7 @@ extension NCShare: UITableViewDataSource { if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell { cell.indexPath = indexPath cell.tableShare = tableShare + cell.isDirectory = metadata.directory cell.delegate = self cell.setupCellUI(userId: session.userId) diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index 576964010a..b7f6a7e9db 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -38,6 +38,7 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { private var index = IndexPath() var tableShare: tableShare? + var isDirectory = false let utility = NCUtility() weak var delegate: NCShareUserCellDelegate? @@ -87,16 +88,17 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { btnQuickStatus.setTitle("", for: .normal) btnQuickStatus.contentHorizontalAlignment = .left - if tableShare.permissions == permissions.permissionCreateShare { - labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "") - } else { - // Read Only - if permissions.isAnyPermissionToEdit(tableShare.permissions) { - labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "") - } else { - labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "") - } +// if tableShare.permissions == permissions.permissionCreateShare { + // labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "") + // } else { + if permissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit + labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "") + } else if tableShare.permissions == permissions.permissionReadShare { // Read only + labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "") + } else { // Custom permissions + labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") } + // } } override func awakeFromNib() { From 219df5a38c7c404fe1c92d072e695a28fe035cce Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 14 Apr 2025 18:34:12 +0200 Subject: [PATCH 10/29] Fix link custom permissions being grayed out Signed-off-by: Milen Pivchev --- iOSClient/Share/Advanced/NCShareCells.swift | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 9df13a5300..2cd0760a15 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -252,6 +252,7 @@ struct NCShareConfig { let type: NCPermission.Type = share.shareType == NCShareCommon().SHARE_TYPE_LINK ? NCLinkPermission.self : NCUserPermission.self self.permissions = parentMetadata.directory ? (parentMetadata.e2eEncrypted ? type.forDirectoryE2EE(account: parentMetadata.account) : type.forDirectory) : type.forFile + // There are many share types, but we only classify them as a link share (link type) and a user share (every other share type). if share.shareType == NCShareCommon().SHARE_TYPE_LINK { let hasDownloadLimitCapability = NCCapabilities .shared @@ -280,7 +281,7 @@ struct NCShareConfig { } // Read permission is always enabled and we show it as a non-interactable permissoin for brevity. - if let cellConfig = cellConfig as? NCPermission, cellConfig.hasReadPermission() { + if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission() { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } From bd87c2ba4cbda43470b4b524cb71247d90289349 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 15 Apr 2025 11:53:19 +0200 Subject: [PATCH 11/29] Fix share screen not updating with sharees on first open Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 9 +++++++-- iOSClient/Share/NCShareNetworking.swift | 12 ++++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 35fd6a06eb..d10e266420 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -163,11 +163,14 @@ class NCShare: UIViewController, NCSharePagingContent { if error == .success, let etag = etag, let imageAvatar = imageAvatar { self.database.addAvatar(fileName: fileName, etag: etag) self.sharedWithYouByImage.image = imageAvatar + self.reloadData() } else if error.errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = self.database.setAvatarLoaded(fileName: fileName) { self.sharedWithYouByImage.image = imageAvatar } } } + + reloadData() } // MARK: - Notification Center @@ -221,18 +224,20 @@ class NCShare: UIViewController, NCSharePagingContent { extension NCShare: NCShareNetworkingDelegate { func readShareCompleted() { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) + reloadData() } func shareCompleted() { NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare) + reloadData() } func unShareCompleted() { - self.reloadData() + reloadData() } func updateShareWithError(idShare: Int) { - self.reloadData() + reloadData() } func getSharees(sharees: [NKSharee]?) { diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index bcf2c69e64..1ba63b8f3b 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -84,8 +84,16 @@ class NCShareNetworking: NSObject { } Task { - try await self.readDownloadLimits(account: account, tokens: shares.map(\.token)) - self.delegate?.readShareCompleted() + do { + defer { + Task { @MainActor in + self.delegate?.readShareCompleted() + } + } + try await self.readDownloadLimits(account: account, tokens: shares.map(\.token)) + } catch { + print("Error reading download limits: \(error)") + } } } } else { From e6098fb6a6880d2db7a40962321621392e3319c1 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 15 Apr 2025 11:59:18 +0200 Subject: [PATCH 12/29] Refactor Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShareNetworking.swift | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index 1ba63b8f3b..a1726136d0 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -84,15 +84,10 @@ class NCShareNetworking: NSObject { } Task { - do { - defer { - Task { @MainActor in - self.delegate?.readShareCompleted() - } - } - try await self.readDownloadLimits(account: account, tokens: shares.map(\.token)) - } catch { - print("Error reading download limits: \(error)") + try? await self.readDownloadLimits(account: account, tokens: shares.map(\.token)) + + Task { @MainActor in + self.delegate?.readShareCompleted() } } } From 4637451896ee76b30605c2d0caaf77f75cd056a0 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 15 Apr 2025 16:18:39 +0200 Subject: [PATCH 13/29] Add capabilities check for download limit This removes the api error Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShareNetworking.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index a1726136d0..8636dd3d8b 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -194,6 +194,8 @@ class NCShareNetworking: NSObject { /// Remove the download limit on the share, if existent. /// func removeShareDownloadLimit(token: String) { + if !NCCapabilities().getCapabilities(account: metadata.account).capabilityFileSharingDownloadLimit { return } + NCActivityIndicator.shared.start(backgroundView: view) NextcloudKit.shared.removeShareDownloadLimit(account: metadata.account, token: token) { error in @@ -213,6 +215,8 @@ class NCShareNetworking: NSObject { /// - Parameter limit: The new download limit to set. /// func setShareDownloadLimit(_ limit: Int, token: String) { + if !NCCapabilities().getCapabilities(account: metadata.account).capabilityFileSharingDownloadLimit { return } + NCActivityIndicator.shared.start(backgroundView: view) NextcloudKit.shared.setShareDownloadLimit(account: metadata.account, token: token, limit: limit) { error in From 6aae638163fbb8e8d05b7136ec078b521f892fbe Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 16 Apr 2025 18:50:34 +0200 Subject: [PATCH 14/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Data/NCManageDatabase+Share.swift | 2 + .../Advanced/NCShareAdvancePermission.swift | 1 - iOSClient/Share/Advanced/NCShareCells.swift | 80 +++++++++++++------ iOSClient/Share/NCShare+NCCellDelegate.swift | 4 +- iOSClient/Share/NCShare.swift | 5 +- iOSClient/Share/NCShareLinkCell.swift | 22 +++++ iOSClient/Share/NCShareLinkCell.xib | 43 +++++++--- 7 files changed, 113 insertions(+), 44 deletions(-) diff --git a/iOSClient/Data/NCManageDatabase+Share.swift b/iOSClient/Data/NCManageDatabase+Share.swift index 1a44561f19..9b945fc042 100644 --- a/iOSClient/Data/NCManageDatabase+Share.swift +++ b/iOSClient/Data/NCManageDatabase+Share.swift @@ -55,6 +55,8 @@ class tableShareV2: Object { @objc dynamic var sendPasswordByTalk: Bool = false @objc dynamic var serverUrl = "" + /// + /// shareType - (int) 0 = user; 1 = group; 3 = public link; 4 = email; 6 = federated cloud share; 7 = circle; 10 = Talk conversation /// /// See [OCS Share API documentation](https://docs.nextcloud.com/server/latest/developer_manual/client_apis/OCS/ocs-share-api.html) for semantic definitions of the different possible values. /// diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index b078592189..3531c2c021 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -262,7 +262,6 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg case .downloadAndSync: share.downloadAndSync.toggle() tableView.reloadData() -// NCManageDatabase.shared.setAttibuteDownload(state: value) } } } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 2cd0760a15..6ab3d1b422 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -50,7 +50,7 @@ protocol NCPermission: NCToggleCellConfig { static var forFile: [Self] { get } static func forDirectoryE2EE(account: String) -> [NCPermission] func hasPermission(for parentPermission: Int) -> Bool - func hasReadPermission() -> Bool + func hasReadPermission(isDirectory: Bool) -> Bool } enum NCUserPermission: CaseIterable, NCPermission { @@ -58,7 +58,7 @@ enum NCUserPermission: CaseIterable, NCPermission { return ((permissionBitFlag & parentPermission) != 0) } - func hasReadPermission() -> Bool { + func hasReadPermission(isDirectory: Bool) -> Bool { return self == .read } @@ -103,17 +103,17 @@ enum NCUserPermission: CaseIterable, NCPermission { } enum NCLinkPermission: NCPermission { - func hasReadPermission() -> Bool { - return true + func hasReadPermission(isDirectory: Bool) -> Bool { + return isDirectory ? self == .read : false } - func didChange(_ share: Shareable, to newValue: Bool) { - guard self != .allowEdit || newValue else { - share.permissions = NCPermissions().permissionReadShare - return - } - share.permissions = permissionValue - } +// func didChange(_ share: Shareable, to newValue: Bool) { +// guard self != .edit || newValue else { +// share.permissions = NCPermissions().permissionReadShare +// return +// } +// share.permissions = permissionValue +// } func hasPermission(for parentPermission: Int) -> Bool { permissionValue & parentPermission == permissionValue @@ -121,14 +121,14 @@ enum NCLinkPermission: NCPermission { var permissionValue: Int { switch self { - case .allowEdit: + case .edit: return NCPermissions().getPermissionValue( canCreate: true, canEdit: true, canDelete: true, canShare: false, isDirectory: false) - case .viewOnly: + case .read: return NCPermissions().getPermissionValue( canCreate: false, canEdit: false, @@ -151,34 +151,60 @@ enum NCLinkPermission: NCPermission { } } - func isOn(for share: Shareable) -> Bool { - let permissions = NCPermissions() + var permissionBitFlag: Int { switch self { - case .allowEdit: return permissions.isAnyPermissionToEdit(share.permissions) - case .viewOnly: return !permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare - case .uploadEdit: return permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare - case .fileDrop: return share.permissions == permissions.permissionCreateShare - case .secureFileDrop: return share.permissions == permissions.permissionCreateShare + case .read: return NCPermissions().permissionReadShare +// case .reshare: return NCPermissions().permissionShareShare + case .edit: return NCPermissions().permissionEditShare +// case .create: return NCPermissions().permissionCreateShare +// case .delete: return NCPermissions().permissionDeleteShare + case .uploadEdit: + return 0 + case .fileDrop: + return 0 + + case .secureFileDrop: + return 0 + } } + func didChange(_ share: Shareable, to newValue: Bool) { + share.permissions ^= permissionBitFlag + } + + func isOn(for share: Shareable) -> Bool { + return (share.permissions & permissionBitFlag) != 0 + } + +// func isOn(for share: Shareable) -> Bool { +// let permissions = NCPermissions() +// switch self { +// case .edit: return permissions.isAnyPermissionToEdit(share.permissions) +// case .read: return share.permissions == permissions.permissionReadShare +// case .uploadEdit: return permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare +// case .fileDrop: return share.permissions == permissions.permissionCreateShare +// case .secureFileDrop: return share.permissions == permissions.permissionCreateShare +// } +// } + static func forDirectoryE2EE(account: String) -> [NCPermission] { return [NCLinkPermission.secureFileDrop] } var title: String { switch self { - case .allowEdit: return NSLocalizedString("_share_can_change_", comment: "") - case .viewOnly: return NSLocalizedString("_share_read_only_", comment: "") + case .edit: return NSLocalizedString("_share_can_change_", comment: "") + case .read: return NSLocalizedString("_share_can_read_", comment: "") case .uploadEdit: return NSLocalizedString("_share_allow_upload_", comment: "") case .fileDrop: return NSLocalizedString("_share_file_drop_", comment: "") case .secureFileDrop: return NSLocalizedString("_share_secure_file_drop_", comment: "") } } - case allowEdit, viewOnly, uploadEdit, fileDrop, secureFileDrop - static let forDirectory: [NCLinkPermission] = [.viewOnly, .uploadEdit, .fileDrop] - static let forFile: [NCLinkPermission] = [.allowEdit] + case edit, read, uploadEdit, fileDrop, secureFileDrop + static let forDirectory: [NCLinkPermission] = [.read, .uploadEdit, .fileDrop] + static let forFile: [NCLinkPermission] = [.read, .edit] } /// @@ -245,10 +271,12 @@ struct NCShareConfig { let advanced: [NCAdvancedPermission] let shareable: Shareable let sharePermission: Int + let isDirectory: Bool init(parentMetadata: tableMetadata, share: Shareable) { self.shareable = share self.sharePermission = parentMetadata.sharePermissionsCollaborationServices + self.isDirectory = parentMetadata.directory let type: NCPermission.Type = share.shareType == NCShareCommon().SHARE_TYPE_LINK ? NCLinkPermission.self : NCUserPermission.self self.permissions = parentMetadata.directory ? (parentMetadata.e2eEncrypted ? type.forDirectoryE2EE(account: parentMetadata.account) : type.forDirectory) : type.forFile @@ -281,7 +309,7 @@ struct NCShareConfig { } // Read permission is always enabled and we show it as a non-interactable permissoin for brevity. - if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission() { + if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission(isDirectory: isDirectory) { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift index 4d128ce875..7d240b37bd 100644 --- a/iOSClient/Share/NCShare+NCCellDelegate.swift +++ b/iOSClient/Share/NCShare+NCCellDelegate.swift @@ -62,8 +62,8 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate { func quickStatus(with tableShare: tableShare?, sender: Any) { guard let tableShare, - let metadata, - tableShare.shareType != NCPermissions().permissionDefaultFileRemoteShareNoSupportShareOption else { return } + let metadata else { return } +// tableShare.shareType != NCPermissions().permissionDefaultFileRemoteShareNoSupportShareOption self.toggleUserPermissionMenu(isDirectory: metadata.directory, share: tableShare) } } diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index d10e266420..19c4bccea1 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -310,10 +310,6 @@ extension NCShare: NCShareNetworkingDelegate { extension NCShare: UITableViewDelegate { func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - if indexPath.section == 0, indexPath.row == 0 { - // internal cell has description - return 40 - } return 60 } } @@ -365,6 +361,7 @@ extension NCShare: UITableViewDataSource { if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell { cell.indexPath = indexPath cell.tableShare = tableShare + cell.isDirectory = metadata.directory cell.delegate = self cell.setupCellUI() return cell diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index 1db528ce16..fdf98dbea6 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -28,9 +28,12 @@ class NCShareLinkCell: UITableViewCell { @IBOutlet private weak var labelTitle: UILabel! @IBOutlet private weak var descriptionLabel: UILabel! + @IBOutlet weak var labelQuickStatus: UILabel! + @IBOutlet weak var statusStackView: UIStackView! @IBOutlet private weak var menuButton: UIButton! @IBOutlet private weak var copyButton: UIButton! var tableShare: tableShare? + var isDirectory = false weak var delegate: NCShareLinkCellDelegate? var isInternalLink = false var indexPath = IndexPath() @@ -43,10 +46,12 @@ class NCShareLinkCell: UITableViewCell { func setupCellUI() { var menuImageName = "ellipsis" + let permissions = NCPermissions() menuButton.isHidden = isInternalLink descriptionLabel.isHidden = !isInternalLink copyButton.isHidden = !isInternalLink && tableShare == nil + statusStackView.isHidden = isInternalLink if #available(iOS 18.0, *) { // use NCShareLinkCell image } else { @@ -78,6 +83,18 @@ class NCShareLinkCell: UITableViewCell { } labelTitle.textColor = NCBrandColor.shared.textColor + + if let tableShare = tableShare { + if permissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit + labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "") + } else if tableShare.permissions == permissions.permissionReadShare { // Read only + labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "") + } else { // Custom permissions + labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") + } + } + + statusStackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openQuickStatus))) } @IBAction func touchUpCopy(_ sender: Any) { @@ -87,9 +104,14 @@ class NCShareLinkCell: UITableViewCell { @IBAction func touchUpMenu(_ sender: Any) { delegate?.tapMenu(with: tableShare, sender: sender) } + + @objc func openQuickStatus(_ sender: UITapGestureRecognizer) { + delegate?.quickStatus(with: tableShare, sender: sender) + } } protocol NCShareLinkCellDelegate: AnyObject { func tapCopy(with tableShare: tableShare?, sender: Any) func tapMenu(with tableShare: tableShare?, sender: Any) + func quickStatus(with tableShare: tableShare?, sender: Any) } diff --git a/iOSClient/Share/NCShareLinkCell.xib b/iOSClient/Share/NCShareLinkCell.xib index caf3d7dc2e..b266d53f29 100755 --- a/iOSClient/Share/NCShareLinkCell.xib +++ b/iOSClient/Share/NCShareLinkCell.xib @@ -1,6 +1,6 @@ - + @@ -19,7 +19,7 @@ - + @@ -28,7 +28,7 @@ - + - - + + - - + - + @@ -104,13 +122,16 @@ + + + From b2140cc233a3846247c99719d6265c36c6ce7a08 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 2 May 2025 16:13:02 +0200 Subject: [PATCH 15/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Menu/NCShare+Menu.swift | 22 +++++++++++++++++++- iOSClient/Share/Advanced/NCShareCells.swift | 18 ++++++++++------ iOSClient/Share/NCShare+NCCellDelegate.swift | 6 ++---- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index fd98697d68..6dd0081f62 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -92,7 +92,7 @@ extension NCShare { self.presentMenu(with: actions) } - func toggleUserPermissionMenu(isDirectory: Bool, share: tableShare) { + func toggleQuickPermissionsMenu(isDirectory: Bool, share: tableShare) { var actions = [NCMenuAction]() let permissions = NCPermissions() @@ -138,6 +138,26 @@ extension NCShare { )] ) + actions.insert(NCMenuAction( + title: NSLocalizedString("_custom_permissions_", comment: ""), + icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]), + action: { _ in + guard + let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission, + let navigationController = self.navigationController, !share.isInvalidated else { return } + advancePermission.networking = self.networking + advancePermission.share = tableShare(value: share) + advancePermission.oldTableShare = tableShare(value: share) + advancePermission.metadata = self.metadata + + if let downloadLimit = try? self.database.getDownloadLimit(byAccount: self.metadata.account, shareToken: share.token) { + advancePermission.downloadLimit = .limited(limit: downloadLimit.limit, count: downloadLimit.count) + } + + navigationController.pushViewController(advancePermission, animated: true) + } + ), at: 2) + self.presentMenu(with: actions) } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index 6ab3d1b422..ca3377b32b 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -50,7 +50,7 @@ protocol NCPermission: NCToggleCellConfig { static var forFile: [Self] { get } static func forDirectoryE2EE(account: String) -> [NCPermission] func hasPermission(for parentPermission: Int) -> Bool - func hasReadPermission(isDirectory: Bool) -> Bool + func hasReadPermission() -> Bool } enum NCUserPermission: CaseIterable, NCPermission { @@ -58,7 +58,7 @@ enum NCUserPermission: CaseIterable, NCPermission { return ((permissionBitFlag & parentPermission) != 0) } - func hasReadPermission(isDirectory: Bool) -> Bool { + func hasReadPermission() -> Bool { return self == .read } @@ -103,8 +103,8 @@ enum NCUserPermission: CaseIterable, NCPermission { } enum NCLinkPermission: NCPermission { - func hasReadPermission(isDirectory: Bool) -> Bool { - return isDirectory ? self == .read : false + func hasReadPermission() -> Bool { + return self == .read } // func didChange(_ share: Shareable, to newValue: Bool) { @@ -308,8 +308,14 @@ struct NCShareConfig { cell?.textLabel?.isEnabled = false } - // Read permission is always enabled and we show it as a non-interactable permissoin for brevity. - if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission(isDirectory: isDirectory) { + // For user permissions: Read permission is always enabled and we show it as a non-interactable permission for brevity. + if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission() { + cell?.isUserInteractionEnabled = false + cell?.textLabel?.isEnabled = false + } + + // For link permissions: Read permission is always enabled and we show it as a non-interactable permission in files only for brevity. + if let cellConfig = cellConfig as? NCLinkPermission, cellConfig.hasReadPermission(), !isDirectory { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift index 7d240b37bd..e79c9c01a2 100644 --- a/iOSClient/Share/NCShare+NCCellDelegate.swift +++ b/iOSClient/Share/NCShare+NCCellDelegate.swift @@ -61,9 +61,7 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate { } func quickStatus(with tableShare: tableShare?, sender: Any) { - guard let tableShare, - let metadata else { return } -// tableShare.shareType != NCPermissions().permissionDefaultFileRemoteShareNoSupportShareOption - self.toggleUserPermissionMenu(isDirectory: metadata.directory, share: tableShare) + guard let tableShare, let metadata else { return } + self.toggleQuickPermissionsMenu(isDirectory: metadata.directory, share: tableShare) } } From 2288d34c0713a4d98d1ebb7e3ca3045e3b6dfba7 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 5 May 2025 16:12:23 +0200 Subject: [PATCH 16/29] Add quick options to link shares Signed-off-by: Milen Pivchev --- Nextcloud.xcodeproj/project.pbxproj | 2 + iOSClient/Menu/NCShare+Menu.swift | 29 ++---- iOSClient/Share/Advanced/NCShareCells.swift | 91 ++++--------------- iOSClient/Share/NCPermissions.swift | 8 +- iOSClient/Share/NCShare.swift | 3 +- iOSClient/Share/NCShareLinkCell.swift | 20 +++- iOSClient/Share/NCShareLinkCell.xib | 5 +- iOSClient/Share/NCShareNetworking.swift | 2 + .../en.lproj/Localizable.strings | 2 +- 9 files changed, 58 insertions(+), 104 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 3099ecb7a7..f239cb2926 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -1373,6 +1373,7 @@ F3CA337C2D0B2B6A00672333 /* AlbumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumModel.swift; sourceTree = ""; }; F3E173AF2C9AF637006D177A /* ScreenAwakeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenAwakeManager.swift; sourceTree = ""; }; F3E173BF2C9B1067006D177A /* AwakeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwakeMode.swift; sourceTree = ""; }; + F3F9C4552DC8CAB8001D3E11 /* NextcloudKit */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = NextcloudKit; path = ../NextcloudKit; sourceTree = SOURCE_ROOT; }; F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = ""; }; F700510022DF63AC003A3356 /* NCShare.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCShare.storyboard; sourceTree = ""; }; F700510422DF6A89003A3356 /* NCShare.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShare.swift; sourceTree = ""; }; @@ -3280,6 +3281,7 @@ F7F67B9F1A24D27800EE80DA = { isa = PBXGroup; children = ( + F3F9C4552DC8CAB8001D3E11 /* NextcloudKit */, AA8E041E2D3114E200E7E89C /* README.md */, F7B8B82F25681C3400967775 /* GoogleService-Info.plist */, F7C1CDD91E6DFC6F005D92BE /* Brand */, diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index 5abc09630c..8e6ba889eb 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -144,26 +144,17 @@ extension NCShare { )] ) - actions.insert(NCMenuAction( - title: NSLocalizedString("_custom_permissions_", comment: ""), - icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]), - sender: sender, - action: { _ in - guard - let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission, - let navigationController = self.navigationController, !share.isInvalidated else { return } - advancePermission.networking = self.networking - advancePermission.share = tableShare(value: share) - advancePermission.oldTableShare = tableShare(value: share) - advancePermission.metadata = self.metadata - - if let downloadLimit = try? self.database.getDownloadLimit(byAccount: self.metadata.account, shareToken: share.token) { - advancePermission.downloadLimit = .limited(limit: downloadLimit.limit, count: downloadLimit.count) + if isDirectory && (share.shareType == 3 /* public link */ || share.shareType == 4 /* email */) { + actions.insert(NCMenuAction( + title: NSLocalizedString("_share_file_drop_", comment: ""), + icon: utility.loadImage(named: "arrow.up.document", colors: [NCBrandColor.shared.iconImageColor]), + sender: sender, + action: { _ in + let permissions = permissions.getPermissionValue(canRead: false, canCreate: true, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory) + self.updateSharePermissions(share: share, permissions: permissions) } - - navigationController.pushViewController(advancePermission, animated: true) - } - ), at: 2) + ), at: 2) + } self.presentMenu(with: actions, sender: sender) } diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index ca3377b32b..fc6b4cd8d0 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -102,70 +102,29 @@ enum NCUserPermission: CaseIterable, NCPermission { } } -enum NCLinkPermission: NCPermission { +enum NCLinkPermission: CaseIterable, NCPermission { + static func forDirectoryE2EE(account: String) -> [any NCPermission] { + if NCCapabilities.shared.getCapabilities(account: account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 { + return NCUserPermission.allCases + } + return [] + } + func hasReadPermission() -> Bool { return self == .read } -// func didChange(_ share: Shareable, to newValue: Bool) { -// guard self != .edit || newValue else { -// share.permissions = NCPermissions().permissionReadShare -// return -// } -// share.permissions = permissionValue -// } - func hasPermission(for parentPermission: Int) -> Bool { - permissionValue & parentPermission == permissionValue - } - - var permissionValue: Int { - switch self { - case .edit: - return NCPermissions().getPermissionValue( - canCreate: true, - canEdit: true, - canDelete: true, - canShare: false, - isDirectory: false) - case .read: - return NCPermissions().getPermissionValue( - canCreate: false, - canEdit: false, - canDelete: false, - // not possible to create "read-only" shares without reshare option - // https://github.com/nextcloud/server/blame/f99876997a9119518fe5f7ad3a3a51d33459d4cc/apps/files_sharing/lib/Controller/ShareAPIController.php#L1104-L1107 - canShare: true, - isDirectory: true) - case .uploadEdit: - return NCPermissions().getPermissionValue( - canCreate: true, - canEdit: true, - canDelete: true, - canShare: false, - isDirectory: true) - case .fileDrop: - return NCPermissions().permissionCreateShare - case .secureFileDrop: - return NCPermissions().permissionCreateShare - } + return ((permissionBitFlag & parentPermission) != 0) } var permissionBitFlag: Int { switch self { case .read: return NCPermissions().permissionReadShare -// case .reshare: return NCPermissions().permissionShareShare + // case .reshare: return NCPermissions().permissionShareShare case .edit: return NCPermissions().permissionEditShare -// case .create: return NCPermissions().permissionCreateShare -// case .delete: return NCPermissions().permissionDeleteShare - case .uploadEdit: - return 0 - case .fileDrop: - return 0 - - case .secureFileDrop: - return 0 - + case .create: return NCPermissions().permissionCreateShare + case .delete: return NCPermissions().permissionDeleteShare } } @@ -177,33 +136,17 @@ enum NCLinkPermission: NCPermission { return (share.permissions & permissionBitFlag) != 0 } -// func isOn(for share: Shareable) -> Bool { -// let permissions = NCPermissions() -// switch self { -// case .edit: return permissions.isAnyPermissionToEdit(share.permissions) -// case .read: return share.permissions == permissions.permissionReadShare -// case .uploadEdit: return permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare -// case .fileDrop: return share.permissions == permissions.permissionCreateShare -// case .secureFileDrop: return share.permissions == permissions.permissionCreateShare -// } -// } - - static func forDirectoryE2EE(account: String) -> [NCPermission] { - return [NCLinkPermission.secureFileDrop] - } - var title: String { switch self { - case .edit: return NSLocalizedString("_share_can_change_", comment: "") case .read: return NSLocalizedString("_share_can_read_", comment: "") - case .uploadEdit: return NSLocalizedString("_share_allow_upload_", comment: "") - case .fileDrop: return NSLocalizedString("_share_file_drop_", comment: "") - case .secureFileDrop: return NSLocalizedString("_share_secure_file_drop_", comment: "") + case .edit: return NSLocalizedString("_share_can_change_", comment: "") + case .create: return NSLocalizedString("_share_can_create_", comment: "") + case .delete: return NSLocalizedString("_share_can_delete_", comment: "") } } - case edit, read, uploadEdit, fileDrop, secureFileDrop - static let forDirectory: [NCLinkPermission] = [.read, .uploadEdit, .fileDrop] + case edit, read, create, delete + static let forDirectory: [NCLinkPermission] = NCLinkPermission.allCases static let forFile: [NCLinkPermission] = [.read, .edit] } diff --git a/iOSClient/Share/NCPermissions.swift b/iOSClient/Share/NCPermissions.swift index 7ea51c8137..f9014edd71 100644 --- a/iOSClient/Share/NCPermissions.swift +++ b/iOSClient/Share/NCPermissions.swift @@ -92,8 +92,12 @@ class NCPermissions: NSObject { } /// Read permission is always true for a share, hence why it's not here. - func getPermissionValue(canCreate: Bool, canEdit: Bool, canDelete: Bool, canShare: Bool, isDirectory: Bool) -> Int { - var permission = permissionReadShare + func getPermissionValue(canRead: Bool = true, canCreate: Bool, canEdit: Bool, canDelete: Bool, canShare: Bool, isDirectory: Bool) -> Int { + var permission = 0 + + if canRead { + permission = permission + permissionReadShare + } if canCreate && isDirectory { permission = permission + permissionCreateShare diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 1483d964bf..b0c33d8bed 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -336,7 +336,7 @@ extension NCShare: UITableViewDataSource { } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - // Setup default share cells +// // Setup default share cells guard indexPath.section != 0 else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell else { return UITableViewCell() } @@ -350,6 +350,7 @@ extension NCShare: UITableViewDataSource { cell.tableShare = shares.firstShareLink } } + cell.isDirectory = metadata.directory cell.setupCellUI() return cell } diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index fdf98dbea6..1d1515326d 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -32,11 +32,14 @@ class NCShareLinkCell: UITableViewCell { @IBOutlet weak var statusStackView: UIStackView! @IBOutlet private weak var menuButton: UIButton! @IBOutlet private weak var copyButton: UIButton! + @IBOutlet weak var imageDownArrow: UIImageView! + var tableShare: tableShare? var isDirectory = false weak var delegate: NCShareLinkCellDelegate? var isInternalLink = false var indexPath = IndexPath() + let utility = NCUtility() override func prepareForReuse() { super.prepareForReuse() @@ -83,18 +86,25 @@ class NCShareLinkCell: UITableViewCell { } labelTitle.textColor = NCBrandColor.shared.textColor - + if let tableShare = tableShare { + labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") + if permissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "") - } else if tableShare.permissions == permissions.permissionReadShare { // Read only + } + if permissions.getPermissionValue(canRead: false, canCreate: true, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory) == tableShare.permissions { + labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "") + } + if permissions.getPermissionValue(canCreate: false, canEdit: false, canDelete: false, canShare: true, isDirectory: isDirectory) == tableShare.permissions { // Read only labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "") - } else { // Custom permissions - labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") +// } else { // Custom permissions } } - + statusStackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openQuickStatus))) + labelQuickStatus.textColor = NCBrandColor.shared.customer + imageDownArrow.image = utility.loadImage(named: "arrowtriangle.down.circle", colors: [NCBrandColor.shared.customer]) } @IBAction func touchUpCopy(_ sender: Any) { diff --git a/iOSClient/Share/NCShareLinkCell.xib b/iOSClient/Share/NCShareLinkCell.xib index b266d53f29..d5810a5294 100755 --- a/iOSClient/Share/NCShareLinkCell.xib +++ b/iOSClient/Share/NCShareLinkCell.xib @@ -121,6 +121,7 @@ + @@ -139,10 +140,10 @@ - + - + diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index 8636dd3d8b..6b4901bc79 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -153,6 +153,8 @@ class NCShareNetworking: NSObject { func updateShare(_ option: Shareable, downloadLimit: DownloadLimitViewModel) { NCActivityIndicator.shared.start(backgroundView: view) NextcloudKit.shared.updateShare(idShare: option.idShare, password: option.password, expireDate: option.formattedDateString, permissions: option.permissions, note: option.note, label: option.label, hideDownload: option.hideDownload, attributes: option.attributes, account: metadata.account) { _, share, _, error in +// NextcloudKit.shared.updateShare(idShare: option.idShare, password: option.password, expireDate: option.formattedDateString, permissions: option.permissions, note: option.note, label: option.label, hideDownload: option.hideDownload, attributes: option.attributes, account: metadata.account) { _, share, _, error in +// NextcloudKit.shared.updateShare(idShare: option.idShare, permissions: option.permissions, hideDownload: option.hideDownload, account: metadata.account) { account, share, responseData, error in NCActivityIndicator.shared.stop() if error == .success, let share = share { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 3f3fb87952..f513e410b4 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -381,7 +381,7 @@ "_share_read_only_" = "View only"; "_share_editing_" = "Can edit"; "_share_allow_upload_" = "Allow upload and editing"; -"_share_file_drop_" = "File drop (upload only)"; +"_share_file_drop_" = "File request"; "_share_secure_file_drop_" = "Secure file drop (upload only)"; "_share_hide_download_" = "Hide download"; "_share_limit_download_" = "Limit downloads"; From d5d5dbfba1299a9bd58ff6f147371b8b0aafd44f Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 6 May 2025 18:23:01 +0200 Subject: [PATCH 17/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Menu/NCShare+Menu.swift | 4 +- .../Advanced/NCShareAdvancePermission.swift | 110 +++++++++--------- iOSClient/Share/Advanced/NCShareCells.swift | 3 +- iOSClient/Share/NCShare.swift | 6 +- iOSClient/Share/NCShareLinkCell.swift | 16 ++- iOSClient/Share/NCShareNetworking.swift | 2 - 6 files changed, 74 insertions(+), 67 deletions(-) diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index 8e6ba889eb..63e64624d6 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -30,7 +30,7 @@ extension NCShare { let capabilities = NCCapabilities.shared.getCapabilities(account: self.metadata.account) var actions = [NCMenuAction]() - if share.shareType == 3, canReshare { + if share.shareType == NCShareCommon().SHARE_TYPE_LINK, canReshare { actions.append( NCMenuAction( title: NSLocalizedString("_share_add_sharelink_", comment: ""), @@ -144,7 +144,7 @@ extension NCShare { )] ) - if isDirectory && (share.shareType == 3 /* public link */ || share.shareType == 4 /* email */) { + if isDirectory && (share.shareType == NCShareCommon().SHARE_TYPE_LINK /* public link */ || share.shareType == NCShareCommon().SHARE_TYPE_EMAIL) { actions.insert(NCMenuAction( title: NSLocalizedString("_share_file_drop_", comment: ""), icon: utility.loadImage(named: "arrow.up.document", colors: [NCBrandColor.shared.iconImageColor]), diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index 3531c2c021..9eeaa1fb07 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -27,59 +27,6 @@ import SVGKit import CloudKit class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDelegate, NCShareNavigationTitleSetting { - func dismissShareAdvanceView(shouldSave: Bool) { - guard shouldSave else { - guard oldTableShare?.hasChanges(comparedTo: share) != false else { - navigationController?.popViewController(animated: true) - return - } - - let alert = UIAlertController( - title: NSLocalizedString("_cancel_request_", comment: ""), - message: NSLocalizedString("_discard_changes_info_", comment: ""), - preferredStyle: .alert) - - alert.addAction(UIAlertAction( - title: NSLocalizedString("_discard_changes_", comment: ""), - style: .destructive, - handler: { _ in self.navigationController?.popViewController(animated: true) })) - - alert.addAction(UIAlertAction(title: NSLocalizedString("_continue_editing_", comment: ""), style: .default)) - self.present(alert, animated: true) - - return - } - - Task { - // TODO: Apply share token to download limit object - - if isNewShare { - let serverUrl = metadata.serverUrl + "/" + metadata.fileName - - if share.shareType != NCShareCommon().SHARE_TYPE_LINK, metadata.e2eEncrypted, - NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 { - - if NCNetworkingE2EE().isInUpload(account: metadata.account, serverUrl: serverUrl) { - let error = NKError(errorCode: NCGlobal.shared.errorE2EEUploadInProgress, errorDescription: NSLocalizedString("_e2e_in_upload_", comment: "")) - return NCContentPresenter().showInfo(error: error) - } - - let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, addUserId: share.shareWith, removeUserId: nil, account: metadata.account) - - if error != .success { - return NCContentPresenter().showError(error: error) - } - } - - networking?.createShare(share, downloadLimit: self.downloadLimit) - } else { - networking?.updateShare(share, downloadLimit: self.downloadLimit) - } - } - - navigationController?.popViewController(animated: true) - } - let database = NCManageDatabase.shared var oldTableShare: tableShare? @@ -264,6 +211,63 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg tableView.reloadData() } } + + func dismissShareAdvanceView(shouldSave: Bool) { + guard shouldSave else { + guard oldTableShare?.hasChanges(comparedTo: share) != false else { + navigationController?.popViewController(animated: true) + return + } + + let alert = UIAlertController( + title: NSLocalizedString("_cancel_request_", comment: ""), + message: NSLocalizedString("_discard_changes_info_", comment: ""), + preferredStyle: .alert) + + alert.addAction(UIAlertAction( + title: NSLocalizedString("_discard_changes_", comment: ""), + style: .destructive, + handler: { _ in self.navigationController?.popViewController(animated: true) })) + + alert.addAction(UIAlertAction(title: NSLocalizedString("_continue_editing_", comment: ""), style: .default)) + self.present(alert, animated: true) + + return + } + + Task { + // TODO: Apply share token to download limit object + + if (share.shareType == NCShareCommon().SHARE_TYPE_LINK || share.shareType == NCShareCommon().SHARE_TYPE_EMAIL) && NCPermissions().isPermissionToCanShare(share.permissions) { + share.permissions = share.permissions - NCPermissions().permissionShareShare + } + + if isNewShare { + let serverUrl = metadata.serverUrl + "/" + metadata.fileName + + if share.shareType != NCShareCommon().SHARE_TYPE_LINK, metadata.e2eEncrypted, + NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 { + + if NCNetworkingE2EE().isInUpload(account: metadata.account, serverUrl: serverUrl) { + let error = NKError(errorCode: NCGlobal.shared.errorE2EEUploadInProgress, errorDescription: NSLocalizedString("_e2e_in_upload_", comment: "")) + return NCContentPresenter().showInfo(error: error) + } + + let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, addUserId: share.shareWith, removeUserId: nil, account: metadata.account) + + if error != .success { + return NCContentPresenter().showError(error: error) + } + } + + networking?.createShare(share, downloadLimit: self.downloadLimit) + } else { + networking?.updateShare(share, downloadLimit: self.downloadLimit) + } + } + + navigationController?.popViewController(animated: true) + } } // MARK: - NCShareDownloadLimitTableViewControllerDelegate diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index fc6b4cd8d0..f7e5ae13b9 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -109,7 +109,7 @@ enum NCLinkPermission: CaseIterable, NCPermission { } return [] } - + func hasReadPermission() -> Bool { return self == .read } @@ -121,7 +121,6 @@ enum NCLinkPermission: CaseIterable, NCPermission { var permissionBitFlag: Int { switch self { case .read: return NCPermissions().permissionReadShare - // case .reshare: return NCPermissions().permissionShareShare case .edit: return NCPermissions().permissionEditShare case .create: return NCPermissions().permissionCreateShare case .delete: return NCPermissions().permissionDeleteShare diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index b0c33d8bed..99853efdec 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -336,7 +336,7 @@ extension NCShare: UITableViewDataSource { } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { -// // Setup default share cells + // Setup default share cells guard indexPath.section != 0 else { guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell else { return UITableViewCell() } @@ -357,8 +357,8 @@ extension NCShare: UITableViewDataSource { guard let tableShare = shares.share?[indexPath.row] else { return UITableViewCell() } - // LINK - if tableShare.shareType == shareCommon.SHARE_TYPE_LINK { + // LINK, EMAIL + if tableShare.shareType == shareCommon.SHARE_TYPE_LINK || tableShare.shareType == shareCommon.SHARE_TYPE_EMAIL { if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell { cell.indexPath = indexPath cell.tableShare = tableShare diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index 1d1515326d..d19199f233 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -23,7 +23,6 @@ import UIKit class NCShareLinkCell: UITableViewCell { - @IBOutlet private weak var imageItem: UIImageView! @IBOutlet private weak var labelTitle: UILabel! @IBOutlet private weak var descriptionLabel: UILabel! @@ -86,8 +85,11 @@ class NCShareLinkCell: UITableViewCell { } labelTitle.textColor = NCBrandColor.shared.textColor - - if let tableShare = tableShare { + + statusStackView.isHidden = true + + if let tableShare { + statusStackView.isHidden = false labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") if permissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit @@ -98,10 +100,14 @@ class NCShareLinkCell: UITableViewCell { } if permissions.getPermissionValue(canCreate: false, canEdit: false, canDelete: false, canShare: true, isDirectory: isDirectory) == tableShare.permissions { // Read only labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "") -// } else { // Custom permissions + } + + if tableShare.shareType == NCShareCommon().SHARE_TYPE_EMAIL { + labelTitle.text = tableShare.shareWithDisplayname + imageItem.image = NCUtility().loadImage(named: "envelope.circle.fill", colors: [NCBrandColor.shared.getElement(account: tableShare.account)]) } } - + statusStackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openQuickStatus))) labelQuickStatus.textColor = NCBrandColor.shared.customer imageDownArrow.image = utility.loadImage(named: "arrowtriangle.down.circle", colors: [NCBrandColor.shared.customer]) diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift index 6b4901bc79..8636dd3d8b 100644 --- a/iOSClient/Share/NCShareNetworking.swift +++ b/iOSClient/Share/NCShareNetworking.swift @@ -153,8 +153,6 @@ class NCShareNetworking: NSObject { func updateShare(_ option: Shareable, downloadLimit: DownloadLimitViewModel) { NCActivityIndicator.shared.start(backgroundView: view) NextcloudKit.shared.updateShare(idShare: option.idShare, password: option.password, expireDate: option.formattedDateString, permissions: option.permissions, note: option.note, label: option.label, hideDownload: option.hideDownload, attributes: option.attributes, account: metadata.account) { _, share, _, error in -// NextcloudKit.shared.updateShare(idShare: option.idShare, password: option.password, expireDate: option.formattedDateString, permissions: option.permissions, note: option.note, label: option.label, hideDownload: option.hideDownload, attributes: option.attributes, account: metadata.account) { _, share, _, error in -// NextcloudKit.shared.updateShare(idShare: option.idShare, permissions: option.permissions, hideDownload: option.hideDownload, account: metadata.account) { account, share, responseData, error in NCActivityIndicator.shared.stop() if error == .success, let share = share { From 1d6ef845eb13fb5cd31a26be58f95cf7976afcd7 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 6 May 2025 18:29:45 +0200 Subject: [PATCH 18/29] Add selected flag to file drop Signed-off-by: Milen Pivchev --- iOSClient/Menu/NCShare+Menu.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift index 63e64624d6..b50d7f7a21 100644 --- a/iOSClient/Menu/NCShare+Menu.swift +++ b/iOSClient/Menu/NCShare+Menu.swift @@ -148,6 +148,8 @@ extension NCShare { actions.insert(NCMenuAction( title: NSLocalizedString("_share_file_drop_", comment: ""), icon: utility.loadImage(named: "arrow.up.document", colors: [NCBrandColor.shared.iconImageColor]), + selected: share.permissions == permissions.permissionCreateShare, + on: false, sender: sender, action: { _ in let permissions = permissions.getPermissionValue(canRead: false, canCreate: true, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory) From 05f0485923dcdd2a2a8f17d8c23f9d5b21d902ba Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 6 May 2025 18:39:25 +0200 Subject: [PATCH 19/29] Remove share permission on email shares Signed-off-by: Milen Pivchev --- iOSClient/Share/Advanced/NCShareCells.swift | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift index f7e5ae13b9..6042717e37 100644 --- a/iOSClient/Share/Advanced/NCShareCells.swift +++ b/iOSClient/Share/Advanced/NCShareCells.swift @@ -102,7 +102,7 @@ enum NCUserPermission: CaseIterable, NCPermission { } } -enum NCLinkPermission: CaseIterable, NCPermission { +enum NCLinkEmailPermission: CaseIterable, NCPermission { static func forDirectoryE2EE(account: String) -> [any NCPermission] { if NCCapabilities.shared.getCapabilities(account: account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 { return NCUserPermission.allCases @@ -145,8 +145,8 @@ enum NCLinkPermission: CaseIterable, NCPermission { } case edit, read, create, delete - static let forDirectory: [NCLinkPermission] = NCLinkPermission.allCases - static let forFile: [NCLinkPermission] = [.read, .edit] + static let forDirectory: [NCLinkEmailPermission] = NCLinkEmailPermission.allCases + static let forFile: [NCLinkEmailPermission] = [.read, .edit] } /// @@ -215,14 +215,14 @@ struct NCShareConfig { let sharePermission: Int let isDirectory: Bool + /// There are many share types, but we only classify them as a link share (link type, email type) and a user share (every other share type). init(parentMetadata: tableMetadata, share: Shareable) { self.shareable = share self.sharePermission = parentMetadata.sharePermissionsCollaborationServices self.isDirectory = parentMetadata.directory - let type: NCPermission.Type = share.shareType == NCShareCommon().SHARE_TYPE_LINK ? NCLinkPermission.self : NCUserPermission.self + let type: NCPermission.Type = (share.shareType == NCShareCommon().SHARE_TYPE_LINK || share.shareType == NCShareCommon().SHARE_TYPE_EMAIL) ? NCLinkEmailPermission.self : NCUserPermission.self self.permissions = parentMetadata.directory ? (parentMetadata.e2eEncrypted ? type.forDirectoryE2EE(account: parentMetadata.account) : type.forDirectory) : type.forFile - // There are many share types, but we only classify them as a link share (link type) and a user share (every other share type). if share.shareType == NCShareCommon().SHARE_TYPE_LINK { let hasDownloadLimitCapability = NCCapabilities .shared @@ -257,7 +257,7 @@ struct NCShareConfig { } // For link permissions: Read permission is always enabled and we show it as a non-interactable permission in files only for brevity. - if let cellConfig = cellConfig as? NCLinkPermission, cellConfig.hasReadPermission(), !isDirectory { + if let cellConfig = cellConfig as? NCLinkEmailPermission, cellConfig.hasReadPermission(), !isDirectory { cell?.isUserInteractionEnabled = false cell?.textLabel?.isEnabled = false } From 559ef53132a934434e6e6ca69ca9c7e64aa10a81 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 7 May 2025 11:22:35 +0200 Subject: [PATCH 20/29] Refactor Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 3 +-- iOSClient/Share/NCSharePaging.swift | 5 ----- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 99853efdec..e0021d8928 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -45,7 +45,6 @@ class NCShare: UIViewController, NCSharePagingContent { weak var appDelegate = UIApplication.shared.delegate as? AppDelegate public var metadata: tableMetadata! - public var sharingEnabled = true public var height: CGFloat = 0 let shareCommon = NCShareCommon() let utilityFileSystem = NCUtilityFileSystem() @@ -105,7 +104,7 @@ class NCShare: UIViewController, NCSharePagingContent { reloadData() networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session) - if sharingEnabled { + if metadata.canShare { let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.page == .sharing networking?.readShare(showLoadingIndicator: isVisible) } diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift index a8951fe869..c8a7ec99e3 100644 --- a/iOSClient/Share/NCSharePaging.swift +++ b/iOSClient/Share/NCSharePaging.swift @@ -225,14 +225,9 @@ extension NCSharePaging: PagingViewControllerDataSource { // MARK: - Header class NCShareHeaderViewController: PagingViewController { - public var image: UIImage? public var metadata = tableMetadata() - public var activityEnabled = true - public var commentsEnabled = true - public var sharingEnabled = true - override func loadView() { view = NCSharePagingView( options: options, From 91869898955640c10da2865ce4d8294efd63c0b5 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 7 May 2025 15:33:23 +0200 Subject: [PATCH 21/29] Fix shares not showing Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index e0021d8928..abf8b39cbb 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -104,10 +104,8 @@ class NCShare: UIViewController, NCSharePagingContent { reloadData() networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session) - if metadata.canShare { - let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.page == .sharing - networking?.readShare(showLoadingIndicator: isVisible) - } + let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.page == .sharing + networking?.readShare(showLoadingIndicator: isVisible) searchField.searchTextField.font = .systemFont(ofSize: 14) searchField.delegate = self From 5375499bb97bf4379ea2ed86363134a436827e5d Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 7 May 2025 16:45:43 +0200 Subject: [PATCH 22/29] Fix ui Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 2 +- iOSClient/Share/NCShareUserCell.xib | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index abf8b39cbb..3b1012b643 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -341,7 +341,7 @@ extension NCShare: UITableViewDataSource { if metadata.e2eEncrypted, NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 { cell.tableShare = shares.firstShareLink } else { - if indexPath.row == 1 { + if indexPath.row == 0 { cell.isInternalLink = true } else if shares.firstShareLink?.isInvalidated != true { cell.tableShare = shares.firstShareLink diff --git a/iOSClient/Share/NCShareUserCell.xib b/iOSClient/Share/NCShareUserCell.xib index df97e61950..eb9b65ca76 100755 --- a/iOSClient/Share/NCShareUserCell.xib +++ b/iOSClient/Share/NCShareUserCell.xib @@ -1,9 +1,9 @@ - + - + @@ -19,10 +19,10 @@ - + - - + + @@ -36,7 +36,7 @@ - + @@ -103,7 +103,7 @@ - + @@ -149,10 +149,10 @@ - + - + From 151ff20f3a274038101165a076125b22e60b8446 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 14 May 2025 13:36:29 +0200 Subject: [PATCH 23/29] Refactor Signed-off-by: Milen Pivchev --- iOSClient/Share/Advanced/NCShareDateCell.swift | 8 ++++---- iOSClient/Share/NCShareCommon.swift | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareDateCell.swift b/iOSClient/Share/Advanced/NCShareDateCell.swift index 5dfcab9dfc..15ddfa415b 100644 --- a/iOSClient/Share/Advanced/NCShareDateCell.swift +++ b/iOSClient/Share/Advanced/NCShareDateCell.swift @@ -68,8 +68,8 @@ class NCShareDateCell: UITableViewCell { shareCommon.SHARE_TYPE_CIRCLE, shareCommon.SHARE_TYPE_ROOM: return NCCapabilities.shared.getCapabilities(account: account).capabilityFileSharingInternalExpireDateEnforced - case shareCommon.SHARE_TYPE_REMOTE, - shareCommon.SHARE_TYPE_REMOTE_GROUP: + case shareCommon.SHARE_TYPE_FEDERATED, + shareCommon.SHARE_TYPE_FEDERATED_GROUP: return NCCapabilities.shared.getCapabilities(account: account).capabilityFileSharingRemoteExpireDateEnforced default: return false @@ -87,8 +87,8 @@ class NCShareDateCell: UITableViewCell { shareCommon.SHARE_TYPE_CIRCLE, shareCommon.SHARE_TYPE_ROOM: return NCCapabilities.shared.getCapabilities(account: account).capabilityFileSharingInternalExpireDateDays - case shareCommon.SHARE_TYPE_REMOTE, - shareCommon.SHARE_TYPE_REMOTE_GROUP: + case shareCommon.SHARE_TYPE_FEDERATED, + shareCommon.SHARE_TYPE_FEDERATED_GROUP: return NCCapabilities.shared.getCapabilities(account: account).capabilityFileSharingRemoteExpireDateDays default: return 0 diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift index da2f6e1189..5f38d26281 100644 --- a/iOSClient/Share/NCShareCommon.swift +++ b/iOSClient/Share/NCShareCommon.swift @@ -31,10 +31,10 @@ class NCShareCommon: NSObject { let SHARE_TYPE_LINK = 3 let SHARE_TYPE_EMAIL = 4 let SHARE_TYPE_CONTACT = 5 - let SHARE_TYPE_REMOTE = 6 + let SHARE_TYPE_FEDERATED = 6 let SHARE_TYPE_CIRCLE = 7 let SHARE_TYPE_GUEST = 8 - let SHARE_TYPE_REMOTE_GROUP = 9 + let SHARE_TYPE_FEDERATED_GROUP = 9 let SHARE_TYPE_ROOM = 10 // swiftlint:enable identifier_name @@ -82,13 +82,13 @@ class NCShareCommon: NSObject { return UIImage(named: "shareTypeEmail")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) case self.SHARE_TYPE_CONTACT: return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) - case self.SHARE_TYPE_REMOTE: + case self.SHARE_TYPE_FEDERATED: return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) case self.SHARE_TYPE_CIRCLE: return UIImage(named: "shareTypeCircles")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) case self.SHARE_TYPE_GUEST: return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) - case self.SHARE_TYPE_REMOTE_GROUP: + case self.SHARE_TYPE_FEDERATED_GROUP: return UIImage(named: "shareTypeGroup")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) case self.SHARE_TYPE_ROOM: return UIImage(named: "shareTypeRoom")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal) From b2fca73e531c3a8c01d0badd5dfe58f38b966180 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 16 May 2025 11:14:17 +0200 Subject: [PATCH 24/29] PR changes Signed-off-by: Milen Pivchev --- .../Advanced/NCShareAdvancePermission.swift | 2 -- iOSClient/Share/NCShare.swift | 7 ++++++- iOSClient/Share/NCShareLinkCell.swift | 7 ++++++- iOSClient/Share/NCShareUserCell.swift | 17 ++++++++++++----- .../en.lproj/Localizable.strings | 1 + 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift index 9eeaa1fb07..d099a08d1b 100644 --- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift +++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift @@ -236,8 +236,6 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg } Task { - // TODO: Apply share token to download limit object - if (share.shareType == NCShareCommon().SHARE_TYPE_LINK || share.shareType == NCShareCommon().SHARE_TYPE_EMAIL) && NCPermissions().isPermissionToCanShare(share.permissions) { share.permissions = share.permissions - NCPermissions().permissionShareShare } diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 651fb8c911..61068dac75 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -51,6 +51,8 @@ class NCShare: UIViewController, NCSharePagingContent { let utility = NCUtility() let database = NCManageDatabase.shared + var shareLinksCount = 0 + var canReshare: Bool { return ((metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0) } @@ -180,6 +182,7 @@ class NCShare: UIViewController, NCSharePagingContent { @objc func reloadData() { shares = self.database.getTableShares(metadata: metadata) + shareLinksCount = 0 tableView.reloadData() } @@ -349,6 +352,7 @@ extension NCShare: UITableViewDataSource { } cell.isDirectory = metadata.directory cell.setupCellUI() + shareLinksCount += 1 return cell } @@ -361,7 +365,8 @@ extension NCShare: UITableViewDataSource { cell.tableShare = tableShare cell.isDirectory = metadata.directory cell.delegate = self - cell.setupCellUI() + cell.setupCellUI(titleAppendString: String(shareLinksCount)) + if tableShare.shareType == shareCommon.SHARE_TYPE_LINK { shareLinksCount += 1 } return cell } } else { diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index d19199f233..e3bef216cd 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -46,7 +46,7 @@ class NCShareLinkCell: UITableViewCell { tableShare = nil } - func setupCellUI() { + func setupCellUI(titleAppendString: String? = nil) { var menuImageName = "ellipsis" let permissions = NCPermissions() @@ -70,6 +70,11 @@ class NCShareLinkCell: UITableViewCell { imageItem.image = NCUtility().loadImage(named: "square.and.arrow.up.circle.fill", colors: [NCBrandColor.shared.iconImageColor2]) } else { labelTitle.text = NSLocalizedString("_share_link_", comment: "") + + if let titleAppendString { + labelTitle.text?.append(" (\(titleAppendString))") + } + if let tableShare = tableShare { if !tableShare.label.isEmpty { labelTitle.text? += " (\(tableShare.label))" diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index 290a2567e6..dc1e1b8d75 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -63,7 +63,9 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { target: self, selector: #selector(tapAvatarImage(_:)))] let permissions = NCPermissions() - labelTitle.text = tableShare.shareWithDisplayname + let typeText: String + labelTitle.text = (tableShare.shareWithDisplayname.isEmpty ? tableShare.shareWith : tableShare.shareWithDisplayname) + " (\(getType(tableShare)))" + labelTitle.lineBreakMode = .byTruncatingMiddle labelTitle.textColor = NCBrandColor.shared.textColor isUserInteractionEnabled = true labelQuickStatus.isHidden = false @@ -88,9 +90,6 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { btnQuickStatus.setTitle("", for: .normal) btnQuickStatus.contentHorizontalAlignment = .left -// if tableShare.permissions == permissions.permissionCreateShare { - // labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "") - // } else { if permissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "") } else if tableShare.permissions == permissions.permissionReadShare { // Read only @@ -98,7 +97,15 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { } else { // Custom permissions labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") } - // } + } + + private func getType(_ tableShare: tableShareV2) -> String { + switch tableShare.shareType { + case NCShareCommon().SHARE_TYPE_FEDERATED: + return NSLocalizedString("_remote_", comment: "") + default: + return "" + } } override func awakeFromNib() { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 79f96af0b7..7904335354 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -403,6 +403,7 @@ "_share_internal_link_des_" = "Only works for users with access to this file/folder."; "_share_reshare_disabled_" = "You are not allowed to reshare this file/folder."; "_share_reshare_restricted_" = "Note: You only have limited permission to reshare this file/folder."; +"_remote_" = "Remote"; "_no_transfer_" = "No transfers yet"; "_no_transfer_sub_" = "Uploads and downloads from this device will show up here"; From ebe9ab311f43e79c85c8c3bdf0282fc1c3e406f1 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Fri, 16 May 2025 15:27:56 +0200 Subject: [PATCH 25/29] PR changes Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 16 +--------------- iOSClient/Share/NCShareLinkCell.swift | 2 +- iOSClient/Share/NCShareUserCell.swift | 27 ++++++++++++++++++++++++--- 3 files changed, 26 insertions(+), 19 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 61068dac75..3155a6ec24 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -376,21 +376,7 @@ extension NCShare: UITableViewDataSource { cell.tableShare = tableShare cell.isDirectory = metadata.directory cell.delegate = self - cell.setupCellUI(userId: session.userId) - - let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: tableShare.shareWith) - let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) - - if results.image == nil { - cell.fileAvatarImageView?.image = utility.loadUserImage(for: tableShare.shareWith, displayName: tableShare.shareWithDisplayname, urlBase: metadata.urlBase) - } else { - cell.fileAvatarImageView?.image = results.image - } - - if !(results.tblAvatar?.loaded ?? false), - NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty { - NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: tableShare.shareWith, fileName: fileName, account: metadata.account, view: tableView)) - } + cell.setupCellUI(userId: session.userId, session: session, metadata: metadata) return cell } diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift index e3bef216cd..60787ab5fd 100644 --- a/iOSClient/Share/NCShareLinkCell.swift +++ b/iOSClient/Share/NCShareLinkCell.swift @@ -70,7 +70,7 @@ class NCShareLinkCell: UITableViewCell { imageItem.image = NCUtility().loadImage(named: "square.and.arrow.up.circle.fill", colors: [NCBrandColor.shared.iconImageColor2]) } else { labelTitle.text = NSLocalizedString("_share_link_", comment: "") - + if let titleAppendString { labelTitle.text?.append(" (\(titleAppendString))") } diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index dc1e1b8d75..d936281bd8 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -54,7 +54,7 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { set {} } - func setupCellUI(userId: String) { + func setupCellUI(userId: String, session: NCSession.Session, metadata: tableMetadata) { guard let tableShare = tableShare else { return } @@ -63,8 +63,13 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { target: self, selector: #selector(tapAvatarImage(_:)))] let permissions = NCPermissions() - let typeText: String - labelTitle.text = (tableShare.shareWithDisplayname.isEmpty ? tableShare.shareWith : tableShare.shareWithDisplayname) + " (\(getType(tableShare)))" + labelTitle.text = (tableShare.shareWithDisplayname.isEmpty ? tableShare.shareWith : tableShare.shareWithDisplayname) + + let type = getType(tableShare) + if !type.isEmpty { + labelTitle.text?.append(" (\(type))") + } + labelTitle.lineBreakMode = .byTruncatingMiddle labelTitle.textColor = NCBrandColor.shared.textColor isUserInteractionEnabled = true @@ -97,6 +102,22 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { } else { // Custom permissions labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "") } + + let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: tableShare.shareWith) + let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) + + if tableShare.shareType == NCShareCommon().SHARE_TYPE_CIRCLE { + fileAvatarImageView?.image = utility.loadImage(named: "person.crop.circle.dashed.circle", colors: [NCBrandColor.shared.iconImageColor]) + } else if results.image == nil { + fileAvatarImageView?.image = utility.loadUserImage(for: tableShare.shareWith, displayName: tableShare.shareWithDisplayname, urlBase: metadata.urlBase) + } else { + fileAvatarImageView?.image = results.image + } + + if !(results.tblAvatar?.loaded ?? false), + NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty { + NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: tableShare.shareWith, fileName: fileName, account: metadata.account, view: self)) + } } private func getType(_ tableShare: tableShareV2) -> String { From f736cd4c88b4ae489896c400d176a85a9ed0818b Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 19 May 2025 17:43:44 +0200 Subject: [PATCH 26/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 1 + iOSClient/Share/NCShareUserCell.swift | 10 +++++++--- .../Supporting Files/en.lproj/Localizable.strings | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 3155a6ec24..32ec856147 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -133,6 +133,7 @@ class NCShare: UIViewController, NCSharePagingContent { searchField.isUserInteractionEnabled = false searchField.alpha = 0.5 searchField.placeholder = NSLocalizedString("_share_reshare_disabled_", comment: "") + btnContact.isEnabled = false } searchFieldTopConstraint.constant = 45 diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift index d936281bd8..e4fe84e1e1 100644 --- a/iOSClient/Share/NCShareUserCell.swift +++ b/iOSClient/Share/NCShareUserCell.swift @@ -106,12 +106,14 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: tableShare.shareWith) let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) + imageItem.contentMode = .scaleAspectFill + if tableShare.shareType == NCShareCommon().SHARE_TYPE_CIRCLE { - fileAvatarImageView?.image = utility.loadImage(named: "person.crop.circle.dashed.circle", colors: [NCBrandColor.shared.iconImageColor]) + imageItem.image = utility.loadImage(named: "person.3.circle.fill", colors: [NCBrandColor.shared.iconImageColor]) } else if results.image == nil { - fileAvatarImageView?.image = utility.loadUserImage(for: tableShare.shareWith, displayName: tableShare.shareWithDisplayname, urlBase: metadata.urlBase) + imageItem.image = utility.loadUserImage(for: tableShare.shareWith, displayName: tableShare.shareWithDisplayname, urlBase: metadata.urlBase) } else { - fileAvatarImageView?.image = results.image + imageItem.image = results.image } if !(results.tblAvatar?.loaded ?? false), @@ -124,6 +126,8 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol { switch tableShare.shareType { case NCShareCommon().SHARE_TYPE_FEDERATED: return NSLocalizedString("_remote_", comment: "") + case NCShareCommon().SHARE_TYPE_ROOM: + return NSLocalizedString("_conversation_", comment: "") default: return "" } diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 7904335354..f41af7dae8 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -404,6 +404,7 @@ "_share_reshare_disabled_" = "You are not allowed to reshare this file/folder."; "_share_reshare_restricted_" = "Note: You only have limited permission to reshare this file/folder."; "_remote_" = "Remote"; +"_conversation_" = "Conversation"; "_no_transfer_" = "No transfers yet"; "_no_transfer_sub_" = "Uploads and downloads from this device will show up here"; From 64becc25d25ee828353faa7b077bd712028ba3da Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Mon, 19 May 2025 18:28:57 +0200 Subject: [PATCH 27/29] Prevent user from choosing themselves Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 32ec856147..e0ae4c64d4 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -261,10 +261,14 @@ extension NCShare: NCShareNetworkingDelegate { appearance.textColor = .darkGray for sharee in sharees { + let account = NCManageDatabase.shared.getTableAccount(account: metadata.account) + if sharee.shareWith == account?.user { continue } + var label = sharee.label if sharee.shareType == shareCommon.SHARE_TYPE_CIRCLE { label += " (\(sharee.circleInfo), \(sharee.circleOwner))" } + dropDown.dataSource.append(label) } From 3cf367dfe6bef75f9e2b13903df4a830687b5902 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Tue, 20 May 2025 10:26:37 +0200 Subject: [PATCH 28/29] Do not show already existing sharees Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index e0ae4c64d4..0c2d579148 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -260,15 +260,18 @@ extension NCShare: NCShareNetworkingDelegate { appearance.animationduration = 0.25 appearance.textColor = .darkGray + let account = NCManageDatabase.shared.getTableAccount(account: metadata.account) + let existingShares = NCManageDatabase.shared.getTableShares(metadata: metadata) + for sharee in sharees { - let account = NCManageDatabase.shared.getTableAccount(account: metadata.account) - if sharee.shareWith == account?.user { continue } + if sharee.shareWith == account?.user { continue } // do not show your own account + if let shares = existingShares.share, shares.contains(where: {$0.shareWith == sharee.shareWith}) { continue } // do not show already existing sharees var label = sharee.label if sharee.shareType == shareCommon.SHARE_TYPE_CIRCLE { label += " (\(sharee.circleInfo), \(sharee.circleOwner))" } - + dropDown.dataSource.append(label) } @@ -452,3 +455,5 @@ extension NCShare: UISearchBarDelegate { networking?.getSharees(searchString: searchString) } } + + From ff67bb1999434aa97b524c4396be23e24e5bc215 Mon Sep 17 00:00:00 2001 From: Milen Pivchev Date: Wed, 21 May 2025 15:56:30 +0200 Subject: [PATCH 29/29] WIP Signed-off-by: Milen Pivchev --- iOSClient/Share/NCShare.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift index 0c2d579148..7012f5b207 100644 --- a/iOSClient/Share/NCShare.swift +++ b/iOSClient/Share/NCShare.swift @@ -266,7 +266,7 @@ extension NCShare: NCShareNetworkingDelegate { for sharee in sharees { if sharee.shareWith == account?.user { continue } // do not show your own account if let shares = existingShares.share, shares.contains(where: {$0.shareWith == sharee.shareWith}) { continue } // do not show already existing sharees - + if metadata.ownerDisplayName == sharee.shareWith { continue } // do not show owner of the share var label = sharee.label if sharee.shareType == shareCommon.SHARE_TYPE_CIRCLE { label += " (\(sharee.circleInfo), \(sharee.circleOwner))"