Skip to content

Commit

Permalink
Add FXIOS-10318 [Menu] Populate account header with data & redux (#22718
Browse files Browse the repository at this point in the history
)

* FXIOS-10318 #22599 ⁃ Populate account header with data & redux

* Update firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuState.swift

Co-authored-by: roux g. buciu <[email protected]>

* Update firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuState.swift

Co-authored-by: roux g. buciu <[email protected]>

* Set body font for title, by default

* Added missing cases for MainMenuActionType enum

* Fixed two MainMenuActionType cases

* Refactored logic to fetch and display account header data
Change the top margin for the menu headers

---------

Co-authored-by: roux g. buciu <[email protected]>
Co-authored-by: roux g. buciu <[email protected]>
  • Loading branch information
3 people authored Oct 28, 2024
1 parent 470f521 commit c83e7f2
Show file tree
Hide file tree
Showing 11 changed files with 210 additions and 17 deletions.
35 changes: 32 additions & 3 deletions BrowserKit/Sources/ComponentLibrary/Headers/HeaderView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public final class HeaderView: UIView, ThemeApplicable {
static let headerLabelDistance: CGFloat = 2
static let separatorHeight: CGFloat = 1
static let closeButtonSize: CGFloat = 30
static let warningIconSize: CGFloat = 24
}

public var closeButtonCallback: (() -> Void)?
Expand All @@ -36,6 +37,7 @@ public final class HeaderView: UIView, ThemeApplicable {
}

private let titleLabel: UILabel = .build { label in
label.font = FXFontStyles.Regular.body.scaledFont()
label.numberOfLines = UX.headerLinesLimit
label.adjustsFontForContentSizeCategory = true
}
Expand All @@ -46,6 +48,8 @@ public final class HeaderView: UIView, ThemeApplicable {
label.adjustsFontForContentSizeCategory = true
}

private lazy var warningIconView: UIImageView = .build()

