Browse Source

Fix details in share permossion

- factor out share advanced permission
- fix note textview & keyboard
  - use (scrollable) textview inside scrollview to enable users to type multiline, while not hiding the header in landscape
- fix footer safe area & padding & dynalic button title
- use NCShareCommon
- remove gesture delegate

Signed-off-by: Henrik Storch <henrik.storch@nextcloud.com>
Henrik Storch 3 years ago
parent
commit
1b428f52ed

+ 19 - 0
Nextcloud.xcodeproj/project.pbxproj

@@ -67,6 +67,10 @@
 		AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */; };
 		AF935067276B84E700BD078F /* NCMenu+FloatingPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */; };
 		AFA2AC8527849604008E1EA7 /* NCActivityCommentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFA2AC8427849604008E1EA7 /* NCActivityCommentView.swift */; };
+		AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */; };
+		AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; };
+		AFCE353727E4ED7B00FEA6C2 /* ShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* ShareCells.swift */; };
+		AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; };
 		AFD33240276A02C100F5AE02 /* UIApplication+Orientation.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */; };
 		D575039F27146F93008DC9DC /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extensions.swift */; };
 		D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; };
@@ -521,6 +525,10 @@
 		AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NCShareNewUserAddComment.swift; sourceTree = "<group>"; };
 		AF935066276B84E700BD078F /* NCMenu+FloatingPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCMenu+FloatingPanel.swift"; sourceTree = "<group>"; };
 		AFA2AC8427849604008E1EA7 /* NCActivityCommentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityCommentView.swift; sourceTree = "<group>"; };
+		AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIToolbar+Extension.swift"; sourceTree = "<group>"; };
+		AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = "<group>"; };
+		AFCE353627E4ED7B00FEA6C2 /* ShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareCells.swift; sourceTree = "<group>"; };
+		AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = "<group>"; };
 		AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIApplication+Orientation.swift"; sourceTree = "<group>"; };
 		D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = "<group>"; };
 		F700222B1EC479840080073F /* Custom.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Custom.xcassets; sourceTree = "<group>"; };
@@ -1069,6 +1077,7 @@
 			isa = PBXGroup;
 			children = (
 				AF93471627E2361E002537EE /* NCShareAdvancePermission.swift */,
+				AFCE353627E4ED7B00FEA6C2 /* ShareCells.swift */,
 				AF93471827E2361E002537EE /* NCShareAdvancePermissionFooter.swift */,
 				AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */,
 				AF93474D27E3F211002537EE /* NCShareNewUserAddComment.swift */,
@@ -1211,6 +1220,7 @@
 			children = (
 				F700510022DF63AC003A3356 /* NCShare.storyboard */,
 				F700510422DF6A89003A3356 /* NCShare.swift */,
+				AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */,
 				AF730AF727834B1400B7520E /* NCShare+NCCellDelegate.swift */,
 				AF93471327E235EB002537EE /* Advanced */,
 				F723B3DC22FC6D1C00301EFE /* NCShareCommentsCell.xib */,
@@ -1450,6 +1460,11 @@
 				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
 				AFD3323F276A02C000F5AE02 /* UIApplication+Orientation.swift */,
 				F7F4F10D27ECDC3C008676F9 /* UIApplication+Orientation.swift */,
+				F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */,
+				F79B645F26CA661600838ACA /* UIControl+Extensions.swift */,
+				AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */,
+				AF1A9B6327D0CA1E00F17A9E /* UIAlertController+Extension.swift */,
+				AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */,
 				AF7E504D27A2D8FF00B5E4AF /* UIBarButton+Extension.swift */,
 				F70CEF5523E9C7E50007035B /* UIColor+Extensions.swift */,
 				F79B645F26CA661600838ACA /* UIControl+Extensions.swift */,
@@ -2556,6 +2571,7 @@
 				F78A18B623CDD07D00F681F3 /* NCViewerRichWorkspaceWebView.swift in Sources */,
 				AFA2AC8527849604008E1EA7 /* NCActivityCommentView.swift in Sources */,
 				F716B75F26F09DF600D37EFC /* NCKTVHTTPCache.swift in Sources */,
+				AFCE353727E4ED7B00FEA6C2 /* ShareCells.swift in Sources */,
 				AF36077127BFA4E8001A243D /* ParallelWorker.swift in Sources */,
 				F75A9EE623796C6F0044CFCE /* NCNetworking.swift in Sources */,
 				F758B460212C56A400515F55 /* NCScan.swift in Sources */,
@@ -2567,6 +2583,7 @@
 				F72928A0253B0937009CA4FD /* NCMainNavigationController.swift in Sources */,
 				F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */,
 				F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */,
+				AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */,
 				F700510522DF6A89003A3356 /* NCShare.swift in Sources */,
 				F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */,
 				F785EE9D246196DF00B3F945 /* NCNetworkingE2EE.swift in Sources */,
@@ -2593,6 +2610,7 @@
 				F74AF3A4247FB6AE00AC767B /* NCUtilityFileSystem.swift in Sources */,
 				F7417DB3216CE925007D05F5 /* NCTrashSectionHeaderFooter.swift in Sources */,
 				F7239871253D86B600257F49 /* NCEmptyDataSet.swift in Sources */,
+				AFCE353327E4ED1900FEA6C2 /* UIToolbar+Extension.swift in Sources */,
 				8491B1CD273BBA82001C8C5B /* UIViewController+Menu.swift in Sources */,
 				F702F2F725EE5CED008F8E80 /* NCLogin.swift in Sources */,
 				F7E98C1627E0D0FC001F9F19 /* NCManageDatabase+Video.swift in Sources */,
@@ -2610,6 +2628,7 @@
 				F7C1EEA525053A9C00866ACC /* NCDataSource.swift in Sources */,
 				F713FF002472764100214AF6 /* UIImage+animatedGIF.m in Sources */,
 				F749C10B23C4A5340027D966 /* NCIntroCollectionViewCell.swift in Sources */,
+				AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */,
 				F718C24E254D507B00C5C256 /* NCViewerMediaDetailView.swift in Sources */,
 				F7381EE1218218C9000B1560 /* NCOffline.swift in Sources */,
 				F78071091EDAB65800EAFFF6 /* NSNotificationCenter+MainThread.m in Sources */,

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

@@ -0,0 +1,18 @@
+//
+//  DateFormatter+Extension.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 18.03.22.
+//  Copyright © 2022 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+extension DateFormatter {
+    static let shareExpDate: DateFormatter = {
+        let dateFormatter = DateFormatter()
+        dateFormatter.formatterBehavior = .behavior10_4
+        dateFormatter.dateStyle = .medium
+        return dateFormatter
+    }()
+}

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

