Skip to content

Commit

Permalink
refactor: Move PreviewError and split to OfficePreviewError (#1345)
Browse files Browse the repository at this point in the history
  • Loading branch information
PhilippeWeidmann authored Dec 6, 2024
2 parents 2931c69 + 48363c8 commit b37650e
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 84 deletions.
59 changes: 59 additions & 0 deletions kDrive/UI/Controller/Files/Preview/PreviewError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
Infomaniak kDrive - iOS App
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
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 Foundation

class PreviewError {
let fileId: Int
var downloadError: Error?

init(fileId: Int, downloadError: Error?) {
self.fileId = fileId
self.downloadError = downloadError
}
}

class OfficePreviewError: PreviewError {
var pdfGenerationProgress: Progress?
var downloadTask: URLSessionDownloadTask?
var pdfUrl: URL?

init(
fileId: Int,
pdfGenerationProgress: Progress? = nil,
downloadTask: URLSessionDownloadTask? = nil,
pdfUrl: URL? = nil,
downloadError: Error? = nil
) {
super.init(fileId: fileId, downloadError: downloadError)
self.pdfGenerationProgress = pdfGenerationProgress
self.downloadTask = downloadTask
self.pdfUrl = pdfUrl
}

func addDownloadTask(_ downloadTask: URLSessionDownloadTask) {
self.downloadTask = downloadTask
pdfGenerationProgress?.completedUnitCount += 1
pdfGenerationProgress?.addChild(downloadTask.progress, withPendingUnitCount: 9)
}

func removeDownloadTask() {
pdfGenerationProgress = nil
downloadTask = nil
}
}
133 changes: 52 additions & 81 deletions kDrive/UI/Controller/Files/Preview/PreviewViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,39 +36,6 @@ import UIKit
final class PreviewViewController: UIViewController, PreviewContentCellDelegate, SceneStateRestorable {
@LazyInjectService var accountManager: AccountManageable

final class PreviewError {
let fileId: Int
var pdfGenerationProgress: Progress?
var downloadTask: URLSessionDownloadTask?
var pdfUrl: URL?
var error: Error?

init(
fileId: Int,
pdfGenerationProgress: Progress? = nil,
downloadTask: URLSessionDownloadTask? = nil,
pdfUrl: URL? = nil,
error: Error? = nil
) {
self.fileId = fileId
self.pdfGenerationProgress = pdfGenerationProgress
self.downloadTask = downloadTask
self.pdfUrl = pdfUrl
self.error = error
}

func addDownloadTask(_ downloadTask: URLSessionDownloadTask) {
self.downloadTask = downloadTask
pdfGenerationProgress?.completedUnitCount += 1
pdfGenerationProgress?.addChild(downloadTask.progress, withPendingUnitCount: 9)
}

func removeDownloadTask() {
pdfGenerationProgress = nil
downloadTask = nil
}
}

@IBOutlet var collectionView: UICollectionView!
private var previewFiles = [File]()
private var previewErrors = [Int: PreviewError]()
Expand Down Expand Up @@ -276,7 +243,7 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
let currentCell = (collectionView.cellForItem(at: currentIndex) as? PreviewCollectionViewCell)
currentCell?.didEndDisplaying()
currentDownloadOperation?.cancel()
previewErrors.values.forEach { $0.downloadTask?.cancel() }
previewErrors.values.compactMap { $0 as? OfficePreviewError }.forEach { $0.downloadTask?.cancel() }
navigationController?.interactivePopGestureRecognizer?.delegate = nil

UIApplication.shared.endReceivingRemoteControlEvents()
Expand Down Expand Up @@ -482,29 +449,9 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
}

let file = previewFiles[index]
let previewError = PreviewError(fileId: fileId)
if file.convertedType == .spreadsheet
|| file.convertedType == .presentation
|| file.convertedType == .text {
previewError.pdfGenerationProgress = Progress(totalUnitCount: 10)
PdfPreviewCache.shared.retrievePdf(for: file, driveFileManager: driveFileManager) { downloadTask in
previewError.addDownloadTask(downloadTask)
Task { @MainActor [weak self] in
self?.collectionView.reloadItems(at: [IndexPath(item: index, section: 0)])
}
} completion: { url, error in
previewError.removeDownloadTask()
if let url {
previewError.pdfUrl = url
} else {
previewError.error = error
}
Task { @MainActor [weak self] in
self?.collectionView.reloadItems(at: [IndexPath(item: index, section: 0)])
}
}
if ConvertedType.documentTypes.contains(file.convertedType) {
handleOfficePreviewError(error, previewIndex: index)
}
previewErrors[fileId] = previewError

// We have to delay reload because errorWhilePreviewing can be called when the collectionView requests a new cell in
// cellForItemAt and iOS 18 seems unhappy about this.
Expand All @@ -513,6 +460,31 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
}
}

func handleOfficePreviewError(_ error: Error, previewIndex: Int) {
let file = previewFiles[previewIndex]

let previewError = OfficePreviewError(fileId: file.id, pdfGenerationProgress: Progress(totalUnitCount: 10))

PdfPreviewCache.shared.retrievePdf(for: file, driveFileManager: driveFileManager) { downloadTask in
previewError.addDownloadTask(downloadTask)
Task { @MainActor [weak self] in
self?.collectionView.reloadItems(at: [IndexPath(item: previewIndex, section: 0)])
}
} completion: { url, error in
previewError.removeDownloadTask()
if let url {
previewError.pdfUrl = url
} else {
previewError.downloadError = error
}
Task { @MainActor [weak self] in
self?.collectionView.reloadItems(at: [IndexPath(item: previewIndex, section: 0)])
}
}

previewErrors[file.id] = previewError
}