private lazy var closeButton: CloseButton = .build { button in
button.addTarget(self, action: #selector(self.closeButtonTapped), for: .touchUpInside)
}
Expand Down Expand Up @@ -75,13 +79,15 @@ public final class HeaderView: UIView, ThemeApplicable {
private func setupViews() {
headerLabelsContainer.addArrangedSubview(titleLabel)
headerLabelsContainer.addArrangedSubview(subtitleLabel)
addSubviews(mainButton, iconMask, favicon, headerLabelsContainer, closeButton, horizontalLine)
addSubviews(iconMask, favicon, headerLabelsContainer, mainButton, closeButton, warningIconView, horizontalLine)
warningIconView.isHidden = true
}

private func updateLayout(isAccessibilityCategory: Bool, isWebsiteIcon: Bool) {
removeConstraints(constraints)
favicon.removeConstraints(favicon.constraints)
closeButton.removeConstraints(closeButton.constraints)
warningIconView.removeConstraints(warningIconView.constraints)
iconMask.removeConstraints(iconMask.constraints)
viewConstraints.removeAll()
viewConstraints.append(contentsOf: [
Expand All @@ -103,10 +109,11 @@ public final class HeaderView: UIView, ThemeApplicable {
constant: UX.siteDomainLabelsVerticalSpacing
),
headerLabelsContainer.trailingAnchor.constraint(
equalTo: closeButton.leadingAnchor,
equalTo: warningIconView.leadingAnchor,
constant: -UX.horizontalMargin
),

warningIconView.trailingAnchor.constraint(equalTo: closeButton.leadingAnchor, constant: -UX.horizontalMargin),
closeButton.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -UX.horizontalMargin),

horizontalLine.leadingAnchor.constraint(equalTo: leadingAnchor),
Expand All @@ -132,6 +139,10 @@ public final class HeaderView: UIView, ThemeApplicable {
viewConstraints.append(closeButton.widthAnchor.constraint(equalToConstant: closeButtonSizes))
closeButton.layer.cornerRadius = 0.5 * closeButtonSizes

let warningIconSizes = isAccessibilityCategory ? UX.largeFaviconImageSize : UX.warningIconSize
viewConstraints.append(warningIconView.heightAnchor.constraint(equalToConstant: warningIconSizes))
viewConstraints.append(warningIconView.widthAnchor.constraint(equalToConstant: warningIconSizes))

let maskButtonSizes = isAccessibilityCategory ? UX.largeFaviconImageSize : UX.maskFaviconImageSize
viewConstraints.append(iconMask.heightAnchor.constraint(equalToConstant: maskButtonSizes))
viewConstraints.append(iconMask.widthAnchor.constraint(equalToConstant: maskButtonSizes))
Expand All @@ -140,9 +151,11 @@ public final class HeaderView: UIView, ThemeApplicable {
if isAccessibilityCategory {
viewConstraints.append(favicon.topAnchor.constraint(equalTo: headerLabelsContainer.topAnchor))
viewConstraints.append(closeButton.topAnchor.constraint(equalTo: headerLabelsContainer.topAnchor))
viewConstraints.append(warningIconView.topAnchor.constraint(equalTo: headerLabelsContainer.topAnchor))
} else {
viewConstraints.append(favicon.centerYAnchor.constraint(equalTo: centerYAnchor))
viewConstraints.append(closeButton.centerYAnchor.constraint(equalTo: centerYAnchor))
viewConstraints.append(warningIconView.centerYAnchor.constraint(equalTo: centerYAnchor))
}
NSLayoutConstraint.activate(viewConstraints)
}
Expand Down Expand Up @@ -172,12 +185,28 @@ public final class HeaderView: UIView, ThemeApplicable {
}

public func setupDetails(subtitle: String, title: String, icon: UIImage?) {
titleLabel.font = FXFontStyles.Regular.body.scaledFont()
if let icon { favicon.manuallySetImage(icon) }
subtitleLabel.text = subtitle
titleLabel.text = title
}

public func setupDetails(subtitle: String, title: String, icon: UIImage?, warningIcon: String?, theme: Theme) {
titleLabel.text = title
subtitleLabel.text = subtitle
subtitleLabel.textColor = theme.colors.textCritical
if let icon {
favicon.manuallySetImage(icon)
let isAccessibilityCategory = UIApplication.shared.preferredContentSizeCategory.isAccessibilityCategory
let maskButtonSizes = isAccessibilityCategory ? UX.largeFaviconImageSize : UX.smallFaviconImageSize
favicon.layer.cornerRadius = 0.5 * maskButtonSizes
}
if let warningIcon {
warningIconView.tintColor = theme.colors.iconCritical
warningIconView.isHidden = false
warningIconView.image = UIImage(named: warningIcon)?.withRenderingMode(.alwaysTemplate)
}
}

public func setIconTheme(with theme: Theme) {
iconMask.backgroundColor = theme.colors.layer2
favicon.tintColor = theme.colors.iconSecondary
Expand Down
3 changes: 2 additions & 1 deletion BrowserKit/Sources/MenuKit/MenuDetailView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public final class MenuDetailView: UIView,
MenuTableViewDataDelegate, ThemeApplicable {
private struct UX {
static let headerLineOffset: CGFloat = 35
static let headerTopMargin: CGFloat = 10
}

// MARK: - UI Elements
Expand All @@ -34,7 +35,7 @@ public final class MenuDetailView: UIView,
addSubview(tableView)

NSLayoutConstraint.activate([
detailHeaderView.topAnchor.constraint(equalTo: self.topAnchor),
detailHeaderView.topAnchor.constraint(equalTo: self.topAnchor, constant: UX.headerTopMargin),
detailHeaderView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
detailHeaderView.trailingAnchor.constraint(equalTo: self.trailingAnchor),

Expand Down
6 changes: 5 additions & 1 deletion BrowserKit/Sources/MenuKit/MenuMainView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import ComponentLibrary

public final class MenuMainView: UIView,
MenuTableViewDataDelegate, ThemeApplicable {
private struct UX {
static let headerTopMargin: CGFloat = 10
}

// MARK: - UI Elements
private var tableView: MenuTableView = .build()
public var accountHeaderView: HeaderView = .build()
Expand All @@ -32,7 +36,7 @@ public final class MenuMainView: UIView,
self.addSubview(tableView)

NSLayoutConstraint.activate([
accountHeaderView.topAnchor.constraint(equalTo: self.topAnchor),
accountHeaderView.topAnchor.constraint(equalTo: self.topAnchor, constant: UX.headerTopMargin),
accountHeaderView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
accountHeaderView.trailingAnchor.constraint(equalTo: self.trailingAnchor),

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,13 @@ class BrowserCoordinator: BaseCoordinator,
return navigationController
}

func showSignInView(fxaParameters: FxASignInViewParameters?) {
guard let fxaParameters else { return }
browserViewController.presentSignInViewController(fxaParameters.launchParameters,
flowType: fxaParameters.flowType,
referringPage: fxaParameters.referringPage)
}

// MARK: - SearchEngineSelectionCoordinatorDelegate

func showSearchEngineSelection(forSourceView sourceView: UIView) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ protocol MainMenuCoordinatorDelegate: AnyObject {
func showLibraryPanel(_ panel: Route.HomepanelSection)
func showSettings(at destination: Route.SettingsSection)
func showFindInPage()
func showSignInView(fxaParameters: FxASignInViewParameters?)
func updateZoomPageBarVisibility()
func showShareSheet(with url: URL?)
}
Expand Down Expand Up @@ -81,6 +82,13 @@ class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable {
self.navigationHandler?.showSettings(at: .password)
case .settings:
self.navigationHandler?.showSettings(at: .general)
case .syncSignIn:
let fxaParameters = FxASignInViewParameters(
launchParameters: FxALaunchParams(entrypoint: .browserMenu, query: [:]),
flowType: .emailLoginFlow,
referringPage: .appMenu
)
self.navigationHandler?.showSignInView(fxaParameters: fxaParameters)
case .shareSheet:
self.navigationHandler?.showShareSheet(with: destination.url)
case .zoom:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,25 @@ final class MainMenuAction: Action {
var navigationDestination: MenuNavigationDestination?
var currentTabInfo: MainMenuTabInfo?
var detailsViewToShow: MainMenuDetailsViewType?
var accountData: AccountData?
var accountIcon: UIImage?

init(
windowUUID: WindowUUID,
actionType: any ActionType,
navigationDestination: MenuNavigationDestination? = nil,
changeMenuViewTo: MainMenuDetailsViewType? = nil,
currentTabInfo: MainMenuTabInfo? = nil,
tabID: TabUUID? = nil
tabID: TabUUID? = nil,
accountData: AccountData? = nil,
accountIcon: UIImage? = nil
) {
self.navigationDestination = navigationDestination
self.detailsViewToShow = changeMenuViewTo
self.currentTabInfo = currentTabInfo
self.tabID = tabID
self.accountData = accountData
self.accountIcon = accountIcon
super.init(windowUUID: windowUUID, actionType: actionType)
}
}
Expand All @@ -40,6 +46,7 @@ enum MainMenuActionType: ActionType {

enum MainMenuMiddlewareActionType: ActionType {
case requestTabInfo
case updateAccountHeader
}

enum MainMenuDetailsActionType: ActionType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import Common
import Redux
import ToolbarKit
import Account

final class MainMenuMiddleware {
private let logger: Logger
Expand All @@ -21,6 +22,22 @@ final class MainMenuMiddleware {
case MainMenuActionType.tapCloseMenu:
self.telemetry.mainMenuDismissed()
case MainMenuActionType.viewDidLoad:
if let accountData = self.getAccountData() {
if let iconURL = accountData.iconURL {
GeneralizedImageFetcher().getImageFor(url: iconURL) { [weak self] image in
guard let self else { return }
self.dispatchUpdateAccountHeader(
accountData: accountData,
action: action,
icon: image)
}
} else {
self.dispatchUpdateAccountHeader(
accountData: accountData,
action: action,
icon: nil)
}
}
store.dispatch(
MainMenuAction(
windowUUID: action.windowUUID,
Expand All @@ -31,4 +48,43 @@ final class MainMenuMiddleware {
break
}
}

private func dispatchUpdateAccountHeader(accountData: AccountData?,
action: MainMenuAction,
icon: UIImage?) {
store.dispatch(
MainMenuAction(
windowUUID: action.windowUUID,
actionType: MainMenuMiddlewareActionType.updateAccountHeader,
accountData: accountData,
accountIcon: icon
)
)
}

private func getAccountData() -> AccountData? {
let rustAccount = RustFirefoxAccounts.shared
let needsReAuth = rustAccount.accountNeedsReauth()

guard let userProfile = rustAccount.userProfile else { return nil }

let title: String = {
if needsReAuth { return .MainMenu.Account.SyncErrorTitle }
return userProfile.displayName ?? userProfile.email
}()

let subtitle: String? = needsReAuth ? .MainMenu.Account.SyncErrorDescription : nil
let warningIcon: String? = needsReAuth ? StandardImageIdentifiers.Large.warningFill : nil

var iconURL: URL?
if let str = rustAccount.userProfile?.avatarUrl,
let url = URL(string: str, invalidCharacters: false) {
iconURL = url
}

return AccountData(title: title,
subtitle: subtitle,
warningIcon: warningIcon,
iconURL: iconURL)
}
}
Loading

0 comments on commit c83e7f2

Please sign in to comment.