Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add FXIOS-10164 [Homepage] Navigation for Pocket Section #22597

Merged
merged 4 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions firefox-ios/Client.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,8 @@
8A8BAE122B2107E400D774EB /* GCDWebServers in Frameworks */ = {isa = PBXBuildFile; productRef = 8A8BAE112B2107E400D774EB /* GCDWebServers */; };
8A8BAE142B21110000D774EB /* GCDWebServers in Frameworks */ = {isa = PBXBuildFile; productRef = 8A8BAE132B21110000D774EB /* GCDWebServers */; };
8A8BAE162B2119E600D774EB /* InternalURL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8BAE152B2119E600D774EB /* InternalURL.swift */; };
8A8D277B2CBFFD710076AD3A /* BrowserNavigationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8D277A2CBFFD710076AD3A /* BrowserNavigationType.swift */; };
8A8D277D2CC000BE0076AD3A /* NavigationBrowserAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8D277C2CC000BE0076AD3A /* NavigationBrowserAction.swift */; };
8A8DDEBF276259A900E7B97A /* RatingPromptManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A8DDEBE276259A900E7B97A /* RatingPromptManager.swift */; };
8A93080927BFE88F0052167D /* PhotonActionSheetContainerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A93080827BFE88F0052167D /* PhotonActionSheetContainerCell.swift */; };
8A93080B27C01AD60052167D /* SingleActionViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A93080A27C01AD60052167D /* SingleActionViewModel.swift */; };
Expand Down Expand Up @@ -7141,6 +7143,8 @@
8A880C432C63CFE200B77F23 /* MockLoginViewModelDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLoginViewModelDelegate.swift; sourceTree = "<group>"; };
8A8917682B57283B008B01EA /* LegacyHomepageHeaderCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyHomepageHeaderCell.swift; sourceTree = "<group>"; };
8A8BAE152B2119E600D774EB /* InternalURL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InternalURL.swift; sourceTree = "<group>"; };
8A8D277A2CBFFD710076AD3A /* BrowserNavigationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BrowserNavigationType.swift; sourceTree = "<group>"; };
8A8D277C2CC000BE0076AD3A /* NavigationBrowserAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBrowserAction.swift; sourceTree = "<group>"; };
8A8DDEBE276259A900E7B97A /* RatingPromptManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingPromptManager.swift; sourceTree = "<group>"; };
8A93080827BFE88F0052167D /* PhotonActionSheetContainerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotonActionSheetContainerCell.swift; sourceTree = "<group>"; };
8A93080A27C01AD60052167D /* SingleActionViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleActionViewModel.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -10495,6 +10499,7 @@
children = (
5A2918CA2B522338002B197E /* GeneralBrowserAction.swift */,
7ADC1D182C27D35B003ED924 /* ActionProviderBuilder.swift */,
8A8D277C2CC000BE0076AD3A /* NavigationBrowserAction.swift */,
);
path = Actions;
sourceTree = "<group>";
Expand Down Expand Up @@ -10738,6 +10743,7 @@
81CAE4DA2B1A2C220040C78A /* BrowserViewControllerState.swift */,
81122E202B221AC0003DD9F8 /* SearchScreenState.swift */,
5A1947142B8FA9E0009C7A6C /* BrowserViewType.swift */,
8A8D277A2CBFFD710076AD3A /* BrowserNavigationType.swift */,
);
path = State;
sourceTree = "<group>";
Expand Down Expand Up @@ -15690,6 +15696,7 @@
1DFE57FF27BAE3150025DE58 /* HomepageSectionType.swift in Sources */,
C2D1A10D2A66C70000205DCC /* BookmarksCoordinator.swift in Sources */,
8C46E1B72B2209F000F56521 /* FakespotAdsEvent.swift in Sources */,
8A8D277D2CC000BE0076AD3A /* NavigationBrowserAction.swift in Sources */,
396E38F11EE0C8EC00CC180F /* FxAPushMessageHandler.swift in Sources */,
8A76B01629F6EB3900A82607 /* ScreenshotService.swift in Sources */,
8C1953322B85EAB500761B20 /* AutofillHeaderView.swift in Sources */,
Expand Down Expand Up @@ -15900,6 +15907,7 @@
43D00493296FC48F00CB0F31 /* CreditCardSettingsEmptyView.swift in Sources */,
CEFA977E1FAA6B490016F365 /* SyncContentSettingsViewController.swift in Sources */,
C8CD80DC2A1E8C970097C3AE /* OnboardingTelemetryUtility.swift in Sources */,
8A8D277B2CBFFD710076AD3A /* BrowserNavigationType.swift in Sources */,
96C11E9B2864C2DD00840E7C /* DependencyHelper.swift in Sources */,
8CE1E4382B8C76C80026530B /* LoginListViewModel.swift in Sources */,
0B8BF3722CA2DA4600E9812D /* EditBookmarkViewController.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ class BrowserCoordinator: BaseCoordinator,
LibraryCoordinatorDelegate,
EnhancedTrackingProtectionCoordinatorDelegate,
FakespotCoordinatorDelegate,
HomepageCoordinatorDelegate,
ParentCoordinatorDelegate,
TabManagerDelegate,
TabTrayCoordinatorDelegate,
Expand Down Expand Up @@ -137,7 +136,6 @@ class BrowserCoordinator: BaseCoordinator,

func showHomepage() {
let homepageController = self.homepageViewController ?? HomepageViewController(windowUUID: windowUUID)
homepageController.parentCoordinator = self
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for a coordinator for homepage since the navigation is done on browser view level and there are no navigation currently that is specific to homepage only.

guard browserViewController.embedContent(homepageController) else {
logger.log("Unable to embed new homepage", level: .debug, category: .coordinator)
return
Expand All @@ -155,8 +153,11 @@ class BrowserCoordinator: BaseCoordinator,
self.privateViewController = privateHomepageController
}

// MARK: - PrivateHomepageDelegate
func navigateFromHomePanel(to url: URL, visitType: VisitType, isGoogleTopSite: Bool) {
browserViewController.homePanel(didSelectURL: url, visitType: visitType, isGoogleTopSite: isGoogleTopSite)
}

// MARK: - PrivateHomepageDelegate
func homePanelDidRequestToOpenInNewTab(with url: URL, isPrivate: Bool, selectNewTab: Bool) {
browserViewController.homePanelDidRequestToOpenInNewTab(
url,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import Storage
import WebKit

import struct MozillaAppServices.CreditCard
import enum MozillaAppServices.VisitType
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a fan of declaring these types from another service, I prefer to have a wrapper object. However, to minimize changing will keep the method for VisitType the same


protocol BrowserNavigationHandler: AnyObject, QRCodeNavigationHandler {
/// Asks to show a settings page, can be a general settings page or a child page
Expand Down Expand Up @@ -99,6 +100,9 @@ protocol BrowserNavigationHandler: AnyObject, QRCodeNavigationHandler {

/// Shows the toolbar's search engine selection bottom sheet (iPhone) or popup (iPad)
func showSearchEngineSelection(forSourceView sourceView: UIView)

/// Navigates from home page to a new link
func navigateFromHomePanel(to url: URL, visitType: VisitType, isGoogleTopSite: Bool)
Comment on lines +104 to +105
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is specific to homepage today because I am calling the homePanel method in the browser coordinator. It would be great to have a single navigateToLink method instead, but leaving this as of now until we revisit some logic that we are doing in BVC. Let me know if any issues!

}

extension BrowserNavigationHandler {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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 Common
import Foundation
import Redux

/// Actions that are related to navigation from the user perspective
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

user perspective for now, we can update this comment if we see that there are API actions taken that uses this

class NavigationBrowserAction: Action {
let url: URL?
init(url: URL? = nil,
windowUUID: WindowUUID,
actionType: ActionType) {
self.url = url
super.init(windowUUID: windowUUID,
actionType: actionType)
}
}

enum NavigationBrowserActionType: ActionType {
case tapOnCustomizeHomepage
case tapOnCell
case tapOnLink
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// 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

/// View types that the browser coordinator can navigate to
enum BrowserNavigationDestination: Equatable {
// Native views
case customizeHomepage

// Webpage views
case link
}

/// This type exists as a field on the BrowserViewControllerState
struct NavigationDestination: Equatable {
let destination: BrowserNavigationDestination
let url: URL?

init(
_ destination: BrowserNavigationDestination,
url: URL? = nil
) {
self.destination = destination
self.url = url
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct BrowserViewControllerState: ScreenState, Equatable {
var buttonTapped: UIButton?
var frame: WKFrameInfo?
var microsurveyState: MicrosurveyPromptState
var navigationDestination: NavigationDestination?

init(appState: AppState, uuid: WindowUUID) {
guard let bvcState = store.state.screenState(
Expand All @@ -72,7 +73,8 @@ struct BrowserViewControllerState: ScreenState, Equatable {
displayView: bvcState.displayView,
buttonTapped: bvcState.buttonTapped,
frame: bvcState.frame,
microsurveyState: bvcState.microsurveyState)
microsurveyState: bvcState.microsurveyState,
navigationDestination: bvcState.navigationDestination)
}

init(windowUUID: WindowUUID) {
Expand All @@ -87,7 +89,8 @@ struct BrowserViewControllerState: ScreenState, Equatable {
navigateTo: nil,
displayView: nil,
buttonTapped: nil,
microsurveyState: MicrosurveyPromptState(windowUUID: windowUUID))
microsurveyState: MicrosurveyPromptState(windowUUID: windowUUID),
navigationDestination: nil)
}

init(
Expand All @@ -103,7 +106,8 @@ struct BrowserViewControllerState: ScreenState, Equatable {
displayView: DisplayType? = nil,
buttonTapped: UIButton? = nil,
frame: WKFrameInfo? = nil,
microsurveyState: MicrosurveyPromptState
microsurveyState: MicrosurveyPromptState,
navigationDestination: NavigationDestination? = nil
) {
self.searchScreenState = searchScreenState
self.showDataClearanceFlow = showDataClearanceFlow
Expand All @@ -118,6 +122,7 @@ struct BrowserViewControllerState: ScreenState, Equatable {
self.buttonTapped = buttonTapped
self.frame = frame
self.microsurveyState = microsurveyState
self.navigationDestination = navigationDestination
}

static let reducer: Reducer<Self> = { state, action in
Expand All @@ -130,6 +135,8 @@ struct BrowserViewControllerState: ScreenState, Equatable {
return BrowserViewControllerState.reduceStateForMicrosurveyAction(action: action, state: state)
} else if let action = action as? GeneralBrowserAction {
return BrowserViewControllerState.reduceStateForGeneralBrowserAction(action: action, state: state)
} else if let action = action as? NavigationBrowserAction {
return BrowserViewControllerState.reduceStateForNavigationBrowserAction(action: action, state: state)
} else {
return BrowserViewControllerState(
searchScreenState: state.searchScreenState,
Expand All @@ -138,7 +145,50 @@ struct BrowserViewControllerState: ScreenState, Equatable {
windowUUID: state.windowUUID,
reloadWebView: false,
browserViewType: state.browserViewType,
microsurveyState: MicrosurveyPromptState.reducer(state.microsurveyState, action))
microsurveyState: MicrosurveyPromptState.reducer(state.microsurveyState, action),
navigationDestination: nil)
}
}

// MARK: - Navigation Browser Action
static func reduceStateForNavigationBrowserAction(
action: NavigationBrowserAction,
state: BrowserViewControllerState
) -> BrowserViewControllerState {
switch action.actionType {
case NavigationBrowserActionType.tapOnCustomizeHomepage:
return BrowserViewControllerState(
searchScreenState: state.searchScreenState,
showDataClearanceFlow: state.showDataClearanceFlow,
fakespotState: FakespotState.reducer(state.fakespotState, action),
windowUUID: state.windowUUID,
browserViewType: state.browserViewType,
microsurveyState: MicrosurveyPromptState.reducer(state.microsurveyState, action),
navigationDestination: NavigationDestination(.customizeHomepage)
)

case NavigationBrowserActionType.tapOnCell,
NavigationBrowserActionType.tapOnLink:
return BrowserViewControllerState(
searchScreenState: state.searchScreenState,
showDataClearanceFlow: state.showDataClearanceFlow,
fakespotState: FakespotState.reducer(state.fakespotState, action),
windowUUID: state.windowUUID,
browserViewType: state.browserViewType,
microsurveyState: MicrosurveyPromptState.reducer(state.microsurveyState, action),
navigationDestination: NavigationDestination(.link, url: action.url)
)

default:
return BrowserViewControllerState(
searchScreenState: state.searchScreenState,
showDataClearanceFlow: state.showDataClearanceFlow,
fakespotState: FakespotState.reducer(state.fakespotState, action),
windowUUID: state.windowUUID,
browserViewType: state.browserViewType,
microsurveyState: MicrosurveyPromptState.reducer(state.microsurveyState, action),
navigationDestination: nil
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2064,6 +2064,9 @@ class BrowserViewController: UIViewController,
handleNavigationActions(for: state)
case _ where state.displayView != nil:
handleDisplayActions(for: state)
case _ where state.navigationDestination != nil:
guard let destination = state.navigationDestination else { return }
handleNavigation(to: destination)
Comment on lines +2067 to +2069
Copy link
Contributor Author

@cyndichin cyndichin Oct 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer if statements, but left this for now to follow suite our other cases.

default: break
}
}
Expand All @@ -2079,6 +2082,20 @@ class BrowserViewController: UIViewController,
store.dispatch(action)
}

private func handleNavigation(to type: NavigationDestination) {
switch type.destination {
case .customizeHomepage:
navigationHandler?.show(settings: .homePage)
case .link:
guard let url = type.url else {
logger.log("url should not be nil when navigating for a link type", level: .warning, category: .coordinator)
return
}
// TODO: FXIOS-10165 - Pass in the proper values based on top sites and other homepage links
navigationHandler?.navigateFromHomePanel(to: url, visitType: .link, isGoogleTopSite: false)
}
}

private func handleDisplayActions(for state: BrowserViewControllerState) {
guard let displayState = state.displayView else { return }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ final class HomepageDiffableDataSource:
enum HomeItem: Hashable {
case header
case pocket(PocketStoryState)
case pocketDiscover(String)
case pocketDiscover
case customizeHomepage

static var cellTypes: [ReusableCell.Type] {
Expand All @@ -43,10 +43,7 @@ final class HomepageDiffableDataSource:

let stories: [HomeItem] = state.pocketState.pocketData.compactMap { .pocket($0) }
snapshot.appendItems(stories, toSection: .pocket)
let discoverItem = state.pocketState.pocketDiscoverTitle
if !discoverItem.isEmpty {
snapshot.appendItems([.pocketDiscover(discoverItem)], toSection: .pocket)
}
snapshot.appendItems([.pocketDiscover], toSection: .pocket)

snapshot.appendItems([], toSection: .pocket)
snapshot.appendItems([.customizeHomepage], toSection: .customizeHomepage)
Expand Down
Loading
Loading