From c6265ac85fc5885434c37998fbd717ad07359f9b Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 12:37:39 -0500 Subject: [PATCH 1/2] Refactor FXIOS-7853 [v122] Redux pattern protocol improvements (backport #17542) (#17626) * Refactor FXIOS-7853 [v122] Redux pattern protocol improvements (#17542) * Add helper functions * updates * Update further places * Update tests --------- Co-authored-by: roux g. buciu (cherry picked from commit b7db64ae905bd71c9f6b14f1710bd248ef002c9a) # Conflicts: # Client/Frontend/Browser/Tabs/TabDisplayViewController.swift # Client/Frontend/Browser/Tabs/TabTrayViewController.swift # Client/Frontend/Home/HomepageViewController.swift * Fix merge issues --------- Co-authored-by: roux g. buciu <11182210+adudenamedruby@users.noreply.github.com> Co-authored-by: Winnie Teichmann <4530+thatswinnie@users.noreply.github.com> --- .../Sources/Redux/StoreSubscriber.swift | 2 + .../Utilities/FakeReduxViewController.swift | 19 ++++++++- .../Browser/BrowserViewController.swift | 14 ++++--- .../Tabs/RemoteTabs/RemoteTabsPanel.swift | 16 +++++--- .../Tabs/TabDisplayViewController.swift | 41 +++++++++++-------- .../Browser/Tabs/TabTrayViewController.swift | 35 +++++++++------- .../ThemeSettingsController.swift | 22 +++++++--- 7 files changed, 98 insertions(+), 51 deletions(-) diff --git a/BrowserKit/Sources/Redux/StoreSubscriber.swift b/BrowserKit/Sources/Redux/StoreSubscriber.swift index c55ec9f7222b..24e83d409469 100644 --- a/BrowserKit/Sources/Redux/StoreSubscriber.swift +++ b/BrowserKit/Sources/Redux/StoreSubscriber.swift @@ -5,6 +5,8 @@ import Foundation public protocol AnyStoreSubscriber: AnyObject { + func subscribeToRedux() + func unsubscribeFromRedux() func newState(state: Any) } diff --git a/BrowserKit/Tests/ReduxTests/Utilities/FakeReduxViewController.swift b/BrowserKit/Tests/ReduxTests/Utilities/FakeReduxViewController.swift index 2dc16f52965e..6a0ae2ce01c4 100644 --- a/BrowserKit/Tests/ReduxTests/Utilities/FakeReduxViewController.swift +++ b/BrowserKit/Tests/ReduxTests/Utilities/FakeReduxViewController.swift @@ -12,15 +12,32 @@ class FakeReduxViewController: UIViewController, StoreSubscriber { override func viewDidLoad() { super.viewDidLoad() + subscribeToRedux() + view.addSubview(label) + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + unsubscribeFromRedux() + } + + // MARK: - Redux + + func subscribeToRedux() { store.subscribe(self) store.dispatch(FakeReduxAction.requestInitialValue) - view.addSubview(label) + } + + func unsubscribeFromRedux() { + store.unsubscribe(self) } func newState(state: FakeReduxState) { label.text = "\(state.counter)" } + // MARK: - Helper functions + func increaseCounter() { store.dispatch(FakeReduxAction.increaseCounter) } diff --git a/Client/Frontend/Browser/BrowserViewController.swift b/Client/Frontend/Browser/BrowserViewController.swift index 836ff3e06ddd..30773101e303 100644 --- a/Client/Frontend/Browser/BrowserViewController.swift +++ b/Client/Frontend/Browser/BrowserViewController.swift @@ -208,9 +208,7 @@ class BrowserViewController: UIViewController, } deinit { - if isReduxIntegrationEnabled { - store.unsubscribe(self) - } + unsubscribeFromRedux() } override var prefersStatusBarHidden: Bool { @@ -467,7 +465,7 @@ class BrowserViewController: UIViewController, // MARK: - Redux - private func subscribeRedux() { + func subscribeToRedux() { guard isReduxIntegrationEnabled else { return } store.dispatch(ActiveScreensStateAction.showScreen(.fakespot)) @@ -476,6 +474,12 @@ class BrowserViewController: UIViewController, }) } + func unsubscribeFromRedux() { + if isReduxIntegrationEnabled { + store.unsubscribe(self) + } + } + func newState(state: FakespotState) { ensureMainThread { [weak self] in guard let self else { return } @@ -550,7 +554,7 @@ class BrowserViewController: UIViewController, // Send settings telemetry for Fakespot FakespotUtils().addSettingTelemetry() - subscribeRedux() + subscribeToRedux() } private func setupAccessibleActions() { diff --git a/Client/Frontend/Browser/Tabs/RemoteTabs/RemoteTabsPanel.swift b/Client/Frontend/Browser/Tabs/RemoteTabs/RemoteTabsPanel.swift index 41a25acada5a..6230cac20f36 100644 --- a/Client/Frontend/Browser/Tabs/RemoteTabs/RemoteTabsPanel.swift +++ b/Client/Frontend/Browser/Tabs/RemoteTabs/RemoteTabsPanel.swift @@ -47,10 +47,7 @@ class RemoteTabsPanel: UIViewController, required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } deinit { - if isReduxIntegrationEnabled { - store.dispatch(ActiveScreensStateAction.closeScreen(.remoteTabsPanel)) - store.unsubscribe(self) - } + unsubscribeFromRedux() } // MARK: - Actions @@ -96,7 +93,7 @@ class RemoteTabsPanel: UIViewController, listenForThemeChange(view) setupLayout() - subscribeRedux() + subscribeToRedux() applyTheme() } @@ -128,7 +125,7 @@ class RemoteTabsPanel: UIViewController, // MARK: - Redux - private func subscribeRedux() { + func subscribeToRedux() { guard isReduxIntegrationEnabled else { return } store.dispatch(ActiveScreensStateAction.showScreen(.remoteTabsPanel)) store.dispatch(RemoteTabsPanelAction.panelDidAppear) @@ -137,6 +134,13 @@ class RemoteTabsPanel: UIViewController, }) } + func unsubscribeFromRedux() { + if isReduxIntegrationEnabled { + store.dispatch(ActiveScreensStateAction.closeScreen(.remoteTabsPanel)) + store.unsubscribe(self) + } + } + func newState(state: RemoteTabsPanelState) { ensureMainThread { [weak self] in guard let self else { return } diff --git a/Client/Frontend/Browser/Tabs/TabDisplayViewController.swift b/Client/Frontend/Browser/Tabs/TabDisplayViewController.swift index ba274c36c16f..784796ea8c55 100644 --- a/Client/Frontend/Browser/Tabs/TabDisplayViewController.swift +++ b/Client/Frontend/Browser/Tabs/TabDisplayViewController.swift @@ -25,7 +25,6 @@ class TabDisplayViewController: UIViewController, private var backgroundPrivacyOverlay: UIView = .build() private lazy var emptyPrivateTabsView: EmptyPrivateTabsView = .build() - // MARK: Redux state var tabsState: TabsState init(isPrivateMode: Bool, @@ -43,8 +42,7 @@ class TabDisplayViewController: UIViewController, } deinit { - store.dispatch(ActiveScreensStateAction.closeScreen(.tabsPanel)) - store.unsubscribe(self) + unsubscribeFromRedux() } override func viewDidLoad() { @@ -52,21 +50,7 @@ class TabDisplayViewController: UIViewController, setupView() listenForThemeChange(view) applyTheme() - subscribeRedux() - } - - private func subscribeRedux() { - store.dispatch(ActiveScreensStateAction.showScreen(.tabsPanel)) - store.dispatch(TabPanelAction.tabPanelDidLoad(tabsState.isPrivateMode)) - store.subscribe(self, transform: { - return $0.select(TabsState.init) - }) - } - - func newState(state: TabsState) { - tabsState = state - tabDisplayView.newState(state: tabsState) - shouldShowEmptyView(tabsState.isPrivateTabsEmpty) + subscribeToRedux() } func setupView() { @@ -116,6 +100,27 @@ class TabDisplayViewController: UIViewController, tabDisplayView.applyTheme(theme: themeManager.currentTheme) } + // MARK: - Redux + + func subscribeToRedux() { + store.dispatch(ActiveScreensStateAction.showScreen(.tabsPanel)) + store.dispatch(TabPanelAction.tabPanelDidLoad(tabsState.isPrivateMode)) + store.subscribe(self, transform: { + return $0.select(TabsState.init) + }) + } + + func unsubscribeFromRedux() { + store.dispatch(ActiveScreensStateAction.closeScreen(.tabsPanel)) + store.unsubscribe(self) + } + + func newState(state: TabsState) { + tabsState = state + tabDisplayView.newState(state: tabsState) + shouldShowEmptyView(tabsState.isPrivateTabsEmpty) + } + // MARK: EmptyPrivateTabsViewDelegate func didTapLearnMore(urlRequest: URLRequest) {} } diff --git a/Client/Frontend/Browser/Tabs/TabTrayViewController.swift b/Client/Frontend/Browser/Tabs/TabTrayViewController.swift index ce969e651663..6f1560935b52 100644 --- a/Client/Frontend/Browser/Tabs/TabTrayViewController.swift +++ b/Client/Frontend/Browser/Tabs/TabTrayViewController.swift @@ -199,7 +199,7 @@ class TabTrayViewController: UIViewController, override func viewDidLoad() { super.viewDidLoad() setupView() - subscribeRedux() + subscribeToRedux() listenForThemeChange(view) updateToolbarItems() } @@ -229,20 +229,7 @@ class TabTrayViewController: UIViewController, super.viewDidDisappear(animated) delegate?.didFinish() - store.dispatch(ActiveScreensStateAction.closeScreen(.tabsTray)) - store.unsubscribe(self) - } - - private func subscribeRedux() { - store.dispatch(ActiveScreensStateAction.showScreen(.tabsTray)) - store.dispatch(TabTrayAction.tabTrayDidLoad(tabTrayState.selectedPanel)) - store.subscribe(self, transform: { - return $0.select(TabTrayState.init) - }) - } - - func newState(state: TabTrayState) { - tabTrayState = state + unsubscribeFromRedux() } private func updateLayout() { @@ -260,6 +247,24 @@ class TabTrayViewController: UIViewController, updateToolbarItems() } + // MARK: - Redux + + func subscribeToRedux() { + store.dispatch(ActiveScreensStateAction.showScreen(.tabsTray)) + store.dispatch(TabTrayAction.tabTrayDidLoad(tabTrayState.selectedPanel)) + store.subscribe(self, transform: { + return $0.select(TabTrayState.init) + }) + } + + func unsubscribeFromRedux() { + store.dispatch(ActiveScreensStateAction.closeScreen(.tabsTray)) + store.unsubscribe(self) + } + + func newState(state: TabTrayState) { + } + // MARK: Themeable func applyTheme() { view.backgroundColor = themeManager.currentTheme.colors.layer1 diff --git a/Client/Frontend/Settings/ThemeSettings/ThemeSettingsController.swift b/Client/Frontend/Settings/ThemeSettings/ThemeSettingsController.swift index 27ac784cf25b..917029a26c3a 100644 --- a/Client/Frontend/Settings/ThemeSettings/ThemeSettingsController.swift +++ b/Client/Frontend/Settings/ThemeSettings/ThemeSettingsController.swift @@ -55,12 +55,7 @@ class ThemeSettingsController: ThemedTableViewController, StoreSubscriber { override func viewDidLoad() { super.viewDidLoad() - if isReduxIntegrationEnabled { - store.dispatch(ThemeSettingsAction.themeSettingsDidAppear) - store.subscribe(self, transform: { - $0.select(ThemeSettingsState.init) - }) - } + subscribeToRedux() title = .SettingsDisplayThemeTitle tableView.accessibilityIdentifier = "DisplayTheme.Setting.Options" @@ -76,6 +71,21 @@ class ThemeSettingsController: ThemedTableViewController, StoreSubscriber { override func viewDidDisappear(_ animated: Bool) { super.viewDidDisappear(animated) + unsubscribeFromRedux() + } + + // MARK: - Redux + + func subscribeToRedux() { + if isReduxIntegrationEnabled { + store.dispatch(ThemeSettingsAction.themeSettingsDidAppear) + store.subscribe(self, transform: { + $0.select(ThemeSettingsState.init) + }) + } + } + + func unsubscribeFromRedux() { if isReduxIntegrationEnabled { store.dispatch(ActiveScreensStateAction.closeScreen(.themeSettings)) store.unsubscribe(self) From dc0bec619d5805e68dd6f22fc9df9a75d7bdd2e7 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 5 Dec 2023 15:03:01 -0500 Subject: [PATCH 2/2] Refactor FXIOS-7817 [v122] Add BrowserViewControllerState (backport #17565) (#17631) * Refactor FXIOS-7817 [v122] Add BrowserViewControllerState (#17565) * Lots of learning * Updates & cleanup * Remove things * Minor refactor lolololololol * Language and big brain fixes * PR comments --------- Co-authored-by: roux g. buciu (cherry picked from commit 723d77f29d69ba1296fbb66cbf97c34befc8a9a5) # Conflicts: # Client.xcodeproj/project.pbxproj # Client/Frontend/FeltPrivacy/FeltPrivacyAction.swift # Client/Frontend/Home/HomepageViewController.swift # Client/Redux/GlobalState/ActiveScreenState.swift # Client/Redux/GlobalState/AppState.swift # Client/TabManagement/TabManager.swift * fix conflicts --------- Co-authored-by: roux g. buciu <11182210+adudenamedruby@users.noreply.github.com> Co-authored-by: roux g. buciu --- Client.xcodeproj/project.pbxproj | 28 ++++++++++ .../Browser/BrowserViewController.swift | 20 +++---- Client/Frontend/Fakespot/FakespotState.swift | 9 +--- .../BrowserViewControllerState.swift | 53 +++++++++++++++++++ .../FeltPrivacy/FeltPrivacyAction.swift | 14 +++++ .../FeltPrivacy/FeltPrivacyManager.swift | 26 +++++++++ .../FeltPrivacy/FeltPrivacyMiddleware.swift | 29 ++++++++++ .../FeltPrivacy/FeltPrivacyState.swift | 31 +++++++++++ .../Home/HomepageViewController.swift | 8 ++- .../GlobalState/ActiveScreenAction.swift | 2 +- .../Redux/GlobalState/ActiveScreenState.swift | 24 ++++----- Client/Redux/GlobalState/AppState.swift | 11 ++-- Client/TabManagement/TabManager.swift | 2 + 13 files changed, 222 insertions(+), 35 deletions(-) create mode 100644 Client/Frontend/FeltPrivacy/BrowserViewControllerState.swift create mode 100644 Client/Frontend/FeltPrivacy/FeltPrivacyAction.swift create mode 100644 Client/Frontend/FeltPrivacy/FeltPrivacyManager.swift create mode 100644 Client/Frontend/FeltPrivacy/FeltPrivacyMiddleware.swift create mode 100644 Client/Frontend/FeltPrivacy/FeltPrivacyState.swift diff --git a/Client.xcodeproj/project.pbxproj b/Client.xcodeproj/project.pbxproj index cce54c33e758..679334cda318 100644 --- a/Client.xcodeproj/project.pbxproj +++ b/Client.xcodeproj/project.pbxproj @@ -534,6 +534,11 @@ 7BEB64441C7345600092C02E /* L10nSuite2SnapshotTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B3632D31C2983F000D12AF9 /* L10nSuite2SnapshotTests.swift */; }; 7BEB64451C7345600092C02E /* SnapshotHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B60B0071BDE3AE10090C984 /* SnapshotHelper.swift */; }; 7BEFC6801BFF68C30059C952 /* QuickActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BEFC67F1BFF68C30059C952 /* QuickActions.swift */; }; + 810FF3542B178343009F062C /* FeltPrivacyMiddleware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810FF3532B178343009F062C /* FeltPrivacyMiddleware.swift */; }; + 810FF3562B1783B0009F062C /* FeltPrivacyManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810FF3552B1783B0009F062C /* FeltPrivacyManager.swift */; }; + 810FF3582B1784E7009F062C /* FeltPrivacyAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810FF3572B1784E7009F062C /* FeltPrivacyAction.swift */; }; + 810FF35A2B178556009F062C /* FeltPrivacyState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 810FF3592B178556009F062C /* FeltPrivacyState.swift */; }; + 81CAE4DB2B1A2C220040C78A /* BrowserViewControllerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 81CAE4DA2B1A2C220040C78A /* BrowserViewControllerState.swift */; }; 884CA7492344A301002E4711 /* TextContentDetector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 884CA7482344A301002E4711 /* TextContentDetector.swift */; }; 8A0017C128A3FF6100FEFC8B /* MessageCardDataAdaptor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0017C028A3FF6100FEFC8B /* MessageCardDataAdaptor.swift */; }; 8A01891C275E9C2A00923EFE /* ClearHistorySheetProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A01891B275E9C2A00923EFE /* ClearHistorySheetProvider.swift */; }; @@ -5007,12 +5012,17 @@ 80B54D93BC553D6E6CDFAA0A /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/AuthenticationManager.strings; sourceTree = ""; }; 80B8473B933671C9605DC837 /* gl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = gl; path = gl.lproj/InfoPlist.strings; sourceTree = ""; }; 80E24B20A5655593E1D9E85B /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = "zh-TW.lproj/Search.strings"; sourceTree = ""; }; + 810FF3532B178343009F062C /* FeltPrivacyMiddleware.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeltPrivacyMiddleware.swift; sourceTree = ""; }; + 810FF3552B1783B0009F062C /* FeltPrivacyManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeltPrivacyManager.swift; sourceTree = ""; }; + 810FF3572B1784E7009F062C /* FeltPrivacyAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeltPrivacyAction.swift; sourceTree = ""; }; + 810FF3592B178556009F062C /* FeltPrivacyState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeltPrivacyState.swift; sourceTree = ""; }; 81504EA4876ED3D974FDA0F6 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/AuthenticationManager.strings; sourceTree = ""; }; 81584D62B22049E40FC78F93 /* sl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sl; path = sl.lproj/3DTouchActions.strings; sourceTree = ""; }; 816D458CBEAE2A6721134028 /* dsb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = dsb; path = dsb.lproj/ClearPrivateData.strings; sourceTree = ""; }; 81754147A06566E64C025F70 /* nn */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nn; path = "nn.lproj/Default Browser.strings"; sourceTree = ""; }; 81A244F4A7C6FC8976DC21F0 /* br */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = br; path = br.lproj/InfoPlist.strings; sourceTree = ""; }; 81C14765AA7C25DF1817AC04 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Today.strings; sourceTree = ""; }; + 81CAE4DA2B1A2C220040C78A /* BrowserViewControllerState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserViewControllerState.swift; sourceTree = ""; }; 81DF4C79AE53A2FCA08EEE9C /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = "da.lproj/Default Browser.strings"; sourceTree = ""; }; 81E446CF88B278374B416BF5 /* or */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = or; path = or.lproj/AuthenticationManager.strings; sourceTree = ""; }; 81F647D98E79EC6406CDFCB4 /* lt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = lt; path = lt.lproj/ClearPrivateData.strings; sourceTree = ""; }; @@ -8462,6 +8472,18 @@ path = Menu; sourceTree = ""; }; + 810FF3522B1782FE009F062C /* FeltPrivacy */ = { + isa = PBXGroup; + children = ( + 81CAE4DA2B1A2C220040C78A /* BrowserViewControllerState.swift */, + 810FF3532B178343009F062C /* FeltPrivacyMiddleware.swift */, + 810FF3592B178556009F062C /* FeltPrivacyState.swift */, + 810FF3572B1784E7009F062C /* FeltPrivacyAction.swift */, + 810FF3552B1783B0009F062C /* FeltPrivacyManager.swift */, + ); + path = FeltPrivacy; + sourceTree = ""; + }; 8A0017BF28A3FED300FEFC8B /* MessageCard */ = { isa = PBXGroup; children = ( @@ -10970,6 +10992,7 @@ F84B21F11A0910F600AAB793 /* Frontend */ = { isa = PBXGroup; children = ( + 810FF3522B1782FE009F062C /* FeltPrivacy */, E1D3FFAF2A66A9BD002D31EF /* Fakespot */, 43D00490296FC44B00CB0F31 /* Autofill */, C855728029AE7EF900AF32B0 /* SurveySurface */, @@ -12758,6 +12781,7 @@ 1DEBC55E2AC4ED70006E4801 /* RemoteTabsPanel.swift in Sources */, 435D660523D794B90046EFA2 /* UpdateViewModel.swift in Sources */, 9658143C29FAB610007339BD /* CreditCardInputFieldHelper.swift in Sources */, + 810FF3542B178343009F062C /* FeltPrivacyMiddleware.swift in Sources */, 215B457F27D7FD4B00E5E800 /* LegacyTabGroupData.swift in Sources */, E12BD0B028AC3A7E0029AAF0 /* UIEdgeInsets+Extension.swift in Sources */, C2D80BE72AADE38100CDF7A9 /* CredentialAutofillCoordinator.swift in Sources */, @@ -12847,6 +12871,7 @@ 8A07910F278F62F2005529CB /* AdjustHelper.swift in Sources */, E1442FC2294782C3003680B0 /* NSAttributedString+Extension.swift in Sources */, 967A028E28FA026F003C35E3 /* SceneDelegate.swift in Sources */, + 810FF3562B1783B0009F062C /* FeltPrivacyManager.swift in Sources */, C8B07A4128199500000AFCE7 /* NimbusFlaggableFeature.swift in Sources */, 0B62EFD21AD63CD100ACB9CD /* Clearables.swift in Sources */, 431C0CA925C890E500395CE4 /* DefaultBrowserOnboardingViewModel.swift in Sources */, @@ -12899,6 +12924,7 @@ 2178A6A0291454B5002EC290 /* ReaderModeThemeButton.swift in Sources */, 39F4C10A2045DB2E00746155 /* FocusHelper.swift in Sources */, E4CD9F2D1A6DC91200318571 /* TabLocationView.swift in Sources */, + 81CAE4DB2B1A2C220040C78A /* BrowserViewControllerState.swift in Sources */, C8BD87602A0C248000CD803A /* OnboardingButtonsModel.swift in Sources */, 0BB5B2881AC0A2B90052877D /* SnackBar.swift in Sources */, E1442FCF294782D9003680B0 /* UIView+Screenshot.swift in Sources */, @@ -13244,6 +13270,7 @@ E1ADE23C2B0649F200FD17AA /* FakespotState.swift in Sources */, 2816F0001B33E05400522243 /* UIConstants.swift in Sources */, 21E78A7228F9A93100F8D687 /* UIDeviceInterface.swift in Sources */, + 810FF35A2B178556009F062C /* FeltPrivacyState.swift in Sources */, EBB89508219398E500EB91A0 /* ContentBlocker+Safelist.swift in Sources */, 437A9B6A2681257F00FB41C1 /* LegacyInactiveTabViewModel.swift in Sources */, C838FD5E289981240068F60B /* WallpaperURLProvider.swift in Sources */, @@ -13357,6 +13384,7 @@ 59A68E0B4ABBF55E14819668 /* BookmarksPanel.swift in Sources */, BD4B2DE429BB4D9A005FAA50 /* TimerSnackBar.swift in Sources */, 21EA466A2B04130500AAAB2D /* TabsState.swift in Sources */, + 810FF3582B1784E7009F062C /* FeltPrivacyAction.swift in Sources */, D04D1B862097859B0074B35F /* DownloadToast.swift in Sources */, C29B64EE2AD937D500F3244B /* QRCodeNavigationHandler.swift in Sources */, 8A19ACB42A3290D9001C2147 /* ContentBlockerSetting.swift in Sources */, diff --git a/Client/Frontend/Browser/BrowserViewController.swift b/Client/Frontend/Browser/BrowserViewController.swift index 30773101e303..dca0ee44ebb4 100644 --- a/Client/Frontend/Browser/BrowserViewController.swift +++ b/Client/Frontend/Browser/BrowserViewController.swift @@ -28,6 +28,8 @@ class BrowserViewController: UIViewController, static let ActionSheetTitleMaxLength = 120 } + typealias SubscriberStateType = BrowserViewControllerState + private let KVOs: [KVOConstants] = [ .estimatedProgress, .loading, @@ -80,7 +82,7 @@ class BrowserViewController: UIViewController, let tabManager: TabManager let ratingPromptManager: RatingPromptManager lazy var isTabTrayRefactorEnabled: Bool = TabTrayFlagManager.isRefactorEnabled - private var fakespotState: FakespotState? + private var browserViewControllerState: BrowserViewControllerState? // Header stack view can contain the top url bar, top reader mode, top ZoomPageBar var header: BaseAlphaStackView = .build { _ in } @@ -467,10 +469,10 @@ class BrowserViewController: UIViewController, func subscribeToRedux() { guard isReduxIntegrationEnabled else { return } - store.dispatch(ActiveScreensStateAction.showScreen(.fakespot)) + store.dispatch(ActiveScreensStateAction.showScreen(.browserViewController)) store.subscribe(self, transform: { - $0.select(FakespotState.init) + $0.select(BrowserViewControllerState.init) }) } @@ -480,17 +482,17 @@ class BrowserViewController: UIViewController, } } - func newState(state: FakespotState) { + func newState(state: BrowserViewControllerState) { ensureMainThread { [weak self] in guard let self else { return } - fakespotState = state + browserViewControllerState = state // opens or close sidebar/bottom sheet to match the saved state - if state.isOpenOnProductPage { + if state.fakespotState.isOpenOnProductPage { guard let productURL = urlBar.currentURL else { return } handleFakespotFlow(productURL: productURL) - } else { + } else if !state.fakespotState.isOpenOnProductPage { _ = dismissFakespotIfNeeded() } } @@ -761,7 +763,7 @@ class BrowserViewController: UIViewController, var fakespotNeedsUpdate = false if urlBar.currentURL != nil { fakespotNeedsUpdate = contentStackView.isSidebarVisible != FakespotUtils().shouldDisplayInSidebar(viewSize: size) - if isReduxIntegrationEnabled, let fakespotState = fakespotState { + if isReduxIntegrationEnabled, let fakespotState = browserViewControllerState?.fakespotState { fakespotNeedsUpdate = fakespotNeedsUpdate && fakespotState.isOpenOnProductPage } @@ -1707,7 +1709,7 @@ class BrowserViewController: UIViewController, !tab.isPrivate, FakespotUtils().shouldDisplayInSidebar(), isReduxIntegrationEnabled, - let fakespotState = fakespotState, + let fakespotState = browserViewControllerState?.fakespotState, fakespotState.isOpenOnProductPage { handleFakespotFlow(productURL: url) } else if contentStackView.isSidebarVisible { diff --git a/Client/Frontend/Fakespot/FakespotState.swift b/Client/Frontend/Fakespot/FakespotState.swift index f4bc294265d6..365aeabb2ef7 100644 --- a/Client/Frontend/Fakespot/FakespotState.swift +++ b/Client/Frontend/Fakespot/FakespotState.swift @@ -8,13 +8,8 @@ import Redux struct FakespotState: ScreenState, Equatable { var isOpenOnProductPage: Bool - init(_ appState: AppState) { - guard let fakespotState = store.state.screenState(FakespotState.self, for: .fakespot) else { - self.init() - return - } - - self.init(isOpenOnProductPage: fakespotState.isOpenOnProductPage) + init(_ appState: BrowserViewControllerState) { + self.init(isOpenOnProductPage: appState.fakespotState.isOpenOnProductPage) } init() { diff --git a/Client/Frontend/FeltPrivacy/BrowserViewControllerState.swift b/Client/Frontend/FeltPrivacy/BrowserViewControllerState.swift new file mode 100644 index 000000000000..f9e3a5ed2c18 --- /dev/null +++ b/Client/Frontend/FeltPrivacy/BrowserViewControllerState.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 Foundation +import Redux + +struct BrowserViewControllerState: ScreenState, Equatable { + var feltPrivacyState: FeltPrivacyState + var fakespotState: FakespotState + + init(_ appState: AppState) { + guard let bvcState = store.state.screenState( + BrowserViewControllerState.self, + for: .browserViewController) + else { + self.init() + return + } + + self.init(feltPrivacyState: bvcState.feltPrivacyState, + fakespotState: bvcState.fakespotState) + } + + init() { + self.init( + feltPrivacyState: FeltPrivacyState(), + fakespotState: FakespotState()) + } + + init( + feltPrivacyState: FeltPrivacyState, + fakespotState: FakespotState + ) { + self.feltPrivacyState = feltPrivacyState + self.fakespotState = fakespotState + } + + static let reducer: Reducer = { state, action in + switch action { + case FeltPrivacyAction.privateModeUpdated(let privacyState): + return BrowserViewControllerState( + feltPrivacyState: FeltPrivacyState.reducer(state.feltPrivacyState, action), + fakespotState: state.fakespotState) + case FakespotAction.toggleAppearance(let isEnabled): + return BrowserViewControllerState( + feltPrivacyState: state.feltPrivacyState, + fakespotState: FakespotState.reducer(state.fakespotState, action)) + default: + return state + } + } +} diff --git a/Client/Frontend/FeltPrivacy/FeltPrivacyAction.swift b/Client/Frontend/FeltPrivacy/FeltPrivacyAction.swift new file mode 100644 index 000000000000..8000600364a0 --- /dev/null +++ b/Client/Frontend/FeltPrivacy/FeltPrivacyAction.swift @@ -0,0 +1,14 @@ +// 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 Redux + +enum FeltPrivacyAction: Action { + // middleware actions + case privateModeUpdated(Bool) + + // user actions + case setPrivateModeTo(Bool) +} diff --git a/Client/Frontend/FeltPrivacy/FeltPrivacyManager.swift b/Client/Frontend/FeltPrivacy/FeltPrivacyManager.swift new file mode 100644 index 000000000000..0b9de7780497 --- /dev/null +++ b/Client/Frontend/FeltPrivacy/FeltPrivacyManager.swift @@ -0,0 +1,26 @@ +// 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 + +protocol FeltPrivacyProtocol { + func getPrivateModeState() -> Bool + func setPrivateModeState(to state: Bool) +} + +class FeltPrivacyManager { + private var isInPrivateMode: Bool + + init(isInPrivateMode: Bool) { + self.isInPrivateMode = isInPrivateMode + } + + func getPrivateModeState() -> Bool { + return isInPrivateMode + } + + func setPrivateModeState(to newState: Bool) { + isInPrivateMode = newState + } +} diff --git a/Client/Frontend/FeltPrivacy/FeltPrivacyMiddleware.swift b/Client/Frontend/FeltPrivacy/FeltPrivacyMiddleware.swift new file mode 100644 index 000000000000..e439984d7236 --- /dev/null +++ b/Client/Frontend/FeltPrivacy/FeltPrivacyMiddleware.swift @@ -0,0 +1,29 @@ +// 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 Redux + +class FeltPrivacyMiddleware { + var privacyManager: FeltPrivacyManager + + init(privacyManager: FeltPrivacyManager = FeltPrivacyManager(isInPrivateMode: false)) { + self.privacyManager = privacyManager + } + + lazy var privacyManagerProvider: Middleware = { state, action in + switch action { + case FeltPrivacyAction.setPrivateModeTo(let privateState): + self.updateManagerWith(newState: privateState) + store.dispatch(FeltPrivacyAction.privateModeUpdated(self.privacyManager.getPrivateModeState())) + default: + break + } + } + + // MARK: - Helper Functions + private func updateManagerWith(newState: Bool) { + privacyManager.setPrivateModeState(to: newState) + } +} diff --git a/Client/Frontend/FeltPrivacy/FeltPrivacyState.swift b/Client/Frontend/FeltPrivacy/FeltPrivacyState.swift new file mode 100644 index 000000000000..3448ebad735c --- /dev/null +++ b/Client/Frontend/FeltPrivacy/FeltPrivacyState.swift @@ -0,0 +1,31 @@ +// 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 Redux + +struct FeltPrivacyState: ScreenState, Equatable { + var shouldHideSearchSuggestionView: Bool + + init(_ appState: BrowserViewControllerState) { + self.init(shouldHideSearchSuggestionView: appState.feltPrivacyState.shouldHideSearchSuggestionView) + } + + init() { + self.init(shouldHideSearchSuggestionView: false) + } + + init(shouldHideSearchSuggestionView: Bool) { + self.shouldHideSearchSuggestionView = shouldHideSearchSuggestionView + } + + static let reducer: Reducer = { state, action in + switch action { + case FeltPrivacyAction.privateModeUpdated(let privacyState): + return FeltPrivacyState(shouldHideSearchSuggestionView: privacyState) + default: + return state + } + } +} diff --git a/Client/Frontend/Home/HomepageViewController.swift b/Client/Frontend/Home/HomepageViewController.swift index e1ffcf3a1510..7a34af739c4a 100644 --- a/Client/Frontend/Home/HomepageViewController.swift +++ b/Client/Frontend/Home/HomepageViewController.swift @@ -9,8 +9,12 @@ import MozillaAppServices import Common import ComponentLibrary -class HomepageViewController: UIViewController, FeatureFlaggable, Themeable, ContentContainable, - SearchBarLocationProvider { +class HomepageViewController: + UIViewController, + FeatureFlaggable, + Themeable, + ContentContainable, + SearchBarLocationProvider { // MARK: - Typealiases private typealias a11y = AccessibilityIdentifiers.FirefoxHomepage typealias SendToDeviceDelegate = InstructionsViewDelegate & DevicePickerViewControllerDelegate diff --git a/Client/Redux/GlobalState/ActiveScreenAction.swift b/Client/Redux/GlobalState/ActiveScreenAction.swift index 7cdc4deb1ca4..a8b4c0800e31 100644 --- a/Client/Redux/GlobalState/ActiveScreenAction.swift +++ b/Client/Redux/GlobalState/ActiveScreenAction.swift @@ -6,11 +6,11 @@ import Foundation import Redux enum AppScreen { + case browserViewController case themeSettings case tabsTray case tabsPanel case remoteTabsPanel - case fakespot } enum ActiveScreensStateAction: Action { diff --git a/Client/Redux/GlobalState/ActiveScreenState.swift b/Client/Redux/GlobalState/ActiveScreenState.swift index 95dc8cd62bb5..c3d10d2b873b 100644 --- a/Client/Redux/GlobalState/ActiveScreenState.swift +++ b/Client/Redux/GlobalState/ActiveScreenState.swift @@ -6,11 +6,11 @@ import Foundation import Redux enum AppScreenState: Equatable { - case themeSettings(ThemeSettingsState) - case tabsTray(TabTrayState) - case tabsPanel(TabsState) + case browserViewController(BrowserViewControllerState) case remoteTabsPanel(RemoteTabsPanelState) - case fakespot(FakespotState) + case tabsPanel(TabsState) + case tabsTray(TabTrayState) + case themeSettings(ThemeSettingsState) static let reducer: Reducer = { state, action in switch state { @@ -18,17 +18,17 @@ enum AppScreenState: Equatable { case .tabsTray(let state): return .tabsTray(TabTrayState.reducer(state, action)) case .tabsPanel(let state): return .tabsPanel(TabsState.reducer(state, action)) case .remoteTabsPanel(let state): return .remoteTabsPanel(RemoteTabsPanelState.reducer(state, action)) - case .fakespot(let state): return .fakespot(FakespotState.reducer(state, action)) + case .browserViewController(let state): return .browserViewController(BrowserViewControllerState.reducer(state, action)) } } /// Returns the matching AppScreen enum for a given AppScreenState var associatedAppScreen: AppScreen { switch self { + case .browserViewController: return .browserViewController case .themeSettings: return .themeSettings case .tabsTray: return .tabsTray case .tabsPanel: return .tabsPanel - case .fakespot: return .fakespot case .remoteTabsPanel: return .remoteTabsPanel } } @@ -52,16 +52,16 @@ struct ActiveScreensState: Equatable { switch action { case .closeScreen(let screenType): screens = screens.filter({ return $0.associatedAppScreen != screenType }) - case .showScreen(.themeSettings): - screens += [.themeSettings(ThemeSettingsState())] + case .showScreen(.browserViewController): + screens += [.browserViewController(BrowserViewControllerState())] + case .showScreen(.remoteTabsPanel): + screens += [.remoteTabsPanel(RemoteTabsPanelState())] case .showScreen(.tabsTray): screens += [.tabsTray(TabTrayState())] case .showScreen(.tabsPanel): screens += [.tabsPanel(TabsState())] - case .showScreen(.remoteTabsPanel): - screens += [.remoteTabsPanel(RemoteTabsPanelState())] - case .showScreen(.fakespot): - screens += [.fakespot(FakespotState())] + case .showScreen(.themeSettings): + screens += [.themeSettings(ThemeSettingsState())] } } diff --git a/Client/Redux/GlobalState/AppState.swift b/Client/Redux/GlobalState/AppState.swift index df405451d4e0..335e85f13204 100644 --- a/Client/Redux/GlobalState/AppState.swift +++ b/Client/Redux/GlobalState/AppState.swift @@ -20,7 +20,7 @@ struct AppState: StateType { case (.tabsTray(let state), .tabsTray): return state as? S case (.tabsPanel(let state), .tabsPanel): return state as? S case (.remoteTabsPanel(let state), .remoteTabsPanel): return state as? S - case (.fakespot(let state), .fakespot): return state as? S + case (.browserViewController(let state), .browserViewController): return state as? S default: return nil } } @@ -36,6 +36,9 @@ extension AppState { let store = Store(state: AppState(), reducer: AppState.reducer, - middlewares: [ThemeManagerMiddleware().themeManagerProvider, - TabsPanelMiddleware().tabsPanelProvider, - RemoteTabsPanelMiddleware().remoteTabsPanelProvider]) + middlewares: [ + FeltPrivacyMiddleware().privacyManagerProvider, + ThemeManagerMiddleware().themeManagerProvider, + TabsPanelMiddleware().tabsPanelProvider, + RemoteTabsPanelMiddleware().remoteTabsPanelProvider + ]) diff --git a/Client/TabManagement/TabManager.swift b/Client/TabManagement/TabManager.swift index 4416180ef714..08c38a88dd1f 100644 --- a/Client/TabManagement/TabManager.swift +++ b/Client/TabManagement/TabManager.swift @@ -69,6 +69,8 @@ extension TabManager { } func selectTab(_ tab: Tab?) { + guard let privateState = tab?.isPrivate else { return } + store.dispatch(FeltPrivacyAction.setPrivateModeTo(privateState)) selectTab(tab, previous: nil) }