123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- //
- // NCShareAdvancePermission.swift
- // Nextcloud
- //
- // Created by T-systems on 09/08/21.
- // Copyright © 2021 Marino Faggiana. All rights reserved.
- //
- import UIKit
- import NCCommunication
- import SVGKit
- import CloudKit
- class NCShareAdvancePermission: UITableViewController {
- var share: tableShare!
- var metadata: tableMetadata!
- var shareConfig: ShareConfig!
- override func viewDidLoad() {
- super.viewDidLoad()
- self.shareConfig = ShareConfig(isDirectory: metadata.directory, share: share)
- }
- override func viewWillLayoutSubviews() {
- super.viewWillLayoutSubviews()
- guard tableView.tableHeaderView == nil, tableView.tableFooterView == nil else { return }
- setupHeaderView()
- setupFooterView()
- }
- @objc func cancelClicked() {
- navigationController?.popViewController(animated: true)
- }
- @objc func nextClicked() {
- }
- func setupFooterView() {
- guard let footerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionFooter", owner: self, options: nil)?.first as? NCShareAdvancePermissionFooter) else { return }
- footerView.backgroundColor = .clear
- footerView.addShadow(location: .top)
- footerView.buttonCancel.addTarget(self, action: #selector(cancelClicked), for: .touchUpInside)
- footerView.buttonCancel.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal)
- footerView.buttonCancel.layer.cornerRadius = 10
- footerView.buttonCancel.layer.masksToBounds = true
- footerView.buttonCancel.layer.borderWidth = 1
- if NCManageDatabase.shared.getTableShare(account: share.account, idShare: share.idShare) == nil {
- footerView.buttonNext.setTitle(NSLocalizedString("_next_", comment: ""), for: .normal)
- } else {
- footerView.buttonNext.setTitle(NSLocalizedString("_apply_changes_", comment: ""), for: .normal)
- }
- footerView.buttonNext.layer.cornerRadius = 10
- footerView.buttonNext.layer.masksToBounds = true
- footerView.buttonNext.backgroundColor = NCBrandColor.shared.brand
- footerView.buttonNext.addTarget(self, action: #selector(nextClicked), for: .touchUpInside)
- footerView.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: 100)
- tableView.tableFooterView = footerView
- tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 100, 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
- }
- func setupHeaderView() {
- guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
- // headerView.backgroundColor = NCBrandColor.shared.secondarySystemBackground
- if FileManager.default.fileExists(atPath: CCUtility.getDirectoryProviderStorageIconOcId(metadata.ocId, etag: metadata.etag)) {
- headerView.fullWidthImageView.image = NCUtility.shared.getImageMetadata(metadata, for: headerView.frame.height)
- headerView.fullWidthImageView.contentMode = .scaleAspectFill
- headerView.imageView.isHidden = true
- } else {
- if metadata!.directory {
- headerView.imageView.image = UIImage(named: "folder")
- } else if !metadata.iconName.isEmpty {
- headerView.imageView.image = UIImage(named: metadata.iconName)
- } else {
- headerView.imageView.image = UIImage(named: "file")
- }
- }
- headerView.favorite.setNeedsUpdateConstraints()
- headerView.favorite.layoutIfNeeded()
- headerView.fileName.text = self.metadata?.fileNameView
- headerView.fileName.textColor = NCBrandColor.shared.label
- // headerView.favorite.addTarget(self, action: #selector(favoriteClicked), for: .touchUpInside)
- if metadata.favorite {
- headerView.favorite.setImage(NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
- } else {
- headerView.favorite.setImage(NCUtility.shared.loadImage(named: "star.fill", color: NCBrandColor.shared.systemGray, size: 24), for: .normal)
- }
- headerView.info.textColor = NCBrandColor.shared.secondaryLabel
- headerView.info.text = CCUtility.transformedSize(metadata.size) + ", " + CCUtility.dateDiff(metadata.date as Date)
- headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 200)
- tableView.tableHeaderView = headerView
- headerView.translatesAutoresizingMaskIntoConstraints = false
- headerView.heightAnchor.constraint(equalToConstant: 200).isActive = true
- headerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
- }
- override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
- if section == 0 { return NSLocalizedString("_advanced_", comment: "") }
- else if section == 1 { return NSLocalizedString("_misc_", comment: "") }
- else { return nil }
- }
- override func numberOfSections(in tableView: UITableView) -> Int {
- return 2
- }
- override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- if section == 0 { return shareConfig.permissions.count }
- else if section == 1 { return shareConfig.advanced.count }
- else { return 0 }
- }
- override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- guard let cell = shareConfig.cellFor(indexPath: indexPath) else { return UITableViewCell() }
- if let cell = cell as? DatePickerTableViewCell {
- cell.onReload = tableView.reloadData
- }
- return cell
- }
- override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
- guard let cellConfig = shareConfig.config(for: indexPath) else { return }
- if let cellConfig = cellConfig as? ToggleCellConfig {
- cellConfig.didSelect(for: share)
- tableView.reloadData()
- } else if let cellConfig = cellConfig as? Advanced {
- switch cellConfig {
- case .hideDownload:
- share.hideDownload.toggle()
- tableView.reloadData()
- case .expirationDate:
- let cell = tableView.cellForRow(at: indexPath) as? DatePickerTableViewCell
- cell?.textField.becomeFirstResponder()
- case .password:
- guard share.password.isEmpty else {
- share.password = ""
- tableView.reloadData()
- return
- }
- let alertController = UIAlertController(title: NSLocalizedString("_enforce_password_protection_", comment: ""), message: "", preferredStyle: .alert)
- alertController.addTextField { textField in
- textField.isSecureTextEntry = true
- }
- alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default) { _ in })
- let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) { _ in
- let password = alertController.textFields?.first?.text
- self.share.password = password ?? ""
- tableView.reloadData()
- }
- alertController.addAction(okAction)
- self.present(alertController, animated: true)
- case .note: break
- // TODO: Pushnote VC
- }
- } // else: unkown cell
- }
- }
- protocol ShareCellConfig {
- var title: String { get }
- func getCell(for share: tableShare) -> UITableViewCell
- func didSelect(for share: tableShare)
- }
- protocol ToggleCellConfig: ShareCellConfig {
- func isOn(for share: tableShare) -> Bool
- func didChange(_ share: tableShare, to newValue: Bool)
- }
- extension ToggleCellConfig {
- func getCell(for share: tableShare) -> UITableViewCell {
- return ToggleCell(isOn: isOn(for: share))
- }
- func didSelect(for share: tableShare) {
- didChange(share, to: isOn(for: share))
- }
- }
- protocol Permission: ToggleCellConfig {
- static var forDirectory: [Self] { get }
- static var forFile: [Self] { get }
- }
- enum UserPermission: CaseIterable, Permission {
- func didChange(_ share: tableShare, to newValue: Bool) {
-
- }
- func isOn(for share: tableShare) -> Bool {
- switch self {
- case .reshare: return CCUtility.isPermission(toCanShare: share.permissions)
- case .edit: return CCUtility.isPermission(toCanChange: share.permissions)
- case .create: return CCUtility.isPermission(toCanCreate: share.permissions)
- case .delete: return CCUtility.isPermission(toCanDelete: share.permissions)
- }
- }
- 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: tableShare, to newValue: Bool) {
-
- }
- func isOn(for share: tableShare) -> 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: tableShare) {
- switch self {
- case .hideDownload: share.hideDownload.toggle()
- case .expirationDate: return
- case .password: return
- case .note: return
- }
- }
- func getCell(for share: tableShare) -> UITableViewCell {
- switch self {
- case .hideDownload:
- return ToggleCell(isOn: share.hideDownload)
- case .expirationDate:
- return DatePickerTableViewCell(share: share)
- case .password: return ToggleCell(isOn: !share.password.isEmpty)
- case .note:
- let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareNote")
- cell.detailTextLabel?.text = share.note
- cell.accessoryType = .disclosureIndicator
- 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 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: tableShare
- init(isDirectory: Bool, share: tableShare) {
- 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 {
- init(isOn: Bool) {
- super.init(style: .default, reuseIdentifier: "toggleCell")
- if isOn {
- self.accessoryType = .checkmark
- } else {
- self.accessoryType = .none
- }
- }
- 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: tableShare) {
- super.init(style: .value1, reuseIdentifier: "shareExpDate")
- picker.datePickerMode = .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.sizeToFit()
- let doneButton = UIBarButtonItem(title: "_done_", style: .done) {
- self.resignFirstResponder()
- share.date = self.picker.date as NSDate
- self.onReload?()
- }
- let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
- let cancelButton = UIBarButtonItem(title: NSLocalizedString("_clear_", comment: ""), style: .plain) {
- self.resignFirstResponder()
- share.date = nil
- self.onReload?()
- }
- toolbar.setItems([cancelButton, spaceButton, doneButton], animated: false)
- textField.inputAccessoryView = toolbar
- textField.inputView = picker
- if let expDate = share.date {
- detailTextLabel?.text = DateFormatter.shareExpDate.string(from: expDate as Date)
- }
- }
-
- required public init?(coder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
- }
|