func openWith(from: UIView) {
let frame = from.convert(from.bounds, to: view)
floatingPanelViewController.dismiss(animated: true)
Expand Down Expand Up @@ -546,7 +518,7 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,

private func downloadFileIfNeeded(at indexPath: IndexPath) {
let currentFile = previewFiles[indexPath.row]
previewErrors.values.forEach { $0.downloadTask?.cancel() }
previewErrors.values.compactMap { $0 as? OfficePreviewError }.forEach { $0.downloadTask?.cancel() }
currentDownloadOperation?.cancel()
currentDownloadOperation = nil
guard currentFile.isLocalVersionOlderThanRemote && ConvertedType.downloadableTypes.contains(currentFile.convertedType)
Expand All @@ -559,37 +531,36 @@ final class PreviewViewController: UIViewController, PreviewContentCellDelegate,
userId: accountManager.currentUserId,
onOperationCreated: { operation in
Task { @MainActor [weak self] in
guard let self = self else {
guard let self else {
return
}

self.currentDownloadOperation = operation
if let progress = self.currentDownloadOperation?.task?.progress,
let cell = self.collectionView.cellForItem(at: indexPath) as? DownloadProgressObserver {
currentDownloadOperation = operation
if let progress = currentDownloadOperation?.task?.progress,
let cell = collectionView.cellForItem(at: indexPath) as? DownloadProgressObserver {
cell.setDownloadProgress(progress)
}
}
},
completion: { error in
Task { @MainActor [weak self] in
guard let self = self else {
return
}
guard let self else { return }

currentDownloadOperation = nil

guard view.window != nil else { return }

self.currentDownloadOperation = nil
if self.view.window != nil {
if let error {
if error != .taskCancelled {
self.previewErrors[currentFile.id] = PreviewError(fileId: currentFile.id, error: error)
self.collectionView.reloadItems(at: [indexPath])
}
} else {
(self.collectionView.cellForItem(at: indexPath) as? DownloadingPreviewCollectionViewCell)?
.previewDownloadTask?.cancel()
self.collectionView.endEditing(true)
self.collectionView.reloadItems(at: [indexPath])
self.updateNavigationBar()
if let error {
if error != .taskCancelled {
previewErrors[currentFile.id] = PreviewError(fileId: currentFile.id, downloadError: error)
collectionView.reloadItems(at: [indexPath])
}
} else {
(collectionView.cellForItem(at: indexPath) as? DownloadingPreviewCollectionViewCell)?
.previewDownloadTask?.cancel()
collectionView.endEditing(true)
collectionView.reloadItems(at: [indexPath])
updateNavigationBar()
}
}
}
Expand Down Expand Up @@ -706,18 +677,18 @@ extension PreviewViewController: UICollectionViewDataSource {
}

private func getNoLocalPreviewCellFor(file: File, indexPath: IndexPath) -> UICollectionViewCell {
if let previewFallback = previewErrors[file.id] {
if let url = previewFallback.pdfUrl {
if let officePreviewError = previewErrors[file.id] as? OfficePreviewError {
if let url = officePreviewError.pdfUrl {
let cell = collectionView.dequeueReusableCell(type: PdfPreviewCollectionViewCell.self, for: indexPath)
cell.previewDelegate = self
cell.configureWith(documentUrl: url)
return cell
} else {
let cell = collectionView.dequeueReusableCell(type: NoPreviewCollectionViewCell.self, for: indexPath)
cell.configureWith(file: file)
if let progress = previewFallback.pdfGenerationProgress {
if let progress = officePreviewError.pdfGenerationProgress {
cell.setDownloadProgress(progress)
} else if previewFallback.error != nil {
} else if officePreviewError.downloadError != nil {
cell.errorDownloading()
}
cell.previewDelegate = self
Expand Down
7 changes: 4 additions & 3 deletions kDriveCore/Data/Models/File.swift
Original file line number Diff line number Diff line change
Expand Up @@ -175,11 +175,12 @@ public enum ConvertedType: String, CaseIterable {
return types.first { uti.conforms(to: $0.uti) } ?? .unknown
}

public static let downloadableTypes = Set<ConvertedType>(arrayLiteral: .code, .form, .pdf, .presentation, .spreadsheet, .text,
.url)
public static let remotePlayableTypes = Set<ConvertedType>(arrayLiteral: .audio, .video)
public static let downloadableTypes: Set<ConvertedType> = [.code, .form, .pdf, .presentation, .spreadsheet, .text, .url]
public static let remotePlayableTypes: Set<ConvertedType> = [.audio, .video]
// Currently it's the same as the downloadableTypes but later this could change
public static let ignoreThumbnailTypes = downloadableTypes
/// Documents that can be previewed by the OS but not necessarily handled by OnlyOffice (eg. .pages)
public static let documentTypes: Set<ConvertedType> = [.presentation, .spreadsheet, .text]
}

public enum SortType: String {
Expand Down

0 comments on commit b37650e

Please sign in to comment.