chromium/chrome/browser/touch_to_fill/autofill/android/internal/java/src/org/chromium/chrome/browser/touch_to_fill/payments/TouchToFillPaymentMethodCoordinator.java

// Copyright 2022 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.touch_to_fill.payments;

import static org.chromium.chrome.browser.autofill.AutofillUiUtils.getCardIcon;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.DISMISS_HANDLER;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.CREDIT_CARD;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FILL_BUTTON;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.FOOTER;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.HEADER;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.ItemType.IBAN;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.SHEET_ITEMS;
import static org.chromium.chrome.browser.touch_to_fill.payments.TouchToFillPaymentMethodProperties.VISIBLE;

import android.content.Context;
import android.graphics.drawable.Drawable;

import androidx.annotation.VisibleForTesting;

import org.chromium.chrome.browser.autofill.AutofillUiUtils;
import org.chromium.chrome.browser.autofill.PersonalDataManager;
import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
import org.chromium.chrome.browser.autofill.PersonalDataManager.Iban;
import org.chromium.chrome.browser.touch_to_fill.common.BottomSheetFocusHelper;
import org.chromium.components.autofill.AutofillSuggestion;
import org.chromium.components.browser_ui.bottomsheet.BottomSheetController;
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;
import java.util.function.Function;

/**
 * Implements the TouchToFillPaymentMethodComponent. It uses a bottom sheet to let the user select a
 * credit card to be filled into the focused form.
 */
public class TouchToFillPaymentMethodCoordinator implements TouchToFillPaymentMethodComponent {
    private final TouchToFillPaymentMethodMediator mMediator = new TouchToFillPaymentMethodMediator();
    private PropertyModel mTouchToFillPaymentMethodModel;
    private Function<TouchToFillPaymentMethodProperties.CardImageMetaData, Drawable>
            mCardImageFunction;

    @Override
    public void initialize(
            Context context,
            PersonalDataManager personalDataManager,
            BottomSheetController sheetController,
            Delegate delegate,
            BottomSheetFocusHelper bottomSheetFocusHelper) {
                mTouchToFillPaymentMethodModel = createModel(mMediator);
        mCardImageFunction =
                (metaData) ->
                        getCardIcon(
                                context,
                                personalDataManager,
                                metaData.artUrl,
                                metaData.iconId,
                                AutofillUiUtils.CardIconSize.LARGE,
                                /* showCustomIcon= */ true);
       mMediator.initialize(
                context, delegate, mTouchToFillPaymentMethodModel, bottomSheetFocusHelper);
        setUpModelChangeProcessors(
                mTouchToFillPaymentMethodModel,
                new TouchToFillPaymentMethodView(context, sheetController));
    }

    @Override
    public void showSheet(
            List<CreditCard> cards,
            List<AutofillSuggestion> suggestions,
            boolean shouldShowScanCreditCard) {
        assert mCardImageFunction != null : "Attempting to call showSheet before initialize.";
        mMediator.showSheet(cards, suggestions, shouldShowScanCreditCard, mCardImageFunction);
    }

    @Override
    public void showSheet(List<Iban> ibans) {
        mMediator.showSheet(ibans);
    }

    @Override
    public void hideSheet() {
        mMediator.hideSheet();
    }

    /**
     * Connects the given model with the given view using Model Change Processors.
     * @param model A {@link PropertyModel} built with {@link TouchToFillPaymentMethodProperties}.
     * @param view A {@link TouchToFillPaymentMethodView}.
     */
    @VisibleForTesting
    static void setUpModelChangeProcessors(PropertyModel model, TouchToFillPaymentMethodView view) {
        PropertyModelChangeProcessor.create(
                model, view, TouchToFillPaymentMethodViewBinder::bindTouchToFillPaymentMethodView);
    }

    static void setUpCardItems(PropertyModel model, TouchToFillPaymentMethodView view) {
        SimpleRecyclerViewAdapter adapter = new SimpleRecyclerViewAdapter(model.get(SHEET_ITEMS));
        adapter.registerType(
                CREDIT_CARD,
                TouchToFillPaymentMethodViewBinder::createCardItemView,
                TouchToFillPaymentMethodViewBinder::bindCardItemView);
        adapter.registerType(
                IBAN,
                TouchToFillPaymentMethodViewBinder::createIbanItemView,
                TouchToFillPaymentMethodViewBinder::bindIbanItemView);
        adapter.registerType(
                HEADER,
                TouchToFillPaymentMethodViewBinder::createHeaderItemView,
                TouchToFillPaymentMethodViewBinder::bindHeaderView);
        adapter.registerType(
                FILL_BUTTON,
                TouchToFillPaymentMethodViewBinder::createFillButtonView,
                TouchToFillPaymentMethodViewBinder::bindFillButtonView);
        adapter.registerType(
                FOOTER,
                TouchToFillPaymentMethodViewBinder::createFooterItemView,
                TouchToFillPaymentMethodViewBinder::bindFooterView);
        view.setSheetItemListAdapter(adapter);
    }

    PropertyModel createModel(TouchToFillPaymentMethodMediator mediator) {
        return new PropertyModel.Builder(TouchToFillPaymentMethodProperties.ALL_KEYS)
                .with(VISIBLE, false)
                .with(SHEET_ITEMS, new ModelList())
                .with(DISMISS_HANDLER, mediator::onDismissed)
                .build();
    }

    PropertyModel getModelForTesting() {
        return mTouchToFillPaymentMethodModel;
    }

    TouchToFillPaymentMethodMediator getMediatorForTesting() {
        return mMediator;
    }
}