From 1e254fdf56ab34f22e4b051794a8e0c179bbaab1 Mon Sep 17 00:00:00 2001 From: Shweta Waikar Date: Wed, 28 Jun 2023 12:11:45 +0530 Subject: [PATCH 1/4] NMC 2341 - Theming changes --- iOSClient/NCGlobal.swift | 1 + iOSClient/Trash/Cell/NCTrashGridCell.swift | 146 ++++++------- iOSClient/Trash/Cell/NCTrashGridCell.xib | 214 +++++++++---------- iOSClient/Trash/Cell/NCTrashListCell.swift | 8 +- iOSClient/Trash/NCTrash+CollectionView.swift | 51 +++-- iOSClient/Trash/NCTrash.swift | 17 +- 6 files changed, 223 insertions(+), 214 deletions(-) diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index 51df24b68c..a57ae7944c 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -134,6 +134,7 @@ final class NCGlobal: Sendable { // let buttonMoreMore = "more" let buttonMoreLock = "moreLock" + let buttonMoreStop = "stop" // Rich Workspace // diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.swift b/iOSClient/Trash/Cell/NCTrashGridCell.swift index 0fae0620f7..62385894db 100644 --- a/iOSClient/Trash/Cell/NCTrashGridCell.swift +++ b/iOSClient/Trash/Cell/NCTrashGridCell.swift @@ -2,23 +2,8 @@ // NCTrashGridCell.swift // Nextcloud // -// Created by Marino Faggiana on 19/03/2024. -// 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 . +// Created by A200073704 on 27/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. // import UIKit @@ -29,20 +14,67 @@ protocol NCTrashGridCellDelegate: AnyObject { class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { + @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageSelect: UIImageView! + @IBOutlet weak var imageStatus: UIImageView! + @IBOutlet weak var imageFavorite: UIImageView! + @IBOutlet weak var imageLocal: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var labelInfo: UILabel! - @IBOutlet weak var labelSubinfo: UILabel! @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var imageVisualEffect: UIVisualEffectView! + @IBOutlet weak var progressView: UIProgressView! - weak var delegate: NCTrashGridCellDelegate? - var objectId = "" + internal var objectId = "" var indexPath = IndexPath() var account = "" var user = "" + weak var delegate: NCTrashGridCellDelegate? + var namedButtonMore = "" + + var fileObjectId: String? { + get { return objectId } + set { objectId = newValue ?? "" } + } + var filePreviewImageView: UIImageView? { + get { return imageItem } + set { imageItem = newValue } + } + var fileUser: String? { + get { return user } + set { user = newValue ?? "" } + } + var fileTitleLabel: UILabel? { + get { return labelTitle } + set { labelTitle = newValue } + } + var fileInfoLabel: UILabel? { + get { return labelInfo } + set { labelInfo = 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 } + } + var fileLocalImage: UIImageView? { + get { return imageLocal } + set { imageLocal = newValue } + } + var fileFavoriteImage: UIImageView? { + get { return imageFavorite } + set { imageFavorite = newValue } + } + override func awakeFromNib() { super.awakeFromNib() initCell() @@ -66,9 +98,14 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { imageVisualEffect.clipsToBounds = true imageVisualEffect.alpha = 0.5 + progressView.tintColor = NCBrandColor.shared.brandElement + progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) + progressView.trackTintColor = .clear + labelTitle.text = "" labelInfo.text = "" - labelSubinfo.text = "" + labelTitle.textColor = .label + labelInfo.textColor = .systemGray } override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? { @@ -79,7 +116,10 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { delegate?.tapMoreGridItem(with: objectId, image: imageItem.image, sender: sender) } + fileprivate func setA11yActions() { + let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_" + self.accessibilityCustomActions = [ UIAccessibilityCustomAction( name: NSLocalizedString("_more_", comment: ""), @@ -88,7 +128,8 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { ] } - func setButtonMore(image: UIImage) { + func setButtonMore(named: String, image: UIImage) { + namedButtonMore = named buttonMore.setImage(image, for: .normal) setA11yActions() } @@ -110,7 +151,7 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { imageSelect.isHidden = false imageVisualEffect.isHidden = false } else { - imageSelect.isHidden = true + imageSelect.image = NCImageCache.shared.getImageCheckedNo() imageVisualEffect.isHidden = true } } @@ -121,8 +162,7 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { dateFormatter.timeStyle = .none dateFormatter.locale = Locale.current - labelInfo.text = dateFormatter.string(from: date as Date) - labelSubinfo.text = NCUtilityFileSystem().transformedSize(size) + labelInfo.text = dateFormatter.string(from: date as Date) + " · " + NCUtilityFileSystem().transformedSize(size) } func setAccessibility(label: String, value: String) { @@ -130,59 +170,3 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { accessibilityValue = value } } - -// MARK: - Grid Layout - -class NCTrashGridLayout: UICollectionViewFlowLayout { - - var heightLabelPlusButton: CGFloat = 60 - var marginLeftRight: CGFloat = 10 - var itemForLine: CGFloat = 3 - var itemWidthDefault: CGFloat = 140 - - // MARK: - View Life Cycle - - override init() { - super.init() - - sectionHeadersPinToVisibleBounds = false - - minimumInteritemSpacing = 1 - minimumLineSpacing = marginLeftRight - - self.scrollDirection = .vertical - self.sectionInset = UIEdgeInsets(top: 10, left: marginLeftRight, bottom: 0, right: marginLeftRight) - } - - required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override var itemSize: CGSize { - get { - if let collectionView = collectionView { - - if collectionView.frame.width < 400 { - itemForLine = 3 - } else { - itemForLine = collectionView.frame.width / itemWidthDefault - } - - let itemWidth: CGFloat = (collectionView.frame.width - marginLeftRight * 2 - marginLeftRight * (itemForLine - 1)) / itemForLine - let itemHeight: CGFloat = itemWidth + heightLabelPlusButton - - return CGSize(width: itemWidth, height: itemHeight) - } - - // Default fallback - return CGSize(width: itemWidthDefault, height: itemWidthDefault) - } - set { - super.itemSize = newValue - } - } - - override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { - return proposedContentOffset - } -} diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.xib b/iOSClient/Trash/Cell/NCTrashGridCell.xib index 607f2744c6..91bd5f805d 100644 --- a/iOSClient/Trash/Cell/NCTrashGridCell.xib +++ b/iOSClient/Trash/Cell/NCTrashGridCell.xib @@ -1,9 +1,9 @@ - - + + - + @@ -11,140 +11,130 @@ - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + - - - - - - - + + + + + + + + + + - + - - + - - - - - - - + diff --git a/iOSClient/Trash/Cell/NCTrashListCell.swift b/iOSClient/Trash/Cell/NCTrashListCell.swift index 5bd89e1615..d2df55c700 100644 --- a/iOSClient/Trash/Cell/NCTrashListCell.swift +++ b/iOSClient/Trash/Cell/NCTrashListCell.swift @@ -46,6 +46,8 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { weak var delegate: NCTrashListCellDelegate? var objectId = "" var account = "" + var indexPath = IndexPath() + let utility = NCUtility() override func awakeFromNib() { super.awakeFromNib() @@ -72,8 +74,10 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { ] - imageRestore.image = NCUtility().loadImage(named: "arrow.counterclockwise", colors: [NCBrandColor.shared.iconImageColor]) - imageMore.image = NCUtility().loadImage(named: "trash", colors: [.red]) + imageRestore.image = utility.loadImage(named: "restore", color: NCBrandColor.shared.iconColor) + imageMore.image = UIImage(systemName: "trash") + imageMore.tintColor = NCBrandColor.shared.iconColor + imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true diff --git a/iOSClient/Trash/NCTrash+CollectionView.swift b/iOSClient/Trash/NCTrash+CollectionView.swift index 8995ce177c..94a2df94be 100644 --- a/iOSClient/Trash/NCTrash+CollectionView.swift +++ b/iOSClient/Trash/NCTrash+CollectionView.swift @@ -23,9 +23,11 @@ import UIKit import RealmSwift +import Foundation // MARK: UICollectionViewDelegate extension NCTrash: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { guard let resultTableTrash = datasource?[indexPath.item] else { return } guard !isEditMode else { @@ -35,7 +37,7 @@ extension NCTrash: UICollectionViewDelegate { selectOcId.append(resultTableTrash.fileId) } collectionView.reloadItems(at: [indexPath]) - tabBarSelect.update(selectOcId: selectOcId) + setNavigationRightItems() return } @@ -51,7 +53,9 @@ extension NCTrash: UICollectionViewDelegate { // MARK: UICollectionViewDataSource extension NCTrash: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + setNavigationRightItems() return datasource?.count ?? 0 } @@ -65,7 +69,7 @@ extension NCTrash: UICollectionViewDataSource { cell = listCell } else { let gridCell = (collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCTrashGridCell)! - gridCell.setButtonMore(image: NCImageCache.shared.getImageButtonMore()) + gridCell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.shared.getImageButtonMore()) gridCell.delegate = self cell = gridCell } @@ -93,12 +97,10 @@ extension NCTrash: UICollectionViewDataSource { } } } - cell.account = resultTableTrash.account cell.objectId = resultTableTrash.fileId cell.setupCellUI(tableTrash: resultTableTrash, image: image) cell.selected(selectOcId.contains(resultTableTrash.fileId), isEditMode: isEditMode, account: resultTableTrash.account) - return cell } @@ -142,18 +144,34 @@ extension NCTrash: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == UICollectionView.elementKindSectionHeader { - guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFirstHeaderEmptyData", for: indexPath) as? NCSectionFirstHeaderEmptyData - else { return NCSectionFirstHeaderEmptyData() } - header.emptyImage.image = utility.loadImage(named: "trash", colors: [NCBrandColor.shared.getElement(account: session.account)]) - header.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "") - header.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "") + + guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu + else { return UICollectionReusableView() } + + 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 + header.setStatusButtonsView(enable: !(datasource?.isEmpty ?? false)) + header.setSortedTitle(layoutForView?.titleButtonHeader ?? "") + header.setButtonsView(height: NCGlobal.shared.heightButtonsView) + header.setRichWorkspaceHeight(0) + header.setSectionHeight(0) + header.setViewTransfer(isHidden: true) + return header + } else { guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter - else { return NCSectionFooter() } - if let datasource { - footer.setTitleLabel(setTextFooter(datasource: datasource)) - } + else { return UICollectionReusableView() } + guard let datasource else { return footer } + footer.setTitleLabel(setTextFooter(datasource: datasource)) + footer.separatorIsHidden(true) return footer } } @@ -161,12 +179,9 @@ extension NCTrash: UICollectionViewDataSource { // MARK: UICollectionViewDelegateFlowLayout extension NCTrash: UICollectionViewDelegateFlowLayout { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - var height: Double = 0 - if let datasource, datasource.isEmpty { - height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: 0) - } - return CGSize(width: collectionView.frame.width, height: height) + return CGSize(width: collectionView.frame.width, height: NCGlobal.shared.heightButtonsView) } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: 85) diff --git a/iOSClient/Trash/NCTrash.swift b/iOSClient/Trash/NCTrash.swift index 797fba1e7c..9d588303a9 100644 --- a/iOSClient/Trash/NCTrash.swift +++ b/iOSClient/Trash/NCTrash.swift @@ -27,7 +27,7 @@ import UIKit import NextcloudKit import RealmSwift -class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate { +class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCSectionHeaderMenuDelegate { @IBOutlet weak var collectionView: UICollectionView! var filePath = "" @@ -68,6 +68,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat collectionView.register(UINib(nibName: "NCTrashGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") + collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") collectionView.alwaysBounceVertical = true @@ -158,6 +159,20 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat } } + func tapButtonSwitch(_ sender: Any) { + if layoutForView?.layout == NCGlobal.shared.layoutGrid { + onListSelected() + } else { + onGridSelected() + } + } + + func tapButtonOrder(_ sender: Any) { + + let sortMenu = NCSortMenu() + sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) + } + func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } func longPressMoreGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } From aa3fbf977d9c600ce0969f6f4a4ccd45851d2019 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Mon, 14 Apr 2025 16:57:15 +0530 Subject: [PATCH 2/4] NMC 2341 - NCTrashView changes --- iOSClient/Trash/Cell/NCTrashGridCell.swift | 11 ++- iOSClient/Trash/Cell/NCTrashListCell.swift | 10 ++- iOSClient/Trash/NCTrash+CollectionView.swift | 28 ++++--- iOSClient/Trash/NCTrash.swift | 78 +++++++++++++++++--- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.swift b/iOSClient/Trash/Cell/NCTrashGridCell.swift index 62385894db..85ee0fd190 100644 --- a/iOSClient/Trash/Cell/NCTrashGridCell.swift +++ b/iOSClient/Trash/Cell/NCTrashGridCell.swift @@ -14,7 +14,6 @@ protocol NCTrashGridCellDelegate: AnyObject { class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { - @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageSelect: UIImageView! @IBOutlet weak var imageStatus: UIImageView! @@ -122,7 +121,7 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { self.accessibilityCustomActions = [ UIAccessibilityCustomAction( - name: NSLocalizedString("_more_", comment: ""), + name: NSLocalizedString(moreName, comment: ""), target: self, selector: #selector(touchUpInsideMore(_:))) ] @@ -140,19 +139,23 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { func selected(_ status: Bool, isEditMode: Bool, account: String) { if isEditMode { + imageSelect.isHidden = false buttonMore.isHidden = true accessibilityCustomActions = nil } else { + imageSelect.isHidden = true buttonMore.isHidden = false + imageVisualEffect.isHidden = true setA11yActions() } if status { + let traitCollectionUserInterfaceStyleDark = traitCollection.userInterfaceStyle == .dark + imageVisualEffect.effect = UIBlurEffect(style: traitCollectionUserInterfaceStyleDark ? .dark : .extraLight) + imageVisualEffect.backgroundColor = traitCollectionUserInterfaceStyleDark ? .black : .lightGray imageSelect.image = NCImageCache.shared.getImageCheckedYes() - imageSelect.isHidden = false imageVisualEffect.isHidden = false } else { imageSelect.image = NCImageCache.shared.getImageCheckedNo() - imageVisualEffect.isHidden = true } } diff --git a/iOSClient/Trash/Cell/NCTrashListCell.swift b/iOSClient/Trash/Cell/NCTrashListCell.swift index d2df55c700..b9cfaf115a 100644 --- a/iOSClient/Trash/Cell/NCTrashListCell.swift +++ b/iOSClient/Trash/Cell/NCTrashListCell.swift @@ -74,7 +74,8 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { ] - imageRestore.image = utility.loadImage(named: "restore", color: NCBrandColor.shared.iconColor) + imageRestore.image = utility.loadImage(named: "restore", colors: [NCBrandColor.shared.iconColor]) + imageMore.image = UIImage(systemName: "trash") imageMore.tintColor = NCBrandColor.shared.iconColor @@ -112,8 +113,11 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { } if status { var blurEffectView: UIView? - blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) - blurEffectView?.backgroundColor = .lightGray + var blurEffect: UIVisualEffect? + let traitCollectionUserInterfaceStyleDark = traitCollection.userInterfaceStyle == .dark + blurEffect = UIBlurEffect(style: traitCollectionUserInterfaceStyleDark ? .dark : .extraLight) + blurEffectView = UIVisualEffectView(effect: blurEffect) + blurEffectView?.backgroundColor = traitCollectionUserInterfaceStyleDark ? .black : .lightGray blurEffectView?.frame = self.bounds blurEffectView?.autoresizingMask = [.flexibleWidth, .flexibleHeight] imageSelect.image = NCImageCache.shared.getImageCheckedYes() diff --git a/iOSClient/Trash/NCTrash+CollectionView.swift b/iOSClient/Trash/NCTrash+CollectionView.swift index 94a2df94be..849dae9472 100644 --- a/iOSClient/Trash/NCTrash+CollectionView.swift +++ b/iOSClient/Trash/NCTrash+CollectionView.swift @@ -29,14 +29,16 @@ import Foundation extension NCTrash: UICollectionViewDelegate { func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let resultTableTrash = datasource?[indexPath.item] else { return } + let resultTableTrash = datasource[indexPath.item] + guard !isEditMode else { - if let index = selectOcId.firstIndex(of: resultTableTrash.fileId) { - selectOcId.remove(at: index) + if let index = fileSelect.firstIndex(of: resultTableTrash.fileId) { + fileSelect.remove(at: index) } else { - selectOcId.append(resultTableTrash.fileId) + fileSelect.append(resultTableTrash.fileId) } collectionView.reloadItems(at: [indexPath]) + tabBarSelect.update(selectOcId: fileSelect) setNavigationRightItems() return } @@ -55,8 +57,10 @@ extension NCTrash: UICollectionViewDelegate { extension NCTrash: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + let numberOfItems = datasource.count + emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section) setNavigationRightItems() - return datasource?.count ?? 0 + return numberOfItems } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -73,14 +77,14 @@ extension NCTrash: UICollectionViewDataSource { gridCell.delegate = self cell = gridCell } - guard let resultTableTrash = datasource?[indexPath.item] else { return cell } - + + let resultTableTrash = datasource[indexPath.item] cell.imageItem.contentMode = .scaleAspectFit if resultTableTrash.iconName.isEmpty { image = NCImageCache.shared.getImageFile() } else { - image = NCUtility().loadImage(named: resultTableTrash.iconName, useTypeIconFile: true, account: resultTableTrash.account) + image = UIImage(named: resultTableTrash.iconName) } if let imageIcon = utility.getImage(ocId: resultTableTrash.fileId, @@ -157,7 +161,7 @@ extension NCTrash: UICollectionViewDataSource { } header.delegate = self - header.setStatusButtonsView(enable: !(datasource?.isEmpty ?? false)) + header.setStatusButtonsView(enable: !datasource.isEmpty) header.setSortedTitle(layoutForView?.titleButtonHeader ?? "") header.setButtonsView(height: NCGlobal.shared.heightButtonsView) header.setRichWorkspaceHeight(0) @@ -169,7 +173,6 @@ extension NCTrash: UICollectionViewDataSource { } else { guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return UICollectionReusableView() } - guard let datasource else { return footer } footer.setTitleLabel(setTextFooter(datasource: datasource)) footer.separatorIsHidden(true) return footer @@ -181,8 +184,13 @@ extension NCTrash: UICollectionViewDataSource { extension NCTrash: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + if datasource.isEmpty { + let height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -20) + return CGSize(width: collectionView.frame.width, height: height) + } return CGSize(width: collectionView.frame.width, height: NCGlobal.shared.heightButtonsView) } + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: 85) } diff --git a/iOSClient/Trash/NCTrash.swift b/iOSClient/Trash/NCTrash.swift index 9d588303a9..074de2955b 100644 --- a/iOSClient/Trash/NCTrash.swift +++ b/iOSClient/Trash/NCTrash.swift @@ -27,7 +27,7 @@ import UIKit import NextcloudKit import RealmSwift -class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCSectionHeaderMenuDelegate { +class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { @IBOutlet weak var collectionView: UICollectionView! var filePath = "" @@ -37,13 +37,14 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat let database = NCManageDatabase.shared let utility = NCUtility() var isEditMode = false - var selectOcId: [String] = [] + var fileSelect: [String] = [] var tabBarSelect: NCTrashSelectTabBar! var datasource: [tableTrash]? var layoutForView: NCDBLayoutForView? var listLayout: NCListLayout! var gridLayout: NCGridLayout! var layoutKey = NCGlobal.shared.layoutViewTrash + var layoutType = NCGlobal.shared.layoutList let refreshControl = UIRefreshControl() var filename: String? @@ -51,6 +52,11 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat var session: NCSession.Session { NCSession.shared.getSession(controller: tabBarController) } + + var serverUrl = "" + var selectableDataSource: [RealmSwiftObject] { datasource } + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var emptyDataSet: NCEmptyDataSet? var controller: NCMainTabBarController? { self.tabBarController as? NCMainTabBarController @@ -60,14 +66,14 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat override func viewDidLoad() { super.viewDidLoad() - navigationController?.setNavigationBarAppearance() + tabBarSelect = NCTrashSelectTabBar(tabBarController: tabBarController, delegate: self) + serverUrl = utilityFileSystem.getHomeServer(session: session) view.backgroundColor = .systemBackground collectionView.register(UINib(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") collectionView.register(UINib(nibName: "NCTrashGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") - collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") @@ -79,25 +85,29 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // Add Refresh Control collectionView.refreshControl = refreshControl - refreshControl.tintColor = NCBrandColor.shared.textColor2 + refreshControl.tintColor = .gray //NCBrandColor.shared.textColor2 refreshControl.action(for: .valueChanged) { _ in Task { await self.loadListingTrash() } } + // Empty + emptyDataSet = NCEmptyDataSet(view: collectionView, offset: NCGlobal.shared.heightButtonsView, delegate: self) + + NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(changeLayout(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeLayout), object: nil) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - if tabBarSelect == nil { - tabBarSelect = NCTrashSelectTabBar(controller: tabBarController, viewController: self, delegate: self) - } + appDelegate.activeViewController = self navigationController?.setNavigationBarAppearance() navigationItem.title = titleCurrentFolder layoutForView = self.database.getLayoutForView(account: session.account, key: NCGlobal.shared.layoutViewTrash, serverUrl: "") + gridLayout.column = CGFloat(layoutForView?.columnGrid ?? 3) if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView.collectionViewLayout = listLayout @@ -112,6 +122,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat await self.reloadDataSource() await loadListingTrash() } + AnalyticsHelper.shared.trackEvent(eventName: .SCREEN_EVENT__DELETED_FILES) } override func viewWillDisappear(_ animated: Bool) { @@ -123,6 +134,53 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // Cancel Queue & Retrieves Properties NCNetworking.shared.downloadThumbnailTrashQueue.cancelAll() + dataSourceTask?.cancel() + isEditMode = false + } + + override func viewWillLayoutSubviews() { + super.viewWillLayoutSubviews() + + if let frame = tabBarController?.tabBar.frame { + tabBarSelect.hostingController?.view.frame = frame + } + } + + // MARK: - Layout + + @objc func changeLayout(_ notification: NSNotification) { + guard let userInfo = notification.userInfo as NSDictionary?, + let account = userInfo["account"] as? String, + let serverUrl = userInfo["serverUrl"] as? String, + let layoutForView = userInfo["layoutForView"] as? NCDBLayoutForView, + account == session.account, + serverUrl == self.serverUrl + else { return } + + self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) + layoutForView.layout = layoutForView.layout + self.layoutType = layoutForView.layout +// self.reloadDataSource() + collectionView.reloadData() + + switch layoutForView.layout { + case NCGlobal.shared.layoutList: + self.collectionView.setCollectionViewLayout(self.listLayout, animated: true) + case NCGlobal.shared.layoutGrid: + self.collectionView.setCollectionViewLayout(self.gridLayout, animated: true) + default: + break + } + + self.collectionView.collectionViewLayout.invalidateLayout() + } + + // MARK: - Empty + + func emptyDataSetView(_ view: NCEmptyView) { + view.emptyImage.image = UIImage(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width) + view.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "") + view.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "") } // MARK: TAP EVENT @@ -170,7 +228,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat func tapButtonOrder(_ sender: Any) { let sortMenu = NCSortMenu() - sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) + sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) } func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } @@ -179,7 +237,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // MARK: - DataSource - func reloadDataSource(withQueryDB: Bool = true) async { + @objc func reloadDataSource(withQueryDB: Bool = true) async { let results = await self.database.getTableTrashAsync(filePath: getFilePath(), account: session.account) await (self.navigationController as? NCMainNavigationController)?.updateRightMenu() From ae5fe9ed2730e5db7c2586847267b8630c2018e3 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Tue, 30 Sep 2025 19:13:16 +0530 Subject: [PATCH 3/4] NMC 2341 - NCTrashView updated changes --- .../Trash/Cell/NCTrashCellProtocol.swift | 5 +- iOSClient/Trash/NCTrash+CollectionView.swift | 34 +++---- .../Trash/NCTrash+SelectTabBarDelegate.swift | 80 +++++++++++----- iOSClient/Trash/NCTrash.swift | 95 +++++++++---------- iOSClient/Trash/NCTrashSelectTabBar.swift | 50 ++++------ 5 files changed, 138 insertions(+), 126 deletions(-) diff --git a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift index 8c82abf6db..77f8e55ead 100644 --- a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift +++ b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift @@ -48,11 +48,12 @@ extension NCTrashCellProtocol where Self: UICollectionViewCell { self.labelInfo?.text = dateFormatter.string(from: tableTrash.trashbinDeletionTime as Date) } if tableTrash.directory { - self.imageItem.image = NCImageCache.shared.getFolder(account: tableTrash.account) + self.imageItem.image = NCImageCache.shared.getFolder() } else { self.imageItem.image = image - self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size) +// self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size) } + self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size) self.accessibilityLabel = tableTrash.trashbinFileName + ", " + (self.labelInfo?.text ?? "") } } diff --git a/iOSClient/Trash/NCTrash+CollectionView.swift b/iOSClient/Trash/NCTrash+CollectionView.swift index 849dae9472..c14ce8b394 100644 --- a/iOSClient/Trash/NCTrash+CollectionView.swift +++ b/iOSClient/Trash/NCTrash+CollectionView.swift @@ -27,9 +27,10 @@ import Foundation // MARK: UICollectionViewDelegate extension NCTrash: UICollectionViewDelegate { - + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let resultTableTrash = datasource[indexPath.item] + + guard let resultTableTrash = datasource?[indexPath.item] else { return } guard !isEditMode else { if let index = fileSelect.firstIndex(of: resultTableTrash.fileId) { @@ -57,10 +58,9 @@ extension NCTrash: UICollectionViewDelegate { extension NCTrash: UICollectionViewDataSource { func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - let numberOfItems = datasource.count - emptyDataSet?.numberOfItemsInSection(numberOfItems, section: section) + emptyDataSet?.numberOfItemsInSection(datasource?.count ?? 0, section: section) setNavigationRightItems() - return numberOfItems + return datasource?.count ?? 0 } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { @@ -78,7 +78,8 @@ extension NCTrash: UICollectionViewDataSource { cell = gridCell } - let resultTableTrash = datasource[indexPath.item] + guard let resultTableTrash = datasource?[indexPath.item] else { return cell } + cell.imageItem.contentMode = .scaleAspectFit if resultTableTrash.iconName.isEmpty { @@ -87,24 +88,21 @@ extension NCTrash: UICollectionViewDataSource { image = UIImage(named: resultTableTrash.iconName) } - if let imageIcon = utility.getImage(ocId: resultTableTrash.fileId, - etag: resultTableTrash.fileName, - ext: NCGlobal.shared.previewExt512, - userId: session.userId, - urlBase: session.urlBase) { + if let imageIcon = utility.getImage(ocId: resultTableTrash.fileId, etag: resultTableTrash.fileName, ext: NCGlobal.shared.previewExt512) { image = imageIcon cell.imageItem.contentMode = .scaleAspectFill } else { if resultTableTrash.hasPreview { if NCNetworking.shared.downloadThumbnailTrashQueue.operations.filter({ ($0 as? NCOperationDownloadThumbnailTrash)?.fileId == resultTableTrash.fileId }).isEmpty { - NCNetworking.shared.downloadThumbnailTrashQueue.addOperation(NCOperationDownloadThumbnailTrash(fileId: resultTableTrash.fileId, fileName: resultTableTrash.fileName, session: session, collectionView: collectionView)) + NCNetworking.shared.downloadThumbnailTrashQueue.addOperation(NCOperationDownloadThumbnailTrash(fileId: resultTableTrash.fileId, fileName: resultTableTrash.fileName, account: session.account, collectionView: collectionView)) } } } + cell.account = resultTableTrash.account cell.objectId = resultTableTrash.fileId cell.setupCellUI(tableTrash: resultTableTrash, image: image) - cell.selected(selectOcId.contains(resultTableTrash.fileId), isEditMode: isEditMode, account: resultTableTrash.account) + cell.selected(fileSelect.contains(resultTableTrash.fileId), isEditMode: isEditMode, account: resultTableTrash.account) return cell } @@ -161,7 +159,7 @@ extension NCTrash: UICollectionViewDataSource { } header.delegate = self - header.setStatusButtonsView(enable: !datasource.isEmpty) + header.setStatusButtonsView(enable: !(datasource?.isEmpty ?? false)) header.setSortedTitle(layoutForView?.titleButtonHeader ?? "") header.setButtonsView(height: NCGlobal.shared.heightButtonsView) header.setRichWorkspaceHeight(0) @@ -173,8 +171,10 @@ extension NCTrash: UICollectionViewDataSource { } else { guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter else { return UICollectionReusableView() } - footer.setTitleLabel(setTextFooter(datasource: datasource)) - footer.separatorIsHidden(true) + if let datasource { + footer.setTitleLabel(setTextFooter(datasource: datasource)) + footer.separatorIsHidden(true) + } return footer } } @@ -184,7 +184,7 @@ extension NCTrash: UICollectionViewDataSource { extension NCTrash: UICollectionViewDelegateFlowLayout { func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - if datasource.isEmpty { + if let datasource, datasource.isEmpty { let height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -20) return CGSize(width: collectionView.frame.width, height: height) } diff --git a/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift b/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift index 677047688c..14b0e071ca 100644 --- a/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift +++ b/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift @@ -22,7 +22,7 @@ import Foundation import UIKit -extension NCTrash: NCTrashSelectTabBarDelegate { +extension NCTrash: NCTrashSelectTabBarDelegate, NCSelectableNavigationView { func onListSelected() { if layoutForView?.layout == NCGlobal.shared.layoutGrid { layoutForView?.layout = NCGlobal.shared.layoutList @@ -44,51 +44,81 @@ extension NCTrash: NCTrashSelectTabBarDelegate { } func selectAll() { - guard let datasource else { return } - if !selectOcId.isEmpty, datasource.count == selectOcId.count { - selectOcId = [] + if !fileSelect.isEmpty, datasource?.count == fileSelect.count { + fileSelect = [] } else { - selectOcId = datasource.compactMap({ $0.fileId }) + fileSelect = (datasource?.compactMap({ $0.fileId }))! } - tabBarSelect.update(selectOcId: selectOcId) + tabBarSelect.update(selectOcId: fileSelect) collectionView.reloadData() } func recover() { - let ids = selectOcId.map { $0 } + fileSelect.forEach(restoreItem) setEditMode(false) - - Task { - for id in ids { - await restoreItem(with: id) - } - } } func delete() { - let ids = selectOcId.map { $0 } + let ocIds = fileSelect.map { $0 } setEditMode(false) Task { - if ids.count > 0, ids.count == datasource?.count { + if ocIds.count > 0, ocIds.count == datasource?.count { await emptyTrash() } else { - await self.deleteItems(with: ids) + await self.deleteItems(with: ocIds) } } } func setEditMode(_ editMode: Bool) { - Task { - isEditMode = editMode - selectOcId.removeAll() + isEditMode = editMode + fileSelect.removeAll() - navigationItem.hidesBackButton = editMode - navigationController?.interactivePopGestureRecognizer?.isEnabled = !editMode - - await (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() - - collectionView.reloadData() + navigationController?.interactivePopGestureRecognizer?.isEnabled = !editMode + navigationItem.hidesBackButton = editMode + DispatchQueue.main.async { + self.collectionView.reloadData() + self.setNavigationRightItems() } } + + func setNavigationRightItems(enableMenu: Bool = false) { + if isEditMode { + let more = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .plain) { self.presentMenu(with: self.selectActions)} + navigationItem.rightBarButtonItems = [more] + } else { + let select = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain) { self.toggleSelect() } + let notification = UIBarButtonItem(image: UIImage(systemName: "bell"), style: .plain, action: tapNotification) + if layoutKey == NCGlobal.shared.layoutViewFiles { + navigationItem.rightBarButtonItems = [select, notification] + } else { + navigationItem.rightBarButtonItems = [select] + } + } + guard layoutKey == NCGlobal.shared.layoutViewFiles else { return } + navigationItem.title = titleCurrentFolder + } + + func createMenuActions() -> [NCMenuAction] { +// guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: "") else { return [] } +// +// let select = UIAction(title: NSLocalizedString("_select_", comment: ""), image: .init(systemName: "checkmark.circle"), attributes: datasource.isEmpty ? .disabled : []) { _ in +// self.setEditMode(true) +// } +// +// let list = UIAction(title: NSLocalizedString("_list_", comment: ""), image: .init(systemName: "list.bullet"), state: layoutForView.layout == NCGlobal.shared.layoutList ? .on : .off) { _ in +// self.onListSelected() +//// self.setNavigationRightItems() +// } +// +// let grid = UIAction(title: NSLocalizedString("_icons_", comment: ""), image: .init(systemName: "square.grid.2x2"), state: layoutForView.layout == NCGlobal.shared.layoutGrid ? .on : .off) { _ in +// self.onGridSelected() +//// self.setNavigationRightItems() +// } +// +// let viewStyleSubmenu = UIMenu(title: "", options: .displayInline, children: [list, grid]) +// + return []//[select, viewStyleSubmenu] + } } diff --git a/iOSClient/Trash/NCTrash.swift b/iOSClient/Trash/NCTrash.swift index 074de2955b..8a0d7c0ab2 100644 --- a/iOSClient/Trash/NCTrash.swift +++ b/iOSClient/Trash/NCTrash.swift @@ -25,6 +25,7 @@ import UIKit import NextcloudKit +import Realm import RealmSwift class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { @@ -33,6 +34,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat var filePath = "" var titleCurrentFolder = NSLocalizedString("_trash_view_", comment: "") var blinkFileId: String? + var dataSourceTask: URLSessionTask? let utilityFileSystem = NCUtilityFileSystem() let database = NCManageDatabase.shared let utility = NCUtility() @@ -47,33 +49,34 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat var layoutType = NCGlobal.shared.layoutList let refreshControl = UIRefreshControl() var filename: String? - - @MainActor var session: NCSession.Session { NCSession.shared.getSession(controller: tabBarController) } - var serverUrl = "" - var selectableDataSource: [RealmSwiftObject] { datasource } - private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! - var emptyDataSet: NCEmptyDataSet? - var controller: NCMainTabBarController? { self.tabBarController as? NCMainTabBarController } + var serverUrl = "" + var selectableDataSource: [RealmSwiftObject] { datasource ?? [] } + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + var emptyDataSet: NCEmptyDataSet? + // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() + tabBarSelect = NCTrashSelectTabBar(tabBarController: tabBarController, delegate: self) serverUrl = utilityFileSystem.getHomeServer(session: session) view.backgroundColor = .systemBackground + self.navigationController?.navigationBar.prefersLargeTitles = true collectionView.register(UINib(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") collectionView.register(UINib(nibName: "NCTrashGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") +// collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") @@ -85,12 +88,9 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // Add Refresh Control collectionView.refreshControl = refreshControl - refreshControl.tintColor = .gray //NCBrandColor.shared.textColor2 - refreshControl.action(for: .valueChanged) { _ in - Task { - await self.loadListingTrash() - } - } + refreshControl.tintColor = .gray + refreshControl.addTarget(self, action: #selector(loadListingTrash), for: .valueChanged) + // Empty emptyDataSet = NCEmptyDataSet(view: collectionView, offset: NCGlobal.shared.heightButtonsView, delegate: self) @@ -116,22 +116,18 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat } isEditMode = false + setNavigationRightItems() - Task { - await (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() - await self.reloadDataSource() - await loadListingTrash() - } + reloadDataSource() + loadListingTrash(nil) + AnalyticsHelper.shared.trackEvent(eventName: .SCREEN_EVENT__DELETED_FILES) + } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - Task { - await NCNetworking.shared.networkingTasks.cancel(identifier: "NCTrash") - } - // Cancel Queue & Retrieves Properties NCNetworking.shared.downloadThumbnailTrashQueue.cancelAll() dataSourceTask?.cancel() @@ -185,11 +181,9 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // MARK: TAP EVENT - func tapRestoreListItem(with id: String, image: UIImage?, sender: Any) { + func tapRestoreListItem(with ocId: String, image: UIImage?, sender: Any) { if !isEditMode { - Task { - await restoreItem(with: id) - } + restoreItem(with: ocId) } else if let button = sender as? UIView { let buttonPosition = button.convert(CGPoint.zero, to: collectionView) let indexPath = collectionView.indexPathForItem(at: buttonPosition) @@ -228,6 +222,7 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat func tapButtonOrder(_ sender: Any) { let sortMenu = NCSortMenu() +// sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) } @@ -237,28 +232,32 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // MARK: - DataSource - @objc func reloadDataSource(withQueryDB: Bool = true) async { - let results = await self.database.getTableTrashAsync(filePath: getFilePath(), account: session.account) - - await (self.navigationController as? NCMainNavigationController)?.updateRightMenu() - - await MainActor.run { - self.datasource = results - self.collectionView.reloadData() - - guard let blinkFileId = self.blinkFileId else { return } - - for itemIx in 0.. Date: Mon, 15 Dec 2025 12:54:00 +0530 Subject: [PATCH 4/4] NMC 2341 - NCTrashView updated changes --- iOSClient/NCGlobal.swift | 56 ++++- .../Trash/Cell/NCTrashCellProtocol.swift | 3 +- iOSClient/Trash/Cell/NCTrashGridCell.swift | 136 ++++++----- iOSClient/Trash/Cell/NCTrashGridCell.xib | 214 +++++++++--------- iOSClient/Trash/Cell/NCTrashListCell.swift | 16 +- iOSClient/Trash/NCTrash+CollectionView.swift | 103 +++------ .../Trash/NCTrash+SelectTabBarDelegate.swift | 80 ++----- iOSClient/Trash/NCTrash.swift | 192 ++++++---------- iOSClient/Trash/NCTrashSelectTabBar.swift | 50 ++-- 9 files changed, 400 insertions(+), 450 deletions(-) diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift index a57ae7944c..b445f506ab 100644 --- a/iOSClient/NCGlobal.swift +++ b/iOSClient/NCGlobal.swift @@ -60,13 +60,14 @@ final class NCGlobal: Sendable { // Intro selector // let introLogin: Int = 0 + let introSignup: Int = 1 let introSignUpWithProvider: Int = 1 // Avatar // let avatarSize: Int = 128 * Int(UIScreen.main.scale) let avatarSizeRounded: Int = 128 - + // Preview size // let size1024: CGSize = CGSize(width: 1024, height: 1024) @@ -136,6 +137,33 @@ final class NCGlobal: Sendable { let buttonMoreLock = "moreLock" let buttonMoreStop = "stop" + // Standard height sections header/footer + // + let heightButtonsView: CGFloat = 50 + let heightHeaderTransfer: CGFloat = 50 + let heightSection: CGFloat = 30 + let heightFooter: CGFloat = 1 + let heightFooterButton: CGFloat = 30 + let endHeightFooter: CGFloat = 85 + + + // Text - OnlyOffice - Collabora - QuickLook + // + let editorText = "text" + let editorOnlyoffice = "onlyoffice" + let editorCollabora = "collabora" + let editorQuickLook = "quicklook" + + let onlyofficeDocx = "onlyoffice_docx" + let onlyofficeXlsx = "onlyoffice_xlsx" + let onlyofficePptx = "onlyoffice_pptx" + + // Template + // + let templateDocument = "document" + let templateSpreadsheet = "spreadsheet" + let templatePresentation = "presentation" + // Rich Workspace // let fileNameRichWorkspace = "Readme.md" @@ -218,6 +246,8 @@ final class NCGlobal: Sendable { let selectorSaveAsScan = "saveAsScan" let selectorOpenDetail = "openDetail" let selectorSynchronizationOffline = "synchronizationOffline" + let selectorPrint = "print" + let selectorDeleteFile = "deleteFile" // Metadata : Status // @@ -248,7 +278,6 @@ final class NCGlobal: Sendable { let metadataStatusForScreenAwake = [-1, -2, 1, 2] let metadataStatusHideInView = [1, 2, 3, 11] let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15] - let metadataStatusTransfers = [-2, -3, 2, 3, 10, 11, 12, 13, 14, 15] let metadatasStatusInWaiting = [-1, 1, 10, 11, 12, 13, 14, 15] let metadatasStatusInProgress = [-2, 2] @@ -265,6 +294,8 @@ final class NCGlobal: Sendable { let notificationCenterChangeTheming = "changeTheming" // userInfo: account let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus" let notificationCenterReloadDataNCShare = "reloadDataNCShare" + let notificationCenterDidCreateShareLink = "didCreateShareLink" + let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView" let notificationCenterReloadAvatar = "reloadAvatar" let notificationCenterClearCache = "clearCache" @@ -272,6 +303,8 @@ final class NCGlobal: Sendable { let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account let notificationCenterNetworkReachability = "networkReachability" + let notificationCenterRenameFile = "renameFile" // userInfo: serverUrl, account, error + let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF" let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF" @@ -286,6 +319,8 @@ final class NCGlobal: Sendable { let notificationCenterPlayerIsPlaying = "playerIsPlaying" let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying" + let notificationCenterFavoriteStatusChanged = "favoriteStatusChanged" + // Networking Status let networkingStatusCreateFolder = "statusCreateFolder" let networkingStatusDelete = "statusDelete" @@ -300,8 +335,9 @@ final class NCGlobal: Sendable { let networkingStatusUploading = "statusUploading" let networkingStatusUploaded = "statusUploaded" - let networkingStatusReloadAvatar = "statusReloadAvatar" + let networkingStatusReloadAvatar = "statusReloadAvatar" + let notificationCenterUpdateIcons = "updateIcons" // TIP // @@ -384,6 +420,20 @@ final class NCGlobal: Sendable { // let taskDescriptionRetrievesProperties = "retrievesProperties" let taskDescriptionSynchronization = "synchronization" + let taskDescriptionDeleteFileOrFolder = "deleteFileOrFolder" + + // MoEngage App Version + // + let moEngageAppVersion = 854 + + // Filename Mask and Type + // + let keyFileNameMask = "fileNameMask" + let keyFileNameType = "fileNameType" + let keyFileNameAutoUploadMask = "fileNameAutoUploadMask" + let keyFileNameAutoUploadType = "fileNameAutoUploadType" + let keyFileNameOriginal = "fileNameOriginal" + let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload" // LOG TAG // diff --git a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift index 77f8e55ead..c2776c1215 100644 --- a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift +++ b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift @@ -48,10 +48,9 @@ extension NCTrashCellProtocol where Self: UICollectionViewCell { self.labelInfo?.text = dateFormatter.string(from: tableTrash.trashbinDeletionTime as Date) } if tableTrash.directory { - self.imageItem.image = NCImageCache.shared.getFolder() + self.imageItem.image = NCImageCache.shared.getFolder(account: tableTrash.account) } else { self.imageItem.image = image -// self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size) } self.labelInfo?.text = (self.labelInfo?.text ?? "") + " · " + NCUtilityFileSystem().transformedSize(tableTrash.size) self.accessibilityLabel = tableTrash.trashbinFileName + ", " + (self.labelInfo?.text ?? "") diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.swift b/iOSClient/Trash/Cell/NCTrashGridCell.swift index 85ee0fd190..cee98d79db 100644 --- a/iOSClient/Trash/Cell/NCTrashGridCell.swift +++ b/iOSClient/Trash/Cell/NCTrashGridCell.swift @@ -16,64 +16,18 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { @IBOutlet weak var imageItem: UIImageView! @IBOutlet weak var imageSelect: UIImageView! - @IBOutlet weak var imageStatus: UIImageView! - @IBOutlet weak var imageFavorite: UIImageView! - @IBOutlet weak var imageLocal: UIImageView! @IBOutlet weak var labelTitle: UILabel! @IBOutlet weak var labelInfo: UILabel! + @IBOutlet weak var labelSubinfo: UILabel! @IBOutlet weak var buttonMore: UIButton! @IBOutlet weak var imageVisualEffect: UIVisualEffectView! - @IBOutlet weak var progressView: UIProgressView! - internal var objectId = "" + weak var delegate: NCTrashGridCellDelegate? + var objectId = "" var indexPath = IndexPath() var account = "" var user = "" - weak var delegate: NCTrashGridCellDelegate? - var namedButtonMore = "" - - var fileObjectId: String? { - get { return objectId } - set { objectId = newValue ?? "" } - } - var filePreviewImageView: UIImageView? { - get { return imageItem } - set { imageItem = newValue } - } - var fileUser: String? { - get { return user } - set { user = newValue ?? "" } - } - var fileTitleLabel: UILabel? { - get { return labelTitle } - set { labelTitle = newValue } - } - var fileInfoLabel: UILabel? { - get { return labelInfo } - set { labelInfo = 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 } - } - var fileLocalImage: UIImageView? { - get { return imageLocal } - set { imageLocal = newValue } - } - var fileFavoriteImage: UIImageView? { - get { return imageFavorite } - set { imageFavorite = newValue } - } - override func awakeFromNib() { super.awakeFromNib() initCell() @@ -97,14 +51,9 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { imageVisualEffect.clipsToBounds = true imageVisualEffect.alpha = 0.5 - progressView.tintColor = NCBrandColor.shared.brandElement - progressView.transform = CGAffineTransform(scaleX: 1.0, y: 0.5) - progressView.trackTintColor = .clear - labelTitle.text = "" labelInfo.text = "" - labelTitle.textColor = .label - labelInfo.textColor = .systemGray + labelSubinfo.text = "" } override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? { @@ -115,20 +64,16 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { delegate?.tapMoreGridItem(with: objectId, image: imageItem.image, sender: sender) } - fileprivate func setA11yActions() { - let moreName = namedButtonMore == NCGlobal.shared.buttonMoreStop ? "_cancel_" : "_more_" - self.accessibilityCustomActions = [ UIAccessibilityCustomAction( - name: NSLocalizedString(moreName, comment: ""), + name: NSLocalizedString("_more_", comment: ""), target: self, selector: #selector(touchUpInsideMore(_:))) ] } - func setButtonMore(named: String, image: UIImage) { - namedButtonMore = named + func setButtonMore(image: UIImage) { buttonMore.setImage(image, for: .normal) setA11yActions() } @@ -139,23 +84,19 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { func selected(_ status: Bool, isEditMode: Bool, account: String) { if isEditMode { - imageSelect.isHidden = false buttonMore.isHidden = true accessibilityCustomActions = nil } else { - imageSelect.isHidden = true buttonMore.isHidden = false - imageVisualEffect.isHidden = true setA11yActions() } if status { - let traitCollectionUserInterfaceStyleDark = traitCollection.userInterfaceStyle == .dark - imageVisualEffect.effect = UIBlurEffect(style: traitCollectionUserInterfaceStyleDark ? .dark : .extraLight) - imageVisualEffect.backgroundColor = traitCollectionUserInterfaceStyleDark ? .black : .lightGray imageSelect.image = NCImageCache.shared.getImageCheckedYes() + imageSelect.isHidden = false imageVisualEffect.isHidden = false } else { - imageSelect.image = NCImageCache.shared.getImageCheckedNo() + imageSelect.isHidden = true + imageVisualEffect.isHidden = true } } @@ -165,7 +106,8 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { dateFormatter.timeStyle = .none dateFormatter.locale = Locale.current - labelInfo.text = dateFormatter.string(from: date as Date) + " · " + NCUtilityFileSystem().transformedSize(size) + labelInfo.text = dateFormatter.string(from: date as Date) + labelSubinfo.text = NCUtilityFileSystem().transformedSize(size) } func setAccessibility(label: String, value: String) { @@ -173,3 +115,59 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol { accessibilityValue = value } } + +// MARK: - Grid Layout + +class NCTrashGridLayout: UICollectionViewFlowLayout { + + var heightLabelPlusButton: CGFloat = 60 + var marginLeftRight: CGFloat = 10 + var itemForLine: CGFloat = 3 + var itemWidthDefault: CGFloat = 140 + + // MARK: - View Life Cycle + + override init() { + super.init() + + sectionHeadersPinToVisibleBounds = false + + minimumInteritemSpacing = 1 + minimumLineSpacing = marginLeftRight + + self.scrollDirection = .vertical + self.sectionInset = UIEdgeInsets(top: 10, left: marginLeftRight, bottom: 0, right: marginLeftRight) + } + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override var itemSize: CGSize { + get { + if let collectionView = collectionView { + + if collectionView.frame.width < 400 { + itemForLine = 3 + } else { + itemForLine = collectionView.frame.width / itemWidthDefault + } + + let itemWidth: CGFloat = (collectionView.frame.width - marginLeftRight * 2 - marginLeftRight * (itemForLine - 1)) / itemForLine + let itemHeight: CGFloat = itemWidth + heightLabelPlusButton + + return CGSize(width: itemWidth, height: itemHeight) + } + + // Default fallback + return CGSize(width: itemWidthDefault, height: itemWidthDefault) + } + set { + super.itemSize = newValue + } + } + + override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint { + return proposedContentOffset + } +} diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.xib b/iOSClient/Trash/Cell/NCTrashGridCell.xib index 91bd5f805d..607f2744c6 100644 --- a/iOSClient/Trash/Cell/NCTrashGridCell.xib +++ b/iOSClient/Trash/Cell/NCTrashGridCell.xib @@ -1,9 +1,9 @@ - - + + - + @@ -11,130 +11,140 @@ - - + + - + - - + + - - - - - + + + + - - + + - - + + + + + - - + - - - + + + + + - - + + - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + - - - - - - - - - - + + + + + + + - + - + + - + + + + + + + diff --git a/iOSClient/Trash/Cell/NCTrashListCell.swift b/iOSClient/Trash/Cell/NCTrashListCell.swift index b9cfaf115a..522a352b76 100644 --- a/iOSClient/Trash/Cell/NCTrashListCell.swift +++ b/iOSClient/Trash/Cell/NCTrashListCell.swift @@ -46,8 +46,6 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { weak var delegate: NCTrashListCellDelegate? var objectId = "" var account = "" - var indexPath = IndexPath() - let utility = NCUtility() override func awakeFromNib() { super.awakeFromNib() @@ -74,11 +72,8 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { ] - imageRestore.image = utility.loadImage(named: "restore", colors: [NCBrandColor.shared.iconColor]) - - imageMore.image = UIImage(systemName: "trash") - imageMore.tintColor = NCBrandColor.shared.iconColor - + imageRestore.image = NCUtility().loadImage(named: "restore", colors: [NCBrandColor.shared.iconImageColor]) + imageMore.image = NCUtility().loadImage(named: "trashIcon", colors: [NCBrandColor.shared.iconImageColor]) //NCUtility().loadImage(named: "trashIcon", colors: [.red]) imageItem.layer.cornerRadius = 6 imageItem.layer.masksToBounds = true @@ -113,11 +108,8 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol { } if status { var blurEffectView: UIView? - var blurEffect: UIVisualEffect? - let traitCollectionUserInterfaceStyleDark = traitCollection.userInterfaceStyle == .dark - blurEffect = UIBlurEffect(style: traitCollectionUserInterfaceStyleDark ? .dark : .extraLight) - blurEffectView = UIVisualEffectView(effect: blurEffect) - blurEffectView?.backgroundColor = traitCollectionUserInterfaceStyleDark ? .black : .lightGray + blurEffectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemMaterial)) + blurEffectView?.backgroundColor = .lightGray blurEffectView?.frame = self.bounds blurEffectView?.autoresizingMask = [.flexibleWidth, .flexibleHeight] imageSelect.image = NCImageCache.shared.getImageCheckedYes() diff --git a/iOSClient/Trash/NCTrash+CollectionView.swift b/iOSClient/Trash/NCTrash+CollectionView.swift index c14ce8b394..239a9d9e6e 100644 --- a/iOSClient/Trash/NCTrash+CollectionView.swift +++ b/iOSClient/Trash/NCTrash+CollectionView.swift @@ -23,24 +23,19 @@ import UIKit import RealmSwift -import Foundation // MARK: UICollectionViewDelegate extension NCTrash: UICollectionViewDelegate { - func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let resultTableTrash = datasource?[indexPath.item] else { return } - guard !isEditMode else { - if let index = fileSelect.firstIndex(of: resultTableTrash.fileId) { - fileSelect.remove(at: index) + if let index = selectOcId.firstIndex(of: resultTableTrash.fileId) { + selectOcId.remove(at: index) } else { - fileSelect.append(resultTableTrash.fileId) + selectOcId.append(resultTableTrash.fileId) } collectionView.reloadItems(at: [indexPath]) - tabBarSelect.update(selectOcId: fileSelect) - setNavigationRightItems() + tabBarSelect.update(selectOcId: selectOcId) return } @@ -56,10 +51,7 @@ extension NCTrash: UICollectionViewDelegate { // MARK: UICollectionViewDataSource extension NCTrash: UICollectionViewDataSource { - func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - emptyDataSet?.numberOfItemsInSection(datasource?.count ?? 0, section: section) - setNavigationRightItems() return datasource?.count ?? 0 } @@ -73,11 +65,10 @@ extension NCTrash: UICollectionViewDataSource { cell = listCell } else { let gridCell = (collectionView.dequeueReusableCell(withReuseIdentifier: "gridCell", for: indexPath) as? NCTrashGridCell)! - gridCell.setButtonMore(named: NCGlobal.shared.buttonMoreMore, image: NCImageCache.shared.getImageButtonMore()) + gridCell.setButtonMore(image: NCImageCache.shared.getImageButtonMore()) gridCell.delegate = self cell = gridCell } - guard let resultTableTrash = datasource?[indexPath.item] else { return cell } cell.imageItem.contentMode = .scaleAspectFit @@ -85,16 +76,20 @@ extension NCTrash: UICollectionViewDataSource { if resultTableTrash.iconName.isEmpty { image = NCImageCache.shared.getImageFile() } else { - image = UIImage(named: resultTableTrash.iconName) + image = NCUtility().loadImage(named: resultTableTrash.iconName, useTypeIconFile: true, account: resultTableTrash.account) } - if let imageIcon = utility.getImage(ocId: resultTableTrash.fileId, etag: resultTableTrash.fileName, ext: NCGlobal.shared.previewExt512) { + if let imageIcon = utility.getImage(ocId: resultTableTrash.fileId, + etag: resultTableTrash.fileName, + ext: NCGlobal.shared.previewExt512, + userId: session.userId, + urlBase: session.urlBase) { image = imageIcon cell.imageItem.contentMode = .scaleAspectFill } else { if resultTableTrash.hasPreview { if NCNetworking.shared.downloadThumbnailTrashQueue.operations.filter({ ($0 as? NCOperationDownloadThumbnailTrash)?.fileId == resultTableTrash.fileId }).isEmpty { - NCNetworking.shared.downloadThumbnailTrashQueue.addOperation(NCOperationDownloadThumbnailTrash(fileId: resultTableTrash.fileId, fileName: resultTableTrash.fileName, account: session.account, collectionView: collectionView)) + NCNetworking.shared.downloadThumbnailTrashQueue.addOperation(NCOperationDownloadThumbnailTrash(fileId: resultTableTrash.fileId, fileName: resultTableTrash.fileName, session: session, collectionView: collectionView)) } } } @@ -102,35 +97,26 @@ extension NCTrash: UICollectionViewDataSource { cell.account = resultTableTrash.account cell.objectId = resultTableTrash.fileId cell.setupCellUI(tableTrash: resultTableTrash, image: image) - cell.selected(fileSelect.contains(resultTableTrash.fileId), isEditMode: isEditMode, account: resultTableTrash.account) + cell.selected(selectOcId.contains(resultTableTrash.fileId), isEditMode: isEditMode, account: resultTableTrash.account) + return cell } - - func setTextFooter(datasource: [tableTrash]) -> String { - var folders: Int = 0, foldersText = "" - var files: Int = 0, filesText = "" - var size: Int64 = 0 + + func setTitleLabel(directories: Int, files: Int, size: Int64) -> String { + var foldersText = "" + var filesText = "" var text = "" - for record: tableTrash in datasource { - if record.directory { - folders += 1 - } else { - files += 1 - size += record.size - } - } - - if folders > 1 { - foldersText = "\(folders) " + NSLocalizedString("_folders_", comment: "") - } else if folders == 1 { + if directories > 1 { + foldersText = "\(directories) " + NSLocalizedString("_folders_", comment: "") + } else if directories == 1 { foldersText = "1 " + NSLocalizedString("_folder_", comment: "") } if files > 1 { - filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " " + utilityFileSystem.transformedSize(size) + filesText = "\(files) " + NSLocalizedString("_files_", comment: "") + " • " + utilityFileSystem.transformedSize(size) } else if files == 1 { - filesText = "1 " + NSLocalizedString("_file_", comment: "") + " " + utilityFileSystem.transformedSize(size) + filesText = "1 " + NSLocalizedString("_file_", comment: "") + " • " + utilityFileSystem.transformedSize(size) } if foldersText.isEmpty { @@ -138,42 +124,25 @@ extension NCTrash: UICollectionViewDataSource { } else if filesText.isEmpty { text = foldersText } else { - text = foldersText + ", " + filesText + text = foldersText + " • " + filesText } - return text } func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { if kind == UICollectionView.elementKindSectionHeader { - - guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionHeaderMenu", for: indexPath) as? NCSectionHeaderMenu - else { return UICollectionReusableView() } - - 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 - header.setStatusButtonsView(enable: !(datasource?.isEmpty ?? false)) - header.setSortedTitle(layoutForView?.titleButtonHeader ?? "") - header.setButtonsView(height: NCGlobal.shared.heightButtonsView) - header.setRichWorkspaceHeight(0) - header.setSectionHeight(0) - header.setViewTransfer(isHidden: true) - + guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFirstHeaderEmptyData", for: indexPath) as? NCSectionFirstHeaderEmptyData + else { return NCSectionFirstHeaderEmptyData() } + header.emptyImage.image = utility.loadImage(named: "trashIcon", colors: [NCBrandColor.shared.getElement(account: session.account)]) + header.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "") + header.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "") return header - } else { guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: "sectionFooter", for: indexPath) as? NCSectionFooter - else { return UICollectionReusableView() } + else { return NCSectionFooter() } if let datasource { - footer.setTitleLabel(setTextFooter(datasource: datasource)) - footer.separatorIsHidden(true) + let info = self.getFooterInformation(datasource: datasource) + footer.setTitleLabel(directories: info.directories, files: info.files, size: info.size) } return footer } @@ -182,15 +151,13 @@ extension NCTrash: UICollectionViewDataSource { // MARK: UICollectionViewDelegateFlowLayout extension NCTrash: UICollectionViewDelegateFlowLayout { - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + var height: Double = 0 if let datasource, datasource.isEmpty { - let height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: -20) - return CGSize(width: collectionView.frame.width, height: height) + height = utility.getHeightHeaderEmptyData(view: view, portraitOffset: 0, landscapeOffset: 0) } - return CGSize(width: collectionView.frame.width, height: NCGlobal.shared.heightButtonsView) + return CGSize(width: collectionView.frame.width, height: height) } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { return CGSize(width: collectionView.frame.width, height: 85) } diff --git a/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift b/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift index 14b0e071ca..677047688c 100644 --- a/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift +++ b/iOSClient/Trash/NCTrash+SelectTabBarDelegate.swift @@ -22,7 +22,7 @@ import Foundation import UIKit -extension NCTrash: NCTrashSelectTabBarDelegate, NCSelectableNavigationView { +extension NCTrash: NCTrashSelectTabBarDelegate { func onListSelected() { if layoutForView?.layout == NCGlobal.shared.layoutGrid { layoutForView?.layout = NCGlobal.shared.layoutList @@ -44,81 +44,51 @@ extension NCTrash: NCTrashSelectTabBarDelegate, NCSelectableNavigationView { } func selectAll() { - if !fileSelect.isEmpty, datasource?.count == fileSelect.count { - fileSelect = [] + guard let datasource else { return } + if !selectOcId.isEmpty, datasource.count == selectOcId.count { + selectOcId = [] } else { - fileSelect = (datasource?.compactMap({ $0.fileId }))! + selectOcId = datasource.compactMap({ $0.fileId }) } - tabBarSelect.update(selectOcId: fileSelect) + tabBarSelect.update(selectOcId: selectOcId) collectionView.reloadData() } func recover() { - fileSelect.forEach(restoreItem) + let ids = selectOcId.map { $0 } setEditMode(false) + + Task { + for id in ids { + await restoreItem(with: id) + } + } } func delete() { - let ocIds = fileSelect.map { $0 } + let ids = selectOcId.map { $0 } setEditMode(false) Task { - if ocIds.count > 0, ocIds.count == datasource?.count { + if ids.count > 0, ids.count == datasource?.count { await emptyTrash() } else { - await self.deleteItems(with: ocIds) + await self.deleteItems(with: ids) } } } func setEditMode(_ editMode: Bool) { - isEditMode = editMode - fileSelect.removeAll() + Task { + isEditMode = editMode + selectOcId.removeAll() - navigationController?.interactivePopGestureRecognizer?.isEnabled = !editMode - navigationItem.hidesBackButton = editMode - DispatchQueue.main.async { - self.collectionView.reloadData() - self.setNavigationRightItems() - } - } - - func setNavigationRightItems(enableMenu: Bool = false) { - if isEditMode { - let more = UIBarButtonItem(image: UIImage(systemName: "ellipsis"), style: .plain) { self.presentMenu(with: self.selectActions)} - navigationItem.rightBarButtonItems = [more] - } else { - let select = UIBarButtonItem(title: NSLocalizedString("_select_", comment: ""), style: UIBarButtonItem.Style.plain) { self.toggleSelect() } - let notification = UIBarButtonItem(image: UIImage(systemName: "bell"), style: .plain, action: tapNotification) - if layoutKey == NCGlobal.shared.layoutViewFiles { - navigationItem.rightBarButtonItems = [select, notification] - } else { - navigationItem.rightBarButtonItems = [select] - } + navigationItem.hidesBackButton = editMode + navigationController?.interactivePopGestureRecognizer?.isEnabled = !editMode + + await (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() + + collectionView.reloadData() } - guard layoutKey == NCGlobal.shared.layoutViewFiles else { return } - navigationItem.title = titleCurrentFolder - } - - func createMenuActions() -> [NCMenuAction] { -// guard let layoutForView = NCManageDatabase.shared.getLayoutForView(account: session.account, key: layoutKey, serverUrl: "") else { return [] } -// -// let select = UIAction(title: NSLocalizedString("_select_", comment: ""), image: .init(systemName: "checkmark.circle"), attributes: datasource.isEmpty ? .disabled : []) { _ in -// self.setEditMode(true) -// } -// -// let list = UIAction(title: NSLocalizedString("_list_", comment: ""), image: .init(systemName: "list.bullet"), state: layoutForView.layout == NCGlobal.shared.layoutList ? .on : .off) { _ in -// self.onListSelected() -//// self.setNavigationRightItems() -// } -// -// let grid = UIAction(title: NSLocalizedString("_icons_", comment: ""), image: .init(systemName: "square.grid.2x2"), state: layoutForView.layout == NCGlobal.shared.layoutGrid ? .on : .off) { _ in -// self.onGridSelected() -//// self.setNavigationRightItems() -// } -// -// let viewStyleSubmenu = UIMenu(title: "", options: .displayInline, children: [list, grid]) -// - return []//[select, viewStyleSubmenu] } } diff --git a/iOSClient/Trash/NCTrash.swift b/iOSClient/Trash/NCTrash.swift index 8a0d7c0ab2..628feb051d 100644 --- a/iOSClient/Trash/NCTrash.swift +++ b/iOSClient/Trash/NCTrash.swift @@ -25,59 +25,49 @@ import UIKit import NextcloudKit -import Realm import RealmSwift -class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate, NCSectionHeaderMenuDelegate, NCEmptyDataSetDelegate { +class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegate { @IBOutlet weak var collectionView: UICollectionView! var filePath = "" var titleCurrentFolder = NSLocalizedString("_trash_view_", comment: "") var blinkFileId: String? - var dataSourceTask: URLSessionTask? let utilityFileSystem = NCUtilityFileSystem() let database = NCManageDatabase.shared let utility = NCUtility() var isEditMode = false - var fileSelect: [String] = [] + var selectOcId: [String] = [] var tabBarSelect: NCTrashSelectTabBar! var datasource: [tableTrash]? var layoutForView: NCDBLayoutForView? var listLayout: NCListLayout! var gridLayout: NCGridLayout! var layoutKey = NCGlobal.shared.layoutViewTrash - var layoutType = NCGlobal.shared.layoutList let refreshControl = UIRefreshControl() var filename: String? + + @MainActor var session: NCSession.Session { NCSession.shared.getSession(controller: tabBarController) } - + var controller: NCMainTabBarController? { self.tabBarController as? NCMainTabBarController } - var serverUrl = "" - var selectableDataSource: [RealmSwiftObject] { datasource ?? [] } - private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! - var emptyDataSet: NCEmptyDataSet? - // MARK: - View Life Cycle override func viewDidLoad() { super.viewDidLoad() - - tabBarSelect = NCTrashSelectTabBar(tabBarController: tabBarController, delegate: self) - serverUrl = utilityFileSystem.getHomeServer(session: session) + navigationController?.setNavigationBarAppearance() view.backgroundColor = .systemBackground - self.navigationController?.navigationBar.prefersLargeTitles = true collectionView.register(UINib(nibName: "NCTrashListCell", bundle: nil), forCellWithReuseIdentifier: "listCell") collectionView.register(UINib(nibName: "NCTrashGridCell", bundle: nil), forCellWithReuseIdentifier: "gridCell") -// collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") - collectionView.register(UINib(nibName: "NCSectionHeaderMenu", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionHeaderMenu") + collectionView.register(UINib(nibName: "NCSectionFirstHeaderEmptyData", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "sectionFirstHeaderEmptyData") collectionView.register(UINib(nibName: "NCSectionFooter", bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: "sectionFooter") collectionView.alwaysBounceVertical = true @@ -88,26 +78,25 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat // Add Refresh Control collectionView.refreshControl = refreshControl - refreshControl.tintColor = .gray - refreshControl.addTarget(self, action: #selector(loadListingTrash), for: .valueChanged) - - // Empty - emptyDataSet = NCEmptyDataSet(view: collectionView, offset: NCGlobal.shared.heightButtonsView, delegate: self) - - NotificationCenter.default.addObserver(self, selector: #selector(reloadDataSource), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataSource), object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(changeLayout(_:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeLayout), object: nil) + refreshControl.tintColor = NCBrandColor.shared.textColor2 + refreshControl.action(for: .valueChanged) { _ in + Task { + await self.loadListingTrash() + } + } } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - appDelegate.activeViewController = self + if tabBarSelect == nil { + tabBarSelect = NCTrashSelectTabBar(controller: tabBarController, viewController: self, delegate: self) + } navigationController?.setNavigationBarAppearance() navigationItem.title = titleCurrentFolder layoutForView = self.database.getLayoutForView(account: session.account, key: NCGlobal.shared.layoutViewTrash, serverUrl: "") - gridLayout.column = CGFloat(layoutForView?.columnGrid ?? 3) if layoutForView?.layout == NCGlobal.shared.layoutList { collectionView.collectionViewLayout = listLayout @@ -116,74 +105,32 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat } isEditMode = false - setNavigationRightItems() - - reloadDataSource() - loadListingTrash(nil) - - AnalyticsHelper.shared.trackEvent(eventName: .SCREEN_EVENT__DELETED_FILES) + Task { + await (self.navigationController as? NCMainNavigationController)?.setNavigationRightItems() + await self.reloadDataSource() + await loadListingTrash() + } } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) - // Cancel Queue & Retrieves Properties - NCNetworking.shared.downloadThumbnailTrashQueue.cancelAll() - dataSourceTask?.cancel() - isEditMode = false - } - - override func viewWillLayoutSubviews() { - super.viewWillLayoutSubviews() - - if let frame = tabBarController?.tabBar.frame { - tabBarSelect.hostingController?.view.frame = frame - } - } - - // MARK: - Layout - - @objc func changeLayout(_ notification: NSNotification) { - guard let userInfo = notification.userInfo as NSDictionary?, - let account = userInfo["account"] as? String, - let serverUrl = userInfo["serverUrl"] as? String, - let layoutForView = userInfo["layoutForView"] as? NCDBLayoutForView, - account == session.account, - serverUrl == self.serverUrl - else { return } - - self.layoutForView = self.database.setLayoutForView(layoutForView: layoutForView) - layoutForView.layout = layoutForView.layout - self.layoutType = layoutForView.layout -// self.reloadDataSource() - collectionView.reloadData() - - switch layoutForView.layout { - case NCGlobal.shared.layoutList: - self.collectionView.setCollectionViewLayout(self.listLayout, animated: true) - case NCGlobal.shared.layoutGrid: - self.collectionView.setCollectionViewLayout(self.gridLayout, animated: true) - default: - break + Task { + await NCNetworking.shared.networkingTasks.cancel(identifier: "NCTrash") } - self.collectionView.collectionViewLayout.invalidateLayout() - } - - // MARK: - Empty - - func emptyDataSetView(_ view: NCEmptyView) { - view.emptyImage.image = UIImage(named: "trash")?.image(color: .gray, size: UIScreen.main.bounds.width) - view.emptyTitle.text = NSLocalizedString("_trash_no_trash_", comment: "") - view.emptyDescription.text = NSLocalizedString("_trash_no_trash_description_", comment: "") + // Cancel Queue & Retrieves Properties + NCNetworking.shared.downloadThumbnailTrashQueue.cancelAll() } // MARK: TAP EVENT - func tapRestoreListItem(with ocId: String, image: UIImage?, sender: Any) { + func tapRestoreListItem(with id: String, image: UIImage?, sender: Any) { if !isEditMode { - restoreItem(with: ocId) + Task { + await restoreItem(with: id) + } } else if let button = sender as? UIView { let buttonPosition = button.convert(CGPoint.zero, to: collectionView) let indexPath = collectionView.indexPathForItem(at: buttonPosition) @@ -211,53 +158,34 @@ class NCTrash: UIViewController, NCTrashListCellDelegate, NCTrashGridCellDelegat } } - func tapButtonSwitch(_ sender: Any) { - if layoutForView?.layout == NCGlobal.shared.layoutGrid { - onListSelected() - } else { - onGridSelected() - } - } - - func tapButtonOrder(_ sender: Any) { - - let sortMenu = NCSortMenu() -// sortMenu.toggleMenu(viewController: self, account: appDelegate.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) - sortMenu.toggleMenu(viewController: self, account: session.account, key: layoutKey, sortButton: sender as? UIButton, serverUrl: serverUrl) - } - func longPressGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } func longPressMoreGridItem(with objectId: String, gestureRecognizer: UILongPressGestureRecognizer) { } // MARK: - DataSource - @objc func reloadDataSource(withQueryDB: Bool = true) { - Task { - // Await async DB call off the main thread - let results = await self.database.getTableTrashAsync(filePath: getFilePath(), account: session.account) - - // Switch back to main thread for UI updates - await MainActor.run { - self.datasource = results - self.collectionView.reloadData() - setNavigationRightItems() -// (self.navigationController as? NCMainNavigationController)?.updateRightMenu() - - guard let blinkFileId = self.blinkFileId else { return } - - for itemIx in 0.. (directories: Int, files: Int, size: Int64) { + let validMetadatas = datasource.filter { !$0.isInvalidated } + let directories = validMetadatas.filter({ $0.directory == true}) + let files = validMetadatas.filter({ $0.directory == false}) + + var size: Int64 = 0 + + directories.forEach { metadata in + size += metadata.size + } + + files.forEach { metadata in + size += metadata.size + } + + return (directories.count, files.count, size) + } } diff --git a/iOSClient/Trash/NCTrashSelectTabBar.swift b/iOSClient/Trash/NCTrashSelectTabBar.swift index 1591751171..bc90132fa8 100644 --- a/iOSClient/Trash/NCTrashSelectTabBar.swift +++ b/iOSClient/Trash/NCTrashSelectTabBar.swift @@ -30,31 +30,46 @@ protocol NCTrashSelectTabBarDelegate: AnyObject { } class NCTrashSelectTabBar: ObservableObject { - var tabBarController: UITabBarController? + var controller: UITabBarController? var hostingController: UIViewController? open weak var delegate: NCTrashSelectTabBarDelegate? @Published var isSelectedEmpty = true - init(tabBarController: UITabBarController? = nil, delegate: NCTrashSelectTabBarDelegate? = nil) { + init(controller: UITabBarController? = nil, viewController: UIViewController, delegate: NCTrashSelectTabBarDelegate? = nil) { + guard let controller else { + return + } let rootView = NCTrashSelectTabBarView(tabBarSelect: self) + let bottomAreaInsets: CGFloat = controller.tabBar.safeAreaInsets.bottom == 0 ? 34 : 0 + let height = controller.tabBar.frame.height + bottomAreaInsets hostingController = UIHostingController(rootView: rootView) + guard let hostingController else { + return + } - self.tabBarController = tabBarController + self.controller = controller self.delegate = delegate - guard let tabBarController, let hostingController else { return } - - tabBarController.view.addSubview(hostingController.view) - - hostingController.view.frame = tabBarController.tabBar.frame - hostingController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight] + hostingController.view.translatesAutoresizingMaskIntoConstraints = false hostingController.view.backgroundColor = .clear hostingController.view.isHidden = true + + viewController.view.addSubview(hostingController.view) + + NSLayoutConstraint.activate([ + hostingController.view.leadingAnchor.constraint(equalTo: viewController.view.leadingAnchor), + hostingController.view.trailingAnchor.constraint(equalTo: viewController.view.trailingAnchor), + hostingController.view.bottomAnchor.constraint(equalTo: viewController.view.bottomAnchor), + hostingController.view.heightAnchor.constraint(equalToConstant: height) + ]) } func show() { - guard let tabBarController, let hostingController else { return } + guard let controller, + let hostingController else { + return + } if #available(iOS 18.0, *) { controller.setTabBarHidden(true, animated: true) @@ -74,7 +89,10 @@ class NCTrashSelectTabBar: ObservableObject { } func hide() { - guard let tabBarController, let hostingController else { return } + guard let controller, + let hostingController else { + return + } hostingController.view.isHidden = true @@ -106,11 +124,11 @@ struct NCTrashSelectTabBarView: View { Button { tabBarSelect.delegate?.recover() } label: { - Image(systemName: "arrow.circlepath") + Image(systemName: "arrow.counterclockwise") .font(Font.system(.body).weight(.light)) .imageScale(sizeClass == .compact ? .medium : .large) } -// .tint(Color(NCBrandColor.shared.iconImageColor)) + .tint(Color(NCBrandColor.shared.iconImageColor)) .frame(maxWidth: .infinity) .disabled(tabBarSelect.isSelectedEmpty) @@ -121,7 +139,7 @@ struct NCTrashSelectTabBarView: View { .font(Font.system(.body).weight(.light)) .imageScale(sizeClass == .compact ? .medium : .large) } -// .tint(.red) + .tint(.red) .frame(maxWidth: .infinity) .disabled(tabBarSelect.isSelectedEmpty) @@ -132,7 +150,7 @@ struct NCTrashSelectTabBarView: View { .font(Font.system(.body).weight(.light)) .imageScale(sizeClass == .compact ? .medium : .large) } -// .tint(Color(NCBrandColor.shared.iconImageColor)) + .tint(Color(NCBrandColor.shared.iconImageColor)) .frame(maxWidth: .infinity) } } @@ -143,5 +161,5 @@ struct NCTrashSelectTabBarView: View { } #Preview { - NCTrashSelectTabBarView(tabBarSelect: NCTrashSelectTabBar()) + NCTrashSelectTabBarView(tabBarSelect: NCTrashSelectTabBar(viewController: UIViewController())) }