From 369c346139a65bbd54b84b074991ef4f379c30f6 Mon Sep 17 00:00:00 2001 From: Stuart Breckenridge Date: Wed, 14 Dec 2022 07:15:22 +0800 Subject: [PATCH] Changes - Removes unused classes - Posts a notification when the app is opened via external context which allows the SwiftUI SettingsView to dismiss itself. --- NetNewsWire.xcodeproj/project.pbxproj | 32 +- Shared/AppNotifications.swift | 1 + iOS/SceneCoordinator.swift | 7 +- .../ColorPaletteTableViewController.swift | 42 -- iOS/Settings/NotificationsTableViewCell.swift | 61 --- .../NotificationsViewController.swift | 335 ------------ iOS/Settings/SettingsViewController.swift | 515 ------------------ iOS/Settings/Views/General/SettingsView.swift | 4 + 8 files changed, 18 insertions(+), 979 deletions(-) delete mode 100644 iOS/Settings/ColorPaletteTableViewController.swift delete mode 100644 iOS/Settings/NotificationsTableViewCell.swift delete mode 100644 iOS/Settings/NotificationsViewController.swift delete mode 100644 iOS/Settings/SettingsViewController.swift diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 01ae9b8c4..b35b41a75 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -235,12 +235,9 @@ 515A5181243E90260089E588 /* ExtensionPointIdentifer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515A5176243E90200089E588 /* ExtensionPointIdentifer.swift */; }; 515D4FCA23257CB500EE1167 /* Node-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97971ED9EFAA007D329B /* Node-Extensions.swift */; }; 515D4FCC2325815A00EE1167 /* SafariExt.js in Resources */ = {isa = PBXBuildFile; fileRef = 515D4FCB2325815A00EE1167 /* SafariExt.js */; }; - 516244E3241E19F000B61C47 /* ColorPaletteTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516244E2241E19F000B61C47 /* ColorPaletteTableViewController.swift */; }; 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 */; }; - 516A093723609A3600EAE89B /* SettingsComboTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 516A091D23609A3600EAE89B /* SettingsComboTableViewCell.xib */; }; - 516A09392360A2AE00EAE89B /* SettingsComboTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 516A09382360A2AE00EAE89B /* SettingsComboTableViewCell.swift */; }; 516A093B2360A4A000EAE89B /* SettingsTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */; }; 516A09402361240900EAE89B /* Account.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 516A093F2361240900EAE89B /* Account.storyboard */; }; 516A09422361248000EAE89B /* Inspector.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 516A09412361248000EAE89B /* Inspector.storyboard */; }; @@ -298,7 +295,6 @@ 51A1699A235E10D700EB091F /* Settings.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 51A16990235E10D600EB091F /* Settings.storyboard */; }; 51A1699B235E10D700EB091F /* AccountInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16991235E10D600EB091F /* AccountInspectorViewController.swift */; }; 51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16992235E10D600EB091F /* AddAccountViewController.swift */; }; - 51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16993235E10D600EB091F /* SettingsViewController.swift */; }; 51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */; }; 51A66685238075AE00CB272D /* AddWebFeedDefaultContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */; }; 51A737AE24DB19730015FA66 /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 51A737AD24DB19730015FA66 /* RSCore */; }; @@ -853,6 +849,8 @@ DDF9E1D728EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */; }; DDF9E1D828EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */; }; DDF9E1D928EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */ = {isa = PBXBuildFile; fileRef = DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */; }; + DF32ABE829493193008E3A12 /* SettingsComboTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF32ABE629493192008E3A12 /* SettingsComboTableViewCell.swift */; }; + DF32ABE929493193008E3A12 /* SettingsComboTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF32ABE729493193008E3A12 /* SettingsComboTableViewCell.xib */; }; DF3630EB2936183D00326FB8 /* OPMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF3630EA2936183D00326FB8 /* OPMLDocument.swift */; }; DF3630EC2936183D00326FB8 /* OPMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF3630EA2936183D00326FB8 /* OPMLDocument.swift */; }; DF3630ED2936183D00326FB8 /* OPMLDocument.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF3630EA2936183D00326FB8 /* OPMLDocument.swift */; }; @@ -880,8 +878,6 @@ DFD406FC291FB63B00C02962 /* SettingsHelpSheets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFD406FB291FB63B00C02962 /* SettingsHelpSheets.swift */; }; DFD406FF291FDC0C00C02962 /* DisplayAndBehaviorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFD406FE291FDC0C00C02962 /* DisplayAndBehaviorsView.swift */; }; DFFB8FC2279B75E300AC21D7 /* Account in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 51BC2F4A24D343A500E90810 /* Account */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - DFFC199827A0D0D7004B7AEF /* NotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */; }; - DFFC199A27A0D32A004B7AEF /* NotificationsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */; }; DFFC4E7428E95C01006B82AF /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFFC4E7328E95C01006B82AF /* AboutView.swift */; }; FF3ABF13232599810074C542 /* ArticleSorterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF09232599450074C542 /* ArticleSorterTests.swift */; }; FF3ABF1523259DDB0074C542 /* ArticleSorter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */; }; @@ -1268,12 +1264,9 @@ 515D4FCB2325815A00EE1167 /* SafariExt.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = SafariExt.js; sourceTree = ""; }; 515D4FCD2325909200EE1167 /* NetNewsWire_iOS_ShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = NetNewsWire_iOS_ShareExtension.entitlements; sourceTree = ""; }; 515D4FCE2325B3D000EE1167 /* NetNewsWire_iOSshareextension_target.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSshareextension_target.xcconfig; sourceTree = ""; }; - 516244E2241E19F000B61C47 /* ColorPaletteTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPaletteTableViewController.swift; sourceTree = ""; }; 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 = ""; }; - 516A091D23609A3600EAE89B /* SettingsComboTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsComboTableViewCell.xib; sourceTree = ""; }; - 516A09382360A2AE00EAE89B /* SettingsComboTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsComboTableViewCell.swift; sourceTree = ""; }; 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SettingsTableViewCell.xib; sourceTree = ""; }; 516A093F2361240900EAE89B /* Account.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Account.storyboard; sourceTree = ""; }; 516A09412361248000EAE89B /* Inspector.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Inspector.storyboard; sourceTree = ""; }; @@ -1318,7 +1311,6 @@ 51A16990235E10D600EB091F /* Settings.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Settings.storyboard; sourceTree = ""; }; 51A16991235E10D600EB091F /* AccountInspectorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountInspectorViewController.swift; sourceTree = ""; }; 51A16992235E10D600EB091F /* AddAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = ""; }; - 51A16993235E10D600EB091F /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FeedbinAccountViewController.swift; 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 = ""; }; @@ -1616,6 +1608,8 @@ D5F4EDB820074D7C00B9E363 /* Folder+Scriptability.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Folder+Scriptability.swift"; sourceTree = ""; }; DD82AB09231003F6002269DF /* SharingTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SharingTests.swift; sourceTree = ""; }; DDF9E1D628EDF2FC000BC355 /* notificationSoundBlip.mp3 */ = {isa = PBXFileReference; lastKnownFileType = audio.mp3; path = notificationSoundBlip.mp3; 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 = ""; }; DF3630EA2936183D00326FB8 /* OPMLDocument.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OPMLDocument.swift; sourceTree = ""; }; DF3630EE293618A900326FB8 /* SettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; DF394EFF29357A180081EB6E /* NewArticleNotificationsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewArticleNotificationsView.swift; sourceTree = ""; }; @@ -1636,8 +1630,6 @@ DFD406FB291FB63B00C02962 /* SettingsHelpSheets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsHelpSheets.swift; sourceTree = ""; }; DFD406FE291FDC0C00C02962 /* DisplayAndBehaviorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayAndBehaviorsView.swift; sourceTree = ""; }; DFD6AACB27ADE80900463FAD /* NewsFax.nnwtheme */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = NewsFax.nnwtheme; sourceTree = ""; }; - DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsViewController.swift; sourceTree = ""; }; - DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationsTableViewCell.swift; sourceTree = ""; }; DFFC4E7328E95C01006B82AF /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = ""; }; FF3ABF09232599450074C542 /* ArticleSorterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorterTests.swift; sourceTree = ""; }; FF3ABF1423259DDB0074C542 /* ArticleSorter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleSorter.swift; sourceTree = ""; }; @@ -2031,17 +2023,13 @@ 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */, 5137C2E926F63AE6009EFEDB /* ArticleThemeImporter.swift */, 510FFAB226EEA22C00F32265 /* ArticleThemesTableViewController.swift */, - 516244E2241E19F000B61C47 /* ColorPaletteTableViewController.swift */, 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */, 51A16990235E10D600EB091F /* Settings.storyboard */, - 516A09382360A2AE00EAE89B /* SettingsComboTableViewCell.swift */, - 516A091D23609A3600EAE89B /* SettingsComboTableViewCell.xib */, + DF32ABE629493192008E3A12 /* SettingsComboTableViewCell.swift */, + DF32ABE729493193008E3A12 /* SettingsComboTableViewCell.xib */, 516A093A2360A4A000EAE89B /* SettingsTableViewCell.xib */, - 51A16993235E10D600EB091F /* SettingsViewController.swift */, 5108F6D12375EED2001ABC45 /* TimelineCustomizerViewController.swift */, 5108F6D32375EEEF001ABC45 /* TimelinePreviewTableViewController.swift */, - DFFC199727A0D0D7004B7AEF /* NotificationsViewController.swift */, - DFFC199927A0D32A004B7AEF /* NotificationsTableViewCell.swift */, ); path = Settings; sourceTree = ""; @@ -3545,7 +3533,6 @@ 84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */, 51BB7C312335ACDE008E8144 /* page.html in Resources */, 512392C324E3451400F11704 /* TwitterAdd.storyboard in Resources */, - 516A093723609A3600EAE89B /* SettingsComboTableViewCell.xib in Resources */, 51077C5A27A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */, 516A09422361248000EAE89B /* Inspector.storyboard in Resources */, DDF9E1D928EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */, @@ -3570,6 +3557,7 @@ DFCE4F9528EF278300405869 /* Thanks.md in Resources */, 51DEE81426FB9233006DAA56 /* Appanoose.nnwtheme in Resources */, 51E36E8C239D6765006F47A5 /* AddFeedSelectFolderTableViewCell.xib in Resources */, + DF32ABE929493193008E3A12 /* SettingsComboTableViewCell.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -4139,12 +4127,12 @@ 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */, B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */, 518ED21D23D0F26000E0A862 /* UIViewController-Extensions.swift in Sources */, - DFFC199827A0D0D7004B7AEF /* NotificationsViewController.swift in Sources */, DFD406FF291FDC0C00C02962 /* DisplayAndBehaviorsView.swift in Sources */, 51A9A5F52380F6A60033AADF /* ModalNavigationController.swift in Sources */, 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 */, @@ -4152,7 +4140,6 @@ 51C45291226509C800C03939 /* SmartFeed.swift in Sources */, 51C452A722650A3D00C03939 /* RSImage-Extensions.swift in Sources */, 511B9807237DCAC90028BCAA /* UserInfoKey.swift in Sources */, - DFFC199A27A0D32A004B7AEF /* NotificationsTableViewCell.swift in Sources */, 51C45269226508F600C03939 /* MasterFeedTableViewCell.swift in Sources */, 51F85BFD2275DCA800C787DC /* SingleLineUILabelSizer.swift in Sources */, 517630232336657E00E15FFF /* WebViewProvider.swift in Sources */, @@ -4167,7 +4154,6 @@ 51AB8AB323B7F4C6008F147D /* WebViewController.swift in Sources */, DFD406F7291FB1A600C02962 /* SafariView.swift in Sources */, DF3630ED2936183D00326FB8 /* OPMLDocument.swift in Sources */, - 516A09392360A2AE00EAE89B /* SettingsComboTableViewCell.swift in Sources */, 176813D22564BA5900D98635 /* WidgetDataEncoder.swift in Sources */, 51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */, 51A1699C235E10D700EB091F /* AddAccountViewController.swift in Sources */, @@ -4218,7 +4204,6 @@ 5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */, 51C4529D22650A1000C03939 /* FaviconURLFinder.swift in Sources */, 5142192A23522B5500E07E2C /* ImageViewController.swift in Sources */, - 516244E3241E19F000B61C47 /* ColorPaletteTableViewController.swift in Sources */, 51C45258226508CF00C03939 /* AppAssets.swift in Sources */, 51FA73A82332BE880090D516 /* ExtractedArticle.swift in Sources */, 51C4527C2265091600C03939 /* MasterTimelineDefaultCellLayout.swift in Sources */, @@ -4317,7 +4302,6 @@ 51C45259226508D300C03939 /* AppDefaults.swift in Sources */, 510FFAB326EEA22C00F32265 /* ArticleThemesTableViewController.swift in Sources */, 511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */, - 51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */, 51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */, 51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */, 769F2ED513DA03EE75B993A8 /* NewsBlurAccountViewController.swift in Sources */, diff --git a/Shared/AppNotifications.swift b/Shared/AppNotifications.swift index 84cfd9a72..fb470ad12 100644 --- a/Shared/AppNotifications.swift +++ b/Shared/AppNotifications.swift @@ -12,6 +12,7 @@ import Articles extension Notification.Name { static let InspectableObjectsDidChange = Notification.Name("TimelineSelectionDidChangeNotification") static let UserDidAddFeed = Notification.Name("UserDidAddFeedNotification") + static let LaunchedFromExternalAction = Notification.Name("LaunchedFromExternalAction") #if !MAC_APP_STORE static let WebInspectorEnabledDidChange = Notification.Name("WebInspectorEnabledDidChange") diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index e57db0edf..8fe3259af 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1326,8 +1326,11 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging { if presentedController.isKind(of: SFSafariViewController.self) { presentedController.dismiss(animated: true, completion: nil) } - guard let settings = presentedController.children.first as? SettingsViewController else { return } - settings.dismiss(animated: true, completion: nil) + + // There's no obvious way to detect if the presented controller + // is the SwiftUI UIHostingController. Posting a notification + // which it can react to seems to be the simplest solution. + NotificationCenter.default.post(name: .LaunchedFromExternalAction, object: nil) } } diff --git a/iOS/Settings/ColorPaletteTableViewController.swift b/iOS/Settings/ColorPaletteTableViewController.swift deleted file mode 100644 index d64671c6f..000000000 --- a/iOS/Settings/ColorPaletteTableViewController.swift +++ /dev/null @@ -1,42 +0,0 @@ -// -// ColorPaletteTableViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 3/15/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import UIKit - -class ColorPaletteTableViewController: UITableViewController { - - // MARK: - Table view data source - - override func numberOfSections(in tableView: UITableView) -> Int { - return 1 - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return UserInterfaceColorPalette.allCases.count - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) - let rowColorPalette = UserInterfaceColorPalette.allCases[indexPath.row] - cell.textLabel?.text = String(describing: rowColorPalette) - if rowColorPalette == AppDefaults.userInterfaceColorPalette { - cell.accessoryType = .checkmark - } else { - cell.accessoryType = .none - } - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if let colorPalette = UserInterfaceColorPalette(rawValue: indexPath.row) { - AppDefaults.userInterfaceColorPalette = colorPalette - } - navigationController?.popViewController(animated: true) - } - -} diff --git a/iOS/Settings/NotificationsTableViewCell.swift b/iOS/Settings/NotificationsTableViewCell.swift deleted file mode 100644 index 3e3683ccf..000000000 --- a/iOS/Settings/NotificationsTableViewCell.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// NotificationsTableViewCell.swift -// NetNewsWire-iOS -// -// Created by Stuart Breckenridge on 26/01/2022. -// Copyright © 2022 Ranchero Software. All rights reserved. -// - -import UIKit -import Account -import UserNotifications - - -class NotificationsTableViewCell: VibrantBasicTableViewCell { - - @IBOutlet weak var notificationsSwitch: UISwitch! - @IBOutlet weak var notificationsLabel: UILabel! - @IBOutlet weak var notificationsImageView: UIImageView! - weak var feed: WebFeed? - - - override func awakeFromNib() { - super.awakeFromNib() - // Initialization code - } - - override func setSelected(_ selected: Bool, animated: Bool) { - super.setSelected(selected, animated: animated) - - // Configure the view for the selected state - } - - func configure(_ webFeed: WebFeed) { - self.feed = webFeed - var isOn = false - if webFeed.isNotifyAboutNewArticles == nil { - isOn = false - } else { - isOn = webFeed.isNotifyAboutNewArticles! - } - notificationsSwitch.isOn = isOn - notificationsSwitch.addTarget(self, action: #selector(toggleWebFeedNotification(_:)), for: .touchUpInside) - notificationsLabel.text = webFeed.nameForDisplay - notificationsImageView.image = IconImageCache.shared.imageFor(webFeed.feedID!)?.image - notificationsImageView.layer.cornerRadius = 4 - } - - @objc - private func toggleWebFeedNotification(_ sender: Any) { - guard let feed = feed else { - return - } - if feed.isNotifyAboutNewArticles == nil { - feed.isNotifyAboutNewArticles = true - } - else { - feed.isNotifyAboutNewArticles!.toggle() - } - } - -} diff --git a/iOS/Settings/NotificationsViewController.swift b/iOS/Settings/NotificationsViewController.swift deleted file mode 100644 index 64387f718..000000000 --- a/iOS/Settings/NotificationsViewController.swift +++ /dev/null @@ -1,335 +0,0 @@ -// -// NotificationsViewController.swift -// NetNewsWire-iOS -// -// Created by Stuart Breckenridge on 26/01/2022. -// Copyright © 2022 Ranchero Software. All rights reserved. -// - -import UIKit -import SwiftUI -import Account -import UserNotifications - -struct NotificationsViewControllerRepresentable: UIViewControllerRepresentable { - func makeUIViewController(context: Context) -> NotificationsViewController { - let storyboard = UIStoryboard(name: "Settings", bundle: .main) - let controller = storyboard.instantiateViewController(withIdentifier: "NotificationsViewController") as! NotificationsViewController - - 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: NotificationsViewController, context: Context) { - // - } - - typealias UIViewControllerType = NotificationsViewController - - class Coordinator { - var parentObserver: NSKeyValueObservation? - } - - func makeCoordinator() -> Self.Coordinator { Coordinator() } - -} - - -class NotificationsViewController: UIViewController { - - @IBOutlet weak var notificationsTableView: UITableView! - - private lazy var searchController: UISearchController = { - let searchController = UISearchController(searchResultsController: nil) - searchController.searchBar.placeholder = NSLocalizedString("Find a feed", comment: "Find a feed") - searchController.searchBar.searchBarStyle = .minimal - searchController.delegate = self - searchController.searchBar.delegate = self - searchController.searchBar.sizeToFit() - searchController.obscuresBackgroundDuringPresentation = false - searchController.hidesNavigationBarDuringPresentation = false - self.definesPresentationContext = true - return searchController - }() - private var status: UNAuthorizationStatus = .notDetermined - private var newArticleNotificationFilter: Bool = false { - didSet { - filterButton.menu = notificationFilterMenu() - } - } - private var filterButton: UIBarButtonItem! - - override func viewDidLoad() { - super.viewDidLoad() - title = NSLocalizedString("New Article Notifications", comment: "Notifications") - - navigationItem.searchController = searchController - notificationsTableView.isPrefetchingEnabled = false - - filterButton = UIBarButtonItem( - title: nil, - image: AppAssets.moreImage, - primaryAction: nil, - menu: notificationFilterMenu()) - - navigationItem.rightBarButtonItem = filterButton - - reloadNotificationTableView() - - NotificationCenter.default.addObserver(self, selector: #selector(updateCellsFrom(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(reloadVisibleCells(_:)), name: .FaviconDidBecomeAvailable, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(reloadNotificationTableView(_:)), name: UIScene.willEnterForegroundNotification, object: nil) - } - - @objc - private func reloadNotificationTableView(_ sender: Any? = nil) { - UNUserNotificationCenter.current().getNotificationSettings { settings in - DispatchQueue.main.async { - self.status = settings.authorizationStatus - if self.status != .authorized { - self.filterButton.isEnabled = false - self.newArticleNotificationFilter = false - } - self.notificationsTableView.reloadData() - } - } - } - - @objc - private func updateCellsFrom(_ notification: Notification) { - guard let webFeed = notification.userInfo?[UserInfoKey.webFeed] as? WebFeed else { return } - if let visibleIndexPaths = notificationsTableView.indexPathsForVisibleRows { - for path in visibleIndexPaths { - if let cell = notificationsTableView.cellForRow(at: path) as? NotificationsTableViewCell { - if cell.feed! == webFeed { - cell.configure(webFeed) - return - } - } - } - } - } - - @objc - private func reloadVisibleCells(_ notification: Notification) { - guard let faviconURLString = notification.userInfo?["faviconURL"] as? String, - let faviconHost = URL(string: faviconURLString)?.host else { - return - } - - for cell in notificationsTableView.visibleCells { - if let notificationCell = cell as? NotificationsTableViewCell { - if let feedURLHost = URL(string: notificationCell.feed!.url)?.host { - if faviconHost == feedURLHost { - notificationCell.configure(notificationCell.feed!) - return - } - } - } - } - } - - - private func notificationFilterMenu() -> UIMenu { - - if filterButton != nil { - if newArticleNotificationFilter { - filterButton.image = AppAssets.moreImageFill - } else { - filterButton.image = AppAssets.moreImage - } - } - - - let filterMenu = UIMenu(title: "", - image: nil, - identifier: nil, - options: [.displayInline], - children: [ - UIAction( - title: NSLocalizedString("Show Feeds with Notifications Enabled", comment: "Feeds with Notifications"), - image: nil, - identifier: nil, - discoverabilityTitle: nil, - attributes: [], - state: newArticleNotificationFilter ? .on : .off, - handler: { [weak self] _ in - self?.newArticleNotificationFilter.toggle() - self?.notificationsTableView.reloadData() - })]) - - - var menus = [UIMenuElement]() - menus.append(filterMenu) - - for account in AccountManager.shared.sortedActiveAccounts { - let accountMenu = UIMenu(title: account.nameForDisplay, image: nil, identifier: nil, options: .singleSelection, children: [enableAllAction(for: account), disableAllAction(for: account)]) - menus.append(accountMenu) - } - - let combinedMenu = UIMenu(title: "", - image: nil, - identifier: nil, - options: .displayInline, - children: menus) - - return combinedMenu - } - - private func enableAllAction(for account: Account) -> UIAction { - let action = UIAction(title: NSLocalizedString("Enable All Notifications", comment: "Enable All"), - image: nil, - identifier: nil, - discoverabilityTitle: nil, - attributes: [], - state: .off) { [weak self] _ in - for feed in account.flattenedWebFeeds() { - feed.isNotifyAboutNewArticles = true - } - self?.notificationsTableView.reloadData() - self?.filterButton.menu = self?.notificationFilterMenu() - } - return action - } - - private func disableAllAction(for account: Account) -> UIAction { - let action = UIAction(title: NSLocalizedString("Disable All Notifications", comment: "Disable All"), - image: nil, - identifier: nil, - discoverabilityTitle: nil, - attributes: [], - state: .off) { [weak self] _ in - for feed in account.flattenedWebFeeds() { - feed.isNotifyAboutNewArticles = false - } - self?.notificationsTableView.reloadData() - self?.filterButton.menu = self?.notificationFilterMenu() - } - return action - } - - // MARK: - Feed Filtering - - private func sortedWebFeedsForAccount(_ account: Account) -> [WebFeed] { - return Array(account.flattenedWebFeeds()).sorted(by: { $0.nameForDisplay.caseInsensitiveCompare($1.nameForDisplay) == .orderedAscending }) - } - - private func filteredWebFeeds(_ searchText: String? = "", account: Account) -> [WebFeed] { - sortedWebFeedsForAccount(account).filter { feed in - return feed.nameForDisplay.lowercased().contains(searchText!.lowercased()) - } - } - - private func feedsWithNotificationsEnabled(_ account: Account) -> [WebFeed] { - sortedWebFeedsForAccount(account).filter { feed in - return feed.isNotifyAboutNewArticles == true - } - } - -} - -// MARK: - UITableViewDataSource -extension NotificationsViewController: UITableViewDataSource { - - func numberOfSections(in tableView: UITableView) -> Int { - if status == .denied { return 1 } - return 1 + AccountManager.shared.activeAccounts.count - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - if section == 0 { - if status == .denied { return 1 } - return 0 - } - if searchController.isActive { - return filteredWebFeeds(searchController.searchBar.text, account: AccountManager.shared.sortedActiveAccounts[section - 1]).count - } else if newArticleNotificationFilter == true { - return feedsWithNotificationsEnabled(AccountManager.shared.sortedActiveAccounts[section - 1]).count - } else { - return AccountManager.shared.sortedActiveAccounts[section - 1].flattenedWebFeeds().count - } - - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - if indexPath.section == 0 { - let openSettingsCell = tableView.dequeueReusableCell(withIdentifier: "OpenSettingsCell") as! VibrantBasicTableViewCell - return openSettingsCell - } else { - if searchController.isActive { - let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell - let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1] - cell.configure(filteredWebFeeds(searchController.searchBar.text, account: account)[indexPath.row]) - return cell - } else if newArticleNotificationFilter == true { - let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell - let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1] - cell.configure(feedsWithNotificationsEnabled(account)[indexPath.row]) - return cell - } else { - let cell = tableView.dequeueReusableCell(withIdentifier: "NotificationsCell") as! NotificationsTableViewCell - let account = AccountManager.shared.sortedActiveAccounts[indexPath.section - 1] - cell.configure(sortedWebFeedsForAccount(account)[indexPath.row]) - return cell - } - } - } - - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - if section == 0 { return nil } - return AccountManager.shared.sortedActiveAccounts[section - 1].nameForDisplay - } - - func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? { - if section == 0 { - if status == .denied { - return NSLocalizedString("Notification permissions are currently denied. Enable notifications in the Settings app.", comment: "Notifications denied.") - } - } - return nil - } -} - - -// MARK: - UITableViewDelegate -extension NotificationsViewController: UITableViewDelegate { - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.deselectRow(at: indexPath, animated: true) - if indexPath.section == 0 { - UIApplication.shared.open(URL(string: "\(UIApplication.openSettingsURLString)")!) - } - } - -} - - -// MARK: - UISearchControllerDelegate -extension NotificationsViewController: UISearchControllerDelegate { - - func didDismissSearchController(_ searchController: UISearchController) { - print(#function) - searchController.isActive = false - notificationsTableView.reloadData() - } - -} - -// MARK: - UISearchBarDelegate -extension NotificationsViewController: UISearchBarDelegate { - - func searchBarTextDidBeginEditing(_ searchBar: UISearchBar) { - searchController.isActive = true - newArticleNotificationFilter = false - notificationsTableView.reloadData() - } - - func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) { - notificationsTableView.reloadData() - } - -} diff --git a/iOS/Settings/SettingsViewController.swift b/iOS/Settings/SettingsViewController.swift deleted file mode 100644 index 2112e62dd..000000000 --- a/iOS/Settings/SettingsViewController.swift +++ /dev/null @@ -1,515 +0,0 @@ -// -// SettingsViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 4/24/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit -import Account -import CoreServices -import SafariServices -import SwiftUI -import UniformTypeIdentifiers -import UserNotifications -import RSCore - -class SettingsViewController: UITableViewController, Logging { - - private weak var opmlAccount: Account? - - @IBOutlet weak var timelineSortOrderSwitch: UISwitch! - @IBOutlet weak var groupByFeedSwitch: UISwitch! - @IBOutlet weak var refreshClearsReadArticlesSwitch: UISwitch! - @IBOutlet weak var articleThemeDetailLabel: UILabel! - @IBOutlet weak var confirmMarkAllAsReadSwitch: UISwitch! - @IBOutlet weak var showFullscreenArticlesSwitch: UISwitch! - @IBOutlet weak var colorPaletteDetailLabel: UILabel! - @IBOutlet weak var openLinksInNetNewsWire: UISwitch! - - var scrollToArticlesSection = false - weak var presentingParentController: UIViewController? - - var notificationStatus: UNAuthorizationStatus = .notDetermined - - override func viewDidLoad() { - // This hack mostly works around a bug in static tables with dynamic type. See: https://spin.atomicobject.com/2018/10/15/dynamic-type-static-uitableview/ - NotificationCenter.default.removeObserver(tableView!, name: UIContentSizeCategory.didChangeNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange), name: .UserDidAddAccount, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(accountsDidChange), name: .UserDidDeleteAccount, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange), name: .DisplayNameDidChange, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(activeExtensionPointsDidChange), name: .ActiveExtensionPointsDidChange, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(refreshNotificationStatus(_:)), name: UIScene.willEnterForegroundNotification, object: nil) - - - tableView.register(UINib(nibName: "SettingsComboTableViewCell", bundle: nil), forCellReuseIdentifier: "SettingsComboTableViewCell") - tableView.register(UINib(nibName: "SettingsTableViewCell", bundle: nil), forCellReuseIdentifier: "SettingsTableViewCell") - - refreshNotificationStatus() - - tableView.rowHeight = UITableView.automaticDimension - tableView.estimatedRowHeight = 44 - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if AppDefaults.shared.timelineSortDirection == .orderedAscending { - timelineSortOrderSwitch.isOn = true - } else { - timelineSortOrderSwitch.isOn = false - } - - if AppDefaults.shared.timelineGroupByFeed { - groupByFeedSwitch.isOn = true - } else { - groupByFeedSwitch.isOn = false - } - - if AppDefaults.shared.refreshClearsReadArticles { - refreshClearsReadArticlesSwitch.isOn = true - } else { - refreshClearsReadArticlesSwitch.isOn = false - } - - articleThemeDetailLabel.text = ArticleThemesManager.shared.currentTheme.name - - if AppDefaults.shared.confirmMarkAllAsRead { - confirmMarkAllAsReadSwitch.isOn = true - } else { - confirmMarkAllAsReadSwitch.isOn = false - } - - colorPaletteDetailLabel.text = String(describing: AppDefaults.userInterfaceColorPalette) - openLinksInNetNewsWire.isOn = !AppDefaults.shared.useSystemBrowser - - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - self.tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - - if scrollToArticlesSection { - tableView.scrollToRow(at: IndexPath(row: 0, section: 4), at: .top, animated: true) - scrollToArticlesSection = false - } - } - - @objc - func refreshNotificationStatus(_ sender: Any? = nil) { - UNUserNotificationCenter.current().getNotificationSettings { settings in - DispatchQueue.main.async { - self.notificationStatus = settings.authorizationStatus - self.tableView.reloadData() - } - } - } - - // MARK: UITableView - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - - switch section { - case 0: - if notificationStatus == .authorized { return 2 } - return 1 - case 1: - return AccountManager.shared.accounts.count + 1 - case 2: - return ExtensionPointManager.shared.activeExtensionPoints.count + 1 - case 3: - let defaultNumberOfRows = super.tableView(tableView, numberOfRowsInSection: section) - if AccountManager.shared.activeAccounts.isEmpty || AccountManager.shared.anyAccountHasNetNewsWireNewsSubscription() { - return defaultNumberOfRows - 1 - } - return defaultNumberOfRows - case 5: - return 3 - default: - return super.tableView(tableView, numberOfRowsInSection: section) - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - - let cell: UITableViewCell - switch indexPath.section { - case 1: - - let sortedAccounts = AccountManager.shared.sortedAccounts - if indexPath.row == sortedAccounts.count { - cell = tableView.dequeueReusableCell(withIdentifier: "SettingsTableViewCell", for: indexPath) - cell.textLabel?.text = NSLocalizedString("Add Account", comment: "Accounts") - } else { - let acctCell = tableView.dequeueReusableCell(withIdentifier: "SettingsComboTableViewCell", for: indexPath) as! SettingsComboTableViewCell - acctCell.applyThemeProperties() - let account = sortedAccounts[indexPath.row] - acctCell.comboImage?.image = AppAssets.image(for: account.type) - acctCell.comboNameLabel?.text = account.nameForDisplay - cell = acctCell - } - - case 2: - - let extensionPoints = Array(ExtensionPointManager.shared.activeExtensionPoints.values) - if indexPath.row == extensionPoints.count { - cell = tableView.dequeueReusableCell(withIdentifier: "SettingsTableViewCell", for: indexPath) - cell.textLabel?.text = NSLocalizedString("Add Extension", comment: "Extensions") - } else { - let acctCell = tableView.dequeueReusableCell(withIdentifier: "SettingsComboTableViewCell", for: indexPath) as! SettingsComboTableViewCell - acctCell.applyThemeProperties() - let extensionPoint = extensionPoints[indexPath.row] - acctCell.comboImage?.image = extensionPoint.image - acctCell.comboNameLabel?.text = extensionPoint.title - cell = acctCell - } - default: - cell = super.tableView(tableView, cellForRowAt: indexPath) - - } - - return cell - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - - switch indexPath.section { - case 0: - if indexPath.row == 0 { - UIApplication.shared.open(URL(string: "\(UIApplication.openSettingsURLString)")!) - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - } else { - let controller = UIStoryboard.settings.instantiateController(ofType: NotificationsViewController.self) - self.navigationController?.pushViewController(controller, animated: true) - } - case 1: - let sortedAccounts = AccountManager.shared.sortedAccounts - if indexPath.row == sortedAccounts.count { - let controller = UIStoryboard.settings.instantiateController(ofType: AddAccountViewController.self) - self.navigationController?.pushViewController(controller, animated: true) - } else { - let controller = UIStoryboard.inspector.instantiateController(ofType: AccountInspectorViewController.self) - controller.account = sortedAccounts[indexPath.row] - self.navigationController?.pushViewController(controller, animated: true) - } - case 2: - let extensionPoints = Array(ExtensionPointManager.shared.activeExtensionPoints.values) - if indexPath.row == extensionPoints.count { - let controller = UIStoryboard.settings.instantiateController(ofType: AddExtensionPointViewController.self) - self.navigationController?.pushViewController(controller, animated: true) - } else { - let controller = UIStoryboard.inspector.instantiateController(ofType: ExtensionPointInspectorViewController.self) - controller.extensionPoint = extensionPoints[indexPath.row] - self.navigationController?.pushViewController(controller, animated: true) - } - case 3: - switch indexPath.row { - case 0: - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - if let sourceView = tableView.cellForRow(at: indexPath) { - let sourceRect = tableView.rectForRow(at: indexPath) - importOPML(sourceView: sourceView, sourceRect: sourceRect) - } - case 1: - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - if let sourceView = tableView.cellForRow(at: indexPath) { - let sourceRect = tableView.rectForRow(at: indexPath) - exportOPML(sourceView: sourceView, sourceRect: sourceRect) - } - case 2: - addFeed() - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - default: - break - } - case 4: - switch indexPath.row { - case 3: - let timeline = UIStoryboard.settings.instantiateController(ofType: TimelineCustomizerViewController.self) - self.navigationController?.pushViewController(timeline, animated: true) - default: - break - } - case 5: - switch indexPath.row { - case 0: - let articleThemes = UIStoryboard.settings.instantiateController(ofType: ArticleThemesTableViewController.self) - self.navigationController?.pushViewController(articleThemes, animated: true) - default: - break - } - case 6: - let colorPalette = UIStoryboard.settings.instantiateController(ofType: ColorPaletteTableViewController.self) - self.navigationController?.pushViewController(colorPalette, animated: true) - case 7: - switch indexPath.row { - case 0: - openURL("https://netnewswire.com/help/ios/6.1/en/") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 1: - openURL("https://netnewswire.com/") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 2: - openURL(URL.releaseNotes.absoluteString) - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 3: - openURL("https://github.com/brentsimmons/NetNewsWire/blob/main/Technotes/HowToSupportNetNewsWire.markdown") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 4: - openURL("https://github.com/brentsimmons/NetNewsWire") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 5: - openURL("https://github.com/brentsimmons/NetNewsWire/issues") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 6: - openURL("https://github.com/brentsimmons/NetNewsWire/tree/main/Technotes") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 7: - openURL("https://netnewswire.com/slack") - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - case 8: - let hosting = UIHostingController(rootView: AboutView()) - self.navigationController?.pushViewController(hosting, animated: true) - default: - break - } - default: - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - } - } - - override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { - return false - } - - override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool { - return false - } - - override func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle { - return .none - } - - override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return UITableView.automaticDimension - } - - override func tableView(_ tableView: UITableView, indentationLevelForRowAt indexPath: IndexPath) -> Int { - return super.tableView(tableView, indentationLevelForRowAt: IndexPath(row: 0, section: 1)) - } - - // MARK: Actions - - @IBAction func done(_ sender: Any) { - dismiss(animated: true) - } - - @IBAction func switchTimelineOrder(_ sender: Any) { - if timelineSortOrderSwitch.isOn { - AppDefaults.shared.timelineSortDirection = .orderedAscending - } else { - AppDefaults.shared.timelineSortDirection = .orderedDescending - } - } - - @IBAction func switchGroupByFeed(_ sender: Any) { - if groupByFeedSwitch.isOn { - AppDefaults.shared.timelineGroupByFeed = true - } else { - AppDefaults.shared.timelineGroupByFeed = false - } - } - - @IBAction func switchClearsReadArticles(_ sender: Any) { - if refreshClearsReadArticlesSwitch.isOn { - AppDefaults.shared.refreshClearsReadArticles = true - } else { - AppDefaults.shared.refreshClearsReadArticles = false - } - } - - @IBAction func switchConfirmMarkAllAsRead(_ sender: Any) { - if confirmMarkAllAsReadSwitch.isOn { - AppDefaults.shared.confirmMarkAllAsRead = true - } else { - AppDefaults.shared.confirmMarkAllAsRead = false - } - } - - @IBAction func switchBrowserPreference(_ sender: Any) { - if openLinksInNetNewsWire.isOn { - AppDefaults.shared.useSystemBrowser = false - } else { - AppDefaults.shared.useSystemBrowser = true - } - } - - - // MARK: Notifications - - @objc func contentSizeCategoryDidChange() { - tableView.reloadData() - } - - @objc func accountsDidChange() { - tableView.reloadData() - } - - @objc func displayNameDidChange() { - tableView.reloadData() - } - - @objc func activeExtensionPointsDidChange() { - tableView.reloadData() - } - - @objc func browserPreferenceDidChange() { - tableView.reloadData() - } - -} - -// MARK: OPML Document Picker - -extension SettingsViewController: UIDocumentPickerDelegate { - - func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) { - for url in urls { - opmlAccount?.importOPML(url) { result in - switch result { - case .success: - break - case .failure: - let title = NSLocalizedString("Import Failed", comment: "Import Failed") - let message = NSLocalizedString("We were unable to process the selected file. Please ensure that it is a properly formatted OPML file.", comment: "Import Failed Message") - self.presentError(title: title, message: message) - } - } - } - } - -} - -// MARK: Private - -private extension SettingsViewController { - - func addFeed() { - self.dismiss(animated: true) - - let addNavViewController = UIStoryboard.add.instantiateViewController(withIdentifier: "AddWebFeedViewControllerNav") as! UINavigationController - let addViewController = addNavViewController.topViewController as! AddFeedViewController - addViewController.initialFeed = AccountManager.netNewsWireNewsURL - addViewController.initialFeedName = NSLocalizedString("NetNewsWire News", comment: "NetNewsWire News") - addNavViewController.modalPresentationStyle = .formSheet - addNavViewController.preferredContentSize = AddFeedViewController.preferredContentSizeForFormSheetDisplay - - presentingParentController?.present(addNavViewController, animated: true) - } - - func importOPML(sourceView: UIView, sourceRect: CGRect) { - switch AccountManager.shared.activeAccounts.count { - case 0: - presentError(title: "Error", message: NSLocalizedString("You must have at least one active account.", comment: "Missing active account")) - case 1: - opmlAccount = AccountManager.shared.activeAccounts.first - importOPMLDocumentPicker() - default: - importOPMLAccountPicker(sourceView: sourceView, sourceRect: sourceRect) - } - } - - func importOPMLAccountPicker(sourceView: UIView, sourceRect: CGRect) { - let title = NSLocalizedString("Choose an account to receive the imported feeds and folders", comment: "Import Account") - let alert = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet) - - if let popoverController = alert.popoverPresentationController { - popoverController.sourceView = view - popoverController.sourceRect = sourceRect - } - - for account in AccountManager.shared.sortedActiveAccounts { - let action = UIAlertAction(title: account.nameForDisplay, style: .default) { [weak self] action in - self?.opmlAccount = account - self?.importOPMLDocumentPicker() - } - alert.addAction(action) - } - - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) - - self.present(alert, animated: true) - } - - func importOPMLDocumentPicker() { - - let utiArray = UTType.types(tag: "opml", tagClass: .filenameExtension, conformingTo: nil) - - let docPicker = UIDocumentPickerViewController(forOpeningContentTypes: utiArray, asCopy: true) - docPicker.delegate = self - docPicker.modalPresentationStyle = .formSheet - self.present(docPicker, animated: true) - } - - func exportOPML(sourceView: UIView, sourceRect: CGRect) { - if AccountManager.shared.accounts.count == 1 { - opmlAccount = AccountManager.shared.accounts.first! - exportOPMLDocumentPicker() - } else { - exportOPMLAccountPicker(sourceView: sourceView, sourceRect: sourceRect) - } - } - - func exportOPMLAccountPicker(sourceView: UIView, sourceRect: CGRect) { - let title = NSLocalizedString("Choose an account with the subscriptions to export", comment: "Export Account") - let alert = UIAlertController(title: title, message: nil, preferredStyle: .actionSheet) - - if let popoverController = alert.popoverPresentationController { - popoverController.sourceView = view - popoverController.sourceRect = sourceRect - } - - for account in AccountManager.shared.sortedAccounts { - let action = UIAlertAction(title: account.nameForDisplay, style: .default) { [weak self] action in - self?.opmlAccount = account - self?.exportOPMLDocumentPicker() - } - alert.addAction(action) - } - - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - alert.addAction(UIAlertAction(title: cancelTitle, style: .cancel)) - - self.present(alert, animated: true) - } - - func exportOPMLDocumentPicker() { - guard let account = opmlAccount else { return } - - let accountName = account.nameForDisplay.replacingOccurrences(of: " ", with: "").trimmingCharacters(in: .whitespaces) - let filename = "Subscriptions-\(accountName).opml" - let tempFile = FileManager.default.temporaryDirectory.appendingPathComponent(filename) - let opmlString = OPMLExporter.OPMLString(with: account, title: filename) - do { - try opmlString.write(to: tempFile, atomically: true, encoding: String.Encoding.utf8) - } catch { - self.presentError(title: "OPML Export Error", message: error.localizedDescription) - logger.error("OPML Export Error: \(error.localizedDescription, privacy: .public)") - } - - let docPicker = UIDocumentPickerViewController(forExporting: [tempFile], asCopy: true) - docPicker.modalPresentationStyle = .formSheet - self.present(docPicker, animated: true) - } - - func openURL(_ urlString: String) { - let vc = SFSafariViewController(url: URL(string: urlString)!) - vc.modalPresentationStyle = .pageSheet - present(vc, animated: true) - } - -} diff --git a/iOS/Settings/Views/General/SettingsView.swift b/iOS/Settings/Views/General/SettingsView.swift index d12a4a892..9ba7a8e69 100644 --- a/iOS/Settings/Views/General/SettingsView.swift +++ b/iOS/Settings/Views/General/SettingsView.swift @@ -13,6 +13,7 @@ import UserNotifications struct SettingsView: View { + @Environment(\.dismiss) var dismiss @StateObject private var appDefaults = AppDefaults.shared @StateObject private var viewModel = SettingsViewModel() @@ -100,6 +101,9 @@ struct SettingsView: View { } } } + .onReceive(NotificationCenter.default.publisher(for: .LaunchedFromExternalAction), perform: { _ in + dismiss() + }) .fileImporter(isPresented: $viewModel.showImportView, allowedContentTypes: OPMLDocument.readableContentTypes) { result in switch result { case .success(let url):