Skip to content

Commit 94d6c11

Browse files
authored
Merge pull request #86 from huttneab/libaddressinput
Add zip code validation and formatter
2 parents 6ca57f5 + 27e150f commit 94d6c11

10 files changed

Lines changed: 91 additions & 104 deletions

File tree

app/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Manifest version information!
22
def versionMajor = 1
33
def versionMinor = 0
4-
def versionPatch = 8
4+
def versionPatch = 9
55
def versionBuild = 0 // bump for dogfood builds, public betas, etc.
66

77
apply plugin: 'com.android.application'

app/src/main/AndroidManifest.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<application
1717
android:name=".GrommetApp"
18-
android:allowBackup="true"
18+
android:allowBackup="false"
1919
android:icon="@mipmap/ic_launcher"
2020
android:label="@string/app_name"
2121
android:supportsRtl="false"

app/src/main/java/com/rockthevote/grommet/ui/registration/PersonalInfoFragment.java

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,29 +8,20 @@
88
import android.widget.CheckBox;
99

1010
import com.f2prateek.rx.preferences.Preference;
11-
import com.jakewharton.rxbinding.widget.RxCompoundButton;
1211
import com.mobsandgeeks.saripaar.annotation.Checked;
1312
import com.rockthevote.grommet.R;
1413
import com.rockthevote.grommet.data.db.model.RockyRequest;
15-
import com.rockthevote.grommet.data.db.model.VoterClassification;
1614
import com.rockthevote.grommet.data.prefs.CurrentRockyRequestId;
1715
import com.rockthevote.grommet.ui.misc.ObservableValidator;
1816
import com.rockthevote.grommet.ui.views.AddressView;
1917
import com.squareup.sqlbrite.BriteDatabase;
2018

21-
import java.util.concurrent.TimeUnit;
22-
2319
import javax.inject.Inject;
2420

2521
import butterknife.BindView;
2622
import butterknife.ButterKnife;
2723
import butterknife.OnCheckedChanged;
2824
import rx.Observable;
29-
import rx.schedulers.Schedulers;
30-
import rx.subscriptions.CompositeSubscription;
31-
32-
import static com.rockthevote.grommet.data.db.Db.DEBOUNCE;
33-
import static com.rockthevote.grommet.data.db.model.VoterClassification.Type.SEND_COPY_IN_MAIL;
3425

3526

