chromium/chrome/android/java/src/org/chromium/chrome/browser/bookmarks/BookmarkFolderPickerCoordinator.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.bookmarks;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import org.chromium.base.supplier.ObservableSupplier;
import org.chromium.base.supplier.ObservableSupplierImpl;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.bookmarks.BookmarkListEntry.ViewType;
import org.chromium.chrome.browser.bookmarks.BookmarkUiPrefs.BookmarkRowDisplayPref;
import org.chromium.components.bookmarks.BookmarkId;
import org.chromium.components.browser_ui.widget.FadingShadow;
import org.chromium.components.browser_ui.widget.FadingShadowView;
import org.chromium.components.browser_ui.widget.gesture.BackPressHandler;
import org.chromium.components.commerce.core.ShoppingService;
import org.chromium.ui.modelutil.MVCListAdapter.ModelList;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.chromium.ui.modelutil.SimpleRecyclerViewAdapter;

import java.util.List;

/** Coordinates the views/mediators that make up the bookmark folder picker. */
public class BookmarkFolderPickerCoordinator implements BackPressHandler {
    private final ObservableSupplierImpl<Boolean> mBackPressStateSupplier =
            new ObservableSupplierImpl<>();
    private final ModelList mModelList = new ModelList();
    private final Context mContext;
    private final BookmarkModel mBookmarkModel;
    private final View mView;
    private final View mMoveButton;
    private final RecyclerView mRecyclerView;
    private final BookmarkFolderPickerMediator mMediator;
    private final BookmarkUiPrefs mBookmarkUiPrefs;

    private final SimpleRecyclerViewAdapter mAdapter = new SimpleRecyclerViewAdapter(mModelList);

    public BookmarkFolderPickerCoordinator(
            Context context,
            BookmarkModel bookmarkModel,
            List<BookmarkId> bookmarkIds,
            Runnable finishRunnable,
            BookmarkAddNewFolderCoordinator addNewFolderCoordinator,
            BookmarkUiPrefs bookmarkUiPrefs,
            ImprovedBookmarkRowCoordinator improvedBookmarkRowCoordinator,
            ShoppingService shoppingService) {
        mContext = context;
        mBookmarkModel = bookmarkModel;
        mView = LayoutInflater.from(mContext).inflate(R.layout.bookmark_folder_picker, null);
        mMoveButton = mView.findViewById(R.id.move_button);

        mRecyclerView = mView.findViewById(R.id.folder_recycler_view);
        mRecyclerView.setLayoutManager(
                new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));
        mRecyclerView.setAdapter(mAdapter);
        mAdapter.registerType(
                ViewType.IMPROVED_BOOKMARK_VISUAL,
                BookmarkManagerCoordinator::buildVisualImprovedBookmarkRow,
                ImprovedBookmarkRowViewBinder::bind);
        mAdapter.registerType(
                ViewType.IMPROVED_BOOKMARK_COMPACT,
                BookmarkManagerCoordinator::buildCompactImprovedBookmarkRow,
                ImprovedBookmarkRowViewBinder::bind);
        mAdapter.registerType(
                ViewType.SECTION_HEADER,
                this::buildSectionHeaderView,
                BookmarkManagerViewBinder::bindSectionHeaderView);

        PropertyModel model = new PropertyModel(BookmarkFolderPickerProperties.ALL_KEYS);
        PropertyModelChangeProcessor.create(model, mView, BookmarkFolderPickerViewBinder::bind);

        mMediator =
                new BookmarkFolderPickerMediator(
                        context,
                        bookmarkModel,
                        bookmarkIds,
                        finishRunnable,
                        bookmarkUiPrefs,
                        model,
                        mModelList,
                        addNewFolderCoordinator,
                        improvedBookmarkRowCoordinator,
                        shoppingService);

        FadingShadowView shadow = mView.findViewById(R.id.shadow);
        shadow.init(mContext.getColor(R.color.toolbar_shadow_color), FadingShadow.POSITION_TOP);
        mRecyclerView.setOnScrollListener(
                new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                        super.onScrollStateChanged(recyclerView, newState);
                    }

                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        shadow.setVisibility(
                                mRecyclerView.canScrollVertically(-1) ? View.VISIBLE : View.GONE);
                    }
                });

        // Back presses are always handled.
        mBackPressStateSupplier.set(true);

        mBookmarkUiPrefs = bookmarkUiPrefs;
    }

    /** Destroys the coordinator. */
    public void destroy() {
        mMediator.destroy();
    }

    /** Returns the view for display. */
    public View getView() {
        return mView;
    }

    /** Returns the {@link Toolbar} for the folder picker. */
    public Toolbar getToolbar() {
        return mView.findViewById(R.id.toolbar);
    }

    public void updateToolbarButtons() {
        mMediator.updateToolbarButtons();
    }

    // Delegate setup methods.

    /** Handle option menu selections. */
    public boolean optionsItemSelected(MenuItem item) {
        return mMediator.optionsItemSelected(item.getItemId());
    }

    public boolean onBackPressed() {
        return mMediator.onBackPressed();
    }

    // Building rows for the recycler view.

    View buildFolderRow(ViewGroup parent) {
        ImprovedBookmarkRow row =
                ImprovedBookmarkRow.buildView(
                        parent.getContext(),
                        mBookmarkUiPrefs.getBookmarkRowDisplayPref()
                                == BookmarkRowDisplayPref.VISUAL);
        return row;
    }

    View buildSectionHeaderView(ViewGroup parent) {
        int layoutId =
                mBookmarkModel.areAccountBookmarkFoldersActive()
                        ? R.layout.bookmark_section_header_v2
                        : R.layout.bookmark_section_header;
        return LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    }

    // BackPressHandler implementation.

    @Override
    public @BackPressResult int handleBackPress() {
        return onBackPressed() ? BackPressResult.SUCCESS : BackPressResult.FAILURE;
    }

    @Override
    public ObservableSupplier<Boolean> getHandleBackPressChangedSupplier() {
        return mBackPressStateSupplier;
    }

    // Testing methods.

    void openFolderForTesting(BookmarkId folder) {
        mMediator.populateFoldersForParentId(folder);
    }
}