Implement initial alert dialog when importing a theme

This commit is contained in:
Maurice Parker 2021-09-08 00:28:13 -05:00
parent 0d089a7246
commit 98b9080b1f
3 changed files with 112 additions and 47 deletions

View File

@ -319,6 +319,12 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations,
AccountManager.shared.receiveRemoteNotification(userInfo: userInfo)
}
func application(_ sender: NSApplication, openFile filename: String) -> Bool {
guard filename.hasSuffix(".nnwtheme") else { return false }
importTheme(filename: filename)
return true
}
func applicationWillTerminate(_ notification: Notification) {
shuttingDown = true
saveState()
@ -769,7 +775,6 @@ private extension AppDelegate {
}
func objectsForInspector() -> [Any]? {
guard let window = NSApplication.shared.mainWindow, let windowController = window.windowController as? MainWindowController else {
return nil
}
@ -782,7 +787,6 @@ private extension AppDelegate {
}
func updateSortMenuItems() {
let sortByNewestOnTop = AppDefaults.shared.timelineSortDirection == .orderedDescending
sortByNewestArticleOnTopMenuItem.state = sortByNewestOnTop ? .on : .off
sortByOldestArticleOnTopMenuItem.state = sortByNewestOnTop ? .off : .on
@ -792,6 +796,48 @@ private extension AppDelegate {
let groupByFeedEnabled = AppDefaults.shared.timelineGroupByFeed
groupArticlesByFeedMenuItem.state = groupByFeedEnabled ? .on : .off
}
func importTheme(filename: String) {
guard let window = mainWindowController?.window else { return }
let theme = ArticleTheme(path: filename)
let alert = NSAlert()
alert.alertStyle = .informational
let localizedMessageText = NSLocalizedString("Install “%@” by %@?", comment: "Theme message text")
alert.messageText = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.name, theme.creatorName) as String
var attrs = [NSAttributedString.Key : Any]()
attrs[.font] = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize)
attrs[.foregroundColor] = NSColor.textColor
let titleParagraphStyle = NSMutableParagraphStyle()
titleParagraphStyle.alignment = .center
attrs[.paragraphStyle] = titleParagraphStyle
let websiteText = NSMutableAttributedString()
websiteText.append(NSAttributedString(string: NSLocalizedString("Author's Website", comment: "Author's Website"), attributes: attrs))
websiteText.append(NSAttributedString(string: "\n"))
attrs[.link] = theme.creatorHomePage
websiteText.append(NSAttributedString(string: theme.creatorHomePage, attributes: attrs))
let textView = NSTextView(frame: CGRect(x: 0, y: 0, width: 200, height: 15))
textView.isEditable = false
textView.drawsBackground = false
textView.textStorage?.setAttributedString(websiteText)
alert.accessoryView = textView
alert.addButton(withTitle: NSLocalizedString("Install Style", comment: "Install Style"))
alert.addButton(withTitle: NSLocalizedString("Cancel", comment: "Cancel Install Style"))
alert.beginSheetModal(for: window) { [weak self] result in
if result == NSApplication.ModalResponse.alertFirstButtonReturn {
guard let self = self else { return }
}
}
}
}
/*

View File

@ -11,10 +11,33 @@ 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?
let info: NSDictionary?
var name: String {
guard let path = path else { return Self.defaultThemeName }
return Self.themeNameForPath(path)
}
var creatorHomePage: String {
return info?["CreatorHomePage"] as? String ?? Self.unknownValue
}
var creatorName: String {
return info?["CreatorName"] as? String ?? Self.unknownValue
}
var version: String {
return info?["Version"] as? String ?? "0.0"
}
private let info: NSDictionary?
init() {
self.path = nil;
@ -23,14 +46,14 @@ struct ArticleTheme: Equatable {
let sharedCSSPath = Bundle.main.path(forResource: "shared", ofType: "css")!
let platformCSSPath = Bundle.main.path(forResource: "styleSheet", ofType: "css")!
if let sharedCSS = stringAtPath(sharedCSSPath), let platformCSS = stringAtPath(platformCSSPath) {
if let sharedCSS = Self.stringAtPath(sharedCSSPath), let platformCSS = Self.stringAtPath(platformCSSPath) {
css = sharedCSS + "\n" + platformCSS
} else {
css = nil
}
let templatePath = Bundle.main.path(forResource: "template", ofType: "html")!
template = stringAtPath(templatePath)
template = Self.stringAtPath(templatePath)
}
init(path: String) {
@ -41,26 +64,40 @@ struct ArticleTheme: Equatable {
self.info = NSDictionary(contentsOfFile: infoPath)
let cssPath = (path as NSString).appendingPathComponent("stylesheet.css")
self.css = stringAtPath(cssPath)
self.css = Self.stringAtPath(cssPath)
let templatePath = (path as NSString).appendingPathComponent("template.html")
self.template = stringAtPath(templatePath)
self.template = Self.stringAtPath(templatePath)
} else {
self.css = stringAtPath(path)
self.css = Self.stringAtPath(path)
self.template = nil
self.info = nil
}
}
}
static func stringAtPath(_ f: String) -> String? {
if !FileManager.default.fileExists(atPath: f) {
return nil
}
private func stringAtPath(_ f: String) -> String? {
if !FileManager.default.fileExists(atPath: f) {
if let s = try? NSString(contentsOfFile: f, usedEncoding: nil) as String {
return s
}
return nil
}
if let s = try? NSString(contentsOfFile: f, usedEncoding: nil) as String {
return s
static func filenameWithThemeSuffixRemoved(_ filename: String) -> String {
return filename.stripping(suffix: Self.nnwThemeSuffix)
}
return nil
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
}
}

View File

@ -17,9 +17,6 @@ import RSCore
let ArticleThemeNamesDidChangeNotification = "ArticleThemeNamesDidChangeNotification"
let CurrentArticleThemeDidChangeNotification = "CurrentArticleThemeDidChangeNotification"
private let themesInResourcesFolderName = "Themes"
private let nnwThemeSuffix = ".nnwtheme"
final class ArticleThemesManager {
static var shared: ArticleThemesManager!
@ -80,7 +77,7 @@ final class ArticleThemesManager {
// MARK : Internal
private func updateThemeNames() {
let updatedThemeNames = allThemePaths(folderPath).map { themeNameForPath($0) }
let updatedThemeNames = allThemePaths(folderPath).map { ArticleTheme.themeNameForPath($0) }
if updatedThemeNames != themeNames {
themeNames = updatedThemeNames
@ -104,7 +101,6 @@ final class ArticleThemesManager {
}
private func updateCurrentTheme() {
var themeName = currentThemeName
if !themeNames.contains(themeName) {
themeName = AppDefaults.defaultThemeName
@ -121,33 +117,19 @@ final class ArticleThemesManager {
currentTheme = articleTheme
}
}
}
private func allThemePaths(_ folder: String) -> [String] {
let filepaths = FileManager.default.filePaths(inFolder: folder)
return filepaths?.filter { $0.hasSuffix(nnwThemeSuffix) } ?? []
}
private func filenameWithThemeSuffixRemoved(_ filename: String) -> String {
return filename.stripping(suffix: nnwThemeSuffix)
}
private func themeNameForPath(_ f: String) -> String {
let filename = (f as NSString).lastPathComponent
return filenameWithThemeSuffixRemoved(filename)
}
private func pathIsPathForThemeName(_ themeName: String, path: String) -> Bool {
let filename = (path as NSString).lastPathComponent
return filenameWithThemeSuffixRemoved(filename) == themeName
}
private func pathForThemeName(_ themeName: String, folder: String) -> String? {
for onePath in allThemePaths(folder) {
if pathIsPathForThemeName(themeName, path: onePath) {
return onePath
}
private func allThemePaths(_ folder: String) -> [String] {
let filepaths = FileManager.default.filePaths(inFolder: folder)
return filepaths?.filter { $0.hasSuffix(ArticleTheme.nnwThemeSuffix) } ?? []
}
return nil
private func pathForThemeName(_ themeName: String, folder: String) -> String? {
for onePath in allThemePaths(folder) {
if ArticleTheme.pathIsPathForThemeName(themeName, path: onePath) {
return onePath
}
}
return nil
}
}