Chromium Code Reviews| Index: chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java |
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java |
| index c673af740649ccbb9b9e4a44069c9611e93b8ed2..122012f826be0cafc50d45babf977862292d50eb 100644 |
| --- a/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java |
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/ui/EditorView.java |
| @@ -24,16 +24,20 @@ import android.view.View.OnClickListener; |
| import android.view.ViewGroup; |
| import android.view.accessibility.AccessibilityEvent; |
| import android.view.inputmethod.EditorInfo; |
| +import android.widget.AdapterView; |
| +import android.widget.AdapterView.OnItemSelectedListener; |
| import android.widget.ArrayAdapter; |
| import android.widget.AutoCompleteTextView; |
| import android.widget.Button; |
| import android.widget.LinearLayout; |
| +import android.widget.Spinner; |
| import android.widget.TextView; |
| import org.chromium.base.ApiCompatibilityUtils; |
| import org.chromium.chrome.R; |
| import org.chromium.chrome.browser.EmbedContentViewActivity; |
| import org.chromium.chrome.browser.payments.ui.PaymentRequestUI.PaymentRequestObserverForTest; |
| +import org.chromium.chrome.browser.preferences.autofill.AutofillProfileBridge.SpinnerKeyValue; |
| import org.chromium.chrome.browser.widget.AlwaysDismissedDialog; |
| import org.chromium.chrome.browser.widget.DualControlLayout; |
| import org.chromium.chrome.browser.widget.FadingShadow; |
| @@ -61,14 +65,15 @@ public class EditorView extends AlwaysDismissedDialog |
| private static final String HELP_URL = "https://support.google.com/chrome/answer/142893?hl=en"; |
| /** Handles validation and display of one field from the {@link EditorFieldModel}. */ |
| - private final class EditorFieldView extends TextInputLayout { |
| + private final class TextFieldView extends TextInputLayout { |
| private final EditorFieldModel mEditorFieldModel; |
| private final AutoCompleteTextView mInput; |
| private boolean mHasFocusedAtLeastOnce; |
| - public EditorFieldView(Context context, final EditorFieldModel fieldModel) { |
| + public TextFieldView(Context context, final EditorFieldModel fieldModel) { |
| super(context); |
| mEditorFieldModel = fieldModel; |
| + assert !fieldModel.isSpinner(); |
| // Build up the label. Required fields are indicated by appending a '*'. |
| CharSequence label = fieldModel.getLabel(); |
| @@ -117,14 +122,42 @@ public class EditorView extends AlwaysDismissedDialog |
| mInput.setThreshold(0); |
| } |
| - if (fieldModel.getInputTypeHint() == EditorFieldModel.INPUT_TYPE_HINT_PHONE) { |
| - mInput.setId(R.id.payments_edit_phone_input); |
| - mInput.setInputType(InputType.TYPE_CLASS_PHONE); |
| - mInput.addTextChangedListener(getPhoneFormatter()); |
| - } else if (fieldModel.getInputTypeHint() == EditorFieldModel.INPUT_TYPE_HINT_EMAIL) { |
| - mInput.setId(R.id.payments_edit_email_input); |
| - mInput.setInputType( |
| - InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); |
| + switch (fieldModel.getInputTypeHint()) { |
| + case EditorFieldModel.INPUT_TYPE_HINT_PHONE: |
| + mInput.setInputType(InputType.TYPE_CLASS_PHONE); |
| + mInput.addTextChangedListener(getPhoneFormatter()); |
| + break; |
| + case EditorFieldModel.INPUT_TYPE_HINT_EMAIL: |
| + mInput.setInputType(InputType.TYPE_CLASS_TEXT |
| + | InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS); |
| + break; |
| + case EditorFieldModel.INPUT_TYPE_HINT_STREET_LINES: |
| + // TODO(rouslan): Provide a hint to the keyboard that the street lines are |
| + // likely to have numbers. |
| + mInput.setInputType(InputType.TYPE_CLASS_TEXT |
| + | InputType.TYPE_TEXT_FLAG_CAP_WORDS |
| + | InputType.TYPE_TEXT_FLAG_MULTI_LINE |
| + | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS); |
| + break; |
| + case EditorFieldModel.INPUT_TYPE_HINT_PERSON_NAME: |
| + mInput.setInputType(InputType.TYPE_CLASS_TEXT |
| + | InputType.TYPE_TEXT_FLAG_CAP_WORDS |
| + | InputType.TYPE_TEXT_VARIATION_PERSON_NAME); |
| + break; |
| + case EditorFieldModel.INPUT_TYPE_HINT_REGION: |
| + mInput.setInputType(InputType.TYPE_CLASS_TEXT |
| + | InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS |
| + | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS); |
| + break; |
| + case EditorFieldModel.INPUT_TYPE_HINT_ALPHA_NUMERIC: |
| + // Intentionally fall through. |
| + // TODO(rouslan): Provide a hint to the keyboard that postal code and sorting |
| + // code are likely to have numbers. |
| + default: |
| + mInput.setInputType(InputType.TYPE_CLASS_TEXT |
| + | InputType.TYPE_TEXT_FLAG_CAP_WORDS |
| + | InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS); |
| + break; |
| } |
| } |
| @@ -148,6 +181,77 @@ public class EditorView extends AlwaysDismissedDialog |
| } |
| } |
| + /** |
| + * Helper class for creating a spinner view with a label. |
| + */ |
| + private final class SpinnerView { |
| + private final EditorFieldModel mFieldModel; |
| + private final TextView mLabel; |
| + private final Spinner mSpinner; |
| + private int mSelectedIndex; |
| + |
| + /** |
| + * Builds a spinner view. |
| + * |
| + * @param context The application context to use when creating widgets. |
| + * @param fieldModel The data model of the spinner. |
| + * @param changedCallback The callback to invoke after user's spinner item selection has |
| + * been processed. |
| + */ |
| + public SpinnerView(Context context, final EditorFieldModel fieldModel, |
| + final Runnable changedCallback) { |
| + mFieldModel = fieldModel; |
| + |
| + mLabel = new TextView(context); |
| + mLabel.setText(mFieldModel.getLabel()); |
| + |
| + final List<SpinnerKeyValue> spinnerKeyValues = mFieldModel.getSpinnerKeyValues(); |
| + for (int j = 0; j < spinnerKeyValues.size(); j++) { |
| + if (spinnerKeyValues.get(j).getKey().equals(mFieldModel.getValue())) { |
| + mSelectedIndex = j; |
| + break; |
| + } |
| + } |
| + |
| + ArrayAdapter<SpinnerKeyValue> adapter = new ArrayAdapter<SpinnerKeyValue>( |
| + context, android.R.layout.simple_spinner_item, spinnerKeyValues); |
| + adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); |
| + |
| + mSpinner = new Spinner(context); |
| + mSpinner.setAdapter(adapter); |
| + mSpinner.setSelection(mSelectedIndex); |
| + mSpinner.setOnItemSelectedListener(new OnItemSelectedListener() { |
| + @Override |
| + public void onItemSelected( |
| + AdapterView<?> parent, View view, int position, long id) { |
| + if (mSelectedIndex != position) { |
| + mSelectedIndex = position; |
| + mFieldModel.setSpinnerKey( |
| + spinnerKeyValues.get(position).getKey(), changedCallback); |
| + } |
| + } |
| + |
| + @Override |
| + public void onNothingSelected(AdapterView<?> parent) {} |
| + }); |
| + } |
| + |
| + /** @return The EditorFieldModel that the SpinnerView represents. */ |
| + public EditorFieldModel getFieldModel() { |
| + return mFieldModel; |
| + } |
| + |
| + /** @return The label view for the spinner. */ |
| + public View getLabel() { |
| + return mLabel; |
| + } |
| + |
| + /** @return The spinner view itself. */ |
| + public View getSpinner() { |
| + return mSpinner; |
| + } |
| + } |
| + |
| private final Context mContext; |
| private final PaymentRequestObserverForTest mObserverForTest; |
| private final Handler mHandler; |
| @@ -251,7 +355,7 @@ public class EditorView extends AlwaysDismissedDialog |
| * @return Whether all fields contain valid information. |
| */ |
| private boolean validateForm() { |
| - final List<EditorFieldView> invalidViews = getViewsWithInvalidInformation(); |
| + final List<TextFieldView> invalidViews = getViewsWithInvalidInformation(); |
| if (invalidViews.isEmpty()) return true; |
| // Focus the first field that's invalid. |
| @@ -261,8 +365,8 @@ public class EditorView extends AlwaysDismissedDialog |
| // to clear existing errors on any newly valid fields. |
| ViewGroup dataView = (ViewGroup) mLayout.findViewById(R.id.contents); |
| for (int i = 0; i < dataView.getChildCount(); i++) { |
| - if (!(dataView.getChildAt(i) instanceof EditorFieldView)) continue; |
| - EditorFieldView fieldView = (EditorFieldView) dataView.getChildAt(i); |
| + if (!(dataView.getChildAt(i) instanceof TextFieldView)) continue; |
| + TextFieldView fieldView = (TextFieldView) dataView.getChildAt(i); |
| fieldView.updateDisplayedError(invalidViews.contains(fieldView)); |
| } |
| @@ -302,20 +406,40 @@ public class EditorView extends AlwaysDismissedDialog |
| buttonBar.setAlignment(DualControlLayout.ALIGN_END); |
| } |
| - /** Create the visual representation of the EditorModel. */ |
| + /** |
| + * Create the visual representation of the EditorModel. |
|
gone
2016/06/28 17:30:29
* Create the visual representation of the EditorMo
please use gerrit instead
2016/06/29 00:28:45
Done.
|
| + * TODO(rouslan): Put views side by side if !fieldModel.isFullLine(); |
| + */ |
| private void prepareEditor() { |
| - ViewGroup dataView = (ViewGroup) mLayout.findViewById(R.id.contents); |
| + final ViewGroup dataView = (ViewGroup) mLayout.findViewById(R.id.contents); |
| for (int i = 0; i < mEditorModel.getFields().size(); i++) { |
| final EditorFieldModel fieldModel = mEditorModel.getFields().get(i); |
| - EditorFieldView inputLayout = new EditorFieldView(mContext, fieldModel); |
| + if (fieldModel.isSpinner()) { |
| + SpinnerView spinnerView = new SpinnerView(mContext, fieldModel, new Runnable() { |
| + @Override |
| + public void run() { |
| + // Do not remove the "* indicates required field" label at the bottom. |
| + dataView.removeViews(0, dataView.getChildCount() - 1); |
| + prepareEditor(); |
| + if (mObserverForTest != null) { |
| + mObserverForTest.onPaymentRequestReadyToEdit(); |
| + } |
| + } |
| + }); |
| - final AutoCompleteTextView input = inputLayout.getTextView(); |
| - if (fieldModel.getInputTypeHint() == EditorFieldModel.INPUT_TYPE_HINT_PHONE) { |
| - assert mPhoneInput == null; |
| - mPhoneInput = input; |
| - } |
| + dataView.addView(spinnerView.getLabel(), dataView.getChildCount() - 1); |
| + dataView.addView(spinnerView.getSpinner(), dataView.getChildCount() - 1); |
| + } else { |
| + TextFieldView inputLayout = new TextFieldView(mContext, fieldModel); |
| + |
| + final AutoCompleteTextView input = inputLayout.getTextView(); |
| + if (fieldModel.getInputTypeHint() == EditorFieldModel.INPUT_TYPE_HINT_PHONE) { |
| + assert mPhoneInput == null; |
| + mPhoneInput = input; |
| + } |
| - dataView.addView(inputLayout, dataView.getChildCount() - 1); |
| + dataView.addView(inputLayout, dataView.getChildCount() - 1); |
| + } |
| } |
| } |
| @@ -337,7 +461,7 @@ public class EditorView extends AlwaysDismissedDialog |
| show(); |
| // Immediately focus the first invalid field to make it faster to edit. |
| - final List<EditorFieldView> invalidViews = getViewsWithInvalidInformation(); |
| + final List<TextFieldView> invalidViews = getViewsWithInvalidInformation(); |
| if (!invalidViews.isEmpty()) { |
| mHandler.post(new Runnable() { |
| @Override |
| @@ -365,15 +489,15 @@ public class EditorView extends AlwaysDismissedDialog |
| } |
| } |
| - private List<EditorFieldView> getViewsWithInvalidInformation() { |
| + private List<TextFieldView> getViewsWithInvalidInformation() { |
| ViewGroup container = (ViewGroup) findViewById(R.id.contents); |
| - List<EditorFieldView> invalidViews = new ArrayList<>(); |
| + List<TextFieldView> invalidViews = new ArrayList<>(); |
| for (int i = 0; i < container.getChildCount(); i++) { |
| View layout = container.getChildAt(i); |
| - if (!(layout instanceof EditorFieldView)) continue; |
| + if (!(layout instanceof TextFieldView)) continue; |
| - EditorFieldView fieldView = (EditorFieldView) layout; |
| + TextFieldView fieldView = (TextFieldView) layout; |
| if (!fieldView.getFieldModel().isValid()) invalidViews.add(fieldView); |
| } |
| return invalidViews; |