From 89240e9f6599ca82e24440a2888312fb7cb51c45 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 3 Oct 2024 13:14:03 +0200 Subject: [PATCH 01/14] feat: V1 of the new view --- .../ProjectDescriptionHelpers/Constants.swift | 2 +- kDrive/AppRouter.swift | 79 ++++---- .../Files/RootMenuViewController.swift | 77 ++++++++ .../UI/Controller/MainTabViewController.swift | 183 +++++++++++++++++- kDriveCore/Utils/AppNavigable.swift | 2 +- 5 files changed, 299 insertions(+), 44 deletions(-) diff --git a/Tuist/ProjectDescriptionHelpers/Constants.swift b/Tuist/ProjectDescriptionHelpers/Constants.swift index 35ef35bb7..c202772c6 100644 --- a/Tuist/ProjectDescriptionHelpers/Constants.swift +++ b/Tuist/ProjectDescriptionHelpers/Constants.swift @@ -28,7 +28,7 @@ public enum Constants { .currentProjectVersion("1") .marketingVersion("5.0.1") - public static let deploymentTarget = DeploymentTargets.iOS("13.4") + public static let deploymentTarget = DeploymentTargets.iOS("14.0") public static let destinations = Set([.iPhone, .iPad]) public static let fileProviderSettings = baseSettings diff --git a/kDrive/AppRouter.swift b/kDrive/AppRouter.swift index cb7517e70..b346748fe 100644 --- a/kDrive/AppRouter.swift +++ b/kDrive/AppRouter.swift @@ -183,42 +183,42 @@ public struct AppRouter: AppNavigable { return } - let selectedIndex = tabBarViewController.selectedIndex - let viewControllers = tabBarViewController.viewControllers - guard let rootNavigationController = viewControllers?[safe: selectedIndex] as? UINavigationController else { - Log.sceneDelegate("unable to access navigationController", level: .error) - return - } - - switch lastViewController { - case .FileDetailViewController: - await restoreFileDetailViewController( - driveFileManager: driveFileManager, - navigationController: rootNavigationController, - sceneUserInfo: sceneUserInfo - ) - - case .FileListViewController: - await restoreFileListViewController( - driveFileManager: driveFileManager, - navigationController: rootNavigationController, - sceneUserInfo: sceneUserInfo - ) - - case .PreviewViewController: - await restorePreviewViewController( - driveFileManager: driveFileManager, - navigationController: rootNavigationController, - sceneUserInfo: sceneUserInfo - ) - - case .StoreViewController: - await restoreStoreViewController( - driveFileManager: driveFileManager, - navigationController: rootNavigationController, - sceneUserInfo: sceneUserInfo - ) - } +// let selectedIndex = tabBarViewController.selectedIndex +// let viewControllers = tabBarViewController.viewControllers +// guard let rootNavigationController = viewControllers?[safe: selectedIndex] as? UINavigationController else { +// Log.sceneDelegate("unable to access navigationController", level: .error) +// return +// } +// +// switch lastViewController { +// case .FileDetailViewController: +// await restoreFileDetailViewController( +// driveFileManager: driveFileManager, +// navigationController: rootNavigationController, +// sceneUserInfo: sceneUserInfo +// ) +// +// case .FileListViewController: +// await restoreFileListViewController( +// driveFileManager: driveFileManager, +// navigationController: rootNavigationController, +// sceneUserInfo: sceneUserInfo +// ) +// +// case .PreviewViewController: +// await restorePreviewViewController( +// driveFileManager: driveFileManager, +// navigationController: rootNavigationController, +// sceneUserInfo: sceneUserInfo +// ) +// +// case .StoreViewController: +// await restoreStoreViewController( +// driveFileManager: driveFileManager, +// navigationController: rootNavigationController, +// sceneUserInfo: sceneUserInfo +// ) +// } } } @@ -339,19 +339,18 @@ public struct AppRouter: AppNavigable { @discardableResult @MainActor public func showMainViewController(driveFileManager: DriveFileManager, - selectedIndex: Int?) -> UITabBarController? { + selectedIndex: Int?) -> UISplitViewController? { guard let window else { SentryDebug.captureNoWindow() return nil } - let currentDriveObjectId = (window.rootViewController as? MainTabViewController)?.driveFileManager.drive.objectId + let currentDriveObjectId = (window.rootViewController as? RootViewController)?.driveFileManager.drive.objectId guard currentDriveObjectId != driveFileManager.drive.objectId else { return nil } - let tabBarViewController = MainTabViewController(driveFileManager: driveFileManager, - selectedIndex: selectedIndex) + let tabBarViewController = RootViewController(driveFileManager: driveFileManager) window.rootViewController = tabBarViewController window.makeKeyAndVisible() diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 31f0ae1cf..bb049cd5f 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -24,6 +24,83 @@ import kDriveResources import RealmSwift import UIKit +class SidebarViewController: UITableViewController { + private typealias MenuDataSource = UICollectionViewDiffableDataSource + + private enum RootMenuSection { + case main + } + + private struct RootMenuItem: Equatable, Hashable { + var id: Int { + return destinationFile.id + } + + let name: String + let image: UIImage + let destinationFile: File + var isFirst = false + var isLast = false + + func hash(into hasher: inout Hasher) { + hasher.combine(id) + hasher.combine(isFirst) + hasher.combine(isLast) + } + } + + private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, + image: KDriveResourcesAsset.favorite.image, + destinationFile: DriveFileManager.favoriteRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, + image: KDriveResourcesAsset.clock.image, + destinationFile: DriveFileManager.lastModificationsRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, + image: KDriveResourcesAsset.folderSelect2.image, + destinationFile: DriveFileManager.sharedWithMeRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, + image: KDriveResourcesAsset.folderSelect.image, + destinationFile: DriveFileManager.mySharedRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.offlineFileTitle, + image: KDriveResourcesAsset.availableOffline.image, + destinationFile: DriveFileManager.offlineRoot), + RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, + image: KDriveResourcesAsset.delete.image, + destinationFile: DriveFileManager.trashRootFile)] + + weak var delegate: SidebarViewControllerDelegate? + + override func viewDidLoad() { + super.viewDidLoad() + + tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") + } + + // MARK: - UITableViewDataSource + + override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return SidebarViewController.baseItems.count + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) + cell.textLabel?.text = SidebarViewController.baseItems[indexPath.row].name + return cell + } + + // MARK: - UITableViewDelegate + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + tableView.deselectRow(at: indexPath, animated: true) + let selectedItem = SidebarViewController.baseItems[indexPath.row] + delegate?.didSelectItem(named: selectedItem.id) + } +} + +protocol SidebarViewControllerDelegate: AnyObject { + func didSelectItem(named: Int) +} + class RootMenuViewController: CustomLargeTitleCollectionViewController, SelectSwitchDriveDelegate { private typealias MenuDataSource = UICollectionViewDiffableDataSource private typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 9ea50b284..cbceee652 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -26,12 +26,191 @@ import UIKit /// Enum to explicit tab names public enum MainTabBarIndex: Int { - case home = 0 - case files = 1 + case files = 0 + case home = 1 case gallery = 3 case profile = 4 } +// class RootViewController: UISplitViewController { +// @LazyInjectService var router: AppNavigable +// let driveFileManager: DriveFileManager +// +// init(driveFileManager: DriveFileManager) { +// self.driveFileManager = driveFileManager +// var rootViewControllers = [UIViewController]() +// rootViewControllers.append(Self.initRootMenuViewController(driveFileManager: driveFileManager)) +//// rootViewControllers.append(Self.initHomeViewController(driveFileManager: driveFileManager)) +//// rootViewControllers.append(Self.initFakeViewController()) +//// rootViewControllers.append(Self.initPhotoListViewController(with: PhotoListViewModel(driveFileManager: +/// driveFileManager))) +//// rootViewControllers.append(Self.initMenuViewController(driveFileManager: driveFileManager)) +// super.init(style: .doubleColumn) +// preferredDisplayMode = .oneBesideSecondary +// viewControllers = rootViewControllers +// } +// +// @available(*, unavailable) +// required init?(coder: NSCoder) { +// fatalError("init(coder:) has not been implemented") +// } +// +// private static func generateProfileTabImages(image: UIImage) -> (UIImage, UIImage) { +// let iconSize = 28.0 +// +// let selectedImage = image +// .resize(size: CGSize(width: iconSize + 2, height: iconSize + 2)) +// .maskImageWithRoundedRect( +// cornerRadius: CGFloat((iconSize + 2) / 2), +// borderWidth: 2, +// borderColor: KDriveResourcesAsset.infomaniakColor.color +// ) +// .withRenderingMode(.alwaysOriginal) +// +// let image = image +// .resize(size: CGSize(width: iconSize, height: iconSize)) +// .maskImageWithRoundedRect(cornerRadius: CGFloat(iconSize / 2), borderWidth: 0, borderColor: nil) +// .withRenderingMode(.alwaysOriginal) +// return (image, selectedImage) +// } +// +// private static func initHomeViewController(driveFileManager: DriveFileManager) -> UIViewController { +// let homeViewController = HomeViewController(driveFileManager: driveFileManager) +// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: homeViewController) +// navigationViewController.navigationBar.prefersLargeTitles = true +// navigationViewController.restorationIdentifier = String(describing: HomeViewController.self) +// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.homeTitle +// navigationViewController.tabBarItem.image = KDriveResourcesAsset.house.image +// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.houseFill.image +// return navigationViewController +// } +// +// private static func initRootMenuViewController(driveFileManager: DriveFileManager) -> UIViewController { +// let homeViewController = SidebarViewController() +// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: homeViewController) +// navigationViewController.navigationBar.prefersLargeTitles = true +// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.homeTitle +// navigationViewController.tabBarItem.image = KDriveResourcesAsset.folder.image +// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.folderFilledTab.image +// return navigationViewController +// } +// +// private static func initMenuViewController(driveFileManager: DriveFileManager) -> UIViewController { +// let menuViewController = MenuViewController(driveFileManager: driveFileManager) +// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: menuViewController) +// let (placeholder, placeholderSelected) = generateProfileTabImages(image: KDriveResourcesAsset.placeholderAvatar.image) +// navigationViewController.restorationIdentifier = String(describing: MenuViewController.self) +// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.menuTitle +// navigationViewController.tabBarItem.image = placeholder +// navigationViewController.tabBarItem.selectedImage = placeholderSelected +// return navigationViewController +// } +// +// private static func initFakeViewController() -> UIViewController { +// let fakeViewController = UIViewController() +// fakeViewController.tabBarItem.isEnabled = false +// return fakeViewController +// } +// +// private static func initPhotoListViewController(with viewModel: FileListViewModel) -> UIViewController { +// let photoListViewController = PhotoListViewController(viewModel: viewModel) +// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: photoListViewController) +// navigationViewController.restorationIdentifier = String(describing: PhotoListViewController.self) +// navigationViewController.navigationBar.prefersLargeTitles = true +// navigationViewController.tabBarItem.accessibilityLabel = viewModel.title +// navigationViewController.tabBarItem.image = KDriveResourcesAsset.mediaInline.image +// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.mediaBold.image +// return navigationViewController +// } +// } + +class RootViewController: UISplitViewController, SidebarViewControllerDelegate { + let sidebarViewController = SidebarViewController() + let detailViewController = DetailViewController() + let driveFileManager: DriveFileManager + + init(driveFileManager: DriveFileManager) { + self.driveFileManager = driveFileManager + super.init(style: .doubleColumn) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + sidebarViewController.delegate = self + + let sidebarNav = UINavigationController(rootViewController: sidebarViewController) + let detailNav = UINavigationController(rootViewController: detailViewController) + + viewControllers = [sidebarNav, detailNav] + preferredDisplayMode = .oneBesideSecondary + } + + // MARK: - SidebarViewControllerDelegate + + func didSelectItem(named folderName: Int) { + + let destinationViewModel: FileListViewModel + switch folderName { + case DriveFileManager.favoriteRootFile.id: + destinationViewModel = FavoritesViewModel(driveFileManager: driveFileManager) + case DriveFileManager.lastModificationsRootFile.id: + destinationViewModel = LastModificationsViewModel(driveFileManager: driveFileManager) + case DriveFileManager.sharedWithMeRootFile.id: + let sharedWithMeDriveFileManager = driveFileManager.instanceWith(context: .sharedWithMe) + destinationViewModel = SharedWithMeViewModel(driveFileManager: sharedWithMeDriveFileManager) + case DriveFileManager.offlineRoot.id: + destinationViewModel = OfflineFilesViewModel(driveFileManager: driveFileManager) + case DriveFileManager.trashRootFile.id: + destinationViewModel = TrashListViewModel(driveFileManager: driveFileManager) + case DriveFileManager.mySharedRootFile.id: + destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) + default: + destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) // à changer + } + + let destinationViewController = FileListViewController(viewModel: destinationViewModel) + + if let detailNav = viewControllers.last as? UINavigationController { + detailNav.setViewControllers([destinationViewController], animated: true) + } + } + +// func didSelectItem(named: String) { +// detailViewController.updateDetail(with: named) +// } +} + +class DetailViewController: UIViewController { + private var label = UILabel() + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + label.text = "Select a folder" + label.textAlignment = .center + + label.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(label) + + // Contraintes pour centrer le texte + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: view.centerXAnchor), + label.centerYAnchor.constraint(equalTo: view.centerYAnchor) + ]) + } + + func updateDetail(with item: String) { + label.text = "You selected: \(item)" + } +} + class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver { /// Tracking the last selection date to detect double tap private var lastInteraction: Date? diff --git a/kDriveCore/Utils/AppNavigable.swift b/kDriveCore/Utils/AppNavigable.swift index dc54ce51a..881d4c654 100644 --- a/kDriveCore/Utils/AppNavigable.swift +++ b/kDriveCore/Utils/AppNavigable.swift @@ -26,7 +26,7 @@ public protocol RouterAppNavigable { /// - Parameters: /// - driveFileManager: driveFileManager to use /// - selectedIndex: Nil will try to use state restoration if available - @MainActor func showMainViewController(driveFileManager: DriveFileManager, selectedIndex: Int?) -> UITabBarController? + @MainActor func showMainViewController(driveFileManager: DriveFileManager, selectedIndex: Int?) -> UISplitViewController? @MainActor func showPreloading(currentAccount: Account) From 73eccd58dc237916d9f66517bdd6afa2ba7d5ae0 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 4 Oct 2024 14:08:44 +0200 Subject: [PATCH 02/14] feat: Work in progress on navBar --- .../Files/RootMenuViewController.swift | 215 ++++++++++++++++-- .../UI/Controller/MainTabViewController.swift | 48 ++-- 2 files changed, 212 insertions(+), 51 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index bb049cd5f..7c5cb13ea 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -24,8 +24,9 @@ import kDriveResources import RealmSwift import UIKit -class SidebarViewController: UITableViewController { +class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwitchDriveDelegate { private typealias MenuDataSource = UICollectionViewDiffableDataSource + private typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot private enum RootMenuSection { case main @@ -49,7 +50,10 @@ class SidebarViewController: UITableViewController { } } - private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, + private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.homeTitle, + image: KDriveResourcesAsset.house.image, + destinationFile: DriveFileManager.favoriteRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, image: KDriveResourcesAsset.favorite.image, destinationFile: DriveFileManager.favoriteRootFile), RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, @@ -66,39 +70,216 @@ class SidebarViewController: UITableViewController { destinationFile: DriveFileManager.offlineRoot), RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, image: KDriveResourcesAsset.delete.image, + destinationFile: DriveFileManager.trashRootFile), + RootMenuItem(name: "Images", + image: KDriveResourcesAsset.mediaInline.image, destinationFile: DriveFileManager.trashRootFile)] weak var delegate: SidebarViewControllerDelegate? + @LazyInjectService private var accountManager: AccountManageable + let driveFileManager: DriveFileManager + private var rootChildrenObservationToken: NotificationToken? + private var rootViewChildren: [File]? + private var dataSource: MenuDataSource? + private let refreshControl = UIRefreshControl() + + private var itemsSnapshot: DataSourceSnapshot { + let userRootFolders = rootViewChildren?.compactMap { + RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) + } ?? [] + + var menuItems = userRootFolders + SidebarViewController.baseItems + if !menuItems.isEmpty { + menuItems[0].isFirst = true + menuItems[menuItems.count - 1].isLast = true + } + + var snapshot = DataSourceSnapshot() + snapshot.appendSections([RootMenuSection.main]) + snapshot.appendItems(menuItems) + return snapshot + } + + init(driveFileManager: DriveFileManager) { + self.driveFileManager = driveFileManager + super.init(collectionViewLayout: SidebarViewController.createListLayout()) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } override func viewDidLoad() { super.viewDidLoad() + navigationItem.title = driveFileManager.drive.name + navigationItem.rightBarButtonItem = FileListBarButton(type: .search, target: self, action: #selector(presentSearch)) - tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cell") + collectionView.backgroundColor = KDriveResourcesAsset.backgroundColor.color + collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: UIConstants.listPaddingBottom, right: 0) + collectionView.refreshControl = refreshControl + + collectionView.register(RootMenuCell.self, forCellWithReuseIdentifier: RootMenuCell.identifier) + collectionView.register(supplementaryView: HomeLargeTitleHeaderView.self, forSupplementaryViewOfKind: .header) + collectionView.register(supplementaryView: RootMenuHeaderView.self, forSupplementaryViewOfKind: RootMenuHeaderView.kind) + + refreshControl.addTarget(self, action: #selector(forceRefresh), for: .valueChanged) + + configureDataSource() + + let rootFileUid = File.uid(driveId: driveFileManager.drive.id, fileId: DriveFileManager.constants.rootID) + guard let root = driveFileManager.database.fetchObject(ofType: File.self, forPrimaryKey: rootFileUid) else { + return + } + + let rootChildren = root.children.filter(NSPredicate( + format: "rawVisibility IN %@", + [FileVisibility.isPrivateSpace.rawValue, FileVisibility.isTeamSpace.rawValue] + )) + rootChildrenObservationToken = rootChildren.observe { [weak self] changes in + guard let self else { return } + switch changes { + case .initial(let children): + rootViewChildren = Array(AnyRealmCollection(children).filesSorted(by: .nameAZ)) + dataSource?.apply(itemsSnapshot, animatingDifferences: false) + case .update(let children, _, _, _): + rootViewChildren = Array(AnyRealmCollection(children).filesSorted(by: .nameAZ)) + dataSource?.apply(itemsSnapshot, animatingDifferences: true) + case .error: + break + } + } } - // MARK: - UITableViewDataSource + func configureDataSource() { + dataSource = MenuDataSource(collectionView: collectionView) { collectionView, indexPath, menuItem -> RootMenuCell? in + guard let rootMenuCell = collectionView.dequeueReusableCell( + withReuseIdentifier: RootMenuCell.identifier, + for: indexPath + ) as? RootMenuCell else { + fatalError("Failed to dequeue cell") + } - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return SidebarViewController.baseItems.count + rootMenuCell.configure(title: menuItem.name, icon: menuItem.image) + rootMenuCell.initWithPositionAndShadow(isFirst: menuItem.isFirst, isLast: menuItem.isLast) + return rootMenuCell + } + + dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in + guard let self else { return UICollectionReusableView() } + + switch kind { + case UICollectionView.elementKindSectionHeader: + let homeLargeTitleHeaderView = collectionView.dequeueReusableSupplementaryView( + ofKind: kind, + view: HomeLargeTitleHeaderView.self, + for: indexPath + ) + + homeLargeTitleHeaderView.configureForDriveSwitch( + accountManager: accountManager, + driveFileManager: driveFileManager, + presenter: self + ) + + headerViewHeight = homeLargeTitleHeaderView.frame.height + return homeLargeTitleHeaderView + case RootMenuHeaderView.kind.rawValue: + let headerView = collectionView.dequeueReusableSupplementaryView( + ofKind: kind, + view: RootMenuHeaderView.self, + for: indexPath + ) + + headerView.configureInCollectionView(collectionView, driveFileManager: driveFileManager, presenter: self) + return headerView + default: + fatalError("Unhandled kind \(kind)") + } + } + + dataSource?.apply(itemsSnapshot, animatingDifferences: false) + } + + static func createListLayout() -> UICollectionViewLayout { + let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), + heightDimension: .estimated(60)) + let item = NSCollectionLayoutItem(layoutSize: itemSize) + + let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), + heightDimension: .estimated(60)) + let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, + subitems: [item]) + + let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(0)) + + let sectionHeaderItem = NSCollectionLayoutBoundarySupplementaryItem( + layoutSize: headerSize, + elementKind: RootMenuHeaderView.kind.rawValue, + alignment: .top + ) + sectionHeaderItem.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12) + sectionHeaderItem.pinToVisibleBounds = true + + let section = NSCollectionLayoutSection(group: group) + section.boundarySupplementaryItems = [sectionHeaderItem] + + let configuration = UICollectionViewCompositionalLayoutConfiguration() + configuration.boundarySupplementaryItems = [generateHeaderItem()] + let layout = UICollectionViewCompositionalLayout(section: section, configuration: configuration) + return layout } - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) - cell.textLabel?.text = SidebarViewController.baseItems[indexPath.row].name - return cell + @objc func presentSearch() { + let viewModel = SearchFilesViewModel(driveFileManager: driveFileManager) + let searchViewController = SearchViewController.instantiateInNavigationController(viewModel: viewModel) + present(searchViewController, animated: true) } - // MARK: - UITableViewDelegate - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true) - let selectedItem = SidebarViewController.baseItems[indexPath.row] - delegate?.didSelectItem(named: selectedItem.id) + @objc func forceRefresh() { + Task { + try? await driveFileManager.initRoot() + refreshControl.endRefreshing() + } + } + + override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard let selectedRootFile = dataSource?.itemIdentifier(for: indexPath)?.destinationFile else { return } + + let destinationViewModel: FileListViewModel + switch selectedRootFile.id { + case DriveFileManager.favoriteRootFile.id: + destinationViewModel = FavoritesViewModel(driveFileManager: driveFileManager) + case DriveFileManager.lastModificationsRootFile.id: + destinationViewModel = LastModificationsViewModel(driveFileManager: driveFileManager) + case DriveFileManager.sharedWithMeRootFile.id: + let sharedWithMeDriveFileManager = driveFileManager.instanceWith(context: .sharedWithMe) + destinationViewModel = SharedWithMeViewModel(driveFileManager: sharedWithMeDriveFileManager) + case DriveFileManager.offlineRoot.id: + destinationViewModel = OfflineFilesViewModel(driveFileManager: driveFileManager) + case DriveFileManager.trashRootFile.id: + destinationViewModel = TrashListViewModel(driveFileManager: driveFileManager) + case DriveFileManager.mySharedRootFile.id: + destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) + default: + destinationViewModel = ConcreteFileListViewModel( + driveFileManager: driveFileManager, + currentDirectory: selectedRootFile + ) + } + + let userRootFolders = rootViewChildren?.compactMap { + RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) + } ?? [] + let menuItems = userRootFolders + SidebarViewController.baseItems + let selectedItemName = menuItems[indexPath.row].name + + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) } } protocol SidebarViewControllerDelegate: AnyObject { - func didSelectItem(named: Int) + func didSelectItem(destinationViewModel: FileListViewModel, name: String) } class RootMenuViewController: CustomLargeTitleCollectionViewController, SelectSwitchDriveDelegate { diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index cbceee652..e79414c42 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -125,8 +125,6 @@ public enum MainTabBarIndex: Int { // } class RootViewController: UISplitViewController, SidebarViewControllerDelegate { - let sidebarViewController = SidebarViewController() - let detailViewController = DetailViewController() let driveFileManager: DriveFileManager init(driveFileManager: DriveFileManager) { @@ -142,6 +140,9 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { override func viewDidLoad() { super.viewDidLoad() + let sidebarViewController = SidebarViewController(driveFileManager: driveFileManager) + let detailViewController = DetailViewController() + sidebarViewController.delegate = self let sidebarNav = UINavigationController(rootViewController: sidebarViewController) @@ -153,37 +154,21 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { // MARK: - SidebarViewControllerDelegate - func didSelectItem(named folderName: Int) { - - let destinationViewModel: FileListViewModel - switch folderName { - case DriveFileManager.favoriteRootFile.id: - destinationViewModel = FavoritesViewModel(driveFileManager: driveFileManager) - case DriveFileManager.lastModificationsRootFile.id: - destinationViewModel = LastModificationsViewModel(driveFileManager: driveFileManager) - case DriveFileManager.sharedWithMeRootFile.id: - let sharedWithMeDriveFileManager = driveFileManager.instanceWith(context: .sharedWithMe) - destinationViewModel = SharedWithMeViewModel(driveFileManager: sharedWithMeDriveFileManager) - case DriveFileManager.offlineRoot.id: - destinationViewModel = OfflineFilesViewModel(driveFileManager: driveFileManager) - case DriveFileManager.trashRootFile.id: - destinationViewModel = TrashListViewModel(driveFileManager: driveFileManager) - case DriveFileManager.mySharedRootFile.id: - destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) - default: - destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) // à changer - } - + func didSelectItem(destinationViewModel: FileListViewModel, name: String) { let destinationViewController = FileListViewController(viewModel: destinationViewModel) - + let homeViewController = HomeViewController(driveFileManager: driveFileManager) + let photoListViewController = PhotoListViewController(viewModel: PhotoListViewModel(driveFileManager: driveFileManager)) + if let detailNav = viewControllers.last as? UINavigationController { - detailNav.setViewControllers([destinationViewController], animated: true) + if name == KDriveResourcesStrings.Localizable.homeTitle { + detailNav.setViewControllers([homeViewController], animated: true) + } else if name == "Images" { + detailNav.setViewControllers([photoListViewController], animated: true) + } else { + detailNav.setViewControllers([destinationViewController], animated: true) + } } } - -// func didSelectItem(named: String) { -// detailViewController.updateDetail(with: named) -// } } class DetailViewController: UIViewController { @@ -199,16 +184,11 @@ class DetailViewController: UIViewController { label.translatesAutoresizingMaskIntoConstraints = false view.addSubview(label) - // Contraintes pour centrer le texte NSLayoutConstraint.activate([ label.centerXAnchor.constraint(equalTo: view.centerXAnchor), label.centerYAnchor.constraint(equalTo: view.centerYAnchor) ]) } - - func updateDetail(with item: String) { - label.text = "You selected: \(item)" - } } class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver { From f855d8d8d8c6fb9939d4a969ca9b52c4141c2f6c Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 4 Oct 2024 14:53:08 +0200 Subject: [PATCH 03/14] feat: NavBar is now sorted --- .../Files/RootMenuViewController.swift | 21 ++++++++++++------- .../UI/Controller/MainTabViewController.swift | 1 - 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 7c5cb13ea..b0f1c2baf 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -42,6 +42,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi let destinationFile: File var isFirst = false var isLast = false + var priority = 0 func hash(into hasher: inout Hasher) { hasher.combine(id) @@ -52,7 +53,8 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.homeTitle, image: KDriveResourcesAsset.house.image, - destinationFile: DriveFileManager.favoriteRootFile), + destinationFile: DriveFileManager.favoriteRootFile, + priority: 3), RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, image: KDriveResourcesAsset.favorite.image, destinationFile: DriveFileManager.favoriteRootFile), @@ -73,7 +75,8 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi destinationFile: DriveFileManager.trashRootFile), RootMenuItem(name: "Images", image: KDriveResourcesAsset.mediaInline.image, - destinationFile: DriveFileManager.trashRootFile)] + destinationFile: DriveFileManager.trashRootFile, + priority: 2)] weak var delegate: SidebarViewControllerDelegate? @LazyInjectService private var accountManager: AccountManageable @@ -85,10 +88,15 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi private var itemsSnapshot: DataSourceSnapshot { let userRootFolders = rootViewChildren?.compactMap { - RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) + RootMenuItem( + name: $0.formattedLocalizedName(drive: driveFileManager.drive), + image: $0.icon, + destinationFile: $0, + priority: 1 + ) } ?? [] - var menuItems = userRootFolders + SidebarViewController.baseItems + var menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } if !menuItems.isEmpty { menuItems[0].isFirst = true menuItems[menuItems.count - 1].isLast = true @@ -267,13 +275,12 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi currentDirectory: selectedRootFile ) } - + let userRootFolders = rootViewChildren?.compactMap { RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) } ?? [] - let menuItems = userRootFolders + SidebarViewController.baseItems + let menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } let selectedItemName = menuItems[indexPath.row].name - delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) } } diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index e79414c42..3555f85e6 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -158,7 +158,6 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { let destinationViewController = FileListViewController(viewModel: destinationViewModel) let homeViewController = HomeViewController(driveFileManager: driveFileManager) let photoListViewController = PhotoListViewController(viewModel: PhotoListViewModel(driveFileManager: driveFileManager)) - if let detailNav = viewControllers.last as? UINavigationController { if name == KDriveResourcesStrings.Localizable.homeTitle { detailNav.setViewControllers([homeViewController], animated: true) From e13229cf3f97db835002d4d2e7840083bf55fd4c Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 4 Oct 2024 15:50:55 +0200 Subject: [PATCH 04/14] feat: Add menu to navBar --- .../Files/RootMenuViewController.swift | 31 ++++++++++++++++--- .../UI/Controller/MainTabViewController.swift | 3 ++ 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index b0f1c2baf..fba3168aa 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -55,6 +55,10 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi image: KDriveResourcesAsset.house.image, destinationFile: DriveFileManager.favoriteRootFile, priority: 3), + RootMenuItem(name: "Images", + image: KDriveResourcesAsset.mediaInline.image, + destinationFile: DriveFileManager.trashRootFile, + priority: 2), RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, image: KDriveResourcesAsset.favorite.image, destinationFile: DriveFileManager.favoriteRootFile), @@ -73,10 +77,10 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, image: KDriveResourcesAsset.delete.image, destinationFile: DriveFileManager.trashRootFile), - RootMenuItem(name: "Images", - image: KDriveResourcesAsset.mediaInline.image, - destinationFile: DriveFileManager.trashRootFile, - priority: 2)] + RootMenuItem(name: KDriveResourcesStrings.Localizable.menuTitle, + image: generateProfileTabImages(image: KDriveResourcesAsset + .placeholderAvatar.image), + destinationFile: DriveFileManager.trashRootFile)] weak var delegate: SidebarViewControllerDelegate? @LazyInjectService private var accountManager: AccountManageable @@ -159,6 +163,25 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } + private static func generateProfileTabImages(image: UIImage) -> (UIImage) { + let iconSize = 28.0 + + let selectedImage = image + .resize(size: CGSize(width: iconSize + 2, height: iconSize + 2)) + .maskImageWithRoundedRect( + cornerRadius: CGFloat((iconSize + 2) / 2), + borderWidth: 2, + borderColor: KDriveResourcesAsset.infomaniakColor.color + ) + .withRenderingMode(.alwaysOriginal) + + let image = image + .resize(size: CGSize(width: iconSize, height: iconSize)) + .maskImageWithRoundedRect(cornerRadius: CGFloat(iconSize / 2), borderWidth: 0, borderColor: nil) + .withRenderingMode(.alwaysOriginal) + return image + } + func configureDataSource() { dataSource = MenuDataSource(collectionView: collectionView) { collectionView, indexPath, menuItem -> RootMenuCell? in guard let rootMenuCell = collectionView.dequeueReusableCell( diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 3555f85e6..1aac97ea2 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -158,11 +158,14 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { let destinationViewController = FileListViewController(viewModel: destinationViewModel) let homeViewController = HomeViewController(driveFileManager: driveFileManager) let photoListViewController = PhotoListViewController(viewModel: PhotoListViewModel(driveFileManager: driveFileManager)) + let menuViewController = MenuViewController(driveFileManager: driveFileManager) if let detailNav = viewControllers.last as? UINavigationController { if name == KDriveResourcesStrings.Localizable.homeTitle { detailNav.setViewControllers([homeViewController], animated: true) } else if name == "Images" { detailNav.setViewControllers([photoListViewController], animated: true) + } else if name == KDriveResourcesStrings.Localizable.menuTitle { + detailNav.setViewControllers([menuViewController], animated: true) } else { detailNav.setViewControllers([destinationViewController], animated: true) } From 83339c64daaa6ed583ea1bb2f4cc816035ec48a5 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Tue, 22 Oct 2024 12:53:08 +0200 Subject: [PATCH 05/14] feat: Add iPhone view when compact --- .../Files/RootMenuViewController.swift | 20 +++++++++---------- .../UI/Controller/MainTabViewController.swift | 1 + 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index fba3168aa..396c947ac 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -38,7 +38,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } let name: String - let image: UIImage + var image: UIImage let destinationFile: File var isFirst = false var isLast = false @@ -51,7 +51,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } - private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.homeTitle, + private static var baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.homeTitle, image: KDriveResourcesAsset.house.image, destinationFile: DriveFileManager.favoriteRootFile, priority: 3), @@ -138,6 +138,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi refreshControl.addTarget(self, action: #selector(forceRefresh), for: .valueChanged) configureDataSource() + updateProfilePicture() let rootFileUid = File.uid(driveId: driveFileManager.drive.id, fileId: DriveFileManager.constants.rootID) guard let root = driveFileManager.database.fetchObject(ofType: File.self, forPrimaryKey: rootFileUid) else { @@ -163,18 +164,15 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } + func updateProfilePicture() { + accountManager.currentAccount?.user?.getAvatar(size: CGSize(width: 512, height: 512)) { image in + SidebarViewController.baseItems[8].image = SidebarViewController.generateProfileTabImages(image: image) + } + } + private static func generateProfileTabImages(image: UIImage) -> (UIImage) { let iconSize = 28.0 - let selectedImage = image - .resize(size: CGSize(width: iconSize + 2, height: iconSize + 2)) - .maskImageWithRoundedRect( - cornerRadius: CGFloat((iconSize + 2) / 2), - borderWidth: 2, - borderColor: KDriveResourcesAsset.infomaniakColor.color - ) - .withRenderingMode(.alwaysOriginal) - let image = image .resize(size: CGSize(width: iconSize, height: iconSize)) .maskImageWithRoundedRect(cornerRadius: CGFloat(iconSize / 2), borderWidth: 0, borderColor: nil) diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 1aac97ea2..7febe0e00 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -149,6 +149,7 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { let detailNav = UINavigationController(rootViewController: detailViewController) viewControllers = [sidebarNav, detailNav] + setViewController(MainTabViewController(driveFileManager: driveFileManager), for: .compact) preferredDisplayMode = .oneBesideSecondary } From b03d7480636df286e8d6c82e2e7524d047d23d73 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 24 Oct 2024 08:26:13 +0200 Subject: [PATCH 06/14] feat: Button add file --- .../Files/RootMenuViewController.swift | 72 +++++++++++++++++-- 1 file changed, 67 insertions(+), 5 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 396c947ac..431735e4e 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -76,11 +76,11 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi destinationFile: DriveFileManager.offlineRoot), RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, image: KDriveResourcesAsset.delete.image, - destinationFile: DriveFileManager.trashRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.menuTitle, - image: generateProfileTabImages(image: KDriveResourcesAsset - .placeholderAvatar.image), destinationFile: DriveFileManager.trashRootFile)] +// RootMenuItem(name: KDriveResourcesStrings.Localizable.menuTitle, +// image: generateProfileTabImages(image: KDriveResourcesAsset +// .placeholderAvatar.image), +// destinationFile: DriveFileManager.trashRootFile)] weak var delegate: SidebarViewControllerDelegate? @LazyInjectService private var accountManager: AccountManageable @@ -138,7 +138,41 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi refreshControl.addTarget(self, action: #selector(forceRefresh), for: .valueChanged) configureDataSource() - updateProfilePicture() +// updateProfilePicture() + + let buttonAdd = UIButton(type: .system) + buttonAdd.setTitle("Ajouter", for: .normal) + buttonAdd.backgroundColor = .systemGreen + buttonAdd.setTitleColor(.white, for: .normal) + buttonAdd.layer.cornerRadius = 10 + buttonAdd.translatesAutoresizingMaskIntoConstraints = false + + let buttonMenu = UIButton(type: .custom) + accountManager.currentAccount?.user?.getAvatar(size: CGSize(width: 512, height: 512)) { image in + buttonMenu + .setImage(SidebarViewController.generateProfileTabImages(image: image), + for: .normal) + buttonMenu.translatesAutoresizingMaskIntoConstraints = false + } + + collectionView.addSubview(buttonAdd) + collectionView.addSubview(buttonMenu) + buttonAdd.addTarget(self, action: #selector(buttonAddClicked), for: .touchUpInside) + buttonMenu.addTarget(self, action: #selector(buttonMenuClicked), for: .touchUpInside) + + NSLayoutConstraint.activate([ + buttonAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 48), + buttonAdd.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), + buttonAdd.heightAnchor.constraint(equalToConstant: 50), + buttonAdd.widthAnchor.constraint(equalToConstant: 200) + ]) + + NSLayoutConstraint.activate([ + buttonMenu.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -30), + buttonMenu.trailingAnchor.constraint(equalTo: view.trailingAnchor), + buttonMenu.widthAnchor.constraint(equalToConstant: 100), + buttonMenu.heightAnchor.constraint(equalToConstant: 100) + ]) let rootFileUid = File.uid(driveId: driveFileManager.drive.id, fileId: DriveFileManager.constants.rootID) guard let root = driveFileManager.database.fetchObject(ofType: File.self, forPrimaryKey: rootFileUid) else { @@ -179,6 +213,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi .withRenderingMode(.alwaysOriginal) return image } + func configureDataSource() { dataSource = MenuDataSource(collectionView: collectionView) { collectionView, indexPath, menuItem -> RootMenuCell? in @@ -304,6 +339,33 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi let selectedItemName = menuItems[indexPath.row].name delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) } + + @objc func buttonAddClicked() { + let currentDriveFileManager = driveFileManager + let currentDirectory = (splitViewController?.viewController(for: .secondary) as? UINavigationController)? + .topViewController as? FileListViewController + let currentDirectoryOrRoot = currentDirectory?.viewModel.currentDirectory ?? driveFileManager.getCachedMyFilesRoot() + guard let currentDirectoryOrRoot else { + return + } + let floatingPanelViewController = AdaptiveDriveFloatingPanelController() + + let plusButtonFloatingPanel = PlusButtonFloatingPanelViewController( + driveFileManager: currentDriveFileManager, + folder: currentDirectoryOrRoot + ) + + floatingPanelViewController.isRemovalInteractionEnabled = true + floatingPanelViewController.delegate = plusButtonFloatingPanel + + floatingPanelViewController.set(contentViewController: plusButtonFloatingPanel) + floatingPanelViewController.trackAndObserve(scrollView: plusButtonFloatingPanel.tableView) + present(floatingPanelViewController, animated: true) + } + + @objc func buttonMenuClicked() { + delegate?.didSelectItem(destinationViewModel: MySharesViewModel(driveFileManager: driveFileManager), name: KDriveResourcesStrings.Localizable.menuTitle) + } } protocol SidebarViewControllerDelegate: AnyObject { From 112242c347e5e3a00cee9822435ebd3416a0f149 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 24 Oct 2024 08:33:06 +0200 Subject: [PATCH 07/14] refactor: Move photoPickerDelegate to openMediaHelper --- kDrive/OpenMediaHelper.swift | 13 +++++++------ kDrive/UI/Controller/MainTabViewController.swift | 2 -- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/kDrive/OpenMediaHelper.swift b/kDrive/OpenMediaHelper.swift index df535c463..537c9dd60 100644 --- a/kDrive/OpenMediaHelper.swift +++ b/kDrive/OpenMediaHelper.swift @@ -28,14 +28,15 @@ import VisionKit struct OpenMediaHelper { var currentDirectory: File? var driveFileManager: DriveFileManager + var photoPickerDelegate = PhotoPickerDelegate() enum Media { case library, camera } - func openMedia(_ mainTabViewController: MainTabViewController, _ media: Media) { - mainTabViewController.photoPickerDelegate.driveFileManager = driveFileManager - mainTabViewController.photoPickerDelegate.currentDirectory = currentDirectory?.freezeIfNeeded() + func openMedia(_ mainTabViewController: UIViewController, _ media: Media) { + photoPickerDelegate.driveFileManager = driveFileManager + photoPickerDelegate.currentDirectory = currentDirectory?.freezeIfNeeded() if #available(iOS 14, *), media == .library { // Check permission @@ -46,7 +47,7 @@ struct OpenMediaHelper { configuration.selectionLimit = 0 let picker = PHPickerViewController(configuration: configuration) - picker.delegate = mainTabViewController.photoPickerDelegate + picker.delegate = photoPickerDelegate mainTabViewController.present(picker, animated: true) } } else { @@ -85,14 +86,14 @@ struct OpenMediaHelper { let picker = UIImagePickerController() picker.sourceType = sourceType - picker.delegate = mainTabViewController.photoPickerDelegate + picker.delegate = photoPickerDelegate picker.mediaTypes = UIImagePickerController .availableMediaTypes(for: sourceType) ?? [UTI.image.identifier, UTI.movie.identifier] mainTabViewController.present(picker, animated: true) } } - func openScan(_ mainTabViewController: MainTabViewController, _ presentedAboveFileList: Bool) { + func openScan(_ mainTabViewController: UIViewController, _ presentedAboveFileList: Bool) { guard VNDocumentCameraViewController.isSupported else { DDLogError("VNDocumentCameraViewController is not supported on this device") return diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 7febe0e00..90d55cbbe 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -201,8 +201,6 @@ class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver /// Time between two tap events that feels alright for a double tap private static let doubleTapInterval = TimeInterval(0.350) - // swiftlint:disable:next weak_delegate - var photoPickerDelegate = PhotoPickerDelegate() @LazyInjectService var accountManager: AccountManageable @LazyInjectService var uploadQueue: UploadQueue From d5efa1c7761d0c851e017a51bfda8926e0672be8 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 24 Oct 2024 08:51:56 +0200 Subject: [PATCH 08/14] refactor: Move MainTabView extension to OpenMediaHelper --- kDrive/OpenMediaHelper.swift | 51 +++++++++++++++++-- ...lusButtonFloatingPanelViewController.swift | 14 ++--- .../UI/Controller/MainTabViewController.swift | 2 - 3 files changed, 53 insertions(+), 14 deletions(-) diff --git a/kDrive/OpenMediaHelper.swift b/kDrive/OpenMediaHelper.swift index 537c9dd60..ac1f2f89d 100644 --- a/kDrive/OpenMediaHelper.swift +++ b/kDrive/OpenMediaHelper.swift @@ -19,22 +19,34 @@ import CocoaLumberjackSwift import Foundation import InfomaniakCore +import InfomaniakDI import kDriveCore import kDriveResources import PhotosUI import Vision import VisionKit -struct OpenMediaHelper { - var currentDirectory: File? - var driveFileManager: DriveFileManager - var photoPickerDelegate = PhotoPickerDelegate() +class OpenMediaHelper: NSObject { + @LazyInjectService var accountManager: AccountManageable + @LazyInjectService var uploadQueue: UploadQueue + @LazyInjectService var fileImportHelper: FileImportHelper + + let currentDirectory: File? + let driveFileManager: DriveFileManager + let photoPickerDelegate = PhotoPickerDelegate() enum Media { case library, camera } + init(currentDirectory: File? = nil, driveFileManager: DriveFileManager) { + self.currentDirectory = currentDirectory + self.driveFileManager = driveFileManager + super.init() + } + func openMedia(_ mainTabViewController: UIViewController, _ media: Media) { + photoPickerDelegate.viewController = mainTabViewController photoPickerDelegate.driveFileManager = driveFileManager photoPickerDelegate.currentDirectory = currentDirectory?.freezeIfNeeded() @@ -47,7 +59,7 @@ struct OpenMediaHelper { configuration.selectionLimit = 0 let picker = PHPickerViewController(configuration: configuration) - picker.delegate = photoPickerDelegate + picker.delegate = self.photoPickerDelegate mainTabViewController.present(picker, animated: true) } } else { @@ -110,3 +122,32 @@ struct OpenMediaHelper { mainTabViewController.present(navigationViewController, animated: true) } } + +extension OpenMediaHelper: UIDocumentPickerDelegate { + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + if let documentPicker = controller as? DriveImportDocumentPickerViewController { + for url in urls { + let targetURL = fileImportHelper.generateImportURL(for: url.uti) + + do { + if FileManager.default.fileExists(atPath: targetURL.path) { + try FileManager.default.removeItem(at: targetURL) + } + + try FileManager.default.moveItem(at: url, to: targetURL) + uploadQueue.saveToRealm( + UploadFile( + parentDirectoryId: documentPicker.importDriveDirectory.id, + userId: accountManager.currentUserId, + driveId: documentPicker.importDriveDirectory.driveId, + url: targetURL, + name: url.lastPathComponent + ) + ) + } catch { + UIConstants.showSnackBarIfNeeded(error: DriveError.unknownError) + } + } + } + } +} diff --git a/kDrive/UI/Controller/Create File/PlusButtonFloatingPanelViewController.swift b/kDrive/UI/Controller/Create File/PlusButtonFloatingPanelViewController.swift index 1f0c49b12..fee1acaa7 100644 --- a/kDrive/UI/Controller/Create File/PlusButtonFloatingPanelViewController.swift +++ b/kDrive/UI/Controller/Create File/PlusButtonFloatingPanelViewController.swift @@ -201,7 +201,7 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane } dismiss(animated: true) - guard let mainTabViewController = parent?.presentingViewController as? MainTabViewController else { + guard let mainTabViewController = parent?.presentingViewController else { return } @@ -240,15 +240,15 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane // MARK: Actions - private func importAction(_ mainTabViewController: MainTabViewController) { + private func importAction(_ mainTabViewController: UIViewController) { let documentPicker = DriveImportDocumentPickerViewController(documentTypes: [UTI.data.identifier], in: .import) documentPicker.importDrive = driveFileManager.drive documentPicker.importDriveDirectory = currentDirectory.freezeIfNeeded() - documentPicker.delegate = mainTabViewController +// documentPicker.delegate = mainTabViewController mainTabViewController.present(documentPicker, animated: true) } - private func folderAction(_ mainTabViewController: MainTabViewController) { + private func folderAction(_ mainTabViewController: UIViewController) { let newFolderViewController = NewFolderTypeTableViewController.instantiateInNavigationController( parentDirectory: currentDirectory, driveFileManager: driveFileManager @@ -256,7 +256,7 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane mainTabViewController.present(newFolderViewController, animated: true) } - private func scanAction(_ mainTabViewController: MainTabViewController) { + private func scanAction(_ mainTabViewController: UIViewController) { guard VNDocumentCameraViewController.isSupported else { DDLogError("VNDocumentCameraViewController is not supported on this device") return @@ -273,12 +273,12 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane mainTabViewController.present(navigationViewController, animated: true) } - private func mediaAction(_ mainTabViewController: MainTabViewController, action: PlusButtonMenuAction) { + private func mediaAction(_ mainTabViewController: UIViewController, action: PlusButtonMenuAction) { let openMediaHelper = OpenMediaHelper(currentDirectory: currentDirectory, driveFileManager: driveFileManager) openMediaHelper.openMedia(mainTabViewController, action == .importMediaAction ? .library : .camera) } - private func documentAction(_ mainTabViewController: MainTabViewController, action: PlusButtonMenuAction) { + private func documentAction(_ mainTabViewController: UIViewController, action: PlusButtonMenuAction) { let alertViewController = AlertDocViewController(fileType: action.docType, directory: currentDirectory.freezeIfNeeded(), driveFileManager: driveFileManager) diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 90d55cbbe..dcb464880 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -201,7 +201,6 @@ class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver /// Time between two tap events that feels alright for a double tap private static let doubleTapInterval = TimeInterval(0.350) - @LazyInjectService var accountManager: AccountManageable @LazyInjectService var uploadQueue: UploadQueue @LazyInjectService var fileImportHelper: FileImportHelper @@ -254,7 +253,6 @@ class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver delegate = self tabBar.backgroundColor = KDriveResourcesAsset.backgroundCardViewColor.color (tabBar as? MainTabBar)?.tabDelegate = self - photoPickerDelegate.viewController = self } override func viewWillLayoutSubviews() { From bbdd39eb49039d275cb6f658517d211315ce7afb Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 24 Oct 2024 14:10:23 +0200 Subject: [PATCH 09/14] feat: Sort sideBar items into sections --- .../Files/RootMenuViewController.swift | 168 +++++++++++------- .../UI/Controller/MainTabViewController.swift | 2 +- .../Controller/Menu/MenuViewController.swift | 2 +- 3 files changed, 106 insertions(+), 66 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 431735e4e..921bd5150 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -30,6 +30,8 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi private enum RootMenuSection { case main + case one + case two } private struct RootMenuItem: Equatable, Hashable { @@ -55,32 +57,35 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi image: KDriveResourcesAsset.house.image, destinationFile: DriveFileManager.favoriteRootFile, priority: 3), - RootMenuItem(name: "Images", + RootMenuItem(name: KDriveResourcesStrings.Localizable.allPictures, image: KDriveResourcesAsset.mediaInline.image, destinationFile: DriveFileManager.trashRootFile, - priority: 2), - RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, - image: KDriveResourcesAsset.favorite.image, - destinationFile: DriveFileManager.favoriteRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, - image: KDriveResourcesAsset.clock.image, - destinationFile: DriveFileManager.lastModificationsRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, - image: KDriveResourcesAsset.folderSelect2.image, - destinationFile: DriveFileManager.sharedWithMeRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, - image: KDriveResourcesAsset.folderSelect.image, - destinationFile: DriveFileManager.mySharedRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.offlineFileTitle, - image: KDriveResourcesAsset.availableOffline.image, - destinationFile: DriveFileManager.offlineRoot), - RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, - image: KDriveResourcesAsset.delete.image, - destinationFile: DriveFileManager.trashRootFile)] -// RootMenuItem(name: KDriveResourcesStrings.Localizable.menuTitle, -// image: generateProfileTabImages(image: KDriveResourcesAsset -// .placeholderAvatar.image), -// destinationFile: DriveFileManager.trashRootFile)] + priority: 2)] + + private static var secondSectionItems: [RootMenuItem] = [RootMenuItem( + name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, + image: KDriveResourcesAsset.folderSelect2.image, + destinationFile: DriveFileManager.sharedWithMeRootFile + ), + RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, + image: KDriveResourcesAsset.folderSelect.image, + destinationFile: DriveFileManager.mySharedRootFile)] + + private static var thirdSectionItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, + image: KDriveResourcesAsset.favorite.image, + destinationFile: DriveFileManager.favoriteRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, + image: KDriveResourcesAsset.clock.image, + destinationFile: DriveFileManager + .lastModificationsRootFile), + RootMenuItem( + name: KDriveResourcesStrings.Localizable.offlineFileTitle, + image: KDriveResourcesAsset.availableOffline.image, + destinationFile: DriveFileManager.offlineRoot + ), + RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, + image: KDriveResourcesAsset.delete.image, + destinationFile: DriveFileManager.trashRootFile)] weak var delegate: SidebarViewControllerDelegate? @LazyInjectService private var accountManager: AccountManageable @@ -100,15 +105,20 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi ) } ?? [] - var menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } - if !menuItems.isEmpty { - menuItems[0].isFirst = true - menuItems[menuItems.count - 1].isLast = true - } +// var menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } +// if !menuItems.isEmpty { +// menuItems[0].isFirst = true +// menuItems[menuItems.count - 1].isLast = true +// } var snapshot = DataSourceSnapshot() snapshot.appendSections([RootMenuSection.main]) - snapshot.appendItems(menuItems) + snapshot.appendSections([RootMenuSection.one]) + snapshot.appendSections([RootMenuSection.two]) + snapshot.appendItems(SidebarViewController.baseItems, toSection: RootMenuSection.main) + snapshot.appendItems(userRootFolders + SidebarViewController.secondSectionItems, toSection: RootMenuSection.one) + snapshot.appendItems(SidebarViewController.thirdSectionItems, toSection: RootMenuSection.two) + return snapshot } @@ -117,6 +127,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi super.init(collectionViewLayout: SidebarViewController.createListLayout()) } + @available(*, unavailable) @available(*, unavailable) required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") @@ -124,8 +135,20 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi override func viewDidLoad() { super.viewDidLoad() + var avatar = UIImage() + accountManager.currentAccount?.user?.getAvatar(size: CGSize(width: 512, height: 512)) { image in + avatar = SidebarViewController.generateProfileTabImages(image: image) + let buttonMenu = UIBarButtonItem( + image: avatar, + style: .plain, + target: self, + action: #selector(self.buttonMenuClicked(_:)) + ) + self.navigationItem.rightBarButtonItem = buttonMenu + } + navigationItem.title = driveFileManager.drive.name - navigationItem.rightBarButtonItem = FileListBarButton(type: .search, target: self, action: #selector(presentSearch)) +// navigationItem.rightBarButtonItem = FileListBarButton(type: .search, target: self, action: #selector(presentSearch)) collectionView.backgroundColor = KDriveResourcesAsset.backgroundColor.color collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: UIConstants.listPaddingBottom, right: 0) @@ -138,42 +161,25 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi refreshControl.addTarget(self, action: #selector(forceRefresh), for: .valueChanged) configureDataSource() -// updateProfilePicture() let buttonAdd = UIButton(type: .system) - buttonAdd.setTitle("Ajouter", for: .normal) - buttonAdd.backgroundColor = .systemGreen + buttonAdd.setTitle(KDriveResourcesStrings.Localizable.buttonAdd, for: .normal) + buttonAdd.backgroundColor = KDriveResourcesAsset.infomaniakColor.color buttonAdd.setTitleColor(.white, for: .normal) buttonAdd.layer.cornerRadius = 10 buttonAdd.translatesAutoresizingMaskIntoConstraints = false - let buttonMenu = UIButton(type: .custom) - accountManager.currentAccount?.user?.getAvatar(size: CGSize(width: 512, height: 512)) { image in - buttonMenu - .setImage(SidebarViewController.generateProfileTabImages(image: image), - for: .normal) - buttonMenu.translatesAutoresizingMaskIntoConstraints = false - } - collectionView.addSubview(buttonAdd) - collectionView.addSubview(buttonMenu) + buttonAdd.addTarget(self, action: #selector(buttonAddClicked), for: .touchUpInside) - buttonMenu.addTarget(self, action: #selector(buttonMenuClicked), for: .touchUpInside) NSLayoutConstraint.activate([ buttonAdd.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 48), buttonAdd.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -20), - buttonAdd.heightAnchor.constraint(equalToConstant: 50), + buttonAdd.heightAnchor.constraint(equalToConstant: 48), buttonAdd.widthAnchor.constraint(equalToConstant: 200) ]) - NSLayoutConstraint.activate([ - buttonMenu.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: -30), - buttonMenu.trailingAnchor.constraint(equalTo: view.trailingAnchor), - buttonMenu.widthAnchor.constraint(equalToConstant: 100), - buttonMenu.heightAnchor.constraint(equalToConstant: 100) - ]) - let rootFileUid = File.uid(driveId: driveFileManager.drive.id, fileId: DriveFileManager.constants.rootID) guard let root = driveFileManager.database.fetchObject(ofType: File.self, forPrimaryKey: rootFileUid) else { return @@ -198,12 +204,6 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } - func updateProfilePicture() { - accountManager.currentAccount?.user?.getAvatar(size: CGSize(width: 512, height: 512)) { image in - SidebarViewController.baseItems[8].image = SidebarViewController.generateProfileTabImages(image: image) - } - } - private static func generateProfileTabImages(image: UIImage) -> (UIImage) { let iconSize = 28.0 @@ -213,7 +213,6 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi .withRenderingMode(.alwaysOriginal) return image } - func configureDataSource() { dataSource = MenuDataSource(collectionView: collectionView) { collectionView, indexPath, menuItem -> RootMenuCell? in @@ -262,6 +261,26 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } +// dataSource?.supplementaryViewProvider = { collectionView, kind, indexPath in +// let headerView = collectionView.dequeueReusableSupplementaryView( +// ofKind: UICollectionView.elementKindSectionHeader, +// withReuseIdentifier: "header", +// for: indexPath +// ) +// +// let section = self.dataSource?.snapshot().sectionIdentifiers[indexPath.section] +// +// switch section { +// case .one: +// headerView.largeContentTitle = "First Section" +// case .two: +// headerView.largeContentTitle = "Second Section" +// default: +// headerView.largeContentTitle = "Defaut" +// } +// return headerView +// } + dataSource?.apply(itemsSnapshot, animatingDifferences: false) } @@ -287,6 +306,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi let section = NSCollectionLayoutSection(group: group) section.boundarySupplementaryItems = [sectionHeaderItem] + section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 0) let configuration = UICollectionViewCompositionalLayoutConfiguration() configuration.boundarySupplementaryItems = [generateHeaderItem()] @@ -311,6 +331,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi guard let selectedRootFile = dataSource?.itemIdentifier(for: indexPath)?.destinationFile else { return } let destinationViewModel: FileListViewModel + switch selectedRootFile.id { case DriveFileManager.favoriteRootFile.id: destinationViewModel = FavoritesViewModel(driveFileManager: driveFileManager) @@ -335,9 +356,25 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi let userRootFolders = rootViewChildren?.compactMap { RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) } ?? [] - let menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } - let selectedItemName = menuItems[indexPath.row].name - delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + switch itemsSnapshot.sectionIdentifiers[indexPath.section] { + case .main: + let menuItems = SidebarViewController.baseItems + let selectedItemName = menuItems[indexPath.row].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + case .one: + let length = (SidebarViewController.baseItems).count + let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems) + let selectedItemName = menuItems[indexPath.row + length].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + case .two: + let length = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems).count + let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems + SidebarViewController.thirdSectionItems) + let selectedItemName = menuItems[indexPath.row + length].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + } } @objc func buttonAddClicked() { @@ -363,8 +400,11 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi present(floatingPanelViewController, animated: true) } - @objc func buttonMenuClicked() { - delegate?.didSelectItem(destinationViewModel: MySharesViewModel(driveFileManager: driveFileManager), name: KDriveResourcesStrings.Localizable.menuTitle) + @objc func buttonMenuClicked(_ sender: UIBarButtonItem) { + delegate?.didSelectItem( + destinationViewModel: MySharesViewModel(driveFileManager: driveFileManager), + name: KDriveResourcesStrings.Localizable.menuTitle + ) } } diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index dcb464880..4f5b192e1 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -163,7 +163,7 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { if let detailNav = viewControllers.last as? UINavigationController { if name == KDriveResourcesStrings.Localizable.homeTitle { detailNav.setViewControllers([homeViewController], animated: true) - } else if name == "Images" { + } else if name == KDriveResourcesStrings.Localizable.allPictures { detailNav.setViewControllers([photoListViewController], animated: true) } else if name == KDriveResourcesStrings.Localizable.menuTitle { detailNav.setViewControllers([menuViewController], animated: true) diff --git a/kDrive/UI/Controller/Menu/MenuViewController.swift b/kDrive/UI/Controller/Menu/MenuViewController.swift index ae38221e6..d29defacb 100644 --- a/kDrive/UI/Controller/Menu/MenuViewController.swift +++ b/kDrive/UI/Controller/Menu/MenuViewController.swift @@ -102,7 +102,7 @@ final class MenuViewController: UITableViewController, SelectSwitchDriveDelegate override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) - navigationController?.setNavigationBarHidden(true, animated: false) + navigationController?.setNavigationBarHidden(false, animated: false) (tabBarController as? PlusButtonObserver)?.updateCenterButton() } From ea468c9e3c932541f1482d1345572215219dbd18 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Thu, 24 Oct 2024 16:08:55 +0200 Subject: [PATCH 10/14] fix: Solve problem of clicking twice on the same cell --- .../Files/RootMenuViewController.swift | 135 +++++++++--------- 1 file changed, 65 insertions(+), 70 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 921bd5150..eed40af28 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -27,6 +27,7 @@ import UIKit class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwitchDriveDelegate { private typealias MenuDataSource = UICollectionViewDiffableDataSource private typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot + private var selectedIndexPath: IndexPath? private enum RootMenuSection { case main @@ -60,30 +61,37 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi RootMenuItem(name: KDriveResourcesStrings.Localizable.allPictures, image: KDriveResourcesAsset.mediaInline.image, destinationFile: DriveFileManager.trashRootFile, - priority: 2)] - - private static var secondSectionItems: [RootMenuItem] = [RootMenuItem( - name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, - image: KDriveResourcesAsset.folderSelect2.image, - destinationFile: DriveFileManager.sharedWithMeRootFile - ), - RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, - image: KDriveResourcesAsset.folderSelect.image, - destinationFile: DriveFileManager.mySharedRootFile)] - - private static var thirdSectionItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, - image: KDriveResourcesAsset.favorite.image, - destinationFile: DriveFileManager.favoriteRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, - image: KDriveResourcesAsset.clock.image, - destinationFile: DriveFileManager - .lastModificationsRootFile), - RootMenuItem( - name: KDriveResourcesStrings.Localizable.offlineFileTitle, - image: KDriveResourcesAsset.availableOffline.image, - destinationFile: DriveFileManager.offlineRoot - ), - RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, + priority: 2), + RootMenuItem( + name: KDriveResourcesStrings.Localizable.favoritesTitle, + image: KDriveResourcesAsset.favorite.image, + destinationFile: DriveFileManager.favoriteRootFile + ), + RootMenuItem( + name: KDriveResourcesStrings.Localizable + .lastEditsTitle, + image: KDriveResourcesAsset.clock.image, + destinationFile: DriveFileManager + .lastModificationsRootFile + ), + RootMenuItem( + name: KDriveResourcesStrings.Localizable + .offlineFileTitle, + image: KDriveResourcesAsset.availableOffline + .image, + destinationFile: DriveFileManager.offlineRoot + )] + + private static var secondSectionItems: [RootMenuItem] = [ + RootMenuItem(name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, + image: KDriveResourcesAsset.folderSelect2.image, + destinationFile: DriveFileManager.sharedWithMeRootFile), + RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, + image: KDriveResourcesAsset.folderSelect.image, + destinationFile: DriveFileManager.mySharedRootFile) + ] + + private static var thirdSectionItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, image: KDriveResourcesAsset.delete.image, destinationFile: DriveFileManager.trashRootFile)] @@ -162,7 +170,7 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi configureDataSource() - let buttonAdd = UIButton(type: .system) + let buttonAdd = ImageButton() buttonAdd.setTitle(KDriveResourcesStrings.Localizable.buttonAdd, for: .normal) buttonAdd.backgroundColor = KDriveResourcesAsset.infomaniakColor.color buttonAdd.setTitleColor(.white, for: .normal) @@ -261,26 +269,6 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } } -// dataSource?.supplementaryViewProvider = { collectionView, kind, indexPath in -// let headerView = collectionView.dequeueReusableSupplementaryView( -// ofKind: UICollectionView.elementKindSectionHeader, -// withReuseIdentifier: "header", -// for: indexPath -// ) -// -// let section = self.dataSource?.snapshot().sectionIdentifiers[indexPath.section] -// -// switch section { -// case .one: -// headerView.largeContentTitle = "First Section" -// case .two: -// headerView.largeContentTitle = "Second Section" -// default: -// headerView.largeContentTitle = "Defaut" -// } -// return headerView -// } - dataSource?.apply(itemsSnapshot, animatingDifferences: false) } @@ -353,28 +341,32 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi ) } - let userRootFolders = rootViewChildren?.compactMap { - RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) - } ?? [] - switch itemsSnapshot.sectionIdentifiers[indexPath.section] { - case .main: - let menuItems = SidebarViewController.baseItems - let selectedItemName = menuItems[indexPath.row].name - delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) - case .one: - let length = (SidebarViewController.baseItems).count - let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController - .secondSectionItems) - let selectedItemName = menuItems[indexPath.row + length].name - delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) - case .two: - let length = (SidebarViewController.baseItems + userRootFolders + SidebarViewController - .secondSectionItems).count - let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController - .secondSectionItems + SidebarViewController.thirdSectionItems) - let selectedItemName = menuItems[indexPath.row + length].name - delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + if indexPath != selectedIndexPath { + let userRootFolders = rootViewChildren?.compactMap { + RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) + } ?? [] + switch itemsSnapshot.sectionIdentifiers[indexPath.section] { + case .main: + let menuItems = SidebarViewController.baseItems + let selectedItemName = menuItems[indexPath.row].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + case .one: + let length = (SidebarViewController.baseItems).count + let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems) + let selectedItemName = menuItems[indexPath.row + length].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + case .two: + let length = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems).count + let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController + .secondSectionItems + SidebarViewController.thirdSectionItems) + let selectedItemName = menuItems[indexPath.row + length].name + delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) + } } + + selectedIndexPath = indexPath } @objc func buttonAddClicked() { @@ -401,10 +393,13 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi } @objc func buttonMenuClicked(_ sender: UIBarButtonItem) { - delegate?.didSelectItem( - destinationViewModel: MySharesViewModel(driveFileManager: driveFileManager), - name: KDriveResourcesStrings.Localizable.menuTitle - ) + if selectedIndexPath != [-1, -1] { + selectedIndexPath = [-1, -1] + delegate?.didSelectItem( + destinationViewModel: MySharesViewModel(driveFileManager: driveFileManager), + name: KDriveResourcesStrings.Localizable.menuTitle + ) + } } } From 8a187ec780876d577e7d0ba7190186781f1ea64a Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 25 Oct 2024 09:36:17 +0200 Subject: [PATCH 11/14] feat: Add spacing in imageButton --- kDrive/UI/Controller/Files/RootMenuViewController.swift | 5 +++++ kDrive/UI/Controller/MainTabViewController.swift | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index eed40af28..7615ac88d 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -171,6 +171,11 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi configureDataSource() let buttonAdd = ImageButton() + buttonAdd.setImage(KDriveResourcesAsset.plus.image, for: .normal) + buttonAdd.tintColor = .white + buttonAdd.imageWidth = 18 + buttonAdd.imageHeight = 18 + buttonAdd.imageSpacing = 20 buttonAdd.setTitle(KDriveResourcesStrings.Localizable.buttonAdd, for: .normal) buttonAdd.backgroundColor = KDriveResourcesAsset.infomaniakColor.color buttonAdd.setTitleColor(.white, for: .normal) diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 4f5b192e1..232f19128 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -162,13 +162,13 @@ class RootViewController: UISplitViewController, SidebarViewControllerDelegate { let menuViewController = MenuViewController(driveFileManager: driveFileManager) if let detailNav = viewControllers.last as? UINavigationController { if name == KDriveResourcesStrings.Localizable.homeTitle { - detailNav.setViewControllers([homeViewController], animated: true) + detailNav.setViewControllers([homeViewController], animated: false) } else if name == KDriveResourcesStrings.Localizable.allPictures { - detailNav.setViewControllers([photoListViewController], animated: true) + detailNav.setViewControllers([photoListViewController], animated: false) } else if name == KDriveResourcesStrings.Localizable.menuTitle { - detailNav.setViewControllers([menuViewController], animated: true) + detailNav.setViewControllers([menuViewController], animated: false) } else { - detailNav.setViewControllers([destinationViewController], animated: true) + detailNav.setViewControllers([destinationViewController], animated: false) } } } From 30f8906170392ab84c5a372124219f219c9f7104 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 25 Oct 2024 11:37:06 +0200 Subject: [PATCH 12/14] fix: CornerRadius on cells --- Tuist/Package.resolved | 31 +++++++++++++- Tuist/Package.swift | 2 +- .../Files/RootMenuViewController.swift | 40 ++++++++++--------- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/Tuist/Package.resolved b/Tuist/Package.resolved index fccf2bb4c..63c87c07b 100644 --- a/Tuist/Package.resolved +++ b/Tuist/Package.resolved @@ -95,8 +95,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/Infomaniak/ios-core-ui", "state" : { - "revision" : "d83b9df4d8e7880fa8a55807549cac0fc4584ce6", - "version" : "13.1.0" + "revision" : "e0afbab522df72496b92042ee65c20f8d593a3f7", + "version" : "13.4.0" } }, { @@ -333,6 +333,15 @@ "version" : "1.3.2" } }, + { + "identity" : "swiftbackports", + "kind" : "remoteSourceControl", + "location" : "https://github.com/shaps80/SwiftBackports", + "state" : { + "revision" : "ddca6a237c1ba2291d5a3cc47ec8480ce6e9f805", + "version" : "1.0.3" + } + }, { "identity" : "swiftregex", "kind" : "remoteSourceControl", @@ -341,6 +350,24 @@ "revision" : "d8c4846dfbbe04aa8196ae5a5a3cdc6cd7f9f6bc", "version" : "1.0.0" } + }, + { + "identity" : "swiftui-introspect", + "kind" : "remoteSourceControl", + "location" : "https://github.com/siteline/SwiftUI-Introspect", + "state" : { + "revision" : "807f73ce09a9b9723f12385e592b4e0aaebd3336", + "version" : "1.3.0" + } + }, + { + "identity" : "swiftuibackports", + "kind" : "remoteSourceControl", + "location" : "https://github.com/shaps80/SwiftUIBackports", + "state" : { + "revision" : "556d42f391b74059a354b81b8c8e19cc7cb576f4", + "version" : "1.15.1" + } } ], "version" : 2 diff --git a/Tuist/Package.swift b/Tuist/Package.swift index d3877874a..6638a3aa5 100644 --- a/Tuist/Package.swift +++ b/Tuist/Package.swift @@ -20,7 +20,7 @@ let package = Package( .package(url: "https://github.com/apple/swift-algorithms", .upToNextMajor(from: "1.2.0")), .package(url: "https://github.com/Alamofire/Alamofire", .upToNextMajor(from: "5.2.2")), .package(url: "https://github.com/Infomaniak/ios-core", .upToNextMajor(from: "12.2.0")), - .package(url: "https://github.com/Infomaniak/ios-core-ui", .upToNextMajor(from: "13.1.0")), + .package(url: "https://github.com/Infomaniak/ios-core-ui", .upToNextMajor(from: "13.4.0")), .package(url: "https://github.com/Infomaniak/ios-login", .upToNextMajor(from: "7.0.1")), .package(url: "https://github.com/Infomaniak/ios-dependency-injection", .upToNextMajor(from: "2.0.0")), .package(url: "https://github.com/Infomaniak/swift-concurrency", .upToNextMajor(from: "0.0.4")), diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/RootMenuViewController.swift index 7615ac88d..c0fef302a 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/RootMenuViewController.swift @@ -30,9 +30,9 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi private var selectedIndexPath: IndexPath? private enum RootMenuSection { - case main - case one - case two + case first + case second + case third } private struct RootMenuItem: Equatable, Hashable { @@ -113,19 +113,23 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi ) } ?? [] -// var menuItems = (userRootFolders + SidebarViewController.baseItems).sorted { $0.priority > $1.priority } -// if !menuItems.isEmpty { -// menuItems[0].isFirst = true -// menuItems[menuItems.count - 1].isLast = true -// } - var snapshot = DataSourceSnapshot() - snapshot.appendSections([RootMenuSection.main]) - snapshot.appendSections([RootMenuSection.one]) - snapshot.appendSections([RootMenuSection.two]) - snapshot.appendItems(SidebarViewController.baseItems, toSection: RootMenuSection.main) - snapshot.appendItems(userRootFolders + SidebarViewController.secondSectionItems, toSection: RootMenuSection.one) - snapshot.appendItems(SidebarViewController.thirdSectionItems, toSection: RootMenuSection.two) + + let firstSectionItems = SidebarViewController.baseItems + let secondSectionItems = userRootFolders + SidebarViewController.secondSectionItems + let thirdSectionItems = SidebarViewController.thirdSectionItems + var sectionsItems = [firstSectionItems, secondSectionItems, thirdSectionItems] + var sections = [RootMenuSection.first, RootMenuSection.second, RootMenuSection.third] + + for i in 0 ... sectionsItems.count - 1 { + if !sections.isEmpty { + sectionsItems[i][0].isFirst = true + sectionsItems[i][sectionsItems[i].count - 1].isLast = true + + snapshot.appendSections([sections[i]]) + snapshot.appendItems(sectionsItems[i], toSection: sections[i]) + } + } return snapshot } @@ -351,17 +355,17 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) } ?? [] switch itemsSnapshot.sectionIdentifiers[indexPath.section] { - case .main: + case .first: let menuItems = SidebarViewController.baseItems let selectedItemName = menuItems[indexPath.row].name delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) - case .one: + case .second: let length = (SidebarViewController.baseItems).count let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController .secondSectionItems) let selectedItemName = menuItems[indexPath.row + length].name delegate?.didSelectItem(destinationViewModel: destinationViewModel, name: selectedItemName) - case .two: + case .third: let length = (SidebarViewController.baseItems + userRootFolders + SidebarViewController .secondSectionItems).count let menuItems = (SidebarViewController.baseItems + userRootFolders + SidebarViewController From 3da622c6a10a570a92c50f623b1b3efa72b6b0a9 Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 25 Oct 2024 13:03:24 +0200 Subject: [PATCH 13/14] fix: Remove useless code --- kDrive/AppRouter.swift | 43 +-- ...ller.swift => SidebarViewController.swift} | 261 ------------------ .../UI/Controller/MainTabViewController.swift | 94 +------ 3 files changed, 4 insertions(+), 394 deletions(-) rename kDrive/UI/Controller/Files/{RootMenuViewController.swift => SidebarViewController.swift} (61%) diff --git a/kDrive/AppRouter.swift b/kDrive/AppRouter.swift index b346748fe..7abf8bbb4 100644 --- a/kDrive/AppRouter.swift +++ b/kDrive/AppRouter.swift @@ -173,52 +173,15 @@ public struct AppRouter: AppNavigable { } Task { @MainActor in - guard restoration, let tabBarViewController else { + guard restoration else { return } guard let sceneUserInfo, let lastViewControllerString = sceneUserInfo[SceneRestorationKeys.lastViewController.rawValue] as? String, - let lastViewController = SceneRestorationScreens(rawValue: lastViewControllerString) else { + SceneRestorationScreens(rawValue: lastViewControllerString) != nil else { return } - -// let selectedIndex = tabBarViewController.selectedIndex -// let viewControllers = tabBarViewController.viewControllers -// guard let rootNavigationController = viewControllers?[safe: selectedIndex] as? UINavigationController else { -// Log.sceneDelegate("unable to access navigationController", level: .error) -// return -// } -// -// switch lastViewController { -// case .FileDetailViewController: -// await restoreFileDetailViewController( -// driveFileManager: driveFileManager, -// navigationController: rootNavigationController, -// sceneUserInfo: sceneUserInfo -// ) -// -// case .FileListViewController: -// await restoreFileListViewController( -// driveFileManager: driveFileManager, -// navigationController: rootNavigationController, -// sceneUserInfo: sceneUserInfo -// ) -// -// case .PreviewViewController: -// await restorePreviewViewController( -// driveFileManager: driveFileManager, -// navigationController: rootNavigationController, -// sceneUserInfo: sceneUserInfo -// ) -// -// case .StoreViewController: -// await restoreStoreViewController( -// driveFileManager: driveFileManager, -// navigationController: rootNavigationController, -// sceneUserInfo: sceneUserInfo -// ) -// } } } @@ -610,7 +573,7 @@ public struct AppRouter: AppNavigable { navController.popToRootViewController(animated: false) } - guard let rootMenuViewController = navController.topViewController as? RootMenuViewController else { + guard let rootMenuViewController = navController.topViewController as? SidebarViewController else { return } diff --git a/kDrive/UI/Controller/Files/RootMenuViewController.swift b/kDrive/UI/Controller/Files/SidebarViewController.swift similarity index 61% rename from kDrive/UI/Controller/Files/RootMenuViewController.swift rename to kDrive/UI/Controller/Files/SidebarViewController.swift index c0fef302a..9472135d5 100644 --- a/kDrive/UI/Controller/Files/RootMenuViewController.swift +++ b/kDrive/UI/Controller/Files/SidebarViewController.swift @@ -415,264 +415,3 @@ class SidebarViewController: CustomLargeTitleCollectionViewController, SelectSwi protocol SidebarViewControllerDelegate: AnyObject { func didSelectItem(destinationViewModel: FileListViewModel, name: String) } - -class RootMenuViewController: CustomLargeTitleCollectionViewController, SelectSwitchDriveDelegate { - private typealias MenuDataSource = UICollectionViewDiffableDataSource - private typealias DataSourceSnapshot = NSDiffableDataSourceSnapshot - - private enum RootMenuSection { - case main - } - - private struct RootMenuItem: Equatable, Hashable { - var id: Int { - return destinationFile.id - } - - let name: String - let image: UIImage - let destinationFile: File - var isFirst = false - var isLast = false - - func hash(into hasher: inout Hasher) { - hasher.combine(id) - hasher.combine(isFirst) - hasher.combine(isLast) - } - } - - private static let baseItems: [RootMenuItem] = [RootMenuItem(name: KDriveResourcesStrings.Localizable.favoritesTitle, - image: KDriveResourcesAsset.favorite.image, - destinationFile: DriveFileManager.favoriteRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.lastEditsTitle, - image: KDriveResourcesAsset.clock.image, - destinationFile: DriveFileManager.lastModificationsRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.sharedWithMeTitle, - image: KDriveResourcesAsset.folderSelect2.image, - destinationFile: DriveFileManager.sharedWithMeRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.mySharesTitle, - image: KDriveResourcesAsset.folderSelect.image, - destinationFile: DriveFileManager.mySharedRootFile), - RootMenuItem(name: KDriveResourcesStrings.Localizable.offlineFileTitle, - image: KDriveResourcesAsset.availableOffline.image, - destinationFile: DriveFileManager.offlineRoot), - RootMenuItem(name: KDriveResourcesStrings.Localizable.trashTitle, - image: KDriveResourcesAsset.delete.image, - destinationFile: DriveFileManager.trashRootFile)] - - @LazyInjectService private var accountManager: AccountManageable - - let driveFileManager: DriveFileManager - private var rootChildrenObservationToken: NotificationToken? - private var rootViewChildren: [File]? - private var dataSource: MenuDataSource? - private let refreshControl = UIRefreshControl() - - private var itemsSnapshot: DataSourceSnapshot { - let userRootFolders = rootViewChildren?.compactMap { - RootMenuItem(name: $0.formattedLocalizedName(drive: driveFileManager.drive), image: $0.icon, destinationFile: $0) - } ?? [] - - var menuItems = userRootFolders + RootMenuViewController.baseItems - if !menuItems.isEmpty { - menuItems[0].isFirst = true - menuItems[menuItems.count - 1].isLast = true - } - - var snapshot = DataSourceSnapshot() - snapshot.appendSections([RootMenuSection.main]) - snapshot.appendItems(menuItems) - return snapshot - } - - init(driveFileManager: DriveFileManager) { - self.driveFileManager = driveFileManager - super.init(collectionViewLayout: RootMenuViewController.createListLayout()) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - navigationItem.title = driveFileManager.drive.name - navigationItem.rightBarButtonItem = FileListBarButton(type: .search, target: self, action: #selector(presentSearch)) - - collectionView.backgroundColor = KDriveResourcesAsset.backgroundColor.color - collectionView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: UIConstants.listPaddingBottom, right: 0) - collectionView.refreshControl = refreshControl - - collectionView.register(RootMenuCell.self, forCellWithReuseIdentifier: RootMenuCell.identifier) - collectionView.register(supplementaryView: HomeLargeTitleHeaderView.self, forSupplementaryViewOfKind: .header) - collectionView.register(supplementaryView: RootMenuHeaderView.self, forSupplementaryViewOfKind: RootMenuHeaderView.kind) - - refreshControl.addTarget(self, action: #selector(forceRefresh), for: .valueChanged) - - configureDataSource() - - let rootFileUid = File.uid(driveId: driveFileManager.drive.id, fileId: DriveFileManager.constants.rootID) - guard let root = driveFileManager.database.fetchObject(ofType: File.self, forPrimaryKey: rootFileUid) else { - return - } - - let rootChildren = root.children.filter(NSPredicate( - format: "rawVisibility IN %@", - [FileVisibility.isPrivateSpace.rawValue, FileVisibility.isTeamSpace.rawValue] - )) - rootChildrenObservationToken = rootChildren.observe { [weak self] changes in - guard let self else { return } - switch changes { - case .initial(let children): - rootViewChildren = Array(AnyRealmCollection(children).filesSorted(by: .nameAZ)) - dataSource?.apply(itemsSnapshot, animatingDifferences: false) - case .update(let children, _, _, _): - rootViewChildren = Array(AnyRealmCollection(children).filesSorted(by: .nameAZ)) - dataSource?.apply(itemsSnapshot, animatingDifferences: true) - case .error: - break - } - } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - (tabBarController as? PlusButtonObserver)?.updateCenterButton() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - saveSceneState() - } - - @objc func presentSearch() { - let viewModel = SearchFilesViewModel(driveFileManager: driveFileManager) - let searchViewController = SearchViewController.instantiateInNavigationController(viewModel: viewModel) - present(searchViewController, animated: true) - } - - @objc func forceRefresh() { - Task { - try? await driveFileManager.initRoot() - refreshControl.endRefreshing() - } - } - - func configureDataSource() { - dataSource = MenuDataSource(collectionView: collectionView) { collectionView, indexPath, menuItem -> RootMenuCell? in - guard let rootMenuCell = collectionView.dequeueReusableCell( - withReuseIdentifier: RootMenuCell.identifier, - for: indexPath - ) as? RootMenuCell else { - fatalError("Failed to dequeue cell") - } - - rootMenuCell.configure(title: menuItem.name, icon: menuItem.image) - rootMenuCell.initWithPositionAndShadow(isFirst: menuItem.isFirst, isLast: menuItem.isLast) - return rootMenuCell - } - - dataSource?.supplementaryViewProvider = { [weak self] collectionView, kind, indexPath in - guard let self else { return UICollectionReusableView() } - - switch kind { - case UICollectionView.elementKindSectionHeader: - let homeLargeTitleHeaderView = collectionView.dequeueReusableSupplementaryView( - ofKind: kind, - view: HomeLargeTitleHeaderView.self, - for: indexPath - ) - - homeLargeTitleHeaderView.configureForDriveSwitch( - accountManager: accountManager, - driveFileManager: driveFileManager, - presenter: self - ) - - headerViewHeight = homeLargeTitleHeaderView.frame.height - return homeLargeTitleHeaderView - case RootMenuHeaderView.kind.rawValue: - let headerView = collectionView.dequeueReusableSupplementaryView( - ofKind: kind, - view: RootMenuHeaderView.self, - for: indexPath - ) - - headerView.configureInCollectionView(collectionView, driveFileManager: driveFileManager, presenter: self) - return headerView - default: - fatalError("Unhandled kind \(kind)") - } - } - - dataSource?.apply(itemsSnapshot, animatingDifferences: false) - } - - static func createListLayout() -> UICollectionViewLayout { - let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(60)) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - - let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), - heightDimension: .estimated(60)) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, - subitems: [item]) - - let headerSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(0)) - - let sectionHeaderItem = NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: headerSize, - elementKind: RootMenuHeaderView.kind.rawValue, - alignment: .top - ) - sectionHeaderItem.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12) - sectionHeaderItem.pinToVisibleBounds = true - - let section = NSCollectionLayoutSection(group: group) - section.boundarySupplementaryItems = [sectionHeaderItem] - - let configuration = UICollectionViewCompositionalLayoutConfiguration() - configuration.boundarySupplementaryItems = [generateHeaderItem()] - let layout = UICollectionViewCompositionalLayout(section: section, configuration: configuration) - return layout - } - - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let selectedRootFile = dataSource?.itemIdentifier(for: indexPath)?.destinationFile else { return } - - let destinationViewModel: FileListViewModel - switch selectedRootFile.id { - case DriveFileManager.favoriteRootFile.id: - destinationViewModel = FavoritesViewModel(driveFileManager: driveFileManager) - case DriveFileManager.lastModificationsRootFile.id: - destinationViewModel = LastModificationsViewModel(driveFileManager: driveFileManager) - case DriveFileManager.sharedWithMeRootFile.id: - let sharedWithMeDriveFileManager = driveFileManager.instanceWith(context: .sharedWithMe) - destinationViewModel = SharedWithMeViewModel(driveFileManager: sharedWithMeDriveFileManager) - case DriveFileManager.offlineRoot.id: - destinationViewModel = OfflineFilesViewModel(driveFileManager: driveFileManager) - case DriveFileManager.trashRootFile.id: - destinationViewModel = TrashListViewModel(driveFileManager: driveFileManager) - case DriveFileManager.mySharedRootFile.id: - destinationViewModel = MySharesViewModel(driveFileManager: driveFileManager) - default: - destinationViewModel = ConcreteFileListViewModel( - driveFileManager: driveFileManager, - currentDirectory: selectedRootFile - ) - } - - let destinationViewController = FileListViewController(viewModel: destinationViewModel) - navigationController?.pushViewController(destinationViewController, animated: true) - } - - // MARK: - State restoration - - var currentSceneMetadata: [AnyHashable: Any] { - [:] - } -} diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 232f19128..1006d1e66 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -32,98 +32,6 @@ public enum MainTabBarIndex: Int { case profile = 4 } -// class RootViewController: UISplitViewController { -// @LazyInjectService var router: AppNavigable -// let driveFileManager: DriveFileManager -// -// init(driveFileManager: DriveFileManager) { -// self.driveFileManager = driveFileManager -// var rootViewControllers = [UIViewController]() -// rootViewControllers.append(Self.initRootMenuViewController(driveFileManager: driveFileManager)) -//// rootViewControllers.append(Self.initHomeViewController(driveFileManager: driveFileManager)) -//// rootViewControllers.append(Self.initFakeViewController()) -//// rootViewControllers.append(Self.initPhotoListViewController(with: PhotoListViewModel(driveFileManager: -/// driveFileManager))) -//// rootViewControllers.append(Self.initMenuViewController(driveFileManager: driveFileManager)) -// super.init(style: .doubleColumn) -// preferredDisplayMode = .oneBesideSecondary -// viewControllers = rootViewControllers -// } -// -// @available(*, unavailable) -// required init?(coder: NSCoder) { -// fatalError("init(coder:) has not been implemented") -// } -// -// private static func generateProfileTabImages(image: UIImage) -> (UIImage, UIImage) { -// let iconSize = 28.0 -// -// let selectedImage = image -// .resize(size: CGSize(width: iconSize + 2, height: iconSize + 2)) -// .maskImageWithRoundedRect( -// cornerRadius: CGFloat((iconSize + 2) / 2), -// borderWidth: 2, -// borderColor: KDriveResourcesAsset.infomaniakColor.color -// ) -// .withRenderingMode(.alwaysOriginal) -// -// let image = image -// .resize(size: CGSize(width: iconSize, height: iconSize)) -// .maskImageWithRoundedRect(cornerRadius: CGFloat(iconSize / 2), borderWidth: 0, borderColor: nil) -// .withRenderingMode(.alwaysOriginal) -// return (image, selectedImage) -// } -// -// private static func initHomeViewController(driveFileManager: DriveFileManager) -> UIViewController { -// let homeViewController = HomeViewController(driveFileManager: driveFileManager) -// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: homeViewController) -// navigationViewController.navigationBar.prefersLargeTitles = true -// navigationViewController.restorationIdentifier = String(describing: HomeViewController.self) -// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.homeTitle -// navigationViewController.tabBarItem.image = KDriveResourcesAsset.house.image -// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.houseFill.image -// return navigationViewController -// } -// -// private static func initRootMenuViewController(driveFileManager: DriveFileManager) -> UIViewController { -// let homeViewController = SidebarViewController() -// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: homeViewController) -// navigationViewController.navigationBar.prefersLargeTitles = true -// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.homeTitle -// navigationViewController.tabBarItem.image = KDriveResourcesAsset.folder.image -// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.folderFilledTab.image -// return navigationViewController -// } -// -// private static func initMenuViewController(driveFileManager: DriveFileManager) -> UIViewController { -// let menuViewController = MenuViewController(driveFileManager: driveFileManager) -// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: menuViewController) -// let (placeholder, placeholderSelected) = generateProfileTabImages(image: KDriveResourcesAsset.placeholderAvatar.image) -// navigationViewController.restorationIdentifier = String(describing: MenuViewController.self) -// navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.menuTitle -// navigationViewController.tabBarItem.image = placeholder -// navigationViewController.tabBarItem.selectedImage = placeholderSelected -// return navigationViewController -// } -// -// private static func initFakeViewController() -> UIViewController { -// let fakeViewController = UIViewController() -// fakeViewController.tabBarItem.isEnabled = false -// return fakeViewController -// } -// -// private static func initPhotoListViewController(with viewModel: FileListViewModel) -> UIViewController { -// let photoListViewController = PhotoListViewController(viewModel: viewModel) -// let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: photoListViewController) -// navigationViewController.restorationIdentifier = String(describing: PhotoListViewController.self) -// navigationViewController.navigationBar.prefersLargeTitles = true -// navigationViewController.tabBarItem.accessibilityLabel = viewModel.title -// navigationViewController.tabBarItem.image = KDriveResourcesAsset.mediaInline.image -// navigationViewController.tabBarItem.selectedImage = KDriveResourcesAsset.mediaBold.image -// return navigationViewController -// } -// } - class RootViewController: UISplitViewController, SidebarViewControllerDelegate { let driveFileManager: DriveFileManager @@ -293,7 +201,7 @@ class MainTabViewController: UITabBarController, Restorable, PlusButtonObserver } private static func initRootMenuViewController(driveFileManager: DriveFileManager) -> UIViewController { - let homeViewController = RootMenuViewController(driveFileManager: driveFileManager) + let homeViewController = SidebarViewController(driveFileManager: driveFileManager) let navigationViewController = TitleSizeAdjustingNavigationController(rootViewController: homeViewController) navigationViewController.navigationBar.prefersLargeTitles = true navigationViewController.tabBarItem.accessibilityLabel = KDriveResourcesStrings.Localizable.homeTitle From 74662545c2d7b820736954e068c3c4c4a47ae6df Mon Sep 17 00:00:00 2001 From: Baptiste Griva Date: Fri, 25 Oct 2024 13:11:30 +0200 Subject: [PATCH 14/14] fix: Remove duplicated lines --- .../UI/Controller/MainTabViewController.swift | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/kDrive/UI/Controller/MainTabViewController.swift b/kDrive/UI/Controller/MainTabViewController.swift index 1006d1e66..9298dbeaf 100644 --- a/kDrive/UI/Controller/MainTabViewController.swift +++ b/kDrive/UI/Controller/MainTabViewController.swift @@ -436,34 +436,3 @@ extension MainTabViewController: UpdateAccountDelegate { } } } - -// MARK: - UIDocumentPickerDelegate - -extension MainTabViewController: UIDocumentPickerDelegate { - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - if let documentPicker = controller as? DriveImportDocumentPickerViewController { - for url in urls { - let targetURL = fileImportHelper.generateImportURL(for: url.uti) - - do { - if FileManager.default.fileExists(atPath: targetURL.path) { - try FileManager.default.removeItem(at: targetURL) - } - - try FileManager.default.moveItem(at: url, to: targetURL) - uploadQueue.saveToRealm( - UploadFile( - parentDirectoryId: documentPicker.importDriveDirectory.id, - userId: accountManager.currentUserId, - driveId: documentPicker.importDriveDirectory.driveId, - url: targetURL, - name: url.lastPathComponent - ) - ) - } catch { - UIConstants.showSnackBarIfNeeded(error: DriveError.unknownError) - } - } - } - } -}