iOS/Sources/App/WebView/DownloadManager/DownloadManagerViewModel.swift
Bruno Pantaleão Gonçalves 5da88f3455
Improve download manager (#3158)
<!-- Thank you for submitting a Pull Request and helping to improve Home
Assistant. Please complete the following sections to help the processing
and review of your changes. Please do not delete anything from this
template. -->

## Summary
<!-- Provide a brief summary of the changes you have made and most
importantly what they aim to achieve -->

## Screenshots
<!-- If this is a user-facing change not in the frontend, please include
screenshots in light and dark mode. -->
![Simulator Screenshot - iPhone 16 - 2024-11-14 at 11 54
53](https://github.com/user-attachments/assets/65483b7e-31d6-46f2-abf1-3cf26856d9fc)

## Link to pull request in Documentation repository
<!-- Pull requests that add, change or remove functionality must have a
corresponding pull request in the Companion App Documentation repository
(https://github.com/home-assistant/companion.home-assistant). Please add
the number of this pull request after the "#" -->
Documentation: home-assistant/companion.home-assistant#

## Any other notes
<!-- If there is any other information of note, like if this Pull
Request is part of a bigger change, please include it here. -->
2024-11-14 14:09:52 +01:00

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
}
}