Skip to content

feat: New view iPadOS #1468

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 63 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
71e495c
feat: V1 of the new view
BaptGrv Oct 3, 2024
a3b3049
feat: Work in progress on navBar
BaptGrv Oct 4, 2024
6e50bf8
feat: NavBar is now sorted
BaptGrv Oct 4, 2024
d730f16
feat: Add menu to navBar
BaptGrv Oct 4, 2024
bf87b86
feat: Add iPhone view when compact
BaptGrv Oct 22, 2024
8e14366
feat: Button add file
BaptGrv Oct 24, 2024
a6160b2
refactor: Move photoPickerDelegate to openMediaHelper
BaptGrv Oct 24, 2024
74c4837
refactor: Move MainTabView extension to OpenMediaHelper
BaptGrv Oct 24, 2024
0565257
feat: Sort sideBar items into sections
BaptGrv Oct 24, 2024
db8a01f
fix: Solve problem of clicking twice on the same cell
BaptGrv Oct 24, 2024
4ceb089
feat: Add spacing in imageButton
BaptGrv Oct 25, 2024
61675b8
fix: CornerRadius on cells
BaptGrv Oct 25, 2024
f4504ed
fix: Remove useless code
BaptGrv Oct 25, 2024
e8db700
chore: Revert "fix: Remove useless code"
BaptGrv Feb 18, 2025
5a944b9
fix: Remove useless code
BaptGrv Oct 25, 2024
0f21f1e
fix: Remove duplicated lines
BaptGrv Oct 25, 2024
21e7b91
fix: Resolve issues after cherry-pick
BaptGrv Feb 18, 2025
9995a45
feat: Change uploadQueue to uploadDatasource
BaptGrv Mar 26, 2025
e6dfb14
feat: SizeClass implementation
BaptGrv Mar 27, 2025
73dbc62
feat: Use of traitCollection to adapt snapshot to the size of the screen
BaptGrv Apr 1, 2025
75aec50
feat: Adjust the view to the size of the rootViewController
BaptGrv Apr 9, 2025
64d19f6
fix: Remove the button while in compactView
BaptGrv Apr 9, 2025
4e1ee53
feat: Add app state restoration
BaptGrv Apr 28, 2025
ea5ff0c
fix: Now can go twice in the same directory while in compact mode
BaptGrv Apr 28, 2025
20a2aa6
fix: UserRootFolders are now showing properly
BaptGrv Apr 28, 2025
4e95b88
fix: Rename var with same name as the field
BaptGrv Apr 30, 2025
b077db0
fix: Add a bool var instead of the if logic
BaptGrv Apr 30, 2025
0a52431
fix: Change type to conform protocol
BaptGrv Apr 30, 2025
8a0958d
fix: Adapt test to validate build and CI
BaptGrv Apr 30, 2025
7f8fbf0
fix: The menu view appears at launch
BaptGrv May 1, 2025
976db5d
fix: Title is no more showing twice in regularView
BaptGrv May 1, 2025
8d32989
fix: Offline disclaimer shows only above first section
BaptGrv May 1, 2025
b4f2b0b
fix: Title alignment and button size
BaptGrv May 2, 2025
54741a1
feat: AppRestoration working both on iOS ans iPadOS
BaptGrv May 8, 2025
3051fe9
fix: Remove force unwrap
BaptGrv May 8, 2025
416f256
fix: Import photos now works on both iPadOS and iOS
BaptGrv May 9, 2025
d6e77d6
fix: NavigationBar reappears after leaving an image preview
BaptGrv May 12, 2025
a999677
feat: Rebase is building
BaptGrv May 12, 2025
b84c611
fix: Not showing button in selectMode
BaptGrv May 12, 2025
62a9a51
fix: Align the title with sections
BaptGrv May 13, 2025
0dc0abf
fix: SwiftLint
BaptGrv May 13, 2025
6f3051c
fix: Show offline and download sections only once on top
BaptGrv May 13, 2025
c05ead8
fix(CustomLargeTitleCollectionViewController): Failure to update navi…
adrien-coye May 14, 2025
c7875ef
refactor: Sharing the isCompactView logic
adrien-coye May 14, 2025
5d5dfda
fix: Add guard to reduce indentation and use UIConstants
BaptGrv May 14, 2025
6dba767
fix: Can now present the right folder after a download
BaptGrv May 14, 2025
541cbda
fix: Ensure we get correct color for back button
PhilippeWeidmann May 19, 2025
1b08227
fix: Wrong var name
BaptGrv May 19, 2025
431a487
fix: SwiftLint
BaptGrv May 19, 2025
4cdacb1
refactor: Use UIButton.Configuration + update constraints
PhilippeWeidmann May 19, 2025
2c24738
fix: Keep hiding navbar in menu
PhilippeWeidmann May 19, 2025
d94695b
fix: More robust sidebar navigation
PhilippeWeidmann May 19, 2025
1a28a2b
fix: Present menu modally
PhilippeWeidmann May 20, 2025
2fbf646
refactor: Separate snapshot code
PhilippeWeidmann May 20, 2025
7a842fe
fix: Use new button APIs
PhilippeWeidmann May 20, 2025
cc5b24d
fix: Correctly set navigationBar tint
PhilippeWeidmann May 20, 2025
d1f142a
fix: Add missing var photoPickerDelegate
BaptGrv May 23, 2025
c4268be
fix: Correct RootMenuDestination hash value
PhilippeWeidmann May 27, 2025
8ab153b
fix: Hide floating panel before presenting MenuViewController
PhilippeWeidmann May 27, 2025
90de84f
fix: Correct plus button size
PhilippeWeidmann May 27, 2025
c06a6c1
fix(PreviewViewController): Use compositional layout for correct sizing
PhilippeWeidmann May 27, 2025
42fa186
feat: Use popover for plus button
PhilippeWeidmann May 28, 2025
426ad2a
refactor: Rename to RootSplitViewController
PhilippeWeidmann May 28, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Tuist/ProjectDescriptionHelpers/ExtensionTarget.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public extension Target {
"kDrive/UI/Controller/Files/Search/**",
"kDrive/UI/Controller/Files/MultipleSelectionViewController.swift",
"kDrive/UI/Controller/Files/File List/**",
"kDrive/UI/Controller/Files/RootMenuViewController.swift",
"kDrive/UI/Controller/Files/SidebarViewController.swift",
"kDrive/UI/Controller/Files/FloatingPanelSortOptionTableViewController.swift",
"kDrive/UI/Controller/Floating Panel Information/**",
"kDrive/UI/Controller/Favorite/FavoritesViewModel.swift",
Expand Down
62 changes: 42 additions & 20 deletions kDrive/AppRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ public struct AppRouter: AppNavigable {
return topViewController
}

@MainActor public var rootViewController: UIViewController? {
guard let rootViewController = window?.rootViewController as? UIViewController else {
return nil
}

return rootViewController
}

// MARK: RouterRootNavigable

@MainActor public func setRootViewController(_ viewController: UIViewController,
Expand Down Expand Up @@ -165,6 +173,23 @@ public struct AppRouter: AppNavigable {
}
}

@MainActor private func getControllerForRestoration(tabBarViewController: UISplitViewController?) -> UIViewController? {
guard let rootViewController = window?.rootViewController else { return nil }
let rootHorizontalSizeClass = rootViewController.traitCollection.horizontalSizeClass
if rootHorizontalSizeClass == .compact {
guard let mainTabViewController = tabBarViewController?.viewControllers.first as? UITabBarController else {
Log.sceneDelegate("unable to access tabBarViewController", level: .error)
return nil
}

let selectedIndex = mainTabViewController.selectedIndex
let viewControllers = mainTabViewController.viewControllers
return viewControllers?[safe: selectedIndex]
} else {
return tabBarViewController?.viewControllers.last
}
}

/// Entry point for scene restoration
@MainActor func restoreMainUIStackIfPossible(driveFileManager: DriveFileManager, restoration: Bool) {
let shouldRestoreApplicationState = appRestorationService.shouldRestoreApplicationState
Expand All @@ -184,7 +209,7 @@ public struct AppRouter: AppNavigable {
}

Task { @MainActor in
guard restoration, let tabBarViewController else {
guard restoration else {
return
}

Expand All @@ -193,16 +218,17 @@ public struct AppRouter: AppNavigable {
let lastViewController = SceneRestorationScreens(rawValue: lastViewControllerString) else {
return
}

guard let previousDriveId = sceneUserInfo[SceneRestorationValues.driveId.rawValue] as? Int,
previousDriveId == driveFileManager.drive.id else {
previousDriveId == driveFileManager.driveId else {
Log.sceneDelegate("driveId do not match for restore :\(sceneUserInfo)", level: .error)
return
}

let selectedIndex = tabBarViewController.selectedIndex
let viewControllers = tabBarViewController.viewControllers
guard let rootNavigationController = viewControllers?[safe: selectedIndex] as? UINavigationController else {
guard let viewController = getControllerForRestoration(tabBarViewController: tabBarViewController) else {
Log.sceneDelegate("unable to access viewControllers", level: .error)
return
}
guard let rootNavigationController = viewController as? UINavigationController else {
Log.sceneDelegate("unable to access navigationController", level: .error)
return
}
Expand Down Expand Up @@ -363,19 +389,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? RootSplitViewController)?.driveFileManager.drive.objectId
guard currentDriveObjectId != driveFileManager.drive.objectId else {
return nil
}

let tabBarViewController = MainTabViewController(driveFileManager: driveFileManager,
selectedIndex: selectedIndex)
let tabBarViewController = RootSplitViewController(driveFileManager: driveFileManager, selectedIndex: selectedIndex)

window.rootViewController = tabBarViewController
window.makeKeyAndVisible()
Expand Down Expand Up @@ -641,8 +666,8 @@ public struct AppRouter: AppNavigable {
}

let account = try await accountManager.updateUser(for: currentAccount, registerToken: true)
let rootViewController = window?.rootViewController as? UpdateAccountDelegate
rootViewController?.didUpdateCurrentAccountInformations(account)
let viewController = window?.rootViewController as? UpdateAccountDelegate
viewController?.didUpdateCurrentAccountInformations(account)

if let oldDriveId,
let newDrive = driveInfosManager.getDrive(primaryKey: oldDriveId),
Expand Down Expand Up @@ -795,14 +820,11 @@ public struct AppRouter: AppNavigable {
}

@MainActor public func present(file: File, driveFileManager: DriveFileManager, office: Bool) {
guard let rootViewController = window?.rootViewController as? MainTabViewController else {
return
}

rootViewController.dismiss(animated: false) {
rootViewController.selectedIndex = MainTabBarIndex.files.rawValue
guard let rootViewController = window?.rootViewController as? UISplitViewController else { return }
guard let viewController = getControllerForRestoration(tabBarViewController: rootViewController) else { return }

guard let navController = rootViewController.selectedViewController as? UINavigationController else {
viewController.dismiss(animated: false) {
guard let navController = viewController as? UINavigationController else {
return
}

Expand All @@ -816,7 +838,7 @@ public struct AppRouter: AppNavigable {
navController.popToRootViewController(animated: false)
}

guard let rootMenuViewController = navController.topViewController as? RootMenuViewController else {
guard let rootMenuViewController = navController.topViewController else {
return
}

Expand Down
58 changes: 49 additions & 9 deletions kDrive/OpenMediaHelper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,36 @@
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
class OpenMediaHelper: NSObject {
@LazyInjectService var accountManager: AccountManageable
@LazyInjectService var uploadDatasource: UploadServiceDataSourceable
@LazyInjectService var fileImportHelper: FileImportHelper

let currentDirectory: File?
let driveFileManager: DriveFileManager
let photoPickerDelegate = PhotoPickerDelegate()

enum Media {
case library, camera
}

func openMedia(_ mainTabViewController: MainTabViewController, _ media: Media) {
mainTabViewController.photoPickerDelegate.driveFileManager = driveFileManager
mainTabViewController.photoPickerDelegate.currentDirectory = currentDirectory?.freezeIfNeeded()
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()

if media == .library {
// Check permission
Expand All @@ -46,7 +59,7 @@ struct OpenMediaHelper {
configuration.selectionLimit = 0

let picker = PHPickerViewController(configuration: configuration)
picker.delegate = mainTabViewController.photoPickerDelegate
picker.delegate = self.photoPickerDelegate
mainTabViewController.present(picker, animated: true)
}
} else {
Expand Down Expand Up @@ -85,14 +98,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
Expand All @@ -109,3 +122,30 @@ struct OpenMediaHelper {
mainTabViewController.present(navigationViewController, animated: true)
}
}

extension OpenMediaHelper: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let documentPicker = controller as? DriveImportDocumentPickerViewController else { return }
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)
let uploadFile = UploadFile(
parentDirectoryId: documentPicker.importDriveDirectory.id,
userId: accountManager.currentUserId,
driveId: documentPicker.importDriveDirectory.driveId,
url: targetURL,
name: url.lastPathComponent
)
uploadDatasource.saveToRealm(uploadFile, itemIdentifier: nil, addToQueue: true)
} catch {
UIConstants.showSnackBarIfNeeded(error: DriveError.unknownError)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ import UIKit
import Vision
import VisionKit

class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPanelControllerDelegate {
public class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPanelControllerDelegate {
@LazyInjectService private var matomo: MatomoUtils

let currentDirectory: File
let driveFileManager: DriveFileManager

let presentedFromPlusButton: Bool
let presentedAboveFileList: Bool
let mediaHelper: OpenMediaHelper

private struct PlusButtonMenuAction: Equatable {
let name: String
Expand Down Expand Up @@ -120,6 +121,7 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
currentDirectory = folder
self.presentedFromPlusButton = presentedFromPlusButton
self.presentedAboveFileList = presentedAboveFileList
mediaHelper = OpenMediaHelper(currentDirectory: folder, driveFileManager: driveFileManager)
super.init(nibName: nil, bundle: nil)
}

Expand All @@ -128,7 +130,7 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
fatalError("init(coder:) has not been implemented")
}

override func viewDidLoad() {
override public func viewDidLoad() {
super.viewDidLoad()
tableView.separatorColor = .clear
tableView.alwaysBounceVertical = false
Expand All @@ -149,26 +151,26 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
#endif
}

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
override public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 && indexPath.section == 0 {
return UIConstants.FloatingPanel.headerHeight
} else {
return UITableView.automaticDimension
}
}

override func numberOfSections(in tableView: UITableView) -> Int {
override public func numberOfSections(in tableView: UITableView) -> Int {
return content.count
}

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
override public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 0 {
return 1
}
return content[section].count
}

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
override public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(type: FloatingPanelTableViewCell.self, for: indexPath)
if indexPath.section == 0 {
cell.titleLabel.text = currentDirectory.formattedLocalizedName(drive: driveFileManager.drive)
Expand Down Expand Up @@ -199,13 +201,13 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
return cell
}

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
override public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.section == 0 {
return
}
dismiss(animated: true)

guard let mainTabViewController = parent?.presentingViewController as? MainTabViewController else {
guard let mainTabViewController = presentingViewController else {
return
}

Expand Down Expand Up @@ -237,30 +239,29 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
return true
}

func floatingPanel(_ fpc: FloatingPanelController, shouldRemoveAt location: CGPoint, with velocity: CGVector) -> Bool {
public func floatingPanel(_ fpc: FloatingPanelController, shouldRemoveAt location: CGPoint, with velocity: CGVector) -> Bool {
// Remove the panel when it's pushed one third down
return location.y > fpc.backdropView.frame.height * 1 / 3
}

// MARK: Actions

private func importAction(_ mainTabViewController: MainTabViewController) {
private func importAction(_ mainTabViewController: UIViewController) {
let documentPicker = DriveImportDocumentPickerViewController(forOpeningContentTypes: [UTType.data], asCopy: true)
documentPicker.importDrive = driveFileManager.drive
documentPicker.importDriveDirectory = currentDirectory.freezeIfNeeded()
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
)
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
Expand All @@ -277,12 +278,11 @@ class PlusButtonFloatingPanelViewController: UITableViewController, FloatingPane
mainTabViewController.present(navigationViewController, animated: true)
}

private func mediaAction(_ mainTabViewController: MainTabViewController, action: PlusButtonMenuAction) {
let openMediaHelper = OpenMediaHelper(currentDirectory: currentDirectory, driveFileManager: driveFileManager)
openMediaHelper.openMedia(mainTabViewController, action == .importMediaAction ? .library : .camera)
private func mediaAction(_ mainTabViewController: UIViewController, action: PlusButtonMenuAction) {
mediaHelper.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)
Expand Down
Loading
Loading