chromium/components/browser_ui/contacts_picker/android/java/src/org/chromium/components/browser_ui/contacts_picker/TopView.java

// Copyright 2019 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.components.browser_ui.contacts_picker;

import android.content.Context;
import android.text.style.StyleSpan;
import android.util.AttributeSet;
import android.view.View;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.RelativeLayout;
import android.widget.TextView;

import org.chromium.components.browser_ui.widget.chips.ChipView;
import org.chromium.ui.text.SpanApplier;

import java.text.NumberFormat;

/** A container class for the Disclaimer and Select All functionality (and both associated labels). */
public class TopView extends RelativeLayout
        implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
    /** An interface for communicating when the Select All checkbox is toggled. */
    public interface SelectAllToggleCallback {
        /**
         * Called when the Select All checkbox is toggled.
         *
         * @param allSelected Whether the Select All checkbox is checked.
         */
        void onSelectAllToggled(boolean allSelected);
    }

    /** An interface for communicating when one of the chips has been toggled. */
    public interface ChipToggledCallback {
        /**
         * Called when a Chip is toggled.
         *
         * @param chip The chip type that was toggled.
         */
        void onChipToggled(@PickerAdapter.FilterType int chip);
    }

    private final Context mContext;

    // The container box for the checkbox and its label and contact count.
    private View mCheckboxContainer;

    // The Select All checkbox.
    private CheckBox mSelectAllBox;

    // The label showing how many contacts were found.
    private TextView mContactCount;

    // The callback to use when notifying that the Select All checkbox was toggled.
    private SelectAllToggleCallback mSelectAllCallback;

    // A Chip for filtering out names.
    private ChipView mNamesFilterChip;

    // A Chip for filtering out addresses.
    private ChipView mAddressFilterChip;

    // A Chip for filtering out emails.
    private ChipView mEmailFilterChip;

    // A Chip for filtering out telephones.
    private ChipView mTelephonesFilterChip;

    // A Chip for filtering out telephones.
    private ChipView mIconsFilterChip;

    // The callback to use to notify when the filter chips are toggled.
    private ChipToggledCallback mChipToggledCallback;

    // Whether to temporarily ignore clicks on the checkbox.
    private boolean mIgnoreCheck;

    public TopView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        mCheckboxContainer = findViewById(R.id.content);
        if (ContactsPickerFeatureMap.isEnabled(
                ContactsPickerFeatureList.CONTACTS_PICKER_SELECT_ALL)) {
            mCheckboxContainer.setVisibility(View.VISIBLE);
        }
        mSelectAllBox = findViewById(R.id.checkbox);
        mContactCount = findViewById(R.id.checkbox_details);

        TextView title = findViewById(R.id.checkbox_title);
        title.setText(R.string.contacts_picker_all_contacts);

        mNamesFilterChip = findViewById(R.id.names_filter);
        TextView textView = mNamesFilterChip.getPrimaryTextView();
        textView.setText(R.string.top_view_names_filter_label);
        mNamesFilterChip.setSelected(true);
        mNamesFilterChip.setOnClickListener(this);
        mNamesFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);

        mAddressFilterChip = findViewById(R.id.address_filter);
        textView = mAddressFilterChip.getPrimaryTextView();
        textView.setText(R.string.top_view_address_filter_label);
        mAddressFilterChip.setSelected(true);
        mAddressFilterChip.setOnClickListener(this);
        mAddressFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);

        mEmailFilterChip = findViewById(R.id.email_filter);
        textView = mEmailFilterChip.getPrimaryTextView();
        textView.setText(R.string.top_view_email_filter_label);
        mEmailFilterChip.setSelected(true);
        mEmailFilterChip.setOnClickListener(this);
        mEmailFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);

        mTelephonesFilterChip = findViewById(R.id.tel_filter);
        textView = mTelephonesFilterChip.getPrimaryTextView();
        textView.setText(R.string.top_view_telephone_filter_label);
        mTelephonesFilterChip.setSelected(true);
        mTelephonesFilterChip.setOnClickListener(this);
        mTelephonesFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);

        mIconsFilterChip = findViewById(R.id.icon_filter);
        textView = mIconsFilterChip.getPrimaryTextView();
        textView.setText(R.string.top_view_icon_filter_label);
        mIconsFilterChip.setSelected(true);
        mIconsFilterChip.setOnClickListener(this);
        mIconsFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.names_filter) {
            notifyChipToggled(PickerAdapter.FilterType.NAMES);
        } else if (id == R.id.address_filter) {
            notifyChipToggled(PickerAdapter.FilterType.ADDRESSES);
        } else if (id == R.id.email_filter) {
            notifyChipToggled(PickerAdapter.FilterType.EMAILS);
        } else if (id == R.id.tel_filter) {
            notifyChipToggled(PickerAdapter.FilterType.TELEPHONES);
        } else if (id == R.id.icon_filter) {
            notifyChipToggled(PickerAdapter.FilterType.ICONS);
        }
    }

    /**
     * Sends a notification that a chip has been toggled and updates the selection state for it.
     *
     * @param chip The id of the chip that was toggled.
     */
    public void notifyChipToggled(@PickerAdapter.FilterType int chip) {
        ChipView chipView;
        int iconResId = 0;

        switch (chip) {
            case PickerAdapter.FilterType.NAMES:
                chipView = mNamesFilterChip;
                iconResId = R.drawable.names;
                break;
            case PickerAdapter.FilterType.ADDRESSES:
                chipView = mAddressFilterChip;
                iconResId = R.drawable.address;
                break;
            case PickerAdapter.FilterType.EMAILS:
                chipView = mEmailFilterChip;
                iconResId = R.drawable.email;
                break;
            case PickerAdapter.FilterType.TELEPHONES:
                chipView = mTelephonesFilterChip;
                iconResId = R.drawable.telephone;
                break;
            case PickerAdapter.FilterType.ICONS:
                chipView = mIconsFilterChip;
                iconResId = R.drawable.face;
                break;
            default:
                assert false;
                return;
        }

        chipView.setSelected(!chipView.isSelected());
        chipView.setIcon(
                chipView.isSelected() ? R.drawable.ic_check_googblue_24dp : iconResId, true);
        mChipToggledCallback.onChipToggled(chip);
    }

    /**
     * Set the string explaining which site the dialog will be sharing the data with.
     *
     * @param origin The origin string to display.
     */
    public void setSiteString(String origin) {
        TextView explanation = findViewById(R.id.explanation);
        StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
        explanation.setText(
                SpanApplier.applySpans(
                        mContext.getString(R.string.disclaimer_sharing_contact_details, origin),
                        new SpanApplier.SpanInfo("<b>", "</b>", boldSpan)));
    }

    /**
     * Register a callback to use to notify that Select All was toggled.
     *
     * @param callback The callback to use.
     */
    public void registerSelectAllCallback(SelectAllToggleCallback callback) {
        mSelectAllCallback = callback;
    }

    /** Register a callback to use to notify when the filter chips are toggled. */
    public void registerChipToggledCallback(ChipToggledCallback callback) {
        mChipToggledCallback = callback;
    }

    /**
     * Updates the visibility of the Select All checkbox.
     *
     * @param visible Whether the checkbox should be visible.
     */
    public void updateCheckboxVisibility(boolean visible) {
        if (visible) {
            mSelectAllBox.setOnCheckedChangeListener(this);
        } else {
            mCheckboxContainer.setVisibility(GONE);
        }
    }

    /**
     * Updates which chips should be displayed as part of the top view.
     *
     * @param shouldDisplayNames Whether the names chip should be displayed.
     * @param shouldDisplayAddresses Whether the addresses chip should be displayed.
     * @param shouldDisplayEmails Whether the emails chip should be displayed.
     * @param shouldDisplayTel Whether the telephone chip should be displayed.
     */
    public void updateChipVisibility(
            boolean shouldDisplayNames,
            boolean shouldDisplayAddresses,
            boolean shouldDisplayEmails,
            boolean shouldDisplayTel,
            boolean shouldDisplayIcons) {
        mNamesFilterChip.setVisibility(shouldDisplayNames ? View.VISIBLE : View.GONE);
        mAddressFilterChip.setVisibility(shouldDisplayAddresses ? View.VISIBLE : View.GONE);
        mEmailFilterChip.setVisibility(shouldDisplayEmails ? View.VISIBLE : View.GONE);
        mTelephonesFilterChip.setVisibility(shouldDisplayTel ? View.VISIBLE : View.GONE);
        mIconsFilterChip.setVisibility(shouldDisplayIcons ? View.VISIBLE : View.GONE);
    }

    /**
     * Updates the total number of contacts found in the dialog.
     *
     * @param count The number of contacts found.
     */
    public void updateContactCount(int count) {
        mContactCount.setText(NumberFormat.getInstance().format(count));
    }

    /** Toggles the Select All checkbox. */
    public void toggle() {
        if (ContactsPickerFeatureMap.isEnabled(
                ContactsPickerFeatureList.CONTACTS_PICKER_SELECT_ALL)) {
            mSelectAllBox.setChecked(!mSelectAllBox.isChecked());
        }
    }

    /** Returns how many filter chips are checked. */
    public int filterChipsChecked() {
        int checked = 0;
        if (mNamesFilterChip.getVisibility() == View.VISIBLE && mNamesFilterChip.isSelected()) {
            ++checked;
        }
        if (mAddressFilterChip.getVisibility() == View.VISIBLE && mAddressFilterChip.isSelected()) {
            ++checked;
        }
        if (mEmailFilterChip.getVisibility() == View.VISIBLE && mEmailFilterChip.isSelected()) {
            ++checked;
        }
        if (mTelephonesFilterChip.getVisibility() == View.VISIBLE
                && mTelephonesFilterChip.isSelected()) {
            ++checked;
        }
        if (mIconsFilterChip.getVisibility() == View.VISIBLE && mIconsFilterChip.isSelected()) {
            ++checked;
        }
        return checked;
    }

    /**
     * Updates the state of the checkbox to reflect whether everything is selected.
     *
     * @param allSelected
     */
    public void updateSelectAllCheckbox(boolean allSelected) {
        mIgnoreCheck = true;
        mSelectAllBox.setChecked(allSelected);
        mIgnoreCheck = false;
    }

    @Override
    public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
        if (!mIgnoreCheck) mSelectAllCallback.onSelectAllToggled(mSelectAllBox.isChecked());
    }
}