diff --git a/iOSClient/Favorites/NCFavorite.swift b/iOSClient/Favorites/NCFavorite.swift index 6dbf0324a2..78adb40e7f 100644 --- a/iOSClient/Favorites/NCFavorite.swift +++ b/iOSClient/Favorites/NCFavorite.swift @@ -32,6 +32,7 @@ class NCFavorite: NCCollectionViewCommon { titleCurrentFolder = NSLocalizedString("_favorites_", comment: "") layoutKey = NCGlobal.shared.layoutViewFavorite enableSearchBar = false + headerMenuButtonsView = true headerRichWorkspaceDisable = true emptyImage = utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite]) emptyTitle = "_favorite_no_files_" diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 3fd5d3a08e..e414754e19 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -67,7 +67,8 @@ class NCFiles: NCCollectionViewCommon { } self.titleCurrentFolder = self.getNavigationTitle() - self.setNavigationLeftItems() + ///Magentacloud branding changes hide user account button on left navigation bar +// self.setNavigationLeftItems() self.reloadDataSource() self.reloadDataSourceNetwork() diff --git a/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift b/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift index 8a315baa1d..da144feb4a 100644 --- a/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift +++ b/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift @@ -40,6 +40,7 @@ protocol NCCellProtocol { var fileMoreImage: UIImageView? { get set } var cellSeparatorView: UIView? { get set } var indexPath: IndexPath { get set } + var fileSharedLabel: UILabel? { get set } func titleInfoTrailingDefault() func titleInfoTrailingFull() @@ -110,6 +111,10 @@ extension NCCellProtocol { get { return nil } set {} } + var fileSharedLabel: UILabel? { + get { return nil } + set { } + } func titleInfoTrailingDefault() {} func titleInfoTrailingFull() {} diff --git a/iOSClient/Main/Collection Common/Cell/NCListCell.swift b/iOSClient/Main/Collection Common/Cell/NCListCell.swift index 8f13107769..bf7180c753 100755 --- a/iOSClient/Main/Collection Common/Cell/NCListCell.swift +++ b/iOSClient/Main/Collection Common/Cell/NCListCell.swift @@ -28,7 +28,6 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto @IBOutlet weak var imageSelect: UIImageView! @IBOutlet weak var imageStatus: UIImageView! @IBOutlet weak var imageFavorite: UIImageView! - @IBOutlet weak var imageFavoriteBackground: UIImageView! @IBOutlet weak var imageLocal: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var labelInfo: UILabel! @@ -39,12 +38,9 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var progressView: UIProgressView! @IBOutlet weak var separator: UIView! - @IBOutlet weak var tag0: UILabel! - @IBOutlet weak var tag1: UILabel! - + @IBOutlet weak var labelShared: UILabel! @IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint! @IBOutlet weak var separatorHeightConstraint: NSLayoutConstraint! - @IBOutlet weak var titleTrailingConstraint: NSLayoutConstraint! @IBOutlet weak var subInfoTrailingConstraint: NSLayoutConstraint! private var objectId = "" @@ -85,6 +81,10 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto get { return progressView } set { progressView = newValue } } + var fileSelectImage: UIImageView? { + get { return imageSelect } + set { imageSelect = newValue } + } var fileStatusImage: UIImageView? { get { return imageStatus } set { imageStatus = newValue } @@ -109,7 +109,10 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto get { return separator } set { separator = newValue } } - + var fileSharedLabel: UILabel? { + get { return labelShared } + set { labelShared = newValue } + } override func awakeFromNib() { super.awakeFromNib() @@ -137,23 +140,14 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto labelTitle.text = "" labelInfo.text = "" - labelSubinfo.text = "" - labelTitle.textColor = NCBrandColor.shared.textColor - labelInfo.textColor = NCBrandColor.shared.textColor2 - labelSubinfo.textColor = NCBrandColor.shared.textColor2 - - imageFavoriteBackground.isHidden = true + labelTitle.textColor = .label + labelInfo.textColor = .systemGray + labelSubinfo.textColor = .systemGray } override func prepareForReuse() { super.prepareForReuse() imageItem.backgroundColor = nil - if fileFavoriteImage?.image != nil { - imageFavoriteBackground.isHidden = false - } else { - imageFavoriteBackground.isHidden = true - } - accessibilityHint = nil accessibilityLabel = nil accessibilityValue = nil @@ -190,12 +184,10 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto } func titleInfoTrailingFull() { - titleTrailingConstraint.constant = 10 subInfoTrailingConstraint.constant = 10 } func titleInfoTrailingDefault() { - titleTrailingConstraint.constant = 90 subInfoTrailingConstraint.constant = 90 } @@ -257,52 +249,14 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto } func writeInfoDateSize(date: NSDate, size: Int64) { - labelInfo.text = NCUtility().dateDiff(date as Date) - labelSubinfo.text = " · " + NCUtilityFileSystem().transformedSize(size) + labelInfo.text = NCUtility().dateDiff(date as Date) + " · " + NCUtilityFileSystem().transformedSize(size) + labelSubinfo.text = "" } func setAccessibility(label: String, value: String) { accessibilityLabel = label accessibilityValue = value } - - func setTags(tags: [String]) { - if tags.isEmpty { - tag0.isHidden = true - tag1.isHidden = true - labelInfo.isHidden = false - labelSubinfo.isHidden = false - } else { - tag0.isHidden = false - tag1.isHidden = true - labelInfo.isHidden = true - labelSubinfo.isHidden = true - - if let tag = tags.first { - tag0.text = tag - if tags.count > 1 { - tag1.isHidden = false - tag1.text = "+\(tags.count - 1)" - } - } - } - } - - func setIconOutlines() { - imageFavoriteBackground.isHidden = fileFavoriteImage?.image == nil - - if imageStatus.image != nil { - imageStatus.makeCircularBackground(withColor: .systemBackground) - } else { - imageStatus.backgroundColor = .clear - } - - if imageLocal.image != nil { - imageLocal.makeCircularBackground(withColor: .systemBackground) - } else { - imageLocal.backgroundColor = .clear - } - } } protocol NCListCellDelegate: AnyObject { diff --git a/iOSClient/Main/Collection Common/Cell/NCListCell.xib b/iOSClient/Main/Collection Common/Cell/NCListCell.xib index 8422b1cfae..a9b542e428 100755 --- a/iOSClient/Main/Collection Common/Cell/NCListCell.xib +++ b/iOSClient/Main/Collection Common/Cell/NCListCell.xib @@ -1,276 +1,191 @@ - + - + - - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift index cc4403d047..bd5e8b23bf 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift @@ -109,21 +109,8 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { default: cell.filePreviewImageView?.image = NCImageCache.images.iconFile } - if !metadata.iconUrl.isEmpty { - if let ownerId = getAvatarFromIconUrl(metadata: metadata) { - let fileName = metadata.userBaseUrl + "-" + ownerId + ".png" - downloadAvatar(fileName: fileName, user: ownerId, dispalyName: nil) - } - } } } - /// AVATAR - if !metadata.ownerId.isEmpty, - metadata.ownerId != appDelegate.userId, - appDelegate.account == metadata.account { - let fileName = metadata.userBaseUrl + "-" + metadata.ownerId + ".png" - downloadAvatar(fileName: fileName, user: metadata.ownerId, dispalyName: metadata.ownerDisplayName) - } } func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { @@ -159,6 +146,7 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell = listCell } guard let metadata = dataSource.cellForItemAt(indexPath: indexPath) else { return cell } + let shares = NCManageDatabase.shared.getTableShares(metadata: metadata) defer { if NCGlobal.shared.disableSharesView || !metadata.isSharable() { @@ -259,18 +247,29 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } // Share image - if isShare { + if isShare || !metadata.shareType.isEmpty { cell.fileSharedImage?.image = NCImageCache.images.shared - } else if !metadata.shareType.isEmpty { - metadata.shareType.contains(3) ? - (cell.fileSharedImage?.image = NCImageCache.images.shareByLink) : - (cell.fileSharedImage?.image = NCImageCache.images.shared) } else { - cell.fileSharedImage?.image = NCImageCache.images.canShare + cell.fileSharedImage?.image = NCImageCache.images.canShare.image(color: NCBrandColor.shared.gray60, size: 50) + cell.fileSharedLabel?.text = "" } if appDelegate.account != metadata.account { cell.fileSharedImage?.image = NCImageCache.images.shared } + cell.fileSharedLabel?.text = NSLocalizedString("_shared_", comment: "") + cell.fileSharedLabel?.textColor = NCBrandColor.shared.customer + if (!metadata.shareType.isEmpty || !(shares.share?.isEmpty ?? true) || (shares.firstShareLink != nil)){ + cell.fileSharedImage?.image = cell.fileSharedImage?.image?.imageColor(NCBrandColor.shared.customer) + } else { + cell.fileSharedImage?.image = NCImageCache.images.canShare.image(color: NCBrandColor.shared.gray60, size: 50) + cell.fileSharedLabel?.text = "" + } + + if metadata.permissions.contains("S"), (metadata.permissions.range(of: "S") != nil) { + cell.fileSharedImage?.image = NCImageCache.images.sharedWithMe + cell.fileSharedLabel?.text = NSLocalizedString("_recieved_", comment: "") + cell.fileSharedLabel?.textColor = NCBrandColor.shared.notificationAction + } // Button More if metadata.isInTransfer || metadata.isWaitingTransfer { @@ -375,12 +374,22 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } cell.setIconOutlines() + + // Hide lines on iPhone + if !UIDevice.current.orientation.isLandscape && UIDevice.current.model.hasPrefix("iPhone") { + cell.cellSeparatorView?.isHidden = true + cell.fileSharedLabel?.isHidden = true + }else{ + cell.cellSeparatorView?.isHidden = false + cell.fileSharedLabel?.isHidden = false + } + return cell } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - if kind == UICollectionView.elementKindSectionHeader || kind == mediaSectionHeader { + if kind == UICollectionView.elementKindSectionHeader { if dataSource.getMetadataSourceForAllSections().isEmpty { @@ -426,6 +435,13 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFirstHeader", for: indexPath) as? NCSectionFirstHeader else { return NCSectionFirstHeader() } let (_, heightHeaderRichWorkspace, heightHeaderSection) = getHeaderHeight(section: indexPath.section) self.sectionFirstHeader = header + if layoutForView?.layout == NCGlobal.shared.layoutGrid { + header.setImageSwitchList() + header.buttonSwitch.accessibilityLabel = NSLocalizedString("_list_view_", comment: "") + } else { + header.setImageSwitchGrid() + header.buttonSwitch.accessibilityLabel = NSLocalizedString("_grid_view_", comment: "") + } header.delegate = self if !isSearchingMode, headerMenuTransferView, let ocId = NCNetworking.shared.transferInForegorund?.ocId { @@ -434,6 +450,14 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } else { header.setViewTransfer(isHidden: true) } + + if headerMenuButtonsView { + header.setStatusButtonsView(enable: !dataSource.getMetadataSourceForAllSections().isEmpty) + header.setButtonsView(height: NCGlobal.shared.heightButtonsView) + header.setSortedTitle(layoutForView?.titleButtonHeader ?? "") + } else { + header.setButtonsView(height: 0) + } header.setRichWorkspaceHeight(heightHeaderRichWorkspace) header.setRichWorkspaceText(richWorkspaceText) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift index 39e0dcebcc..1ac753e8cc 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift @@ -141,7 +141,8 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate { if editMode { navigationItem.leftBarButtonItems = nil } else { - setNavigationLeftItems() + ///Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() } setNavigationRightItems() @@ -150,4 +151,127 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate { searchController(enabled: !editMode) collectionView.reloadData() } + + /// If explicit `isOn` is not set, it will invert `isEditMode` + func toggleSelect(isOn: Bool? = nil) { + DispatchQueue.main.async { + self.isEditMode = isOn ?? !self.isEditMode + self.selectOcId.removeAll() + self.setNavigationLeftItems() + self.setNavigationRightItems() + self.collectionView.reloadData() + } + } + + func createMenuActions() -> [NCMenuAction] { + var actions = [NCMenuAction]() + + actions.append(.cancelAction { + self.toggleSelect() + }) + if selectOcId.count != dataSource.getMetadataSourceForAllSections().count { + actions.append(.selectAllAction(action: selectAll)) + } + + guard !selectOcId.isEmpty else { return actions } + + actions.append(.seperator(order: 0)) + + var selectedMetadatas: [tableMetadata] = [] + var selectedMediaMetadatas: [tableMetadata] = [] + var isAnyOffline = false + var isAnyFolder = false + var isAnyLocked = false + var canUnlock = true + var canOpenIn = false + var isDirectoryE2EE = false + + for ocId in selectOcId { + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { continue } + if metadata.e2eEncrypted { + selectOcId.removeAll(where: {$0 == metadata.ocId}) + } else { + selectedMetadatas.append(metadata) + } + + if [NKCommon.TypeClassFile.image.rawValue, NKCommon.TypeClassFile.video.rawValue].contains(metadata.classFile) { + selectedMediaMetadatas.append(metadata) + } + if metadata.directory { isAnyFolder = true } + if metadata.lock { + isAnyLocked = true + if metadata.lockOwner != appDelegate.userId { + canUnlock = false + } + } + + guard !isAnyOffline else { continue } + if metadata.directory, + let directory = NCManageDatabase.shared.getTableDirectory(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@", appDelegate.account, metadata.serverUrl + "/" + metadata.fileName)) { + isAnyOffline = directory.offline + } else if let localFile = NCManageDatabase.shared.getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) { + isAnyOffline = localFile.offline + } // else: file is not offline, continue + + if !metadata.directory { + canOpenIn = true + } + + if metadata.isDirectoryE2EE { + isDirectoryE2EE = true + } + } + + if canOpenIn { + actions.append(.share(selectedMetadatas: selectedMetadatas, viewController: self, completion: { self.toggleSelect() })) + } + + if !isAnyFolder, canUnlock, !NCGlobal.shared.capabilityFilesLockVersion.isEmpty { + actions.append(.lockUnlockFiles(shouldLock: !isAnyLocked, metadatas: selectedMetadatas, completion: { self.toggleSelect() })) + } + + if !selectedMediaMetadatas.isEmpty { + var title: String = NSLocalizedString("_save_selected_files_", comment: "") + var icon = NCUtility().loadImage(named: "save_files",colors: [NCBrandColor.shared.iconImageColor]) + if selectedMediaMetadatas.allSatisfy({ NCManageDatabase.shared.getMetadataLivePhoto(metadata: $0) != nil }) { + title = NSLocalizedString("_livephoto_save_", comment: "") + icon = NCUtility().loadImage(named: "livephoto") + } + + actions.append(NCMenuAction( + title: title, + icon: icon, + order: 0, + action: { _ in + for metadata in selectedMediaMetadatas { + if let metadataMOV = NCManageDatabase.shared.getMetadataLivePhoto(metadata: metadata) { + NCNetworking.shared.saveLivePhotoQueue.addOperation(NCOperationSaveLivePhoto(metadata: metadata, metadataMOV: metadataMOV, hudView: self.view)) + } else { + if NCUtilityFileSystem().fileProviderStorageExists(metadata) { + NCActionCenter.shared.saveAlbum(metadata: metadata, controller: self.tabBarController as? NCMainTabBarController) + } else { + if NCNetworking.shared.downloadQueue.operations.filter({ ($0 as? NCOperationDownload)?.metadata.ocId == metadata.ocId }).isEmpty { + NCNetworking.shared.downloadQueue.addOperation(NCOperationDownload(metadata: metadata, selector: NCGlobal.shared.selectorSaveAlbum)) + } + } + } + } + self.toggleSelect() + } + ) + ) + } + actions.append(.setAvailableOfflineAction(selectedMetadatas: selectedMetadatas, isAnyOffline: isAnyOffline, viewController: self, completion: { + self.reloadDataSource() + self.toggleSelect() + })) + + if !isDirectoryE2EE { + actions.append(.moveOrCopyAction(selectedMetadatas: selectedMetadatas, viewController: self, indexPath: [], completion: { self.toggleSelect() })) + actions.append(.copyAction(selectOcId: selectOcId, viewController: self, completion: { self.toggleSelect() })) + } + actions.append(.deleteAction(selectedMetadatas: selectedMetadatas, indexPaths: [], viewController: self, completion: { self.toggleSelect() })) + return actions + } + } diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift index a9b5b77b97..11a580f6a3 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift @@ -39,7 +39,7 @@ extension NCCollectionViewCommon: SwipeCollectionViewCellDelegate { } } favoriteAction.backgroundColor = NCBrandColor.shared.yellowFavorite - favoriteAction.image = .init(systemName: metadata.favorite ? "star.slash.fill" : "star.fill") + favoriteAction.image = .init(systemName: "star.fill") favoriteAction.transitionDelegate = scaleTransition favoriteAction.hidesWhenSelected = true diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 11bd2566ee..9c3ad88e9a 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -66,6 +66,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var attributesZoomIn: UIMenuElement.Attributes = [] var attributesZoomOut: UIMenuElement.Attributes = [] let maxImageGrid: CGFloat = 7 + var headerMenu: NCSectionFirstHeader? // DECLARE var layoutKey = "" @@ -74,6 +75,7 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var enableSearchBar: Bool = false var headerMenuTransferView = false var headerRichWorkspaceDisable: Bool = false + var headerMenuButtonsView: Bool = true var emptyImage: UIImage? var emptyTitle: String = "" var emptyDescription: String = "" @@ -166,7 +168,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS navigationItem.title = titleCurrentFolder isEditMode = false - setNavigationLeftItems() + /// Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() setNavigationRightItems() layoutForView = NCManageDatabase.shared.getLayoutForView(account: appDelegate.account, key: layoutKey, serverUrl: serverUrl) @@ -315,8 +318,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS guard let userInfo = notification.userInfo as NSDictionary?, let error = userInfo["error"] as? NKError, error.errorCode != NCGlobal.shared.errorNotModified else { return } - - setNavigationLeftItems() + /// Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() } @objc func changeTheming() { @@ -843,14 +846,16 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } if isEditMode { - tabBarSelect.update(selectOcId: selectOcId, metadatas: getSelectedMetadatas(), userId: appDelegate.userId) - tabBarSelect.show() + /// Magentacloud branding changes hide options on bottom tab bar +// tabBarSelect.update(selectOcId: selectOcId, metadatas: getSelectedMetadatas(), userId: appDelegate.userId) +// tabBarSelect.show() let select = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .done) { self.setEditMode(false) } navigationItem.rightBarButtonItems = [select] } else if navigationItem.rightBarButtonItems == nil || (!isEditMode && !tabBarSelect.isHidden()) { - tabBarSelect.hide() + /// Magentacloud branding changes hide options on bottom tab bar +// tabBarSelect.hide() let menuButton = UIBarButtonItem(image: utility.loadImage(named: "ellipsis.circle"), menu: UIMenu(children: createMenuActions())) menuButton.tintColor = NCBrandColor.shared.iconImageColor if layoutKey == NCGlobal.shared.layoutViewFiles { @@ -867,10 +872,26 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } else { navigationItem.rightBarButtonItems?.first?.menu = navigationItem.rightBarButtonItems?.first?.menu?.replacingChildren(createMenuActions()) } - // fix, if the tabbar was hidden before the update, set it in hidden - if isTabBarHidden, isTabBarSelectHidden { - self.tabBarController?.tabBar.isHidden = true + + if isEditMode { + let more = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .plain) { self.presentMenu(with: self.createMenuActions())} + navigationItem.rightBarButtonItems = [more] + } else { + let select = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain) { self.toggleSelect() } + if layoutKey == NCGlobal.shared.layoutViewFiles { + let notification = UIBarButtonItem(image: utility.loadImage(named: "bell"), style: .plain) { + if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification { + self.navigationController?.pushViewController(viewController, animated: true) + } + } + notification.tintColor = NCBrandColor.shared.iconImageColor + navigationItem.rightBarButtonItems = [select, notification] + } else { + navigationItem.rightBarButtonItems = [select] + } } + guard layoutKey == NCGlobal.shared.layoutViewFiles else { return } + navigationItem.title = titleCurrentFolder } func getNavigationTitle() -> String { @@ -1077,6 +1098,28 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } } + func tapButtonSwitch(_ sender: Any) { + guard !isTransitioning else { return } + isTransitioning = true + + guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: appDelegate.account, key: layoutKey, serverUrl: serverUrl) else { return } + + if layoutForView.layout == NCGlobal.shared.layoutGrid { + layoutForView.layout = NCGlobal.shared.layoutList + } else { + layoutForView.layout = NCGlobal.shared.layoutGrid + } + self.layoutForView = NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) + self.collectionView.reloadData() + self.collectionView.collectionViewLayout.invalidateLayout() + self.collectionView.setCollectionViewLayout(layoutForView.layout == NCGlobal.shared.layoutList ? self.listLayout : self.gridLayout, animated: true) {_ in self.isTransitioning = false } + } + + func tapButtonOrder(_ sender: Any) { + let sortMenu = NCSortMenu() + sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) + } + func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) { } @@ -1275,6 +1318,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS } else { NCNetworking.shared.transferInForegorund = nil } + if headerMenuButtonsView { + size += NCGlobal.shared.heightButtonsView + } return size } diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift index e71baa5fae..9e53a1cdad 100644 --- a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift @@ -25,12 +25,21 @@ import UIKit import MarkdownKit protocol NCSectionFirstHeaderDelegate: AnyObject { + func tapButtonSwitch(_ sender: Any) + func tapButtonOrder(_ sender: Any) func tapButtonTransfer(_ sender: Any) func tapRichWorkspace(_ sender: Any) } +extension NCSectionFirstHeaderDelegate { + func tapButtonSwitch(_ sender: Any) {} + func tapButtonOrder(_ sender: Any) {} +} + class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegate { + @IBOutlet weak var buttonSwitch: UIButton! + @IBOutlet weak var buttonOrder: UIButton! @IBOutlet weak var buttonTransfer: UIButton! @IBOutlet weak var imageButtonTransfer: UIImageView! @IBOutlet weak var labelTransfer: UILabel! @@ -41,8 +50,12 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat @IBOutlet weak var viewTransfer: UIView! @IBOutlet weak var viewRichWorkspace: UIView! @IBOutlet weak var viewSection: UIView! + @IBOutlet weak var viewButtonsView: UIView! + @IBOutlet weak var viewSeparator: UIView! @IBOutlet weak var viewTransferHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewButtonsViewHeightConstraint: NSLayoutConstraint! + @IBOutlet weak var viewSeparatorHeightConstraint: NSLayoutConstraint! @IBOutlet weak var viewRichWorkspaceHeightConstraint: NSLayoutConstraint! @IBOutlet weak var viewSectionHeightConstraint: NSLayoutConstraint! @IBOutlet weak var transferSeparatorBottomHeightConstraint: NSLayoutConstraint! @@ -58,6 +71,12 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat super.awakeFromNib() backgroundColor = .clear + + //Button + buttonSwitch.setImage(UIImage(systemName: "list.bullet"), for: .normal)//!.image(color: NCBrandColor.shared.iconColor, size: 25), for: .normal) + + buttonOrder.setTitle("", for: .normal) + buttonOrder.setTitleColor(NCBrandColor.shared.brand, for: .normal) // Gradient gradient.startPoint = CGPoint(x: 0, y: 0.8) @@ -105,6 +124,40 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat setInterfaceColor() } + // MARK: - View + + func setStatusButtonsView(enable: Bool) { + + buttonSwitch.isEnabled = enable + buttonOrder.isEnabled = enable + } + + func setImageSwitchList() { + + buttonSwitch.setImage(UIImage(systemName: "list.bullet"), for: .normal)//!.image(color: NCBrandColor.shared.iconColor, width: 20, height: 15), for: .normal) + } + + func setImageSwitchGrid() { + + buttonSwitch.setImage(UIImage(systemName: "square.grid.2x2")!.image(color: NCBrandColor.shared.iconImageColor, size: 20), for: .normal) + } + + func setButtonsView(height: CGFloat) { + + viewButtonsViewHeightConstraint.constant = height + if height == 0 { + viewButtonsView.isHidden = true + } else { + viewButtonsView.isHidden = false + } + } + + func setSortedTitle(_ title: String) { + + let title = NSLocalizedString(title, comment: "") + buttonOrder.setTitle(title, for: .normal) + } + // MARK: - RichWorkspace func setRichWorkspaceHeight(_ size: CGFloat) { @@ -174,6 +227,14 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat } // MARK: - Action + + @IBAction func touchUpInsideSwitch(_ sender: Any) { + delegate?.tapButtonSwitch(sender) + } + + @IBAction func touchUpInsideOrder(_ sender: Any) { + delegate?.tapButtonOrder(sender) + } @IBAction func touchUpTransfer(_ sender: Any) { delegate?.tapButtonTransfer(sender) diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib index 9568658d6b..528b2f0098 100644 --- a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib @@ -1,9 +1,9 @@ - + - + @@ -11,15 +11,66 @@ - + - + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -27,72 +78,72 @@ - - - - - + + + + + - + - + - + - - + - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - + - - - - - + + + + - + - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/NCActionCenter.swift b/iOSClient/Main/NCActionCenter.swift index 1772f8d4b5..8d20ac0391 100644 --- a/iOSClient/Main/NCActionCenter.swift +++ b/iOSClient/Main/NCActionCenter.swift @@ -425,6 +425,55 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec } } } + + // MARK: - Copy & Paste + + func copyPasteboard(pasteboardOcIds: [String], viewController: UIViewController) { + var items = [[String: Any]]() + guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return } + let hudView = viewController.view + var fractionCompleted: Float = 0 + + // getting file data can take some time and block the main queue + DispatchQueue.global(qos: .userInitiated).async { + var downloadMetadatas: [tableMetadata] = [] + for ocid in pasteboardOcIds { + guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocid) else { continue } + if let pasteboardItem = metadata.toPasteBoardItem() { + items.append(pasteboardItem) + } else { + downloadMetadatas.append(metadata) + } + } + + // do 5 downloads in parallel to optimize efficiency + let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadatas.count, hudView: hudView) + + for metadata in downloadMetadatas { + processor.execute { completion in + guard let metadata = NCManageDatabase.shared.setMetadatasSessionInWaitDownload(metadatas: [metadata], + session: NextcloudKit.shared.nkCommonInstance.sessionIdentifierDownload, + selector: "") else { return completion() } + NCNetworking.shared.download(metadata: metadata, withNotificationProgressTask: false) { + } requestHandler: { _ in + } progressHandler: { progress in + if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 { + processor.hud?.progress = Float(progress.fractionCompleted) + fractionCompleted = Float(progress.fractionCompleted) + } + } completion: { _, _ in + fractionCompleted = 0 + completion() + } + } + } + processor.completeWork { + items.append(contentsOf: downloadMetadatas.compactMap({ $0.toPasteBoardItem() })) + UIPasteboard.general.setItems(items, options: [:]) + } + } + } + // MARK: - Copy & Paste @@ -628,3 +677,19 @@ class NCActionCenter: NSObject, UIDocumentInteractionControllerDelegate, NCSelec } } } + + +fileprivate extension tableMetadata { + func toPasteBoardItem() -> [String: Any]? { + // Get Data + let fileUrl = URL(fileURLWithPath: NCUtilityFileSystem().getDirectoryProviderStorageOcId(ocId, fileNameView: fileNameView)) + guard NCUtilityFileSystem().fileProviderStorageExists(self), + let data = try? Data(contentsOf: fileUrl) else { return nil } + + // Determine the UTI for the file + guard let fileUTI = UTType(filenameExtension: fileExtension)?.identifier else { return nil } + + // Pasteboard item + return [fileUTI: data] + } +} diff --git a/iOSClient/Menu/NCMenuAction.swift b/iOSClient/Menu/NCMenuAction.swift index 208693c756..13b1df788b 100644 --- a/iOSClient/Menu/NCMenuAction.swift +++ b/iOSClient/Menu/NCMenuAction.swift @@ -194,6 +194,21 @@ extension NCMenuAction { } ) } + + /// Copy files to pasteboard + static func copyAction(selectOcId: [String], viewController: UIViewController, order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction { + NCMenuAction( + title: NSLocalizedString("_copy_file_", comment: ""), + icon: NCUtility().loadImage(named: "copy", colors: [NCBrandColor.shared.iconImageColor]), + order: order, + action: { _ in + NCActionCenter.shared.copyPasteboard(pasteboardOcIds: selectOcId, viewController: viewController) + completion?() + } + ) + } + + /// Open view that lets the user move or copy the files within Nextcloud static func moveOrCopyAction(selectedMetadatas: [tableMetadata], viewController: UIViewController, indexPath: [IndexPath], order: Int = 0, completion: (() -> Void)? = nil) -> NCMenuAction { NCMenuAction( diff --git a/iOSClient/Menu/NCSortMenu.swift b/iOSClient/Menu/NCSortMenu.swift new file mode 100644 index 0000000000..3aaadb4dcd --- /dev/null +++ b/iOSClient/Menu/NCSortMenu.swift @@ -0,0 +1,149 @@ +// +// NCSortMenu.swift +// Nextcloud +// +// Created by Marino Faggiana on 27/08/2020. +// Copyright © 2020 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import UIKit +import FloatingPanel +import NextcloudKit + +class NCSortMenu: NSObject { + + private var sortButton: UIButton? + private var serverUrl: String = "" + private var hideDirectoryOnTop: Bool? + + private var key = "" + + func toggleMenu(viewController: UIViewController, account: String, key: String, sortButton: UIButton?, serverUrl: String, hideDirectoryOnTop: Bool = false) { + + self.key = key + self.sortButton = sortButton + self.serverUrl = serverUrl + self.hideDirectoryOnTop = hideDirectoryOnTop + + guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: account, key: key, serverUrl: serverUrl) else { return } + var actions = [NCMenuAction]() + var title = "" + var icon = UIImage() + + if layoutForView.ascending { + title = NSLocalizedString("_order_by_name_z_a_", comment: "") + icon = UIImage(named: "sortFileNameZA")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } else { + title = NSLocalizedString("_order_by_name_a_z_", comment: "") + icon = UIImage(named: "sortFileNameAZ")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } + + actions.append( + NCMenuAction( + title: title, + icon: icon, + selected: layoutForView.sort == "fileName", + on: layoutForView.sort == "fileName", + action: { _ in + layoutForView.sort = "fileName" + layoutForView.ascending = !layoutForView.ascending + self.actionMenu(layoutForView: layoutForView) + } + ) + ) + + if layoutForView.ascending { + title = NSLocalizedString("_order_by_date_more_recent_", comment: "") + icon = UIImage(named: "sortDateMoreRecent")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } else { + title = NSLocalizedString("_order_by_date_less_recent_", comment: "") + icon = UIImage(named: "sortDateLessRecent")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } + + actions.append( + NCMenuAction( + title: title, + icon: icon, + selected: layoutForView.sort == "date", + on: layoutForView.sort == "date", + action: { _ in + layoutForView.sort = "date" + layoutForView.ascending = !layoutForView.ascending + self.actionMenu(layoutForView: layoutForView) + } + ) + ) + + if layoutForView.ascending { + title = NSLocalizedString("_order_by_size_largest_", comment: "") + icon = UIImage(named: "sortLargest")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } else { + title = NSLocalizedString("_order_by_size_smallest_", comment: "") + icon = UIImage(named: "sortSmallest")!.image(color: NCBrandColor.shared.iconImageColor, size: 50) + } + + actions.append( + NCMenuAction( + title: title, + icon: icon, + selected: layoutForView.sort == "size", + on: layoutForView.sort == "size", + action: { _ in + layoutForView.sort = "size" + layoutForView.ascending = !layoutForView.ascending + self.actionMenu(layoutForView: layoutForView) + } + ) + ) + + if !hideDirectoryOnTop { + actions.append( + NCMenuAction( + title: NSLocalizedString("_directory_on_top_no_", comment: ""), + icon: UIImage(named: "foldersOnTop")!.image(color: NCBrandColor.shared.iconImageColor, size: 50), + selected: layoutForView.directoryOnTop, + on: layoutForView.directoryOnTop, + action: { _ in + layoutForView.directoryOnTop = !layoutForView.directoryOnTop + self.actionMenu(layoutForView: layoutForView) + } + ) + ) + } + + viewController.presentMenu(with: actions) + } + + func actionMenu(layoutForView: NCDBLayoutForView) { + + switch layoutForView.sort { + case "fileName": + layoutForView.titleButtonHeader = layoutForView.ascending ? "_sorted_by_name_a_z_" : "_sorted_by_name_z_a_" + case "date": + layoutForView.titleButtonHeader = layoutForView.ascending ? "_sorted_by_date_less_recent_" : "_sorted_by_date_more_recent_" + case "size": + layoutForView.titleButtonHeader = layoutForView.ascending ? "_sorted_by_size_smallest_" : "_sorted_by_size_largest_" + default: + break + } + + self.sortButton?.setTitle(NSLocalizedString(layoutForView.titleButtonHeader, comment: ""), for: .normal) + NCManageDatabase.shared.setLayoutForView(layoutForView: layoutForView) + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource) + } +} diff --git a/iOSClient/Offline/NCOffline.swift b/iOSClient/Offline/NCOffline.swift index 87a25c145e..2ff9d604d2 100644 --- a/iOSClient/Offline/NCOffline.swift +++ b/iOSClient/Offline/NCOffline.swift @@ -33,7 +33,7 @@ class NCOffline: NCCollectionViewCommon { layoutKey = NCGlobal.shared.layoutViewOffline enableSearchBar = false headerRichWorkspaceDisable = true - emptyImage = NCUtility().loadImage(named: "icloud.and.arrow.down", colors: [NCBrandColor.shared.brandElement]) + emptyImage = UIImage(named: "folder") emptyTitle = "_files_no_files_" emptyDescription = "_tutorial_offline_view_" emptyDataPortaitOffset = 30