diff --git a/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift b/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift index 9f4a5a4537eed..290c1aa072a8b 100644 --- a/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift +++ b/firefox-ios/Client/Coordinators/Browser/BrowserCoordinator.swift @@ -493,6 +493,10 @@ class BrowserCoordinator: BaseCoordinator, } } + func editLatestBookmark() { + browserViewController.openBookmarkEditPanel() + } + func showFindInPage() { browserViewController.showFindInPage() } diff --git a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift index 1e7a93e941beb..07bd30b8dcf42 100644 --- a/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift +++ b/firefox-ios/Client/Frontend/Browser/BrowserViewController/Views/BrowserViewController.swift @@ -667,19 +667,32 @@ class BrowserViewController: UIViewController, } private func showToastType(toast: ToastType) { - let viewModel = ButtonToastViewModel( - labelText: toast.title, - buttonText: toast.buttonText) - let uuid = windowUUID - let toast = ButtonToast(viewModel: viewModel, - theme: currentTheme(), - completion: { buttonPressed in - if let action = toast.reduxAction(for: uuid), buttonPressed { - store.dispatch(action) - } - }) + switch toast { + case .addShortcut, + .addToReadingList, + .removeShortcut, + .removeFromReadingList, + .addBookmark: + SimpleToast().showAlertWithText( + toast.title, + bottomContainer: contentContainer, + theme: currentTheme() + ) + default: + let viewModel = ButtonToastViewModel( + labelText: toast.title, + buttonText: toast.buttonText) + let uuid = windowUUID + let toast = ButtonToast(viewModel: viewModel, + theme: currentTheme(), + completion: { buttonPressed in + if let action = toast.reduxAction(for: uuid), buttonPressed { + store.dispatch(action) + } + }) - show(toast: toast) + show(toast: toast) + } } private func handleMicrosurvey(state: BrowserViewControllerState) { diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift index 37ad5c95ca9ea..d9068dc4829ba 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuConfigurationUtility.swift @@ -15,7 +15,7 @@ struct MainMenuConfigurationUtility: Equatable { static let findInPage = StandardImageIdentifiers.Large.search static let tools = StandardImageIdentifiers.Large.tool static let save = StandardImageIdentifiers.Large.save - static let bookmarks = StandardImageIdentifiers.Large.bookmarkTrayFill + static let bookmarks = StandardImageIdentifiers.Large.bookmark static let history = StandardImageIdentifiers.Large.history static let downloads = StandardImageIdentifiers.Large.download static let passwords = StandardImageIdentifiers.Large.login @@ -32,6 +32,7 @@ struct MainMenuConfigurationUtility: Equatable { static let saveToReadingList = StandardImageIdentifiers.Large.readingListAdd static let removeFromReadingList = StandardImageIdentifiers.Large.readingListSlashFill static let bookmarkThisPage = StandardImageIdentifiers.Large.bookmark + static let editThisBookmark = StandardImageIdentifiers.Large.bookmarkFill static let reportBrokenSite = StandardImageIdentifiers.Large.lightbulb static let customizeHomepage = StandardImageIdentifiers.Large.gridAdd static let saveAsPDF = StandardImageIdentifiers.Large.folder @@ -367,12 +368,13 @@ struct MainMenuConfigurationUtility: Equatable { typealias A11y = SaveMenu.AccessibilityLabels let title = tabInfo.isBookmarked ? SaveMenu.EditBookmark : SaveMenu.BookmarkThisPage + let icon = tabInfo.isBookmarked ? Icons.editThisBookmark : Icons.bookmarkThisPage let a11yLabel = tabInfo.isBookmarked ? A11y.EditBookmark : A11y.BookmarkThisPage let actionType: MainMenuDetailsActionType = tabInfo.isBookmarked ? .editBookmark : .addToBookmarks return MenuElement( title: title, - iconName: Icons.bookmarkThisPage, + iconName: icon, isEnabled: true, isActive: tabInfo.isBookmarked, a11yLabel: a11yLabel, diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift index 442bcbfc814c1..b012a0c0502b5 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/MainMenuCoordinator.swift @@ -13,6 +13,7 @@ protocol MainMenuCoordinatorDelegate: AnyObject { func showLibraryPanel(_ panel: Route.HomepanelSection) func showSettings(at destination: Route.SettingsSection) func showFindInPage() + func editLatestBookmark() } class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable { @@ -62,6 +63,8 @@ class MainMenuCoordinator: BaseCoordinator, FeatureFlaggable { self.navigationHandler?.showSettings(at: .homePage) case .downloads: self.navigationHandler?.showLibraryPanel(.downloads) + case .editBookmark: + self.navigationHandler?.editLatestBookmark() case .findInPage: self.navigationHandler?.showFindInPage() case .goToURL: diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuDetailState.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuDetailState.swift index 3668c96a6e96e..dc0d943d113dd 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuDetailState.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MainMenuDetailState.swift @@ -12,7 +12,7 @@ struct MainMenuDetailsState: ScreenState, Equatable { var menuElements: [MenuSection] var shouldDismiss: Bool var shouldGoBackToMainMenu: Bool - var navigationDestination: MainMenuNavigationDestination? + var navigationDestination: MenuNavigationDestination? var submenuType: MainMenuDetailsViewType? var title: String { @@ -57,7 +57,7 @@ struct MainMenuDetailsState: ScreenState, Equatable { windowUUID: WindowUUID, menuElements: [MenuSection], submenuType: MainMenuDetailsViewType?, - navigationDestination: MainMenuNavigationDestination? = nil, + navigationDestination: MenuNavigationDestination? = nil, shouldDismiss: Bool = false, shouldGoBackToMenu: Bool = false ) { @@ -108,7 +108,6 @@ struct MainMenuDetailsState: ScreenState, Equatable { ) case MainMenuDetailsActionType.dismissView, MainMenuDetailsActionType.addToBookmarks, - MainMenuDetailsActionType.editBookmark, MainMenuDetailsActionType.addToShortcuts, MainMenuDetailsActionType.removeFromShortcuts, MainMenuDetailsActionType.addToReadingList, @@ -119,6 +118,13 @@ struct MainMenuDetailsState: ScreenState, Equatable { submenuType: state.submenuType, shouldDismiss: true ) + case MainMenuDetailsActionType.editBookmark: + return MainMenuDetailsState( + windowUUID: state.windowUUID, + menuElements: state.menuElements, + submenuType: state.submenuType, + navigationDestination: MenuNavigationDestination(.editBookmark) + ) default: return MainMenuDetailsState( windowUUID: state.windowUUID, diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MenuNavigationDestination.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MenuNavigationDestination.swift index 2e21a762d95aa..dbc85ef8f1011 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MenuNavigationDestination.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/Redux/MenuNavigationDestination.swift @@ -8,6 +8,7 @@ enum MainMenuNavigationDestination: Equatable, CaseIterable { case bookmarks case customizeHomepage case downloads + case editBookmark case findInPage case goToURL case history diff --git a/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailsViewController.swift b/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailsViewController.swift index 95293668cd602..322532354ffcf 100644 --- a/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailsViewController.swift +++ b/firefox-ios/Client/Frontend/Browser/MainMenu/Views/MainMenuDetailsViewController.swift @@ -167,6 +167,11 @@ class MainMenuDetailsViewController: UIViewController, func newState(state: MainMenuDetailsState) { submenuState = state + if let destination = submenuState.navigationDestination { + coordinator?.navigateTo(destination, animated: true) + return + } + if submenuState.shouldGoBackToMainMenu { coordinator?.dismissDetailViewController() return diff --git a/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift b/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift index c1fc364e87dfe..3544f7cccfa60 100644 --- a/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift +++ b/firefox-ios/Client/Frontend/Browser/Tabs/Middleware/TabManagerMiddleware.swift @@ -43,12 +43,9 @@ class TabManagerMiddleware { didLoadTabPeek(tabID: tabUUID, uuid: action.windowUUID) case TabPeekActionType.addToBookmarks: - addToBookmarks(with: tabUUID, uuid: action.windowUUID) - TelemetryWrapper.recordEvent(category: .action, - method: .add, - object: .bookmark, - value: .tabTray) - + let shareItem = createShareItem(with: tabUUID, and: action.windowUUID) + addToBookmarks(shareItem) + setBookmarkQuickActions(with: shareItem, uuid: action.windowUUID) case TabPeekActionType.copyURL: copyURL(tabID: tabUUID, uuid: action.windowUUID) @@ -365,6 +362,29 @@ class TabManagerMiddleware { } } + private func setBookmarkQuickActions(with shareItem: ShareItem?, uuid: WindowUUID) { + guard let shareItem else { return } + + var userData = [QuickActionInfos.tabURLKey: shareItem.url] + if let title = shareItem.title { + userData[QuickActionInfos.tabTitleKey] = title + } + + QuickActionsImplementation().addDynamicApplicationShortcutItemOfType(.openLastBookmark, + withUserData: userData, + toApplication: .shared) + + let toastAction = TabPanelMiddlewareAction(toastType: .addBookmark, + windowUUID: uuid, + actionType: TabPanelMiddlewareActionType.showToast) + store.dispatch(toastAction) + + TelemetryWrapper.recordEvent(category: .action, + method: .add, + object: .bookmark, + value: .tabTray) + } + /// Trigger refreshTabs action after a change in `TabManager` @MainActor private func triggerRefresh(shouldScrollToTab: Bool, uuid: WindowUUID, isPrivate: Bool) { @@ -627,7 +647,16 @@ class TabManagerMiddleware { provideTabInfo(forWindow: action.windowUUID) case MainMenuDetailsActionType.addToBookmarks: guard let tabID = action.tabID else { return } - addToBookmarks(with: tabID, uuid: action.windowUUID) + let shareItem = createShareItem(with: tabID, and: action.windowUUID) + addToBookmarks(shareItem) + + store.dispatch( + GeneralBrowserAction( + toastType: .addBookmark, + windowUUID: action.windowUUID, + actionType: GeneralBrowserActionType.showToast + ) + ) case MainMenuDetailsActionType.addToReadingList: addToReadingList(with: action.tabID, uuid: action.windowUUID) case MainMenuDetailsActionType.removeFromReadingList: @@ -793,35 +822,26 @@ class TabManagerMiddleware { } // MARK: - Tab Manager Helper functions - private func addToBookmarks(with tabID: TabUUID, uuid: WindowUUID) { + private func createShareItem(with tabID: TabUUID, and uuid: WindowUUID) -> ShareItem? { let tabManager = tabManager(for: uuid) guard let tab = tabManager.getTabForUUID(uuid: tabID), let url = tab.url?.absoluteString, !url.isEmpty - else { return } + else { return nil } var title = (tab.tabState.title ?? "").trimmingCharacters(in: .whitespacesAndNewlines) if title.isEmpty { title = url } - let shareItem = ShareItem(url: url, title: title) + return ShareItem(url: url, title: title) + } + + private func addToBookmarks(_ shareItem: ShareItem?) { + guard let shareItem else { return } // Add new mobile bookmark at the top of the list profile.places.createBookmark(parentGUID: BookmarkRoots.MobileFolderGUID, url: shareItem.url, title: shareItem.title, position: 0) - - var userData = [QuickActionInfos.tabURLKey: shareItem.url] - if let title = shareItem.title { - userData[QuickActionInfos.tabTitleKey] = title - } - QuickActionsImplementation().addDynamicApplicationShortcutItemOfType(.openLastBookmark, - withUserData: userData, - toApplication: .shared) - - let toastAction = TabPanelMiddlewareAction(toastType: .addBookmark, - windowUUID: uuid, - actionType: TabPanelMiddlewareActionType.showToast) - store.dispatch(toastAction) } private func addToReadingList(with tabID: TabUUID?, uuid: WindowUUID) {