diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 6b3b7f8f4..579ad1d45 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -103,7 +103,6 @@ 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 */; }; - 5110C37D2373A8D100A9C04F /* InspectorIconHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5110C37C2373A8D100A9C04F /* InspectorIconHeaderView.swift */; }; 51126DA4225FDE2F00722696 /* RSImage-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */; }; 5117715524E1EA0F00A2A836 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5117715424E1EA0F00A2A836 /* ArticleExtractorButton.swift */; }; 5117715624E1EA0F00A2A836 /* ArticleExtractorButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5117715424E1EA0F00A2A836 /* ArticleExtractorButton.swift */; }; @@ -191,7 +190,6 @@ 513F32812593EF180003048F /* Account in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 516B695E24D2F33B00B5702F /* Account */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 513F32882593EF8F0003048F /* RSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 513F32872593EF8F0003048F /* RSCore */; }; 513F32892593EF8F0003048F /* RSCore in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 513F32872593EF8F0003048F /* RSCore */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; - 5141E7392373C18B0013FF27 /* WebFeedInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5141E7382373C18B0013FF27 /* WebFeedInspectorViewController.swift */; }; 514217062921C9DD00963F14 /* Bundle-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF42273625800C787DC /* Bundle-Extensions.swift */; }; 5142192A23522B5500E07E2C /* ImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5142192923522B5500E07E2C /* ImageViewController.swift */; }; 514219372352510100E07E2C /* ImageScrollView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 514219362352510100E07E2C /* ImageScrollView.swift */; }; @@ -240,7 +238,6 @@ 51627A93238A3836007B3B4B /* CroppingPreviewParameters.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51627A92238A3836007B3B4B /* CroppingPreviewParameters.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 */; }; 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 */; }; @@ -288,12 +285,10 @@ 519E743D22C663F900A78E47 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519E743422C663F900A78E47 /* SceneDelegate.swift */; }; 519ED456244828C3007F8E94 /* AddExtensionPointViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */; }; 519ED47A24482AEB007F8E94 /* EnableExtensionPointViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */; }; - 519ED47C24488C6F007F8E94 /* ExtensionInspectorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519ED47B24488C6F007F8E94 /* ExtensionInspectorViewController.swift */; }; 51A052CE244FB9D7006C2024 /* AddFeedWIndowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */; }; 51A052CF244FB9D7006C2024 /* AddFeedWIndowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */; }; 51A16999235E10D700EB091F /* LocalAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A1698F235E10D600EB091F /* LocalAccountViewController.swift */; }; 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 */; }; 51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A16996235E10D700EB091F /* FeedbinAccountViewController.swift */; }; 51A66685238075AE00CB272D /* AddWebFeedDefaultContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51A66684238075AE00CB272D /* AddWebFeedDefaultContainer.swift */; }; @@ -864,6 +859,12 @@ DF766FED29377FD9006FBBE2 /* ExtensionsManagementView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF766FEC29377FD9006FBBE2 /* ExtensionsManagementView.swift */; }; DF790D6228E990A900455FC7 /* AboutData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF790D6128E990A900455FC7 /* AboutData.swift */; }; DFB3497A294A962D00BC81AD /* AddAccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB34979294A962D00BC81AD /* AddAccountView.swift */; }; + DFB34980294B085100BC81AD /* AccountInspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB3497F294B085100BC81AD /* AccountInspectorView.swift */; }; + DFB34982294B0B9B00BC81AD /* Inspector.strings in Resources */ = {isa = PBXBuildFile; fileRef = DFB34981294B0B9B00BC81AD /* Inspector.strings */; }; + DFB34984294B3AFF00BC81AD /* Buttons.strings in Resources */ = {isa = PBXBuildFile; fileRef = DFB34983294B3AFF00BC81AD /* Buttons.strings */; }; + DFB34988294B447F00BC81AD /* InjectedNavigationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB34987294B447F00BC81AD /* InjectedNavigationView.swift */; }; + DFB3498A294B45AC00BC81AD /* ExtensionInspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB34989294B45AC00BC81AD /* ExtensionInspectorView.swift */; }; + DFB3498C294B4CA700BC81AD /* WebFeedInspectorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFB3498B294B4CA700BC81AD /* WebFeedInspectorView.swift */; }; DFC14F0F28EA55BD00F6EE86 /* AboutWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */; }; DFC14F1228EA5DC500F6EE86 /* AboutData.swift in Sources */ = {isa = PBXBuildFile; fileRef = DF790D6128E990A900455FC7 /* AboutData.swift */; }; DFC14F1328EA677C00F6EE86 /* Bundle-Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51F85BF42273625800C787DC /* Bundle-Extensions.swift */; }; @@ -1205,7 +1206,6 @@ 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 = ""; }; - 5110C37C2373A8D100A9C04F /* InspectorIconHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InspectorIconHeaderView.swift; sourceTree = ""; }; 51121AA12265430A00BC0EC1 /* NetNewsWire_iOSapp_target.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = NetNewsWire_iOSapp_target.xcconfig; sourceTree = ""; }; 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-Extensions.swift"; sourceTree = ""; }; 5117715424E1EA0F00A2A836 /* ArticleExtractorButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleExtractorButton.swift; sourceTree = ""; }; @@ -1238,7 +1238,6 @@ 513C5CE8232571C2003D4054 /* ShareViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareViewController.swift; sourceTree = ""; }; 513C5CEB232571C2003D4054 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/MainInterface.storyboard; sourceTree = ""; }; 513C5CED232571C2003D4054 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 5141E7382373C18B0013FF27 /* WebFeedInspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebFeedInspectorViewController.swift; sourceTree = ""; }; 5141E7552374A2890013FF27 /* DetailIconSchemeHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailIconSchemeHandler.swift; sourceTree = ""; }; 5142192923522B5500E07E2C /* ImageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageViewController.swift; sourceTree = ""; }; 514219362352510100E07E2C /* ImageScrollView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImageScrollView.swift; sourceTree = ""; }; @@ -1270,7 +1269,6 @@ 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 = ""; }; 516A093F2361240900EAE89B /* Account.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Account.storyboard; sourceTree = ""; }; - 516A09412361248000EAE89B /* Inspector.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = Inspector.storyboard; 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 = ""; }; @@ -1306,11 +1304,9 @@ 519E743422C663F900A78E47 /* SceneDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; 519ED455244828C3007F8E94 /* AddExtensionPointViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddExtensionPointViewController.swift; sourceTree = ""; }; 519ED47924482AEB007F8E94 /* EnableExtensionPointViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnableExtensionPointViewController.swift; sourceTree = ""; }; - 519ED47B24488C6F007F8E94 /* ExtensionInspectorViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionInspectorViewController.swift; sourceTree = ""; }; 51A052CD244FB9D6006C2024 /* AddFeedWIndowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AddFeedWIndowController.swift; path = AddFeed/AddFeedWIndowController.swift; sourceTree = ""; }; 51A1698F235E10D600EB091F /* LocalAccountViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalAccountViewController.swift; sourceTree = ""; }; 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 = ""; }; 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 = ""; }; @@ -1621,6 +1617,12 @@ DF766FEC29377FD9006FBBE2 /* ExtensionsManagementView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsManagementView.swift; sourceTree = ""; }; DF790D6128E990A900455FC7 /* AboutData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutData.swift; sourceTree = ""; }; DFB34979294A962D00BC81AD /* AddAccountView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountView.swift; sourceTree = ""; }; + DFB3497F294B085100BC81AD /* AccountInspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountInspectorView.swift; sourceTree = ""; }; + DFB34981294B0B9B00BC81AD /* Inspector.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Inspector.strings; sourceTree = ""; }; + DFB34983294B3AFF00BC81AD /* Buttons.strings */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; path = Buttons.strings; sourceTree = ""; }; + DFB34987294B447F00BC81AD /* InjectedNavigationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InjectedNavigationView.swift; sourceTree = ""; }; + DFB34989294B45AC00BC81AD /* ExtensionInspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionInspectorView.swift; sourceTree = ""; }; + DFB3498B294B4CA700BC81AD /* WebFeedInspectorView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebFeedInspectorView.swift; sourceTree = ""; }; DFC14F0E28EA55BD00F6EE86 /* AboutWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutWindowController.swift; sourceTree = ""; }; DFC14F1428EB177000F6EE86 /* AboutNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutNetNewsWireView.swift; sourceTree = ""; }; DFC14F1628EB17A800F6EE86 /* CreditsNetNewsWireView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditsNetNewsWireView.swift; sourceTree = ""; }; @@ -1911,11 +1913,8 @@ 5123DB95233EC69300282CC9 /* Inspector */ = { isa = PBXGroup; children = ( - 516A09412361248000EAE89B /* Inspector.storyboard */, - 51A16991235E10D600EB091F /* AccountInspectorViewController.swift */, - 519ED47B24488C6F007F8E94 /* ExtensionInspectorViewController.swift */, - 5110C37C2373A8D100A9C04F /* InspectorIconHeaderView.swift */, - 5141E7382373C18B0013FF27 /* WebFeedInspectorViewController.swift */, + DFB34981294B0B9B00BC81AD /* Inspector.strings */, + DFB3497D294B076C00BC81AD /* Views */, ); path = Inspector; sourceTree = ""; @@ -2179,6 +2178,7 @@ 51C452802265093600C03939 /* Add */ = { isa = PBXGroup; children = ( + DFB3497E294B07D900BC81AD /* Views */, 51C452822265093600C03939 /* Add.storyboard */, 51E4397F23805EBC00015C31 /* AddComboTableViewCell.swift */, 51E43961238037C400015C31 /* AddFeedFolderViewController.swift */, @@ -2637,6 +2637,7 @@ 511D43CE231FA51100FB1562 /* Resources */, 176813A22564B9D100D98635 /* Widget */, 173A64162547BE0900267F6E /* AccountType+Helpers.swift */, + DFB34985294B3B0800BC81AD /* Translations */, ); path = Shared; sourceTree = ""; @@ -2748,6 +2749,7 @@ 5123DB95233EC69300282CC9 /* Inspector */, 513145F9235A55A700387FDC /* Intents */, 5183CCEB227117C70010922C /* Settings */, + DFB34986294B446300BC81AD /* SwiftUI Extensions */, 51C45245226506C800C03939 /* UIKit Extensions */, 513C5CE7232571C2003D4054 /* ShareExtension */, 51314643235A7C2300387FDC /* IntentsExtension */, @@ -2940,8 +2942,8 @@ DFB3497B294AA95200BC81AD /* Accounts */ = { isa = PBXGroup; children = ( - DFB34979294A962D00BC81AD /* AddAccountView.swift */, DF59F0732920DB5100ACD33D /* AccountsManagementView.swift */, + DFB34979294A962D00BC81AD /* AddAccountView.swift */, ); path = Accounts; sourceTree = ""; @@ -2955,6 +2957,39 @@ path = Extensions; sourceTree = ""; }; + DFB3497D294B076C00BC81AD /* Views */ = { + isa = PBXGroup; + children = ( + DFB3497F294B085100BC81AD /* AccountInspectorView.swift */, + DFB34989294B45AC00BC81AD /* ExtensionInspectorView.swift */, + DFB3498B294B4CA700BC81AD /* WebFeedInspectorView.swift */, + ); + path = Views; + sourceTree = ""; + }; + DFB3497E294B07D900BC81AD /* Views */ = { + isa = PBXGroup; + children = ( + ); + path = Views; + sourceTree = ""; + }; + DFB34985294B3B0800BC81AD /* Translations */ = { + isa = PBXGroup; + children = ( + DFB34983294B3AFF00BC81AD /* Buttons.strings */, + ); + path = Translations; + sourceTree = ""; + }; + DFB34986294B446300BC81AD /* SwiftUI Extensions */ = { + isa = PBXGroup; + children = ( + DFB34987294B447F00BC81AD /* InjectedNavigationView.swift */, + ); + path = "SwiftUI Extensions"; + sourceTree = ""; + }; DFC14F0928EA51AB00F6EE86 /* About */ = { isa = PBXGroup; children = ( @@ -3551,9 +3586,9 @@ 511D43D2231FA62C00FB1562 /* GlobalKeyboardShortcuts.plist in Resources */, 84C9FCA12262A1B300D921D6 /* Main.storyboard in Resources */, 51BB7C312335ACDE008E8144 /* page.html in Resources */, + DFB34982294B0B9B00BC81AD /* Inspector.strings in Resources */, 512392C324E3451400F11704 /* TwitterAdd.storyboard in Resources */, 51077C5A27A86D16000C71DB /* Hyperlegible.nnwtheme in Resources */, - 516A09422361248000EAE89B /* Inspector.storyboard in Resources */, DDF9E1D928EDF2FC000BC355 /* notificationSoundBlip.mp3 in Resources */, DF32ABEB29494CF1008E3A12 /* Settings.strings in Resources */, 51DEE81A26FBFF84006DAA56 /* Promenade.nnwtheme in Resources */, @@ -3567,6 +3602,7 @@ 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 */, @@ -4143,6 +4179,7 @@ 51EF0F79227716380050506E /* ColorHash.swift in Sources */, DF59F072292085B800ACD33D /* ColorPaletteSelectorView.swift in Sources */, 51F9F3FB23DFB25700A314FD /* Animations.swift in Sources */, + DFB34988294B447F00BC81AD /* InjectedNavigationView.swift in Sources */, 5195C1DA2720205F00888867 /* ShadowTableChanges.swift in Sources */, 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */, B2B80778239C4C7000F191E0 /* RSImage-AppIcons.swift in Sources */, @@ -4194,6 +4231,7 @@ 5126EE97226CB48A00C22AFC /* SceneCoordinator.swift in Sources */, 84CAFCB022BC8C35007694F0 /* FetchRequestOperation.swift in Sources */, DFD406FA291FB5E400C02962 /* SettingsRows.swift in Sources */, + DFB3498C294B4CA700BC81AD /* WebFeedInspectorView.swift in Sources */, 5193CD5A245E44A90092735E /* RedditFeedProvider-Extensions.swift in Sources */, 51EF0F77227716200050506E /* FaviconGenerator.swift in Sources */, 51938DF3231AFC660055A1A0 /* SearchTimelineFeedDelegate.swift in Sources */, @@ -4208,7 +4246,6 @@ 51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */, 5F323809231DF9F000706F6B /* VibrantTableViewCell.swift in Sources */, 51FE10042345529D0056195D /* UserNotificationManager.swift in Sources */, - 519ED47C24488C6F007F8E94 /* ExtensionInspectorViewController.swift in Sources */, 51C4CFF224D37D1F00AF9874 /* Secrets.swift in Sources */, 51C452A022650A1900C03939 /* WebFeedIconDownloader.swift in Sources */, 51C4529E22650A1900C03939 /* ImageDownloader.swift in Sources */, @@ -4221,6 +4258,7 @@ 51B5C87B23F2317700032075 /* ExtensionFeedAddRequest.swift in Sources */, 51627A93238A3836007B3B4B /* CroppingPreviewParameters.swift in Sources */, 512AF9DD236F05230066F8BE /* InteractiveLabel.swift in Sources */, + DFB3498A294B45AC00BC81AD /* ExtensionInspectorView.swift in Sources */, 51E3EB3D229AB08300645299 /* ErrorHandler.swift in Sources */, 5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */, 51C4529D22650A1000C03939 /* FaviconURLFinder.swift in Sources */, @@ -4245,7 +4283,6 @@ 51C9DE5823EA2EF4003D5A6D /* WrapperScriptMessageHandler.swift in Sources */, 51B5C87D23F2346200032075 /* ExtensionContainersFile.swift in Sources */, 51102165233A7D6C0007A5F7 /* ArticleExtractorButton.swift in Sources */, - 5141E7392373C18B0013FF27 /* WebFeedInspectorViewController.swift in Sources */, C5A6ED6D23C9B0C800AB6BE2 /* UIActivityViewController-Extensions.swift in Sources */, 5108F6D42375EEEF001ABC45 /* TimelinePreviewTableViewController.swift in Sources */, 84CAFCA522BC8C08007694F0 /* FetchRequestQueue.swift in Sources */, @@ -4266,12 +4303,10 @@ 51C45297226509E300C03939 /* DefaultFeedsImporter.swift in Sources */, 512E094D2268B8AB00BDCFDD /* DeleteCommand.swift in Sources */, DFD406FC291FB63B00C02962 /* SettingsHelpSheets.swift in Sources */, - 5110C37D2373A8D100A9C04F /* InspectorIconHeaderView.swift in Sources */, 51F85BFB2275D85000C787DC /* Array-Extensions.swift in Sources */, 515A5180243E90260089E588 /* TwitterFeedProvider-Extensions.swift in Sources */, 51C452AC22650FD200C03939 /* AppNotifications.swift in Sources */, 51EF0F7E2277A57D0050506E /* MasterTimelineAccessibilityCellLayout.swift in Sources */, - 51A1699B235E10D700EB091F /* AccountInspectorViewController.swift in Sources */, 512D554423C804DE0023FFFA /* OpenInSafariActivity.swift in Sources */, DF47CDB2294803AB00FCD57E /* AddExtensionListView.swift in Sources */, 512392C224E33A3C00F11704 /* RedditEnterDetailTableViewController.swift in Sources */, @@ -4283,6 +4318,7 @@ 51B5C8C023F3866C00032075 /* ExtensionFeedAddRequestFile.swift in Sources */, 51A169A0235E10D700EB091F /* FeedbinAccountViewController.swift in Sources */, 51934CCE2310792F006127BE /* ActivityManager.swift in Sources */, + DFB34980294B085100BC81AD /* AccountInspectorView.swift in Sources */, 5108F6B72375E612001ABC45 /* CacheCleaner.swift in Sources */, DF59F0742920DB5100ACD33D /* AccountsManagementView.swift in Sources */, 518651DA235621840078E021 /* ImageTransition.swift in Sources */, diff --git a/Shared/ExtensionPoints/ExtensionPointManager.swift b/Shared/ExtensionPoints/ExtensionPointManager.swift index bf8cb0402..bd8a173cb 100644 --- a/Shared/ExtensionPoints/ExtensionPointManager.swift +++ b/Shared/ExtensionPoints/ExtensionPointManager.swift @@ -38,7 +38,7 @@ final class ExtensionPointManager: FeedProviderManagerDelegate { let activeExtensionPointTypes = activeExtensionPoints.keys.compactMap({ ObjectIdentifier($0.extensionPointType) }) var available = [ExtensionPoint.Type]() for possibleExtensionPointType in possibleExtensionPointTypes { - if !(AppDefaults.shared.isDeveloperBuild && possibleExtensionPointType.isDeveloperBuildRestricted) { + if (AppDefaults.shared.isDeveloperBuild && possibleExtensionPointType.isDeveloperBuildRestricted) { if possibleExtensionPointType.isSinglton { if !activeExtensionPointTypes.contains(ObjectIdentifier(possibleExtensionPointType)) { available.append(possibleExtensionPointType) diff --git a/Shared/Translations/Buttons.strings b/Shared/Translations/Buttons.strings new file mode 100644 index 000000000..c869b0268 --- /dev/null +++ b/Shared/Translations/Buttons.strings @@ -0,0 +1,10 @@ +/* + Buttons.strings + NetNewsWire + + Created by Stuart Breckenridge on 15/12/2022. + Copyright © 2022 Ranchero Software. All rights reserved. +*/ + +"CANCEL_BUTTON_TITLE" = "Cancel"; +"DONE_BUTTON_TITLE" = "Done"; diff --git a/iOS/Inspector/AccountInspectorViewController.swift b/iOS/Inspector/AccountInspectorViewController.swift deleted file mode 100644 index 95c3c7e01..000000000 --- a/iOS/Inspector/AccountInspectorViewController.swift +++ /dev/null @@ -1,231 +0,0 @@ -// -// AccountInspectorViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 5/17/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit -import SafariServices -import Account -import SwiftUI - -struct AccountInspectorWrapper: UIViewControllerRepresentable { - - var account: Account - - func makeUIViewController(context: Context) -> AccountInspectorViewController { - let controller = UIStoryboard.inspector.instantiateViewController(withIdentifier: "AccountInspectorViewController") as! AccountInspectorViewController - controller.account = account - return controller - } - - func updateUIViewController(_ uiViewController: AccountInspectorViewController, context: Context) { - // - } - - typealias UIViewControllerType = AccountInspectorViewController - -} - - -class AccountInspectorViewController: UITableViewController { - - static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 400.0) - - @IBOutlet weak var nameTextField: UITextField! - @IBOutlet weak var activeSwitch: UISwitch! - @IBOutlet weak var deleteAccountButton: VibrantButton! - @IBOutlet weak var limitationsAndSolutionsView: UIView! - - var isModal = false - weak var account: Account? - - override func viewDidLoad() { - super.viewDidLoad() - - guard let account = account else { return } - - nameTextField.placeholder = account.defaultName - nameTextField.text = account.name - nameTextField.delegate = self - activeSwitch.isOn = account.isActive - - navigationItem.title = account.nameForDisplay - - if account.type != .onMyMac { - deleteAccountButton.setTitle(NSLocalizedString("Remove Account", comment: "Remove Account"), for: .normal) - } - - if account.type != .cloudKit { - limitationsAndSolutionsView.isHidden = true - } - - if isModal { - let doneBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(done)) - navigationItem.leftBarButtonItem = doneBarButtonItem - } - - tableView.register(ImageHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader") - - } - - override func viewWillDisappear(_ animated: Bool) { - account?.name = nameTextField.text - account?.isActive = activeSwitch.isOn - } - - @objc func done() { - dismiss(animated: true) - } - - @IBAction func credentials(_ sender: Any) { - guard let account = account else { return } - switch account.type { - case .feedbin: - let navController = UIStoryboard.account.instantiateViewController(withIdentifier: "FeedbinAccountNavigationViewController") as! UINavigationController - let addViewController = navController.topViewController as! FeedbinAccountViewController - addViewController.account = account - navController.modalPresentationStyle = .currentContext - present(navController, animated: true) - case .newsBlur: - let navController = UIStoryboard.account.instantiateViewController(withIdentifier: "NewsBlurAccountNavigationViewController") as! UINavigationController - let addViewController = navController.topViewController as! NewsBlurAccountViewController - addViewController.account = account - navController.modalPresentationStyle = .currentContext - present(navController, animated: true) - case .inoreader, .bazQux, .theOldReader, .freshRSS: - let navController = UIStoryboard.account.instantiateViewController(withIdentifier: "ReaderAPIAccountNavigationViewController") as! UINavigationController - let addViewController = navController.topViewController as! ReaderAPIAccountViewController - addViewController.accountType = account.type - addViewController.account = account - navController.modalPresentationStyle = .currentContext - present(navController, animated: true) - default: - break - } - } - - @IBAction func deleteAccount(_ sender: Any) { - guard let account = account else { - return - } - - let title = NSLocalizedString("Remove Account", comment: "Remove Account") - let message: String = { - switch account.type { - case .feedly: - return NSLocalizedString("Are you sure you want to remove this account? NetNewsWire will no longer be able to access articles and feeds unless the account is added again.", comment: "Log Out and Remove Account") - default: - return NSLocalizedString("Are you sure you want to remove this account? This cannot be undone.", comment: "Remove Account") - } - }() - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) - alertController.addAction(cancelAction) - - let markTitle = NSLocalizedString("Remove", comment: "Remove") - let markAction = UIAlertAction(title: markTitle, style: .default) { [weak self] (action) in - guard let self = self, let account = self.account else { return } - AccountManager.shared.deleteAccount(account) - if self.isModal { - self.dismiss(animated: true) - } else { - self.navigationController?.popViewController(animated: true) - } - } - alertController.addAction(markAction) - alertController.preferredAction = markAction - - present(alertController, animated: true) - } - - @IBAction func openLimitationsAndSolutions(_ sender: Any) { - let vc = SFSafariViewController(url: CloudKitWebDocumentation.limitationsAndSolutionsURL) - vc.modalPresentationStyle = .pageSheet - present(vc, animated: true) - } - -} - -// MARK: Table View - -extension AccountInspectorViewController { - - var hidesCredentialsSection: Bool { - guard let account = account else { - return true - } - switch account.type { - case .onMyMac, .cloudKit, .feedly: - return true - default: - return false - } - } - - override func numberOfSections(in tableView: UITableView) -> Int { - guard let account = account else { return 0 } - - if account == AccountManager.shared.defaultAccount { - return 1 - } else if hidesCredentialsSection { - return 2 - } else { - return super.numberOfSections(in: tableView) - } - } - - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return section == 0 ? ImageHeaderView.rowHeight : super.tableView(tableView, heightForHeaderInSection: section) - } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - guard let account = account else { return nil } - - if section == 0 { - let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! ImageHeaderView - headerView.imageView.image = AppAssets.image(for: account.type) - return headerView - } else { - return super.tableView(tableView, viewForHeaderInSection: section) - } - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell: UITableViewCell - - if indexPath.section == 1, hidesCredentialsSection { - cell = super.tableView(tableView, cellForRowAt: IndexPath(row: 0, section: 2)) - } else { - cell = super.tableView(tableView, cellForRowAt: indexPath) - } - - return cell - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - if indexPath.section > 0 { - return true - } - return false - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - } - -} - -// MARK: UITextFieldDelegate - -extension AccountInspectorViewController: UITextFieldDelegate { - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return true - } - -} diff --git a/iOS/Inspector/ExtensionInspectorViewController.swift b/iOS/Inspector/ExtensionInspectorViewController.swift deleted file mode 100644 index 74b885890..000000000 --- a/iOS/Inspector/ExtensionInspectorViewController.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// ExtensionPointInspectorViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 4/16/20. -// Copyright © 2020 Ranchero Software. All rights reserved. -// - -import UIKit -import SwiftUI - -struct ExtensionPointInspectorWrapper: UIViewControllerRepresentable { - - var extensionPoint: ExtensionPoint? - - func makeUIViewController(context: Context) -> ExtensionPointInspectorViewController { - let controller = UIStoryboard.inspector.instantiateViewController(withIdentifier: "ExtensionPointInspectorViewController") as! ExtensionPointInspectorViewController - controller.extensionPoint = extensionPoint - return controller - } - - func updateUIViewController(_ uiViewController: ExtensionPointInspectorViewController, context: Context) { - // - } - - typealias UIViewControllerType = ExtensionPointInspectorViewController - - -} - - -class ExtensionPointInspectorViewController: UITableViewController { - - @IBOutlet weak var extensionDescription: UILabel! - var extensionPoint: ExtensionPoint? - - override func viewDidLoad() { - super.viewDidLoad() - guard let extensionPoint = extensionPoint else { return } - navigationItem.title = extensionPoint.title - extensionDescription.attributedText = extensionPoint.description - tableView.register(ImageHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader") - } - - @IBAction func disable(_ sender: Any) { - guard let extensionPoint = extensionPoint else { return } - - let title = NSLocalizedString("Deactivate Extension", comment: "Deactivate Extension") - let extensionPointTypeTitle = extensionPoint.extensionPointID.extensionPointType.title - let message = NSLocalizedString("Are you sure you want to deactivate the \(extensionPointTypeTitle) extension “\(extensionPoint.title)”?", comment: "Deactivate text") - - let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel") - let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) - alertController.addAction(cancelAction) - - let markTitle = NSLocalizedString("Deactivate", comment: "Deactivate") - let markAction = UIAlertAction(title: markTitle, style: .default) { [weak self] (action) in - ExtensionPointManager.shared.deactivateExtensionPoint(extensionPoint.extensionPointID) - self?.navigationController?.popViewController(animated: true) - } - alertController.addAction(markAction) - alertController.preferredAction = markAction - - present(alertController, animated: true) - - } -} - -// MARK: Table View - -extension ExtensionPointInspectorViewController { - - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return section == 0 ? ImageHeaderView.rowHeight : super.tableView(tableView, heightForHeaderInSection: section) - } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - guard let extensionPoint = extensionPoint else { return nil } - - if section == 0 { - let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! ImageHeaderView - headerView.imageView.image = extensionPoint.image - return headerView - } else { - return super.tableView(tableView, viewForHeaderInSection: section) - } - } - - override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { - if indexPath.section > 0 { - return true - } - return false - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - tableView.selectRow(at: nil, animated: true, scrollPosition: .none) - } - -} - diff --git a/iOS/Inspector/Inspector.storyboard b/iOS/Inspector/Inspector.storyboard deleted file mode 100644 index b9c566da5..000000000 --- a/iOS/Inspector/Inspector.storyboard +++ /dev/null @@ -1,516 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS/Inspector/Inspector.strings b/iOS/Inspector/Inspector.strings new file mode 100644 index 000000000..fa413a537 --- /dev/null +++ b/iOS/Inspector/Inspector.strings @@ -0,0 +1,23 @@ +/* + Inspector.strings + NetNewsWire + + Created by Stuart Breckenridge on 15/12/2022. + Copyright © 2022 Ranchero Software. All rights reserved. +*/ + +/* Account Inspector */ +"ACCOUNT_NAME_FIELD" = "Account Name"; +"ACTIVE" = "Active"; +"CLOUDKIT_LIMITATIONS_TITLE" = "[iCloud Syncing Limitations & Solutions](https://netnewswire.com/help/iCloud)"; +"REMOVE_ACCOUNT_TITLE" = "Remove Account"; +"REMOVE_ACCOUNT_BUTTON_TITLE" = "Remove Account"; +"REMOVE_FEEDLY_MESSAGE" = "Are you sure you want to remove this account? NetNewsWire will no longer be able to access articles and feeds unless the account is added again."; +"REMOVE_ACCOUNT_MESSAGE" = "Are you sure you want to remove this account? This cannot be undone."; +"REMOVE_ACCOUNT_TITLE" = "Remove Account"; + + +"NOTIFY_ABOUT_NEW_ARTICLES" = "Notify About New Articles"; +"ALWAYS_SHOW_READER_VIEW" = "Always Show Reader View"; +"HOME_PAGE" = "Home Page"; +"FEED_URL" = "Feed URL"; diff --git a/iOS/Inspector/InspectorIconHeaderView.swift b/iOS/Inspector/InspectorIconHeaderView.swift deleted file mode 100644 index e0e45f559..000000000 --- a/iOS/Inspector/InspectorIconHeaderView.swift +++ /dev/null @@ -1,34 +0,0 @@ -// -// InspectorIconHeaderView.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 11/6/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit - -class InspectorIconHeaderView: UITableViewHeaderFooterView { - - var iconView = IconView() - - override init(reuseIdentifier: String?) { - super.init(reuseIdentifier: reuseIdentifier) - commonInit() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - commonInit() - } - - func commonInit() { - addSubview(iconView) - } - - override func layoutSubviews() { - let x = (bounds.width - 48.0) / 2 - let y = (bounds.height - 48.0) / 2 - iconView.frame = CGRect(x: x, y: y, width: 48.0, height: 48.0) - } -} diff --git a/iOS/Inspector/Views/AccountInspectorView.swift b/iOS/Inspector/Views/AccountInspectorView.swift new file mode 100644 index 000000000..13f75a441 --- /dev/null +++ b/iOS/Inspector/Views/AccountInspectorView.swift @@ -0,0 +1,105 @@ +// +// AccountInspectorView.swift +// NetNewsWire-iOS +// +// Created by Stuart Breckenridge on 15/12/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import SwiftUI +import SafariServices +import Account + +struct AccountInspectorView: View { + + @Environment(\.dismiss) var dismiss + @State private var showRemoveAccountAlert: Bool = false + var account: Account + + var body: some View { + Form { + Section(header: accountHeaderView){} + + TextField(text: Binding( + get: { account.name ?? account.defaultName }, + set: { account.name = $0 }), + prompt: Text(account.defaultName)) { + Text("ACCOUNT_NAME", tableName: "Inspector") + } + + Toggle(isOn: Binding(get: { + account.isActive + }, set: { account.isActive = $0 })) { + Text("ACTIVE", tableName: "Inspector") + } + + if account != AccountManager.shared.defaultAccount { + Section { + Button(role: .destructive) { + showRemoveAccountAlert = true + } label: { + HStack { + Spacer() + Text("REMOVE_ACCOUNT_BUTTON_TITLE", tableName: "Inspector") + Spacer() + } + } + .confirmationDialog(Text("REMOVE_ACCOUNT_TITLE", tableName: "Inspector"), isPresented: $showRemoveAccountAlert, titleVisibility: .visible) { + Button(role: .destructive) { + AccountManager.shared.deleteAccount(account) + dismiss() + } label: { + Text("REMOVE_ACCOUNT_BUTTON_TITLE", tableName: "Inspector") + } + + Button(role: .cancel) { + // + } label: { + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") + } + + } message: { + if account.type == .feedly { + Text("REMOVE_FEEDLY_MESSAGE", tableName: "Inspector") + } else { + Text("REMOVE_ACCOUNT_MESSAGE", tableName: "Inspector") + } + } + } + } + + if account.type == .cloudKit { + Section(footer: cloudKitLimitations){} + } + } + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(account.nameForDisplay) + .tint(Color(uiColor: AppAssets.primaryAccentColor)) + .edgesIgnoringSafeArea(.bottom) // Fix to make sure view is not offset from the top when presented + } + + var accountHeaderView: some View { + HStack { + Spacer() + Image(uiImage: account.smallIcon!.image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 30, height: 30) + Spacer() + } + } + + var cloudKitLimitations: some View { + HStack { + Spacer() + Text("CLOUDKIT_LIMITATIONS_TITLE", tableName: "Inspector") + Spacer() + } + } +} + +struct AccountInspectorView_Previews: PreviewProvider { + static var previews: some View { + AccountInspectorView(account: AccountManager.shared.defaultAccount) + } +} diff --git a/iOS/Inspector/Views/ExtensionInspectorView.swift b/iOS/Inspector/Views/ExtensionInspectorView.swift new file mode 100644 index 000000000..148aee0e2 --- /dev/null +++ b/iOS/Inspector/Views/ExtensionInspectorView.swift @@ -0,0 +1,72 @@ +// +// ExtensionInspectorView.swift +// NetNewsWire-iOS +// +// Created by Stuart Breckenridge on 15/12/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import SwiftUI + +struct ExtensionInspectorView: View { + + @State private var showDeactivateConfirmation: Bool = false + var extensionPoint: ExtensionPoint? + + var body: some View { + Form { + Section(header: extensionHeader) {} + Section(footer: Text(extensionPoint?.description.string ?? ""), content: { + // + }) + + HStack { + Spacer() + Button(role: .destructive) { + showDeactivateConfirmation = true + } label: { + Text("DEACTIVATE_EXTENSION_TITLE", tableName: "Settings") + } + .confirmationDialog(Text("DEACTIVATE_EXTENSION_TITLE", tableName: "Settings") , isPresented: $showDeactivateConfirmation, titleVisibility: .visible) { + + Button(role: .destructive) { + ExtensionPointManager.shared.deactivateExtensionPoint(extensionPoint!.extensionPointID) + } label: { + Text("DEACTIVATE", tableName: "Settings") + } + + Button(role: .cancel) { + // + } label: { + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") + } + } message: { + Text("DEACTIVATE_EXTENSION \(extensionPoint?.title ?? "")", tableName: "Settings") + } + Spacer() + } + + + } + .navigationTitle(Text(extensionPoint?.title ?? "")) + .edgesIgnoringSafeArea(.bottom) + } + + + var extensionHeader: some View { + HStack { + Spacer() + Image(uiImage: extensionPoint!.image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 30, height: 30) + Spacer() + } + } +} + +struct ExtensionInspectorView_Previews: PreviewProvider { + static var previews: some View { + ExtensionInspectorView() + } +} diff --git a/iOS/Inspector/Views/WebFeedInspectorView.swift b/iOS/Inspector/Views/WebFeedInspectorView.swift new file mode 100644 index 000000000..bc145356e --- /dev/null +++ b/iOS/Inspector/Views/WebFeedInspectorView.swift @@ -0,0 +1,85 @@ +// +// WebFeedInspectorView.swift +// NetNewsWire-iOS +// +// Created by Stuart Breckenridge on 15/12/2022. +// Copyright © 2022 Ranchero Software. All rights reserved. +// + +import SwiftUI +import Account +import SafariServices +import UserNotifications + +struct WebFeedInspectorView: View { + + var webFeed: WebFeed! + @State private var showHomePage: Bool = false + + var body: some View { + Form { + + Section(header: webFeedHeaderView) {} + + Section { + TextField(webFeed.nameForDisplay, + text: Binding( + get: { webFeed.name ?? webFeed.nameForDisplay }, + set: { webFeed.name = $0 }), + prompt: nil) + + Toggle(isOn: Binding(get: { webFeed.isNotifyAboutNewArticles ?? false }, set: { webFeed.isNotifyAboutNewArticles = $0 })) { + Text("NOTIFY_ABOUT_NEW_ARTICLES", tableName: "Inspector") + } + + if webFeed.isFeedProvider == false { + Toggle(isOn: Binding( + get: { webFeed.isArticleExtractorAlwaysOn ?? false }, + set: { webFeed.isArticleExtractorAlwaysOn = $0 })) { + Text("ALWAYS_SHOW_READER_VIEW", tableName: "Inspector") + } + } + } + + Section(header: Text("HOME_PAGE", tableName: "Inspector")) { + HStack { + Text(webFeed.homePageURL?.decodedURLString ?? "") + Spacer() + Image(uiImage: AppAssets.safariImage) + .renderingMode(.template) + .foregroundColor(Color(uiColor: AppAssets.primaryAccentColor)) + } + .onTapGesture { + if webFeed.homePageURL != nil { showHomePage = true } + } + } + + Section(header: Text("FEED_URL", tableName: "Inspector")) { + Text(webFeed.url.description) + } + } + .navigationBarTitleDisplayMode(.inline) + .navigationTitle(webFeed.nameForDisplay) + .sheet(isPresented: $showHomePage, onDismiss: nil) { + //SwiftUISafariView(url: URL(string: webFeed.homePageURL!)!) + SafariView(url: URL(string: webFeed.homePageURL!)!) + } + } + + var webFeedHeaderView: some View { + HStack { + Spacer() + Image(uiImage: webFeed.smallIcon!.image) + .resizable() + .aspectRatio(contentMode: .fit) + .frame(width: 30, height: 30) + Spacer() + } + } +} + +struct WebFeedInspectorView_Previews: PreviewProvider { + static var previews: some View { + WebFeedInspectorView() + } +} diff --git a/iOS/Inspector/WebFeedInspectorViewController.swift b/iOS/Inspector/WebFeedInspectorViewController.swift deleted file mode 100644 index 3a96b70df..000000000 --- a/iOS/Inspector/WebFeedInspectorViewController.swift +++ /dev/null @@ -1,233 +0,0 @@ -// -// WebFeedInspectorViewController.swift -// NetNewsWire-iOS -// -// Created by Maurice Parker on 11/6/19. -// Copyright © 2019 Ranchero Software. All rights reserved. -// - -import UIKit -import Account -import SafariServices -import UserNotifications - -class WebFeedInspectorViewController: UITableViewController { - - static let preferredContentSizeForFormSheetDisplay = CGSize(width: 460.0, height: 500.0) - - var webFeed: WebFeed! - @IBOutlet weak var nameTextField: UITextField! - @IBOutlet weak var notifyAboutNewArticlesSwitch: UISwitch! - @IBOutlet weak var alwaysShowReaderViewSwitch: UISwitch! - @IBOutlet weak var homePageLabel: InteractiveLabel! - @IBOutlet weak var feedURLLabel: InteractiveLabel! - - private var headerView: InspectorIconHeaderView? - private var iconImage: IconImage? { - return IconImageCache.shared.imageForFeed(webFeed) - } - - private let homePageIndexPath = IndexPath(row: 0, section: 1) - - private var shouldHideHomePageSection: Bool { - return webFeed.homePageURL == nil - } - - private var userNotificationSettings: UNNotificationSettings? - - override func viewDidLoad() { - tableView.register(InspectorIconHeaderView.self, forHeaderFooterViewReuseIdentifier: "SectionHeader") - - navigationItem.title = webFeed.nameForDisplay - nameTextField.text = webFeed.nameForDisplay - - notifyAboutNewArticlesSwitch.setOn(webFeed.isNotifyAboutNewArticles ?? false, animated: false) - - if webFeed.isFeedProvider { - alwaysShowReaderViewSwitch.isOn = false - alwaysShowReaderViewSwitch.isEnabled = false - } else { - alwaysShowReaderViewSwitch.setOn(webFeed.isArticleExtractorAlwaysOn ?? false, animated: false) - } - - - homePageLabel.text = webFeed.homePageURL?.decodedURLString - feedURLLabel.text = webFeed.url.decodedURLString - - NotificationCenter.default.addObserver(self, selector: #selector(webFeedIconDidBecomeAvailable(_:)), name: .WebFeedIconDidBecomeAvailable, object: nil) - - NotificationCenter.default.addObserver(self, selector: #selector(updateNotificationSettings), name: UIApplication.willEnterForegroundNotification, object: nil) - - } - - override func viewDidAppear(_ animated: Bool) { - updateNotificationSettings() - } - - override func viewDidDisappear(_ animated: Bool) { - if nameTextField.text != webFeed.nameForDisplay { - let nameText = nameTextField.text ?? "" - let newName = nameText.isEmpty ? (webFeed.name ?? NSLocalizedString("Untitled", comment: "Feed name")) : nameText - webFeed.rename(to: newName) { _ in } - } - } - - // MARK: Notifications - @objc func webFeedIconDidBecomeAvailable(_ notification: Notification) { - headerView?.iconView.iconImage = iconImage - } - - @IBAction func notifyAboutNewArticlesChanged(_ sender: Any) { - guard let settings = userNotificationSettings else { - notifyAboutNewArticlesSwitch.isOn = !notifyAboutNewArticlesSwitch.isOn - return - } - if settings.authorizationStatus == .denied { - notifyAboutNewArticlesSwitch.isOn = !notifyAboutNewArticlesSwitch.isOn - present(notificationUpdateErrorAlert(), animated: true, completion: nil) - } else if settings.authorizationStatus == .authorized { - webFeed.isNotifyAboutNewArticles = notifyAboutNewArticlesSwitch.isOn - } else { - UNUserNotificationCenter.current().requestAuthorization(options:[.badge, .sound, .alert]) { (granted, error) in - self.updateNotificationSettings() - if granted { - DispatchQueue.main.async { - self.webFeed.isNotifyAboutNewArticles = self.notifyAboutNewArticlesSwitch.isOn - UIApplication.shared.registerForRemoteNotifications() - } - } else { - DispatchQueue.main.async { - self.notifyAboutNewArticlesSwitch.isOn = !self.notifyAboutNewArticlesSwitch.isOn - } - } - } - } - } - - @IBAction func alwaysShowReaderViewChanged(_ sender: Any) { - webFeed.isArticleExtractorAlwaysOn = alwaysShowReaderViewSwitch.isOn - } - - @IBAction func done(_ sender: Any) { - dismiss(animated: true) - } - - /// Returns a new indexPath, taking into consideration any - /// conditions that may require the tableView to be - /// displayed differently than what is setup in the storyboard. - private func shift(_ indexPath: IndexPath) -> IndexPath { - return IndexPath(row: indexPath.row, section: shift(indexPath.section)) - } - - /// Returns a new section, taking into consideration any - /// conditions that may require the tableView to be - /// displayed differently than what is setup in the storyboard. - private func shift(_ section: Int) -> Int { - if section >= homePageIndexPath.section && shouldHideHomePageSection { - return section + 1 - } - return section - } - - -} - -// MARK: Table View - -extension WebFeedInspectorViewController { - - override func numberOfSections(in tableView: UITableView) -> Int { - let numberOfSections = super.numberOfSections(in: tableView) - return shouldHideHomePageSection ? numberOfSections - 1 : numberOfSections - } - - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return super.tableView(tableView, numberOfRowsInSection: shift(section)) - } - - override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { - return section == 0 ? ImageHeaderView.rowHeight : super.tableView(tableView, heightForHeaderInSection: shift(section)) - } - - override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = super.tableView(tableView, cellForRowAt: shift(indexPath)) - if indexPath.section == 0 && indexPath.row == 1 { - guard let label = cell.contentView.subviews.filter({ $0.isKind(of: UILabel.self) })[0] as? UILabel else { - return cell - } - label.numberOfLines = 2 - label.text = webFeed.notificationDisplayName.capitalized - } - return cell - } - - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - super.tableView(tableView, titleForHeaderInSection: shift(section)) - } - - override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - if shift(section) == 0 { - headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as? InspectorIconHeaderView - headerView?.iconView.iconImage = iconImage - return headerView - } else { - return super.tableView(tableView, viewForHeaderInSection: shift(section)) - } - } - - override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - if shift(indexPath) == homePageIndexPath, - let homePageUrlString = webFeed.homePageURL, - let homePageUrl = URL(string: homePageUrlString) { - - let safari = SFSafariViewController(url: homePageUrl) - safari.modalPresentationStyle = .pageSheet - present(safari, animated: true) { - tableView.deselectRow(at: indexPath, animated: true) - } - } - } - -} - -// MARK: UITextFieldDelegate - -extension WebFeedInspectorViewController: UITextFieldDelegate { - - func textFieldShouldReturn(_ textField: UITextField) -> Bool { - textField.resignFirstResponder() - return true - } - -} - -// MARK: UNUserNotificationCenter - -extension WebFeedInspectorViewController { - - @objc - func updateNotificationSettings() { - UNUserNotificationCenter.current().getNotificationSettings { (settings) in - DispatchQueue.main.async { - self.userNotificationSettings = settings - if settings.authorizationStatus == .authorized { - UIApplication.shared.registerForRemoteNotifications() - } - } - } - } - - func notificationUpdateErrorAlert() -> UIAlertController { - let alert = UIAlertController(title: NSLocalizedString("Enable Notifications", comment: "Notifications"), - message: NSLocalizedString("Notifications need to be enabled in the Settings app.", comment: "Notifications need to be enabled in the Settings app."), preferredStyle: .alert) - let openSettings = UIAlertAction(title: NSLocalizedString("Open Settings", comment: "Open Settings"), style: .default) { (action) in - UIApplication.shared.open(URL(string: UIApplication.openSettingsURLString)!, options: [UIApplication.OpenExternalURLOptionsKey.universalLinksOnly : false], completionHandler: nil) - } - let dismiss = UIAlertAction(title: NSLocalizedString("Dismiss", comment: "Dismiss"), style: .cancel, handler: nil) - alert.addAction(openSettings) - alert.addAction(dismiss) - alert.preferredAction = openSettings - return alert - } - -} diff --git a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/Contents.json b/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/Contents.json index b16e4373f..64197aab9 100644 --- a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/Contents.json +++ b/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/Contents.json @@ -1,16 +1,6 @@ { "images" : [ { - "filename" : "feedbin-logo-filled-1.pdf", - "idiom" : "universal" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], "filename" : "feedbin-logo-filled.pdf", "idiom" : "universal" } diff --git a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled-1.pdf b/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled-1.pdf deleted file mode 100644 index a68d754ae..000000000 Binary files a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled-1.pdf and /dev/null differ diff --git a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled.pdf b/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled.pdf index a68d754ae..fd592dbf4 100644 Binary files a/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled.pdf and b/iOS/Resources/Assets.xcassets/accountFeedbin.imageset/feedbin-logo-filled.pdf differ diff --git a/iOS/SceneCoordinator.swift b/iOS/SceneCoordinator.swift index 8fe3259af..1ec3d517b 100644 --- a/iOS/SceneCoordinator.swift +++ b/iOS/SceneCoordinator.swift @@ -1167,14 +1167,17 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging { } func showAccountInspector(for account: Account) { - let accountInspectorNavController = - UIStoryboard.inspector.instantiateViewController(identifier: "AccountInspectorNavigationViewController") as! UINavigationController - let accountInspectorController = accountInspectorNavController.topViewController as! AccountInspectorViewController - accountInspectorNavController.modalPresentationStyle = .formSheet - accountInspectorNavController.preferredContentSize = AccountInspectorViewController.preferredContentSizeForFormSheetDisplay - accountInspectorController.isModal = true - accountInspectorController.account = account - rootSplitViewController.present(accountInspectorNavController, animated: true) + let hosting = UIHostingController(rootView: InjectedNavigationView(injectedView: AccountInspectorView(account: account))) + rootSplitViewController.present(hosting, animated: true, completion: nil) + +// let accountInspectorNavController = +// UIStoryboard.inspector.instantiateViewController(identifier: "AccountInspectorNavigationViewController") as! UINavigationController +// let accountInspectorController = accountInspectorNavController.topViewController as! AccountInspectorViewController +// accountInspectorNavController.modalPresentationStyle = .formSheet +// accountInspectorNavController.preferredContentSize = AccountInspectorViewController.preferredContentSizeForFormSheetDisplay +// accountInspectorController.isModal = true +// accountInspectorController.account = account +// rootSplitViewController.present(accountInspectorNavController, animated: true) } func showFeedInspector() { @@ -1187,13 +1190,10 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, Logging { } func showFeedInspector(for feed: WebFeed) { - let feedInspectorNavController = - UIStoryboard.inspector.instantiateViewController(identifier: "FeedInspectorNavigationViewController") as! UINavigationController - let feedInspectorController = feedInspectorNavController.topViewController as! WebFeedInspectorViewController - feedInspectorNavController.modalPresentationStyle = .formSheet - feedInspectorNavController.preferredContentSize = WebFeedInspectorViewController.preferredContentSizeForFormSheetDisplay - feedInspectorController.webFeed = feed - rootSplitViewController.present(feedInspectorNavController, animated: true) + + let hosting = UIHostingController(rootView: InjectedNavigationView(injectedView: WebFeedInspectorView(webFeed: feed))) + + rootSplitViewController.present(hosting, animated: true) } func showAddWebFeed(initialFeed: String? = nil, initialFeedName: String? = nil) { diff --git a/iOS/Settings/Settings.strings b/iOS/Settings/Settings.strings index b87334880..a6650a130 100644 --- a/iOS/Settings/Settings.strings +++ b/iOS/Settings/Settings.strings @@ -46,7 +46,6 @@ "OPEN_LINKS_IN_APP" = "Open Links in NetNewsWire"; /* Account Management */ - "ADD_ACCOUNT" = "Add Account"; "NO_INACTIVE_ACCOUNT_FOOTER" = "There are no inactive accounts."; "ACCOUNT_REMOVE %@" = "Are you sure you want to remove “%@”?"; @@ -56,21 +55,18 @@ "INACTIVE_ACCOUNTS_HEADER" = "Inactive Accounts"; /* Extension Management */ - "DEACTIVATE" = "Deactivate"; "DEACTIVATE_EXTENSION_TITLE" = "Deactivate Extension"; -"DEACTIVATE_EXTENSION %@" = "Deactivate “%@”"; +"DEACTIVATE_EXTENSION %@" = "Are you sure you want to deactivate the “%@” extension?"; "ACTIVE_EXTENSIONS" = "Active Extensions"; "FEED_PROVIDER_HEADER" = "Feed Provider"; "FEED_PROVIDER_FOOTER" = "Feed Providers allow you to subscribe to some pages as if they were RSS Feeds."; "ADD_EXTENSIONS_TITLE" = "Add Extension"; /* New Article Notifications */ - "NEW_ARTICLE_NOTIFICATIONS_TITLE" = "New Article Notifications"; /* About */ - "ABOUT_TITLE" = "About"; "PRIMARY_CONTRIBUTORS" = "Primary Contributors"; "ADDITIONAL_CONTRIBUTORS" = "Additional Contributors"; @@ -89,7 +85,6 @@ /* Alerts */ - "IMPORT_OPML_CONFIRMATION" = "Choose an account to receive the imported feeds and folders"; "IMPORT_OPML_SUCCESS_TITLE" = "Imported Successfully"; "IMPORT_OPML_SUCCESS_MESSAGE %@" = "Subscriptions have been imported to your %@ account."; @@ -98,5 +93,3 @@ "EXPORT_OPML_SUCCESS_MESSAGE" = "Your OPML file has been successfully exported."; "ERROR_TITLE" = "Error"; "REMOVE" = "Remove"; -"CANCEL" = "Cancel"; -"DONE" = "Done"; diff --git a/iOS/Settings/Views/Account and Extensions/Accounts/AccountsManagementView.swift b/iOS/Settings/Views/Account and Extensions/Accounts/AccountsManagementView.swift index 497b9f7a3..2bc756eb0 100644 --- a/iOS/Settings/Views/Account and Extensions/Accounts/AccountsManagementView.swift +++ b/iOS/Settings/Views/Account and Extensions/Accounts/AccountsManagementView.swift @@ -73,7 +73,7 @@ struct AccountsManagementView: View { Button(role: .cancel) { accountToRemove = nil } label: { - Text("CANCEL", tableName: "Settings") + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") } } message: { switch accountToRemove { @@ -91,14 +91,15 @@ struct AccountsManagementView: View { } func refreshAccounts() { + sortedActiveAccounts = [] + sortedInactiveAccounts = [] sortedActiveAccounts = AccountManager.shared.sortedActiveAccounts sortedInactiveAccounts = AccountManager.shared.sortedAccounts.filter({ $0.isActive == false }) } func accountRow(_ account: Account, showRemoveAccountAlert: Binding, accountToRemove: Binding) -> some View { NavigationLink { - AccountInspectorWrapper(account: account) - .edgesIgnoringSafeArea(.all) + AccountInspectorView(account: account) } label: { Image(uiImage: account.smallIcon!.image) .resizable() @@ -112,7 +113,7 @@ struct AccountsManagementView: View { showRemoveAccountAlert.wrappedValue = true } label: { Label { - Text("REMOVE_ACCOUNT", tableName: "Settings") + Text("REMOVE_ACCOUNT_TITLE", tableName: "Settings") } icon: { Image(systemName: "trash") } diff --git a/iOS/Settings/Views/Account and Extensions/Accounts/AddAccountView.swift b/iOS/Settings/Views/Account and Extensions/Accounts/AddAccountView.swift index dcaa6384d..6e19a8e6e 100644 --- a/iOS/Settings/Views/Account and Extensions/Accounts/AddAccountView.swift +++ b/iOS/Settings/Views/Account and Extensions/Accounts/AddAccountView.swift @@ -76,11 +76,11 @@ struct AddAccountView: View { .navigationBarTitleDisplayMode(.inline) .listItemTint(.primary) .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { + ToolbarItem(placement: .navigationBarLeading) { Button(role: .cancel) { dismiss() } label: { - Text("DONE", tableName: "Settings") + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") } } } diff --git a/iOS/Settings/Views/Account and Extensions/Extensions/AddExtensionListView.swift b/iOS/Settings/Views/Account and Extensions/Extensions/AddExtensionListView.swift index a67aa73dd..b1dd53af3 100644 --- a/iOS/Settings/Views/Account and Extensions/Extensions/AddExtensionListView.swift +++ b/iOS/Settings/Views/Account and Extensions/Extensions/AddExtensionListView.swift @@ -37,11 +37,11 @@ struct AddExtensionListView: View { .navigationBarTitleDisplayMode(.inline) .navigationTitle(Text("ADD_EXTENSIONS_TITLE", tableName: "Settings")) .toolbar { - ToolbarItem(placement: .navigationBarTrailing) { + ToolbarItem(placement: .navigationBarLeading) { Button(role: .cancel) { dismiss() } label: { - Text("DONE", tableName: "Settings") + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") } } } diff --git a/iOS/Settings/Views/Account and Extensions/Extensions/ExtensionsManagementView.swift b/iOS/Settings/Views/Account and Extensions/Extensions/ExtensionsManagementView.swift index 2727a7ae3..50fb8fe17 100644 --- a/iOS/Settings/Views/Account and Extensions/Extensions/ExtensionsManagementView.swift +++ b/iOS/Settings/Views/Account and Extensions/Extensions/ExtensionsManagementView.swift @@ -45,7 +45,7 @@ struct ExtensionsManagementView: View { Button(role: .cancel) { extensionToDeactivate = nil } label: { - Text("DISMISS", tableName: "Settings") + Text("CANCEL_BUTTON_TITLE", tableName: "Buttons") } } message: { @@ -62,9 +62,7 @@ struct ExtensionsManagementView: View { ForEach(0..