@@ -0,0 +1,31 @@
+//
+//  UIToolbar+Extension.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 18.03.22.
+//  Copyright © 2022 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+extension UIToolbar {
+    static func toolbar(onClear: (() -> Void)?, completion: @escaping () -> Void) -> UIToolbar {
+        let toolbar = UIToolbar()
+        toolbar.sizeToFit()
+        var buttons: [UIBarButtonItem] = []
+        let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
+            completion()
+        }
+        buttons.append(doneButton)
+
+        if let onClear = onClear {
+            let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+            let clearButton = UIBarButtonItem(title: NSLocalizedString("_clear_", comment: ""), style: .plain) {
+                onClear()
+            }
+            buttons.append(contentsOf: [spaceButton, clearButton])
+        }
+        toolbar.setItems(buttons, animated: false)
+        return toolbar
+    }
+}

+ 0 - 1
iOSClient/Menu/NCShare+Menu.swift

@@ -44,7 +44,6 @@ extension NCShare {
                     guard
                         let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
                         let navigationController = self.navigationController, !share.isInvalidated else { return }
-                    // FIXME: Fatal - Object has been deleted or invalidated
                     advancePermission.networking = self.networking
                     advancePermission.share = tableShare(value: share)
                     advancePermission.metadata = self.metadata

+ 11 - 310
iOSClient/Share/Advanced/NCShareAdvancePermission.swift

@@ -11,26 +11,11 @@ import NCCommunication
 import SVGKit
 import CloudKit
 
-protocol NCShareDetail {
-    var share: TableShareable! { get }
-}
-
-extension NCShareDetail where Self: UIViewController {
-    func setNavigationTitle() {
-        title = NSLocalizedString("_share_", comment: "") + "  – "
-        if share.shareType == 0 {
-            title! += share.shareWithDisplayname.isEmpty ? share.shareWith : share.shareWithDisplayname
-        } else {
-            title! += share.label.isEmpty ? NSLocalizedString("_share_link_", comment: "") : share.label
-        }
-    }
-}
-
 class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDelegate, NCShareDetail {
     func dismissShareAdvanceView(shouldSave: Bool) {
         defer { navigationController?.popViewController(animated: true) }
         guard shouldSave else { return }
-        if NCManageDatabase.shared.getTableShare(account: share.account, idShare: share.idShare) == nil {
+        if isNewShare {
             networking?.createShare(option: share)
         } else {
             networking?.updateShare(option: share)
@@ -38,6 +23,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
     }
 
     var share: TableShareable!
+    var isNewShare: Bool { NCManageDatabase.shared.getTableShare(account: share.account, idShare: share.idShare) == nil }
     var metadata: tableMetadata!
     var shareConfig: ShareConfig!
     var networking: NCShareNetworking?
@@ -46,6 +32,10 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
         super.viewDidLoad()
         self.shareConfig = ShareConfig(isDirectory: metadata.directory, share: share)
         self.setNavigationTitle()
+        if #available(iOS 13.0, *) {
+            // disbale pull to dimiss
+            isModalInPresentation = true
+        }
     }
 
     override func viewWillLayoutSubviews() {
@@ -59,20 +49,19 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
         guard let footerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionFooter", owner: self, options: nil)?.first as? NCShareAdvancePermissionFooter) else { return }
         footerView.setupUI(delegate: self)
 
-        footerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 100)
+        footerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 120)
         tableView.tableFooterView = footerView
-        tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, right: 0)
+        tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 120, right: 0)
         footerView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
-        footerView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
-        footerView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
-        footerView.heightAnchor.constraint(equalToConstant: 100).isActive = true
+        footerView.heightAnchor.constraint(equalToConstant: 120).isActive = true
+        footerView.widthAnchor.constraint(equalTo: view.safeAreaLayoutGuide.widthAnchor).isActive = true
     }
 
     func setupHeaderView() {
         guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
         headerView.setupUI(with: metadata)
 
-        headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 200)
+        headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.width, height: 200)
         tableView.tableHeaderView = headerView
         headerView.translatesAutoresizingMaskIntoConstraints = false
         headerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
@@ -148,291 +137,3 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
         }
     }
 }
