iOS/Sources/App/WebView/DownloadManager/DownloadManagerViewModel.swift

78 lines
2.6 KiB
Swift

import Foundation
import Shared
import WebKit
@MainActor
final class DownloadManagerViewModel: NSObject, ObservableObject {
@Published var fileName: String = ""
@Published var finished: Bool = false
@Published var failed: Bool = false
@Published var errorMessage: String = ""
@Published var progress: String = ""
@Published var lastURLCreated: URL?
private var progressObservation: NSKeyValueObservation?
private var lastDownload: WKDownload?
func deleteFile() {
if let url = lastURLCreated {
// Guarantee to delete file before leaving screen
do {
try FileManager.default.removeItem(at: url)
} catch {
Current.Log.error("Failed to remove file before leaving download manager at \(url), error: \(error)")
}
}
}
func cancelDownload() {
progressObservation?.invalidate()
lastDownload?.cancel()
}
private func bytesToMBString(_ bytes: Int64) -> String {
let formatter = ByteCountFormatter()
formatter.allowedUnits = [.useMB]
formatter.countStyle = .file
return formatter.string(fromByteCount: bytes)
}
}
extension DownloadManagerViewModel: WKDownloadDelegate {
func download(
_ download: WKDownload,
decideDestinationUsing response: URLResponse,
suggestedFilename: String
) async -> URL? {
lastDownload = download
let name = suggestedFilename.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "Unknown"
fileName = name
if let url = URL(string: name, relativeTo: AppConstants.DownloadsDirectory) {
lastURLCreated = url
// Guarantee file does not exist, otherwise download will fail
do {
try FileManager.default.removeItem(at: url)
} catch {
Current.Log.error("Failed to remove file for download manager at \(url), error: \(error)")
}
progressObservation?.invalidate()
progressObservation = download.progress.observe(\.completedUnitCount) { [weak self] progress, _ in
guard let self else { return }
self.progress = bytesToMBString(progress.completedUnitCount)
}
return url
} else {
return nil
}
}
func downloadDidFinish(_ download: WKDownload) {
finished = true
}
func download(_ download: WKDownload, didFailWithError error: any Error, resumeData: Data?) {
errorMessage = L10n.DownloadManager.Failed.title(error.localizedDescription)
failed = true
}
}