From b08236079372b9f5266ea6ff8904497ebdbf3449 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:09:33 +0530 Subject: [PATCH 1/2] NMC 2172 - dashboard theming customisation --- iOSClient/Favorites/NCFavorite.swift | 1 + iOSClient/Files/NCFiles.swift | 4 +- .../Cell/NCCellProtocol.swift | 6 + .../Collection Common/Cell/NCListCell.swift | 157 ++++---- .../Collection Common/Cell/NCListCell.xib | 339 +++++++--------- ...nViewCommon+CollectionViewDataSource.swift | 183 ++++++++- .../NCCollectionViewCommon+SelectTabBar.swift | 126 +++++- ...mmon+SwipeCollectionViewCellDelegate.swift | 94 +++++ .../NCCollectionViewCommon.swift | 364 +++++++++++++++++- .../NCSectionFirstHeader.swift | 139 ++++++- .../NCSectionFirstHeader.xib | 232 +++++++---- iOSClient/Main/NCActionCenter.swift | 65 ++++ iOSClient/Menu/NCMenuAction.swift | 15 + iOSClient/Menu/NCSortMenu.swift | 149 +++++++ iOSClient/Offline/NCOffline.swift | 1 + 15 files changed, 1464 insertions(+), 411 deletions(-) create mode 100644 iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift create mode 100644 iOSClient/Menu/NCSortMenu.swift diff --git a/iOSClient/Favorites/NCFavorite.swift b/iOSClient/Favorites/NCFavorite.swift index c0b11e4ab2..1574c9cd17 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 emptyImageName = "star.fill" emptyImageColors = [NCBrandColor.shared.yellowFavorite] diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 02c852aabb..2f4ae0c1c3 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -83,8 +83,8 @@ class NCFiles: NCCollectionViewCommon { } self.titleCurrentFolder = self.getNavigationTitle() - self.navigationItem.title = self.titleCurrentFolder - (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems() + ///Magentacloud branding changes hide user account button on left navigation bar +// self.setNavigationLeftItems() self.dataSource.removeAll() self.reloadDataSource() diff --git a/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift b/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift index b861d54f00..9e969faed9 100644 --- a/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift +++ b/iOSClient/Main/Collection Common/Cell/NCCellProtocol.swift @@ -39,6 +39,8 @@ protocol NCCellProtocol { var fileSharedImage: UIImageView? { get set } var fileMoreImage: UIImageView? { get set } var cellSeparatorView: UIView? { get set } + var indexPath: IndexPath { get set } + var fileSharedLabel: UILabel? { get set } func titleInfoTrailingDefault() func titleInfoTrailingFull() @@ -115,6 +117,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 e5a99c373a..31f1000ece 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! @@ -38,30 +37,26 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto @IBOutlet weak var buttonShared: UIButton! @IBOutlet weak var imageMore: UIImageView! @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! - var ocId = "" - var ocIdTransfer = "" - var user = "" + private var objectId = "" + private var user = "" + var indexPath = IndexPath() weak var listCellDelegate: NCListCellDelegate? + var namedButtonMore = "" var fileAvatarImageView: UIImageView? { return imageShared } - var fileOcId: String? { - get { return ocId } - set { ocId = newValue ?? "" } - } - var fileOcIdTransfer: String? { - get { return ocIdTransfer } - set { ocIdTransfer = newValue ?? "" } + var fileObjectId: String? { + get { return objectId } + set { objectId = newValue ?? "" } } var filePreviewImageView: UIImageView? { get { return imageItem } @@ -83,6 +78,14 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto get { return labelSubinfo } set { labelSubinfo = newValue } } + var fileProgressView: UIProgressView? { + get { return progressView } + set { progressView = newValue } + } + var fileSelectImage: UIImageView? { + get { return imageSelect } + set { imageSelect = newValue } + } var fileStatusImage: UIImageView? { get { return imageStatus } set { imageStatus = newValue } @@ -107,45 +110,48 @@ 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() - initCell() - } - override func prepareForReuse() { - super.prepareForReuse() - initCell() - } + imageItem.layer.cornerRadius = 6 + imageItem.layer.masksToBounds = true - func initCell() { + // use entire cell as accessibility element accessibilityHint = nil accessibilityLabel = nil accessibilityValue = nil isAccessibilityElement = true - imageItem.image = nil - imageItem.layer.cornerRadius = 6 - imageItem.layer.masksToBounds = true - imageStatus.image = nil - imageFavorite.image = nil - imageFavoriteBackground.isHidden = true - imageLocal.image = nil - labelTitle.text = "" - labelInfo.text = "" - labelSubinfo.text = "" - imageShared.image = nil - imageMore.image = nil - separatorHeightConstraint.constant = 0.5 - tag0.text = "" - tag1.text = "" - titleInfoTrailingDefault() + progressView.tintColor = NCBrandColor.shared.brandElement + progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) + progressView.trackTintColor = .clear let longPressedGesture = UILongPressGestureRecognizer(target: self, action: #selector(longPress(gestureRecognizer:))) longPressedGesture.minimumPressDuration = 0.5 longPressedGesture.delegate = self longPressedGesture.delaysTouchesBegan = true self.addGestureRecognizer(longPressedGesture) + + separator.backgroundColor = .separator + separatorHeightConstraint.constant = 0.5 + + labelTitle.text = "" + labelInfo.text = "" + labelTitle.textColor = .label + labelInfo.textColor = .systemGray + labelSubinfo.textColor = .systemGray + } + + override func prepareForReuse() { + super.prepareForReuse() + imageItem.backgroundColor = nil + accessibilityHint = nil + accessibilityLabel = nil + accessibilityValue = nil } override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? { @@ -153,40 +159,43 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto } @IBAction func touchUpInsideShare(_ sender: Any) { - listCellDelegate?.tapShareListItem(with: ocId, ocIdTransfer: ocIdTransfer, sender: sender) + listCellDelegate?.tapShareListItem(with: objectId, indexPath: indexPath, sender: sender) } @IBAction func touchUpInsideMore(_ sender: Any) { - listCellDelegate?.tapMoreListItem(with: ocId, ocIdTransfer: ocIdTransfer, image: imageItem.image, sender: sender) + listCellDelegate?.tapMoreListItem(with: objectId, namedButtonMore: namedButtonMore, image: imageItem.image, indexPath: indexPath, sender: sender) } @objc func longPress(gestureRecognizer: UILongPressGestureRecognizer) { - listCellDelegate?.longPressListItem(with: ocId, ocIdTransfer: ocIdTransfer, gestureRecognizer: gestureRecognizer) + listCellDelegate?.longPressListItem(with: objectId, indexPath: indexPath, gestureRecognizer: gestureRecognizer) } fileprivate func setA11yActions() { + let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_" self.accessibilityCustomActions = [ UIAccessibilityCustomAction( name: NSLocalizedString("_share_", comment: ""), target: self, selector: #selector(touchUpInsideShare)), UIAccessibilityCustomAction( - name: NSLocalizedString("_more_", comment: ""), + name: NSLocalizedString(moreName, comment: ""), target: self, selector: #selector(touchUpInsideMore)) ] } func titleInfoTrailingFull() { - titleTrailingConstraint.constant = 10 + subInfoTrailingConstraint.constant = 10 } func titleInfoTrailingDefault() { - titleTrailingConstraint.constant = 90 + subInfoTrailingConstraint.constant = 90 } - func setButtonMore(image: UIImage) { + func setButtonMore(named: String, image: UIImage) { + namedButtonMore = named imageMore.image = image + setA11yActions() } @@ -200,6 +209,10 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto buttonShared.isHidden = status } + func hideSeparator(_ status: Bool) { + separator.isHidden = status + } + func selected(_ status: Bool, isEditMode: Bool) { if isEditMode { imageItemLeftConstraint.constant = 45 @@ -225,11 +238,11 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellProto blurEffectView?.backgroundColor = .lightGray blurEffectView?.frame = self.bounds blurEffectView?.autoresizingMask = [.flexibleWidth, .flexibleHeight] - imageSelect.image = NCImageCache.shared.getImageCheckedYes() + imageSelect.image = NCImageCache.images.checkedYes backgroundView = blurEffectView separator.isHidden = true } else { - imageSelect.image = NCImageCache.shared.getImageCheckedNo() + imageSelect.image = NCImageCache.images.checkedNo backgroundView = nil separator.isHidden = false } @@ -237,58 +250,20 @@ 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 { - func tapShareListItem(with ocId: String, ocIdTransfer: String, sender: Any) - func tapMoreListItem(with ocId: String, ocIdTransfer: String, image: UIImage?, sender: Any) - func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) + func tapShareListItem(with objectId: String, indexPath: IndexPath, sender: Any) + func tapMoreListItem(with objectId: String, namedButtonMore: String, image: UIImage?, indexPath: IndexPath, sender: Any) + func longPressListItem(with objectId: String, indexPath: IndexPath, gestureRecognizer: UILongPressGestureRecognizer) } // MARK: - List Layout diff --git a/iOSClient/Main/Collection Common/Cell/NCListCell.xib b/iOSClient/Main/Collection Common/Cell/NCListCell.xib index 0d02c3cfba..a9b542e428 100755 --- a/iOSClient/Main/Collection Common/Cell/NCListCell.xib +++ b/iOSClient/Main/Collection Common/Cell/NCListCell.xib @@ -1,272 +1,191 @@ - + - - + + - - + + - + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift index 9b9a00d4aa..bef043ea8b 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift @@ -37,10 +37,89 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { self.autoUploadDirectory = self.database.getAccountAutoUploadDirectory(session: self.session) // get layout for view self.layoutForView = self.database.getLayoutForView(account: self.session.account, key: self.layoutKey, serverUrl: self.serverUrl) - + return self.dataSource.numberOfItemsInSection(section) } + func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + guard let metadata = dataSource.cellForItemAt(indexPath: indexPath), + let cell = (cell as? NCCellProtocol) else { return } + let existsIcon = utilityFileSystem.fileProviderStoragePreviewIconExists(metadata.ocId, etag: metadata.etag) + + func downloadAvatar(fileName: String, user: String, dispalyName: String?) { + if let image = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName) { + cell.fileAvatarImageView?.contentMode = .scaleAspectFill + cell.fileAvatarImageView?.image = image + } else { + NCNetworking.shared.downloadAvatar(user: user, dispalyName: dispalyName, fileName: fileName, cell: cell, view: collectionView) + } + } + /// CONTENT MODE + cell.filePreviewImageView?.layer.borderWidth = 0 + if existsIcon { + cell.filePreviewImageView?.contentMode = .scaleAspectFill + } else { + cell.filePreviewImageView?.contentMode = .scaleAspectFit + } + cell.fileAvatarImageView?.contentMode = .center + /// THUMBNAIL + if !metadata.directory { + if metadata.hasPreviewBorder { + cell.filePreviewImageView?.layer.borderWidth = 0.2 + cell.filePreviewImageView?.layer.borderColor = UIColor.lightGray.cgColor + } + if metadata.name == NCGlobal.shared.appName { + if layoutForView?.layout == NCGlobal.shared.layoutPhotoRatio || layoutForView?.layout == NCGlobal.shared.layoutPhotoSquare { + if let image = NCImageCache.shared.getPreviewImageCache(ocId: metadata.ocId, etag: metadata.etag) { + cell.filePreviewImageView?.image = image + } else if let image = UIImage(contentsOfFile: self.utilityFileSystem.getDirectoryProviderStoragePreviewOcId(metadata.ocId, etag: metadata.etag)) { + cell.filePreviewImageView?.image = image + NCImageCache.shared.addPreviewImageCache(metadata: metadata, image: image) + } + } else { + if let image = NCImageCache.shared.getIconImageCache(ocId: metadata.ocId, etag: metadata.etag) { + cell.filePreviewImageView?.image = image + } else if metadata.hasPreview { + cell.filePreviewImageView?.image = utility.getIcon(metadata: metadata) + } + } + if cell.filePreviewImageView?.image == nil { + if metadata.iconName.isEmpty { + cell.filePreviewImageView?.image = NCImageCache.images.file + } else { + cell.filePreviewImageView?.image = utility.loadImage(named: metadata.iconName, useTypeIconFile: true) + } + if metadata.hasPreview && metadata.status == NCGlobal.shared.metadataStatusNormal && !existsIcon { + for case let operation as NCCollectionViewDownloadThumbnail in NCNetworking.shared.downloadThumbnailQueue.operations where operation.metadata.ocId == metadata.ocId { return } + NCNetworking.shared.downloadThumbnailQueue.addOperation(NCCollectionViewDownloadThumbnail(metadata: metadata, cell: cell, collectionView: collectionView)) + } + } + } else { + /// APP NAME - UNIFIED SEARCH + switch metadata.iconName { + case let str where str.contains("contacts"): + cell.filePreviewImageView?.image = NCImageCache.images.iconContacts + case let str where str.contains("conversation"): + cell.filePreviewImageView?.image = NCImageCache.images.iconTalk + case let str where str.contains("calendar"): + cell.filePreviewImageView?.image = NCImageCache.images.iconCalendar + case let str where str.contains("deck"): + cell.filePreviewImageView?.image = NCImageCache.images.iconDeck + case let str where str.contains("mail"): + cell.filePreviewImageView?.image = NCImageCache.images.iconMail + case let str where str.contains("talk"): + cell.filePreviewImageView?.image = NCImageCache.images.iconTalk + case let str where str.contains("confirm"): + cell.filePreviewImageView?.image = NCImageCache.images.iconConfirm + case let str where str.contains("pages"): + cell.filePreviewImageView?.image = NCImageCache.images.iconPages + default: + cell.filePreviewImageView?.image = NCImageCache.images.iconFile + } + } + } + } + func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { if !collectionView.indexPathsForVisibleItems.contains(indexPath) { guard let metadata = self.dataSource.getMetadata(indexPath: indexPath) else { return } @@ -133,9 +212,25 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { var isShare = false var isMounted = false var a11yValues: [String] = [] + + // LAYOUT PHOTO + if layoutForView?.layout == NCGlobal.shared.layoutPhotoRatio || layoutForView?.layout == NCGlobal.shared.layoutPhotoSquare { + guard let photoCell = collectionView.dequeueReusableCell(withReuseIdentifier: "photoCell", for: indexPath) as? NCPhotoCell else { return NCPhotoCell() } + photoCell.photoCellDelegate = self + cell = photoCell + } else if layoutForView?.layout == NCGlobal.shared.layoutGrid { + // LAYOUT GRID + guard let gridCell = collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCGridCell else { return NCGridCell() } + gridCell.gridCellDelegate = self + cell = gridCell + } else { + // LAYOUT LIST + guard let listCell = collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? NCListCell else { return NCListCell() } + listCell.listCellDelegate = self + cell = listCell + } let metadata = self.dataSource.getMetadata(indexPath: indexPath) ?? tableMetadata() - let existsImagePreview = utilityFileSystem.fileProviderStorageImageExists(metadata.ocId, etag: metadata.etag) - let ext = global.getSizeExtension(column: self.numberOfColumns) + let shares = NCManageDatabase.shared.getTableShares(metadata: metadata) defer { if !metadata.isSharable() || NCCapabilities.shared.disableSharesView(account: metadata.account) { @@ -327,14 +422,28 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { } // Share image - if isShare { - cell.fileSharedImage?.image = imageCache.getImageShared() - } else if !metadata.shareType.isEmpty { - metadata.shareType.contains(3) ? - (cell.fileSharedImage?.image = imageCache.getImageShareByLink()) : - (cell.fileSharedImage?.image = imageCache.getImageShared()) + if isShare || !metadata.shareType.isEmpty { + cell.fileSharedImage?.image = NCImageCache.images.shared } else { - cell.fileSharedImage?.image = imageCache.getImageCanShare() + 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 @@ -476,6 +585,16 @@ 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 } @@ -483,6 +602,15 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { func setContent(header: UICollectionReusableView, indexPath: IndexPath) { let (heightHeaderRichWorkspace, heightHeaderRecommendations, heightHeaderSection) = getHeaderHeight(section: indexPath.section) + if kind == UICollectionView.elementKindSectionHeader { + + if dataSource.getMetadataSourceForAllSections().isEmpty { + + guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFirstHeaderEmptyData", for: indexPath) as? NCSectionFirstHeaderEmptyData else { return NCSectionFirstHeaderEmptyData() } + self.sectionFirstHeaderEmptyData = header + header.delegate = self + + } if let header = header as? NCSectionFirstHeader { let recommendations = self.database.getRecommendedFiles(account: self.session.account) var sectionText = NSLocalizedString("_all_files_", comment: "") @@ -565,7 +693,40 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFirstHeader", for: indexPath) as? NCSectionFirstHeader else { return NCSectionFirstHeader() } self.sectionFirstHeader = header - setContent(header: header, indexPath: indexPath) +// setContent(header: header, indexPath: indexPath) + 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, isHeaderMenuTransferViewEnabled() != nil { + header.setViewTransfer(isHidden: false) + } 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) + + header.setSectionHeight(heightHeaderSection) + if heightHeaderSection == 0 { + header.labelSection.text = "" + } else { + header.labelSection.text = self.dataSource.getSectionValueLocalization(indexPath: indexPath) + } + header.labelSection.textColor = NCBrandColor.shared.textColor return header diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift index 3fb479b0d3..a1a03e5a1f 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SelectTabBar.swift @@ -128,7 +128,8 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate { if editMode { navigationItem.leftBarButtonItems = nil } else { - (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems() + ///Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() } (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() @@ -137,4 +138,127 @@ extension NCCollectionViewCommon: NCCollectionViewCommonSelectTabBarDelegate { searchController(enabled: !editMode) self.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 new file mode 100644 index 0000000000..11a580f6a3 --- /dev/null +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift @@ -0,0 +1,94 @@ +// +// NCCollectionViewCommon+SwipeCollectionViewCellDelegate.swift +// Nextcloud +// +// Created by Milen on 01.03.24. +// Copyright © 2024 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 Foundation +import SwipeCellKit + +extension NCCollectionViewCommon: SwipeCollectionViewCellDelegate { + func collectionView(_ collectionView: UICollectionView, editActionsForItemAt indexPath: IndexPath, for orientation: SwipeCellKit.SwipeActionsOrientation) -> [SwipeCellKit.SwipeAction]? { + guard orientation == .right, let metadata = self.dataSource.cellForItemAt(indexPath: indexPath) else { return nil } + + let scaleTransition = ScaleTransition(duration: 0.3, initialScale: 0.8, threshold: 0.8) + + // wait a fix for truncate the text .. ? .. + let favoriteAction = SwipeAction(style: .default, title: NSLocalizedString(metadata.favorite ? "_favorite_short_" : "_favorite_short_", comment: "") ) { _, _ in + NCNetworking.shared.favoriteMetadata(metadata) { error in + if error != .success { + NCContentPresenter().showError(error: error) + } + } + } + favoriteAction.backgroundColor = NCBrandColor.shared.yellowFavorite + favoriteAction.image = .init(systemName: "star.fill") + favoriteAction.transitionDelegate = scaleTransition + favoriteAction.hidesWhenSelected = true + + var actions = [favoriteAction] + + let shareAction = SwipeAction(style: .default, title: NSLocalizedString("_share_", comment: "")) { _, _ in + NCActionCenter.shared.openActivityViewController(selectedMetadata: [metadata]) + } + shareAction.backgroundColor = .blue + shareAction.image = .init(systemName: "square.and.arrow.up") + shareAction.transitionDelegate = scaleTransition + shareAction.hidesWhenSelected = true + + let deleteAction = SwipeAction(style: .destructive, title: NSLocalizedString("_delete_", comment: "")) { _, _ in + let titleDelete: String + + if metadata.directory { + titleDelete = NSLocalizedString("_delete_folder_", comment: "") + } else { + titleDelete = NSLocalizedString("_delete_file_", comment: "") + } + + let message = NSLocalizedString("_want_delete_", comment: "") + "\n - " + metadata.fileNameView + + let alertController = UIAlertController.deleteFileOrFolder(titleString: titleDelete + "?", message: message, canDeleteServer: !metadata.lock, selectedMetadatas: [metadata], indexPaths: self.selectIndexPaths) { _ in } + + self.viewController.present(alertController, animated: true, completion: nil) + } + deleteAction.image = .init(systemName: "trash") + deleteAction.style = .destructive + deleteAction.transitionDelegate = scaleTransition + deleteAction.hidesWhenSelected = true + + if !NCManageDatabase.shared.isMetadataShareOrMounted(metadata: metadata, metadataFolder: metadataFolder) { + actions.insert(deleteAction, at: 0) + } + + if metadata.canShare { + actions.append(shareAction) + } + + return actions + } + + func collectionView(_ collectionView: UICollectionView, editActionsOptionsForItemAt indexPath: IndexPath, for orientation: SwipeActionsOrientation) -> SwipeOptions { + var options = SwipeOptions() + options.expansionStyle = .selection + options.transitionStyle = .border + options.backgroundColor = .clear + return options + } +} diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 16ca2ab50d..0fed0bfdf3 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -66,6 +66,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var tabBarSelect: NCCollectionViewCommonSelectTabBar? var attributesZoomIn: UIMenuElement.Attributes = [] var attributesZoomOut: UIMenuElement.Attributes = [] + let maxImageGrid: CGFloat = 7 + var headerMenu: NCSectionFirstHeader? // DECLARE var layoutKey = "" @@ -76,6 +78,8 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS var emptyImageName: String? var emptyImageColors: [UIColor]? + var headerMenuButtonsView: Bool = true + var emptyImage: UIImage? var emptyTitle: String = "" var emptyDescription: String = "" @@ -266,8 +270,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS isEditMode = false - (self.navigationController as? NCMainNavigationController)?.setNavigationLeftItems() - (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() + /// Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() + setNavigationRightItems() layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) if isLayoutList { @@ -388,6 +393,17 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS self.refreshControl.endRefreshing() } + @objc func reloadAvatar(_ notification: NSNotification) { + DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { + self.showTip() + } + guard let userInfo = notification.userInfo as NSDictionary?, + let error = userInfo["error"] as? NKError, + error.errorCode != global.errorNotModified else { return } + /// Magentacloud branding changes hide user account button on left navigation bar +// setNavigationLeftItems() + } + @objc func changeTheming(_ notification: NSNotification) { self.reloadDataSource() } @@ -651,6 +667,286 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS // MARK: - Layout + func setNavigationLeftItems() { + guard layoutKey == global.layoutViewFiles, + let tableAccount = database.getTableAccount(predicate: NSPredicate(format: "account == %@", session.account)) else { + return } + let image = utility.loadUserImage(for: tableAccount.user, displayName: tableAccount.displayName, urlBase: tableAccount.urlBase) + let accountButton = AccountSwitcherButton(type: .custom) + let accounts = database.getAllAccountOrderAlias() + var childrenAccountSubmenu: [UIMenuElement] = [] + + accountButton.setImage(image, for: .normal) + accountButton.setImage(image, for: .highlighted) + accountButton.semanticContentAttribute = .forceLeftToRight + accountButton.sizeToFit() + + if !accounts.isEmpty { + let accountActions: [UIAction] = accounts.map { account in + let image = utility.loadUserImage(for: account.user, displayName: account.displayName, urlBase: account.urlBase) + var name: String = "" + var url: String = "" + + if account.alias.isEmpty { + name = account.displayName + url = (URL(string: account.urlBase)?.host ?? "") + } else { + name = account.alias + } + + let action = UIAction(title: name, image: image, state: account.active ? .on : .off) { _ in + if !account.active { + NCAccount().changeAccount(account.account, userProfile: nil, controller: self.controller) { } + self.setEditMode(false) + } + } + + action.subtitle = url + return action + } + + let addAccountAction = UIAction(title: NSLocalizedString("_add_account_", comment: ""), image: utility.loadImage(named: "person.crop.circle.badge.plus", colors: NCBrandColor.shared.iconImageMultiColors)) { _ in + self.appDelegate.openLogin(selector: self.global.introLogin) + } + + let settingsAccountAction = UIAction(title: NSLocalizedString("_account_settings_", comment: ""), image: utility.loadImage(named: "gear", colors: [NCBrandColor.shared.iconImageColor])) { _ in + let accountSettingsModel = NCAccountSettingsModel(controller: self.controller, delegate: self) + let accountSettingsView = NCAccountSettingsView(model: accountSettingsModel) + let accountSettingsController = UIHostingController(rootView: accountSettingsView) + self.present(accountSettingsController, animated: true, completion: nil) + } + + if !NCBrandOptions.shared.disable_multiaccount { + childrenAccountSubmenu.append(addAccountAction) + } + childrenAccountSubmenu.append(settingsAccountAction) + + let addAccountSubmenu = UIMenu(title: "", options: .displayInline, children: childrenAccountSubmenu) + let menu = UIMenu(children: accountActions + [addAccountSubmenu]) + + accountButton.menu = menu + accountButton.showsMenuAsPrimaryAction = true + + accountButton.onMenuOpened = { + self.dismissTip() + } + } + + navigationItem.leftItemsSupplementBackButton = true + navigationItem.setLeftBarButtonItems([UIBarButtonItem(customView: accountButton)], animated: true) + + if titlePreviusFolder != nil { + navigationController?.navigationBar.topItem?.title = titlePreviusFolder + } + + navigationItem.title = titleCurrentFolder + } + + func setNavigationRightItems() { + guard layoutKey != global.layoutViewTransfers else { return } + let isTabBarHidden = self.tabBarController?.tabBar.isHidden ?? true + let isTabBarSelectHidden = tabBarSelect.isHidden() + + func createMenuActions() -> [UIMenuElement] { + guard let layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) else { return [] } + + let select = UIAction(title: NSLocalizedString("_select_", comment: ""), + image: utility.loadImage(named: "checkmark.circle"), + attributes: (self.dataSource.isEmpty() || NCNetworking.shared.isOffline) ? .disabled : []) { _ in + self.setEditMode(true) + self.collectionView.reloadData() + } + + let list = UIAction(title: NSLocalizedString("_list_", comment: ""), image: utility.loadImage(named: "list.bullet"), state: layoutForView.layout == global.layoutList ? .on : .off) { _ in + + layoutForView.layout = self.global.layoutList + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let grid = UIAction(title: NSLocalizedString("_icons_", comment: ""), image: utility.loadImage(named: "square.grid.2x2"), state: layoutForView.layout == global.layoutGrid ? .on : .off) { _ in + + layoutForView.layout = self.global.layoutGrid + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let mediaSquare = UIAction(title: NSLocalizedString("_media_square_", comment: ""), image: utility.loadImage(named: "square.grid.3x3"), state: layoutForView.layout == global.layoutPhotoSquare ? .on : .off) { _ in + + layoutForView.layout = self.global.layoutPhotoSquare + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let mediaRatio = UIAction(title: NSLocalizedString("_media_ratio_", comment: ""), image: utility.loadImage(named: "rectangle.grid.3x2"), state: layoutForView.layout == self.global.layoutPhotoRatio ? .on : .off) { _ in + + layoutForView.layout = self.global.layoutPhotoRatio + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let viewStyleSubmenu = UIMenu(title: "", options: .displayInline, children: [list, grid, mediaSquare, mediaRatio]) + + let ascending = layoutForView.ascending + let ascendingChevronImage = utility.loadImage(named: ascending ? "chevron.up" : "chevron.down") + let isName = layoutForView.sort == "fileName" + let isDate = layoutForView.sort == "date" + let isSize = layoutForView.sort == "size" + + let byName = UIAction(title: NSLocalizedString("_name_", comment: ""), image: isName ? ascendingChevronImage : nil, state: isName ? .on : .off) { _ in + + if isName { // repeated press + layoutForView.ascending = !layoutForView.ascending + } + layoutForView.sort = "fileName" + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let byNewest = UIAction(title: NSLocalizedString("_date_", comment: ""), image: isDate ? ascendingChevronImage : nil, state: isDate ? .on : .off) { _ in + + if isDate { // repeated press + layoutForView.ascending = !layoutForView.ascending + } + layoutForView.sort = "date" + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let byLargest = UIAction(title: NSLocalizedString("_size_", comment: ""), image: isSize ? ascendingChevronImage : nil, state: isSize ? .on : .off) { _ in + + if isSize { // repeated press + layoutForView.ascending = !layoutForView.ascending + } + layoutForView.sort = "size" + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let sortSubmenu = UIMenu(title: NSLocalizedString("_order_by_", comment: ""), options: .displayInline, children: [byName, byNewest, byLargest]) + + let foldersOnTop = UIAction(title: NSLocalizedString("_directory_on_top_no_", comment: ""), image: utility.loadImage(named: "folder"), state: layoutForView.directoryOnTop ? .on : .off) { _ in + + layoutForView.directoryOnTop = !layoutForView.directoryOnTop + + NotificationCenter.default.postOnMainThread(name: self.global.notificationCenterChangeLayout, + object: nil, + userInfo: ["account": self.session.account, + "serverUrl": self.serverUrl, + "layoutForView": layoutForView]) + } + + let personalFilesOnly = NCKeychain().getPersonalFilesOnly(account: session.account) + let personalFilesOnlyAction = UIAction(title: NSLocalizedString("_personal_files_only_", comment: ""), image: utility.loadImage(named: "folder.badge.person.crop", colors: NCBrandColor.shared.iconImageMultiColors), state: personalFilesOnly ? .on : .off) { _ in + + NCKeychain().setPersonalFilesOnly(account: self.session.account, value: !personalFilesOnly) + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": self.serverUrl, "clearDataSource": true]) + self.setNavigationRightItems() + } + + let showDescriptionKeychain = NCKeychain().showDescription + let showDescription = UIAction(title: NSLocalizedString("_show_description_", comment: ""), image: utility.loadImage(named: "list.dash.header.rectangle"), attributes: richWorkspaceText == nil ? .disabled : [], state: showDescriptionKeychain && richWorkspaceText != nil ? .on : .off) { _ in + + NCKeychain().showDescription = !showDescriptionKeychain + + NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource, userInfo: ["serverUrl": self.serverUrl, "clearDataSource": true]) + self.setNavigationRightItems() + } + showDescription.subtitle = richWorkspaceText == nil ? NSLocalizedString("_no_description_available_", comment: "") : "" + + if layoutKey == global.layoutViewRecent { + return [select] + } else { + var additionalSubmenu = UIMenu() + if layoutKey == global.layoutViewFiles { + additionalSubmenu = UIMenu(title: "", options: .displayInline, children: [foldersOnTop, personalFilesOnlyAction, showDescription]) + } else { + additionalSubmenu = UIMenu(title: "", options: .displayInline, children: [foldersOnTop, showDescription]) + } + return [select, viewStyleSubmenu, sortSubmenu, additionalSubmenu] + } + } + + if isEditMode { + /// 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) + self.collectionView.reloadData() + } + navigationItem.rightBarButtonItems = [select] + } else if navigationItem.rightBarButtonItems == nil || (!isEditMode && !tabBarSelect.isHidden()) { + /// 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 == global.layoutViewFiles { + let notification = UIBarButtonItem(image: utility.loadImage(named: "bell"), style: .plain) { + if let viewController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? NCNotification { + viewController.session = self.session + self.navigationController?.pushViewController(viewController, animated: true) + } + } + notification.tintColor = NCBrandColor.shared.iconImageColor + navigationItem.rightBarButtonItems = [menuButton, notification] + } else { + navigationItem.rightBarButtonItems = [menuButton] + } + } else { + navigationItem.rightBarButtonItems?.first?.menu = navigationItem.rightBarButtonItems?.first?.menu?.replacingChildren(createMenuActions()) + } + + 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 { let tableAccount = self.database.getTableAccount(predicate: NSPredicate(format: "account == %@", session.account)) if let tableAccount, @@ -751,7 +1047,30 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS func longPressListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } - func longPressGridItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } + 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) { + } func longPressMoreListItem(with ocId: String, ocIdTransfer: String, gestureRecognizer: UILongPressGestureRecognizer) { } @@ -927,28 +1246,31 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS // MARK: - Header size - func getHeaderHeight(section: Int) -> (heightHeaderRichWorkspace: CGFloat, - heightHeaderRecommendations: CGFloat, - heightHeaderSection: CGFloat) { - var heightHeaderRichWorkspace: CGFloat = 0 - var heightHeaderRecommendations: CGFloat = 0 - var heightHeaderSection: CGFloat = 0 + func getHeaderHeight(section: Int) -> (heightHeaderCommands: CGFloat, heightHeaderRichWorkspace: CGFloat, heightHeaderSection: CGFloat) { + var headerRichWorkspace: CGFloat = 0 - if showDescription, - !isSearchingMode, - let richWorkspaceText = self.richWorkspaceText, - !richWorkspaceText.trimmingCharacters(in: .whitespaces).isEmpty { - heightHeaderRichWorkspace = UIScreen.main.bounds.size.height / 6 - } + func getHeaderHeight() -> CGFloat { + var size: CGFloat = 0 - if isRecommendationActived, - !isSearchingMode, - NCKeychain().showRecommendedFiles, - !self.database.getRecommendedFiles(account: self.session.account).isEmpty { - heightHeaderRecommendations = self.heightHeaderRecommendations - heightHeaderSection = self.heightHeaderSection + if isHeaderMenuTransferViewEnabled() != nil { + if !isSearchingMode { + size += global.heightHeaderTransfer + } + } + if headerMenuButtonsView { + size += NCGlobal.shared.heightButtonsView + } + return size } +// if isRecommendationActived, +// !isSearchingMode, +// NCKeychain().showRecommendedFiles, +// !self.database.getRecommendedFiles(account: self.session.account).isEmpty { +// heightHeaderRecommendations = self.heightHeaderRecommendations +// heightHeaderSection = self.heightHeaderSection +// } + if isSearchingMode || layoutForView?.groupBy != "none" || self.dataSource.numberOfSections() > 1 { if section == 0 { return (heightHeaderRichWorkspace, heightHeaderRecommendations, self.heightHeaderSection) diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift index 27d81de6b1..83bef696ab 100644 --- a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.swift @@ -26,16 +26,40 @@ import MarkdownKit import NextcloudKit protocol NCSectionFirstHeaderDelegate: AnyObject { + func tapButtonSwitch(_ sender: Any) + func tapButtonOrder(_ sender: Any) + func tapButtonTransfer(_ sender: Any) func tapRichWorkspace(_ sender: Any) func tapRecommendations(with metadata: tableMetadata) func tapRecommendationsButtonMenu(with metadata: tableMetadata, image: UIImage?) } +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! + @IBOutlet weak var progressTransfer: UIProgressView! + @IBOutlet weak var transferSeparatorBottom: UIView! + @IBOutlet weak var textViewRichWorkspace: UITextView! + @IBOutlet weak var labelSection: UILabel! + @IBOutlet weak var viewTransfer: UIView! @IBOutlet weak var viewRichWorkspace: UIView! @IBOutlet weak var viewRecommendations: 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 viewRecommendationsHeightConstraint: NSLayoutConstraint! @IBOutlet weak var viewSectionHeightConstraint: NSLayoutConstraint! @@ -62,6 +86,18 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat richWorkspaceGradient.startPoint = CGPoint(x: 0, y: 0.8) richWorkspaceGradient.endPoint = CGPoint(x: 0, y: 0.9) viewRichWorkspace.layer.addSublayer(richWorkspaceGradient) + 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) +// gradient.endPoint = CGPoint(x: 0, y: 0.9) +// viewRichWorkspace.layer.addSublayer(gradient) let tap = UITapGestureRecognizer(target: self, action: #selector(touchUpInsideViewRichWorkspace(_:))) tap.delegate = self @@ -90,6 +126,19 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat // labelSection.text = "" viewSectionHeightConstraint.constant = 0 + + buttonTransfer.backgroundColor = .clear + buttonTransfer.setImage(nil, for: .normal) + buttonTransfer.layer.cornerRadius = 6 + buttonTransfer.layer.masksToBounds = true + imageButtonTransfer.image = NCUtility().loadImage(named: "stop.circle") + imageButtonTransfer.tintColor = .white + labelTransfer.text = "" + progressTransfer.progress = 0 + progressTransfer.tintColor = NCBrandColor.shared.brandElement + progressTransfer.trackTintColor = NCBrandColor.shared.brandElement.withAlphaComponent(0.2) + transferSeparatorBottom.backgroundColor = .separator + transferSeparatorBottomHeightConstraint.constant = 0.5 } override func layoutSublayers(of layer: CALayer) { @@ -105,6 +154,41 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat setRichWorkspaceColor() } + // 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 setContent(heightHeaderRichWorkspace: CGFloat, richWorkspaceText: String?, heightHeaderRecommendations: CGFloat, @@ -116,7 +200,7 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat viewRichWorkspaceHeightConstraint.constant = heightHeaderRichWorkspace viewRecommendationsHeightConstraint.constant = heightHeaderRecommendations viewSectionHeightConstraint.constant = heightHeaderSection - + if let richWorkspaceText, richWorkspaceText != self.richWorkspaceText { textViewRichWorkspace.attributedText = markdownParser.parse(richWorkspaceText) self.richWorkspaceText = richWorkspaceText @@ -126,17 +210,48 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat self.labelSection.text = sectionText self.viewController = viewController self.delegate = delegate - + if heightHeaderRichWorkspace != 0, let richWorkspaceText, !richWorkspaceText.isEmpty { viewRichWorkspace.isHidden = false } else { viewRichWorkspace.isHidden = true } + } + + func setRichWorkspaceText(_ text: String?) { + guard let text = text else { return } + + if text != self.richWorkspaceText { + textViewRichWorkspace.attributedText = markdownParser.parse(text) + self.richWorkspaceText = text + } + } - if heightHeaderRecommendations != 0 && !recommendations.isEmpty { - viewRecommendations.isHidden = false + // MARK: - Transfer + + func setViewTransfer(isHidden: Bool, ocId: String? = nil, text: String? = nil, progress: Float? = nil) { + labelTransfer.text = text + viewTransfer.isHidden = isHidden + progressTransfer.progress = 0 + + if isHidden { + viewTransferHeightConstraint.constant = 0 } else { - viewRecommendations.isHidden = true + var image: UIImage? + if let ocId, + let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) { + image = utility.getIcon(metadata: metadata)?.darken() + if image == nil { + image = utility.loadImage(named: metadata.iconName, useTypeIconFile: true) + buttonTransfer.backgroundColor = .lightGray + } else { + buttonTransfer.backgroundColor = .clear + } + } + viewTransferHeightConstraint.constant = NCGlobal.shared.heightHeaderTransfer + if let progress { + progressTransfer.progress = progress + } } if heightHeaderSection == 0 { @@ -157,6 +272,20 @@ class NCSectionFirstHeader: UICollectionReusableView, UIGestureRecognizerDelegat richWorkspaceGradient.colors = [UIColor(white: 1, alpha: 0).cgColor, UIColor.white.cgColor] } } + + // 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) + } @objc func touchUpInsideViewRichWorkspace(_ sender: Any) { delegate?.tapRichWorkspace(sender) diff --git a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib index 1206a44a6a..528b2f0098 100644 --- a/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib +++ b/iOSClient/Main/Collection Common/Section Header Footer/NCSectionFirstHeader.xib @@ -1,24 +1,76 @@ - + - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -26,98 +78,138 @@ - - - - - + + + + + - - + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + - - + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + + + + - - + + diff --git a/iOSClient/Main/NCActionCenter.swift b/iOSClient/Main/NCActionCenter.swift index 47e3c59a48..7e95250cf0 100644 --- a/iOSClient/Main/NCActionCenter.swift +++ b/iOSClient/Main/NCActionCenter.swift @@ -444,6 +444,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 @@ -654,3 +703,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 b648d75cf8..0600ec2b08 100644 --- a/iOSClient/Menu/NCMenuAction.swift +++ b/iOSClient/Menu/NCMenuAction.swift @@ -192,6 +192,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, 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 0050d669ec..42f02207d1 100644 --- a/iOSClient/Offline/NCOffline.swift +++ b/iOSClient/Offline/NCOffline.swift @@ -35,6 +35,7 @@ class NCOffline: NCCollectionViewCommon { enableSearchBar = false headerRichWorkspaceDisable = true emptyImageName = "icloud.and.arrow.down" + emptyImage = UIImage(named: "folder") emptyTitle = "_files_no_files_" emptyDescription = "_tutorial_offline_view_" emptyDataPortaitOffset = 30 From 140aface3c3081ecf65ca8775b68009749a07daf Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Thu, 30 Nov 2023 15:09:33 +0530 Subject: [PATCH 2/2] NMC 2172 - dashboard theming customisation --- ...nViewCommon+CollectionViewDataSource.swift | 17 +++++++++++++ .../NCCollectionViewCommon.swift | 25 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift index bef043ea8b..85309dcead 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDataSource.swift @@ -446,6 +446,23 @@ extension NCCollectionViewCommon: UICollectionViewDataSource { cell.fileSharedLabel?.textColor = NCBrandColor.shared.notificationAction } + // Button More + if metadata.isInTransfer || metadata.isWaitingTransfer { + cell.setButtonMore(named: NCGlobal.shared.buttonMoreStop, image: NCImageCache.images.buttonStop) + } else if metadata.lock == true { + cell.setButtonMore(named: NCGlobal.shared.buttonMoreLock, image: NCImageCache.images.buttonMoreLock) + a11yValues.append(String(format: NSLocalizedString("_locked_by_", comment: ""), metadata.lockOwnerDisplayName)) + } 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.lock == true { cell.setButtonMore(image: imageCache.getImageButtonMoreLock()) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 0fed0bfdf3..cde1f90f23 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -1069,6 +1069,28 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) } + 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) { } @@ -1260,6 +1282,9 @@ class NCCollectionViewCommon: UIViewController, UIGestureRecognizerDelegate, UIS if headerMenuButtonsView { size += NCGlobal.shared.heightButtonsView } + if headerMenuButtonsView { + size += NCGlobal.shared.heightButtonsView + } return size }