1 // Copyright 2019 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.components.browser_ui.contacts_picker;
6 
7 import android.content.Context;
8 import android.text.style.StyleSpan;
9 import android.util.AttributeSet;
10 import android.view.View;
11 import android.widget.CheckBox;
12 import android.widget.CompoundButton;
13 import android.widget.RelativeLayout;
14 import android.widget.TextView;
15 
16 import org.chromium.ui.text.SpanApplier;
17 import org.chromium.ui.widget.ChipView;
18 
19 import java.text.NumberFormat;
20 
21 /**
22  * A container class for the Disclaimer and Select All functionality (and both associated labels).
23  */
24 public class TopView extends RelativeLayout
25         implements CompoundButton.OnCheckedChangeListener, View.OnClickListener {
26     /**
27      * An interface for communicating when the Select All checkbox is toggled.
28      */
29     public interface SelectAllToggleCallback {
30         /**
31          * Called when the Select All checkbox is toggled.
32          * @param allSelected Whether the Select All checkbox is checked.
33          */
onSelectAllToggled(boolean allSelected)34         void onSelectAllToggled(boolean allSelected);
35     }
36 
37     /**
38      * An interface for communicating when one of the chips has been toggled.
39      */
40     public interface ChipToggledCallback {
41         /**
42          * Called when a Chip is toggled.
43          * @param chip The chip type that was toggled.
44          */
onChipToggled(@ickerAdapter.FilterType int chip)45         void onChipToggled(@PickerAdapter.FilterType int chip);
46     }
47 
48     private final Context mContext;
49 
50     // The container box for the checkbox and its label and contact count.
51     private View mCheckboxContainer;
52 
53     // The Select All checkbox.
54     private CheckBox mSelectAllBox;
55 
56     // The label showing how many contacts were found.
57     private TextView mContactCount;
58 
59     // The callback to use when notifying that the Select All checkbox was toggled.
60     private SelectAllToggleCallback mSelectAllCallback;
61 
62     // A Chip for filtering out names.
63     private ChipView mNamesFilterChip;
64 
65     // A Chip for filtering out addresses.
66     private ChipView mAddressFilterChip;
67 
68     // A Chip for filtering out emails.
69     private ChipView mEmailFilterChip;
70 
71     // A Chip for filtering out telephones.
72     private ChipView mTelephonesFilterChip;
73 
74     // A Chip for filtering out telephones.
75     private ChipView mIconsFilterChip;
76 
77     // The callback to use to notify when the filter chips are toggled.
78     private ChipToggledCallback mChipToggledCallback;
79 
80     // Whether to temporarily ignore clicks on the checkbox.
81     private boolean mIgnoreCheck;
82 
TopView(Context context, AttributeSet attrs)83     public TopView(Context context, AttributeSet attrs) {
84         super(context, attrs);
85         mContext = context;
86     }
87 
88     @Override
onFinishInflate()89     protected void onFinishInflate() {
90         super.onFinishInflate();
91 
92         mCheckboxContainer = findViewById(R.id.content);
93         if (ContactsPickerFeatureList.isEnabled(
94                     ContactsPickerFeatureList.CONTACTS_PICKER_SELECT_ALL)) {
95             mCheckboxContainer.setVisibility(View.VISIBLE);
96         }
97         mSelectAllBox = findViewById(R.id.checkbox);
98         mContactCount = findViewById(R.id.checkbox_details);
99 
100         TextView title = findViewById(R.id.checkbox_title);
101         title.setText(R.string.contacts_picker_all_contacts);
102 
103         mNamesFilterChip = findViewById(R.id.names_filter);
104         TextView textView = mNamesFilterChip.getPrimaryTextView();
105         textView.setText(R.string.top_view_names_filter_label);
106         mNamesFilterChip.setSelected(true);
107         mNamesFilterChip.setOnClickListener(this);
108         mNamesFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
109 
110         mAddressFilterChip = findViewById(R.id.address_filter);
111         textView = mAddressFilterChip.getPrimaryTextView();
112         textView.setText(R.string.top_view_address_filter_label);
113         mAddressFilterChip.setSelected(true);
114         mAddressFilterChip.setOnClickListener(this);
115         mAddressFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
116 
117         mEmailFilterChip = findViewById(R.id.email_filter);
118         textView = mEmailFilterChip.getPrimaryTextView();
119         textView.setText(R.string.top_view_email_filter_label);
120         mEmailFilterChip.setSelected(true);
121         mEmailFilterChip.setOnClickListener(this);
122         mEmailFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
123 
124         mTelephonesFilterChip = findViewById(R.id.tel_filter);
125         textView = mTelephonesFilterChip.getPrimaryTextView();
126         textView.setText(R.string.top_view_telephone_filter_label);
127         mTelephonesFilterChip.setSelected(true);
128         mTelephonesFilterChip.setOnClickListener(this);
129         mTelephonesFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
130 
131         mIconsFilterChip = findViewById(R.id.icon_filter);
132         textView = mIconsFilterChip.getPrimaryTextView();
133         textView.setText(R.string.top_view_icon_filter_label);
134         mIconsFilterChip.setSelected(true);
135         mIconsFilterChip.setOnClickListener(this);
136         mIconsFilterChip.setIcon(R.drawable.ic_check_googblue_24dp, false);
137     }
138 
139     @Override
onClick(View view)140     public void onClick(View view) {
141         int id = view.getId();
142         if (id == R.id.names_filter) {
143             notifyChipToggled(PickerAdapter.FilterType.NAMES);
144         } else if (id == R.id.address_filter) {
145             notifyChipToggled(PickerAdapter.FilterType.ADDRESSES);
146         } else if (id == R.id.email_filter) {
147             notifyChipToggled(PickerAdapter.FilterType.EMAILS);
148         } else if (id == R.id.tel_filter) {
149             notifyChipToggled(PickerAdapter.FilterType.TELEPHONES);
150         } else if (id == R.id.icon_filter) {
151             notifyChipToggled(PickerAdapter.FilterType.ICONS);
152         }
153     }
154 
155     /**
156      * Sends a notification that a chip has been toggled and updates the selection state for it.
157      * @param chip The id of the chip that was toggled.
158      */
notifyChipToggled(@ickerAdapter.FilterType int chip)159     public void notifyChipToggled(@PickerAdapter.FilterType int chip) {
160         ChipView chipView;
161         int iconResId = 0;
162 
163         switch (chip) {
164             case PickerAdapter.FilterType.NAMES:
165                 chipView = mNamesFilterChip;
166                 iconResId = R.drawable.names;
167                 break;
168             case PickerAdapter.FilterType.ADDRESSES:
169                 chipView = mAddressFilterChip;
170                 iconResId = R.drawable.address;
171                 break;
172             case PickerAdapter.FilterType.EMAILS:
173                 chipView = mEmailFilterChip;
174                 iconResId = R.drawable.email;
175                 break;
176             case PickerAdapter.FilterType.TELEPHONES:
177                 chipView = mTelephonesFilterChip;
178                 iconResId = R.drawable.telephone;
179                 break;
180             case PickerAdapter.FilterType.ICONS:
181                 chipView = mIconsFilterChip;
182                 iconResId = R.drawable.face;
183                 break;
184             default:
185                 assert false;
186                 return;
187         }
188 
189         chipView.setSelected(!chipView.isSelected());
190         chipView.setIcon(
191                 chipView.isSelected() ? R.drawable.ic_check_googblue_24dp : iconResId, true);
192         mChipToggledCallback.onChipToggled(chip);
193     }
194 
195     /**
196      * Set the string explaining which site the dialog will be sharing the data with.
197      * @param origin The origin string to display.
198      */
setSiteString(String origin)199     public void setSiteString(String origin) {
200         TextView explanation = findViewById(R.id.explanation);
201         StyleSpan boldSpan = new StyleSpan(android.graphics.Typeface.BOLD);
202         explanation.setText(SpanApplier.applySpans(
203                 mContext.getString(R.string.disclaimer_sharing_contact_details, origin),
204                 new SpanApplier.SpanInfo("<b>", "</b>", boldSpan)));
205     }
206 
207     /**
208      * Register a callback to use to notify that Select All was toggled.
209      * @param callback The callback to use.
210      */
registerSelectAllCallback(SelectAllToggleCallback callback)211     public void registerSelectAllCallback(SelectAllToggleCallback callback) {
212         mSelectAllCallback = callback;
213     }
214 
215     /**
216      * Register a callback to use to notify when the filter chips are toggled.
217      */
registerChipToggledCallback(ChipToggledCallback callback)218     public void registerChipToggledCallback(ChipToggledCallback callback) {
219         mChipToggledCallback = callback;
220     }
221 
222     /**
223      * Updates the visibility of the Select All checkbox.
224      * @param visible Whether the checkbox should be visible.
225      */
updateCheckboxVisibility(boolean visible)226     public void updateCheckboxVisibility(boolean visible) {
227         if (visible) {
228             mSelectAllBox.setOnCheckedChangeListener(this);
229         } else {
230             mCheckboxContainer.setVisibility(GONE);
231         }
232     }
233 
234     /**
235      * Updates which chips should be displayed as part of the top view.
236      * @param shouldDisplayNames Whether the names chip should be displayed.
237      * @param shouldDisplayAddresses Whether the addresses chip should be displayed.
238      * @param shouldDisplayEmails Whether the emails chip should be displayed.
239      * @param shouldDisplayTel Whether the telephone chip should be displayed.
240      */
updateChipVisibility(boolean shouldDisplayNames, boolean shouldDisplayAddresses, boolean shouldDisplayEmails, boolean shouldDisplayTel, boolean shouldDisplayIcons)241     public void updateChipVisibility(boolean shouldDisplayNames, boolean shouldDisplayAddresses,
242             boolean shouldDisplayEmails, boolean shouldDisplayTel, boolean shouldDisplayIcons) {
243         mNamesFilterChip.setVisibility(shouldDisplayNames ? View.VISIBLE : View.GONE);
244         mAddressFilterChip.setVisibility(shouldDisplayAddresses ? View.VISIBLE : View.GONE);
245         mEmailFilterChip.setVisibility(shouldDisplayEmails ? View.VISIBLE : View.GONE);
246         mTelephonesFilterChip.setVisibility(shouldDisplayTel ? View.VISIBLE : View.GONE);
247         mIconsFilterChip.setVisibility(shouldDisplayIcons ? View.VISIBLE : View.GONE);
248     }
249 
250     /**
251      * Updates the total number of contacts found in the dialog.
252      * @param count The number of contacts found.
253      */
updateContactCount(int count)254     public void updateContactCount(int count) {
255         mContactCount.setText(NumberFormat.getInstance().format(count));
256     }
257 
258     /**
259      * Toggles the Select All checkbox.
260      */
toggle()261     public void toggle() {
262         if (ContactsPickerFeatureList.isEnabled(
263                     ContactsPickerFeatureList.CONTACTS_PICKER_SELECT_ALL)) {
264             mSelectAllBox.setChecked(!mSelectAllBox.isChecked());
265         }
266     }
267 
268     /**
269      * Returns how many filter chips are checked.
270      */
filterChipsChecked()271     public int filterChipsChecked() {
272         int checked = 0;
273         if (mNamesFilterChip.getVisibility() == View.VISIBLE && mNamesFilterChip.isSelected()) {
274             ++checked;
275         }
276         if (mAddressFilterChip.getVisibility() == View.VISIBLE && mAddressFilterChip.isSelected()) {
277             ++checked;
278         }
279         if (mEmailFilterChip.getVisibility() == View.VISIBLE && mEmailFilterChip.isSelected()) {
280             ++checked;
281         }
282         if (mTelephonesFilterChip.getVisibility() == View.VISIBLE
283                 && mTelephonesFilterChip.isSelected()) {
284             ++checked;
285         }
286         if (mIconsFilterChip.getVisibility() == View.VISIBLE && mIconsFilterChip.isSelected()) {
287             ++checked;
288         }
289         return checked;
290     }
291 
292     /**
293      * Updates the state of the checkbox to reflect whether everything is selected.
294      * @param allSelected
295      */
updateSelectAllCheckbox(boolean allSelected)296     public void updateSelectAllCheckbox(boolean allSelected) {
297         mIgnoreCheck = true;
298         mSelectAllBox.setChecked(allSelected);
299         mIgnoreCheck = false;
300     }
301 
302     @Override
onCheckedChanged(CompoundButton compoundButton, boolean b)303     public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
304         if (!mIgnoreCheck) mSelectAllCallback.onSelectAllToggled(mSelectAllBox.isChecked());
305     }
306 }
307