-
-protocol ShareCellConfig {
-    var title: String { get }
-    func getCell(for share: TableShareable) -> UITableViewCell
-    func didSelect(for share: TableShareable)
-}
-
-protocol ToggleCellConfig: ShareCellConfig {
-    func isOn(for share: TableShareable) -> Bool
-    func didChange(_ share: TableShareable, to newValue: Bool)
-}
-
-extension ToggleCellConfig {
-    func getCell(for share: TableShareable) -> UITableViewCell {
-        return ToggleCell(isOn: isOn(for: share))
-    }
-
-    func didSelect(for share: TableShareable) {
-        didChange(share, to: !isOn(for: share))
-    }
-}
-
-protocol Permission: ToggleCellConfig {
-    static var forDirectory: [Self] { get }
-    static var forFile: [Self] { get }
-}
-
-enum UserPermission: CaseIterable, Permission {
-    var permissionBitFlag: Int {
-        switch self {
-        case .reshare: return NCGlobal.shared.permissionShareShare
-        case .edit: return NCGlobal.shared.permissionUpdateShare
-        case .create: return NCGlobal.shared.permissionCreateShare
-        case .delete: return NCGlobal.shared.permissionDeleteShare
-        }
-    }
-
-    func didChange(_ share: TableShareable, to newValue: Bool) {
-        share.permissions ^= permissionBitFlag
-    }
-
-    func isOn(for share: TableShareable) -> Bool {
-        return (share.permissions & permissionBitFlag) != 0
-    }
-
-    case reshare, edit, create, delete
-    static let forDirectory: [UserPermission] = UserPermission.allCases
-    static let forFile: [UserPermission] = [.reshare, .edit]
-
-    var title: String {
-        switch self {
-        case .reshare: return NSLocalizedString("_share_can_reshare_", 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: "")
-        }
-    }
-}
-
-enum LinkPermission: Permission {
-    func didChange(_ share: TableShareable, to newValue: Bool) {
-        guard self != .allowEdit else {
-            // file
-            share.permissions = CCUtility.getPermissionsValue(
-                byCanEdit: newValue,
-                andCanCreate: newValue,
-                andCanChange: newValue,
-                andCanDelete: newValue,
-                andCanShare: false,
-                andIsFolder: false)
-            return
-        }
-        // can't deselect, only change
-        guard newValue == true else { return }
-        switch self {
-        case .allowEdit: return
-        case .viewOnly:
-            share.permissions = CCUtility.getPermissionsValue(
-                byCanEdit: false,
-                andCanCreate: false,
-                andCanChange: false,
-                andCanDelete: false,
-                andCanShare: false,
-                andIsFolder: true)
-        case .uploadEdit:
-            share.permissions = CCUtility.getPermissionsValue(
-                byCanEdit: true,
-                andCanCreate: true,
-                andCanChange: true,
-                andCanDelete: true,
-                andCanShare: false,
-                andIsFolder: true)
-        case .fileDrop:
-            share.permissions = NCGlobal.shared.permissionCreateShare
-        }
-    }
-
-    func isOn(for share: TableShareable) -> Bool {
-        switch self {
-        case .allowEdit: return CCUtility.isAnyPermission(toEdit: share.permissions)
-        case .viewOnly: return !CCUtility.isAnyPermission(toEdit: share.permissions) && share.permissions != NCGlobal.shared.permissionCreateShare
-        case .uploadEdit: return CCUtility.isAnyPermission(toEdit: share.permissions) && share.permissions != NCGlobal.shared.permissionCreateShare
-        case .fileDrop: return share.permissions == NCGlobal.shared.permissionCreateShare
-        }
-    }
-
-    var title: String {
-        switch self {
-        case .allowEdit: return NSLocalizedString("_share_can_change_", comment: "")
-        case .viewOnly: return NSLocalizedString("_share_read_only_", comment: "")
-        case .uploadEdit: return NSLocalizedString("_share_allow_upload_", comment: "")
-        case .fileDrop: return NSLocalizedString("_share_file_drop_", comment: "")
-        }
-    }
-
-    case allowEdit, viewOnly, uploadEdit, fileDrop
-    static let forDirectory: [LinkPermission] = [.viewOnly, .uploadEdit, .fileDrop]
-    static let forFile: [LinkPermission] = [.allowEdit]
-}
-
-enum Advanced: CaseIterable, ShareCellConfig {
-    func didSelect(for share: TableShareable) {
-        switch self {
-        case .hideDownload: share.hideDownload.toggle()
-        case .expirationDate: return
-        case .password: return
-        case .note: return
-        case .label: return
-        }
-    }
-
-    func getCell(for share: TableShareable) -> UITableViewCell {
-        switch self {
-        case .hideDownload:
-            return ToggleCell(isOn: share.hideDownload)
-        case .expirationDate:
-            return DatePickerTableViewCell(share: share)
-        case .password: return ToggleCell(isOn: !share.password.isEmpty, customIcons: ("lock", "lock.open"))
-        case .note:
-            let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareNote")
-            cell.detailTextLabel?.text = share.note
-            cell.accessoryType = .disclosureIndicator
-            return cell
-        case .label:
-            let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareLabel")
-            cell.detailTextLabel?.text = share.label
-            return cell
-        }
-    }
-
-    var title: String {
-        switch self {
-        case .hideDownload: return NSLocalizedString("_share_hide_download_", comment: "")
-        case .expirationDate: return NSLocalizedString("_share_expiration_date_", comment: "")
-        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 label, hideDownload, expirationDate, password, note
-    static let forLink: [Advanced] = Advanced.allCases
-    static let forUser: [Advanced] = [.expirationDate, .note]
-}
-
-struct ShareConfig {
-    let permissions: [Permission]
-    let advanced: [Advanced]
-    let share: TableShareable
-
-    init(isDirectory: Bool, share: TableShareable) {
-        self.share = share
-        let type: Permission.Type = share.shareType == 3 ? LinkPermission.self : UserPermission.self
-        self.permissions = isDirectory ? type.forDirectory : type.forFile
-        self.advanced = share.shareType == 3 ? Advanced.forLink : Advanced.forUser
-    }
-
-    func cellFor(indexPath: IndexPath) -> UITableViewCell? {
-        let cellConfig = config(for: indexPath)
-        let cell = cellConfig?.getCell(for: share)
-        cell?.textLabel?.text = cellConfig?.title
-        return cell
-    }
-
-    func didSelectRow(at indexPath: IndexPath) {
-        let cellConfig = config(for: indexPath)
-        cellConfig?.didSelect(for: share)
-    }
-
-    func config(for indexPath: IndexPath) -> ShareCellConfig? {
-        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 }
-    }
-}
-
-class ToggleCell: UITableViewCell {
-    typealias CustomToggleIcon = (onIconName: String?, offIconName: String?)
-    init(isOn: Bool, customIcons: CustomToggleIcon? = nil) {
-        super.init(style: .default, reuseIdentifier: "toggleCell")
-        guard let customIcons = customIcons,
-              let iconName = isOn ? customIcons.onIconName : customIcons.offIconName else {
-            self.accessoryType = isOn ? .checkmark : .none
-            return
-        }
-        let image = NCUtility.shared.loadImage(named: iconName, color: NCBrandColor.shared.brandElement)
-        self.accessoryView = UIImageView(image: image)
-    }
-
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-extension DateFormatter {
-    static let shareExpDate: DateFormatter = {
-        let dateFormatter = DateFormatter()
-        dateFormatter.formatterBehavior = .behavior10_4
-        dateFormatter.dateStyle = .medium
-        return dateFormatter
-    }()
-}
-
-open class DatePickerTableViewCell: UITableViewCell {
-    let picker = UIDatePicker()
-    let textField = UITextField()
-
-    var onReload: (() -> Void)?
-
-    init(share: TableShareable) {
-        super.init(style: .value1, reuseIdentifier: "shareExpDate")
-        picker.datePickerMode = .date
-        picker.minimumDate = Date()
-        if #available(iOS 13.4, *) {
-            picker.preferredDatePickerStyle = .wheels
-        }
-        picker.action(for: .valueChanged) { datePicker in
-            guard let datePicker = datePicker as? UIDatePicker else { return }
-            self.detailTextLabel?.text = DateFormatter.shareExpDate.string(from: datePicker.date)
-        }
-        accessoryView = textField
-
-        let toolbar = UIToolbar.toolbar {
-            self.resignFirstResponder()
-            share.expirationDate = nil
-            self.onReload?()
-        } completion: {
-            self.resignFirstResponder()
-            share.expirationDate = self.picker.date as NSDate
-            self.onReload?()
-        }
-
-        textField.inputAccessoryView = toolbar
-        textField.inputView = picker
-
-        if let expDate = share.expirationDate {
-            detailTextLabel?.text = DateFormatter.shareExpDate.string(from: expDate as Date)
-        }
-    }
-
-    required public init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-}
-
-extension UIToolbar {
-    static func toolbar(onClear: (() -> Void)?, completion: @escaping () -> Void) -> UIToolbar {
-        let toolbar = UIToolbar()
-        toolbar.sizeToFit()
-        var buttons: [UIBarButtonItem] = []
-        let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
-            completion()
-        }
-        buttons.append(doneButton)
-
-        if let onClear = onClear {
-            let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
-            let clearButton = UIBarButtonItem(title: NSLocalizedString("_clear_", comment: ""), style: .plain) {
-                onClear()
-            }
-            buttons.append(contentsOf: [spaceButton, clearButton])
-        }
-        toolbar.setItems(buttons, animated: false)
-        return toolbar
-    }
-}

+ 2 - 1
iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift

@@ -9,6 +9,7 @@
 import UIKit
 
 protocol NCShareAdvanceFotterDelegate: AnyObject {
+    var isNewShare: Bool { get }
     func dismissShareAdvanceView(shouldSave: Bool)
 }
 
