diff --git a/app/build.gradle b/app/build.gradle index 73d609ee..dbe72730 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,7 +1,7 @@ // Manifest version information! def versionMajor = 1 def versionMinor = 0 -def versionPatch = 8 +def versionPatch = 9 def versionBuild = 0 // bump for dogfood builds, public betas, etc. apply plugin: 'com.android.application' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 23757807..1a65aa30 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,7 +15,7 @@ rockyRequestRowId; @Inject BriteDatabase db; - private CompositeSubscription subscriptions; - private ObservableValidator validator; @Nullable @@ -76,34 +63,10 @@ public void onViewCreated(View view, Bundle savedInstanceState) { validator = new ObservableValidator(this, getActivity()); } - @Override - public void onResume() { - super.onResume(); - subscriptions = new CompositeSubscription(); - - // try to use debounce when possible to reduce DB churn - subscriptions.add(RxCompoundButton.checkedChanges(sendCopyInMail) - .observeOn(Schedulers.io()) - .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) - .skip(1) - .subscribe(checked -> { - VoterClassification.insertOrUpdate(db, rockyRequestRowId.get(), SEND_COPY_IN_MAIL, - new VoterClassification.Builder() - .assertion(checked) - .build()); - })); - } - - @Override - public void onPause() { - super.onPause(); - subscriptions.unsubscribe(); - } - @OnCheckedChanged(R.id.mailing_address_is_different) public void onMailingAddressDifferentChecked(boolean checked) { mailingAddress.setVisibility(checked ? View.VISIBLE : View.GONE); - maillingDivider.setVisibility(checked ? View.VISIBLE : View.GONE); + mailingDivider.setVisibility(checked ? View.VISIBLE : View.GONE); db.update(RockyRequest.TABLE, new RockyRequest.Builder() 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 422fef48..6483c783 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 @@ -15,8 +15,8 @@ import com.f2prateek.rx.preferences.Preference; import com.jakewharton.rxbinding.widget.RxTextView; -import com.mobsandgeeks.saripaar.annotation.Length; import com.mobsandgeeks.saripaar.annotation.NotEmpty; +import com.mobsandgeeks.saripaar.annotation.Pattern; import com.rockthevote.grommet.R; import com.rockthevote.grommet.data.Injector; import com.rockthevote.grommet.data.db.model.Address; @@ -25,6 +25,7 @@ import com.rockthevote.grommet.ui.misc.ChildrenViewStateHelper; import com.rockthevote.grommet.ui.misc.ObservableValidator; import com.rockthevote.grommet.util.Strings; +import com.rockthevote.grommet.util.ZipTextWatcher; import com.squareup.sqlbrite.BriteDatabase; import java.util.concurrent.TimeUnit; @@ -62,7 +63,7 @@ public class AddressView extends FrameLayout { @BindView(R.id.spinner_state) BetterSpinner stateSpinner; - @Length(min = 5, max = 10) + @Pattern(regex = "^[0-9]{5}(?:-[0-9]{4})?$", messageResId = R.string.zip_code_error) @BindView(R.id.til_zip_code) TextInputLayout zipTIL; @BindView(R.id.zip) EditText zipEditText; @@ -74,15 +75,14 @@ public class AddressView extends FrameLayout { @Inject BriteDatabase db; - ObservableValidator validator; + private ObservableValidator validator; private ArrayAdapter countyAdapter; - private ArrayAdapter stateAdapter; private Address.Type type; - private CompositeSubscription subscriptions = new CompositeSubscription(); + private ZipTextWatcher zipTextWatcher = new ZipTextWatcher(); public AddressView(Context context) { this(context, null); @@ -182,6 +182,7 @@ protected void onFinishInflate() { if (Strings.isBlank(stateSpinner.getEditText().getEditableText().toString())) { stateSpinner.getEditText().setText(stateAdapter.getItem(stateAdapter.getPosition(PA_ABREV))); } + } } @@ -189,6 +190,8 @@ protected void onFinishInflate() { protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!isInEditMode()) { + zipEditText.addTextChangedListener(zipTextWatcher); + subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(streetEditText), RxTextView.afterTextChangeEvents(unitEditText), RxTextView.afterTextChangeEvents(cityEditText), @@ -215,6 +218,7 @@ protected void onAttachedToWindow() { protected void onDetachedFromWindow() { super.onDetachedFromWindow(); subscriptions.unsubscribe(); + zipEditText.removeTextChangedListener(zipTextWatcher); } @Override diff --git a/app/src/main/java/com/rockthevote/grommet/ui/views/EventDetails.java b/app/src/main/java/com/rockthevote/grommet/ui/views/EventDetails.java index 4fdbf4b6..5c46bb91 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/views/EventDetails.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/views/EventDetails.java @@ -13,7 +13,7 @@ import android.widget.TextView; import com.f2prateek.rx.preferences.Preference; -import com.mobsandgeeks.saripaar.annotation.Length; +import com.mobsandgeeks.saripaar.annotation.Pattern; import com.rockthevote.grommet.R; import com.rockthevote.grommet.data.Injector; import com.rockthevote.grommet.data.api.RockyService; @@ -25,7 +25,9 @@ import com.rockthevote.grommet.data.prefs.PartnerId; import com.rockthevote.grommet.data.prefs.PartnerName; import com.rockthevote.grommet.ui.misc.BetterViewAnimator; +import com.rockthevote.grommet.ui.misc.ObservableValidator; import com.rockthevote.grommet.util.Strings; +import com.rockthevote.grommet.util.ZipTextWatcher; import java.util.List; import java.util.concurrent.TimeUnit; @@ -39,6 +41,8 @@ import rx.schedulers.Schedulers; import rx.subscriptions.CompositeSubscription; +import static com.rockthevote.grommet.ui.views.EditableActionView.EditableActionViewListener; + public class EventDetails extends FrameLayout { static final ButterKnife.Setter ENABLED = @@ -47,46 +51,35 @@ public class EventDetails extends FrameLayout { @BindViews({R.id.ede_til_canvasser_name, R.id.ede_til_event_name, R.id.ede_til_event_zip, R.id.ede_til_partner_id}) List editableViews; - @BindView(R.id.ed_animator) BetterViewAnimator viewAnimator; @BindView(R.id.ed_canvasser_name) TextView edCanvasserName; - @BindView(R.id.ed_event_name) TextView edEventName; - @BindView(R.id.ed_event_zip) TextView edEventZip; - @BindView(R.id.ed_partner_name) TextView edPartnerName; @BindView(R.id.ede_canvasser_name) EditText edeCanvasserName; - @BindView(R.id.ede_event_name) EditText edeEventName; + @Pattern(regex = "^[0-9]{5}(?:-[0-9]{4})?$", messageResId = R.string.zip_code_error) + @BindView(R.id.ede_til_event_zip) TextInputLayout edeEventZipTIL; @BindView(R.id.ede_event_zip) EditText edeEventZip; - @BindView(R.id.ede_til_partner_id) TextInputLayout edePartnerIdTIL; - @BindView(R.id.ede_partner_id) EditText edePartnerId; @Inject @EventRegTotal Preference eventRegTotalPref; - @Inject @CanvasserName Preference canvasserNamePref; - @Inject @EventName Preference eventNamePref; - @Inject @EventZip Preference eventZipPref; - @Inject @PartnerId Preference partnerIdPref; - @Inject @PartnerName Preference partnerNamePref; @Inject RockyService rockyService; private CompositeSubscription subscriptions = new CompositeSubscription(); - - private EditableActionView.EditableActionViewListener listener; - private EditableActionView editableActionView; + private ZipTextWatcher zipTextWatcher = new ZipTextWatcher(); + private ObservableValidator validator; public EventDetails(Context context) { this(context, null); @@ -109,13 +102,18 @@ public EventDetails(Context context, AttributeSet attrs, int defStyleAttr) { @Override protected void onFinishInflate() { super.onFinishInflate(); - ButterKnife.bind(this); + if (!isInEditMode()) { + ButterKnife.bind(this); + validator = new ObservableValidator(this, getContext()); + } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!isInEditMode()) { + edeEventZip.addTextChangedListener(zipTextWatcher); + subscriptions.add(canvasserNamePref.asObservable() .subscribe(name -> edCanvasserName.setText(name))); @@ -132,7 +130,7 @@ protected void onAttachedToWindow() { public void setEditableActionView(EditableActionView view) { editableActionView = view; - listener = new EditableActionView.EditableActionViewListener() { + editableActionView.setListener(new EditableActionViewListener() { @Override public void onEdit() { enableEditMode(true); @@ -147,41 +145,41 @@ public void onCancel() { public void onSave() { // allow the user to not set a partner ID - if (Strings.isBlank(edePartnerId.getText().toString())) { - setPartnerName(""); - } else if (edePartnerId.getText().toString().equals(partnerIdPref.get())) { - setPartnerName(partnerNamePref.get()); - } else { - rockyService.getPartnerName(edePartnerId.getText().toString()) - .subscribeOn(Schedulers.io()) - .delay(500, TimeUnit.MILLISECONDS) - .observeOn(AndroidSchedulers.mainThread()) - .doOnSubscribe(() -> { - editableActionView.showSpinner(); - ButterKnife.apply(editableViews, ENABLED, false); - }) - .doOnCompleted(() -> ButterKnife.apply(editableViews, ENABLED, true)) - .subscribe(result -> { - if (!result.isError() && result.response().isSuccessful()) { - PartnerNameResponse partnerNameResponse = result.response().body(); - if (partnerNameResponse.isValid()) { - setPartnerName(partnerNameResponse.partnerName()); + if (validator.validate().toBlocking().single()) { + if (Strings.isBlank(edePartnerId.getText().toString())) { + setPartnerName(""); + } else if (edePartnerId.getText().toString().equals(partnerIdPref.get())) { + setPartnerName(partnerNamePref.get()); + } else { + rockyService.getPartnerName(edePartnerId.getText().toString()) + .subscribeOn(Schedulers.io()) + .delay(500, TimeUnit.MILLISECONDS) + .observeOn(AndroidSchedulers.mainThread()) + .doOnSubscribe(() -> { + editableActionView.showSpinner(); + ButterKnife.apply(editableViews, ENABLED, false); + }) + .doOnCompleted(() -> ButterKnife.apply(editableViews, ENABLED, true)) + .subscribe(result -> { + if (!result.isError() && result.response().isSuccessful()) { + PartnerNameResponse partnerNameResponse = result.response().body(); + if (partnerNameResponse.isValid()) { + setPartnerName(partnerNameResponse.partnerName()); + } else { + edePartnerIdTIL.setError( + getContext().getString(R.string.error_partner_id)); + editableActionView.showSaveCancel(); + } } else { edePartnerIdTIL.setError( getContext().getString(R.string.error_partner_id)); editableActionView.showSaveCancel(); } - } else { - edePartnerIdTIL.setError( - getContext().getString(R.string.error_partner_id)); - editableActionView.showSaveCancel(); - } - }); + }); + } } } - }; - - editableActionView.setListener(listener); + }); } private void setPartnerName(String name) { diff --git a/app/src/main/java/com/rockthevote/grommet/util/ZipTextWatcher.java b/app/src/main/java/com/rockthevote/grommet/util/ZipTextWatcher.java new file mode 100644 index 00000000..85a3acd5 --- /dev/null +++ b/app/src/main/java/com/rockthevote/grommet/util/ZipTextWatcher.java @@ -0,0 +1,27 @@ +package com.rockthevote.grommet.util; + +import android.text.Editable; +import android.text.TextWatcher; + +public class ZipTextWatcher implements TextWatcher { + + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + + } + + @Override + public void afterTextChanged(Editable s) { + if (!s.toString().contains("-") && s.length() > 5) { + s.insert(5, "-"); + } else if( s.toString().contains("-") && s.length() < 7){ + int dashIndex = s.toString().indexOf("-"); + s.delete(dashIndex, s.length()); + } + } +} diff --git a/app/src/main/res/layout/event_details_editable.xml b/app/src/main/res/layout/event_details_editable.xml index b498189a..87b2a5d6 100644 --- a/app/src/main/res/layout/event_details_editable.xml +++ b/app/src/main/res/layout/event_details_editable.xml @@ -63,7 +63,8 @@ style="@android:style/TextAppearance.Material.Subhead" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="number" + android:inputType="phone" + android:maxLength="10" android:maxLines="1" /> diff --git a/app/src/main/res/layout/fragment_personal_info.xml b/app/src/main/res/layout/fragment_personal_info.xml index 2d55744b..ee6e824b 100644 --- a/app/src/main/res/layout/fragment_personal_info.xml +++ b/app/src/main/res/layout/fragment_personal_info.xml @@ -87,11 +87,4 @@ tools:visibility="visible" /> - diff --git a/app/src/main/res/layout/view_address.xml b/app/src/main/res/layout/view_address.xml index 0e11bda8..05485f2f 100644 --- a/app/src/main/res/layout/view_address.xml +++ b/app/src/main/res/layout/view_address.xml @@ -69,7 +69,7 @@ @@ -107,8 +107,8 @@ android:layout_width="match_parent" android:layout_height="@dimen/list_item_height" android:hint="@string/label_zip_code" - android:inputType="number" - android:maxEms="5" + android:inputType="phone" + android:maxLength="10" android:maxLines="1"/> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cf0602f0..85640c4a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,6 +75,7 @@ County Required I have no permanent or mailing address Complete registration using paper form + Invalid zip–code Personal