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