3627
public class PersonalInfoFragment extends BaseRegistrationFragment {
@@ -48,18 +39,14 @@ public class PersonalInfoFragment extends BaseRegistrationFragment {
4839

4940
@BindView(R.id.address_changed) CheckBox addressChanged;
5041

51-
@BindView(R.id.mailing_address_divider) View maillingDivider;
42+
@BindView(R.id.mailing_address_divider) View mailingDivider;
5243

5344
@BindView(R.id.previous_address_divider) View prevDivider;
5445

55-
@BindView(R.id.send_copy_in_mail) CheckBox sendCopyInMail;
56-
5746
@Inject @CurrentRockyRequestId Preference<Long> rockyRequestRowId;
5847

5948
@Inject BriteDatabase db;
6049

61-
private CompositeSubscription subscriptions;
62-
6350
private ObservableValidator validator;
6451

6552
@Nullable
@@ -76,34 +63,10 @@ public void onViewCreated(View view, Bundle savedInstanceState) {
7663
validator = new ObservableValidator(this, getActivity());
7764
}
7865

79-
@Override
80-
public void onResume() {
81-
super.onResume();
82-
subscriptions = new CompositeSubscription();
83-
84-
// try to use debounce when possible to reduce DB churn
85-
subscriptions.add(RxCompoundButton.checkedChanges(sendCopyInMail)
86-
.observeOn(Schedulers.io())
87-
.debounce(DEBOUNCE, TimeUnit.MILLISECONDS)
88-
.skip(1)
89-
.subscribe(checked -> {
90-
VoterClassification.insertOrUpdate(db, rockyRequestRowId.get(), SEND_COPY_IN_MAIL,
91-
new VoterClassification.Builder()
92-
.assertion(checked)
93-
.build());
94-
}));
95-
}
96-
97-
@Override
98-
public void onPause() {
99-
super.onPause();
100-
subscriptions.unsubscribe();
101-
}
102-
10366
@OnCheckedChanged(R.id.mailing_address_is_different)
10467
public void onMailingAddressDifferentChecked(boolean checked) {
10568
mailingAddress.setVisibility(checked ? View.VISIBLE : View.GONE);
106-
maillingDivider.setVisibility(checked ? View.VISIBLE : View.GONE);
69+
mailingDivider.setVisibility(checked ? View.VISIBLE : View.GONE);
10770

10871
db.update(RockyRequest.TABLE,
10972
new RockyRequest.Builder()

app/src/main/java/com/rockthevote/grommet/ui/views/AddressView.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515

1616
import com.f2prateek.rx.preferences.Preference;
1717
import com.jakewharton.rxbinding.widget.RxTextView;
18-
import com.mobsandgeeks.saripaar.annotation.Length;
1918
import com.mobsandgeeks.saripaar.annotation.NotEmpty;
19+
import com.mobsandgeeks.saripaar.annotation.Pattern;
2020
import com.rockthevote.grommet.R;
2121
import com.rockthevote.grommet.data.Injector;
2222
import com.rockthevote.grommet.data.db.model.Address;
@@ -25,6 +25,7 @@
2525
import com.rockthevote.grommet.ui.misc.ChildrenViewStateHelper;
2626
import com.rockthevote.grommet.ui.misc.ObservableValidator;
2727
import com.rockthevote.grommet.util.Strings;
28+
import com.rockthevote.grommet.util.ZipTextWatcher;
2829
import com.squareup.sqlbrite.BriteDatabase;
2930

3031
import java.util.concurrent.TimeUnit;
@@ -62,7 +63,7 @@ public class AddressView extends FrameLayout {
6263

6364
@BindView(R.id.spinner_state) BetterSpinner stateSpinner;
6465

65-
@Length(min = 5, max = 10)
66+
@Pattern(regex = "^[0-9]{5}(?:-[0-9]{4})?$", messageResId = R.string.zip_code_error)
6667
@BindView(R.id.til_zip_code) TextInputLayout zipTIL;
6768
@BindView(R.id.zip) EditText zipEditText;
6869

@@ -74,15 +75,14 @@ public class AddressView extends FrameLayout {
7475

7576
@Inject BriteDatabase db;
7677

77-
ObservableValidator validator;
78+
private ObservableValidator validator;
7879

7980
private ArrayAdapter<CharSequence> countyAdapter;
80-
8181
private ArrayAdapter<CharSequence> stateAdapter;
8282

8383
private Address.Type type;
84-
8584
private CompositeSubscription subscriptions = new CompositeSubscription();
85+
private ZipTextWatcher zipTextWatcher = new ZipTextWatcher();
8686

8787
public AddressView(Context context) {
8888
this(context, null);
@@ -182,13 +182,16 @@ protected void onFinishInflate() {
182182
if (Strings.isBlank(stateSpinner.getEditText().getEditableText().toString())) {
183183
stateSpinner.getEditText().setText(stateAdapter.getItem(stateAdapter.getPosition(PA_ABREV)));
184184
}
185+
185186
}
186187
}
187188

188189
@Override
189190
protected void onAttachedToWindow() {
190191
super.onAttachedToWindow();
191192
if (!isInEditMode()) {
193+
zipEditText.addTextChangedListener(zipTextWatcher);
194+
192195
subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(streetEditText),
193196
RxTextView.afterTextChangeEvents(unitEditText),
194197
RxTextView.afterTextChangeEvents(cityEditText),
@@ -215,6 +218,7 @@ protected void onAttachedToWindow() {
215218
protected void onDetachedFromWindow() {
216219
super.onDetachedFromWindow();
217220
subscriptions.unsubscribe();
221+
zipEditText.removeTextChangedListener(zipTextWatcher);
218222
}
219223

220224
@Override

app/src/main/java/com/rockthevote/grommet/ui/views/EventDetails.java

Lines changed: 44 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
import android.widget.TextView;
1414

1515
import com.f2prateek.rx.preferences.Preference;
16-
import com.mobsandgeeks.saripaar.annotation.Length;
16+
import com.mobsandgeeks.saripaar.annotation.Pattern;
1717
import com.rockthevote.grommet.R;
1818
import com.rockthevote.grommet.data.Injector;
1919
import com.rockthevote.grommet.data.api.RockyService;
@@ -25,7 +25,9 @@
2525
import com.rockthevote.grommet.data.prefs.PartnerId;
2626
import com.rockthevote.grommet.data.prefs.PartnerName;
2727
import com.rockthevote.grommet.ui.misc.BetterViewAnimator;
28+
import com.rockthevote.grommet.ui.misc.ObservableValidator;
2829
import com.rockthevote.grommet.util.Strings;
30+
import com.rockthevote.grommet.util.ZipTextWatcher;
2931

3032
import java.util.List;
3133
import java.util.concurrent.TimeUnit;
@@ -39,6 +41,8 @@
3941
import rx.schedulers.Schedulers;
4042
import rx.subscriptions.CompositeSubscription;
4143

44+
import static com.rockthevote.grommet.ui.views.EditableActionView.EditableActionViewListener;
45+
4246
public class EventDetails extends FrameLayout {
4347

4448
static final ButterKnife.Setter<View, Boolean> ENABLED =
@@ -47,46 +51,35 @@ public class EventDetails extends FrameLayout {
4751
@BindViews({R.id.ede_til_canvasser_name, R.id.ede_til_event_name,
4852
R.id.ede_til_event_zip, R.id.ede_til_partner_id})
4953
List<TextInputLayout> editableViews;
50-
5154
@BindView(R.id.ed_animator) BetterViewAnimator viewAnimator;
5255

5356
@BindView(R.id.ed_canvasser_name) TextView edCanvasserName;
54-
5557
@BindView(R.id.ed_event_name) TextView edEventName;
56-
5758
@BindView(R.id.ed_event_zip) TextView edEventZip;
58-
5959
@BindView(R.id.ed_partner_name) TextView edPartnerName;
6060

6161
@BindView(R.id.ede_canvasser_name) EditText edeCanvasserName;
62-
6362
@BindView(R.id.ede_event_name) EditText edeEventName;
6463

64+
@Pattern(regex = "^[0-9]{5}(?:-[0-9]{4})?$", messageResId = R.string.zip_code_error)
65+
@BindView(R.id.ede_til_event_zip) TextInputLayout edeEventZipTIL;
6566
@BindView(R.id.ede_event_zip) EditText edeEventZip;
66-
6767
@BindView(R.id.ede_til_partner_id) TextInputLayout edePartnerIdTIL;
68-
6968
@BindView(R.id.ede_partner_id) EditText edePartnerId;
7069

7170
@Inject @EventRegTotal Preference<Integer> eventRegTotalPref;
72-
7371
@Inject @CanvasserName Preference<String> canvasserNamePref;
74-
7572
@Inject @EventName Preference<String> eventNamePref;
76-
7773
@Inject @EventZip Preference<String> eventZipPref;
78-
7974
@Inject @PartnerId Preference<String> partnerIdPref;
80-
8175
@Inject @PartnerName Preference<String> partnerNamePref;
8276

8377
@Inject RockyService rockyService;
8478

8579
private CompositeSubscription subscriptions = new CompositeSubscription();
86-
87-
private EditableActionView.EditableActionViewListener listener;
88-
8980
private EditableActionView editableActionView;
81+
private ZipTextWatcher zipTextWatcher = new ZipTextWatcher();
82+
private ObservableValidator validator;
9083

9184
public EventDetails(Context context) {
9285
this(context, null);
@@ -109,13 +102,18 @@ public EventDetails(Context context, AttributeSet attrs, int defStyleAttr) {
109102
@Override
110103
protected void onFinishInflate() {
111104
super.onFinishInflate();
112-
ButterKnife.bind(this);
105+
if (!isInEditMode()) {
106+
ButterKnife.bind(this);
107+
validator = new ObservableValidator(this, getContext());
108+
}
113109
}
114110

115111
@Override
116112
protected void onAttachedToWindow() {
117113
super.onAttachedToWindow();
118114
if (!isInEditMode()) {
115+
edeEventZip.addTextChangedListener(zipTextWatcher);
116+
119117
subscriptions.add(canvasserNamePref.asObservable()
120118
.subscribe(name -> edCanvasserName.setText(name)));
121119

@@ -132,7 +130,7 @@ protected void onAttachedToWindow() {
132130

133131
public void setEditableActionView(EditableActionView view) {
134132
editableActionView = view;
135-
listener = new EditableActionView.EditableActionViewListener() {
133+
editableActionView.setListener(new EditableActionViewListener() {
136134
@Override
137135
public void onEdit() {
138136
enableEditMode(true);
@@ -147,41 +145,41 @@ public void onCancel() {
147145
public void onSave() {
148146

149147
// allow the user to not set a partner ID
150-
if (Strings.isBlank(edePartnerId.getText().toString())) {
151-
setPartnerName("");
152-
} else if (edePartnerId.getText().toString().equals(partnerIdPref.get())) {
153-
setPartnerName(partnerNamePref.get());
154-
} else {
155-
rockyService.getPartnerName(edePartnerId.getText().toString())
156-
.subscribeOn(Schedulers.io())
157-
.delay(500, TimeUnit.MILLISECONDS)
158-
.observeOn(AndroidSchedulers.mainThread())
159-
.doOnSubscribe(() -> {
160-
editableActionView.showSpinner();
161-
ButterKnife.apply(editableViews, ENABLED, false);
162-
})
163-
.doOnCompleted(() -> ButterKnife.apply(editableViews, ENABLED, true))
164-
.subscribe(result -> {
165-
if (!result.isError() && result.response().isSuccessful()) {
166-
PartnerNameResponse partnerNameResponse = result.response().body();
167-
if (partnerNameResponse.isValid()) {
168-
setPartnerName(partnerNameResponse.partnerName());
148+
if (validator.validate().toBlocking().single()) {
149+
if (Strings.isBlank(edePartnerId.getText().toString())) {
150+
setPartnerName("");
151+
} else if (edePartnerId.getText().toString().equals(partnerIdPref.get())) {
152+
setPartnerName(partnerNamePref.get());
153+
} else {
154+
rockyService.getPartnerName(edePartnerId.getText().toString())
155+
.subscribeOn(Schedulers.io())
156+
.delay(500, TimeUnit.MILLISECONDS)
157+
.observeOn(AndroidSchedulers.mainThread())
158+
.doOnSubscribe(() -> {
159+
editableActionView.showSpinner();
160+
ButterKnife.apply(editableViews, ENABLED, false);
161+
})
162+
.doOnCompleted(() -> ButterKnife.apply(editableViews, ENABLED, true))
163+
.subscribe(result -> {
164+
if (!result.isError() && result.response().isSuccessful()) {
165+
PartnerNameResponse partnerNameResponse = result.response().body();
166+
if (partnerNameResponse.isValid()) {
167+
setPartnerName(partnerNameResponse.partnerName());
168+
} else {
169+
edePartnerIdTIL.setError(
170+
getContext().getString(R.string.error_partner_id));
171+
editableActionView.showSaveCancel();
172+
}
169173
} else {
170174
edePartnerIdTIL.setError(
171175
getContext().getString(R.string.error_partner_id));
172176
editableActionView.showSaveCancel();
173177
}
174-
} else {
175-
edePartnerIdTIL.setError(
176-
getContext().getString(R.string.error_partner_id));
177-
editableActionView.showSaveCancel();
178-
}
179-
});
178+
});
179+
}
180180
}
181181
}
182-
};
183-
184-
editableActionView.setListener(listener);
182+
});
185183
}
186184

187185
private void setPartnerName(String name) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.rockthevote.grommet.util;
2+
3+
import android.text.Editable;
4+
import android.text.TextWatcher;
5+
6+
public class ZipTextWatcher implements TextWatcher {
7+
8+
@Override
9+
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
10+
11+
}
12+
13+
@Override
14+
public void onTextChanged(CharSequence s, int start, int before, int count) {
15+
16+
}
17+
18+
@Override
19+
public void afterTextChanged(Editable s) {
20+
if (!s.toString().contains("-") && s.length() > 5) {
21+
s.insert(5, "-");
22+
} else if( s.toString().contains("-") && s.length() < 7){
23+
int dashIndex = s.toString().indexOf("-");
24+
s.delete(dashIndex, s.length());
25+
}
26+
}
27+
}

app/src/main/res/layout/event_details_editable.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@
6363
style="@android:style/TextAppearance.Material.Subhead"
6464
android:layout_width="match_parent"
6565
android:layout_height="wrap_content"
66-
android:inputType="number"
66+
android:inputType="phone"
67+
android:maxLength="10"
6768
android:maxLines="1"
6869
/>
6970

0 commit comments

Comments
 (0)