From 551c2820653279520606bb76ec3d68de2721f784 Mon Sep 17 00:00:00 2001 From: Alexandru Farcasanu Date: Thu, 19 Sep 2024 16:05:40 +0300 Subject: [PATCH] =?UTF-8?q?FXIOS-10023=20#21995=20=E2=81=83=20Create=20hea?= =?UTF-8?q?der=20for=20Detail=20View=20on=20top=20of=20menu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BrowserKit/Package.swift | 2 +- .../Headers/NavigationHeaderView.swift | 55 ++++++++++++------- .../Sources/MenuKit/MenuDetailView.swift | 9 ++- .../MenuKit/MenuSubmenuHeaderView.swift | 54 ------------------ firefox-ios/Client.xcodeproj/project.pbxproj | 4 -- .../MainMenuConfigurationUtility.swift | 6 +- .../MainMenu/MainMenuCoordinator.swift | 13 +++-- .../MainMenu/Redux/MainMenuAction.swift | 2 +- .../Views/MainMenuDetailViewController.swift | 13 ++++- ...ckingProtectionDetailsViewController.swift | 4 +- 10 files changed, 67 insertions(+), 95 deletions(-) rename firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionNavigationHeaderView.swift => BrowserKit/Sources/ComponentLibrary/Headers/NavigationHeaderView.swift (68%) delete mode 100644 BrowserKit/Sources/MenuKit/MenuSubmenuHeaderView.swift diff --git a/BrowserKit/Package.swift b/BrowserKit/Package.swift index 1d7e82c667f8..51a003729fba 100644 --- a/BrowserKit/Package.swift +++ b/BrowserKit/Package.swift @@ -123,7 +123,7 @@ let package = Package( dependencies: ["ToolbarKit"]), .target( name: "MenuKit", - dependencies: ["Common"], + dependencies: ["Common", "ComponentLibrary"], swiftSettings: [.unsafeFlags(["-enable-testing"])]), .testTarget( name: "MenuKitTests", diff --git a/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionNavigationHeaderView.swift b/BrowserKit/Sources/ComponentLibrary/Headers/NavigationHeaderView.swift similarity index 68% rename from firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionNavigationHeaderView.swift rename to BrowserKit/Sources/ComponentLibrary/Headers/NavigationHeaderView.swift index a6abf07e307a..ccb063ebda23 100644 --- a/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionNavigationHeaderView.swift +++ b/BrowserKit/Sources/ComponentLibrary/Headers/NavigationHeaderView.swift @@ -2,17 +2,21 @@ // 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 UIKit import Common -import Shared -import ComponentLibrary -class TrackingProtectionNavigationHeaderView: UIView { +public protocol NavigationHeaderViewActionsHandler: AnyObject { + func backToMainView() + func dismissMenu() +} + +public final class NavigationHeaderView: UIView { private struct UX { static let closeButtonSize: CGFloat = 30 static let imageMargins: CGFloat = 10 static let baseDistance: CGFloat = 20 + static let horizontalMargin: CGFloat = 16 + static let separatorHeight: CGFloat = 1 } let siteTitleLabel: UILabel = .build { label in @@ -23,22 +27,23 @@ class TrackingProtectionNavigationHeaderView: UIView { label.accessibilityTraits.insert(.header) } - private var closeButton: CloseButton = .build { button in + private lazy var closeButton: CloseButton = .build { button in button.layer.cornerRadius = 0.5 * UX.closeButtonSize + button.addTarget(self, action: #selector(self.dismissMenuTapped), for: .touchUpInside) } - var backButton: UIButton = .build { button in - button.layer.cornerRadius = 0.5 * UX.closeButtonSize - button.clipsToBounds = true - button.setTitle(.KeyboardShortcuts.Back, for: .normal) + private lazy var backButton: UIButton = .build { button in button.setImage(UIImage(imageLiteralResourceName: StandardImageIdentifiers.Large.chevronLeft) .withRenderingMode(.alwaysTemplate), for: .normal) - button.titleLabel?.font = FXFontStyles.Regular.headline.scaledFont() + button.titleLabel?.font = FXFontStyles.Regular.body.scaledFont() + button.addTarget(self, action: #selector(self.backButtonTapped), for: .touchUpInside) } private let horizontalLine: UIView = .build { _ in } + public weak var navigationDelegate: NavigationHeaderViewActionsHandler? + override init(frame: CGRect) { super.init(frame: frame) setupView() @@ -60,8 +65,8 @@ class TrackingProtectionNavigationHeaderView: UIView { backButton.centerYAnchor.constraint(equalTo: centerYAnchor), siteTitleLabel.centerYAnchor.constraint(equalTo: centerYAnchor), - siteTitleLabel.leadingAnchor.constraint(equalTo: backButton.trailingAnchor), - siteTitleLabel.trailingAnchor.constraint(equalTo: closeButton.leadingAnchor), + siteTitleLabel.leadingAnchor.constraint(equalTo: leadingAnchor), + siteTitleLabel.trailingAnchor.constraint(equalTo: trailingAnchor), siteTitleLabel.topAnchor.constraint( equalTo: topAnchor, constant: UX.baseDistance @@ -73,30 +78,38 @@ class TrackingProtectionNavigationHeaderView: UIView { closeButton.trailingAnchor.constraint( equalTo: trailingAnchor, - constant: -TPMenuUX.UX.horizontalMargin - ), - closeButton.topAnchor.constraint( - equalTo: self.topAnchor, - constant: TPMenuUX.UX.horizontalMargin + constant: -UX.horizontalMargin ), closeButton.heightAnchor.constraint(greaterThanOrEqualToConstant: UX.closeButtonSize), closeButton.widthAnchor.constraint(greaterThanOrEqualToConstant: UX.closeButtonSize), + closeButton.centerYAnchor.constraint(equalTo: centerYAnchor), horizontalLine.leadingAnchor.constraint(equalTo: leadingAnchor), horizontalLine.trailingAnchor.constraint(equalTo: trailingAnchor), horizontalLine.bottomAnchor.constraint(equalTo: bottomAnchor), - horizontalLine.heightAnchor.constraint(equalToConstant: TPMenuUX.UX.Line.height) + horizontalLine.heightAnchor.constraint(equalToConstant: UX.separatorHeight) ]) } - func setTitle(with text: String) { - siteTitleLabel.text = text + public func setViews(with title: String, and backButtonText: String) { + siteTitleLabel.text = title + backButton.setTitle(backButtonText, for: .normal) + } + + @objc + private func backButtonTapped() { + navigationDelegate?.backToMainView() + } + + @objc + private func dismissMenuTapped() { + navigationDelegate?.dismissMenu() } // MARK: ThemeApplicable public func applyTheme(theme: Theme) { let buttonImage = UIImage(named: StandardImageIdentifiers.Medium.cross)? - .tinted(withColor: theme.colors.iconSecondary) + .withTintColor(theme.colors.iconSecondary) closeButton.setImage(buttonImage, for: .normal) closeButton.backgroundColor = theme.colors.layer2 backButton.tintColor = theme.colors.iconAction diff --git a/BrowserKit/Sources/MenuKit/MenuDetailView.swift b/BrowserKit/Sources/MenuKit/MenuDetailView.swift index 20537e5756c9..00d69d194ce7 100644 --- a/BrowserKit/Sources/MenuKit/MenuDetailView.swift +++ b/BrowserKit/Sources/MenuKit/MenuDetailView.swift @@ -4,6 +4,7 @@ import Common import UIKit +import ComponentLibrary public final class MenuDetailView: UIView, MenuTableViewDataDelegate, ThemeApplicable { @@ -13,7 +14,7 @@ public final class MenuDetailView: UIView, // MARK: - UI Elements private var tableView: MenuTableView = .build() - private var detailHeaderView: MenuSubmenuHeaderView = .build() + private var detailHeaderView: NavigationHeaderView = .build() // MARK: - Initializers override init(frame: CGRect) { @@ -48,10 +49,14 @@ public final class MenuDetailView: UIView, tableView.reloadTableView(with: data) } - public func setupHeaderNavigation(from delegate: MainMenuDetailNavigationHandler) { + public func setupHeaderNavigation(from delegate: NavigationHeaderViewActionsHandler) { detailHeaderView.navigationDelegate = delegate } + public func setViews(with title: String, and backButtonText: String) { + detailHeaderView.setViews(with: title, and: backButtonText) + } + // MARK: - Theme Applicable public func applyTheme(theme: Theme) { backgroundColor = .clear diff --git a/BrowserKit/Sources/MenuKit/MenuSubmenuHeaderView.swift b/BrowserKit/Sources/MenuKit/MenuSubmenuHeaderView.swift deleted file mode 100644 index 370b28177d6f..000000000000 --- a/BrowserKit/Sources/MenuKit/MenuSubmenuHeaderView.swift +++ /dev/null @@ -1,54 +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 Common -import Foundation -import UIKit - -public protocol MainMenuDetailNavigationHandler: AnyObject { - func backToMainView() -} - -final class MenuSubmenuHeaderView: UIView, ThemeApplicable { - // MARK: - UI Elements - private lazy var backButton: UIButton = .build { button in - button.addTarget(self, action: #selector(self.backButtonTapped), for: .touchUpInside) - } - - // MARK: - Properties - weak var navigationDelegate: MainMenuDetailNavigationHandler? - - // MARK: - Initializers - override init(frame: CGRect) { - super.init(frame: frame) - setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - UI Setup - private func setupView() { - addSubviews(backButton) - - NSLayoutConstraint.activate([ - backButton.centerYAnchor.constraint(equalTo: centerYAnchor), - backButton.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 10), - backButton.heightAnchor.constraint(equalToConstant: 35), - backButton.widthAnchor.constraint(equalToConstant: 60), - ]) - } - - @objc - private func backButtonTapped() { - navigationDelegate?.backToMainView() - } - - // MARK: Theme Applicable - func applyTheme(theme: Theme) { - backgroundColor = theme.colors.layer3 - backButton.tintColor = theme.colors.textAccent - } -} diff --git a/firefox-ios/Client.xcodeproj/project.pbxproj b/firefox-ios/Client.xcodeproj/project.pbxproj index 9759eae062ce..50dab666b06a 100644 --- a/firefox-ios/Client.xcodeproj/project.pbxproj +++ b/firefox-ios/Client.xcodeproj/project.pbxproj @@ -25,7 +25,6 @@ 0A93C8AC2C870E7100BEA143 /* TrackingProtectionToggleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A93C8AB2C870E7100BEA143 /* TrackingProtectionToggleView.swift */; }; 0AC659272BF35854005C614A /* FxAWebViewModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC659262BF35854005C614A /* FxAWebViewModelTests.swift */; }; 0AC659292BF493CE005C614A /* MockFxAWebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AC659282BF493CE005C614A /* MockFxAWebViewModel.swift */; }; - 0ACBC3472C89E90300B4D868 /* TrackingProtectionNavigationHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0ACBC3462C89E90200B4D868 /* TrackingProtectionNavigationHeaderView.swift */; }; 0AD3EEAC2C2485A7001044E5 /* ThemedCenteredTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AD3EEAB2C2485A7001044E5 /* ThemedCenteredTableViewCell.swift */; }; 0AFF7F642C7784D600265214 /* MockDataCleaner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF7F632C7784D600265214 /* MockDataCleaner.swift */; }; 0AFF7F662C7784F100265214 /* TrackingProtectionModelTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AFF7F652C7784F000265214 /* TrackingProtectionModelTests.swift */; }; @@ -2202,7 +2201,6 @@ 0A93C8AB2C870E7100BEA143 /* TrackingProtectionToggleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackingProtectionToggleView.swift; sourceTree = ""; }; 0AC659262BF35854005C614A /* FxAWebViewModelTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FxAWebViewModelTests.swift; sourceTree = ""; }; 0AC659282BF493CE005C614A /* MockFxAWebViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockFxAWebViewModel.swift; sourceTree = ""; }; - 0ACBC3462C89E90200B4D868 /* TrackingProtectionNavigationHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackingProtectionNavigationHeaderView.swift; sourceTree = ""; }; 0AD3EEAB2C2485A7001044E5 /* ThemedCenteredTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemedCenteredTableViewCell.swift; sourceTree = ""; }; 0AE9462E8A8E05CE07D4973D /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/InfoPlist.strings; sourceTree = ""; }; 0AFF7F632C7784D600265214 /* MockDataCleaner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockDataCleaner.swift; sourceTree = ""; }; @@ -11385,7 +11383,6 @@ 0A76936A2C82018700103A6D /* TrackingProtectionBlockedTrackersView.swift */, 0A93C8A92C87070300BEA143 /* TrackingProtectionConnectionStatusView.swift */, 0A93C8AB2C870E7100BEA143 /* TrackingProtectionToggleView.swift */, - 0ACBC3462C89E90200B4D868 /* TrackingProtectionNavigationHeaderView.swift */, ); path = TrackingProtection; sourceTree = ""; @@ -15160,7 +15157,6 @@ 8ADC2A102A33758E00543DAA /* FxALaunchParams.swift in Sources */, D3C3696E1CC6B78800348A61 /* LocalRequestHelper.swift in Sources */, E17496382991A2720096900A /* AdaptiveStack.swift in Sources */, - 0ACBC3472C89E90300B4D868 /* TrackingProtectionNavigationHeaderView.swift in Sources */, E4B423DD1ABA0318007E66C8 /* ReaderModeHandlers.swift in Sources */, E177989C2BD7D48500F6F0EB /* ToolbarAction.swift in Sources */, F8A0B08229AD61FA0091C75B /* RustSyncManager.swift in Sources */, diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift index 041576ba7473..cb4ed5dc4c1b 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift @@ -130,7 +130,8 @@ struct MainMenuConfigurationUtility: Equatable { MainMenuAction( windowUUID: uuid, actionType: MainMenuActionType.show( - .detailsView(with: getToolsSubmenu(with: uuid)) + .detailsView(with: getToolsSubmenu(with: uuid), + title: .MainMenu.ToolsSection.Tools) ) ) ) @@ -149,7 +150,8 @@ struct MainMenuConfigurationUtility: Equatable { MainMenuAction( windowUUID: uuid, actionType: MainMenuActionType.show( - .detailsView(with: getSaveSubmenu(with: uuid)) + .detailsView(with: getSaveSubmenu(with: uuid), + title: .MainMenu.ToolsSection.Save) ) ) ) diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift index 2ae3c7ed4f77..f04646458186 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift @@ -33,9 +33,9 @@ class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable { ) } - func showDetailViewController(with submenu: [MenuSection]) { + func showDetailViewController(with submenu: [MenuSection], title: String) { router.push( - createMainMenuDetailViewController(with: submenu), + createMainMenuDetailViewController(with: submenu, title: title), animated: true ) } @@ -50,8 +50,8 @@ class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable { } func navigateTo(_ destination: MainMenuNavigationDestination, animated: Bool) { - if case let .detailsView(with: submenu) = destination { - self.showDetailViewController(with: submenu) + if case let .detailsView(with: submenu, title: title) = destination { + self.showDetailViewController(with: submenu, title: title) } else { router.dismiss(animated: animated, completion: { [weak self] in guard let self else { return } @@ -94,10 +94,11 @@ class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable { return mainMenuViewController } - private func createMainMenuDetailViewController(with submenu: [MenuSection]) -> MainMenuDetailViewController { + private func createMainMenuDetailViewController(with submenu: [MenuSection], title: String) -> MainMenuDetailViewController { let detailVC = MainMenuDetailViewController( windowUUID: windowUUID, - with: submenu + with: submenu, + title: title ) detailVC.coordinator = self return detailVC diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuAction.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuAction.swift index 1b371fa7138f..21fd82002362 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuAction.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuAction.swift @@ -26,7 +26,7 @@ enum MainMenuActionType: ActionType { enum MainMenuNavigationDestination: Equatable { case bookmarks case customizeHomepage - case detailsView(with: [MenuSection]) + case detailsView(with: [MenuSection], title: String) case downloads case findInPage case goToURL(URL?) diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailViewController.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailViewController.swift index bf8fadc088c9..fcf2e451e6c5 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailViewController.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailViewController.swift @@ -6,9 +6,10 @@ import Foundation import MenuKit import Common import UIKit +import ComponentLibrary class MainMenuDetailViewController: UIViewController, - MainMenuDetailNavigationHandler, + NavigationHeaderViewActionsHandler, MenuTableViewDataDelegate, Notifiable { // MARK: - UI/UX elements @@ -23,11 +24,13 @@ class MainMenuDetailViewController: UIViewController, var currentWindowUUID: UUID? { return windowUUID } var submenuData: [MenuSection] + var submenuTitle: String // MARK: - Initializers init( windowUUID: WindowUUID, with data: [MenuSection], + title: String, notificationCenter: NotificationProtocol = NotificationCenter.default, themeManager: ThemeManager = AppContainer.shared.resolve() ) { @@ -35,6 +38,7 @@ class MainMenuDetailViewController: UIViewController, self.notificationCenter = notificationCenter self.themeManager = themeManager self.submenuData = data + self.submenuTitle = title super.init(nibName: nil, bundle: nil) setupNotifications(forObserver: self, @@ -52,6 +56,7 @@ class MainMenuDetailViewController: UIViewController, setupView() setupTableView() submenuContent.setupHeaderNavigation(from: self) + submenuContent.setViews(with: submenuTitle, and: .KeyboardShortcuts.Back) } override func viewWillAppear(_ animated: Bool) { @@ -86,11 +91,15 @@ class MainMenuDetailViewController: UIViewController, submenuContent.reloadTableView(with: data) } - // MARK: - MainMenuDetailNavigationHandler + // MARK: - NavigationHeaderViewActionsHandler func backToMainView() { coordinator?.dismissDetailViewController() } + func dismissMenu() { + coordinator?.dismissMenuModal(animated: true) + } + // MARK: - Notifications func handleNotifications(_ notification: Notification) { } } diff --git a/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionDetailsViewController.swift b/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionDetailsViewController.swift index 7d698b5f4c0c..081b9eb525d6 100644 --- a/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionDetailsViewController.swift +++ b/firefox-ios/Client/Frontend/TrackingProtection/TrackingProtectionDetailsViewController.swift @@ -37,7 +37,7 @@ class TrackingProtectionDetailsViewController: UIViewController, Themeable { stackView.distribution = .fillProportionally } - private let headerView: TrackingProtectionNavigationHeaderView = .build { header in + private let headerView: NavigationHeaderView = .build { header in header.accessibilityIdentifier = AccessibilityIdentifiers.EnhancedTrackingProtection.DetailsScreen.headerView } private let connectionView: TrackingProtectionStatusView = .build { view in @@ -206,7 +206,7 @@ class TrackingProtectionDetailsViewController: UIViewController, Themeable { } private func updateViewDetails() { - headerView.setTitle(with: model.topLevelDomain) + headerView.setViews(with: model.topLevelDomain, and: .KeyboardShortcuts.Back) connectionView.connectionStatusLabel.text = model.connectionStatusMessage if let certificate, let issuer = "\(certificate.issuer)".getDictionary()[CertificateKeys.commonName] {