From fe5a7d185ba0b84a1d19ba2f7c80651252803c35 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Tue, 20 Dec 2022 22:04:04 +0800 Subject: [PATCH] Tidy up on the themes view --- NetNewsWire.xcodeproj/project.pbxproj | 20 - .../ArticleStyles/ArticleThemesManager.swift | 9 +- Shared/Localizations/Buttons.strings | 1 + Shared/Localizations/Errors.strings | 1 + .../LocalizedNetNewsWireError.swift | 4 + Shared/Localizations/Settings.strings | 4 +- Shared/Resources/NewsFax.nnwtheme/Info.plist | 4 +- .../Resources/Promenade.nnwtheme/Info.plist | 4 +- .../Appearance/ArticleThemeManagerView.swift | 76 +- .../ArticleThemesTableViewController.swift | 150 -- iOS/Settings/Settings.storyboard | 1347 ----------------- iOS/Settings/SettingsComboTableViewCell.swift | 30 - iOS/Settings/SettingsComboTableViewCell.xib | 48 - iOS/Settings/SettingsTableViewCell.xib | 21 - 14 files changed, 77 insertions(+), 1642 deletions(-) delete mode 100644 iOS/Settings/ArticleThemesTableViewController.swift delete mode 100644 iOS/Settings/Settings.storyboard delete mode 100644 iOS/Settings/SettingsComboTableViewCell.swift delete mode 100644 iOS/Settings/SettingsComboTableViewCell.xib delete mode 100644 iOS/Settings/SettingsTableViewCell.xib diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 0a932159a..c03c7b408 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -96,7 +96,6 @@ 510C418624E5D1B4008226FD /* ExtensionFeedAddRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51B5C87A23F2317700032075 /* ExtensionFeedAddRequest.swift */; }; 510C43F7243D035C009F70C3 /* ExtensionPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */; }; 510C43F8243D035C009F70C3 /* ExtensionPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */; }; - 510FFAB326EEA22C00F32265 /* ArticleThemesTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */; }; 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */; }; 51107746243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */; }; 51107747243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */; }; @@ -232,7 +231,6 @@ 51627A6723861DA3007B3B4B /* MasterFeedViewController+Drag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51627A6623861DA3007B3B4B /* MasterFeedViewController+Drag.swift */; }; 51627A6923861DED007B3B4B /* MasterFeedViewController+Drop.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51627A6823861DED007B3B4B /* MasterFeedViewController+Drop.swift */; }; 51627A93238A3836007B3B4B /* CroppingPreviewParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */; }; - 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */; }; 516AE9B32371C372007DEEAA /* MasterFeedTableViewSectionHeaderLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516AE9B22371C372007DEEAA /* MasterFeedTableViewSectionHeaderLayout.swift */; }; 516AE9DF2372269A007DEEAA /* IconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516AE9DE2372269A007DEEAA /* IconImage.swift */; }; 516AE9E02372269A007DEEAA /* IconImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516AE9DE2372269A007DEEAA /* IconImage.swift */; }; @@ -280,7 +278,6 @@ 519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; }; 51A052CE244FB9D7006C2024 /* AddFeedWIndowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */; }; 51A052CF244FB9D7006C2024 /* AddFeedWIndowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */; }; - 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51A16990235E10D600EB091F /* Settings.storyboard */; }; 51A66685238075AE00CB272D /* AddWebFeedDefaultContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */; }; 51A737AE24DB19730015FA66 /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 51A737AD24DB19730015FA66 /* RSCore */; }; 51A737AF24DB19730015FA66 /* RSCore in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51A737AD24DB19730015FA66 /* RSCore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -839,8 +836,6 @@ DF28B453294FE6C600C4D8CA /* EnableExtensionPointView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF28B452294FE6C600C4D8CA /* EnableExtensionPointView.swift */; }; DF28B455294FE74A00C4D8CA /* ExtensionSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF28B454294FE74A00C4D8CA /* ExtensionSectionHeader.swift */; }; DF28B4572950163F00C4D8CA /* EnableExtensionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF28B4562950163F00C4D8CA /* EnableExtensionViewModel.swift */; }; - DF32ABE829493193008E3A12 /* SettingsComboTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF32ABE629493192008E3A12 /* SettingsComboTableViewCell.swift */; }; - DF32ABE929493193008E3A12 /* SettingsComboTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF32ABE729493193008E3A12 /* SettingsComboTableViewCell.xib */; }; DF32ABEB29494CF1008E3A12 /* Settings.strings in Resources */ = {isa = PBXBuildFile; fileRef = DF32ABEA29494CF0008E3A12 /* Settings.strings */; }; DF3630EB2936183D00326FB8 /* OPMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF3630EA2936183D00326FB8 /* OPMLDocument.swift */; }; DF3630EC2936183D00326FB8 /* OPMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF3630EA2936183D00326FB8 /* OPMLDocument.swift */; }; @@ -1210,7 +1205,6 @@ 510C416624E5CDE3008226FD /* ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareExtension.entitlements; sourceTree = ""; }; 510C418724E5D2E3008226FD /* NetNewsWire_shareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_shareextension_target.xcconfig; sourceTree = ""; }; 510C43F6243D035C009F70C3 /* ExtensionPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPoint.swift; sourceTree = ""; }; - 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleThemesTableViewController.swift; sourceTree = ""; }; 51102164233A7D6C0007A5F7 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = ""; }; 51107745243BEE2500D97C8C /* ExtensionPointPreferencesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionPointPreferencesViewController.swift; sourceTree = ""; }; 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = ""; }; @@ -1273,7 +1267,6 @@ 51627A6623861DA3007B3B4B /* MasterFeedViewController+Drag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MasterFeedViewController+Drag.swift"; sourceTree = ""; }; 51627A6823861DED007B3B4B /* MasterFeedViewController+Drop.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MasterFeedViewController+Drop.swift"; sourceTree = ""; }; 51627A92238A3836007B3B4B /* CroppingPreviewParameters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CroppingPreviewParameters.swift; sourceTree = ""; }; - 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; sourceTree = ""; }; 516AE5FF246AF34100731738 /* RedditAdd.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = RedditAdd.storyboard; sourceTree = ""; }; 516AE601246AF36100731738 /* RedditSelectTypeTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditSelectTypeTableViewController.swift; sourceTree = ""; }; 516AE603246AF37B00731738 /* RedditSelectAccountTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RedditSelectAccountTableViewController.swift; sourceTree = ""; }; @@ -1308,7 +1301,6 @@ 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = ""; }; 519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedWIndowController.swift; path = AddFeed/AddFeedWIndowController.swift; sourceTree = ""; }; - 51A16990235E10D600EB091F /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; 51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddWebFeedDefaultContainer.swift; sourceTree = ""; }; 51A9A5E32380C8870033AADF /* ShareFolderPickerAccountCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareFolderPickerAccountCell.xib; sourceTree = ""; }; 51A9A5E52380C8B20033AADF /* ShareFolderPickerFolderCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ShareFolderPickerFolderCell.xib; sourceTree = ""; }; @@ -1610,8 +1602,6 @@ DF28B452294FE6C600C4D8CA /* EnableExtensionPointView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableExtensionPointView.swift; sourceTree = ""; }; DF28B454294FE74A00C4D8CA /* ExtensionSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionSectionHeader.swift; sourceTree = ""; }; DF28B4562950163F00C4D8CA /* EnableExtensionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableExtensionViewModel.swift; sourceTree = ""; }; - DF32ABE629493192008E3A12 /* SettingsComboTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsComboTableViewCell.swift; sourceTree = ""; }; - DF32ABE729493193008E3A12 /* SettingsComboTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsComboTableViewCell.xib; sourceTree = ""; }; DF32ABEA29494CF0008E3A12 /* Settings.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Settings.strings; sourceTree = ""; }; DF3630EA2936183D00326FB8 /* OPMLDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLDocument.swift; sourceTree = ""; }; DF3630EE293618A900326FB8 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; @@ -2041,11 +2031,6 @@ DF3630E92936038400326FB8 /* New Article Notifications */, DF766FEA2936337A006FBBE2 /* Help */, 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */, - 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */, - 51A16990235E10D600EB091F /* Settings.storyboard */, - DF32ABE629493192008E3A12 /* SettingsComboTableViewCell.swift */, - DF32ABE729493193008E3A12 /* SettingsComboTableViewCell.xib */, - 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */, ); path = Settings; sourceTree = ""; @@ -3604,14 +3589,12 @@ DFB3499A294C4F1D00BC81AD /* Errors.strings in Resources */, 51D0214826ED617100FF2E0F /* core.css in Resources */, 84C9FCA42262A1B800D921D6 /* LaunchScreenPhone.storyboard in Resources */, - 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */, 511D43D1231FA62800FB1562 /* SidebarKeyboardShortcuts.plist in Resources */, 51C452AB22650DC600C03939 /* template.html in Resources */, 84A3EE61223B667F00557320 /* DefaultFeeds.opml in Resources */, B27EEBFB244D15F3000932E6 /* stylesheet.css in Resources */, DFB34984294B3AFF00BC81AD /* Buttons.strings in Resources */, 511D43CF231FA62200FB1562 /* DetailKeyboardShortcuts.plist in Resources */, - 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */, 49F40DF92335B71000552BF4 /* newsfoot.js in Resources */, 512392C024E33A3C00F11704 /* RedditAdd.storyboard in Resources */, 5177C21327B07CFE00643901 /* NewsFax.nnwtheme in Resources */, @@ -3620,7 +3603,6 @@ DFCE4F9528EF278300405869 /* Thanks.md in Resources */, 51DEE81426FB9233006DAA56 /* Appanoose.nnwtheme in Resources */, 51E36E8C239D6765006F47A5 /* AddFeedSelectFolderTableViewCell.xib in Resources */, - DF32ABE929493193008E3A12 /* SettingsComboTableViewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4200,7 +4182,6 @@ 51EAED96231363EF00A9EEE3 /* NonIntrinsicButton.swift in Sources */, 51C4527B2265091600C03939 /* MasterUnreadIndicatorView.swift in Sources */, 5186A635235EF3A800C97195 /* VibrantLabel.swift in Sources */, - DF32ABE829493193008E3A12 /* SettingsComboTableViewCell.swift in Sources */, 51F85BF92274AA7B00C787DC /* UIBarButtonItem-Extensions.swift in Sources */, 51B62E68233186730085F949 /* IconView.swift in Sources */, 179D280D26F73D83003B2E0A /* ArticleThemePlist.swift in Sources */, @@ -4371,7 +4352,6 @@ 51627A6723861DA3007B3B4B /* MasterFeedViewController+Drag.swift in Sources */, 51FFF0C4235EE8E5002762AA /* VibrantButton.swift in Sources */, 51C45259226508D300C03939 /* AppDefaults.swift in Sources */, - 510FFAB326EEA22C00F32265 /* ArticleThemesTableViewController.swift in Sources */, 511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */, 51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */, 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */, diff --git a/Shared/ArticleStyles/ArticleThemesManager.swift b/Shared/ArticleStyles/ArticleThemesManager.swift index 80b38d293..8692047ad 100644 --- a/Shared/ArticleStyles/ArticleThemesManager.swift +++ b/Shared/ArticleStyles/ArticleThemesManager.swift @@ -93,6 +93,7 @@ final class ArticleThemesManager: NSObject, NSFilePresenter, Logging, Observable func themeExists(filename: String) -> Bool { let filenameLastPathComponent = (filename as NSString).lastPathComponent let toFilename = (folderPath as NSString).appendingPathComponent(filenameLastPathComponent) + logger.debug("\(filenameLastPathComponent), \(toFilename)") return FileManager.default.fileExists(atPath: toFilename) } @@ -130,8 +131,12 @@ final class ArticleThemesManager: NSObject, NSFilePresenter, Logging, Observable func deleteTheme(themeName: String) { if let filename = pathForThemeName(themeName, folder: folderPath) { - try? FileManager.default.removeItem(atPath: filename) - objectWillChange.send() + do { + try FileManager.default.removeItem(atPath: filename) + } catch { + logger.error("\(error.localizedDescription)") + } + } } diff --git a/Shared/Localizations/Buttons.strings b/Shared/Localizations/Buttons.strings index e4f9cf191..27b69d9fa 100644 --- a/Shared/Localizations/Buttons.strings +++ b/Shared/Localizations/Buttons.strings @@ -19,3 +19,4 @@ "USE_CLOUDKIT_BUTTON_TITLE" = "Use iCloud"; "DELETE_THEME_BUTTON_TITLE" = "Delete Theme"; "IMPORT_THEME_BUTTON_TITLE" = "Import Theme"; +"IMPORT_AND_OVERWRITE_THEME_BUTTON_TITLE" = "Overwrite Existing Theme"; diff --git a/Shared/Localizations/Errors.strings b/Shared/Localizations/Errors.strings index 9a0312549..40d454828 100644 --- a/Shared/Localizations/Errors.strings +++ b/Shared/Localizations/Errors.strings @@ -12,3 +12,4 @@ "USERNAME_AND_PASSWORD_REQUIRED" = "Username and password required."; "INVALID_USERNAME_PASSWORD" = "Invalid email or password combination."; "KEYCHAIN_ERROR" = "Keychain error while storing credentials."; +"DUPLICATE_DEFAULT_THEME" = "You cannot import a theme that shares the same name as a provided theme."; diff --git a/Shared/Localizations/LocalizedNetNewsWireError.swift b/Shared/Localizations/LocalizedNetNewsWireError.swift index c67974f50..18a03ab34 100644 --- a/Shared/Localizations/LocalizedNetNewsWireError.swift +++ b/Shared/Localizations/LocalizedNetNewsWireError.swift @@ -24,6 +24,8 @@ public enum LocalizedNetNewsWireError: LocalizedError { case invalidUsernameOrPassword case keychainError + + case duplicateDefaultTheme public var errorDescription: String? { switch self { @@ -37,6 +39,8 @@ public enum LocalizedNetNewsWireError: LocalizedError { return Bundle.main.localizedString(forKey: "INVALID_USERNAME_PASSWORD", value: nil, table: "Errors") case .keychainError: return Bundle.main.localizedString(forKey: "KEYCHAIN_ERROR", value: nil, table: "Errors") + case .duplicateDefaultTheme: + return Bundle.main.localizedString(forKey: "DUPLICATE_DEFAULT_THEME", value: nil, table: "Errors") } } } diff --git a/Shared/Localizations/Settings.strings b/Shared/Localizations/Settings.strings index 243f0cf30..03978d47e 100644 --- a/Shared/Localizations/Settings.strings +++ b/Shared/Localizations/Settings.strings @@ -46,10 +46,12 @@ "INSTALLED_THEMES" = "Installed Themes"; "ARTICLE_THEMES_TITLE" = "Article Themes"; "ARTICLE_THEME" = "Article Theme"; +"ARTICLE_THEME_CREATOR_%@" = "by %@"; "IMPORT_THEME_CONFIRMATION_TITLE" = "Import Theme"; "IMPORT_THEME_CONFIRMATION_MESSAGE_%@_%@" = "Are you sure you want to import “%@” by %@?"; +"IMPORT_AND_OVERWRITE_THEME_CONFIRMATION_MESSAGE_%@" = "The theme “%@” already exists. Do you want to overwrite it?"; "IMPORT_THEME_SUCCESS_TITLE" = "Import Successful"; -"IMPORT_THEME_SUCCESS_MESSAGE_%@" = "“%@” has been imported successfully."; +"IMPORT_THEME_SUCCESS_MESSAGE_%@" = "The theme “%@” has been imported."; "DELETE_THEME_ALERT_TITLE_%@" = "Are you sure you want to delete “%@”?"; "DELETE_THEME_ALERT_MESSAGE" = "Are you sure you want to delete this theme? This action is not reversible."; "CONFIRM_MARK_ALL_AS_READ" = "Confirm Mark All as Read"; diff --git a/Shared/Resources/NewsFax.nnwtheme/Info.plist b/Shared/Resources/NewsFax.nnwtheme/Info.plist index 68e2fb253..39ec987b7 100644 --- a/Shared/Resources/NewsFax.nnwtheme/Info.plist +++ b/Shared/Resources/NewsFax.nnwtheme/Info.plist @@ -7,9 +7,9 @@ ThemeIdentifier com.mynameisstuart.themes.newsfax CreatorHomePage - https://mynameisstuart.com/ + https://stuartbreckenridge.net/ CreatorName - Stuart Breckenridge + Ranchero Software Version 3 diff --git a/Shared/Resources/Promenade.nnwtheme/Info.plist b/Shared/Resources/Promenade.nnwtheme/Info.plist index 24ec5ca47..8baa4f763 100644 --- a/Shared/Resources/Promenade.nnwtheme/Info.plist +++ b/Shared/Resources/Promenade.nnwtheme/Info.plist @@ -7,9 +7,9 @@ ThemeIdentifier com.mynameisstuart.themes.promenade CreatorHomePage - https://mynameisstuart.com/ + https://stuartbreckenridge.net/ CreatorName - Stuart Breckenridge + Ranchero Software Version 14 diff --git a/iOS/Settings/Appearance/ArticleThemeManagerView.swift b/iOS/Settings/Appearance/ArticleThemeManagerView.swift index d8ac8fedb..566f012a0 100644 --- a/iOS/Settings/Appearance/ArticleThemeManagerView.swift +++ b/iOS/Settings/Appearance/ArticleThemeManagerView.swift @@ -44,7 +44,7 @@ struct ArticleThemeManagerView: View { switch result { case .success(let success): do { - let theme = try ArticleTheme(path: success.path, isAppTheme: true) + let theme = try ArticleTheme(path: success.path, isAppTheme: false) showImportConfirmationAlert = (theme, true) } catch { showImportErrorAlert = (error, true) @@ -55,7 +55,7 @@ struct ArticleThemeManagerView: View { } .alert(Text("DELETE_THEME_ALERT_TITLE_\(showDeleteConfirmation.0)", tableName: "Settings"), isPresented: $showDeleteConfirmation.1, actions: { Button(role: .destructive) { - ArticleThemesManager.shared.deleteTheme(themeName: showDeleteConfirmation.0) + themeManager.deleteTheme(themeName: showDeleteConfirmation.0) } label: { Text("DELETE_THEME_BUTTON_TITLE", tableName: "Buttons") } @@ -73,14 +73,27 @@ struct ArticleThemeManagerView: View { actions: { Button { do { - try ArticleThemesManager.shared.importTheme(filename: showImportConfirmationAlert.0!.path!) - showImportSuccessAlert = true + if themeManager.themeExists(filename: showImportConfirmationAlert.0!.path!) { + if try! themeManager.articleThemeWithThemeName(showImportConfirmationAlert.0!.name).isAppTheme { + showImportErrorAlert = (LocalizedNetNewsWireError.duplicateDefaultTheme, true) + } else { + try themeManager.importTheme(filename: showImportConfirmationAlert.0!.path!) + showImportSuccessAlert = true + } + } else { + try themeManager.importTheme(filename: showImportConfirmationAlert.0!.path!) + showImportSuccessAlert = true + } } catch { showImportErrorAlert = (error, true) } - } label: { - Text("IMPORT_THEME_BUTTON_TITLE", tableName: "Buttons") + let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "") + if exists == true { + Text("IMPORT_AND_OVERWRITE_THEME_BUTTON_TITLE", tableName: "Buttons") + } else { + Text("IMPORT_THEME_BUTTON_TITLE", tableName: "Buttons") + } } Button(role: .cancel) { @@ -89,7 +102,12 @@ struct ArticleThemeManagerView: View { Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") } }, message: { - Text("IMPORT_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")_\(showImportConfirmationAlert.0?.creatorName ?? "")", tableName: "Settings") + let exists = themeManager.themeExists(filename: showImportConfirmationAlert.0?.path ?? "") + if exists { + Text("IMPORT_AND_OVERWRITE_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")", tableName: "Settings") + } else { + Text("IMPORT_THEME_CONFIRMATION_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")_\(showImportConfirmationAlert.0?.creatorName ?? "")", tableName: "Settings") + } }) .alert(Text("IMPORT_THEME_SUCCESS_TITLE", tableName: "Settings"), isPresented: $showImportSuccessAlert, @@ -102,32 +120,52 @@ struct ArticleThemeManagerView: View { }, message: { Text("IMPORT_THEME_SUCCESS_MESSAGE_\(showImportConfirmationAlert.0?.name ?? "")", tableName: "Settings") }) + .alert(Text("ERROR_TITLE", tableName: "Errors"), + isPresented: $showImportErrorAlert.1, + actions: { + Button(role: .cancel) { + + } label: { + Text("DISMISS_BUTTON_TITLE", tableName: "Buttons") + } + }, message: { + Text("\(showImportErrorAlert.0?.localizedDescription ?? "")") + }) } func articleThemeRow(_ theme: String) -> some View { Button { - ArticleThemesManager.shared.currentThemeName = theme + themeManager.currentThemeName = theme } label: { HStack { - Text(theme) - .foregroundColor(.primary) + VStack(alignment: .leading) { + Text(theme) + .foregroundColor(.primary) + if let articleTheme = try? themeManager.articleThemeWithThemeName(theme) { + Text("ARTICLE_THEME_CREATOR_\(articleTheme.creatorName)", tableName: "Settings") + .font(.caption) + .foregroundColor(.secondary) + } + } Spacer() - if ArticleThemesManager.shared.currentThemeName == theme { + if themeManager.currentThemeName == theme { Image(systemName: "checkmark") .foregroundColor(Color(uiColor: AppAssets.primaryAccentColor)) } } } .swipeActions(edge: .trailing, allowsFullSwipe: false) { - if theme == "Default" || ArticleThemesManager.shared.currentThemeName == theme { } - else { - Button { - showDeleteConfirmation = (theme, true) - } label: { - Text("DELETE_BUTTON_TITLE", tableName: "Buttons") - Image(systemName: "trash") + if theme == themeManager.currentThemeName { } + if let currentTheme = try? themeManager.articleThemeWithThemeName(theme) { + if currentTheme.isAppTheme { } else { + Button { + showDeleteConfirmation = (theme, true) + } label: { + Text("DELETE_BUTTON_TITLE", tableName: "Buttons") + Image(systemName: "trash") + } + .tint(.red) } - .tint(.red) } } } diff --git a/iOS/Settings/ArticleThemesTableViewController.swift b/iOS/Settings/ArticleThemesTableViewController.swift deleted file mode 100644 index 85bd60806..000000000 --- a/iOS/Settings/ArticleThemesTableViewController.swift +++ /dev/null @@ -1,150 +0,0 @@ -// -// ArticleThemesTableViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 9/12/21. -// Copyright © 2021 Ranchero Software. All rights reserved. -// - -import Foundation -import UniformTypeIdentifiers -import RSCore -import UIKit -import SwiftUI - -struct ArticleThemesWrapper: UIViewControllerRepresentable { - func makeUIViewController(context: Context) -> ArticleThemesTableViewController { - let storyboard = UIStoryboard(name: "Settings", bundle: .main) - let controller = storyboard.instantiateViewController(withIdentifier: "ArticleThemesTableViewController") as! ArticleThemesTableViewController - - context.coordinator.parentObserver = controller.observe(\.parent, changeHandler: { vc, _ in - vc.parent?.title = vc.title - vc.parent?.navigationItem.rightBarButtonItems = vc.navigationItem.rightBarButtonItems - }) - - return controller - } - - func updateUIViewController(_ uiViewController: ArticleThemesTableViewController, context: Context) { - // - } - - typealias UIViewControllerType = ArticleThemesTableViewController - - class Coordinator { - var parentObserver: NSKeyValueObservation? - } - - func makeCoordinator() -> Self.Coordinator { Coordinator() } - -} - - - -class ArticleThemesTableViewController: UITableViewController, Logging { - - 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(forOpeningContentTypes: [.nnwTheme], asCopy: true) - docPicker.delegate = self - docPicker.modalPresentationStyle = .formSheet - self.present(docPicker, animated: true) - } - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return ArticleThemesManager.shared.themeNames.count + 1 - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - - let themeName: String - if indexPath.row == 0 { - themeName = ArticleTheme.defaultTheme.name - } else { - themeName = ArticleThemesManager.shared.themeNames[indexPath.row - 1] - } - - cell.textLabel?.text = themeName - if themeName == ArticleThemesManager.shared.currentTheme.name { - cell.accessoryType = .checkmark - } else { - cell.accessoryType = .none - } - - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let cell = tableView.cellForRow(at: indexPath), let themeName = cell.textLabel?.text else { return } - ArticleThemesManager.shared.currentThemeName = themeName - navigationController?.popViewController(animated: true) - } - - override func tableView(_ tableView: UITableView, trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? { - guard let cell = tableView.cellForRow(at: indexPath), - let themeName = cell.textLabel?.text else { return nil } - - guard let theme = try? ArticleThemesManager.shared.articleThemeWithThemeName(themeName), !theme.isAppTheme else { return nil } - - let deleteTitle = NSLocalizedString("Delete", comment: "Delete") - let deleteAction = UIContextualAction(style: .normal, title: deleteTitle) { [weak self] (action, view, completion) in - let title = NSLocalizedString("Delete Theme?", comment: "Delete Theme") - - let localizedMessageText = NSLocalizedString("Are you sure you want to delete the theme “%@”?.", comment: "Delete Theme Message") - let message = NSString.localizedStringWithFormat(localizedMessageText as NSString, themeName) as String - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) { action in - completion(true) - } - alertController.addAction(cancelAction) - - let deleteTitle = NSLocalizedString("Delete", comment: "Delete") - let deleteAction = UIAlertAction(title: deleteTitle, style: .destructive) { action in - ArticleThemesManager.shared.deleteTheme(themeName: themeName) - completion(true) - } - alertController.addAction(deleteAction) - - self?.present(alertController, animated: true) - } - - deleteAction.image = AppAssets.trashImage - deleteAction.backgroundColor = UIColor.systemRed - - return UISwipeActionsConfiguration(actions: [deleteAction]) - } -} - -// MARK: UIDocumentPickerDelegate - -extension ArticleThemesTableViewController: UIDocumentPickerDelegate { - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - guard let url = urls.first else { return } - try ArticleThemeImporter.importTheme(controller: self, filename: url.standardizedFileURL.path) - } - -} diff --git a/iOS/Settings/Settings.storyboard b/iOS/Settings/Settings.storyboard deleted file mode 100644 index 2718d31a0..000000000 --- a/iOS/Settings/Settings.storyboard +++ /dev/null @@ -1,1347 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Settings/SettingsComboTableViewCell.swift b/iOS/Settings/SettingsComboTableViewCell.swift deleted file mode 100644 index 9e0200a27..000000000 --- a/iOS/Settings/SettingsComboTableViewCell.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// SettingsAccountTableViewCell.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 10/23/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit - -class SettingsComboTableViewCell: VibrantTableViewCell { - - @IBOutlet weak var comboImage: UIImageView! - @IBOutlet weak var comboNameLabel: UILabel! - - override func updateVibrancy(animated: Bool) { - super.updateVibrancy(animated: animated) - updateLabelVibrancy(comboNameLabel, color: labelColor, animated: animated) - - let tintColor = isHighlighted || isSelected ? AppAssets.vibrantTextColor : UIColor.label - if animated { - UIView.animate(withDuration: Self.duration) { - self.comboImage?.tintColor = tintColor - } - } else { - self.comboImage?.tintColor = tintColor - } - } - -} diff --git a/iOS/Settings/SettingsComboTableViewCell.xib b/iOS/Settings/SettingsComboTableViewCell.xib deleted file mode 100644 index 4cf193f27..000000000 --- a/iOS/Settings/SettingsComboTableViewCell.xib +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Settings/SettingsTableViewCell.xib b/iOS/Settings/SettingsTableViewCell.xib deleted file mode 100644 index 27afad7ce..000000000 --- a/iOS/Settings/SettingsTableViewCell.xib +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - - -