From 42bcaf7e5537c13b9e84b335b84f4fa23f428495 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 18 Sep 2021 10:28:19 -0500 Subject: [PATCH 1/2] Extract Theme Import logic so that it can be reused --- NetNewsWire.xcodeproj/project.pbxproj | 4 ++ iOS/SceneCoordinator.swift | 77 +------------------- iOS/Settings/ArticleThemeImporter.swift | 96 +++++++++++++++++++++++++ 3 files changed, 101 insertions(+), 76 deletions(-) create mode 100644 iOS/Settings/ArticleThemeImporter.swift diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 5a51bdb4a..3bf61e948 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -253,6 +253,7 @@ 5137C2E626F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; }; 5137C2E726F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; }; 5137C2E826F3F52D009EFEDB /* Sepia.nnwtheme in Resources */ = {isa = PBXBuildFile; fileRef = 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */; }; + 5137C2EA26F63AE6009EFEDB /* ArticleThemeImporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */; }; 51386A8E25673277005F3762 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51386A8D25673276005F3762 /* AccountCell.swift */; }; 51386A8F25673277005F3762 /* AccountCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51386A8D25673276005F3762 /* AccountCell.swift */; }; 5138E93A24D33E5600AFF0FE /* RSTree in Frameworks */ = {isa = PBXBuildFile; productRef = 5138E93924D33E5600AFF0FE /* RSTree */; }; @@ -1656,6 +1657,7 @@ 51333D1524685D2E00EB5C91 /* AddRedditFeedWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddRedditFeedWindowController.swift; sourceTree = ""; }; 51333D3A2468615D00EB5C91 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Mac/Base.lproj/AddRedditFeedSheet.xib; sourceTree = SOURCE_ROOT; }; 5137C2E326F3F52D009EFEDB /* Sepia.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = Sepia.nnwtheme; sourceTree = ""; }; + 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleThemeImporter.swift; sourceTree = ""; }; 51386A8D25673276005F3762 /* AccountCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountCell.swift; sourceTree = ""; }; 51392D1A24AC19A000BE0D35 /* SidebarExpandedContainers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarExpandedContainers.swift; sourceTree = ""; }; 513C5CE6232571C2003D4054 /* NetNewsWire iOS Share Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "NetNewsWire iOS Share Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2801,6 +2803,7 @@ 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */, 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */, 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */, + 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */, 516244E2241E19F000B61C47 /* ColorPaletteTableViewController.swift */, 516A09382360A2AE00EAE89B /* SettingsComboTableViewCell.swift */, 516A091D23609A3600EAE89B /* SettingsComboTableViewCell.xib */, @@ -5615,6 +5618,7 @@ 51C45268226508F600C03939 /* MasterFeedUnreadCountView.swift in Sources */, D3A39865246505DF00F9A366 /* FindInArticleActivity.swift in Sources */, 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */, + 5137C2EA26F63AE6009EFEDB /* ArticleThemeImporter.swift in Sources */, 51C4529F22650A1900C03939 /* AuthorAvatarDownloader.swift in Sources */, 5108F6D22375EED2001ABC45 /* TimelineCustomizerViewController.swift in Sources */, 519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */, diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 08637a03f..16d63ee5c 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1295,68 +1295,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider { } func importTheme(filename: String) { - let theme = ArticleTheme(path: filename) - - let localizedTitleText = NSLocalizedString("Install theme “%@” by %@?", comment: "Theme message text") - let title = NSString.localizedStringWithFormat(localizedTitleText as NSString, theme.name, theme.creatorName) as String - - let localizedMessageText = NSLocalizedString("Author's Website:\n%@", comment: "Authors website") - let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.creatorHomePage) as String - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) - - if let url = URL(string: theme.creatorHomePage) { - let visitSiteTitle = NSLocalizedString("Show Website", comment: "Show Website") - let visitSiteAction = UIAlertAction(title: visitSiteTitle, style: .default) { [weak self] action in - UIApplication.shared.open(url) - self?.importTheme(filename: filename) - } - alertController.addAction(visitSiteAction) - } - - func importTheme() { - do { - try ArticleThemesManager.shared.importTheme(filename: filename) - confirmImportSuccess(themeName: theme.name) - } catch { - rootSplitViewController.presentError(error) - } - } - - let installThemeTitle = NSLocalizedString("Install Theme", comment: "Install Theme") - let installThemeAction = UIAlertAction(title: installThemeTitle, style: .default) { [weak self] action in - - if ArticleThemesManager.shared.themeExists(filename: filename) { - let title = NSLocalizedString("Duplicate Theme", comment: "Duplicate Theme") - let localizedMessageText = NSLocalizedString("The theme “%@” already exists. Overwrite it?", comment: "Overwrite theme") - let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.name) as String - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) - - let overwriteAction = UIAlertAction(title: NSLocalizedString("Overwrite", comment: "Overwrite"), style: .default) { action in - importTheme() - } - alertController.addAction(overwriteAction) - alertController.preferredAction = overwriteAction - - self?.rootSplitViewController.present(alertController, animated: true) - } else { - importTheme() - } - - } - - alertController.addAction(installThemeAction) - alertController.preferredAction = installThemeAction - - rootSplitViewController.present(alertController, animated: true) - + ArticleThemeImporter.importTheme(controller: rootSplitViewController, filename: filename); } } @@ -2363,18 +2302,4 @@ private extension SceneCoordinator { return true } - func confirmImportSuccess(themeName: String) { - let title = NSLocalizedString("Theme installed", comment: "Theme installed") - - let localizedMessageText = NSLocalizedString("The theme “%@” has been installed.", comment: "Theme installed") - let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, themeName) as String - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let doneTitle = NSLocalizedString("Done", comment: "Done") - alertController.addAction(UIAlertAction(title: doneTitle, style: .default)) - - rootSplitViewController.present(alertController, animated: true) - } - } diff --git a/iOS/Settings/ArticleThemeImporter.swift b/iOS/Settings/ArticleThemeImporter.swift new file mode 100644 index 000000000..7c2950622 --- /dev/null +++ b/iOS/Settings/ArticleThemeImporter.swift @@ -0,0 +1,96 @@ +// +// ArticleThemeImporter.swift +// NetNewsWire +// +// Created by Maurice Parker on 9/18/21. +// Copyright © 2021 Ranchero Software. All rights reserved. +// + +import UIKit + +struct ArticleThemeImporter { + + static func importTheme(controller: UIViewController, filename: String) { + let theme = ArticleTheme(path: filename) + + let localizedTitleText = NSLocalizedString("Install theme “%@” by %@?", comment: "Theme message text") + let title = NSString.localizedStringWithFormat(localizedTitleText as NSString, theme.name, theme.creatorName) as String + + let localizedMessageText = NSLocalizedString("Author's Website:\n%@", comment: "Authors website") + let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.creatorHomePage) as String + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") + alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) + + if let url = URL(string: theme.creatorHomePage) { + let visitSiteTitle = NSLocalizedString("Show Website", comment: "Show Website") + let visitSiteAction = UIAlertAction(title: visitSiteTitle, style: .default) { action in + UIApplication.shared.open(url) + Self.importTheme(controller: controller, filename: filename) + } + alertController.addAction(visitSiteAction) + } + + func importTheme() { + do { + try ArticleThemesManager.shared.importTheme(filename: filename) + confirmImportSuccess(controller: controller, themeName: theme.name) + } catch { + controller.presentError(error) + } + } + + let installThemeTitle = NSLocalizedString("Install Theme", comment: "Install Theme") + let installThemeAction = UIAlertAction(title: installThemeTitle, style: .default) { action in + + if ArticleThemesManager.shared.themeExists(filename: filename) { + let title = NSLocalizedString("Duplicate Theme", comment: "Duplicate Theme") + let localizedMessageText = NSLocalizedString("The theme “%@” already exists. Overwrite it?", comment: "Overwrite theme") + let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, theme.name) as String + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") + alertController.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) + + let overwriteAction = UIAlertAction(title: NSLocalizedString("Overwrite", comment: "Overwrite"), style: .default) { action in + importTheme() + } + alertController.addAction(overwriteAction) + alertController.preferredAction = overwriteAction + + controller.present(alertController, animated: true) + } else { + importTheme() + } + + } + + alertController.addAction(installThemeAction) + alertController.preferredAction = installThemeAction + + controller.present(alertController, animated: true) + + } + +} + +private extension ArticleThemeImporter { + + static func confirmImportSuccess(controller: UIViewController, themeName: String) { + let title = NSLocalizedString("Theme installed", comment: "Theme installed") + + let localizedMessageText = NSLocalizedString("The theme “%@” has been installed.", comment: "Theme installed") + let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, themeName) as String + + let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) + + let doneTitle = NSLocalizedString("Done", comment: "Done") + alertController.addAction(UIAlertAction(title: doneTitle, style: .default)) + + controller.present(alertController, animated: true) + } + +} From 04d7ab188f7cb6d5f4bf738d5c08b0bb1d8e860a Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Sat, 18 Sep 2021 10:49:30 -0500 Subject: [PATCH 2/2] Add import button to Themes listing scene --- NetNewsWire.xcodeproj/project.pbxproj | 6 ++--- .../ArticleThemesTableViewController.swift | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 3bf61e948..ba2096bab 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -2797,14 +2797,14 @@ 5183CCEB227117C70010922C /* Settings */ = { isa = PBXGroup; children = ( - 51A16990235E10D600EB091F /* Settings.storyboard */, 51A16995235E10D600EB091F /* AboutViewController.swift */, 51A16992235E10D600EB091F /* AddAccountViewController.swift */, - 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */, 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */, - 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */, 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */, + 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */, 516244E2241E19F000B61C47 /* ColorPaletteTableViewController.swift */, + 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */, + 51A16990235E10D600EB091F /* Settings.storyboard */, 516A09382360A2AE00EAE89B /* SettingsComboTableViewCell.swift */, 516A091D23609A3600EAE89B /* SettingsComboTableViewCell.xib */, 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */, diff --git a/iOS/Settings/ArticleThemesTableViewController.swift b/iOS/Settings/ArticleThemesTableViewController.swift index 7bc123341..1ae2ef2a3 100644 --- a/iOS/Settings/ArticleThemesTableViewController.swift +++ b/iOS/Settings/ArticleThemesTableViewController.swift @@ -13,13 +13,26 @@ import UIKit class ArticleThemesTableViewController: UITableViewController { override func viewDidLoad() { + let importBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(importTheme(_:))); + importBarButtonItem.title = NSLocalizedString("Import Theme", comment: "Import Theme"); + navigationItem.rightBarButtonItem = importBarButtonItem + NotificationCenter.default.addObserver(self, selector: #selector(articleThemeNamesDidChangeNotification(_:)), name: .ArticleThemeNamesDidChangeNotification, object: nil) } + // MARK: Notifications + @objc func articleThemeNamesDidChangeNotification(_ note: Notification) { tableView.reloadData() } + @objc func importTheme(_ sender: Any?) { + let docPicker = UIDocumentPickerViewController(documentTypes: ["com.ranchero.netnewswire.theme"], in: .import) + docPicker.delegate = self + docPicker.modalPresentationStyle = .formSheet + self.present(docPicker, animated: true) + } + // MARK: - Table view data source override func numberOfSections(in tableView: UITableView) -> Int { @@ -92,3 +105,14 @@ class ArticleThemesTableViewController: UITableViewController { return UISwipeActionsConfiguration(actions: [deleteAction]) } } + +// MARK: UIDocumentPickerDelegate + +extension ArticleThemesTableViewController: UIDocumentPickerDelegate { + + func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { + guard let url = urls.first else { return } + ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path) + } + +}