chromium/chrome/browser/ui/android/plus_addresses/java/src/org/chromium/chrome/browser/ui/plus_addresses/PlusAddressCreationMediator.java

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.ui.plus_addresses;

import org.chromium.chrome.browser.layouts.LayoutStateProvider;
import org.chromium.chrome.browser.layouts.LayoutStateProvider.LayoutStateObserver;
import org.chromium.chrome.browser.layouts.LayoutType;
import org.chromium.chrome.browser.tab.Tab;
import org.chromium.chrome.browser.tab.TabLaunchType;
import org.chromium.chrome.browser.tabmodel.TabModel;
import org.chromium.chrome.browser.tabmodel.TabModelObserver;
import org.chromium.chrome.browser.tabmodel.TabModelSelector;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController.StateChangeReason;
import org.chromium.components.browser_ui.bottomsheet.EmptyBottomSheetObserver;
import org.chromium.content_public.browser.LoadUrlParams;
import org.chromium.url.GURL;

/**
 * Mediator class for the plus address creation UI.
 *
 * <p>This component shows a bottom sheet to let the user create a plus address.
 *
 * <p>This mediator manages the lifecycle of the bottom sheet by observing layout and tab changes.
 * When the layout is no longer on browsing (for example the tab switcher) the bottom sheet is
 * hidden. When the selected tab changes the bottom sheet is hidden.
 *
 * <p>This mediator sends UI events (OnUiShown, OnUiAccepted, etc.) to the bridge.
 */
/*package*/ class PlusAddressCreationMediator extends EmptyBottomSheetObserver
        implements PlusAddressCreationDelegate, TabModelObserver, LayoutStateObserver {
    private final PlusAddressCreationBottomSheetContent mBottomSheetContent;
    private final BottomSheetController mBottomSheetController;
    private final LayoutStateProvider mLayoutStateProvider;
    private final TabModelSelector mTabModelSelector;
    private final TabModel mTabModel;
    private final PlusAddressCreationViewBridge mBridge;

    /**
     * Creates the mediator.
     *
     * @param bottomSheetContent The bottom sheet content to be shown.
     * @param bottomSheetController The controller to use for showing or hiding the content.
     * @param layoutStateProvider The LayoutStateProvider used to detect when the bottom sheet needs
     *     to be hidden after a change of layout (e.g. to the tab switcher).
     * @param tabModel The TabModel used to detect when the bottom sheet needs to be hidden after a
     *     tab change.
     * @param tabModelSelector The TabModelSelector for tabModel
     * @param bridge The bridge to signal UI flow events (onConfirmed, onCanceled, etc.) to.
     */
    PlusAddressCreationMediator(
            PlusAddressCreationBottomSheetContent bottomSheetContent,
            BottomSheetController bottomSheetController,
            LayoutStateProvider layoutStateProvider,
            TabModel tabModel,
            TabModelSelector tabModelSelector,
            PlusAddressCreationViewBridge bridge) {
        mBottomSheetContent = bottomSheetContent;
        mBottomSheetController = bottomSheetController;
        mLayoutStateProvider = layoutStateProvider;
        mTabModel = tabModel;
        mTabModelSelector = tabModelSelector;
        mBridge = bridge;

        mBottomSheetContent.setDelegate(this);
        mBottomSheetController.addObserver(this);
        mLayoutStateProvider.addObserver(this);
        mTabModel.addObserver(this);
    }

    /** Requests to show the bottom sheet content. */
    void requestShowContent() {
        mBottomSheetController.requestShowContent(mBottomSheetContent, /* animate= */ true);
    }

    void updateProposedPlusAddress(String plusAddress) {
        mBottomSheetContent.setProposedPlusAddress(plusAddress);
    }

    void showError() {
        mBottomSheetContent.showError();
    }

    void hideRefreshButton() {
        mBottomSheetContent.hideRefreshButton();
    }

    /** Hide the bottom sheet (if showing) and clean up observers. */
    void destroy() {
        mBottomSheetController.hideContent(mBottomSheetContent, /* animate= */ false);
        mBottomSheetController.removeObserver(this);
        mLayoutStateProvider.removeObserver(this);
        mTabModel.removeObserver(this);
    }

    // PlusAddressCreationDelegate implementation:
    @Override
    public void onRefreshClicked() {
        mBridge.onRefreshClicked();
    }

    @Override
    public void onConfirmRequested() {
        mBridge.onConfirmRequested();
    }

    @Override
    public void onCanceled() {
        mBridge.onCanceled();
    }

    @Override
    public void onConfirmFinished() {
        mBottomSheetController.hideContent(
                mBottomSheetContent, /* animate= */ true, StateChangeReason.INTERACTION_COMPLETE);
    }

    @Override
    public void onPromptDismissed() {
        mBridge.onPromptDismissed();
    }

    @Override
    public void openUrl(GURL url) {
        mTabModelSelector.openNewTab(
                new LoadUrlParams(url.getSpec()),
                TabLaunchType.FROM_LINK,
                mTabModelSelector.getCurrentTab(),
                /* incognito= */ false);
    }

    // EmptyBottomSheetObserver overridden methods follow:
    @Override
    public void onSheetClosed(@StateChangeReason int reason) {
        // Swipe to dismiss should record cancel metrics.
        if (reason == StateChangeReason.SWIPE) {
            mBridge.onCanceled();
        }
        this.onPromptDismissed();
    }

    // TabModelObserver
    @Override
    public void didSelectTab(Tab tab, int type, int lastId) {
        // While the bottom sheet scrim covers the omnibox UI, a new tab can be created in other
        // ways such as by opening a link from another app. In this case we want to hide the bottom
        // sheet rather than keeping the bottom sheet open while this tab loads behind the scrim.
        if (lastId != tab.getId()) {
            mBottomSheetController.hideContent(mBottomSheetContent, /* animate= */ false);
        }
    }

    // LayoutStateObserver
    @Override
    public void onStartedShowing(@LayoutType int layoutType) {
        // When the browser layout changes away from browsing to say the tab switcher, then the
        // bottom sheet must be hidden.
        if (layoutType != LayoutType.BROWSING) {
            mBottomSheetController.hideContent(mBottomSheetContent, /* animate= */ true);
        }
    }
}