From 8e5d9ddc6c30ccf8d406254e5bc6bf42a3fb1bf0 Mon Sep 17 00:00:00 2001 From: Pascal Chevrel Date: Mon, 25 Nov 2024 17:25:52 +0100 Subject: [PATCH 1/9] Bump - Set version to 135.0 (#23372) --- bitrise.yml | 6 +++--- firefox-ios/Client/Info.plist | 2 +- firefox-ios/CredentialProvider/Info.plist | 2 +- firefox-ios/Extensions/NotificationService/Info.plist | 2 +- firefox-ios/Extensions/ShareTo/Info.plist | 2 +- firefox-ios/WidgetKit/Info.plist | 2 +- focus-ios/Blockzilla/Info.plist | 2 +- focus-ios/ContentBlocker/Info.plist | 2 +- focus-ios/FocusIntentExtension/Info.plist | 2 +- focus-ios/OpenInFocus/Info.plist | 2 +- focus-ios/Widgets/Info.plist | 2 +- 11 files changed, 13 insertions(+), 13 deletions(-) diff --git a/bitrise.yml b/bitrise.yml index 8f9124fec680..4c5f135d3c67 100644 --- a/bitrise.yml +++ b/bitrise.yml @@ -2106,17 +2106,17 @@ app: BITRISE_NIGHTLY_VERSION: '9000' - opts: is_expand: false - BITRISE_RELEASE_VERSION: '134.0' + BITRISE_RELEASE_VERSION: '135.0' - opts: is_expand: false - BITRISE_BETA_VERSION: '134.0' + BITRISE_BETA_VERSION: '135.0' trigger_map: - push_branch: main pipeline: pipeline_build_and_test - push_branch: epic-branch/* pipeline: pipeline_build_and_test -- push_branch: release/v134 +- push_branch: release/v135 pipeline: pipeline_build_and_test - pull_request_target_branch: main pipeline: pipeline_build_and_test diff --git a/firefox-ios/Client/Info.plist b/firefox-ios/Client/Info.plist index 998995d893b1..d0690706c8e1 100644 --- a/firefox-ios/Client/Info.plist +++ b/firefox-ios/Client/Info.plist @@ -28,7 +28,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 134.0 + 135.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/firefox-ios/CredentialProvider/Info.plist b/firefox-ios/CredentialProvider/Info.plist index 517b3cef21c8..aba7f4ab9393 100644 --- a/firefox-ios/CredentialProvider/Info.plist +++ b/firefox-ios/CredentialProvider/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 134.0 + 135.0 CFBundleVersion 1 MozDevelopmentTeam diff --git a/firefox-ios/Extensions/NotificationService/Info.plist b/firefox-ios/Extensions/NotificationService/Info.plist index 70ef54cf2901..e18f461821eb 100644 --- a/firefox-ios/Extensions/NotificationService/Info.plist +++ b/firefox-ios/Extensions/NotificationService/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 134.0 + 135.0 CFBundleVersion 1 MozDevelopmentTeam diff --git a/firefox-ios/Extensions/ShareTo/Info.plist b/firefox-ios/Extensions/ShareTo/Info.plist index 3e1aa4eb18db..be97b311ace0 100644 --- a/firefox-ios/Extensions/ShareTo/Info.plist +++ b/firefox-ios/Extensions/ShareTo/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 134.0 + 135.0 CFBundleSignature ???? CFBundleVersion diff --git a/firefox-ios/WidgetKit/Info.plist b/firefox-ios/WidgetKit/Info.plist index c082a344a2bc..7c3840f3d01b 100644 --- a/firefox-ios/WidgetKit/Info.plist +++ b/firefox-ios/WidgetKit/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType $(PRODUCT_BUNDLE_PACKAGE_TYPE) CFBundleShortVersionString - 134.0 + 135.0 CFBundleVersion 1 MozDevelopmentTeam diff --git a/focus-ios/Blockzilla/Info.plist b/focus-ios/Blockzilla/Info.plist index c8761ecf7a73..dcb11d503297 100644 --- a/focus-ios/Blockzilla/Info.plist +++ b/focus-ios/Blockzilla/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 134.0 + 135.0 CFBundleSignature ???? CFBundleURLTypes diff --git a/focus-ios/ContentBlocker/Info.plist b/focus-ios/ContentBlocker/Info.plist index a7120e7badeb..fd0d025bbbd0 100644 --- a/focus-ios/ContentBlocker/Info.plist +++ b/focus-ios/ContentBlocker/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 134.0 + 135.0 CFBundleSignature ???? CFBundleVersion diff --git a/focus-ios/FocusIntentExtension/Info.plist b/focus-ios/FocusIntentExtension/Info.plist index 93e5c9db488b..b6bfb313bf79 100644 --- a/focus-ios/FocusIntentExtension/Info.plist +++ b/focus-ios/FocusIntentExtension/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 134.0 + 135.0 CFBundleVersion 1 NSExtension diff --git a/focus-ios/OpenInFocus/Info.plist b/focus-ios/OpenInFocus/Info.plist index 7aa757a79025..69f45ba3ea9d 100644 --- a/focus-ios/OpenInFocus/Info.plist +++ b/focus-ios/OpenInFocus/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 134.0 + 135.0 CFBundleVersion 1 NSExtension diff --git a/focus-ios/Widgets/Info.plist b/focus-ios/Widgets/Info.plist index 1dbe57bd5d19..7393560e4e18 100644 --- a/focus-ios/Widgets/Info.plist +++ b/focus-ios/Widgets/Info.plist @@ -3,7 +3,7 @@ CFBundleShortVersionString - 134.0 + 135.0 NSExtension NSExtensionPointIdentifier From caffb15c56a27e7aeac36e2262e2494a650cfb8b Mon Sep 17 00:00:00 2001 From: lmarceau Date: Mon, 25 Nov 2024 12:32:04 -0500 Subject: [PATCH 2/9] Add FXIOS-10639 #23286 Inactive tab telemetry back into tab tray (#23296) * Clean up + trying to figure out where to put telemetry calls * Fix telemetry, add tests * Clean up * Rename TabDisplayPanel to TabDisplayPanelViewController --- firefox-ios/Client.xcodeproj/project.pbxproj | 26 ++++----- .../TabTray/TabTrayCoordinator.swift | 6 +-- .../Browser/Tabs/Action/TabPanelAction.swift | 5 +- .../Browser/Tabs/InactiveTabsTelemetry.swift | 36 +++++++++++++ .../Middleware/TabManagerMiddleware.swift | 22 ++++++-- ...ft => TabDisplayPanelViewController.swift} | 12 +++-- .../Browser/Tabs/Views/TabDisplayView.swift | 7 ++- .../Browser/TopTabDisplayManager.swift | 1 - .../Client/Telemetry/TelemetryWrapper.swift | 26 --------- .../TabTray/InactiveTabsTelemetryTests.swift | 53 +++++++++++++++++++ .../TabTray/TabDisplayPanelTests.swift | 4 +- .../TabTray/TabTrayViewControllerTests.swift | 4 +- .../Telemetry/ToolbarTelemetryTests.swift | 5 ++ 13 files changed, 150 insertions(+), 57 deletions(-) create mode 100644 firefox-ios/Client/Frontend/Browser/Tabs/InactiveTabsTelemetry.swift rename firefox-ios/Client/Frontend/Browser/Tabs/Views/{TabDisplayPanel.swift => TabDisplayPanelViewController.swift} (95%) create mode 100644 firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/InactiveTabsTelemetryTests.swift diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index 368578867690..41cc57e0aea8 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -162,7 +162,7 @@ 2137786529832C8900D01309 /* OverlayModeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2137786429832C8900D01309 /* OverlayModeManager.swift */; }; 213B67A627CE682B000542F5 /* StartAtHomeHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213B67A527CE682B000542F5 /* StartAtHomeHelper.swift */; }; 213B67A827CE721E000542F5 /* StartAtHomeHelperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213B67A727CE721E000542F5 /* StartAtHomeHelperTests.swift */; }; - 213BF7532AC21D1B00C53A64 /* TabDisplayPanel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213BF7522AC21D1B00C53A64 /* TabDisplayPanel.swift */; }; + 213BF7532AC21D1B00C53A64 /* TabDisplayPanelViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 213BF7522AC21D1B00C53A64 /* TabDisplayPanelViewController.swift */; }; 21420EF72ABA338D00B28550 /* TabTrayCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21420EF62ABA338D00B28550 /* TabTrayCoordinator.swift */; }; 21420EF92ABC75A400B28550 /* TabTrayCoordinatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21420EF82ABC75A400B28550 /* TabTrayCoordinatorTests.swift */; }; 214EF4152AC5D5D0005BCCDA /* TabDisplayView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214EF4142AC5D5D0005BCCDA /* TabDisplayView.swift */; }; @@ -716,6 +716,7 @@ 8A1F6C312BC5A6BE00DA6F86 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8ACD3B972BA8EA8300E73E9A /* PrivacyInfo.xcprivacy */; }; 8A1F6C322BC5A6C400DA6F86 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8ACD3B972BA8EA8300E73E9A /* PrivacyInfo.xcprivacy */; }; 8A1F6C332BC5A6D100DA6F86 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 8ACD3B972BA8EA8300E73E9A /* PrivacyInfo.xcprivacy */; }; + 8A25556D2CF0E0E6009C0989 /* InactiveTabsTelemetryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A25556C2CF0E0E6009C0989 /* InactiveTabsTelemetryTests.swift */; }; 8A2783F1275FFDC50080D29D /* KeyboardPressesHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A2783F0275FFDC50080D29D /* KeyboardPressesHandler.swift */; }; 8A2825352760399B00395E66 /* KeyboardPressesHandlerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A2825342760399B00395E66 /* KeyboardPressesHandlerTests.swift */; }; 8A285B08294A5D4C00149B0F /* HomepageHeroImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A285B07294A5D4C00149B0F /* HomepageHeroImageViewModel.swift */; }; @@ -1009,6 +1010,7 @@ 8AE1E1D227B1ADC40024C45E /* TopBottomInterchangeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE1E1D127B1ADC40024C45E /* TopBottomInterchangeable.swift */; }; 8AE1E1D927B1BD380024C45E /* UIStackViewExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE1E1D827B1BD380024C45E /* UIStackViewExtensionsTests.swift */; }; 8AE1E1DB27B1C1320024C45E /* SearchBarSettingsViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE1E1DA27B1C1320024C45E /* SearchBarSettingsViewModelTests.swift */; }; + 8AE459922CEFB1DC002D6679 /* InactiveTabsTelemetry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE459912CEFB1DC002D6679 /* InactiveTabsTelemetry.swift */; }; 8AE80BAD2891957C00BC12EA /* TopSitesDimensionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE80BAC2891957C00BC12EA /* TopSitesDimensionTests.swift */; }; 8AE80BAF2891960300BC12EA /* MockTraitCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE80BAE2891960300BC12EA /* MockTraitCollection.swift */; }; 8AE80BB62891AEA100BC12EA /* MockDispatchGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8AE80BB42891AE6700BC12EA /* MockDispatchGroup.swift */; }; @@ -2591,7 +2593,7 @@ 2137786429832C8900D01309 /* OverlayModeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverlayModeManager.swift; sourceTree = ""; }; 213B67A527CE682B000542F5 /* StartAtHomeHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartAtHomeHelper.swift; sourceTree = ""; }; 213B67A727CE721E000542F5 /* StartAtHomeHelperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StartAtHomeHelperTests.swift; sourceTree = ""; }; - 213BF7522AC21D1B00C53A64 /* TabDisplayPanel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabDisplayPanel.swift; sourceTree = ""; }; + 213BF7522AC21D1B00C53A64 /* TabDisplayPanelViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabDisplayPanelViewController.swift; sourceTree = ""; }; 21420EF62ABA338D00B28550 /* TabTrayCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTrayCoordinator.swift; sourceTree = ""; }; 21420EF82ABC75A400B28550 /* TabTrayCoordinatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabTrayCoordinatorTests.swift; sourceTree = ""; }; 214EF4142AC5D5D0005BCCDA /* TabDisplayView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabDisplayView.swift; sourceTree = ""; }; @@ -7297,6 +7299,7 @@ 8A1E3BE128CBACD7003388C4 /* SponsoredContentFilterUtilityTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SponsoredContentFilterUtilityTests.swift; sourceTree = ""; }; 8A1E3BE528CBBF44003388C4 /* OpenSearchEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenSearchEngine.swift; sourceTree = ""; }; 8A1E93E92A3CDC6100DD540A /* BaseCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseCoordinator.swift; sourceTree = ""; }; + 8A25556C2CF0E0E6009C0989 /* InactiveTabsTelemetryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InactiveTabsTelemetryTests.swift; sourceTree = ""; }; 8A2783F0275FFDC50080D29D /* KeyboardPressesHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPressesHandler.swift; sourceTree = ""; }; 8A2825342760399B00395E66 /* KeyboardPressesHandlerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardPressesHandlerTests.swift; sourceTree = ""; }; 8A285B07294A5D4C00149B0F /* HomepageHeroImageViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageHeroImageViewModel.swift; sourceTree = ""; }; @@ -7596,6 +7599,7 @@ 8AE1E1D127B1ADC40024C45E /* TopBottomInterchangeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBottomInterchangeable.swift; sourceTree = ""; }; 8AE1E1D827B1BD380024C45E /* UIStackViewExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIStackViewExtensionsTests.swift; sourceTree = ""; }; 8AE1E1DA27B1C1320024C45E /* SearchBarSettingsViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchBarSettingsViewModelTests.swift; sourceTree = ""; }; + 8AE459912CEFB1DC002D6679 /* InactiveTabsTelemetry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InactiveTabsTelemetry.swift; sourceTree = ""; }; 8AE80BAC2891957C00BC12EA /* TopSitesDimensionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSitesDimensionTests.swift; sourceTree = ""; }; 8AE80BAE2891960300BC12EA /* MockTraitCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTraitCollection.swift; sourceTree = ""; }; 8AE80BB42891AE6700BC12EA /* MockDispatchGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockDispatchGroup.swift; sourceTree = ""; }; @@ -9970,13 +9974,6 @@ path = TopSites; sourceTree = ""; }; - 212429F22AA27204002D57A8 /* Legacy */ = { - isa = PBXGroup; - children = ( - ); - path = Legacy; - sourceTree = ""; - }; 21357F2B293FDB07004BF9FD /* RemoteTabs */ = { isa = PBXGroup; children = ( @@ -10120,7 +10117,7 @@ 1DEBC55D2AC4ED70006E4801 /* RemoteTabsPanel.swift */, 1D2F68AE2ACB272500524B92 /* RemoteTabsTableViewController.swift */, 1D2F68B02ACCA22000524B92 /* RemoteTabsEmptyView.swift */, - 213BF7522AC21D1B00C53A64 /* TabDisplayPanel.swift */, + 213BF7522AC21D1B00C53A64 /* TabDisplayPanelViewController.swift */, 214EF4142AC5D5D0005BCCDA /* TabDisplayView.swift */, 1DDE3DB22AC34E1E0039363B /* TabCell.swift */, 21E77E4D2AA8BA5200FABA10 /* TabTrayViewController.swift */, @@ -10147,6 +10144,7 @@ children = ( 8A7AF0C42C9A1135009691B5 /* Redux */, 21B548982B1E7FDF00DC1DF8 /* InactiveTabsManagerTests.swift */, + 8A25556C2CF0E0E6009C0989 /* InactiveTabsTelemetryTests.swift */, 219935ED2B07B9B300E5966F /* Legacy */, 1D8487B52AD6038100F7527C /* RemoteTabPanelStateTests.swift */, 1D3C90872ACE1AF400304C87 /* RemoteTabPanelTests.swift */, @@ -10192,14 +10190,14 @@ children = ( 219914032AF963E000153598 /* Action */, 21C5B3572AF2A6D80093F366 /* LayoutManager */, - 212429F22AA27204002D57A8 /* Legacy */, 21B548932B1E5EC000DC1DF8 /* Middleware */, 219935EA2B0710E900E5966F /* Models */, 21357F2B293FDB07004BF9FD /* RemoteTabs */, 21C5B3592AF2A73F0093F366 /* State */, 21C5B3582AF2A7130093F366 /* Views */, - 21B548942B1E5F1400DC1DF8 /* InactiveTabsManager.swift */, 968BD7EA27DFF0F8003148B3 /* ASGroup.swift */, + 8AE459912CEFB1DC002D6679 /* InactiveTabsTelemetry.swift */, + 21B548942B1E5F1400DC1DF8 /* InactiveTabsManager.swift */, ); path = Tabs; sourceTree = ""; @@ -16684,6 +16682,7 @@ C869912D28917688007ACC5C /* WallpaperImageLoader.swift in Sources */, 96A5F73829928B3700234E5F /* GeneralizedImageFetcher.swift in Sources */, 8A454D362CB86993009436D9 /* PocketStoryState.swift in Sources */, + 8AE459922CEFB1DC002D6679 /* InactiveTabsTelemetry.swift in Sources */, 1D7B78992ADF328E0011E9F2 /* AppEvent.swift in Sources */, 43F7952525795F69005AEE40 /* SearchTelemetry.swift in Sources */, E65075541E37F6FC006961AC /* LegacyDynamicFontHelper.swift in Sources */, @@ -16722,7 +16721,7 @@ 8A0A1BA32B22030100E8706F /* PrivateMessageCardCell.swift in Sources */, AB9CBC022C53B64C00102610 /* TrackingProtectionAction.swift in Sources */, 0E456F152C541CB300EE93BF /* PasswordGeneratorViewController.swift in Sources */, - 213BF7532AC21D1B00C53A64 /* TabDisplayPanel.swift in Sources */, + 213BF7532AC21D1B00C53A64 /* TabDisplayPanelViewController.swift in Sources */, 434E733725EED32E006D3BDE /* BrowserViewController+URLBarDelegate.swift in Sources */, C88E7A5B2A0553510072E638 /* OnboardingLinkInfoModel.swift in Sources */, 2137785F297F3B1B00D01309 /* DownloadsPanelViewModel.swift in Sources */, @@ -17127,6 +17126,7 @@ 81DAB2F92C8901AC00F4BE98 /* MainMenuStateTests.swift in Sources */, 8ACA8F74291987AE00D3075D /* AccountSyncHandlerTests.swift in Sources */, 8AAEBA0B2BF53AF6000C02B5 /* MicrosurveyStateTests.swift in Sources */, + 8A25556D2CF0E0E6009C0989 /* InactiveTabsTelemetryTests.swift in Sources */, 8AA7347B28AEDB3100443D24 /* PocketViewModelTests.swift in Sources */, C2446B312A856D13000C527D /* MockLibraryCoordinatorDelegate.swift in Sources */, C869915728917809007ACC5C /* NetworkingMock.swift in Sources */, diff --git a/firefox-ios/Client/Coordinators/TabTray/TabTrayCoordinator.swift b/firefox-ios/Client/Coordinators/TabTray/TabTrayCoordinator.swift index 6338b14670d0..d4cc360ec004 100644 --- a/firefox-ios/Client/Coordinators/TabTray/TabTrayCoordinator.swift +++ b/firefox-ios/Client/Coordinators/TabTray/TabTrayCoordinator.swift @@ -36,7 +36,7 @@ class TabTrayCoordinator: BaseCoordinator, func dismissChildTabTrayPanels() { // [FXIOS-10482] Initial bandaid for memory leaking during tab tray open/close. Needs further investigation. guard let childVCs = tabTrayViewController.currentPanel?.viewControllers else { return } - childVCs.forEach { ($0 as? TabDisplayPanel)?.removeTabPanel() } + childVCs.forEach { ($0 as? TabDisplayPanelViewController)?.removeTabPanel() } } private func initializeTabTrayViewController(selectedTab: TabTrayPanelType) { @@ -53,8 +53,8 @@ class TabTrayCoordinator: BaseCoordinator, private func makeChildPanels() -> [UINavigationController] { let windowUUID = tabManager.windowUUID - let regularTabsPanel = TabDisplayPanel(isPrivateMode: false, windowUUID: windowUUID) - let privateTabsPanel = TabDisplayPanel(isPrivateMode: true, windowUUID: windowUUID) + let regularTabsPanel = TabDisplayPanelViewController(isPrivateMode: false, windowUUID: windowUUID) + let privateTabsPanel = TabDisplayPanelViewController(isPrivateMode: true, windowUUID: windowUUID) let syncTabs = RemoteTabsPanel(windowUUID: windowUUID) return [ ThemedNavigationController(rootViewController: regularTabsPanel, windowUUID: windowUUID), diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift b/firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift index 9240981535b9..7f83c6fd50a7 100644 --- a/firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift +++ b/firefox-ios/Client/Frontend/Browser/Tabs/Action/TabPanelAction.swift @@ -20,6 +20,7 @@ class TabPanelViewAction: Action { let moveTabData: MoveTabData? let toastType: ToastType? let shareSheetURL: URL? + let isInactiveTab: Bool? init(panelType: TabTrayPanelType?, isPrivateModeActive: Bool? = nil, @@ -28,6 +29,7 @@ class TabPanelViewAction: Action { moveTabData: MoveTabData? = nil, toastType: ToastType? = nil, shareSheetURL: URL? = nil, + isInactiveTab: Bool? = nil, windowUUID: WindowUUID, actionType: ActionType) { self.panelType = panelType @@ -37,6 +39,7 @@ class TabPanelViewAction: Action { self.moveTabData = moveTabData self.toastType = toastType self.shareSheetURL = shareSheetURL + self.isInactiveTab = isInactiveTab super.init(windowUUID: windowUUID, actionType: actionType) } @@ -54,7 +57,7 @@ enum TabPanelViewActionType: ActionType { case undoCloseAllTabs case moveTab case toggleInactiveTabs - case closeInactiveTabs + case closeInactiveTab case undoCloseInactiveTab case closeAllInactiveTabs case undoCloseAllInactiveTabs diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/InactiveTabsTelemetry.swift b/firefox-ios/Client/Frontend/Browser/Tabs/InactiveTabsTelemetry.swift new file mode 100644 index 000000000000..e7d283f1e02b --- /dev/null +++ b/firefox-ios/Client/Frontend/Browser/Tabs/InactiveTabsTelemetry.swift @@ -0,0 +1,36 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation +import Glean + +struct InactiveTabsTelemetry { + enum EventExtraKey: String { + case inactiveTabsCollapsed = "collapsed" + case inactiveTabsExpanded = "expanded" + } + + func sectionShown() { + GleanMetrics.InactiveTabsTray.inactiveTabShown.add() + } + + func tabSwipedToClose() { + GleanMetrics.InactiveTabsTray.inactiveTabSwipeClose.add() + } + + func closedAllTabs() { + GleanMetrics.InactiveTabsTray.inactiveTabsCloseAllBtn.add() + } + + func tabOpened() { + GleanMetrics.InactiveTabsTray.openInactiveTab.add() + } + + func sectionToggled(hasExpanded: Bool) { + let hasExpandedEvent: EventExtraKey = hasExpanded ? .inactiveTabsExpanded : .inactiveTabsCollapsed + let expandedExtras = GleanMetrics.InactiveTabsTray.ToggleInactiveTabTrayExtra(toggleType: hasExpandedEvent.rawValue) + + GleanMetrics.InactiveTabsTray.toggleInactiveTabTray.record(expandedExtras) + } +} diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift b/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift index a1e5d474821e..efff9efdc8b2 100644 --- a/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift +++ b/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift @@ -13,6 +13,7 @@ import enum MozillaAppServices.BookmarkRoots class TabManagerMiddleware { private let profile: Profile private let logger: Logger + private let inactiveTabTelemetry = InactiveTabsTelemetry() init(profile: Profile = AppContainer.shared.resolve(), logger: Logger = DefaultLogger.shared) { @@ -147,7 +148,7 @@ class TabManagerMiddleware { case TabPanelViewActionType.selectTab: guard let tabUUID = action.tabUUID else { return } - selectTab(for: tabUUID, uuid: action.windowUUID) + selectTab(for: tabUUID, uuid: action.windowUUID, isInactiveTab: action.isInactiveTab ?? false) case TabPanelViewActionType.closeAllInactiveTabs: closeAllInactiveTabs(state: state, uuid: action.windowUUID) @@ -155,7 +156,7 @@ class TabManagerMiddleware { case TabPanelViewActionType.undoCloseAllInactiveTabs: undoCloseAllInactiveTabs(uuid: action.windowUUID) - case TabPanelViewActionType.closeInactiveTabs: + case TabPanelViewActionType.closeInactiveTab: guard let tabUUID = action.tabUUID else { return } closeInactiveTab(for: tabUUID, state: state, uuid: action.windowUUID) @@ -166,6 +167,15 @@ class TabManagerMiddleware { guard let urlRequest = action.urlRequest else { return } didTapLearnMoreAboutPrivate(with: urlRequest, uuid: action.windowUUID) + case TabPanelViewActionType.toggleInactiveTabs: + guard let tabState = state.screenState(TabsPanelState.self, + for: .tabsPanel, + window: action.windowUUID) + else { return } + let expanded = tabState.isInactiveTabsExpanded + inactiveTabTelemetry.sectionToggled(hasExpanded: expanded) + break + default: break } @@ -508,6 +518,7 @@ class TabManagerMiddleware { /// Makes a backup of tabs to be deleted in case the undo option is selected. private func closeAllInactiveTabs(state: AppState, uuid: WindowUUID) { guard let tabsState = state.screenState(TabsPanelState.self, for: .tabsPanel, window: uuid) else { return } + inactiveTabTelemetry.closedAllTabs() let tabManager = tabManager(for: uuid) Task { await tabManager.removeAllInactiveTabs() @@ -547,6 +558,7 @@ class TabManagerMiddleware { private func closeInactiveTab(for tabUUID: String, state: AppState, uuid: WindowUUID) { guard let tabsState = state.screenState(TabsPanelState.self, for: .tabsPanel, window: uuid) else { return } + inactiveTabTelemetry.tabSwipedToClose() let tabManager = tabManager(for: uuid) Task { if let tabToClose = tabManager.getTabForUUID(uuid: tabUUID) { @@ -587,7 +599,7 @@ class TabManagerMiddleware { addNewTab(with: urlRequest, isPrivate: true, showOverlay: false, for: uuid) } - private func selectTab(for tabUUID: TabUUID, uuid: WindowUUID) { + private func selectTab(for tabUUID: TabUUID, uuid: WindowUUID, isInactiveTab: Bool) { let tabManager = tabManager(for: uuid) guard let tab = tabManager.getTabForUUID(uuid: tabUUID) else { return } @@ -596,6 +608,10 @@ class TabManagerMiddleware { let action = TabTrayAction(windowUUID: uuid, actionType: TabTrayActionType.dismissTabTray) store.dispatch(action) + + if isInactiveTab { + inactiveTabTelemetry.tabOpened() + } } private func tabManager(for uuid: WindowUUID) -> TabManager { diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanel.swift b/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanelViewController.swift similarity index 95% rename from firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanel.swift rename to firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanelViewController.swift index 720971a98caa..1ea79f2505be 100644 --- a/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanel.swift +++ b/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayPanelViewController.swift @@ -7,10 +7,10 @@ import Redux import Storage import UIKit -class TabDisplayPanel: UIViewController, - Themeable, - EmptyPrivateTabsViewDelegate, - StoreSubscriber { +class TabDisplayPanelViewController: UIViewController, + Themeable, + EmptyPrivateTabsViewDelegate, + StoreSubscriber { typealias SubscriberStateType = TabsPanelState let panelType: TabTrayPanelType @@ -62,6 +62,10 @@ class TabDisplayPanel: UIViewController, listenForThemeChange(view) applyTheme() subscribeToRedux() + + if !tabDisplayView.shouldHideInactiveTabs { + InactiveTabsTelemetry().sectionShown() + } } override func viewWillAppear(_ animated: Bool) { diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift b/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift index 49fddf108fc2..cbe4477a50d1 100644 --- a/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift +++ b/firefox-ios/Client/Frontend/Browser/Tabs/Views/TabDisplayView.swift @@ -23,11 +23,12 @@ class TabDisplayView: UIView, private var inactiveTabsSectionManager: InactiveTabsSectionManager private var tabsSectionManager: TabsSectionManager private let windowUUID: WindowUUID + private let inactiveTabsTelemetry = InactiveTabsTelemetry() var theme: Theme? private var dataSource: TabDisplayDiffableDataSource? - private var shouldHideInactiveTabs: Bool { + var shouldHideInactiveTabs: Bool { guard !tabsState.isPrivateMode else { return true } return tabsState.inactiveTabs.isEmpty } @@ -281,7 +282,7 @@ class TabDisplayView: UIView, let action = TabPanelViewAction(panelType: panelType, tabUUID: inactiveTabs.tabUUID, windowUUID: windowUUID, - actionType: TabPanelViewActionType.closeInactiveTabs) + actionType: TabPanelViewActionType.closeInactiveTab) store.dispatch(action) } @@ -289,9 +290,11 @@ class TabDisplayView: UIView, if let selectedItem = dataSource?.itemIdentifier(for: indexPath) { switch selectedItem { case .inactiveTab(let inactiveTabsModel): + inactiveTabsTelemetry.tabOpened() let tabUUID = inactiveTabsModel.tabUUID let action = TabPanelViewAction(panelType: panelType, tabUUID: tabUUID, + isInactiveTab: true, windowUUID: windowUUID, actionType: TabPanelViewActionType.selectTab) store.dispatch(action) diff --git a/firefox-ios/Client/Frontend/Browser/TopTabDisplayManager.swift b/firefox-ios/Client/Frontend/Browser/TopTabDisplayManager.swift index 837aa1171367..668feb9f3990 100644 --- a/firefox-ios/Client/Frontend/Browser/TopTabDisplayManager.swift +++ b/firefox-ios/Client/Frontend/Browser/TopTabDisplayManager.swift @@ -75,7 +75,6 @@ class TopTabDisplayManager: NSObject { private let collectionView: UICollectionView private let tabReuseIdentifier: String - private var hasSentInactiveTabShownEvent = false var profile: Profile var notificationCenter: NotificationProtocol diff --git a/firefox-ios/Client/Telemetry/TelemetryWrapper.swift b/firefox-ios/Client/Telemetry/TelemetryWrapper.swift index 76e95f5e3b56..b6b2611fd661 100644 --- a/firefox-ios/Client/Telemetry/TelemetryWrapper.swift +++ b/firefox-ios/Client/Telemetry/TelemetryWrapper.swift @@ -525,7 +525,6 @@ extension TelemetryWrapper { case syncedTabTileImpressions = "synced-tab-tile-impressions" case historyImpressions = "history-highlights-impressions" case bookmarkImpressions = "bookmark-impressions" - case inactiveTabTray = "inactiveTabTray" case reload = "reload" case reloadFromUrlBar = "reload-from-url-bar" case restoreTabsAlert = "restore-tabs-alert" @@ -613,12 +612,6 @@ extension TelemetryWrapper { case addBookmarkToast = "add-bookmark-toast" case openHomeFromAwesomebar = "open-home-from-awesomebar" case openHomeFromPhotonMenuButton = "open-home-from-photon-menu-button" - case openInactiveTab = "openInactiveTab" - case inactiveTabShown = "inactive-Tab-Shown" - case inactiveTabExpand = "inactivetab-expand" - case inactiveTabCollapse = "inactivetab-collapse" - case inactiveTabCloseAllButton = "inactive-tab-close-all-button" - case inactiveTabSwipeClose = "inactive-tab-swipe-close" case openRecentlyClosedTab = "openRecentlyClosedTab" case tabGroupWithExtras = "tabGroupWithExtras" case closeGroupedTab = "recordCloseGroupedTab" @@ -697,10 +690,6 @@ extension TelemetryWrapper { // Tabs Tray case done = "done" - // Inactive Tab - case inactiveTabsCollapsed = "collapsed" - case inactiveTabsExpanded = "expanded" - // GleanPlumb case actionUUID = "action-uuid" case messageKey = "message-key" @@ -1766,21 +1755,6 @@ extension TelemetryWrapper { } case (.action, .tap, .newPrivateTab, .tabTray, _): GleanMetrics.TabsTray.newPrivateTabTapped.record() - // MARK: Inactive Tab Tray - case (.action, .tap, .inactiveTabTray, .openInactiveTab, _): - GleanMetrics.InactiveTabsTray.openInactiveTab.add() - case (.action, .tap, .inactiveTabTray, .inactiveTabExpand, _): - let expandedExtras = GleanMetrics.InactiveTabsTray.ToggleInactiveTabTrayExtra(toggleType: EventExtraKey.inactiveTabsExpanded.rawValue) - GleanMetrics.InactiveTabsTray.toggleInactiveTabTray.record(expandedExtras) - case (.action, .tap, .inactiveTabTray, .inactiveTabCollapse, _): - let collapsedExtras = GleanMetrics.InactiveTabsTray.ToggleInactiveTabTrayExtra(toggleType: EventExtraKey.inactiveTabsCollapsed.rawValue) - GleanMetrics.InactiveTabsTray.toggleInactiveTabTray.record(collapsedExtras) - case (.action, .tap, .inactiveTabTray, .inactiveTabSwipeClose, _): - GleanMetrics.InactiveTabsTray.inactiveTabSwipeClose.add() - case (.action, .tap, .inactiveTabTray, .inactiveTabCloseAllButton, _): - GleanMetrics.InactiveTabsTray.inactiveTabsCloseAllBtn.add() - case (.action, .tap, .inactiveTabTray, .inactiveTabShown, _): - GleanMetrics.InactiveTabsTray.inactiveTabShown.add() // MARK: Tab Groups case (.action, .view, .tabTray, .tabGroupWithExtras, let extras): diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/InactiveTabsTelemetryTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/InactiveTabsTelemetryTests.swift new file mode 100644 index 000000000000..f71430b539e9 --- /dev/null +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/InactiveTabsTelemetryTests.swift @@ -0,0 +1,53 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Glean +import XCTest + +@testable import Client + +final class InactiveTabsTelemetryTests: XCTestCase { + var subject: InactiveTabsTelemetry? + + override func setUp() { + super.setUp() + Glean.shared.resetGlean(clearStores: true) + subject = InactiveTabsTelemetry() + } + + override func tearDown() { + subject = nil + super.tearDown() + } + + func testRecordInactiveTabWhenSectionShownThenGleanIsCalled() throws { + subject?.sectionShown() + + testCounterMetricRecordingSuccess(metric: GleanMetrics.InactiveTabsTray.inactiveTabShown) + } + + func testRecordInactiveTabWhenClosedAllTabsThenGleanIsCalled() throws { + subject?.closedAllTabs() + + testCounterMetricRecordingSuccess(metric: GleanMetrics.InactiveTabsTray.inactiveTabsCloseAllBtn) + } + + func testRecordInactiveTabWhenTabOpenedThenGleanIsCalled() throws { + subject?.tabOpened() + + testCounterMetricRecordingSuccess(metric: GleanMetrics.InactiveTabsTray.openInactiveTab) + } + + func testRecordInactiveTabWhenTabSwipedClosedThenGleanIsCalled() throws { + subject?.tabSwipedToClose() + + testCounterMetricRecordingSuccess(metric: GleanMetrics.InactiveTabsTray.inactiveTabSwipeClose) + } + + func testRecordInactiveTabWhenThenGleanIsCalled() throws { + subject?.sectionToggled(hasExpanded: true) + + testEventMetricRecordingSuccess(metric: GleanMetrics.InactiveTabsTray.toggleInactiveTabTray) + } +} diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift index 56bd0edf4d79..1cbcae636f39 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabDisplayPanelTests.swift @@ -46,11 +46,11 @@ final class TabDisplayPanelTests: XCTestCase { emptyTabs: Bool, emptyInactiveTabs: Bool, file: StaticString = #file, - line: UInt = #line) -> TabDisplayPanel { + line: UInt = #line) -> TabDisplayPanelViewController { let subjectState = createSubjectState(isPrivateMode: isPrivateMode, emptyTabs: emptyTabs, emptyInactiveTabs: emptyInactiveTabs) - let subject = TabDisplayPanel(isPrivateMode: isPrivateMode, windowUUID: .XCTestDefaultUUID) + let subject = TabDisplayPanelViewController(isPrivateMode: isPrivateMode, windowUUID: .XCTestDefaultUUID) subject.newState(state: subjectState) trackForMemoryLeaks(subject, file: file, line: line) diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabTrayViewControllerTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabTrayViewControllerTests.swift index 663a87d84e01..d7cc03a00e6c 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabTrayViewControllerTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/TabTray/TabTrayViewControllerTests.swift @@ -113,8 +113,8 @@ final class TabTrayViewControllerTests: XCTestCase { } private func makeChildPanels() -> [UINavigationController] { - let regularTabsPanel = TabDisplayPanel(isPrivateMode: false, windowUUID: .XCTestDefaultUUID) - let privateTabsPanel = TabDisplayPanel(isPrivateMode: true, windowUUID: .XCTestDefaultUUID) + let regularTabsPanel = TabDisplayPanelViewController(isPrivateMode: false, windowUUID: .XCTestDefaultUUID) + let privateTabsPanel = TabDisplayPanelViewController(isPrivateMode: true, windowUUID: .XCTestDefaultUUID) let syncTabs = RemoteTabsPanel(windowUUID: .XCTestDefaultUUID) return [ ThemedNavigationController(rootViewController: regularTabsPanel, windowUUID: windowUUID), diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Telemetry/ToolbarTelemetryTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Telemetry/ToolbarTelemetryTests.swift index 75e7c214fb6a..ab0e2d237c0b 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/Telemetry/ToolbarTelemetryTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/Telemetry/ToolbarTelemetryTests.swift @@ -16,6 +16,11 @@ final class ToolbarTelemetryTests: XCTestCase { subject = ToolbarTelemetry() } + override func tearDown() { + subject = nil + super.tearDown() + } + func testRecordToolbarWhenQrCodeTappedThenGleanIsCalled() throws { subject?.qrCodeButtonTapped(isPrivate: true) testEventMetricRecordingSuccess(metric: GleanMetrics.Toolbar.qrScanButtonTapped) From ba2ebd4b4db816510ff3c750ed64743fd2d0b23e Mon Sep 17 00:00:00 2001 From: Isabella Date: Mon, 25 Nov 2024 13:24:47 -0600 Subject: [PATCH 3/9] Refactor FXIOS-10669 [Sent From Firefox] Refactor the TabPrintPageRenderer up to current code standards (#23341) * Refactor the TabPrintPagerRenderer for sharing so that it is up to current code standards and will be more testable. --- .../Browser/TabPrintPageRenderer.swift | 51 +++++++++---------- .../Frontend/Share/ShareExtensionHelper.swift | 8 ++- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/firefox-ios/Client/Frontend/Browser/TabPrintPageRenderer.swift b/firefox-ios/Client/Frontend/Browser/TabPrintPageRenderer.swift index 012187aaa29b..7788dc4cce6d 100644 --- a/firefox-ios/Client/Frontend/Browser/TabPrintPageRenderer.swift +++ b/firefox-ios/Client/Frontend/Browser/TabPrintPageRenderer.swift @@ -5,19 +5,24 @@ import Foundation import Common -private struct PrintedPageUX { - static let PageInsets = CGFloat(36.0) - static let PageTextFont = FXFontStyles.Regular.caption1.scaledFont() - static let PageMarginScale = CGFloat(0.5) -} - class TabPrintPageRenderer: UIPrintPageRenderer { - fileprivate weak var tab: Tab? - let textAttributes = [NSAttributedString.Key.font: PrintedPageUX.PageTextFont] + private struct UX { + static let insets = CGFloat(36.0) + static let textFont = FXFontStyles.Regular.caption1.scaledFont() + static let marginScale = CGFloat(0.5) + } + + fileprivate var tabDisplayTitle: String + fileprivate var tabURL: URL? + fileprivate weak var webView: TabWebView? + + let textAttributes = [NSAttributedString.Key.font: UX.textFont] let dateString: String - required init(tab: Tab) { - self.tab = tab + required init(tabDisplayTitle: String, tabURL: URL?, webView: TabWebView?) { + self.tabDisplayTitle = tabDisplayTitle + self.tabURL = tabURL + self.webView = webView let dateFormatter = DateFormatter() dateFormatter.dateStyle = .short dateFormatter.timeStyle = .short @@ -25,17 +30,11 @@ class TabPrintPageRenderer: UIPrintPageRenderer { super.init() - self.footerHeight = PrintedPageUX.PageMarginScale * PrintedPageUX.PageInsets - self.headerHeight = PrintedPageUX.PageMarginScale * PrintedPageUX.PageInsets + self.footerHeight = UX.marginScale * UX.insets + self.headerHeight = UX.marginScale * UX.insets - if let tab = self.tab, let webview = tab.webView { - let formatter = webview.viewPrintFormatter() - formatter.perPageContentInsets = UIEdgeInsets( - top: PrintedPageUX.PageInsets, - left: PrintedPageUX.PageInsets, - bottom: PrintedPageUX.PageInsets, - right: PrintedPageUX.PageInsets - ) + if let formatter = webView?.viewPrintFormatter() { + formatter.perPageContentInsets = UIEdgeInsets(equalInset: UX.insets) addPrintFormatter(formatter, startingAtPageAt: 0) } } @@ -43,14 +42,14 @@ class TabPrintPageRenderer: UIPrintPageRenderer { override func drawFooterForPage(at pageIndex: Int, in headerRect: CGRect) { let headerInsets = UIEdgeInsets( top: headerRect.minY, - left: PrintedPageUX.PageInsets, + left: UX.insets, bottom: paperRect.maxY - headerRect.maxY, - right: PrintedPageUX.PageInsets + right: UX.insets ) let headerRect = paperRect.inset(by: headerInsets) // url on left - self.drawTextAtPoint(tab!.url?.displayURL?.absoluteString ?? "", rect: headerRect, onLeft: true) + self.drawTextAtPoint(tabURL?.displayURL?.absoluteString ?? "", rect: headerRect, onLeft: true) // page number on right let pageNumberString = "\(pageIndex + 1)" @@ -60,14 +59,14 @@ class TabPrintPageRenderer: UIPrintPageRenderer { override func drawHeaderForPage(at pageIndex: Int, in headerRect: CGRect) { let headerInsets = UIEdgeInsets( top: headerRect.minY, - left: PrintedPageUX.PageInsets, + left: UX.insets, bottom: paperRect.maxY - headerRect.maxY, - right: PrintedPageUX.PageInsets + right: UX.insets ) let headerRect = paperRect.inset(by: headerInsets) // page title on left - self.drawTextAtPoint(tab!.displayTitle, rect: headerRect, onLeft: true) + self.drawTextAtPoint(tabDisplayTitle, rect: headerRect, onLeft: true) // date on right self.drawTextAtPoint(dateString, rect: headerRect, onLeft: false) diff --git a/firefox-ios/Client/Frontend/Share/ShareExtensionHelper.swift b/firefox-ios/Client/Frontend/Share/ShareExtensionHelper.swift index cb608414fe39..24978de577f2 100644 --- a/firefox-ios/Client/Frontend/Share/ShareExtensionHelper.swift +++ b/firefox-ios/Client/Frontend/Share/ShareExtensionHelper.swift @@ -98,7 +98,13 @@ class ShareExtensionHelper: NSObject, FeatureFlaggable { // when tab is not loaded (webView != nil) don't show print activity if let tab = selectedTab, tab.webView != nil { - activityItems.append(TabPrintPageRenderer(tab: tab)) + activityItems.append( + TabPrintPageRenderer( + tabDisplayTitle: tab.displayTitle, + tabURL: tab.url, + webView: tab.webView + ) + ) } if let title = selectedTab?.title { From 0a32b73d8d00cc82f302380d98b2dd29f292cb5f Mon Sep 17 00:00:00 2001 From: PARAIPAN SORIN <51127880+PARAIPAN9@users.noreply.github.com> Date: Mon, 25 Nov 2024 21:37:53 +0200 Subject: [PATCH 4/9] Refactor FXIOS-10693 - Optimize `showMenuWarningBadge` Toolbar Action dispatch (#23373) --- .../Views/BrowserViewController.swift | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift index 2f294efb36b3..128e6530c718 100644 --- a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift +++ b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift @@ -391,6 +391,13 @@ class BrowserViewController: UIViewController, let showWarningBadge = isActionNeeded if isToolbarRefactorEnabled { + let shouldShowWarningBadge = store.state.screenState( + ToolbarState.self, + for: .toolbar, + window: windowUUID + )?.showMenuWarningBadge + + guard showWarningBadge != shouldShowWarningBadge else { return } let action = ToolbarAction( showMenuWarningBadge: showWarningBadge, windowUUID: windowUUID, From 273cbdbc1e4db5cd3ea0805e2f0e6eb01ec1f52c Mon Sep 17 00:00:00 2001 From: lmarceau Date: Mon, 25 Nov 2024 15:19:07 -0500 Subject: [PATCH 5/9] Remove [Clean up] Dead code (#23380) Clean up dead code and remove some unused import --- .../Buttons/LegacyResizableButton.swift | 71 ----- firefox-ios/Client.xcodeproj/project.pbxproj | 24 -- .../Client/Application/SceneDelegate.swift | 2 - firefox-ios/Client/BookmarkItemsHelper.swift | 1 - .../AddressAutofillCoordinator.swift | 1 - .../Library/BookmarksCoordinator.swift | 1 - .../Coordinators/Scene/SceneCoordinator.swift | 1 - .../Library/HistoryPanel/HistoryPanel.swift | 6 - .../HistoryPanel/HistoryPanelViewModel.swift | 6 - .../LibraryPanelViewState.swift | 79 ----- .../BreachAlertsClient.swift | 2 +- .../BreachAlertsManager.swift | 2 +- .../Client/Frontend/Settings/Clearables.swift | 9 - .../SearchSettings/SearchSettingsAction.swift | 7 - .../SearchSettingsMiddleware.swift | 8 - .../SearchSettings/SearchSettingsState.swift | 26 -- .../Providers/Pocket/PocketProvider.swift | 4 - firefox-ios/Providers/RustSyncManager.swift | 8 - .../LibraryPanelViewStateTests.swift | 286 ------------------ 19 files changed, 2 insertions(+), 542 deletions(-) delete mode 100644 BrowserKit/Sources/ComponentLibrary/Buttons/LegacyResizableButton.swift delete mode 100644 firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsAction.swift delete mode 100644 firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsMiddleware.swift delete mode 100644 firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsState.swift delete mode 100644 firefox-ios/firefox-ios-tests/Tests/ClientTests/LibraryPanelViewStateTests.swift diff --git a/BrowserKit/Sources/ComponentLibrary/Buttons/LegacyResizableButton.swift b/BrowserKit/Sources/ComponentLibrary/Buttons/LegacyResizableButton.swift deleted file mode 100644 index ecb22b62f5b3..000000000000 --- a/BrowserKit/Sources/ComponentLibrary/Buttons/LegacyResizableButton.swift +++ /dev/null @@ -1,71 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import UIKit - -/// Deprecated base button class that use content, image and title edge insets. -/// Should be replaced gradually with ``ResizableButton``, using UIButton.Configuration instead. -@available(*, deprecated, renamed: "ResizableButton", - message: "Should be replaced with ResizableButton, using UIButton.Configuration") -open class LegacyResizableButton: UIButton { - public struct UX { - public static let buttonEdgeSpacing: CGFloat = 8 - } - - public var buttonEdgeSpacing: CGFloat = UX.buttonEdgeSpacing { - didSet { - contentEdgeInsets = UIEdgeInsets(top: 0, - left: buttonEdgeSpacing, - bottom: 0, - right: buttonEdgeSpacing) - } - } - - override public init(frame: CGRect) { - super.init(frame: frame) - commonInit() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - fatalError("init(coder:) has not been implemented") - } - - func commonInit() { - titleLabel?.numberOfLines = 0 - titleLabel?.adjustsFontForContentSizeCategory = true - titleLabel?.lineBreakMode = .byWordWrapping - adjustsImageSizeForAccessibilityContentSizeCategory = true - contentEdgeInsets = UIEdgeInsets(top: 0, - left: buttonEdgeSpacing, - bottom: 0, - right: buttonEdgeSpacing) - } - - override public var intrinsicContentSize: CGSize { - guard let title = titleLabel else { - return super.intrinsicContentSize - } - - let widthTitleInset = titleEdgeInsets.left + titleEdgeInsets.right - let widthImageInset = imageEdgeInsets.left + imageEdgeInsets.right - let widthContentInset = contentEdgeInsets.left + contentEdgeInsets.right - - var availableWidth = frame.width - widthTitleInset - widthImageInset - widthContentInset - if let imageWidth = image(for: [])?.size.width { - availableWidth = availableWidth - imageWidth - } - - let size = title.sizeThatFits(CGSize(width: availableWidth, height: .greatestFiniteMagnitude)) - return CGSize(width: size.width + widthContentInset, - height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom) - } - - override public func layoutSubviews() { - super.layoutSubviews() - guard let title = titleLabel else { return } - - titleLabel?.preferredMaxLayoutWidth = title.frame.size.width - } -} diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index 41cc57e0aea8..4c1083490775 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -1130,9 +1130,6 @@ 96EB6C4027DBEE9800A9D159 /* SearchGroupedItemsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EB6C3F27DBEE9800A9D159 /* SearchGroupedItemsViewController.swift */; }; 96EB6C4327DC205D00A9D159 /* SearchGroupedItemsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96EB6C4227DC205D00A9D159 /* SearchGroupedItemsViewModel.swift */; }; 96F8DA49280452CA00E53239 /* GleanPlumbContextProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F8DA48280452CA00E53239 /* GleanPlumbContextProvider.swift */; }; - A5519CF52B5D57560062BECB /* SearchSettingsState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5519CF42B5D57560062BECB /* SearchSettingsState.swift */; }; - A55319BB2B5D5A850051559F /* SearchSettingsAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55319BA2B5D5A850051559F /* SearchSettingsAction.swift */; }; - A55319BD2B5D5AE70051559F /* SearchSettingsMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = A55319BC2B5D5AE70051559F /* SearchSettingsMiddleware.swift */; }; A83E5B1A1C1DA8BF0026D912 /* image.gif in Resources */ = {isa = PBXBuildFile; fileRef = A83E5B181C1DA8BF0026D912 /* image.gif */; }; A83E5B1B1C1DA8BF0026D912 /* image.png in Resources */ = {isa = PBXBuildFile; fileRef = A83E5B191C1DA8BF0026D912 /* image.png */; }; A83E5B1D1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = A83E5B1C1C1DA8D80026D912 /* UIPasteboardExtensionsTests.swift */; }; @@ -1289,7 +1286,6 @@ C84266752728462900382274 /* AccessibilityIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84266742728462900382274 /* AccessibilityIdentifiers.swift */; }; C84266772728462900382274 /* AccessibilityIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84266742728462900382274 /* AccessibilityIdentifiers.swift */; }; C8445A14264428DC00B83F53 /* LibraryPanelViewState.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8445A13264428DC00B83F53 /* LibraryPanelViewState.swift */; }; - C8445AD126443C7F00B83F53 /* LibraryPanelViewStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8445AD026443C7F00B83F53 /* LibraryPanelViewStateTests.swift */; }; C84655E22887388F00861B4A /* Wallpaper.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84655E12887388F00861B4A /* Wallpaper.swift */; }; C84655E42887394B00861B4A /* WallpaperMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84655E32887394B00861B4A /* WallpaperMetadata.swift */; }; C84655E62887398700861B4A /* WallpaperCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = C84655E52887398700861B4A /* WallpaperCollection.swift */; }; @@ -7933,9 +7929,6 @@ A4CA448AA96CDBC3A7DBAC77 /* es-AR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "es-AR"; path = "es-AR.lproj/Storage.strings"; sourceTree = ""; }; A4DC42139D8B8F1B3EF09187 /* is */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = is; path = is.lproj/AuthenticationManager.strings; sourceTree = ""; }; A53F4A73AD12CBDA5CE2257D /* eu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = eu; path = eu.lproj/Storage.strings; sourceTree = ""; }; - A5519CF42B5D57560062BECB /* SearchSettingsState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsState.swift; sourceTree = ""; }; - A55319BA2B5D5A850051559F /* SearchSettingsAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsAction.swift; sourceTree = ""; }; - A55319BC2B5D5AE70051559F /* SearchSettingsMiddleware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchSettingsMiddleware.swift; sourceTree = ""; }; A5624F1DA2ABA87677302EDA /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Shared.strings; sourceTree = ""; }; A56E4D2BB5542C88A788D957 /* uz */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uz; path = uz.lproj/PrivateBrowsing.strings; sourceTree = ""; }; A5724A80AF359D2F273F343E /* ne-NP */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ne-NP"; path = "ne-NP.lproj/Localizable.strings"; sourceTree = ""; }; @@ -8323,7 +8316,6 @@ C8417D212657F0600010B877 /* LibraryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryViewModel.swift; sourceTree = ""; }; C84266742728462900382274 /* AccessibilityIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityIdentifiers.swift; sourceTree = ""; }; C8445A13264428DC00B83F53 /* LibraryPanelViewState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryPanelViewState.swift; sourceTree = ""; }; - C8445AD026443C7F00B83F53 /* LibraryPanelViewStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibraryPanelViewStateTests.swift; sourceTree = ""; }; C8464093BC0470D518B16C72 /* af */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = af; path = af.lproj/3DTouchActions.strings; sourceTree = ""; }; C84655E12887388F00861B4A /* Wallpaper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Wallpaper.swift; sourceTree = ""; }; C84655E32887394B00861B4A /* WallpaperMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WallpaperMetadata.swift; sourceTree = ""; }; @@ -10318,7 +10310,6 @@ 2F44FC551A9E83E200FD20CC /* Settings */ = { isa = PBXGroup; children = ( - A5519CF32B5D572A0062BECB /* SearchSettings */, 216A0D772A40E83F008077BA /* ThemeSettings */, 8A3EF7ED2A2FCEC900796E3A /* Main */, EBB895322193FFF400EB91A0 /* ContentBlockerSettingViewController.swift */, @@ -12276,16 +12267,6 @@ path = GeneralizedTableView; sourceTree = ""; }; - A5519CF32B5D572A0062BECB /* SearchSettings */ = { - isa = PBXGroup; - children = ( - A5519CF42B5D57560062BECB /* SearchSettingsState.swift */, - A55319BA2B5D5A850051559F /* SearchSettingsAction.swift */, - A55319BC2B5D5AE70051559F /* SearchSettingsMiddleware.swift */, - ); - path = SearchSettings; - sourceTree = ""; - }; AB11407B2CAC0CA8005080CE /* TrackigProtectionRedux */ = { isa = PBXGroup; children = ( @@ -14150,7 +14131,6 @@ C889D7D32858CD4500121E1D /* HistoryHighlights */, 8A2825342760399B00395E66 /* KeyboardPressesHandlerTests.swift */, 8AED868128CA3A1F00351A50 /* Library */, - C8445AD026443C7F00B83F53 /* LibraryPanelViewStateTests.swift */, 81DAB2EF2C88EFEE00F4BE98 /* MainMenu */, C8DC90CA2A067BF10008832B /* MarkupParseUtilityTests */, C83DE54529DF3579006E1B69 /* Messaging */, @@ -16227,7 +16207,6 @@ 21B359C62AEAC20300FF09E3 /* TabsSectionManager.swift in Sources */, 21BFEEF52A040EF40033048D /* TabMigrationUtility.swift in Sources */, 8AEAD9F52C3D7BA9001A2C5A /* FeatureFlagsDebugViewController.swift in Sources */, - A55319BB2B5D5A850051559F /* SearchSettingsAction.swift in Sources */, 810CD9C12BB346D800E290C2 /* OnboardingCardViewController.swift in Sources */, C8A012F126AB07D70096A7A7 /* JumpBackInViewModel.swift in Sources */, 8AAAB05F2C1B72C9008830B3 /* SearchHighlightItem.swift in Sources */, @@ -16341,7 +16320,6 @@ D87F84AC20B891160091F2DA /* TopTabDisplayManager.swift in Sources */, D0C95EF6201A55A800E4E51C /* BrowserViewController+UIDropInteractionDelegate.swift in Sources */, D31CF65C1CC1959A001D0BD0 /* PrivilegedRequest.swift in Sources */, - A55319BD2B5D5AE70051559F /* SearchSettingsMiddleware.swift in Sources */, 8A6A796D27F773550022D6C6 /* HomepageContextMenuHelper.swift in Sources */, 8A2783F1275FFDC50080D29D /* KeyboardPressesHandler.swift in Sources */, E650755C1E37F747006961AC /* Swizzling.m in Sources */, @@ -16675,7 +16653,6 @@ C84655FF2887A06B00861B4A /* WallpaperFilePathProvider.swift in Sources */, 8A1E93EA2A3CDC6100DD540A /* BaseCoordinator.swift in Sources */, E1442FD6294782D9003680B0 /* UIView+Extension.swift in Sources */, - A5519CF52B5D57560062BECB /* SearchSettingsState.swift in Sources */, AB936A692C05F2B100600F82 /* TrackingProtectionButton.swift in Sources */, 74F80D342A0A52D700013C3D /* PrivacyPolicyViewController.swift in Sources */, 274A36CE239EB9EC00A21587 /* LibraryViewController+LibraryPanelDelegate.swift in Sources */, @@ -17186,7 +17163,6 @@ 967EDABD29D705300089208D /* CreditCardValidatorTests.swift in Sources */, D815A3A824A53F3200AAB221 /* TabToolbarHelperTests.swift in Sources */, 967EDABF29D769A10089208D /* CreditCardInputFieldTests.swift in Sources */, - C8445AD126443C7F00B83F53 /* LibraryPanelViewStateTests.swift in Sources */, 21F2A2D42B0D194A00626AEC /* TabsPanelStateTests.swift in Sources */, 8CFD56892AAF06D3003157A6 /* ShoppingProductTests.swift in Sources */, 8ACA8F7629198D6400D3075D /* ThrottlerTests.swift in Sources */, diff --git a/firefox-ios/Client/Application/SceneDelegate.swift b/firefox-ios/Client/Application/SceneDelegate.swift index 5156159ab38d..fc3c86d5e9b5 100644 --- a/firefox-ios/Client/Application/SceneDelegate.swift +++ b/firefox-ios/Client/Application/SceneDelegate.swift @@ -4,11 +4,9 @@ import UIKit import CoreSpotlight -import Storage import Shared import Sync import UserNotifications -import Account import Common class SceneDelegate: UIResponder, UIWindowSceneDelegate { diff --git a/firefox-ios/Client/BookmarkItemsHelper.swift b/firefox-ios/Client/BookmarkItemsHelper.swift index 88054025b3dc..6808d5876854 100644 --- a/firefox-ios/Client/BookmarkItemsHelper.swift +++ b/firefox-ios/Client/BookmarkItemsHelper.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Storage import Shared import class MozillaAppServices.BookmarkItemData diff --git a/firefox-ios/Client/Coordinators/AddressAutofillCoordinator.swift b/firefox-ios/Client/Coordinators/AddressAutofillCoordinator.swift index ed9a9308fa67..0fc61a2c1813 100644 --- a/firefox-ios/Client/Coordinators/AddressAutofillCoordinator.swift +++ b/firefox-ios/Client/Coordinators/AddressAutofillCoordinator.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Common -import Storage import ComponentLibrary import WebKit diff --git a/firefox-ios/Client/Coordinators/Library/BookmarksCoordinator.swift b/firefox-ios/Client/Coordinators/Library/BookmarksCoordinator.swift index f140ac15f823..c8d5f6d997ec 100644 --- a/firefox-ios/Client/Coordinators/Library/BookmarksCoordinator.swift +++ b/firefox-ios/Client/Coordinators/Library/BookmarksCoordinator.swift @@ -3,7 +3,6 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/ import Foundation -import Storage import Common import MozillaAppServices diff --git a/firefox-ios/Client/Coordinators/Scene/SceneCoordinator.swift b/firefox-ios/Client/Coordinators/Scene/SceneCoordinator.swift index b7342b9d9e0f..70b14ae5c3aa 100644 --- a/firefox-ios/Client/Coordinators/Scene/SceneCoordinator.swift +++ b/firefox-ios/Client/Coordinators/Scene/SceneCoordinator.swift @@ -5,7 +5,6 @@ import Common import UIKit import Shared -import Storage /// Each scene has it's own scene coordinator, which is the root coordinator for a scene. class SceneCoordinator: BaseCoordinator, LaunchCoordinatorDelegate, LaunchFinishedLoadingDelegate { diff --git a/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanel.swift b/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanel.swift index 6a1124a1dc9f..7e66d454912b 100644 --- a/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanel.swift +++ b/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanel.swift @@ -9,12 +9,6 @@ import WebKit import Common import SiteImageView -private class FetchInProgressError: MaybeErrorType { - internal var description: String { - return "Fetch is already in-progress" - } -} - @objcMembers class HistoryPanel: UIViewController, LibraryPanel, diff --git a/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanelViewModel.swift b/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanelViewModel.swift index 24d6b76f48f6..9b28d95a2069 100644 --- a/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanelViewModel.swift +++ b/firefox-ios/Client/Frontend/Library/HistoryPanel/HistoryPanelViewModel.swift @@ -10,12 +10,6 @@ import SwiftUI import struct MozillaAppServices.VisitTransitionSet -private class FetchInProgressError: MaybeErrorType { - internal var description: String { - return "Fetch is already in-progress" - } -} - class HistoryPanelViewModel: FeatureFlaggable { enum Sections: Int, CaseIterable { case additionalHistoryActions diff --git a/firefox-ios/Client/Frontend/Library/LibraryViewController/LibraryPanelViewState.swift b/firefox-ios/Client/Frontend/Library/LibraryViewController/LibraryPanelViewState.swift index 085a1b993953..224de1c5928e 100644 --- a/firefox-ios/Client/Frontend/Library/LibraryViewController/LibraryPanelViewState.swift +++ b/firefox-ios/Client/Frontend/Library/LibraryViewController/LibraryPanelViewState.swift @@ -81,82 +81,3 @@ enum LibraryPanelSubState { return false } } - -/// The `LibraryPanelViewState` class is a state machine that will keep track of the -/// current state of each panel of the Library Panel. The current state is accessed/updated -/// through the `currentState` variable, which will ensure that specific substates for each -/// are preserved. -class LibraryPanelViewState { - private var state: LibraryPanelMainState = .bookmarks(state: .mainView) - var currentState: LibraryPanelMainState { - get { return state } - set { - updateState(to: newValue) - } - } - - // All states with a substate must have their own variable in order to keep - // track of what substate we were in such that, when the user returns to - // that panel, we retain the correct state. - private var bookmarksState: LibraryPanelMainState = .bookmarks(state: .mainView) - private var historyState: LibraryPanelMainState = .history(state: .mainView) - - private func updateState(to newState: LibraryPanelMainState) { - let changingPanels = state.panelIsDifferentFrom(newState) - storeCurrentState() - switch newState { - // All cases where we have substates must use the `updateStateVariables` - // function in order to check if it's a legal update - case .bookmarks(let newSubviewState): - guard case .bookmarks(let oldSubviewState) = bookmarksState else { return } - updateStateVariables(for: newState, - andCategory: bookmarksState, - with: newSubviewState, - and: oldSubviewState, - isChangingPanels: changingPanels) - - case .history(let newSubviewState): - guard case .history(let oldSubviewState) = historyState else { return } - updateStateVariables(for: newState, - andCategory: historyState, - with: newSubviewState, - and: oldSubviewState, - isChangingPanels: changingPanels) - - // In the case of panels without substates, we can just update - // the state directly without worry. - case .downloads, - .readingList: - self.state = newState - } - } - - private func storeCurrentState() { - switch state { - case .bookmarks: - bookmarksState = state - case .history: - historyState = state - case .downloads, .readingList: - return - } - } - - private func updateStateVariables( - for newState: LibraryPanelMainState, - andCategory category: LibraryPanelMainState, - with newSubviewState: LibraryPanelSubState, - and oldSubviewState: LibraryPanelSubState, - isChangingPanels: Bool - ) { - if isChangingPanels { - self.state = category - } else if newSubviewState.isChildState(of: oldSubviewState) - || newSubviewState.isParentState(of: oldSubviewState) - || oldSubviewState == newSubviewState { - self.state = newState - } else if newSubviewState == .search || oldSubviewState == .search { - self.state = newState - } - } -} diff --git a/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsClient.swift b/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsClient.swift index e79d6899a8fe..e7de9ed3465d 100644 --- a/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsClient.swift +++ b/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsClient.swift @@ -24,7 +24,7 @@ protocol BreachAlertsClientProtocol { } /// Handles all network requests for BreachAlertsManager. -public class BreachAlertsClient: BreachAlertsClientProtocol { +class BreachAlertsClient: BreachAlertsClientProtocol { private var dataTask: URLSessionDataTask? public enum Endpoint: String { case breachedAccounts = "https://monitor.firefox.com/hibp/breaches" diff --git a/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsManager.swift b/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsManager.swift index 1c35ef092064..20239fffa986 100644 --- a/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsManager.swift +++ b/firefox-ios/Client/Frontend/PasswordManagement/BreachAlertsManager.swift @@ -24,7 +24,7 @@ struct BreachRecord: Codable, Equatable, Hashable { } /// A manager for the user's breached login information, if any. -public final class BreachAlertsManager { +final class BreachAlertsManager { static let monitorAboutUrl = URL(string: "https://monitor.firefox.com/about") var breaches = Set() var client: BreachAlertsClientProtocol diff --git a/firefox-ios/Client/Frontend/Settings/Clearables.swift b/firefox-ios/Client/Frontend/Settings/Clearables.swift index 5a6345f47304..f903a60edf41 100644 --- a/firefox-ios/Client/Frontend/Settings/Clearables.swift +++ b/firefox-ios/Client/Frontend/Settings/Clearables.swift @@ -15,15 +15,6 @@ protocol Clearable { var label: String { get } } -class ClearableError: MaybeErrorType { - fileprivate let msg: String - init(msg: String) { - self.msg = msg - } - - var description: String { return msg } -} - // Clears our browsing history, including favicons and thumbnails. class HistoryClearable: Clearable { let profile: Profile diff --git a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsAction.swift b/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsAction.swift deleted file mode 100644 index 761bb1c05a5e..000000000000 --- a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsAction.swift +++ /dev/null @@ -1,7 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import Redux - -class SearchSettingsAction: Action {} diff --git a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsMiddleware.swift b/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsMiddleware.swift deleted file mode 100644 index 8095bb2cb92f..000000000000 --- a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsMiddleware.swift +++ /dev/null @@ -1,8 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import Foundation - -class SearchSettingsMiddleware { -} diff --git a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsState.swift b/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsState.swift deleted file mode 100644 index 51879cc7a7d0..000000000000 --- a/firefox-ios/Client/Frontend/Settings/SearchSettings/SearchSettingsState.swift +++ /dev/null @@ -1,26 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import Redux -import Common - -struct SearchSettingsState: ScreenState, Equatable { - let windowUUID: WindowUUID - - init(_ appState: AppState, windowUUID: WindowUUID) { - self.windowUUID = windowUUID - } - - init(windowUUID: WindowUUID) { - self.windowUUID = windowUUID - } - - static let reducer: Reducer = { state, action in - return defaultState(from: state) - } - - static func defaultState(from state: SearchSettingsState) -> SearchSettingsState { - return SearchSettingsState(windowUUID: state.windowUUID) - } -} diff --git a/firefox-ios/Providers/Pocket/PocketProvider.swift b/firefox-ios/Providers/Pocket/PocketProvider.swift index c9b373f0fab7..30610296a208 100644 --- a/firefox-ios/Providers/Pocket/PocketProvider.swift +++ b/firefox-ios/Providers/Pocket/PocketProvider.swift @@ -24,10 +24,6 @@ extension PocketStoriesProviding { } class PocketProvider: PocketStoriesProviding, FeatureFlaggable, URLCaching { - private class PocketError: MaybeErrorType { - var description = "Failed to load from API" - } - private let pocketEnvAPIKey = "PocketEnvironmentAPIKey" private static let SupportedLocales = ["en_CA", "en_US", "en_GB", "en_ZA", "de_DE", "de_AT", "de_CH"] diff --git a/firefox-ios/Providers/RustSyncManager.swift b/firefox-ios/Providers/RustSyncManager.swift index 6a06cd43de79..bd6bd7719b88 100644 --- a/firefox-ios/Providers/RustSyncManager.swift +++ b/firefox-ios/Providers/RustSyncManager.swift @@ -339,10 +339,6 @@ public class RustSyncManager: NSObject, SyncManager { public let description = "No key data found for scope." } - public class EncryptionKeyError: MaybeErrorType { - public let description = "Failed to get stored key." - } - public class DeviceIdError: MaybeErrorType { public let description = "Failed to get deviceId." } @@ -351,10 +347,6 @@ public class RustSyncManager: NSObject, SyncManager { public let description = "Failed to get token server endpoint url." } - public class EngineAndKeyRetrievalError: MaybeErrorType { - public let description = "Failed to get sync engine and key data." - } - private func registerSyncEngines(engines: [RustSyncManagerAPI.TogglableEngine], loginKey: String?, creditCardKey: String?, diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/LibraryPanelViewStateTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/LibraryPanelViewStateTests.swift deleted file mode 100644 index 6a9879e32e6b..000000000000 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/LibraryPanelViewStateTests.swift +++ /dev/null @@ -1,286 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/ - -import XCTest -@testable import Client - -class LibraryPanelViewStateTests: XCTestCase { - var panelState: LibraryPanelViewState? - - override func setUp() { - super.setUp() - panelState = LibraryPanelViewState() - } - - override func tearDown() { - super.tearDown() - panelState = nil - } - - // MARK: - Single panel interaction tests - func testStateMachineInitializesWithProperState() { - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .mainView) - - XCTAssertEqual(actualState, expectedState, "The library panel view is not initializing correctly.") - } - - func testStateChangingToSameState() { - panelState?.currentState = .bookmarks(state: .mainView) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .mainView) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view changing from one state to the same state is not working!" - ) - } - - func testStateOnBookmarkPanelGoesIntoFolderState() { - panelState?.currentState = .bookmarks(state: .inFolder) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolder) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolder state for bookmarks" - ) - } - - func testStateOnBookmarkPanelGoesIntoEditFolderState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolderEditMode) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolderEditMode state for bookmarks" - ) - } - - func testStateOnBookmarkPanelGoesIntoItemEditState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: .itemEditMode) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .itemEditMode) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolderEditMode state for bookmarks" - ) - } - - func testStateOnBookmarkPanelGoesBackToFolderEditModeFromItemEditState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: .itemEditMode) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolderEditMode) - - // swiftlint:disable line_length - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolderEditMode state for bookmarks from the .itemEditMode state" - ) - // swiftlint:enable line_length - } - - func testStateOnBookmarkPanelGoesBackToFolderEditModeFromItemEditInvalidFieldState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: .itemEditModeInvalidField) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolderEditMode) - - // swiftlint:disable line_length - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolderEditMode state for bookmarks from the .itemEditModeInvalidField state" - ) - // swiftlint:enable line_length - } - - func testStateOnBookmarkPanelGoesIntoItemEditInvalidFieldState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: .itemEditModeInvalidField) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .itemEditModeInvalidField) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inItemEditModeInvalidField state for bookmarks" - ) - } - - func testStateOnBookmarkPanelGoesBackToFolderEditModeFromItemEditInvalidState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: .itemEditModeInvalidField) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolderEditMode) - - // swiftlint:disable line_length - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .inFolderEditMode state for bookmarks from the .itemEditMode state" - ) - // swiftlint:enable line_length - } - - func testStateOnBookmarkPanelFollowStateProgressionMovingIntoStates() { - testStateOnBookmarkPanelFollowStateProgressionMovingIntoStates(using: .itemEditMode) - testStateOnBookmarkPanelFollowStateProgressionMovingIntoStates(using: .itemEditModeInvalidField) - } - - private func testStateOnBookmarkPanelFollowStateProgressionMovingIntoStates(using state: LibraryPanelSubState) { - panelState?.currentState = .bookmarks(state: state) - var actualState = panelState?.currentState - var wrongState: LibraryPanelMainState = .bookmarks(state: state) - let expectedState: LibraryPanelMainState = .bookmarks(state: .mainView) - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .mainView state for bookmarks" - ) - XCTAssertNotEqual(actualState, wrongState, "Attempting to move to the wrong state did not fail!") - - panelState?.currentState = .bookmarks(state: state) - actualState = panelState?.currentState - wrongState = .bookmarks(state: state) - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .mainView state for bookmarks" - ) - XCTAssertNotEqual(actualState, wrongState, "Attempting to move to the wrong state did not fail!") - } - - func testStateOnBookmarkPanelFollowsStateProgressionMovingOutOfStates() { - testStateOnBookmarkPanelFollowsStateProgressionMovingOutOfStates(lastState: .itemEditMode) - testStateOnBookmarkPanelFollowsStateProgressionMovingOutOfStates(lastState: .itemEditModeInvalidField) - } - - private func testStateOnBookmarkPanelFollowsStateProgressionMovingOutOfStates(lastState: LibraryPanelSubState) { - // Go to last state - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .bookmarks(state: lastState) - - // attempt to climb backwards - panelState?.currentState = .bookmarks(state: .inFolder) - var actualState = panelState?.currentState - var wrongState: LibraryPanelMainState = .bookmarks(state: .inFolder) - let expectedState: LibraryPanelMainState = .bookmarks(state: lastState) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the correct edit state for bookmarks" - ) - XCTAssertNotEqual(actualState, wrongState, "Attempting to move to the wrong state did not fail!") - - panelState?.currentState = .bookmarks(state: .mainView) - actualState = panelState?.currentState - wrongState = .bookmarks(state: .mainView) - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the correct edit state for bookmarks" - ) - XCTAssertNotEqual(actualState, wrongState, "Attempting to move to the wrong state did not fail!") - } - - // MARK: - Multi-panel tests - func testStateForBookmarkMainViewToOtherPanelMainView() { - panelState?.currentState = .history(state: .mainView) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .history(state: .mainView) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly enter the .history(.mainView) state for the History Panel" - ) - } - - func testStateForBookmarkMainViewToOtherPanelMainViewAndBack() { - panelState?.currentState = .history(state: .mainView) - panelState?.currentState = .bookmarks(state: .mainView) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .mainView) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly return to the .bookmarks(.mainView) state" - ) - } - - func testBookmarkViewInFolderModeSwitchingToOtherPanelAndReturningToCorrectBookmarksState() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .history(state: .mainView) - panelState?.currentState = .bookmarks(state: .mainView) - - let actualState = panelState?.currentState - let expectedState: LibraryPanelMainState = .bookmarks(state: .inFolder) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly return to the .bookmarks(.inFolder) state" - ) - } - - func testChangingDifferentPanelsAndSavingStates() { - panelState?.currentState = .bookmarks(state: .inFolder) - panelState?.currentState = .bookmarks(state: .inFolderEditMode) - panelState?.currentState = .history(state: .mainView) - panelState?.currentState = .history(state: .inFolder) - panelState?.currentState = .downloads - panelState?.currentState = .bookmarks(state: .mainView) - - var actualState = panelState?.currentState - var expectedState: LibraryPanelMainState = .bookmarks(state: .inFolderEditMode) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly return to the .bookmarks(.inFolderEditMode) state" - ) - - panelState?.currentState = .history(state: .mainView) - actualState = panelState?.currentState - expectedState = .history(state: .inFolder) - - XCTAssertEqual( - actualState, - expectedState, - "The library panel view did not correctly return to the .history(.inFolder) state" - ) - } -} From 4d19dac2e4a36d774025092891108b697d759ff6 Mon Sep 17 00:00:00 2001 From: Daniel Dervishi <58835213+DanielDervishi@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:30:26 -0500 Subject: [PATCH 6/9] Bugfix FXIOS-10560 - Password Generator: Keyboard Closing After Accessing Pass Gen (#23305) * Keyboard dismissal bug fix * Completed ticket * swiftlint changes * Addressed comments --- .../Common/Logger/LoggerCategory.swift | 3 +++ .../PasswordGeneratorMiddleware.swift | 25 ++++++++++++++----- .../PasswordGeneratorViewController.swift | 4 ++- .../AllFrames/AtDocumentStart/LoginsHelper.js | 4 ++- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/BrowserKit/Sources/Common/Logger/LoggerCategory.swift b/BrowserKit/Sources/Common/Logger/LoggerCategory.swift index 1291b1fdd517..294dbc04cdaa 100644 --- a/BrowserKit/Sources/Common/Logger/LoggerCategory.swift +++ b/BrowserKit/Sources/Common/Logger/LoggerCategory.swift @@ -65,4 +65,7 @@ public enum LoggerCategory: String { /// Remote settings case remoteSettings + + /// Password Generator + case passwordGenerator } diff --git a/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorMiddleware.swift b/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorMiddleware.swift index 5671236ea897..2ae6d65061c1 100644 --- a/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorMiddleware.swift +++ b/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorMiddleware.swift @@ -95,16 +95,29 @@ final class PasswordGeneratorMiddleware { private func userTappedUsePassword(frame: WKFrameInfo, password: String) { passwordGeneratorTelemetry.usePasswordButtonPressed() - let jsFunctionCall = "window.__firefox__.logins.fillGeneratedPassword(\"\(password)\")" - frame.webView?.evaluateJavascriptInDefaultContentWorld(jsFunctionCall, frame) { (result, error) in - if error != nil { - self.logger.log("Error filling in password info", - level: .warning, - category: .webview) + if let escapedPassword = escapeString(string: password) { + let jsFunctionCall = "window.__firefox__.logins.fillGeneratedPassword(\(escapedPassword))" + frame.webView?.evaluateJavascriptInDefaultContentWorld(jsFunctionCall, frame) { (result, error) in + if error != nil { + self.logger.log("Error filling in password info", + level: .warning, + category: .passwordGenerator) + } } } } + private func escapeString(string: String) -> String? { + guard let jsonData = try? JSONEncoder().encode(string), + let jsonString = String(data: jsonData, encoding: .utf8) else { + self.logger.log("Error encoding generated password to JSON", + level: .warning, + category: .passwordGenerator) + return nil + } + return jsonString + } + private func userTappedRefreshPassword(frame: WKFrameInfo, windowUUID: WindowUUID) { guard let origin = frame.webView?.url?.origin else {return} generateNewPassword(frame: frame, completion: { generatedPassword in diff --git a/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorViewController.swift b/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorViewController.swift index e2c33e14c845..6a75d497d456 100644 --- a/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorViewController.swift +++ b/firefox-ios/Client/Frontend/PasswordGenerator/PasswordGeneratorViewController.swift @@ -234,5 +234,7 @@ class PasswordGeneratorViewController: UIViewController, StoreSubscriber, Themea } extension PasswordGeneratorViewController: BottomSheetChild { - func willDismiss() { currentTab.webView?.accessoryView.reloadViewFor(.standard)} + func willDismiss() { + LoginsHelper.yieldFocusBackToField(with: currentTab) + } } diff --git a/firefox-ios/Client/Frontend/UserContent/UserScripts/AllFrames/AtDocumentStart/LoginsHelper.js b/firefox-ios/Client/Frontend/UserContent/UserScripts/AllFrames/AtDocumentStart/LoginsHelper.js index 20d799e110df..fdbe3b2eb044 100644 --- a/firefox-ios/Client/Frontend/UserContent/UserScripts/AllFrames/AtDocumentStart/LoginsHelper.js +++ b/firefox-ios/Client/Frontend/UserContent/UserScripts/AllFrames/AtDocumentStart/LoginsHelper.js @@ -468,11 +468,13 @@ window.__firefox__.includeOnce("LoginsHelper", function() { }; function fillGeneratedPassword(password) { + LoginManagerContent.fromFill = true this.yieldFocusBackToField(); const passwordField = LoginManagerContent.activeField; passwordField?.setUserInput(password); const confirmationField = Logic.findConfirmationField(passwordField, LoginFormFactory); confirmationField?.setUserInput(password); + LoginManagerContent.fromFill = false } function yieldFocusBackToField() { @@ -499,7 +501,7 @@ window.__firefox__.includeOnce("LoginsHelper", function() { const isPasswordField = field === password; const isYieldingFocus = LoginManagerContent.activeField === field; LoginManagerContent.activeField = field; - if (formHasNewPassword && isPasswordField && !isYieldingFocus) { + if (formHasNewPassword && isPasswordField && !LoginManagerContent.fromFill) { webkit.messageHandlers.loginsManagerMessageHandler.postMessage({ type: "generatePassword", }); From b645d680c7bdbbb2a7d5dfe3312aea38133de929 Mon Sep 17 00:00:00 2001 From: Clare So <1740517+clarmso@users.noreply.github.com> Date: Mon, 25 Nov 2024 17:43:46 -0500 Subject: [PATCH 7/9] Refactor MTE-3641 Sync Integration Tests for Xcode 16 and iOS 18.1 (#23335) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Code fixes for iOS 16 * Bump iOS version * 🈳 Empty commit 🈳 * Sometimes we get "Sync is offline". Tapping on it helps. * Revert change just for me --- .../Tests/SyncIntegrationTests/xcodebuild.py | 2 +- .../firefox-ios-tests/Tests/SyncIntegrationTests/xcrun.py | 2 +- .../Tests/XCUITests/IntegrationTests.swift | 7 +++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcodebuild.py b/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcodebuild.py index ac5bccc02ae7..69c588cb7e51 100644 --- a/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcodebuild.py +++ b/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcodebuild.py @@ -10,7 +10,7 @@ class XCodeBuild(object): binary = 'xcodebuild' - destination = 'platform=iOS Simulator,name=iPhone 15,OS=17.4' + destination = 'platform=iOS Simulator,name=iPhone 16,OS=18.1' logger = logging.getLogger() scheme = 'Fennec' testPlan = 'SyncIntegrationTestPlan' diff --git a/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcrun.py b/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcrun.py index 87792d3caf71..05efc42bc881 100644 --- a/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcrun.py +++ b/firefox-ios/firefox-ios-tests/Tests/SyncIntegrationTests/xcrun.py @@ -14,7 +14,7 @@ def _run(self, *args): self.logger.info('Running: {}'.format(' '.join(args))) subprocess.check_call(args) - def boot(self, device='iPhone 15'): + def boot(self, device='iPhone 16'): ios_device = os.environ.get("SIMULATOR_UDID", device) self._run('boot', ios_device) diff --git a/firefox-ios/firefox-ios-tests/Tests/XCUITests/IntegrationTests.swift b/firefox-ios/firefox-ios-tests/Tests/XCUITests/IntegrationTests.swift index 1ff1216790db..22ea362da597 100644 --- a/firefox-ios/firefox-ios-tests/Tests/XCUITests/IntegrationTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/XCUITests/IntegrationTests.swift @@ -78,6 +78,9 @@ class IntegrationTests: BaseTestCase { mozWaitForElementToExist(app.staticTexts["ACCOUNT"], timeout: TIMEOUT_LONG) mozWaitForElementToNotExist(app.staticTexts["Sync and Save Data"]) sleep(5) + if app.tables.staticTexts["Sync is offline"].exists { + app.tables.staticTexts["Sync is offline"].tap() + } if app.tables.staticTexts["Sync Now"].exists { app.tables.staticTexts["Sync Now"].tap() } @@ -199,7 +202,7 @@ class IntegrationTests: BaseTestCase { navigator.nowAt(SettingsScreen) navigator.goto(LoginsSettings) mozWaitForElementToExist(app.buttons.firstMatch) - app.buttons["Continue"].tap() + app.scrollViews.buttons["Continue"].tap() let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let passcodeInput = springboard.secureTextFields["Passcode field"] @@ -254,7 +257,7 @@ class IntegrationTests: BaseTestCase { navigator.nowAt(SettingsScreen) navigator.goto(LoginsSettings) mozWaitForElementToExist(app.buttons.firstMatch) - app.buttons["Continue"].tap() + app.scrollViews.buttons["Continue"].tap() let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard") let passcodeInput = springboard.secureTextFields["Passcode field"] From c527e91c5559b7c148bb13e2894c7e7ecd8698f0 Mon Sep 17 00:00:00 2001 From: mattreaganmozilla <145381717+mattreaganmozilla@users.noreply.github.com> Date: Mon, 25 Nov 2024 15:50:37 -0800 Subject: [PATCH 8/9] Add FXIOS-10667 Content blocklist support via Remote Settings (#23342) * [FXIOS-10667] Remove the old Disconnect file references from Xcode, as well as old content blocker script, and update the bootstrap to no longer call it * [FXIOS-10667] Add xcodeproj references to the new Remote Settings default disconnect (blocklist) files * [FXIOS-10667] Initial work to load blocklist JSON through remote settings APIs rather than directly as bundle resource * [FXIOX-10667] Comment cleanup * [FXIOS-10667] Have more generalized RemoteSetting load func call into new JSON utility func. * [FXIOS-10667] Use RemoteSettings API for hash check for content lists * [FXIOS-10667] Add and update tests for RemoteDataTypeRecord * [FXIOS-10667] Fix missing node npm in bootstrap --- bootstrap.sh | 5 +- content_blocker_update.sh | 20 ---- firefox-ios/Client.xcodeproj/project.pbxproj | 104 +++++++++++------- .../RemoteSettings/RemoteDataType.swift | 45 ++++++-- .../ContentBlockingListRecord.swift | 11 ++ .../ContentBlocker/ContentBlocker.swift | 21 ++-- .../TrackingProtectionPageStats.swift | 11 +- .../RemoteSettings/RemoteDataTypeTests.swift | 43 +++++++- 8 files changed, 171 insertions(+), 89 deletions(-) delete mode 100755 content_blocker_update.sh create mode 100644 firefox-ios/Client/Application/RemoteSettings/RemoteRecords/ContentBlockingListRecord.swift diff --git a/bootstrap.sh b/bootstrap.sh index 1760055e10e9..5bf6726c07f6 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -47,5 +47,6 @@ cp -r .githooks/* .git/hooks/ # Make the hooks are executable chmod +x .git/hooks/* -# Run and update content blocker -./content_blocker_update.sh +# Install Node.js dependencies and build user scripts +npm install +npm run build diff --git a/content_blocker_update.sh b/content_blocker_update.sh deleted file mode 100755 index 84ffc1ecf27a..000000000000 --- a/content_blocker_update.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/sh -set -e - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -# Version 107.0 hash -SHAVAR_COMMIT_HASH="91cf7dd142fc69aabe334a1a6e0091a1db228203" - -# Install Node.js dependencies and build user scripts -npm install -npm run build - -# Clone shavar prod list -rm -rf shavar-prod-lists && git clone https://github.com/mozilla-services/shavar-prod-lists.git && git -C shavar-prod-lists checkout $SHAVAR_COMMIT_HASH - -cd BrowserKit -swift run || true -swift run diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index 4c1083490775..c07180af83d4 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -119,6 +119,27 @@ 1D7B789F2AE088930011E9F2 /* EventQueueTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D7B789E2AE088930011E9F2 /* EventQueueTests.swift */; }; 1D8487B42AD0C6C100F7527C /* RemoteTabsPanelMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8487B32AD0C6C100F7527C /* RemoteTabsPanelMiddleware.swift */; }; 1D8487B62AD6038100F7527C /* RemoteTabPanelStateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D8487B52AD6038100F7527C /* RemoteTabPanelStateTests.swift */; }; + 1D91C17E2CF11EA500B24960 /* disconnect-block-cookies-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1742CF11EA400B24960 /* disconnect-block-cookies-analytics.json */; }; + 1D91C17F2CF11EA500B24960 /* disconnect-block-cookies-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1752CF11EA400B24960 /* disconnect-block-cookies-content.json */; }; + 1D91C1802CF11EA500B24960 /* disconnect-block-cookies-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1762CF11EA400B24960 /* disconnect-block-cookies-social.json */; }; + 1D91C1812CF11EA500B24960 /* disconnect-block-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1772CF11EA400B24960 /* disconnect-block-advertising.json */; }; + 1D91C1822CF11EA500B24960 /* disconnect-block-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1782CF11EA400B24960 /* disconnect-block-content.json */; }; + 1D91C1832CF11EA500B24960 /* disconnect-block-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1792CF11EA400B24960 /* disconnect-block-analytics.json */; }; + 1D91C1842CF11EA500B24960 /* disconnect-block-cryptomining.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17A2CF11EA500B24960 /* disconnect-block-cryptomining.json */; }; + 1D91C1852CF11EA500B24960 /* disconnect-block-fingerprinting.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17B2CF11EA500B24960 /* disconnect-block-fingerprinting.json */; }; + 1D91C1862CF11EA500B24960 /* disconnect-block-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17C2CF11EA500B24960 /* disconnect-block-social.json */; }; + 1D91C1872CF11EA500B24960 /* disconnect-block-cookies-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17D2CF11EA500B24960 /* disconnect-block-cookies-advertising.json */; }; + 1D91C1892CF1203F00B24960 /* ContentBlockingListRecord.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D91C1882CF1203F00B24960 /* ContentBlockingListRecord.swift */; }; + 1D91C18A2CF526EF00B24960 /* disconnect-block-cookies-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1762CF11EA400B24960 /* disconnect-block-cookies-social.json */; }; + 1D91C18B2CF526EF00B24960 /* disconnect-block-cryptomining.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17A2CF11EA500B24960 /* disconnect-block-cryptomining.json */; }; + 1D91C18C2CF526EF00B24960 /* disconnect-block-cookies-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1752CF11EA400B24960 /* disconnect-block-cookies-content.json */; }; + 1D91C18D2CF526EF00B24960 /* disconnect-block-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1782CF11EA400B24960 /* disconnect-block-content.json */; }; + 1D91C18E2CF526EF00B24960 /* disconnect-block-cookies-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17D2CF11EA500B24960 /* disconnect-block-cookies-advertising.json */; }; + 1D91C18F2CF526EF00B24960 /* disconnect-block-fingerprinting.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17B2CF11EA500B24960 /* disconnect-block-fingerprinting.json */; }; + 1D91C1902CF526EF00B24960 /* disconnect-block-cookies-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1742CF11EA400B24960 /* disconnect-block-cookies-analytics.json */; }; + 1D91C1912CF526EF00B24960 /* disconnect-block-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1792CF11EA400B24960 /* disconnect-block-analytics.json */; }; + 1D91C1922CF526EF00B24960 /* disconnect-block-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C1772CF11EA400B24960 /* disconnect-block-advertising.json */; }; + 1D91C1932CF526EF00B24960 /* disconnect-block-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 1D91C17C2CF11EA500B24960 /* disconnect-block-social.json */; }; 1DA3CE5D24EEE73100422BB2 /* OpenTabsWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA3CE5C24EEE73100422BB2 /* OpenTabsWidget.swift */; }; 1DA3CE5F24EEE7C600422BB2 /* LegacyTabDataRetriever.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DA3CE5E24EEE7C600422BB2 /* LegacyTabDataRetriever.swift */; }; 1DA3CE6724EEE86C00422BB2 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E65075641E37F7AB006961AC /* AppInfo.swift */; }; @@ -731,16 +752,6 @@ 8A32DD5028B419B300D57C60 /* HomepageMessageCardViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A32DD4F28B419B300D57C60 /* HomepageMessageCardViewModelTests.swift */; }; 8A33221F27DFE318008F809E /* TopSitesDataAdaptorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A33221E27DFE318008F809E /* TopSitesDataAdaptorTests.swift */; }; 8A33222227DFE658008F809E /* NimbusMock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A33222127DFE658008F809E /* NimbusMock.swift */; }; - 8A3345612BA499B7008C52AB /* disconnect-block-fingerprinting.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A3345572BA499B6008C52AB /* disconnect-block-fingerprinting.json */; }; - 8A3345622BA499B7008C52AB /* disconnect-block-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A3345582BA499B6008C52AB /* disconnect-block-advertising.json */; }; - 8A3345632BA499B7008C52AB /* disconnect-block-cookies-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A3345592BA499B6008C52AB /* disconnect-block-cookies-content.json */; }; - 8A3345642BA499B7008C52AB /* disconnect-block-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455A2BA499B6008C52AB /* disconnect-block-analytics.json */; }; - 8A3345652BA499B7008C52AB /* disconnect-block-cookies-advertising.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455B2BA499B7008C52AB /* disconnect-block-cookies-advertising.json */; }; - 8A3345662BA499B7008C52AB /* disconnect-block-content.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455C2BA499B7008C52AB /* disconnect-block-content.json */; }; - 8A3345672BA499B7008C52AB /* disconnect-block-cookies-analytics.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455D2BA499B7008C52AB /* disconnect-block-cookies-analytics.json */; }; - 8A3345682BA499B7008C52AB /* disconnect-block-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455E2BA499B7008C52AB /* disconnect-block-social.json */; }; - 8A3345692BA499B7008C52AB /* disconnect-block-cookies-social.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A33455F2BA499B7008C52AB /* disconnect-block-cookies-social.json */; }; - 8A33456A2BA499B7008C52AB /* disconnect-block-cryptomining.json in Resources */ = {isa = PBXBuildFile; fileRef = 8A3345602BA499B7008C52AB /* disconnect-block-cryptomining.json */; }; 8A359EF32A1FD449004A5BB7 /* AdjustWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A359EF22A1FD449004A5BB7 /* AdjustWrapper.swift */; }; 8A359EF62A1FE840004A5BB7 /* MockAdjustWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A359EF52A1FE840004A5BB7 /* MockAdjustWrapper.swift */; }; 8A36AC2C2886F27F00CDC0AD /* MockTabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A36AC2B2886F27F00CDC0AD /* MockTabManager.swift */; }; @@ -2532,6 +2543,17 @@ 1D8487B32AD0C6C100F7527C /* RemoteTabsPanelMiddleware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteTabsPanelMiddleware.swift; sourceTree = ""; }; 1D8487B52AD6038100F7527C /* RemoteTabPanelStateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteTabPanelStateTests.swift; sourceTree = ""; }; 1D90440B860A503D4DBA4213 /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/Storage.strings; sourceTree = ""; }; + 1D91C1742CF11EA400B24960 /* disconnect-block-cookies-analytics.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-analytics.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-cookies-analytics.json"; sourceTree = ""; }; + 1D91C1752CF11EA400B24960 /* disconnect-block-cookies-content.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-content.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-cookies-content.json"; sourceTree = ""; }; + 1D91C1762CF11EA400B24960 /* disconnect-block-cookies-social.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-social.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-cookies-social.json"; sourceTree = ""; }; + 1D91C1772CF11EA400B24960 /* disconnect-block-advertising.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-advertising.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-advertising.json"; sourceTree = ""; }; + 1D91C1782CF11EA400B24960 /* disconnect-block-content.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-content.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-content.json"; sourceTree = ""; }; + 1D91C1792CF11EA400B24960 /* disconnect-block-analytics.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-analytics.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-analytics.json"; sourceTree = ""; }; + 1D91C17A2CF11EA500B24960 /* disconnect-block-cryptomining.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cryptomining.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-cryptomining.json"; sourceTree = ""; }; + 1D91C17B2CF11EA500B24960 /* disconnect-block-fingerprinting.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-fingerprinting.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-fingerprinting.json"; sourceTree = ""; }; + 1D91C17C2CF11EA500B24960 /* disconnect-block-social.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-social.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-social.json"; sourceTree = ""; }; + 1D91C17D2CF11EA500B24960 /* disconnect-block-cookies-advertising.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-advertising.json"; path = "attachments/tracking-protection-lists-ios/disconnect-block-cookies-advertising.json"; sourceTree = ""; }; + 1D91C1882CF1203F00B24960 /* ContentBlockingListRecord.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentBlockingListRecord.swift; sourceTree = ""; }; 1DA24C60879E7D4B2073FD63 /* kab */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = kab; path = kab.lproj/Search.strings; sourceTree = ""; }; 1DA3CE5C24EEE73100422BB2 /* OpenTabsWidget.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenTabsWidget.swift; sourceTree = ""; }; 1DA3CE5E24EEE7C600422BB2 /* LegacyTabDataRetriever.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyTabDataRetriever.swift; sourceTree = ""; }; @@ -7310,16 +7332,6 @@ 8A32DD4F28B419B300D57C60 /* HomepageMessageCardViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomepageMessageCardViewModelTests.swift; sourceTree = ""; }; 8A33221E27DFE318008F809E /* TopSitesDataAdaptorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSitesDataAdaptorTests.swift; sourceTree = ""; }; 8A33222127DFE658008F809E /* NimbusMock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NimbusMock.swift; sourceTree = ""; }; - 8A3345572BA499B6008C52AB /* disconnect-block-fingerprinting.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-fingerprinting.json"; path = "../../../ContentBlockingLists/disconnect-block-fingerprinting.json"; sourceTree = ""; }; - 8A3345582BA499B6008C52AB /* disconnect-block-advertising.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-advertising.json"; path = "../../../ContentBlockingLists/disconnect-block-advertising.json"; sourceTree = ""; }; - 8A3345592BA499B6008C52AB /* disconnect-block-cookies-content.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-content.json"; path = "../../../ContentBlockingLists/disconnect-block-cookies-content.json"; sourceTree = ""; }; - 8A33455A2BA499B6008C52AB /* disconnect-block-analytics.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-analytics.json"; path = "../../../ContentBlockingLists/disconnect-block-analytics.json"; sourceTree = ""; }; - 8A33455B2BA499B7008C52AB /* disconnect-block-cookies-advertising.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-advertising.json"; path = "../../../ContentBlockingLists/disconnect-block-cookies-advertising.json"; sourceTree = ""; }; - 8A33455C2BA499B7008C52AB /* disconnect-block-content.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-content.json"; path = "../../../ContentBlockingLists/disconnect-block-content.json"; sourceTree = ""; }; - 8A33455D2BA499B7008C52AB /* disconnect-block-cookies-analytics.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-analytics.json"; path = "../../../ContentBlockingLists/disconnect-block-cookies-analytics.json"; sourceTree = ""; }; - 8A33455E2BA499B7008C52AB /* disconnect-block-social.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-social.json"; path = "../../../ContentBlockingLists/disconnect-block-social.json"; sourceTree = ""; }; - 8A33455F2BA499B7008C52AB /* disconnect-block-cookies-social.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cookies-social.json"; path = "../../../ContentBlockingLists/disconnect-block-cookies-social.json"; sourceTree = ""; }; - 8A3345602BA499B7008C52AB /* disconnect-block-cryptomining.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; name = "disconnect-block-cryptomining.json"; path = "../../../ContentBlockingLists/disconnect-block-cryptomining.json"; sourceTree = ""; }; 8A359EF22A1FD449004A5BB7 /* AdjustWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdjustWrapper.swift; sourceTree = ""; }; 8A359EF52A1FE840004A5BB7 /* MockAdjustWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockAdjustWrapper.swift; sourceTree = ""; }; 8A36AC2B2886F27F00CDC0AD /* MockTabManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockTabManager.swift; sourceTree = ""; }; @@ -11402,6 +11414,7 @@ isa = PBXGroup; children = ( 8A46F5A52C9E4389005B6422 /* PasswordRuleRecord.swift */, + 1D91C1882CF1203F00B24960 /* ContentBlockingListRecord.swift */, ); path = RemoteRecords; sourceTree = ""; @@ -11902,16 +11915,6 @@ 8AD984F12AF1554F00B9FDA4 /* ContentBlocker */ = { isa = PBXGroup; children = ( - 8A3345582BA499B6008C52AB /* disconnect-block-advertising.json */, - 8A33455A2BA499B6008C52AB /* disconnect-block-analytics.json */, - 8A33455C2BA499B7008C52AB /* disconnect-block-content.json */, - 8A33455B2BA499B7008C52AB /* disconnect-block-cookies-advertising.json */, - 8A33455D2BA499B7008C52AB /* disconnect-block-cookies-analytics.json */, - 8A3345592BA499B6008C52AB /* disconnect-block-cookies-content.json */, - 8A33455F2BA499B7008C52AB /* disconnect-block-cookies-social.json */, - 8A3345602BA499B7008C52AB /* disconnect-block-cryptomining.json */, - 8A3345572BA499B6008C52AB /* disconnect-block-fingerprinting.json */, - 8A33455E2BA499B7008C52AB /* disconnect-block-social.json */, EBB894F8219398E500EB91A0 /* ContentBlocker.swift */, EBB894F9219398E500EB91A0 /* ContentBlocker+Safelist.swift */, EBB894F7219398E500EB91A0 /* TabContentBlocker.swift */, @@ -12084,6 +12087,16 @@ 8AF4E76A2C41D60A00BAD91C /* RemoteSettingsData */ = { isa = PBXGroup; children = ( + 1D91C1772CF11EA400B24960 /* disconnect-block-advertising.json */, + 1D91C1792CF11EA400B24960 /* disconnect-block-analytics.json */, + 1D91C1782CF11EA400B24960 /* disconnect-block-content.json */, + 1D91C17D2CF11EA500B24960 /* disconnect-block-cookies-advertising.json */, + 1D91C1742CF11EA400B24960 /* disconnect-block-cookies-analytics.json */, + 1D91C1752CF11EA400B24960 /* disconnect-block-cookies-content.json */, + 1D91C1762CF11EA400B24960 /* disconnect-block-cookies-social.json */, + 1D91C17A2CF11EA500B24960 /* disconnect-block-cryptomining.json */, + 1D91C17B2CF11EA500B24960 /* disconnect-block-fingerprinting.json */, + 1D91C17C2CF11EA500B24960 /* disconnect-block-social.json */, 8AF4E76B2C41D7C200BAD91C /* Update_Remote_Settings.py */, 8AF4E76D2C41D86100BAD91C /* RemoteSettingsFetchConfig.json */, 8AF4E7702C45B98F00BAD91C /* RemotePasswordRules.json */, @@ -15316,28 +15329,25 @@ 43F92B3829E9F52B000C0F17 /* AutofillAllFramesAtDocumentStart.js in Resources */, 8C29376A2BF79EE000146613 /* AddressFormManager.css in Resources */, 8C29376B2BF79EE000146613 /* AddressFormManager.html in Resources */, - 8A3345662BA499B7008C52AB /* disconnect-block-content.json in Resources */, 39D056382665235700FBEE59 /* initial_experiments.json in Resources */, C8B0F5F8283B7D38007AE65D /* pocketsponsoredfeed.json in Resources */, - 8A33456A2BA499B7008C52AB /* disconnect-block-cryptomining.json in Resources */, D38A1EE01CB458EC0080C842 /* CertError.html in Resources */, + 1D91C1852CF11EA500B24960 /* disconnect-block-fingerprinting.json in Resources */, 8AEE62CB2756BA34003207D1 /* DownloadHelper.js in Resources */, 8AEE62CA2756BA34003207D1 /* TrackingProtectionStats.js in Resources */, 0BA1E0301B051A07007675AF /* NetError.css in Resources */, F84B220B1A0910F600AAB793 /* Images.xcassets in Resources */, - 8A3345692BA499B7008C52AB /* disconnect-block-cookies-social.json in Resources */, - 8A3345682BA499B7008C52AB /* disconnect-block-social.json in Resources */, 4336FAD2264B169000A6B076 /* WebcompatAllFramesAtDocumentStart.js in Resources */, + 1D91C1802CF11EA500B24960 /* disconnect-block-cookies-social.json in Resources */, 23BEA767251A99ED00A014BF /* NewYorkMedium-Bold.otf in Resources */, E4CD9F541A71506400318571 /* Reader.html in Resources */, E1BDAC832B9F65780063E6BF /* reportSiteIssueOff.json in Resources */, + 1D91C17F2CF11EA500B24960 /* disconnect-block-cookies-content.json in Resources */, E1AF3563286DE5F800960045 /* FullFunctionalTestPlan.xctestplan in Resources */, - 8A3345642BA499B7008C52AB /* disconnect-block-analytics.json in Resources */, E1AF3567286DE5F800960045 /* PerformanceTestPlan.xctestplan in Resources */, 8A1A935A2B757C7C0069C190 /* portrait.json in Resources */, 23BEA76A251A99ED00A014BF /* NewYorkMedium-RegularItalic.otf in Resources */, 7B2142FE1E5E055000CDD3FC /* InfoPlist.strings in Resources */, - 8A3345652BA499B7008C52AB /* disconnect-block-cookies-advertising.json in Resources */, E1AF27442A17BCF700CE5991 /* engagementNotificationWithoutConditions.json in Resources */, E69922171B94E3EF007C480D /* Licenses.html in Resources */, 8A1F6C2F2BC5A62400DA6F86 /* PrivacyInfo.xcprivacy in Resources */, @@ -15347,6 +15357,8 @@ D0FCF8061FE4772D004A7995 /* AllFramesAtDocumentEnd.js in Resources */, D37524871C6E8B5A00A5F6C2 /* topdomains.txt in Resources */, 8ABE9F1E2CB462CA0080E1DF /* RemoteSettingsFetchConfig.json in Resources */, + 1D91C1872CF11EA500B24960 /* disconnect-block-cookies-advertising.json in Resources */, + 1D91C1842CF11EA500B24960 /* disconnect-block-cryptomining.json in Resources */, 39F4C0FA2045D87400746155 /* FocusHelper.js in Resources */, E1AF3562286DE5F800960045 /* Smoketest2.xctestplan in Resources */, 8C29376C2BF79EE000146613 /* AddressFormManager.mjs in Resources */, @@ -15360,27 +15372,28 @@ E1AF3566286DE5F800960045 /* Smoketest1.xctestplan in Resources */, E1AF3561286DE5F800960045 /* Smoketest4.xctestplan in Resources */, 8A2B1A5D28216C4D0061216B /* Debug.xcconfig in Resources */, - 8A3345632BA499B7008C52AB /* disconnect-block-cookies-content.json in Resources */, - 8A3345612BA499B7008C52AB /* disconnect-block-fingerprinting.json in Resources */, 0BA1E00E1B03FB0B007675AF /* NetError.html in Resources */, 23BEA768251A99ED00A014BF /* NewYorkMedium-BoldItalic.otf in Resources */, E4A961381AC06FA50069AD6F /* ReaderViewLoading.html in Resources */, E1AF3565286DE5F800960045 /* UnitTest.xctestplan in Resources */, + 1D91C1832CF11EA500B24960 /* disconnect-block-analytics.json in Resources */, E1AF3564286DE5F800960045 /* SyncIntegrationTestPlan.xctestplan in Resources */, 0BBAC4BC2CDD44EC0072DB61 /* easterEggGif.gif in Resources */, + 1D91C1822CF11EA500B24960 /* disconnect-block-content.json in Resources */, 8A7D1AC52BA3542600162F4B /* splashScreen.json in Resources */, 8AEE62C92756BA34003207D1 /* LoginsHelper.js in Resources */, - 8A3345672BA499B7008C52AB /* disconnect-block-cookies-analytics.json in Resources */, + 1D91C1812CF11EA500B24960 /* disconnect-block-advertising.json in Resources */, 8A2B1A5F28216C4D0061216B /* Release.xcconfig in Resources */, + 1D91C17E2CF11EA500B24960 /* disconnect-block-cookies-analytics.json in Resources */, 8CC033FA2BA476840033449E /* FormAutofillHelper.js in Resources */, D0E17FB6201F847600F1FCB5 /* FxASignIn.js in Resources */, 8A2B1A5E28216C4D0061216B /* Common.xcconfig in Resources */, + 1D91C1862CF11EA500B24960 /* disconnect-block-social.json in Resources */, 39A35AED1C0662A3006B9E87 /* SpotlightHelper.js in Resources */, 8AF4E7712C45B98F00BAD91C /* RemotePasswordRules.json in Resources */, D0FCF8071FE4772D004A7995 /* MainFrameAtDocumentEnd.js in Resources */, E4D6BEB91A0930EC00F538BD /* LaunchScreen.xib in Resources */, 23BEA769251A99ED00A014BF /* NewYorkMedium-Regular.otf in Resources */, - 8A3345622BA499B7008C52AB /* disconnect-block-advertising.json in Resources */, D03F8F23200EAC1F003C2224 /* AllFramesAtDocumentStart.js in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -15398,6 +15411,16 @@ C869915D28917811007ACC5C /* wallpaperAvailabilityStart.json in Resources */, C87BE0A428A2ED3F00BAADF5 /* wallpaperNoLearnMoreURL.json in Resources */, C869915A28917811007ACC5C /* wallpaperBadTextColor.json in Resources */, + 1D91C18A2CF526EF00B24960 /* disconnect-block-cookies-social.json in Resources */, + 1D91C18B2CF526EF00B24960 /* disconnect-block-cryptomining.json in Resources */, + 1D91C18C2CF526EF00B24960 /* disconnect-block-cookies-content.json in Resources */, + 1D91C18D2CF526EF00B24960 /* disconnect-block-content.json in Resources */, + 1D91C18E2CF526EF00B24960 /* disconnect-block-cookies-advertising.json in Resources */, + 1D91C18F2CF526EF00B24960 /* disconnect-block-fingerprinting.json in Resources */, + 1D91C1902CF526EF00B24960 /* disconnect-block-cookies-analytics.json in Resources */, + 1D91C1912CF526EF00B24960 /* disconnect-block-analytics.json in Resources */, + 1D91C1922CF526EF00B24960 /* disconnect-block-advertising.json in Resources */, + 1D91C1932CF526EF00B24960 /* disconnect-block-social.json in Resources */, C8B0F5EB283B7BF9007AE65D /* pocketsponsoredfeed.json in Resources */, C869915F28917811007ACC5C /* wallpaperGoodData.json in Resources */, 8ABE9F1A2CB45B4B0080E1DF /* RemotePasswordRules.json in Resources */, @@ -16415,6 +16438,7 @@ E63ED8E11BFD25580097D08E /* PasswordManagerListViewController.swift in Sources */, 8ADC2A162A33765E00543DAA /* UrlToOpenModel.swift in Sources */, D0625CA8208FC47A0081F3B2 /* BrowserViewController+DownloadQueueDelegate.swift in Sources */, + 1D91C1892CF1203F00B24960 /* ContentBlockingListRecord.swift in Sources */, C22753402A3C9E1300B9C0D1 /* WebsiteDataManagementViewModel.swift in Sources */, 2F44FCC71A9E8CF500FD20CC /* SearchSettingsTableViewController.swift in Sources */, 0AFF7F682C78989000265214 /* CertificatesHeaderItem.swift in Sources */, diff --git a/firefox-ios/Client/Application/RemoteSettings/RemoteDataType.swift b/firefox-ios/Client/Application/RemoteSettings/RemoteDataType.swift index 70c0b76bade6..f5852dea3009 100644 --- a/firefox-ios/Client/Application/RemoteSettings/RemoteDataType.swift +++ b/firefox-ios/Client/Application/RemoteSettings/RemoteDataType.swift @@ -20,18 +20,23 @@ enum RemoteDataTypeError: Error, LocalizedError { enum RemoteDataType: String, Codable { case passwordRules + case contentBlockingLists var type: any RemoteDataTypeRecord.Type { switch self { case .passwordRules: return PasswordRuleRecord.self + case .contentBlockingLists: + return ContentBlockingListRecord.self } } - var fileName: String { + var fileNames: [String] { switch self { case .passwordRules: - return "RemotePasswordRules" + return ["RemotePasswordRules"] + case .contentBlockingLists: + return BlocklistFileName.allCases.map { $0.filename } } } @@ -39,11 +44,38 @@ enum RemoteDataType: String, Codable { switch self { case .passwordRules: return "Password Rules" + case .contentBlockingLists: + return "Content Blocking Lists" } } + /// Loads the local settings for the given data type record, returning the + /// decoded objects. + /// - Returns: settings decoded to their RemoteDataTypeRecord. func loadLocalSettingsFromJSON() async throws -> [T] { - let fileName = self.fileName + guard let fileName = self.fileNames.first else { + assertionFailure("No filename available for setting type.") + throw RemoteDataTypeError.fileNotFound(fileName: "") + } + + let data = try loadLocalSettingsFileAsJSON(fileName: fileName) + do { + if let decodedArray = try? JSONDecoder().decode([T].self, from: data) { + return decodedArray + } + let singleObject = try JSONDecoder().decode(T.self, from: data) + return [singleObject] + } catch { + throw RemoteDataTypeError.decodingError(fileName: fileName, error: error) + } + } + + /// Loads the local settings JSON for the given setting file. + /// - Returns: the raw JSON file data. + func loadLocalSettingsFileAsJSON(fileName: String) throws -> Data { + guard fileNames.contains(fileName) else { + throw RemoteDataTypeError.fileNotFound(fileName: fileName) + } guard let path = Bundle.main.path(forResource: fileName, ofType: "json") else { throw RemoteDataTypeError.fileNotFound(fileName: fileName) @@ -53,12 +85,7 @@ enum RemoteDataType: String, Codable { do { let data = try Data(contentsOf: url) - - if let decodedArray = try? JSONDecoder().decode([T].self, from: data) { - return decodedArray - } - let singleObject = try JSONDecoder().decode(T.self, from: data) - return [singleObject] + return data } catch { throw RemoteDataTypeError.decodingError(fileName: fileName, error: error) } diff --git a/firefox-ios/Client/Application/RemoteSettings/RemoteRecords/ContentBlockingListRecord.swift b/firefox-ios/Client/Application/RemoteSettings/RemoteRecords/ContentBlockingListRecord.swift new file mode 100644 index 000000000000..4ca2a53a0cb9 --- /dev/null +++ b/firefox-ios/Client/Application/RemoteSettings/RemoteRecords/ContentBlockingListRecord.swift @@ -0,0 +1,11 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/ + +import Foundation + +/// Object model to represent content blocking rules. +/// This is not used (yet) since we load the JSON directly +/// in order to modify it before injecting to WKWebView. +struct ContentBlockingListRecord: RemoteDataTypeRecord { +} diff --git a/firefox-ios/Client/ContentBlocker/ContentBlocker.swift b/firefox-ios/Client/ContentBlocker/ContentBlocker.swift index 576de3ad5d06..ab1832788712 100644 --- a/firefox-ios/Client/ContentBlocker/ContentBlocker.swift +++ b/firefox-ios/Client/ContentBlocker/ContentBlocker.swift @@ -253,8 +253,14 @@ extension ContentBlocker { let suffixLength = jsonSuffix.count // Trim off .json suffix if needed, we only want the raw file name let fileTrimmed = file.hasSuffix(jsonSuffix) ? String(file.dropLast(suffixLength)) : file - if let path = Bundle.main.path(forResource: fileTrimmed, ofType: "json") { - source = try String(contentsOfFile: path, encoding: .utf8) + + if fileTrimmed.hasPrefix(BlocklistFileName.customBlocklistJSONFilePrefix) { + if let path = Bundle.main.path(forResource: fileTrimmed, ofType: "json") { + source = try String(contentsOfFile: path, encoding: .utf8) + } + } else { + let json = try RemoteDataType.contentBlockingLists.loadLocalSettingsFileAsJSON(fileName: fileTrimmed) + source = String(data: json, encoding: .utf8) ?? "" } } catch let error { logger.log("Error loading content-blocking JSON: \(error)", level: .warning, category: .adblock) @@ -288,11 +294,7 @@ extension ContentBlocker { } } - private func calculateHash(forFileAtPath path: String) -> String? { - guard let fileData = try? Data(contentsOf: URL(fileURLWithPath: path)) else { - return nil - } - + private func calculateHash(for fileData: Data) -> String? { let hash = SHA256.hash(data: fileData) return hash.compactMap { String(format: "%02x", $0) }.joined() } @@ -302,9 +304,10 @@ extension ContentBlocker { let defaults = UserDefaults.standard var hasChanged = false + let lists = RemoteDataType.contentBlockingLists for list in blocklists { - guard let path = Bundle.main.path(forResource: list, ofType: "json"), - let newHash = calculateHash(forFileAtPath: path) else { continue } + guard let data = try? lists.loadLocalSettingsFileAsJSON(fileName: list) else { continue } + guard let newHash = calculateHash(for: data) else { continue } let oldHash = defaults.string(forKey: list) if oldHash != newHash { diff --git a/firefox-ios/Client/ContentBlocker/TrackingProtectionPageStats.swift b/firefox-ios/Client/ContentBlocker/TrackingProtectionPageStats.swift index 74ca12b3be63..e27b9085ad76 100644 --- a/firefox-ios/Client/ContentBlocker/TrackingProtectionPageStats.swift +++ b/firefox-ios/Client/ContentBlocker/TrackingProtectionPageStats.swift @@ -171,13 +171,12 @@ class TPStatsBlocklists { ] { let list: [[String: AnyObject]] do { - guard let path = Bundle.main.path(forResource: blockListFile.filename, ofType: "json") else { - logger.log("Blocklists: bad file path.", level: .warning, category: .webview) - assertionFailure("Blocklists: bad file path.") - return + let settingsLists = RemoteDataType.contentBlockingLists + guard let json = try? settingsLists.loadLocalSettingsFileAsJSON(fileName: blockListFile.filename) else { + logger.log("Blocklists: could not load blocklist JSON file.", level: .warning, category: .webview) + assertionFailure("Blocklists: could not load file.") + continue } - - let json = try Data(contentsOf: URL(fileURLWithPath: path)) guard let data = try JSONSerialization.jsonObject( with: json, options: [] diff --git a/firefox-ios/firefox-ios-tests/Tests/ClientTests/RemoteSettings/RemoteDataTypeTests.swift b/firefox-ios/firefox-ios-tests/Tests/ClientTests/RemoteSettings/RemoteDataTypeTests.swift index 3091c83d66d3..4ff92f05ed30 100644 --- a/firefox-ios/firefox-ios-tests/Tests/ClientTests/RemoteSettings/RemoteDataTypeTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/ClientTests/RemoteSettings/RemoteDataTypeTests.swift @@ -51,13 +51,50 @@ class RemoteDataTypeTests: XCTestCase { } } + // MARK: ContentBlockingListRecord Tests + + func testLoadContentBlockingListRecords() async throws { + // Note: currently ContentBlockingListRecord is a placeholder model. + do { + let _: [ContentBlockingListRecord] = try await loadAndTestRecords(for: .contentBlockingLists) + } catch { + XCTFail("testLoadContentBlockingListRecords failed: \(error)") + } + } + + func testRecordsInContentBlockingJSONFileNotEmpty() async throws { + // Note: currently ContentBlockingListRecord is a placeholder model. + do { + let records: [ContentBlockingListRecord] = try await loadAndTestRecords(for: .contentBlockingLists) + XCTAssertGreaterThan(records.count, 0, "Expected more than 0 records, but found none") + } catch { + XCTFail("testRecordsInContentBlockingJSONFileNotEmpty failed: \(error)") + } + } + + func testLoadContentBlockListJSONFiles() { + let lists = RemoteDataType.contentBlockingLists + lists.fileNames.forEach { + do { + let data = try lists.loadLocalSettingsFileAsJSON(fileName: $0) + XCTAssertNotNil(data, "Received nil data for content blocking JSON data. File: \($0).") + } catch { + XCTFail("Error while attempting to decode content blocking list \($0): \(error)") + } + } + } + // MARK: Helper // Indirectly tests `loadLocalSettingsFromJSON` by calling it within this function. // Any failure in loading or decoding will propagate here and fail the test. func loadAndTestRecords(for remoteDataType: RemoteDataType) async throws -> [T] { - guard Bundle(for: type(of: self)).path(forResource: remoteDataType.fileName, ofType: "json") != nil else { - XCTFail("\(remoteDataType.fileName).json not found in test bundle") + guard let fileName = remoteDataType.fileNames.first else { + XCTFail("\(String(describing: remoteDataType)) fileNames list is unexpectedly empty.") + return [] + } + guard Bundle(for: type(of: self)).path(forResource: fileName, ofType: "json") != nil else { + XCTFail("\(fileName).json not found in test bundle") return [] } @@ -66,7 +103,7 @@ class RemoteDataTypeTests: XCTestCase { XCTAssertGreaterThan(records.count, 0, "Expected more than 0 records") return records } catch { - XCTFail("Failed to load and decode records from \(remoteDataType.fileName).json: \(error)") + XCTFail("Failed to load and decode records from \(fileName).json: \(error)") throw error } } From ad0a142abb3b56d748a54a6fbf82d2fe48441296 Mon Sep 17 00:00:00 2001 From: dragosb01 <134391433+dragosb01@users.noreply.github.com> Date: Tue, 26 Nov 2024 10:25:27 +0200 Subject: [PATCH 9/9] Fixes MTE-3890 - for flaky smoke tests (#23389) --- .../Tests/XCUITests/AddressesTests.swift | 13 ++++++++----- .../Tests/XCUITests/BookmarksTests.swift | 1 + .../Tests/XCUITests/DragAndDropTests.swift | 1 + 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/firefox-ios/firefox-ios-tests/Tests/XCUITests/AddressesTests.swift b/firefox-ios/firefox-ios-tests/Tests/XCUITests/AddressesTests.swift index f717cff7b799..74a240068ce3 100644 --- a/firefox-ios/firefox-ios-tests/Tests/XCUITests/AddressesTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/XCUITests/AddressesTests.swift @@ -191,10 +191,9 @@ class AddressesTests: BaseTestCase { updateAddress(updateCountry: updateCountry, isPostalCode: isPostalCode) tapSave() // The "Address saved" toast message is displayed - // mozWaitForElementToExist(app.staticTexts[addressSavedTxt]) + mozWaitForElementToExist(app.staticTexts[addressSavedTxt]) // The address is saved - // Update with correct toast message after https://mozilla-hub.atlassian.net/browse/FXIOS-10422 is fixed - // mozWaitForElementToExist(app.staticTexts[savedAddressesTxt]) + mozWaitForElementToExist(app.staticTexts[savedAddressesTxt]) if updateCountry { let addressInfo = ["Test2", "test address2", "city test2, 100000"] for index in addressInfo { @@ -318,8 +317,12 @@ class AddressesTests: BaseTestCase { app.typeText(email) } - private func tapSave() { - app.buttons["Save"].tapWithRetry() + private func tapSave(withRetry: Bool = false) { + if withRetry { + app.buttons["Save"].tapWithRetry() + } else { + app.buttons["Save"].tap() + } } private func tapEdit() { diff --git a/firefox-ios/firefox-ios-tests/Tests/XCUITests/BookmarksTests.swift b/firefox-ios/firefox-ios-tests/Tests/XCUITests/BookmarksTests.swift index f3f9c3a43704..3de5dcb852c4 100644 --- a/firefox-ios/firefox-ios-tests/Tests/XCUITests/BookmarksTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/XCUITests/BookmarksTests.swift @@ -148,6 +148,7 @@ class BookmarksTests: BaseTestCase { navigator.nowAt(BrowserTab) // Clear text and enter new url + waitUntilPageLoad() waitForTabsButton() navigator.performAction(Action.OpenNewTabFromTabTray) navigator.goto(URLBarOpen) diff --git a/firefox-ios/firefox-ios-tests/Tests/XCUITests/DragAndDropTests.swift b/firefox-ios/firefox-ios-tests/Tests/XCUITests/DragAndDropTests.swift index 12e6588a63d4..178fe02a8c4e 100644 --- a/firefox-ios/firefox-ios-tests/Tests/XCUITests/DragAndDropTests.swift +++ b/firefox-ios/firefox-ios-tests/Tests/XCUITests/DragAndDropTests.swift @@ -192,6 +192,7 @@ private extension BaseTestCase { navigator.nowAt(NewTabScreen) } navigator.openURL(firstWebsite.url) + waitUntilPageLoad() waitForTabsButton() navigator.performAction(Action.OpenNewTabFromTabTray) navigator.nowAt(NewTabScreen)