@@ -28,7 +29,7 @@ class NCShareAdvancePermissionFooter: UIView {
         buttonCancel.layer.cornerRadius = 10
         buttonCancel.layer.masksToBounds = true
 
-        buttonNext.setTitle(NSLocalizedString("_save_", comment: ""), for: .normal)
+        buttonNext.setTitle(NSLocalizedString(delegate?.isNewShare == true ? "_share_" : "_save_", comment: ""), for: .normal)
         buttonNext.layer.cornerRadius = 10
         buttonNext.layer.masksToBounds = true
         buttonNext.backgroundColor = NCBrandColor.shared.brand

+ 9 - 7
iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.xib

@@ -4,17 +4,18 @@
     <dependencies>
         <deployment identifier="iOS"/>
         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="19519"/>
+        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
     </dependencies>
     <objects>
         <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
         <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
         <view contentMode="scaleToFill" id="iN0-l3-epB" customClass="NCShareAdvancePermissionFooter" customModule="Nextcloud" customModuleProvider="target">
-            <rect key="frame" x="0.0" y="0.0" width="746" height="100"/>
+            <rect key="frame" x="0.0" y="0.0" width="750" height="296"/>
             <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
             <subviews>
                 <button opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="249" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Mg2-Ou-yoX">
-                    <rect key="frame" x="16" y="16" width="349" height="50"/>
+                    <rect key="frame" x="16" y="212" width="351" height="50"/>
                     <color key="backgroundColor" red="0.8862745098" green="0.0" blue="0.4549019608" alpha="1" colorSpace="calibratedRGB"/>
                     <state key="normal" title="Send share"/>
                     <state key="highlighted">
@@ -22,7 +23,7 @@
                     </state>
                 </button>
                 <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="rCI-63-PtL">
-                    <rect key="frame" x="381" y="16" width="349" height="50"/>
+                    <rect key="frame" x="383" y="212" width="351" height="50"/>
                     <color key="backgroundColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                     <constraints>
                         <constraint firstAttribute="height" constant="50" id="vdI-sH-cTb"/>
@@ -32,22 +33,23 @@
                     <state key="normal" title="Cancel"/>
                 </button>
             </subviews>
+            <viewLayoutGuide key="safeArea" id="sWQ-1v-CIt"/>
             <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
             <constraints>
                 <constraint firstItem="rCI-63-PtL" firstAttribute="leading" secondItem="Mg2-Ou-yoX" secondAttribute="trailing" constant="16" id="4Px-cS-Hta"/>
-                <constraint firstItem="Mg2-Ou-yoX" firstAttribute="top" secondItem="iN0-l3-epB" secondAttribute="top" constant="16" id="53I-Ri-rEO"/>
-                <constraint firstItem="Mg2-Ou-yoX" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" constant="16" id="Jdi-WJ-zVF"/>
+                <constraint firstItem="Mg2-Ou-yoX" firstAttribute="leading" secondItem="sWQ-1v-CIt" secondAttribute="leading" constant="16" id="Jdi-WJ-zVF"/>
+                <constraint firstItem="sWQ-1v-CIt" firstAttribute="bottom" secondItem="Mg2-Ou-yoX" secondAttribute="bottom" id="SzT-aI-aUz"/>
                 <constraint firstItem="Mg2-Ou-yoX" firstAttribute="height" secondItem="rCI-63-PtL" secondAttribute="height" id="bNp-Nf-uMw"/>
                 <constraint firstItem="Mg2-Ou-yoX" firstAttribute="width" secondItem="rCI-63-PtL" secondAttribute="width" id="dfu-GZ-P99"/>
                 <constraint firstItem="rCI-63-PtL" firstAttribute="centerY" secondItem="Mg2-Ou-yoX" secondAttribute="centerY" id="hEl-ij-sMX"/>
-                <constraint firstAttribute="trailing" secondItem="rCI-63-PtL" secondAttribute="trailing" constant="16" id="s9t-ud-ofw"/>
+                <constraint firstItem="sWQ-1v-CIt" firstAttribute="trailing" secondItem="rCI-63-PtL" secondAttribute="trailing" constant="16" id="s9t-ud-ofw"/>
             </constraints>
             <freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
             <connections>
                 <outlet property="buttonCancel" destination="rCI-63-PtL" id="SoT-Ko-LL5"/>
                 <outlet property="buttonNext" destination="Mg2-Ou-yoX" id="F2d-L5-dHo"/>
             </connections>
-            <point key="canvasLocation" x="166.66666666666669" y="126.89732142857142"/>
+            <point key="canvasLocation" x="169.56521739130437" y="197.54464285714286"/>
         </view>
     </objects>
 </document>

+ 0 - 1
iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.swift

@@ -16,7 +16,6 @@ class NCShareAdvancePermissionHeader: UIView {
     @IBOutlet weak var fullWidthImageView: UIImageView!
 
     func setupUI(with metadata: tableMetadata) {
-        //        headerView.backgroundColor = NCBrandColor.shared.secondarySystemBackground
         if FileManager.default.fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
             fullWidthImageView.image = NCUtility.shared.getImageMetadata(metadata, for: frame.height)
             fullWidthImageView.contentMode = .scaleAspectFill

+ 20 - 0
iOSClient/Share/Advanced/NCShareNewUserAddComment.swift

@@ -27,6 +27,10 @@ class NCShareNewUserAddComment: UIViewController, NCShareDetail {
     override func viewDidLoad() {
         super.viewDidLoad()
         self.setNavigationTitle()
+
+        NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
+        NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
+
         guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
         headerContainerView.addSubview(headerView)
         headerView.frame = headerContainerView.frame
@@ -60,4 +64,20 @@ class NCShareNewUserAddComment: UIViewController, NCShareDetail {
         share.note = noteTextField.text
         onDismiss?()
     }
+
+    @objc func adjustForKeyboard(notification: Notification) {
+        guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
+              let globalTextViewFrame = noteTextField.superview?.convert(noteTextField.frame, to: nil) else { return }
+
+        let keyboardScreenEndFrame = keyboardValue.cgRectValue
+        let portionCovoredByLeyboard = globalTextViewFrame.maxY - keyboardScreenEndFrame.minY
+
+        if notification.name == UIResponder.keyboardWillHideNotification || portionCovoredByLeyboard < 0 {
+            noteTextField.contentInset = .zero
+        } else {
+            noteTextField.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: portionCovoredByLeyboard, right: 0)
+        }
+
+        noteTextField.scrollIndicatorInsets = noteTextField.contentInset
+    }
 }

+ 266 - 0
iOSClient/Share/Advanced/ShareCells.swift

@@ -0,0 +1,266 @@
+//
+//  ShareCells.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 18.03.22.
+//  Copyright © 2022 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+protocol ShareCellConfig {
+    var title: String { get }
+    func getCell(for share: TableShareable) -> UITableViewCell
+    func didSelect(for share: TableShareable)
+}
+
+protocol ToggleCellConfig: ShareCellConfig {
+    func isOn(for share: TableShareable) -> Bool
+    func didChange(_ share: TableShareable, to newValue: Bool)
+}
+
+extension ToggleCellConfig {
+    func getCell(for share: TableShareable) -> UITableViewCell {
+        return ToggleCell(isOn: isOn(for: share))
+    }
+
+    func didSelect(for share: TableShareable) {
+        didChange(share, to: !isOn(for: share))
+    }
+}
+
+protocol Permission: ToggleCellConfig {
+    static var forDirectory: [Self] { get }
+    static var forFile: [Self] { get }
+}
+
+enum UserPermission: CaseIterable, Permission {
+    var permissionBitFlag: Int {
+        switch self {
+        case .reshare: return NCGlobal.shared.permissionShareShare
+        case .edit: return NCGlobal.shared.permissionUpdateShare
+        case .create: return NCGlobal.shared.permissionCreateShare
+        case .delete: return NCGlobal.shared.permissionDeleteShare
+        }
+    }
+
+    func didChange(_ share: TableShareable, to newValue: Bool) {
+        share.permissions ^= permissionBitFlag
+    }
+
+    func isOn(for share: TableShareable) -> Bool {
+        return (share.permissions & permissionBitFlag) != 0
+    }
+
+    case reshare, edit, create, delete
+    static let forDirectory: [UserPermission] = UserPermission.allCases
+    static let forFile: [UserPermission] = [.reshare, .edit]
+
+    var title: String {
+        switch self {
+        case .reshare: return NSLocalizedString("_share_can_reshare_", 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: "")
+        }
+    }
+}
+
+enum LinkPermission: Permission {
+    func didChange(_ share: TableShareable, to newValue: Bool) {
+        guard self != .allowEdit else {
+            // file
+            share.permissions = CCUtility.getPermissionsValue(
+                byCanEdit: newValue,
+                andCanCreate: newValue,
+                andCanChange: newValue,
+                andCanDelete: newValue,
+                andCanShare: false,
+                andIsFolder: false)
+            return
+        }
+        // can't deselect, only change
+        guard newValue == true else { return }
+        switch self {
+        case .allowEdit: return
+        case .viewOnly:
+            share.permissions = CCUtility.getPermissionsValue(
+                byCanEdit: false,
+                andCanCreate: false,
+                andCanChange: false,
+                andCanDelete: false,
+                andCanShare: false,
+                andIsFolder: true)
+        case .uploadEdit:
+            share.permissions = CCUtility.getPermissionsValue(
+                byCanEdit: true,
+                andCanCreate: true,
+                andCanChange: true,
+                andCanDelete: true,
+                andCanShare: false,
+                andIsFolder: true)
+        case .fileDrop:
+            share.permissions = NCGlobal.shared.permissionCreateShare
+        }
+    }
+
+    func isOn(for share: TableShareable) -> Bool {
+        switch self {
+        case .allowEdit: return CCUtility.isAnyPermission(toEdit: share.permissions)
+        case .viewOnly: return !CCUtility.isAnyPermission(toEdit: share.permissions) && share.permissions != NCGlobal.shared.permissionCreateShare
+        case .uploadEdit: return CCUtility.isAnyPermission(toEdit: share.permissions) && share.permissions != NCGlobal.shared.permissionCreateShare
+        case .fileDrop: return share.permissions == NCGlobal.shared.permissionCreateShare
+        }
+    }
+
+    var title: String {
+        switch self {
+        case .allowEdit: return NSLocalizedString("_share_can_change_", comment: "")
+        case .viewOnly: return NSLocalizedString("_share_read_only_", comment: "")
+        case .uploadEdit: return NSLocalizedString("_share_allow_upload_", comment: "")
+        case .fileDrop: return NSLocalizedString("_share_file_drop_", comment: "")
+        }
+    }
+
+    case allowEdit, viewOnly, uploadEdit, fileDrop
+    static let forDirectory: [LinkPermission] = [.viewOnly, .uploadEdit, .fileDrop]
+    static let forFile: [LinkPermission] = [.allowEdit]
+}
+
+enum Advanced: CaseIterable, ShareCellConfig {
+    func didSelect(for share: TableShareable) {
+        switch self {
+        case .hideDownload: share.hideDownload.toggle()
+        case .expirationDate: return
+        case .password: return
+        case .note: return
+        case .label: return
+        }
+    }
+
+    func getCell(for share: TableShareable) -> UITableViewCell {
+        switch self {
+        case .hideDownload:
+            return ToggleCell(isOn: share.hideDownload)
+        case .expirationDate:
+            return DatePickerTableViewCell(share: share)
+        case .password: return ToggleCell(isOn: !share.password.isEmpty, customIcons: ("lock", "lock.open"))
+        case .note:
+            let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareNote")
+            cell.detailTextLabel?.text = share.note
+            cell.accessoryType = .disclosureIndicator
+            return cell
+        case .label:
+            let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareLabel")
+            cell.detailTextLabel?.text = share.label
+            return cell
+        }
+    }
+
+    var title: String {
+        switch self {
+        case .hideDownload: return NSLocalizedString("_share_hide_download_", comment: "")
+        case .expirationDate: return NSLocalizedString("_share_expiration_date_", comment: "")
+        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 label, hideDownload, expirationDate, password, note
+    static let forLink: [Advanced] = Advanced.allCases
+    static let forUser: [Advanced] = [.expirationDate, .note]
+}
+
+struct ShareConfig {
+    let permissions: [Permission]
+    let advanced: [Advanced]
+    let share: TableShareable
+
+    init(isDirectory: Bool, share: TableShareable) {
+        self.share = share
+        let type: Permission.Type = share.shareType == NCShareCommon.shared.SHARE_TYPE_LINK ? LinkPermission.self : UserPermission.self
+        self.permissions = isDirectory ? type.forDirectory : type.forFile
+        self.advanced = share.shareType == NCShareCommon.shared.SHARE_TYPE_LINK ? Advanced.forLink : Advanced.forUser
+    }
+
+    func cellFor(indexPath: IndexPath) -> UITableViewCell? {
+        let cellConfig = config(for: indexPath)
+        let cell = cellConfig?.getCell(for: share)
+        cell?.textLabel?.text = cellConfig?.title
+        return cell
+    }
+
+    func didSelectRow(at indexPath: IndexPath) {
+        let cellConfig = config(for: indexPath)
+        cellConfig?.didSelect(for: share)
+    }
+
+    func config(for indexPath: IndexPath) -> ShareCellConfig? {
+        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 }
+    }
+}
+
+class ToggleCell: UITableViewCell {
+    typealias CustomToggleIcon = (onIconName: String?, offIconName: String?)
+    init(isOn: Bool, customIcons: CustomToggleIcon? = nil) {
+        super.init(style: .default, reuseIdentifier: "toggleCell")
+        guard let customIcons = customIcons,
+              let iconName = isOn ? customIcons.onIconName : customIcons.offIconName else {
+            self.accessoryType = isOn ? .checkmark : .none
+            return
+        }
+        let image = NCUtility.shared.loadImage(named: iconName, color: NCBrandColor.shared.brandElement)
+        self.accessoryView = UIImageView(image: image)
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}
+
+open class DatePickerTableViewCell: UITableViewCell {
+    let picker = UIDatePicker()
+    let textField = UITextField()
+
+    var onReload: (() -> Void)?
+
+    init(share: TableShareable) {
+        super.init(style: .value1, reuseIdentifier: "shareExpDate")
+        picker.datePickerMode = .date
+        picker.minimumDate = Date()
+        if #available(iOS 13.4, *) {
+            picker.preferredDatePickerStyle = .wheels
+        }
+        picker.action(for: .valueChanged) { datePicker in
+            guard let datePicker = datePicker as? UIDatePicker else { return }
+            self.detailTextLabel?.text = DateFormatter.shareExpDate.string(from: datePicker.date)
+        }
+        accessoryView = textField
+
+        let toolbar = UIToolbar.toolbar {
+            self.resignFirstResponder()
+            share.expirationDate = nil
+            self.onReload?()
+        } completion: {
+            self.resignFirstResponder()
+            share.expirationDate = self.picker.date as NSDate
+            self.onReload?()
+        }
+
+        textField.inputAccessoryView = toolbar
+        textField.inputView = picker
+
+        if let expDate = share.expirationDate {
+            detailTextLabel?.text = DateFormatter.shareExpDate.string(from: expDate as Date)
+        }
+    }
+
+    required public init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+}

+ 87 - 0
iOSClient/Share/NCShare+Helper.swift

@@ -0,0 +1,87 @@
+//
+//  NCShare+Helper.swift
+//  Nextcloud
+//
+//  Created by Henrik Storch on 19.03.22.
+//  Copyright © 2022 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+import NCCommunication
+
+extension tableShare: TableShareable { }
+protocol TableShareable: AnyObject {
+    var shareType: Int { get set }
+    var permissions: Int { get set }
+
+    var account: String { get }
+
+    var idShare: Int { get set }
+    var shareWith: String { get set }
+//    var publicUpload: Bool? = false
+    var hideDownload: Bool { get set }
+    var password: String { get set }
+    var label: String { get set }
+    var note: String { get set }
+    var expirationDate: NSDate? { get set }
+    var shareWithDisplayname: String { get set }
+}
+
+extension TableShareable {
+    var expDateString: String? {
+        guard let date = expirationDate else { return nil }
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
+        return dateFormatter.string(from: date as Date)
+    }
+}
+
+class TableShareOptions: TableShareable {
+    var shareType: Int
+    var permissions: Int
+
+    let account: String
+
+    var idShare: Int = 0
+    var shareWith: String = ""
+//    var publicUpload: Bool? = false
+    var hideDownload: Bool = false
+    var password: String = ""
+    var label: String = ""
+    var note: String = ""
+    var expirationDate: NSDate?
+    var shareWithDisplayname: String = ""
+
+    private init(shareType: Int, metadata: tableMetadata, password: String? = nil) {
+        self.permissions = NCManageDatabase.shared.getCapabilitiesServerInt(account: metadata.account, elements: ["ocs", "data", "capabilities", "files_sharing", "default_permissions"]) & metadata.sharePermissionsCollaborationServices
+        self.shareType = shareType
+        self.account = metadata.account
+        if let password = password {
+            self.password = password
+        }
+    }
+
+    convenience init(sharee: NCCommunicationSharee, metadata: tableMetadata) {
+        self.init(shareType: sharee.shareType, metadata: metadata)
+        self.shareWith = sharee.shareWith
+    }
+
+    static func shareLink(metadata: tableMetadata, password: String?) -> TableShareOptions {
+        return TableShareOptions(shareType: NCShareCommon.shared.SHARE_TYPE_LINK, metadata: metadata, password: password)
+    }
+}
+
+protocol NCShareDetail {
+    var share: TableShareable! { get }
+}
+
+extension NCShareDetail where Self: UIViewController {
+    func setNavigationTitle() {
+        title = NSLocalizedString("_share_", comment: "") + "  – "
+        if share.shareType == NCShareCommon.shared.SHARE_TYPE_LINK {
+            title! += share.label.isEmpty ? NSLocalizedString("_share_link_", comment: "") : share.label
+        } else {
+            title! += share.shareWithDisplayname.isEmpty ? share.shareWith : share.shareWithDisplayname
+        }
+    }
+}

+ 76 - 55
iOSClient/Share/NCShare.storyboard

@@ -164,68 +164,89 @@
                         <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                         <subviews>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YMG-hf-HEX">
-                                <rect key="frame" x="0.0" y="200" width="414" height="536"/>
+                            <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="UNN-v3-g1S">
+                                <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
                                 <subviews>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="_share_note_recipient_" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3yF-lL-GwU">
-                                        <rect key="frame" x="16" y="56.333333333333314" width="161.66666666666666" height="18"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
-                                        <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
-                                    <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" canCancelContentTouches="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="VT0-1l-5HI">
-                                        <rect key="frame" x="16" y="106.33333333333329" width="382" height="377.66666666666674"/>
-                                        <color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
-                                        <inset key="scrollIndicatorInsets" minX="0.0" minY="0.0" maxX="10" maxY="0.0"/>
-                                        <color key="textColor" systemColor="labelColor"/>
-                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
-                                        <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
-                                        <userDefinedRuntimeAttributes>
-                                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
-                                                <integer key="value" value="10"/>
-                                            </userDefinedRuntimeAttribute>
-                                        </userDefinedRuntimeAttributes>
-                                        <connections>
-                                            <outlet property="delegate" destination="VvU-6J-pzy" id="cAt-UZ-6KT"/>
-                                        </connections>
-                                    </textView>
-                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sharing" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vkm-Pe-6qd">
-                                        <rect key="frame" x="16.000000000000004" y="24" width="61.333333333333343" height="20.333333333333329"/>
-                                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
-                                        <nil key="textColor"/>
-                                        <nil key="highlightedColor"/>
-                                    </label>
+                                    <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" translatesAutoresizingMaskIntoConstraints="NO" id="rZ9-oE-c21">
+                                        <rect key="frame" x="0.0" y="0.0" width="414" height="736"/>
+                                        <subviews>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qVy-Qr-W7j">
+                                                <rect key="frame" x="0.0" y="0.0" width="414" height="200"/>
+                                                <color key="backgroundColor" systemColor="systemBackgroundColor"/>
+                                                <constraints>
+                                                    <constraint firstAttribute="height" constant="200" id="GX8-Mb-uqf"/>
+                                                </constraints>
+                                            </view>
+                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="YMG-hf-HEX">
+                                                <rect key="frame" x="0.0" y="200" width="414" height="536"/>
+                                                <subviews>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="_share_note_recipient_" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="3yF-lL-GwU">
+                                                        <rect key="frame" x="16" y="56.333333333333314" width="161.66666666666666" height="18"/>
+                                                        <fontDescription key="fontDescription" type="system" pointSize="15"/>
+                                                        <color key="textColor" red="0.59999999999999998" green="0.59999999999999998" blue="0.59999999999999998" alpha="1" colorSpace="calibratedRGB"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                    <textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" canCancelContentTouches="NO" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="VT0-1l-5HI">
+                                                        <rect key="frame" x="16" y="106.33333333333329" width="382" height="377.66666666666674"/>
+                                                        <color key="backgroundColor" systemColor="secondarySystemBackgroundColor"/>
+                                                        <constraints>
+                                                            <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="100" id="wqE-G9-M95"/>
+                                                        </constraints>
+                                                        <inset key="scrollIndicatorInsets" minX="0.0" minY="0.0" maxX="10" maxY="0.0"/>
+                                                        <color key="textColor" systemColor="labelColor"/>
+                                                        <fontDescription key="fontDescription" type="system" pointSize="14"/>
+                                                        <textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
+                                                        <userDefinedRuntimeAttributes>
+                                                            <userDefinedRuntimeAttribute type="number" keyPath="cornerRadius">
+                                                                <integer key="value" value="10"/>
+                                                            </userDefinedRuntimeAttribute>
+                                                        </userDefinedRuntimeAttributes>
+                                                        <connections>
+                                                            <outlet property="delegate" destination="VvU-6J-pzy" id="cAt-UZ-6KT"/>
+                                                        </connections>
+                                                    </textView>
+                                                    <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sharing" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="vkm-Pe-6qd">
+                                                        <rect key="frame" x="16.000000000000004" y="24" width="61.333333333333343" height="20.333333333333329"/>
+                                                        <fontDescription key="fontDescription" type="system" weight="semibold" pointSize="17"/>
+                                                        <nil key="textColor"/>
+                                                        <nil key="highlightedColor"/>
+                                                    </label>
+                                                </subviews>
+                                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
+                                                <constraints>
+                                                    <constraint firstItem="3yF-lL-GwU" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="3yQ-Gl-Co9"/>
+                                                    <constraint firstItem="vkm-Pe-6qd" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="Auk-mC-Mie"/>
+                                                    <constraint firstItem="VT0-1l-5HI" firstAttribute="top" secondItem="3yF-lL-GwU" secondAttribute="bottom" constant="31.999999999999972" id="EpF-os-G1u"/>
+                                                    <constraint firstAttribute="bottom" secondItem="VT0-1l-5HI" secondAttribute="bottom" priority="100" constant="52" id="FYk-Lv-5f6"/>
+                                                    <constraint firstItem="vkm-Pe-6qd" firstAttribute="top" secondItem="YMG-hf-HEX" secondAttribute="top" constant="24" id="L0w-Cz-uK2"/>
+                                                    <constraint firstAttribute="trailing" secondItem="VT0-1l-5HI" secondAttribute="trailing" constant="16" id="TgX-1J-iTO"/>
+                                                    <constraint firstItem="VT0-1l-5HI" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="gEq-qv-UTR"/>
+                                                    <constraint firstAttribute="height" constant="536" id="oYk-ib-hVx"/>
+                                                    <constraint firstItem="3yF-lL-GwU" firstAttribute="top" secondItem="vkm-Pe-6qd" secondAttribute="bottom" constant="12" id="qtk-si-To3"/>
+                                                </constraints>
+                                            </view>
+                                        </subviews>
+                                    </stackView>
                                 </subviews>
-                                <color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
-                                <constraints>
-                                    <constraint firstItem="3yF-lL-GwU" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="3yQ-Gl-Co9"/>
-                                    <constraint firstItem="vkm-Pe-6qd" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="Auk-mC-Mie"/>
-                                    <constraint firstItem="VT0-1l-5HI" firstAttribute="top" secondItem="3yF-lL-GwU" secondAttribute="bottom" constant="31.999999999999972" id="EpF-os-G1u"/>
-                                    <constraint firstAttribute="bottom" secondItem="VT0-1l-5HI" secondAttribute="bottom" constant="52" id="FYk-Lv-5f6"/>
-                                    <constraint firstItem="vkm-Pe-6qd" firstAttribute="top" secondItem="YMG-hf-HEX" secondAttribute="top" constant="24" id="L0w-Cz-uK2"/>
-                                    <constraint firstAttribute="trailing" secondItem="VT0-1l-5HI" secondAttribute="trailing" constant="16" id="TgX-1J-iTO"/>
-                                    <constraint firstItem="VT0-1l-5HI" firstAttribute="leading" secondItem="YMG-hf-HEX" secondAttribute="leading" constant="16" id="gEq-qv-UTR"/>
-                                    <constraint firstItem="3yF-lL-GwU" firstAttribute="top" secondItem="vkm-Pe-6qd" secondAttribute="bottom" constant="12" id="qtk-si-To3"/>
-                                </constraints>
-                            </view>
-                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="qVy-Qr-W7j">
-                                <rect key="frame" x="0.0" y="0.0" width="414" height="200"/>
-                                <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                                 <constraints>
-                                    <constraint firstAttribute="height" constant="200" id="GX8-Mb-uqf"/>
+                                    <constraint firstItem="rZ9-oE-c21" firstAttribute="trailing" secondItem="cdt-uF-sLc" secondAttribute="trailing" id="JLe-cg-49Y"/>
+                                    <constraint firstItem="rZ9-oE-c21" firstAttribute="bottom" secondItem="cdt-uF-sLc" secondAttribute="bottom" id="fHi-hu-MpS"/>
+                                    <constraint firstItem="rZ9-oE-c21" firstAttribute="top" secondItem="cdt-uF-sLc" secondAttribute="top" id="od8-4k-3u3"/>
+                                    <constraint firstItem="rZ9-oE-c21" firstAttribute="width" secondItem="yeM-rG-mCp" secondAttribute="width" id="v9J-mK-SfO"/>
+                                    <constraint firstItem="rZ9-oE-c21" firstAttribute="leading" secondItem="cdt-uF-sLc" secondAttribute="leading" id="xze-Xh-I92"/>
                                 </constraints>
-                            </view>
+                                <viewLayoutGuide key="contentLayoutGuide" id="cdt-uF-sLc"/>
+                                <viewLayoutGuide key="frameLayoutGuide" id="yeM-rG-mCp"/>
+                            </scrollView>
                         </subviews>
                         <viewLayoutGuide key="safeArea" id="8hH-o3-iQD"/>
                         <color key="backgroundColor" systemColor="systemBackgroundColor"/>
                         <constraints>
-                            <constraint firstItem="YMG-hf-HEX" firstAttribute="centerX" secondItem="8hH-o3-iQD" secondAttribute="centerX" id="AMx-HK-399"/>
-                            <constraint firstItem="qVy-Qr-W7j" firstAttribute="leading" secondItem="8hH-o3-iQD" secondAttribute="leading" id="GgF-9f-6cX"/>
-                            <constraint firstItem="YMG-hf-HEX" firstAttribute="leading" secondItem="qVy-Qr-W7j" secondAttribute="leading" id="I0h-H2-lCU"/>
-                            <constraint firstItem="8hH-o3-iQD" firstAttribute="trailing" secondItem="qVy-Qr-W7j" secondAttribute="trailing" id="d5Y-gH-Wzt"/>
-                            <constraint firstItem="8hH-o3-iQD" firstAttribute="bottom" secondItem="YMG-hf-HEX" secondAttribute="bottom" id="gCl-hx-9Wg"/>
-                            <constraint firstItem="YMG-hf-HEX" firstAttribute="top" secondItem="qVy-Qr-W7j" secondAttribute="bottom" id="jgh-Ux-svW"/>
-                            <constraint firstItem="qVy-Qr-W7j" firstAttribute="top" secondItem="8hH-o3-iQD" secondAttribute="top" id="o0L-sP-cbb"/>
+                            <constraint firstItem="UNN-v3-g1S" firstAttribute="top" secondItem="8hH-o3-iQD" secondAttribute="top" id="UD6-u2-ckg"/>
+                            <constraint firstItem="8hH-o3-iQD" firstAttribute="bottom" secondItem="UNN-v3-g1S" secondAttribute="bottom" id="WzJ-jl-e33"/>
+                            <constraint firstItem="VT0-1l-5HI" firstAttribute="height" relation="lessThanOrEqual" secondItem="EtF-Pb-SYb" secondAttribute="height" constant="-150" id="h3K-2H-qDr"/>
+                            <constraint firstItem="UNN-v3-g1S" firstAttribute="leading" secondItem="8hH-o3-iQD" secondAttribute="leading" id="r39-yL-F9v"/>
+                            <constraint firstItem="8hH-o3-iQD" firstAttribute="trailing" secondItem="UNN-v3-g1S" secondAttribute="trailing" id="rNm-B2-hl3"/>
                         </constraints>
                     </view>
                     <navigationItem key="navigationItem" id="uC3-gg-Wos"/>
@@ -238,7 +259,7 @@
                 </viewController>
                 <placeholder placeholderIdentifier="IBFirstResponder" id="LJ3-hs-98b" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
             </objects>
-            <point key="canvasLocation" x="4260.8695652173919" y="-168.75"/>
+            <point key="canvasLocation" x="4261" y="-168"/>
         </scene>
         <!--Share Advance Permission-->
         <scene sceneID="59b-BB-FLA">

+ 3 - 69
iOSClient/Share/NCShare.swift

@@ -28,7 +28,7 @@ import DropDown
 import NCCommunication
 import MarqueeLabel
 
-class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingDelegate, NCSharePagingContent {
+class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent {
 
     @IBOutlet weak var viewContainerConstraint: NSLayoutConstraint!
     @IBOutlet weak var sharedWithYouByView: UIView!
@@ -192,10 +192,6 @@ class NCShare: UIViewController, UIGestureRecognizerDelegate, NCShareNetworkingD
         self.present(UIAlertController.sharePassword(completion: callback), animated: true)
     }
 
-    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
-        return gestureRecognizer.view == touch.view
-    }
-
     // MARK: - NCShareNetworkingDelegate
 
     func readShareCompleted() {
@@ -311,7 +307,7 @@ extension NCShare: UITableViewDataSource {
         guard let appDelegate = appDelegate, let tableShare = shares.share?[indexPath.row] else { return UITableViewCell() }
 
         // LINK
-        if tableShare.shareType == 3 {
+        if tableShare.shareType == NCShareCommon.shared.SHARE_TYPE_LINK {
             if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell {
                 cell.tableShare = tableShare
                 cell.delegate = self
@@ -319,7 +315,7 @@ extension NCShare: UITableViewDataSource {
                 return cell
             }
         } else {
-        // USER
+        // USER / GROUP etc.
             if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell {
                 cell.tableShare = tableShare
                 cell.delegate = self
@@ -333,65 +329,3 @@ extension NCShare: UITableViewDataSource {
         return UITableViewCell()
     }
 }
-
-extension tableShare: TableShareable { }
-protocol TableShareable: AnyObject {
-    var shareType: Int { get set }
-    var permissions: Int { get set }
-
-    var account: String { get }
-
-    var idShare: Int { get set }
-    var shareWith: String { get set }
-//    var publicUpload: Bool? = false
-    var hideDownload: Bool { get set }
-    var password: String { get set }
-    var label: String { get set }
-    var note: String { get set }
-    var expirationDate: NSDate? { get set }
-    var shareWithDisplayname: String { get set }
-}
-
-extension TableShareable {
-    var expDateString: String? {
-        guard let date = expirationDate else { return nil }
-        let dateFormatter = DateFormatter()
-        dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
-        return dateFormatter.string(from: date as Date)
-    }
-}
-
-class TableShareOptions: TableShareable {
-    var shareType: Int
-    var permissions: Int
-
-    let account: String
-
-    var idShare: Int = 0
-    var shareWith: String = ""
-//    var publicUpload: Bool? = false
-    var hideDownload: Bool = false
-    var password: String = ""
-    var label: String = ""
-    var note: String = ""
-    var expirationDate: NSDate?
-    var shareWithDisplayname: String = ""
-
-    private init(shareType: Int, metadata: tableMetadata, password: String? = nil) {
-        self.permissions = NCManageDatabase.shared.getCapabilitiesServerInt(account: metadata.account, elements: ["ocs", "data", "capabilities", "files_sharing", "default_permissions"]) & metadata.sharePermissionsCollaborationServices
-        self.shareType = shareType
-        self.account = metadata.account
-        if let password = password {
-            self.password = password
-        }
-    }
-
-    convenience init(sharee: NCCommunicationSharee, metadata: tableMetadata) {
-        self.init(shareType: sharee.shareType, metadata: metadata)
-        self.shareWith = sharee.shareWith
-    }
-
-    static func shareLink(metadata: tableMetadata, password: String?) -> TableShareOptions {
-        return TableShareOptions(shareType: 3, metadata: metadata, password: password)
-    }
-}

+ 0 - 1
iOSClient/Share/NCShareLinkCell.swift

@@ -57,7 +57,6 @@ class NCShareLinkCell: UITableViewCell {
         } else {
             labelTitle.text = NSLocalizedString("_share_link_", comment: "")
             if let tableShare = tableShare {
-                // FIXME: FATAL - Object has been deleted or invalidated
                 if !tableShare.label.isEmpty {
                     labelTitle.text? += " (\(tableShare.label))"
                 }