diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 69636e937..ebf1bd30d 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -323,7 +323,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, func application(_ sender: NSApplication, openFile filename: String) -> Bool { guard filename.hasSuffix(ArticleTheme.nnwThemeSuffix) else { return false } - try? importTheme(filename: filename) + importTheme(filename: filename) return true } @@ -386,7 +386,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, return } DispatchQueue.main.async { - try? self.importTheme(filename: url.path) + self.importTheme(filename: url.path) } } @@ -921,11 +921,30 @@ internal extension AppDelegate { let window = mainWindowController?.window else { return } + + var informativeText: String = "" + if let decodingError = error as? DecodingError { + switch decodingError { + case .typeMismatch(let type, _): + informativeText = "Type '\(type)' mismatch." + case .valueNotFound(let value, _): + informativeText = "Value '\(value)' not found." + case .keyNotFound(let codingKey, _): + informativeText = "Key '\(codingKey.stringValue)' not found." + case .dataCorrupted( _): + informativeText = error.localizedDescription + default: + informativeText = error.localizedDescription + } + } else { + informativeText = error.localizedDescription + } + DispatchQueue.main.async { let alert = NSAlert() alert.alertStyle = .warning alert.messageText = NSLocalizedString("Theme Error", comment: "Theme download error") - alert.informativeText = NSLocalizedString("This theme cannot be imported due to the following error: \(error.localizedDescription)", comment: "Theme download error information") + alert.informativeText = NSLocalizedString("This theme cannot be imported due to the following error: \(informativeText)", comment: "Theme download error information") alert.addButton(withTitle: NSLocalizedString("OK", comment: "OK")) alert.beginSheetModal(for: window) } diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index be116d4ca..7d1644d2c 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -6436,8 +6436,8 @@ isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/marmelroy/Zip.git"; requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.0; + kind = revision; + revision = 059e7346082d02de16220cd79df7db18ddeba8c3; }; }; 5102AE4324D17E820050839C /* XCRemoteSwiftPackageReference "RSCore" */ = { diff --git a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index fc2737cdd..dc8075713 100644 --- a/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/NetNewsWire.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -123,8 +123,8 @@ "repositoryURL": "https://github.com/marmelroy/Zip.git", "state": { "branch": null, - "revision": "bd19d974e8a38cc8d3a88c90c8a107386c3b8ccf", - "version": "2.1.1" + "revision": "059e7346082d02de16220cd79df7db18ddeba8c3", + "version": null } } ] diff --git a/Shared/ArticleStyles/ArticleTheme.swift b/Shared/ArticleStyles/ArticleTheme.swift index 7d4e16bde..dc03e816f 100644 --- a/Shared/ArticleStyles/ArticleTheme.swift +++ b/Shared/ArticleStyles/ArticleTheme.swift @@ -9,13 +9,13 @@ import Foundation struct ArticleTheme: Equatable { - + static let defaultTheme = ArticleTheme() static let nnwThemeSuffix = ".nnwtheme" - + private static let defaultThemeName = NSLocalizedString("Default", comment: "Default") private static let unknownValue = NSLocalizedString("Unknown", comment: "Unknown Value") - + let path: String? let template: String? let css: String? @@ -38,26 +38,27 @@ struct ArticleTheme: Equatable { } private let info: ArticleThemePlist? - + init() { self.path = nil; self.info = ArticleThemePlist(name: "Article Theme", themeIdentifier: "com.ranchero.netnewswire.theme.article", creatorHomePage: "https://netnewswire.com/", creatorName: "Ranchero Software", version: 1) - + let corePath = Bundle.main.path(forResource: "core", ofType: "css")! let stylesheetPath = Bundle.main.path(forResource: "stylesheet", ofType: "css")! css = Self.stringAtPath(corePath)! + "\n" + Self.stringAtPath(stylesheetPath)! - + let templatePath = Bundle.main.path(forResource: "template", ofType: "html")! template = Self.stringAtPath(templatePath)! } - + init(path: String) throws { self.path = path - + let infoPath = (path as NSString).appendingPathComponent("Info.plist") let data = try Data(contentsOf: URL(fileURLWithPath: infoPath)) self.info = try PropertyListDecoder().decode(ArticleThemePlist.self, from: data) + let corePath = Bundle.main.path(forResource: "core", ofType: "css")! let stylesheetPath = (path as NSString).appendingPathComponent("stylesheet.css") if let stylesheetCSS = Self.stringAtPath(stylesheetPath) { @@ -65,7 +66,7 @@ struct ArticleTheme: Equatable { } else { self.css = nil } - + let templatePath = (path as NSString).appendingPathComponent("template.html") self.template = Self.stringAtPath(templatePath) } @@ -74,22 +75,22 @@ struct ArticleTheme: Equatable { if !FileManager.default.fileExists(atPath: f) { return nil } - + if let s = try? NSString(contentsOfFile: f, usedEncoding: nil) as String { return s } return nil } - + static func filenameWithThemeSuffixRemoved(_ filename: String) -> String { return filename.stripping(suffix: Self.nnwThemeSuffix) } - + static func themeNameForPath(_ f: String) -> String { let filename = (f as NSString).lastPathComponent return filenameWithThemeSuffixRemoved(filename) } - + static func pathIsPathForThemeName(_ themeName: String, path: String) -> Bool { let filename = (path as NSString).lastPathComponent return filenameWithThemeSuffixRemoved(filename) == themeName diff --git a/iOS/SceneDelegate.swift b/iOS/SceneDelegate.swift index af4069522..6812578ac 100644 --- a/iOS/SceneDelegate.swift +++ b/iOS/SceneDelegate.swift @@ -184,7 +184,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { NotificationCenter.default.post(name: .didBeginDownloadingTheme, object: nil) } let task = URLSession.shared.downloadTask(with: request) { [weak self] location, response, error in - guard let self = self, + guard let location = location else { return } do { diff --git a/iOS/UIKit Extensions/UIViewController-Extensions.swift b/iOS/UIKit Extensions/UIViewController-Extensions.swift index a21bc05eb..9d06d7609 100644 --- a/iOS/UIKit Extensions/UIViewController-Extensions.swift +++ b/iOS/UIKit Extensions/UIViewController-Extensions.swift @@ -15,6 +15,23 @@ extension UIViewController { func presentError(_ error: Error, dismiss: (() -> Void)? = nil) { if let accountError = error as? AccountError, accountError.isCredentialsError { presentAccountError(accountError, dismiss: dismiss) + } else if let decodingError = error as? DecodingError { + let errorTitle = NSLocalizedString("Error", comment: "Error") + switch decodingError { + case .typeMismatch(let type, _): + let str = "Type '\(type)' mismatch." + presentError(title: errorTitle, message: str, dismiss: dismiss) + case .valueNotFound(let value, _): + let str = "Value '\(value)' not found." + presentError(title: errorTitle, message: str, dismiss: dismiss) + case .keyNotFound(let codingKey, _): + let str = "Key '\(codingKey.stringValue)' not found." + presentError(title: errorTitle, message: str, dismiss: dismiss) + case .dataCorrupted( _): + presentError(title: errorTitle, message: error.localizedDescription, dismiss: dismiss) + default: + presentError(title: errorTitle, message: error.localizedDescription, dismiss: dismiss) + } } else { let errorTitle = NSLocalizedString("Error", comment: "Error") presentError(title: errorTitle, message: error.localizedDescription, dismiss: dismiss)