Skip to content
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

feat: External links list files #1307

Merged
merged 9 commits into from
Oct 23, 2024
34 changes: 27 additions & 7 deletions kDrive/AppRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ public struct AppRouter: AppNavigable {
// MARK: RouterFileNavigable

@MainActor public func presentPublicShare(
rootFolder: File,
frozenRootFolder: File,
publicShareProxy: PublicShareProxy,
driveFileManager: DriveFileManager,
apiFetcher: PublicShareApiFetcher
Expand All @@ -597,12 +597,32 @@ public struct AppRouter: AppNavigable {
fatalError("TODO: lazy load a rootViewController")
}

let filePresenter = FilePresenter(viewController: rootViewController)
filePresenter.presentPublicShareDirectory(publicShareProxy: publicShareProxy,
rootFolder: rootFolder,
rootViewController: rootViewController,
driveFileManager: driveFileManager,
apiFetcher: apiFetcher)
guard let rootViewController = window.rootViewController as? MainTabViewController else {
fatalError("Root is not a MainTabViewController")
PhilippeWeidmann marked this conversation as resolved.
Show resolved Hide resolved
return
}

// TODO: Fix access right
guard !frozenRootFolder.isDisabled else {
fatalError("isDisabled")
return
}

rootViewController.dismiss(animated: false) {
rootViewController.selectedIndex = MainTabBarIndex.files.rawValue

guard let navigationController = rootViewController.selectedViewController as? UINavigationController else {
return
}

let viewModel = PublicShareViewModel(publicShareProxy: publicShareProxy,
sortType: .nameAZ,
driveFileManager: driveFileManager,
currentDirectory: frozenRootFolder,
apiFetcher: apiFetcher)
let viewController = FileListViewController(viewModel: viewModel)
navigationController.pushViewController(viewController, animated: true)
}
}

@MainActor public func present(file: File, driveFileManager: DriveFileManager) {
Expand Down
31 changes: 6 additions & 25 deletions kDrive/UI/Controller/Files/FilePresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,31 +132,6 @@ final class FilePresenter {
}
}

public func presentPublicShareDirectory(
publicShareProxy: PublicShareProxy,
rootFolder: File,
rootViewController: UIViewController,
driveFileManager: DriveFileManager,
apiFetcher: PublicShareApiFetcher
) {
let viewModel = PublicShareViewModel(publicShareProxy: publicShareProxy,
sortType: .nameAZ,
driveFileManager: driveFileManager,
currentDirectory: rootFolder,
apiFetcher: apiFetcher)

// TODO: Fix access right
// guard !rootFolder.isDisabled else {
// return
// }

let nextVC = FileListViewController(viewModel: viewModel)
print("nextVC:\(nextVC) viewModel:\(viewModel) navigationController:\(navigationController)")
// navigationController?.pushViewController(nextVC, animated: true)

rootViewController.present(nextVC, animated: true)
}

public func presentDirectory(
for file: File,
driveFileManager: DriveFileManager,
Expand All @@ -170,6 +145,12 @@ final class FilePresenter {
let viewModel: FileListViewModel
if driveFileManager.drive.sharedWithMe {
viewModel = SharedWithMeViewModel(driveFileManager: driveFileManager, currentDirectory: file)
} else if let publicShareProxy = driveFileManager.publicShareProxy {
viewModel = PublicShareViewModel(publicShareProxy: publicShareProxy,
sortType: .nameAZ,
driveFileManager: driveFileManager,
currentDirectory: file,
apiFetcher: PublicShareApiFetcher())
} else if file.isTrashed || file.deletedAt != nil {
viewModel = TrashListViewModel(driveFileManager: driveFileManager, currentDirectory: file)
} else {
Expand Down
10 changes: 7 additions & 3 deletions kDrive/UI/Controller/Files/Preview/PreviewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -609,8 +609,8 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
previewPageViewController.driveFileManager = driveFileManager
previewPageViewController.normalFolderHierarchy = normalFolderHierarchy
previewPageViewController.presentationOrigin = presentationOrigin
// currentIndex should be set at the end of the function as the it takes time and the viewDidLoad() is called before the
// function returns
// currentIndex should be set at the end of the function as the it takes time
// and the viewDidLoad() is called before the function returns
// this should be fixed in the future with the refactor of the init
previewPageViewController.currentIndex = IndexPath(row: index, section: 0)
return previewPageViewController
Expand Down Expand Up @@ -650,7 +650,11 @@ extension PreviewViewController: UICollectionViewDataSource {
) {
let file = previewFiles[indexPath.row]
if let cell = cell as? DownloadingPreviewCollectionViewCell {
cell.progressiveLoadingForFile(file)
if let publicShareProxy = driveFileManager.publicShareProxy {
cell.progressiveLoadingForPublicShareFile(file, publicShareProxy: publicShareProxy)
} else {
cell.progressiveLoadingForFile(file)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
Infomaniak kDrive - iOS App
Copyright (C) 2021 Infomaniak Network SA
Copyright (C) 2024 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -28,19 +28,18 @@ final class PublicShareViewModel: InMemoryFileListViewModel {

required init(driveFileManager: DriveFileManager, currentDirectory: File? = nil) {
guard let currentDirectory else {
fatalError("woops")
fatalError("PublicShareViewModel requires a currentDirectory to work")
adrien-coye marked this conversation as resolved.
Show resolved Hide resolved
}

let configuration = Configuration(selectAllSupported: false,
rootTitle: "public share",
rootTitle: KDriveCoreStrings.Localizable.sharedWithMeTitle,
emptyViewType: .emptyFolder,
supportsDrop: false,
matomoViewPath: [MatomoUtils.Views.menu.displayName, "publicShare"])

rootProxy = currentDirectory.proxify()
super.init(configuration: configuration, driveFileManager: driveFileManager, currentDirectory: currentDirectory)
observedFiles = AnyRealmCollection(currentDirectory.children)
print("• observedFiles :\(observedFiles.count)")
}

convenience init(
Expand All @@ -57,7 +56,6 @@ final class PublicShareViewModel: InMemoryFileListViewModel {
}

override func loadFiles(cursor: String? = nil, forceRefresh: Bool = false) async throws {
print("• loadFiles:\(cursor):\(forceRefresh)")
guard !isLoading || cursor != nil,
let publicShareProxy,
let publicShareApiFetcher else {
Expand All @@ -75,39 +73,6 @@ final class PublicShareViewModel: InMemoryFileListViewModel {
let (_, nextCursor) = try await driveFileManager.publicShareFiles(rootProxy: rootProxy,
publicShareProxy: publicShareProxy,
publicShareApiFetcher: publicShareApiFetcher)
print("• nextCursor:\(nextCursor)")
endRefreshing()
if let nextCursor {
try await loadFiles(cursor: nextCursor)
}
}
}

class SharedWithMeViewModel: FileListViewModel {
required init(driveFileManager: DriveFileManager, currentDirectory: File? = nil) {
let sharedWithMeRootFile = driveFileManager.getManagedFile(from: DriveFileManager.sharedWithMeRootFile)
let configuration = Configuration(selectAllSupported: false,
rootTitle: KDriveCoreStrings.Localizable.sharedWithMeTitle,
emptyViewType: .noSharedWithMe,
supportsDrop: false,
matomoViewPath: [MatomoUtils.Views.menu.displayName, "SharedWithMe"])

super.init(configuration: configuration, driveFileManager: driveFileManager, currentDirectory: sharedWithMeRootFile)
observedFiles = AnyRealmCollection(AnyRealmCollection(sharedWithMeRootFile.children).filesSorted(by: sortType))
}

override func loadFiles(cursor: String? = nil, forceRefresh: Bool = false) async throws {
guard !isLoading || cursor != nil else { return }

// Only show loading indicator if we have nothing in cache
if !currentDirectory.canLoadChildrenFromCache {
startRefreshing(cursor: cursor)
}
defer {
endRefreshing()
}

let (_, nextCursor) = try await driveFileManager.sharedWithMeFiles(cursor: cursor, sortType: sortType, forceRefresh: true)
endRefreshing()
if let nextCursor {
try await loadFiles(cursor: nextCursor)
Expand Down
53 changes: 53 additions & 0 deletions kDrive/UI/Controller/Menu/Share/SharedWithMeViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
Infomaniak kDrive - iOS App
Copyright (C) 2021 Infomaniak Network SA

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

import kDriveCore
import RealmSwift
import UIKit

class SharedWithMeViewModel: FileListViewModel {
required init(driveFileManager: DriveFileManager, currentDirectory: File? = nil) {
let sharedWithMeRootFile = driveFileManager.getManagedFile(from: DriveFileManager.sharedWithMeRootFile)
let configuration = Configuration(selectAllSupported: false,
rootTitle: KDriveCoreStrings.Localizable.sharedWithMeTitle,
emptyViewType: .noSharedWithMe,
supportsDrop: false,
matomoViewPath: [MatomoUtils.Views.menu.displayName, "SharedWithMe"])

super.init(configuration: configuration, driveFileManager: driveFileManager, currentDirectory: sharedWithMeRootFile)
observedFiles = AnyRealmCollection(AnyRealmCollection(sharedWithMeRootFile.children).filesSorted(by: sortType))
}

override func loadFiles(cursor: String? = nil, forceRefresh: Bool = false) async throws {
guard !isLoading || cursor != nil else { return }

// Only show loading indicator if we have nothing in cache
if !currentDirectory.canLoadChildrenFromCache {
startRefreshing(cursor: cursor)
}
defer {
endRefreshing()
}

let (_, nextCursor) = try await driveFileManager.sharedWithMeFiles(cursor: cursor, sortType: sortType, forceRefresh: true)
endRefreshing()
if let nextCursor {
try await loadFiles(cursor: nextCursor)
}
}
}
66 changes: 49 additions & 17 deletions kDrive/UI/View/Files/FileCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ protocol FileCellDelegate: AnyObject {
var file: File
var selectionMode: Bool
var isSelected = false

/// Public share data if file exists within a public share
let publicShareProxy: PublicShareProxy?

private var downloadProgressObserver: ObservationToken?
private var downloadObserver: ObservationToken?
var thumbnailDownloadTask: Kingfisher.DownloadTask?
Expand Down Expand Up @@ -114,6 +118,7 @@ protocol FileCellDelegate: AnyObject {
init(driveFileManager: DriveFileManager, file: File, selectionMode: Bool) {
self.file = file
self.selectionMode = selectionMode
publicShareProxy = driveFileManager.publicShareProxy
categories = driveFileManager.drive.categories(for: file)
}

Expand All @@ -138,30 +143,50 @@ protocol FileCellDelegate: AnyObject {
}

func setThumbnail(on imageView: UIImageView) {
// check if public share / use specific endpoint
guard !file.isInvalidated,
(file.convertedType == .image || file.convertedType == .video) && file.supportedBy.contains(.thumbnail)
else { return }
(file.convertedType == .image || file.convertedType == .video) && file.supportedBy.contains(.thumbnail) else {
return
}

// Configure placeholder
imageView.image = nil
imageView.contentMode = .scaleAspectFill
imageView.layer.cornerRadius = UIConstants.imageCornerRadius
imageView.layer.masksToBounds = true
imageView.backgroundColor = KDriveResourcesAsset.loaderDefaultColor.color
// Fetch thumbnail
thumbnailDownloadTask = file.getThumbnail { [requestFileId = file.id, weak self] image, _ in
guard let self,
!self.file.isInvalidated,
!self.isSelected else {
return

if let publicShareProxy {
// Fetch public share thumbnail
thumbnailDownloadTask = file.getPublicShareThumbnail(publicShareId: publicShareProxy.shareLinkUid,
publicDriveId: publicShareProxy.driveId,
publicFileId: file.id) { [
requestFileId = file.id,
weak self
] image, _ in
self?.setImage(image, on: imageView, requestFileId: requestFileId)
}

if file.id == requestFileId {
imageView.image = image
imageView.backgroundColor = nil
} else {
// Fetch thumbnail
thumbnailDownloadTask = file.getThumbnail { [requestFileId = file.id, weak self] image, _ in
self?.setImage(image, on: imageView, requestFileId: requestFileId)
}
}
}

private func setImage(_ image: UIImage, on imageView: UIImageView, requestFileId: Int) {
guard !file.isInvalidated,
!isSelected else {
return
}

if file.id == requestFileId {
imageView.image = image
imageView.backgroundColor = nil
}
}

deinit {
downloadProgressObserver?.cancel()
downloadObserver?.cancel()
Expand Down Expand Up @@ -302,7 +327,7 @@ class FileCollectionViewCell: UICollectionViewCell, SwipableCell {

func configure(with viewModel: FileViewModel) {
self.viewModel = viewModel
configureLogoImage()
configureLogoImage(viewModel: viewModel)
titleLabel.text = viewModel.title
detailLabel?.text = viewModel.subtitle
favoriteImageView?.isHidden = !viewModel.isFavorite
Expand All @@ -321,7 +346,12 @@ class FileCollectionViewCell: UICollectionViewCell, SwipableCell {
}

func configureWith(driveFileManager: DriveFileManager, file: File, selectionMode: Bool = false) {
configure(with: FileViewModel(driveFileManager: driveFileManager, file: file, selectionMode: selectionMode))
let fileViewModel = FileViewModel(
driveFileManager: driveFileManager,
file: file,
selectionMode: selectionMode
)
configure(with: fileViewModel)
}

/// Update the cell selection mode.
Expand All @@ -333,18 +363,20 @@ class FileCollectionViewCell: UICollectionViewCell, SwipableCell {
}

func configureForSelection() {
guard viewModel?.selectionMode == true else { return }
guard let viewModel,
viewModel.selectionMode == true else {
return
}

if isSelected {
configureCheckmarkImage()
configureImport(shouldDisplay: false)
} else {
configureLogoImage()
configureLogoImage(viewModel: viewModel)
}
}

private func configureLogoImage() {
guard let viewModel else { return }
private func configureLogoImage(viewModel: FileViewModel) {
logoImage.isAccessibilityElement = true
logoImage.accessibilityLabel = viewModel.iconAccessibilityLabel
logoImage.image = viewModel.icon
Expand Down
7 changes: 6 additions & 1 deletion kDrive/UI/View/Files/FileGridCollectionViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,12 @@ class FileGridCollectionViewCell: FileCollectionViewCell {
}

override func configureWith(driveFileManager: DriveFileManager, file: File, selectionMode: Bool = false) {
configure(with: FileGridViewModel(driveFileManager: driveFileManager, file: file, selectionMode: selectionMode))
let viewModel = FileGridViewModel(
driveFileManager: driveFileManager,
file: file,
selectionMode: selectionMode
)
configure(with: viewModel)
}

override func configureLoading() {
Expand Down
Loading
Loading