From f0894cc2b949a7342cfe559e3269e543530d61c3 Mon Sep 17 00:00:00 2001 From: Aaron Huttner Date: Fri, 26 Aug 2016 16:00:08 -0400 Subject: [PATCH] Fix a big UI bug for save instance state. Fix subAddress --> sub_address JSON bug. Make sure default preferred language made it into the DB. Fix some other UI bugs. version bump --- app/build.gradle | 2 +- .../grommet/data/api/model/ApiAddress.java | 2 +- .../grommet/ui/misc/BetterSpinner.java | 49 +++++++++++++++++++ .../ui/misc/ChildrenViewStateHelper.java | 12 ++++- .../grommet/ui/misc/StepperTabLayout.java | 9 +++- .../registration/AdditionalInfoFragment.java | 24 +++++++-- .../ReviewAndConfirmFragment.java | 15 +++++- .../grommet/ui/views/AddressView.java | 29 +++++++---- .../grommet/ui/views/NameView.java | 16 +++--- .../res/layout/fragment_additional_info.xml | 1 + 10 files changed, 132 insertions(+), 27 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 42a3ac1e..73d609ee 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,7 @@ // Manifest version information! def versionMajor = 1 def versionMinor = 0 -def versionPatch = 7 +def versionPatch = 8 def versionBuild = 0 // bump for dogfood builds, public betas, etc. apply plugin: 'com.android.application' diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAddress.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAddress.java index fc28ed31..b54c8945 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAddress.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAddress.java @@ -134,7 +134,7 @@ public void toJson(JsonWriter writer, ApiAddress value) throws IOException { writer.beginObject(); writer.name("sub_address_type"); writer.value("APT"); - writer.name("subAddress"); + writer.name("sub_address"); subAddressAdapter.toJson(writer, value.subAddress()); writer.endObject(); diff --git a/app/src/main/java/com/rockthevote/grommet/ui/misc/BetterSpinner.java b/app/src/main/java/com/rockthevote/grommet/ui/misc/BetterSpinner.java index 0e05212a..1d1ac39d 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/misc/BetterSpinner.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/misc/BetterSpinner.java @@ -1,11 +1,14 @@ package com.rockthevote.grommet.ui.misc; import android.content.Context; +import android.os.Bundle; +import android.os.Parcelable; import android.support.annotation.NonNull; import android.support.design.widget.TextInputEditText; import android.support.design.widget.TextInputLayout; import android.support.v7.widget.ListPopupWindow; import android.util.AttributeSet; +import android.util.SparseArray; import android.widget.AdapterView; import android.widget.ListAdapter; @@ -13,6 +16,8 @@ public class BetterSpinner extends TextInputLayout { + private String childrenStateKey; + private String superStateKey; ListPopupWindow listPopupWindow; ListAdapter listAdapter; @@ -29,6 +34,10 @@ public BetterSpinner(Context context, AttributeSet attrs) { public BetterSpinner(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); + superStateKey = BetterSpinner.class.getSimpleName() + ".superState"; + childrenStateKey = BetterSpinner.class.getSimpleName() + ".childState"; + + editText = new TextInputEditText(context); editText.setId(R.id.titleId); editText.setHeight((int) getResources().getDimension(R.dimen.list_item_height)); @@ -64,6 +73,46 @@ public void setHeight(int height) { listPopupWindow.setHeight(height); } + @Override + public Parcelable onSaveInstanceState() { + final Bundle state = new Bundle(); + state.putParcelable(superStateKey, super.onSaveInstanceState()); + state.putSparseParcelableArray(childrenStateKey, + ChildrenViewStateHelper.newInstance(this).saveChildrenState(childrenStateKey)); + return state; + } + + @Override + protected void onRestoreInstanceState(final Parcelable state) { + if (state instanceof Bundle) { + final Bundle localState = (Bundle) state; + super.onRestoreInstanceState(localState.getParcelable(superStateKey)); + ChildrenViewStateHelper.newInstance(this).restoreChildrenState(localState + .getSparseParcelableArray(childrenStateKey), childrenStateKey); + } else { + super.onRestoreInstanceState(state); + } + } + + @Override + protected void dispatchSaveInstanceState(SparseArray container) { + dispatchFreezeSelfOnly(container); + } + + @Override + protected void dispatchRestoreInstanceState(SparseArray container) { + dispatchThawSelfOnly(container); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + if (!enabled) { + getEditText().setText(""); + } + getEditText().setEnabled(enabled); + } + @NonNull @Override public TextInputEditText getEditText() { diff --git a/app/src/main/java/com/rockthevote/grommet/ui/misc/ChildrenViewStateHelper.java b/app/src/main/java/com/rockthevote/grommet/ui/misc/ChildrenViewStateHelper.java index 978d0b36..2f179ef7 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/misc/ChildrenViewStateHelper.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/misc/ChildrenViewStateHelper.java @@ -25,12 +25,16 @@ private ChildrenViewStateHelper() { * Also you need override {@link ViewGroup#dispatchSaveInstanceState(SparseArray)} and call {@link ViewGroup#dispatchFreezeSelfOnly(SparseArray)}. */ public SparseArray saveChildrenState() { + return saveChildrenState(DEFAULT_CHILDREN_STATE_KEY); + } + + public SparseArray saveChildrenState(String stateKey) { final SparseArray array = new SparseArray<>(); for (int i = 0; i < mClientViewGroup.getChildCount(); i++) { final Bundle bundle = new Bundle(); final SparseArray childArray = new SparseArray<>(); //create independent SparseArray for each child (View or ViewGroup) mClientViewGroup.getChildAt(i).saveHierarchyState(childArray); - bundle.putSparseParcelableArray(DEFAULT_CHILDREN_STATE_KEY, childArray); + bundle.putSparseParcelableArray(stateKey, childArray); array.append(i, bundle); } return array; @@ -41,12 +45,16 @@ public SparseArray saveChildrenState() { * Also you need override {@link ViewGroup#dispatchRestoreInstanceState(SparseArray)} and call {@link ViewGroup#dispatchThawSelfOnly(SparseArray)}. */ public void restoreChildrenState(@Nullable final SparseArray childrenState) { + restoreChildrenState(childrenState, DEFAULT_CHILDREN_STATE_KEY); + } + + public void restoreChildrenState(@Nullable final SparseArray childrenState, String stateKey) { if (null == childrenState) { return; } for (int i = 0; i < mClientViewGroup.getChildCount(); i++) { final Bundle bundle = (Bundle) childrenState.get(i); - final SparseArray childState = bundle.getSparseParcelableArray(DEFAULT_CHILDREN_STATE_KEY); + final SparseArray childState = bundle.getSparseParcelableArray(stateKey); mClientViewGroup.getChildAt(i).restoreHierarchyState(childState); } } diff --git a/app/src/main/java/com/rockthevote/grommet/ui/misc/StepperTabLayout.java b/app/src/main/java/com/rockthevote/grommet/ui/misc/StepperTabLayout.java index 919019ac..a4534570 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/misc/StepperTabLayout.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/misc/StepperTabLayout.java @@ -65,20 +65,25 @@ public void enableTabAtPosition(int pos) { @Override protected Parcelable onSaveInstanceState() { final Bundle state = new Bundle(); - state.putParcelable("superState", super.onSaveInstanceState()); + state.putParcelable("stepperSuperState", super.onSaveInstanceState()); state.putParcelable(STEPPER_STATE_KEY, new SparseBooleanArrayParcelable(enabled)); return state; } @Override + @SuppressWarnings("ConstantConditions") protected void onRestoreInstanceState(final Parcelable state) { if (state instanceof Bundle) { final Bundle localState = (Bundle) state; - super.onRestoreInstanceState(localState.getParcelable("superState")); + super.onRestoreInstanceState(localState.getParcelable("stepperSuperState")); enabled = localState.getParcelable(STEPPER_STATE_KEY); + for (int i = 0; i < getTabCount(); i++) { + getTabAt(i).getCustomView().setEnabled(enabled.get(i)); + } } else { super.onRestoreInstanceState(state); } } + } diff --git a/app/src/main/java/com/rockthevote/grommet/ui/registration/AdditionalInfoFragment.java b/app/src/main/java/com/rockthevote/grommet/ui/registration/AdditionalInfoFragment.java index 1fe467f6..6bc70da1 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/registration/AdditionalInfoFragment.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/registration/AdditionalInfoFragment.java @@ -53,6 +53,7 @@ import static com.rockthevote.grommet.data.db.model.VoterId.Type.SSN_LAST_FOUR; public class AdditionalInfoFragment extends BaseRegistrationFragment { + private static final String OTHER_PARTY_VISIBILITY_KEY = "other_party_visibility_key"; @BindView(R.id.spinner_race) BetterSpinner raceSpinner; @@ -131,7 +132,6 @@ public void onViewCreated(View view, Bundle savedInstanceState) { validator = new ObservableValidator(this, getActivity()); - // Setup Race Spinner raceEnumAdapter = new EnumAdapter<>(getActivity(), Race.class); raceSpinner.setAdapter(raceEnumAdapter); @@ -139,7 +139,6 @@ public void onViewCreated(View view, Bundle savedInstanceState) { raceSpinner.getEditText().setText(raceEnumAdapter.getItem(i).toString()); raceSpinner.dismiss(); }); - raceSpinner.getEditText().setText(Race.OTHER.toString()); // Setup Party Spinner @@ -168,12 +167,24 @@ public void onViewCreated(View view, Bundle savedInstanceState) { phoneTypeSpinner.getEditText().setText(phoneTypeEnumAdapter.getItem(i).toString()); phoneTypeSpinner.dismiss(); }); - phoneTypeSpinner.getEditText().setText(phoneTypeEnumAdapter.getItem(0).toString()); + + if (null != savedInstanceState) { + otherPartyTIL.setVisibility(savedInstanceState.getBoolean(OTHER_PARTY_VISIBILITY_KEY) ? + View.VISIBLE : View.GONE); + } + } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); + + // set up defaults + if (null == savedInstanceState) { + raceSpinner.getEditText().setText(Race.OTHER.toString()); + phoneTypeSpinner.getEditText().setText(phoneTypeEnumAdapter.getItem(0).toString()); + } + phoneOptIn.setText(getString(R.string.label_receive_text, partnerNamePref.get())); emailOptIn.setText(getString(R.string.label_receive_email, partnerNamePref.get())); } @@ -222,7 +233,6 @@ public void onResume() { subscriptions.add(RxTextView.afterTextChangeEvents(preferredLanguage) .observeOn(Schedulers.io()) .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) - .skip(1) .subscribe(event -> { AdditionalInfo.insertOrUpdate(db, rockyRequestRowId.get(), LANGUAGE_PREF, new AdditionalInfo.Builder() @@ -356,6 +366,12 @@ public void onSSNChecked(boolean checked) { doesNotHaveSSN.onNext(checked); } + @Override + public void onSaveInstanceState(Bundle outState) { + outState.putBoolean(OTHER_PARTY_VISIBILITY_KEY, View.VISIBLE == otherPartyTIL.getVisibility()); + super.onSaveInstanceState(outState); + } + @Override public Observable verify() { return validator.validate(); diff --git a/app/src/main/java/com/rockthevote/grommet/ui/registration/ReviewAndConfirmFragment.java b/app/src/main/java/com/rockthevote/grommet/ui/registration/ReviewAndConfirmFragment.java index 363098ce..1fc73169 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/registration/ReviewAndConfirmFragment.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/registration/ReviewAndConfirmFragment.java @@ -137,7 +137,15 @@ public void onAcceptClick() { .subscribe(rockyRequest -> { birthday.setText(Dates.formatAsISO8601_ShortDate(rockyRequest.dateOfBirth())); race.setText(rockyRequest.race().toString()); - party.setText(rockyRequest.party().toString()); + + String polParty; + if (RockyRequest.Party.OTHER_PARTY == rockyRequest.party()) { + polParty = rockyRequest.otherParty(); + } else { + polParty = rockyRequest.party().toString(); + } + + party.setText(polParty); phoneLabel.setText(rockyRequest.phoneType().toString()); // show/hide registration address views for (View v : mailingAddressViews) { @@ -187,6 +195,8 @@ public void onClearSignatureClick(View v) { public void onCheckChanged(boolean checked) { if (checked) { dialog.show(getFragmentManager(), "disclosure_dialog"); + } else { + buttonRegister.setEnabled(false); } } @@ -198,7 +208,8 @@ public void onStartSigning() { @Override public void onSigned() { ByteArrayOutputStream baos = new ByteArrayOutputStream(); - Bitmap image = (Images.aspectSafeScale(Images.transformAspectRatio(signaturePad.getSignatureBitmap(), 3, 1), 180, 60)); + Bitmap image = Images.transformAspectRatio(signaturePad.getSignatureBitmap(), 3, 1); + image = Images.aspectSafeScale(image, 180, 60); image.compress(Bitmap.CompressFormat.PNG, 100, baos); db.update(RockyRequest.TABLE, diff --git a/app/src/main/java/com/rockthevote/grommet/ui/views/AddressView.java b/app/src/main/java/com/rockthevote/grommet/ui/views/AddressView.java index 9a997068..422fef48 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/views/AddressView.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/views/AddressView.java @@ -24,6 +24,7 @@ import com.rockthevote.grommet.ui.misc.BetterSpinner; import com.rockthevote.grommet.ui.misc.ChildrenViewStateHelper; import com.rockthevote.grommet.ui.misc.ObservableValidator; +import com.rockthevote.grommet.util.Strings; import com.squareup.sqlbrite.BriteDatabase; import java.util.concurrent.TimeUnit; @@ -41,6 +42,11 @@ public class AddressView extends FrameLayout { private static final String PA_ABREV = "PA"; + private static final String COUNTY_ENABLED_KEY = "county_enabled_key"; + + private String childrenStateKey; + private String superStateKey; + @NotEmpty @BindView(R.id.til_street_address) TextInputLayout streetTIL; @BindView(R.id.street) EditText streetEditText; @@ -112,10 +118,14 @@ public AddressView(Context context, AttributeSet attrs, int defStyleAttr) { break; case 4: type = Address.Type.ASSISTANT_ADDRESS; + break; } } finally { typedArray.recycle(); } + + superStateKey = AddressView.class.getSimpleName() + ".superState." + type.toString(); + childrenStateKey = AddressView.class.getSimpleName() + ".childState." + type.toString(); } } @@ -163,16 +173,15 @@ protected void onFinishInflate() { if (!PA_ABREV.equals(stateAdapter.getItem(i))) { countySpinner.setErrorEnabled(false); countySpinner.setEnabled(false); - countySpinner.getEditText().setText(""); - countySpinner.getEditText().setEnabled(false); } else { - countySpinner.getEditText().setEnabled(true); countySpinner.setEnabled(true); } stateSpinner.dismiss(); }); - stateSpinner.getEditText().setText(stateAdapter.getItem(stateAdapter.getPosition(PA_ABREV))); + if (Strings.isBlank(stateSpinner.getEditText().getEditableText().toString())) { + stateSpinner.getEditText().setText(stateAdapter.getItem(stateAdapter.getPosition(PA_ABREV))); + } } } @@ -211,9 +220,10 @@ protected void onDetachedFromWindow() { @Override protected Parcelable onSaveInstanceState() { final Bundle state = new Bundle(); - state.putParcelable("superState", super.onSaveInstanceState()); - state.putSparseParcelableArray(ChildrenViewStateHelper.DEFAULT_CHILDREN_STATE_KEY, - ChildrenViewStateHelper.newInstance(this).saveChildrenState()); + state.putParcelable(superStateKey, super.onSaveInstanceState()); + state.putBoolean(COUNTY_ENABLED_KEY, countySpinner.isEnabled()); + state.putSparseParcelableArray(childrenStateKey, + ChildrenViewStateHelper.newInstance(this).saveChildrenState(childrenStateKey)); return state; } @@ -221,9 +231,10 @@ protected Parcelable onSaveInstanceState() { protected void onRestoreInstanceState(final Parcelable state) { if (state instanceof Bundle) { final Bundle localState = (Bundle) state; - super.onRestoreInstanceState(localState.getParcelable("superState")); + super.onRestoreInstanceState(localState.getParcelable(superStateKey)); ChildrenViewStateHelper.newInstance(this).restoreChildrenState(localState - .getSparseParcelableArray(ChildrenViewStateHelper.DEFAULT_CHILDREN_STATE_KEY)); + .getSparseParcelableArray(childrenStateKey), childrenStateKey); + countySpinner.setEnabled(localState.getBoolean(COUNTY_ENABLED_KEY, true)); } else { super.onRestoreInstanceState(state); } diff --git a/app/src/main/java/com/rockthevote/grommet/ui/views/NameView.java b/app/src/main/java/com/rockthevote/grommet/ui/views/NameView.java index 7acd9f19..8b3916ff 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/views/NameView.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/views/NameView.java @@ -41,6 +41,9 @@ public class NameView extends FrameLayout { + private String childrenStateKey; + private String superStateKey; + @BindView(R.id.name_section_title) TextView sectionTitle; @NotEmpty @@ -108,7 +111,8 @@ public NameView(Context context, AttributeSet attrs, int defStyleAttr) { } finally { typedArray.recycle(); } - + superStateKey = NameView.class.getSimpleName() + ".superState." + type.toString(); + childrenStateKey = NameView.class.getSimpleName() + ".childState." + type.toString(); } } @@ -182,9 +186,9 @@ protected void onDetachedFromWindow() { @Override protected Parcelable onSaveInstanceState() { final Bundle state = new Bundle(); - state.putParcelable("superState", super.onSaveInstanceState()); - state.putSparseParcelableArray(ChildrenViewStateHelper.DEFAULT_CHILDREN_STATE_KEY, - ChildrenViewStateHelper.newInstance(this).saveChildrenState()); + state.putParcelable(superStateKey, super.onSaveInstanceState()); + state.putSparseParcelableArray(childrenStateKey, + ChildrenViewStateHelper.newInstance(this).saveChildrenState(childrenStateKey)); return state; } @@ -192,9 +196,9 @@ protected Parcelable onSaveInstanceState() { protected void onRestoreInstanceState(final Parcelable state) { if (state instanceof Bundle) { final Bundle localState = (Bundle) state; - super.onRestoreInstanceState(localState.getParcelable("superState")); + super.onRestoreInstanceState(localState.getParcelable(superStateKey)); ChildrenViewStateHelper.newInstance(this).restoreChildrenState(localState - .getSparseParcelableArray(ChildrenViewStateHelper.DEFAULT_CHILDREN_STATE_KEY)); + .getSparseParcelableArray(childrenStateKey), childrenStateKey); } else { super.onRestoreInstanceState(state); } diff --git a/app/src/main/res/layout/fragment_additional_info.xml b/app/src/main/res/layout/fragment_additional_info.xml index 977a2e3e..db34f929 100644 --- a/app/src/main/res/layout/fragment_additional_info.xml +++ b/app/src/main/res/layout/fragment_additional_info.xml @@ -156,6 +156,7 @@ android:id="@+id/ssn_last_four_edit_text" android:layout_width="match_parent" android:layout_height="wrap_content" + android:digits="0123456789" android:hint="@string/label_ssn_last_four" android:inputType="number" android:maxLength="4"