mirror of
https://github.com/Ranchero-Software/NetNewsWire.git
synced 2025-02-03 04:17:44 +01:00
78e0595708
- `try` added where applicable to ArticleTheme inits - `ArticleThemePlist` has fixed spelling of theme identifier and conforms to Equatable - `ArticleTheme` now uses `ArticleThemePlist` - `ArticleThemeDownloader` is now a class - `ArticleThemeDownloader` will now download themes to Application Support/NetNewsWire/Downloads on macOS and iOS. - `ArticleThemeDownloader` will remove downloaded themes from the Download folder when the application is closed. - macOS app delegate now observes for theme download fails - Error display code moved from SceneDelegate to SceneCoordinator so that it can use existing presentError on rootVC.
94 lines
3.4 KiB
Swift
94 lines
3.4 KiB
Swift
//
|
|
// ArticleThemeDownloader.swift
|
|
// ArticleThemeDownloader
|
|
//
|
|
// Created by Stuart Breckenridge on 20/09/2021.
|
|
// Copyright © 2021 Ranchero Software. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import Zip
|
|
|
|
public class ArticleThemeDownloader {
|
|
|
|
public enum ArticleThemeDownloaderError: LocalizedError {
|
|
case noThemeFile
|
|
|
|
public var errorDescription: String? {
|
|
switch self {
|
|
case .noThemeFile:
|
|
return "There is no NetNewsWire theme available."
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
public static let shared = ArticleThemeDownloader()
|
|
private init() {}
|
|
|
|
public func handleFile(at location: URL) throws {
|
|
createDownloadDirectoryIfRequired()
|
|
let movedFileLocation = try moveTheme(from: location)
|
|
let unzippedFileLocation = try unzipFile(at: movedFileLocation)
|
|
NotificationCenter.default.post(name: .didEndDownloadingTheme, object: nil, userInfo: ["url" : unzippedFileLocation])
|
|
}
|
|
|
|
|
|
/// Creates `Application Support/NetNewsWire/Downloads` if needed.
|
|
private func createDownloadDirectoryIfRequired() {
|
|
try? FileManager.default.createDirectory(at: downloadDirectory(), withIntermediateDirectories: true, attributes: nil)
|
|
}
|
|
|
|
/// Moves the downloaded `.tmp` file to the `downloadDirectory` and renames it a `.zip`
|
|
/// - Parameter location: The temporary file location.
|
|
/// - Returns: Destination `URL`.
|
|
private func moveTheme(from location: URL) throws -> URL {
|
|
var tmpFileName = location.lastPathComponent
|
|
tmpFileName = tmpFileName.replacingOccurrences(of: ".tmp", with: ".zip")
|
|
let fileUrl = downloadDirectory().appendingPathComponent("\(tmpFileName)")
|
|
try FileManager.default.moveItem(at: location, to: fileUrl)
|
|
return fileUrl
|
|
}
|
|
|
|
/// Unzips the zip file
|
|
/// - Parameter location: Location of the zip archive.
|
|
/// - Returns: Enclosed `.nnwtheme` file.
|
|
private func unzipFile(at location: URL) throws -> URL {
|
|
do {
|
|
let unzipDirectory = URL(fileURLWithPath: location.path.replacingOccurrences(of: ".zip", with: ""))
|
|
try Zip.unzipFile(location, destination: unzipDirectory, overwrite: true, password: nil, progress: nil, fileOutputHandler: nil) // Unzips to folder in Application Support/NetNewsWire/Downloads
|
|
try FileManager.default.removeItem(at: location) // Delete zip in Cache
|
|
let themeFilePath = FileManager.default.filenames(inFolder: unzipDirectory.path)?.first(where: { $0.contains(".nnwtheme") })
|
|
if themeFilePath == nil {
|
|
throw ArticleThemeDownloaderError.noThemeFile
|
|
}
|
|
return URL(fileURLWithPath: unzipDirectory.appendingPathComponent(themeFilePath!).path)
|
|
} catch {
|
|
try? FileManager.default.removeItem(at: location)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
/// The download directory used by the theme downloader: `Application Suppport/NetNewsWire/Downloads`
|
|
/// - Returns: `URL`
|
|
private func downloadDirectory() -> URL {
|
|
FileManager.default.urls(for: .applicationSupportDirectory, in: .userDomainMask).first!.appendingPathComponent("NetNewsWire/Downloads", isDirectory: true)
|
|
}
|
|
|
|
/// Removes downloaded themes, where themes == folders, from `Application Suppport/NetNewsWire/Downloads`.
|
|
public func cleanUp() {
|
|
guard let filenames = try? FileManager.default.contentsOfDirectory(atPath: downloadDirectory().path) else {
|
|
return
|
|
}
|
|
for path in filenames {
|
|
do {
|
|
if FileManager.default.isFolder(atPath: downloadDirectory().appendingPathComponent(path).path) {
|
|
try FileManager.default.removeItem(atPath: downloadDirectory().appendingPathComponent(path).path)
|
|
}
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
}
|
|
}
|