diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/RegistrationService.java b/app/src/main/java/com/rockthevote/grommet/data/api/RegistrationService.java index 44c1b3ae..39a3c4a6 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/RegistrationService.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/RegistrationService.java @@ -19,6 +19,7 @@ import com.rockthevote.grommet.data.api.model.ApiContactMethod; import com.rockthevote.grommet.data.api.model.ApiGeoLocation; import com.rockthevote.grommet.data.api.model.ApiName; +import com.rockthevote.grommet.data.api.model.ApiRegistrationHelper; import com.rockthevote.grommet.data.api.model.ApiRockyRequest; import com.rockthevote.grommet.data.api.model.ApiRockyRequestWrapper; import com.rockthevote.grommet.data.api.model.ApiSignature; @@ -49,15 +50,20 @@ import rx.schedulers.Schedulers; import timber.log.Timber; +import static com.rockthevote.grommet.data.db.model.Address.Type.ASSISTANT_ADDRESS; import static com.rockthevote.grommet.data.db.model.Address.Type.MAILING_ADDRESS; import static com.rockthevote.grommet.data.db.model.Address.Type.PREVIOUS_ADDRESS; import static com.rockthevote.grommet.data.db.model.Address.Type.REGISTRATION_ADDRESS; +import static com.rockthevote.grommet.data.db.model.ContactMethod.Type.ASSISTANT_PHONE; +import static com.rockthevote.grommet.data.db.model.Name.Type.ASSISTANT_NAME; +import static com.rockthevote.grommet.data.db.model.Name.Type.CURRENT_NAME; +import static com.rockthevote.grommet.data.db.model.Name.Type.PREVIOUS_NAME; import static com.rockthevote.grommet.data.db.model.RockyRequest.GENERATED_DATE; import static com.rockthevote.grommet.data.db.model.RockyRequest.STATUS; import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.ABANDONED; import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.FORM_COMPLETE; import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.IN_PROGRESS; -import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.REGISTER_FAILURE; +import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.REGISTER_SERVER_FAILURE; import static com.rockthevote.grommet.data.db.model.RockyRequest.Status.REGISTER_SUCCESS; import static java.util.Map.Entry; @@ -148,7 +154,7 @@ private void doWork(final RockyRequest rockyRequest) { .subscribe(regResponse -> { RockyRequest.Status status = !regResponse.isError() && regResponse.response().isSuccessful() - ? REGISTER_SUCCESS : REGISTER_FAILURE; + ? REGISTER_SUCCESS : REGISTER_SERVER_FAILURE; UploadNotification.notify(getApplicationContext(), status); @@ -164,7 +170,7 @@ private void doWork(final RockyRequest rockyRequest) { /** * check for

* {@link RockyRequest.Status#ABANDONED},

- * {@link RockyRequest.Status#REGISTER_FAILURE},

+ * {@link RockyRequest.Status#REGISTER_SERVER_FAILURE},

* {@link RockyRequest.Status#REGISTER_SUCCESS}

* as well as {@link RockyRequest.Status#IN_PROGRESS} that are more than one hour old * rows and delete them @@ -174,7 +180,7 @@ private void cleanup() { String completedRows = "" + STATUS + " IN (" + "'" + ABANDONED + "', " - + "'" + REGISTER_FAILURE + "'," + + "'" + REGISTER_SERVER_FAILURE + "'," + "'" + REGISTER_SUCCESS + "'" + ")"; @@ -255,7 +261,7 @@ public , Object> Observable> toEnumMap( * @param additionalInfo * @return {@link ApiRockyRequestWrapper} object */ - @SuppressWarnings("Convert2streamapi") + @SuppressWarnings({"Convert2streamapi", "ArraysAsListWithZeroOrOneArgument"}) private ApiRockyRequestWrapper zipRockyRequest(RockyRequest rockyRequest, EnumMap addresses, EnumMap contactMethods, @@ -265,47 +271,74 @@ private ApiRockyRequestWrapper zipRockyRequest(RockyRequest rockyRequest, EnumMap additionalInfo) { - ApiAddress apiRegAddress = ApiAddress.fromDb(addresses.get(REGISTRATION_ADDRESS)); + // Get address info objects + ApiAddress apiRegAddress = ApiAddress.fromAddress(addresses.get(REGISTRATION_ADDRESS)); ApiAddress apiMailAddress = rockyRequest.hasMailingAddress() ? - ApiAddress.fromDb(addresses.get(MAILING_ADDRESS)) : null; + ApiAddress.fromAddress(addresses.get(MAILING_ADDRESS)) : null; ApiAddress apiPrevAddress = rockyRequest.hasPreviousAddress() ? - ApiAddress.fromDb(addresses.get(PREVIOUS_ADDRESS)) : null; + ApiAddress.fromAddress(addresses.get(PREVIOUS_ADDRESS)) : null; - ApiName apiName = ApiName.fromDb(names.get(Name.Type.CURRENT_NAME)); + // Get name info objects + ApiName apiName = ApiName.fromName(names.get(CURRENT_NAME)); ApiName apiPrevName = rockyRequest.hasPreviousName() ? - ApiName.fromDb(names.get(Name.Type.PREVIOUS_NAME)) : null; - - List apiContactMethods = new ArrayList<>(contactMethods.size()); + ApiName.fromName(names.get(PREVIOUS_NAME)) : null; + // Get registrant contact info objects + List apiContactMethods = new ArrayList<>(); for (Entry entry : contactMethods.entrySet()) { - apiContactMethods.add(ApiContactMethod.fromDb(entry.getValue(), rockyRequest.phoneType())); + if (ASSISTANT_PHONE != entry.getKey()) { + apiContactMethods.add(ApiContactMethod.fromContactMethod( + entry.getValue(), rockyRequest.phoneType())); + } } + // Get voter classification objects List apiClassifications = new ArrayList<>(); for (Entry entry : classifications.entrySet()) { - apiClassifications.add(ApiVoterClassification.fromDb(entry.getValue())); + apiClassifications.add(ApiVoterClassification.fromVoterClassification(entry.getValue())); } + // Get voter ID objects List apiVoterIds = new ArrayList<>(); for (Entry entry : voterIds.entrySet()) { - apiVoterIds.add(ApiVoterId.fromDb(entry.getValue())); + apiVoterIds.add(ApiVoterId.fromVoterId(entry.getValue())); } + // get additional info objects List apiAdditionalInfo = new ArrayList<>(); for (Entry entry : additionalInfo.entrySet()) { - apiAdditionalInfo.add(ApiAdditionalInfo.fromDb(entry.getValue())); + apiAdditionalInfo.add(ApiAdditionalInfo.fromAdditionalInfo(entry.getValue())); } ApiSignature apiSignature = ApiSignature.fromDb(rockyRequest); ApiGeoLocation apiGeoLocation = ApiGeoLocation.fromDb(rockyRequest); + // build voter registration helper object + List helperContactMethods = new ArrayList<>(); + for (Entry entry : contactMethods.entrySet()) { + if (ASSISTANT_PHONE == entry.getKey()) { + helperContactMethods.add(ApiContactMethod.fromContactMethod( + entry.getValue(), rockyRequest.phoneType())); + } + } + + ApiRegistrationHelper helper = !rockyRequest.hasAssistant() ? null : + ApiRegistrationHelper.builder() + .address(ApiAddress.fromAddress(addresses.get(ASSISTANT_ADDRESS))) + .name(ApiName.fromName(names.get(ASSISTANT_NAME))) + .contactMethods(helperContactMethods) + .build(); + + // build voter registration api object ApiVoterRegistration apiVoterRegistration = ApiVoterRegistration.fromDb(rockyRequest, apiMailAddress, apiPrevAddress, apiRegAddress, apiName, apiPrevName, apiClassifications, - apiSignature, apiVoterIds, apiContactMethods, apiAdditionalInfo); + apiSignature, apiVoterIds, apiContactMethods, apiAdditionalInfo, helper); + // build voter records request api object ApiVoterRecordsRequest apiVoterRecordsRequest = ApiVoterRecordsRequest.fromDb(rockyRequest, apiVoterRegistration); + // build rocky request api object ApiRockyRequest apiRockyRequest = ApiRockyRequest.fromDb(rockyRequest, apiVoterRecordsRequest, apiGeoLocation); diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAdditionalInfo.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAdditionalInfo.java index 87a1130c..4a4c5e0a 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAdditionalInfo.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiAdditionalInfo.java @@ -34,7 +34,7 @@ abstract static class Builder { } @Nullable - public static ApiAdditionalInfo fromDb(AdditionalInfo additionalInfo) { + public static ApiAdditionalInfo fromAdditionalInfo(AdditionalInfo additionalInfo) { if (null == additionalInfo) { return null; } 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 98885c1b..fc28ed31 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 @@ -168,7 +168,7 @@ public void toJson(JsonWriter writer, ApiAddress value) throws IOException { } @Nullable - public static ApiAddress fromDb(Address address) { + public static ApiAddress fromAddress(Address address) { if(null == address){ return null; } diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiContactMethod.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiContactMethod.java index 0076dded..a0adf587 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiContactMethod.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiContactMethod.java @@ -37,14 +37,15 @@ abstract static class Builder{ } @Nullable - public static ApiContactMethod fromDb(ContactMethod contactMethod, PhoneType phoneType){ + public static ApiContactMethod fromContactMethod(ContactMethod contactMethod, PhoneType phoneType) { if (null == contactMethod) { return null; } List capabilities = new ArrayList<>(); // right now we only support phone (no fax) - if(contactMethod.type() == ContactMethod.Type.PHONE){ + if (contactMethod.type() == ContactMethod.Type.PHONE || + contactMethod.type() == ContactMethod.Type.ASSISTANT_PHONE) { capabilities.add(ContactMethod.Capability.VOICE.toString()); if(phoneType == PhoneType.MOBILE){ capabilities.add(ContactMethod.Capability.SMS.toString()); diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiName.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiName.java index 1ad83deb..1b2d6870 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiName.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiName.java @@ -49,7 +49,7 @@ abstract static class Builder { } @Nullable - public static ApiName fromDb(Name name) { + public static ApiName fromName(Name name) { if (null == name) { return null; } diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiRegistrationHelper.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiRegistrationHelper.java new file mode 100644 index 00000000..01638731 --- /dev/null +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiRegistrationHelper.java @@ -0,0 +1,46 @@ +package com.rockthevote.grommet.data.api.model; + +import com.google.auto.value.AutoValue; +import com.squareup.moshi.Json; +import com.squareup.moshi.JsonAdapter; +import com.squareup.moshi.Moshi; + +import java.util.List; + +@AutoValue +public abstract class ApiRegistrationHelper { + + @Json(name = "registration_helper_type") + public abstract String type(); + + public abstract ApiName name(); + + public abstract ApiAddress address(); + + @Json(name = "contact_methods") + abstract List contactMethods(); + + + public static JsonAdapter jsonAdapter(Moshi moshi) { + return new AutoValue_ApiRegistrationHelper.MoshiJsonAdapter(moshi); + } + + public static Builder builder() { + return new AutoValue_ApiRegistrationHelper.Builder() + .type("assistant"); + } + + @AutoValue.Builder + public abstract static class Builder { + + public abstract Builder type(String type); + + public abstract Builder name(ApiName name); + + public abstract Builder address(ApiAddress address); + + public abstract Builder contactMethods(List contactMethods); + + public abstract ApiRegistrationHelper build(); + } +} diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterClassification.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterClassification.java index e9179a35..04985909 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterClassification.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterClassification.java @@ -30,7 +30,7 @@ abstract static class Builder { abstract ApiVoterClassification build(); } - public static ApiVoterClassification fromDb(VoterClassification classification) { + public static ApiVoterClassification fromVoterClassification(VoterClassification classification) { return builder() .type(classification.type().toString()) .assertion(classification.assertion()) diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterId.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterId.java index c3aececc..0b67845b 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterId.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterId.java @@ -36,7 +36,7 @@ abstract static class Builder { abstract ApiVoterId build(); } - public static ApiVoterId fromDb(VoterId voterId) { + public static ApiVoterId fromVoterId(VoterId voterId) { return builder() .type(voterId.type().toString()) .stringValue(voterId.value()) diff --git a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterRegistration.java b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterRegistration.java index 34585e6c..c4993c82 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterRegistration.java +++ b/app/src/main/java/com/rockthevote/grommet/data/api/model/ApiVoterRegistration.java @@ -18,6 +18,10 @@ @AutoValue public abstract class ApiVoterRegistration { + @Json(name = "registration_helper") + @Nullable + abstract ApiRegistrationHelper registrationHelper(); + @Json(name = "date_of_birth") abstract String dateOfBirth(); @@ -61,6 +65,7 @@ public abstract class ApiVoterRegistration { @Json(name = "additional_info") abstract List additionalInfo(); + public static JsonAdapter jsonAdapter(Moshi moshi) { return new AutoValue_ApiVoterRegistration.MoshiJsonAdapter(moshi); } @@ -71,6 +76,8 @@ static Builder builder() { @AutoValue.Builder abstract static class Builder { + abstract Builder registrationHelper(ApiRegistrationHelper registrationHelper); + abstract Builder dateOfBirth(String value); abstract Builder mailingAddress(ApiAddress value); @@ -114,7 +121,8 @@ public static ApiVoterRegistration fromDb(RockyRequest rockyRequest, ApiSignature signature, List voterIds, List contactMethods, - List additionalInfo) { + List additionalInfo, + ApiRegistrationHelper registrationHelper) { return builder() .dateOfBirth(Dates.formatAsISO8601_ShortDate(rockyRequest.dateOfBirth())) .mailingAddress(mailingAddress) @@ -131,6 +139,7 @@ public static ApiVoterRegistration fromDb(RockyRequest rockyRequest, .voterIds(voterIds) .contactMethods(contactMethods) .additionalInfo(additionalInfo) + .registrationHelper(registrationHelper) .build(); } } diff --git a/app/src/main/java/com/rockthevote/grommet/data/db/DbOpenHelper.java b/app/src/main/java/com/rockthevote/grommet/data/db/DbOpenHelper.java index 71fb22cf..b5345d22 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/db/DbOpenHelper.java +++ b/app/src/main/java/com/rockthevote/grommet/data/db/DbOpenHelper.java @@ -44,7 +44,8 @@ public class DbOpenHelper extends SQLiteOpenHelper { + RockyRequest.LATITUDE + " REAL," + RockyRequest.LONGITUDE + " REAL," + RockyRequest.HAS_PREVIOUS_NAME + " INTEGER DEFAULT " + Db.BOOLEAN_FALSE + "," - + RockyRequest.HAS_PREVIOUS_ADDRESS + " INTEGER DEFAULT " + Db.BOOLEAN_FALSE + + RockyRequest.HAS_PREVIOUS_ADDRESS + " INTEGER DEFAULT " + Db.BOOLEAN_FALSE + "," + + RockyRequest.HAS_ASSISTANT + " INTEGER DEFAULT " + Db.BOOLEAN_FALSE + ")"; private static final String CREATE_ADDRESS = "" diff --git a/app/src/main/java/com/rockthevote/grommet/data/db/model/RockyRequest.java b/app/src/main/java/com/rockthevote/grommet/data/db/model/RockyRequest.java index e4b103c8..5a5bdd32 100644 --- a/app/src/main/java/com/rockthevote/grommet/data/db/model/RockyRequest.java +++ b/app/src/main/java/com/rockthevote/grommet/data/db/model/RockyRequest.java @@ -41,6 +41,7 @@ public abstract class RockyRequest implements Parcelable, BaseColumns { public static final String LONGITUDE = "longitude"; public static final String HAS_PREVIOUS_NAME = "has_previous_name"; public static final String HAS_PREVIOUS_ADDRESS = "has_previous_address"; + public static final String HAS_ASSISTANT = "has_assistant"; public static final String SELECT_BY_ID = "" + "SELECT * FROM " @@ -107,6 +108,8 @@ public abstract class RockyRequest implements Parcelable, BaseColumns { public abstract boolean hasPreviousAddress(); + public abstract boolean hasAssistant(); + public static final Func1 MAPPER = cursor -> { long id = Db.getLong(cursor, _ID); Status status = Status.fromString(Db.getString(cursor, STATUS)); @@ -131,12 +134,13 @@ public abstract class RockyRequest implements Parcelable, BaseColumns { long longitude = Db.getLong(cursor, LONGITUDE); boolean hasPreviousName = Db.getBoolean(cursor, HAS_PREVIOUS_NAME); boolean hasPreviousAddress = Db.getBoolean(cursor, HAS_PREVIOUS_ADDRESS); + boolean hasAssistant = Db.getBoolean(cursor, HAS_ASSISTANT); return new AutoValue_RockyRequest(id, status, language, phoneType, partnerId, optInEmail, optInSMS, optInVolunteer, partnerOptInSMS, partnerOptInEmail, sourceTrackingId, partnerTrackingId, openTrackingId, generatedDate, dateOfBirth, hasMailingAddress, race, party, signature, - latitude, longitude, hasPreviousName, hasPreviousAddress); + latitude, longitude, hasPreviousName, hasPreviousAddress, hasAssistant); }; public static final class Builder { @@ -262,6 +266,11 @@ public Builder hasPreviousAddress(boolean hasPreviousAddress) { return this; } + public Builder hasAssistant(boolean hasAssistant) { + values.put(HAS_ASSISTANT, hasAssistant); + return this; + } + public ContentValues build() { return values; } @@ -333,7 +342,8 @@ public enum Status { ABANDONED("abandoned"), FORM_COMPLETE("form_complete"), REGISTER_SUCCESS("register_success"), - REGISTER_FAILURE("register_failure"); + REGISTER_SERVER_FAILURE("register_server_failure"), + REGISTER_CLIENT_FAILURE("register_client_failure"); private final String status; diff --git a/app/src/main/java/com/rockthevote/grommet/ui/UploadNotification.java b/app/src/main/java/com/rockthevote/grommet/ui/UploadNotification.java index bd0d662e..c4bb6156 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/UploadNotification.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/UploadNotification.java @@ -72,7 +72,7 @@ int getNotifTitle(RockyRequest.Status status) { case REGISTER_SUCCESS: return R.string.upload_notification_title_success; default: - case REGISTER_FAILURE: + case REGISTER_SERVER_FAILURE: return R.string.upload_notification_title_failure; } } @@ -82,7 +82,7 @@ private static int getNotificationId(RockyRequest.Status status) { case REGISTER_SUCCESS: return NOTIFICATION_SUCCESS_ID; default: - case REGISTER_FAILURE: + case REGISTER_SERVER_FAILURE: return NOTIFICATION_FAILURE_ID; } } @@ -92,7 +92,7 @@ private static String getNotificationTag(RockyRequest.Status status) { case REGISTER_SUCCESS: return NOTIFICATION_SUCCESS_TAG; default: - case REGISTER_FAILURE: + case REGISTER_SERVER_FAILURE: return NOTIFICATION_FAILURE_TAG; } } 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 d1aaeaed..2b7dc95f 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 @@ -1,7 +1,5 @@ package com.rockthevote.grommet.ui.registration; -import android.app.Activity; -import android.content.Context; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.TextInputLayout; @@ -98,7 +96,7 @@ public class AdditionalInfoFragment extends BaseRegistrationFragment { @Inject BriteDatabase db; private ObservableValidator validator; - private CompositeSubscription subscriptions; + private CompositeSubscription subscriptions = new CompositeSubscription(); private EnumAdapter raceEnumAdapter; private EnumAdapter partyEnumAdapter; @@ -161,7 +159,6 @@ public void onActivityCreated(@Nullable Bundle savedInstanceState) { @Override public void onResume() { super.onResume(); - subscriptions = new CompositeSubscription(); phoneFormatter = new PhoneNumberFormattingTextWatcher(); phone.addTextChangedListener(phoneFormatter); diff --git a/app/src/main/java/com/rockthevote/grommet/ui/registration/AssistantInfoFragment.java b/app/src/main/java/com/rockthevote/grommet/ui/registration/AssistantInfoFragment.java index aa884d4b..4bcf9cb5 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/registration/AssistantInfoFragment.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/registration/AssistantInfoFragment.java @@ -2,25 +2,70 @@ import android.os.Bundle; import android.support.annotation.Nullable; +import android.support.design.widget.TextInputLayout; +import android.telephony.PhoneNumberFormattingTextWatcher; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.CheckBox; +import android.widget.EditText; import com.f2prateek.rx.preferences.Preference; +import com.jakewharton.rxbinding.widget.RxTextView; +import com.mobsandgeeks.saripaar.Validator; +import com.mobsandgeeks.saripaar.annotation.Checked; import com.rockthevote.grommet.R; +import com.rockthevote.grommet.data.db.model.ContactMethod; +import com.rockthevote.grommet.data.db.model.RockyRequest; import com.rockthevote.grommet.data.prefs.CurrentRockyRequestId; +import com.rockthevote.grommet.ui.misc.ObservableValidator; +import com.rockthevote.grommet.ui.views.AddressView; +import com.rockthevote.grommet.ui.views.NameView; +import com.rockthevote.grommet.util.PhoneOrEmpty; import com.squareup.sqlbrite.BriteDatabase; +import java.util.concurrent.TimeUnit; + import javax.inject.Inject; +import butterknife.BindView; import butterknife.ButterKnife; +import butterknife.OnCheckedChanged; +import rx.Observable; +import rx.schedulers.Schedulers; +import rx.subscriptions.CompositeSubscription; + +import static com.rockthevote.grommet.data.db.Db.DEBOUNCE; +import static com.rockthevote.grommet.data.db.model.ContactMethod.Type.ASSISTANT_PHONE; public class AssistantInfoFragment extends BaseRegistrationFragment { + @BindView(R.id.assistant_fields) View assistantFields; + + @BindView(R.id.assistant_name) NameView nameView; + + @BindView(R.id.assistant_address) AddressView addressView; + + @PhoneOrEmpty(messageResId = R.string.phone_format_error) + @BindView(R.id.til_assistant_phone) TextInputLayout phoneTIL; + + @BindView(R.id.assistant_phone) EditText phoneEditText; + + @BindView(R.id.checkbox_has_assistant) CheckBox hasAssistant; + + @Checked + @BindView(R.id.checkbox_assistant_affirmation) CheckBox assistantAffirmation; + @Inject @CurrentRockyRequestId Preference rockyRequestRowId; @Inject BriteDatabase db; + private ObservableValidator validator; + + private PhoneNumberFormattingTextWatcher phoneFormatter; + + private CompositeSubscription subscriptions = new CompositeSubscription(); + @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -32,5 +77,59 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ButterKnife.bind(this, view); + + Validator.registerAnnotation(PhoneOrEmpty.class); + validator = new ObservableValidator(this, getActivity()); + + } + + @Override + public void onResume() { + super.onResume(); + phoneFormatter = new PhoneNumberFormattingTextWatcher(); + phoneEditText.addTextChangedListener(phoneFormatter); + + subscriptions.add(RxTextView.afterTextChangeEvents(phoneEditText) + .observeOn(Schedulers.io()) + .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) + .skip(1) + .subscribe(event -> { + ContactMethod.insertOrUpdate(db, rockyRequestRowId.get(), ASSISTANT_PHONE, + new ContactMethod.Builder() + .value(event.editable().toString()) + .build() + ); + })); + + } + + @Override + public void onPause() { + super.onPause(); + phoneEditText.removeTextChangedListener(phoneFormatter); + subscriptions.unsubscribe(); + } + + @OnCheckedChanged(R.id.checkbox_has_assistant) + public void onHasAssistantChecked(boolean checked) { + assistantFields.setVisibility(checked ? View.VISIBLE : View.GONE); + + db.update(RockyRequest.TABLE, + new RockyRequest.Builder() + .hasAssistant(checked) + .build(), + RockyRequest._ID + " = ? ", String.valueOf(rockyRequestRowId.get())); + + } + + @Override + public Observable verify() { + + if (!hasAssistant.isChecked()) { + return super.verify(); + } + + return Observable.zip(nameView.verify(), addressView.verify(), validator.validate(), + (name, address, other) -> name && address && other); } } diff --git a/app/src/main/java/com/rockthevote/grommet/ui/registration/RegistrationPagerAdapter.java b/app/src/main/java/com/rockthevote/grommet/ui/registration/RegistrationPagerAdapter.java index 3bb682ca..8934bbd7 100644 --- a/app/src/main/java/com/rockthevote/grommet/ui/registration/RegistrationPagerAdapter.java +++ b/app/src/main/java/com/rockthevote/grommet/ui/registration/RegistrationPagerAdapter.java @@ -20,8 +20,8 @@ public RegistrationPagerAdapter(FragmentManager fm, Context context) { titles.put(0, context.getString(R.string.fragment_title_new_registrant)); titles.put(1, context.getString(R.string.fragment_title_personal_info)); titles.put(2, context.getString(R.string.fragment_title_additional_info)); -// titles.put(3, context.getString(R.string.fragment_title_assistant_info)); - titles.put(3, context.getString(R.string.fragment_title_review)); + titles.put(3, context.getString(R.string.fragment_title_assistant_info)); + titles.put(4, context.getString(R.string.fragment_title_review)); } @Override @@ -37,9 +37,9 @@ private Fragment getNewFragment(int position) { return new PersonalInfoFragment(); case 2: return new AdditionalInfoFragment(); -// case 3: -// return new AssistantInfoFragment(); case 3: + return new AssistantInfoFragment(); + case 4: return new ReviewAndConfirmFragment(); default: throw new IllegalStateException("Unknown fragment position: " + position); @@ -55,7 +55,7 @@ public Object instantiateItem(ViewGroup container, int position) { @Override public int getCount() { - return 4; + return 5; } @Override 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 7423fd25..4b1a6fac 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 @@ -122,83 +122,84 @@ public AddressView(Context context, AttributeSet attrs, int defStyleAttr) { @Override protected void onFinishInflate() { super.onFinishInflate(); - ButterKnife.bind(this); - validator = new ObservableValidator(this, getContext()); - - switch (type) { - case REGISTRATION_ADDRESS: - sectionTitle.setText(R.string.section_label_registration_address); - break; - case MAILING_ADDRESS: - sectionTitle.setText(R.string.section_label_mailing_address); - break; - case PREVIOUS_ADDRESS: - sectionTitle.setText(R.string.section_label_previous_address); - break; - case ASSISTANT_ADDRESS: - sectionTitle.setText(R.string.section_label_registration_address); - } - - countyAdapter = ArrayAdapter.createFromResource(getContext(), - R.array.pa_counties, android.R.layout.simple_list_item_1); - countyAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1); - - countySpinner.setAdapter(countyAdapter); - countySpinner.setHeight((int) getResources().getDimension(R.dimen.list_pop_up_max_height)); - countySpinner.setOnItemClickListener((adapterView, view, i, l) -> { - countySpinner.getEditText().setText(countyAdapter.getItem(i)); - countySpinner.dismiss(); - }); - - stateAdapter = ArrayAdapter.createFromResource(getContext(), - R.array.states, android.R.layout.simple_list_item_1); - stateAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1); - - stateSpinner.setAdapter(stateAdapter); - stateSpinner.setHeight((int) getResources().getDimension(R.dimen.list_pop_up_max_height)); - stateSpinner.setOnItemClickListener((adapterView, view, i, l) -> { - stateSpinner.getEditText().setText(stateAdapter.getItem(i)); - - 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); + if (!isInEditMode()) { + ButterKnife.bind(this); + validator = new ObservableValidator(this, getContext()); + + switch (type) { + case REGISTRATION_ADDRESS: + sectionTitle.setText(R.string.section_label_registration_address); + break; + case MAILING_ADDRESS: + sectionTitle.setText(R.string.section_label_mailing_address); + break; + case PREVIOUS_ADDRESS: + sectionTitle.setText(R.string.section_label_previous_address); + break; + case ASSISTANT_ADDRESS: + sectionTitle.setText(R.string.section_label_registration_address); } - stateSpinner.dismiss(); - }); - stateSpinner.getEditText().setText(stateAdapter.getItem(stateAdapter.getPosition(PA_ABREV))); + countyAdapter = ArrayAdapter.createFromResource(getContext(), + R.array.pa_counties, android.R.layout.simple_list_item_1); + countyAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1); + + countySpinner.setAdapter(countyAdapter); + countySpinner.setHeight((int) getResources().getDimension(R.dimen.list_pop_up_max_height)); + countySpinner.setOnItemClickListener((adapterView, view, i, l) -> { + countySpinner.getEditText().setText(countyAdapter.getItem(i)); + countySpinner.dismiss(); + }); + + stateAdapter = ArrayAdapter.createFromResource(getContext(), + R.array.states, android.R.layout.simple_list_item_1); + stateAdapter.setDropDownViewResource(android.R.layout.simple_list_item_1); + + stateSpinner.setAdapter(stateAdapter); + stateSpinner.setHeight((int) getResources().getDimension(R.dimen.list_pop_up_max_height)); + stateSpinner.setOnItemClickListener((adapterView, view, i, l) -> { + stateSpinner.getEditText().setText(stateAdapter.getItem(i)); + + 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))); + } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - - subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(streetEditText), - RxTextView.afterTextChangeEvents(unitEditText), - RxTextView.afterTextChangeEvents(cityEditText), - RxTextView.afterTextChangeEvents(stateSpinner.getEditText()), - RxTextView.afterTextChangeEvents(zipEditText), - RxTextView.afterTextChangeEvents(stateSpinner.getEditText()), - (street, unit, city, state, zip, county) -> new Address.Builder() - .streetName(street.editable().toString()) - .subAddress(unit.editable().toString()) - .municipalJurisdiction(city.editable().toString()) - .state(state.editable().toString()) - .zip(zip.editable().toString()) - .county(county.editable().toString()) - .build()) - .observeOn(Schedulers.io()) - .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) - .subscribe(contentValues -> { - Address.insertOrUpdate(db, rockyRequestRowId.get(), type, contentValues); - })); - + if (!isInEditMode()) { + subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(streetEditText), + RxTextView.afterTextChangeEvents(unitEditText), + RxTextView.afterTextChangeEvents(cityEditText), + RxTextView.afterTextChangeEvents(stateSpinner.getEditText()), + RxTextView.afterTextChangeEvents(zipEditText), + RxTextView.afterTextChangeEvents(stateSpinner.getEditText()), + (street, unit, city, state, zip, county) -> new Address.Builder() + .streetName(street.editable().toString()) + .subAddress(unit.editable().toString()) + .municipalJurisdiction(city.editable().toString()) + .state(state.editable().toString()) + .zip(zip.editable().toString()) + .county(county.editable().toString()) + .build()) + .observeOn(Schedulers.io()) + .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) + .subscribe(contentValues -> { + Address.insertOrUpdate(db, rockyRequestRowId.get(), type, contentValues); + })); + } } @Override 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 fad24362..7acd9f19 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 @@ -115,59 +115,62 @@ public NameView(Context context, AttributeSet attrs, int defStyleAttr) { @Override protected void onFinishInflate() { super.onFinishInflate(); - ButterKnife.bind(this); - - validator = new ObservableValidator(this, getContext()); - - switch (type) { - case CURRENT_NAME: - sectionTitle.setText(R.string.section_label_name); - break; - case PREVIOUS_NAME: - sectionTitle.setText(R.string.section_label_previous_name); - break; - case ASSISTANT_NAME: - sectionTitle.setText(R.string.section_label_name); - break; - } + if (!isInEditMode()) { + ButterKnife.bind(this); + + validator = new ObservableValidator(this, getContext()); + + switch (type) { + case CURRENT_NAME: + sectionTitle.setText(R.string.section_label_name); + break; + case PREVIOUS_NAME: + sectionTitle.setText(R.string.section_label_previous_name); + break; + case ASSISTANT_NAME: + sectionTitle.setText(R.string.section_label_name); + break; + } - titleEnumAdapter = new EnumAdapter<>(getContext(), Name.Prefix.class); - titleSpinner.setAdapter(titleEnumAdapter); - titleSpinner.setOnItemClickListener((adapterView, view, i, l) -> { - titleSpinner.getEditText().setText(titleEnumAdapter.getItem(i).toString()); - titleSpinner.dismiss(); - }); - - suffixEnumAdapter = new EnumAdapter<>(getContext(), Name.Suffix.class); - suffixSpinner.setAdapter(suffixEnumAdapter); - suffixSpinner.setOnItemClickListener((adapterView, view, i, l) -> { - suffixSpinner.getEditText().setText(suffixEnumAdapter.getItem(i).toString()); - suffixSpinner.dismiss(); - }); + titleEnumAdapter = new EnumAdapter<>(getContext(), Name.Prefix.class); + titleSpinner.setAdapter(titleEnumAdapter); + titleSpinner.setOnItemClickListener((adapterView, view, i, l) -> { + titleSpinner.getEditText().setText(titleEnumAdapter.getItem(i).toString()); + titleSpinner.dismiss(); + }); + + suffixEnumAdapter = new EnumAdapter<>(getContext(), Name.Suffix.class); + suffixSpinner.setAdapter(suffixEnumAdapter); + suffixSpinner.setOnItemClickListener((adapterView, view, i, l) -> { + suffixSpinner.getEditText().setText(suffixEnumAdapter.getItem(i).toString()); + suffixSpinner.dismiss(); + }); + } } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); - - subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(firstNameEditText), - RxTextView.afterTextChangeEvents(middleNameEditText), - RxTextView.afterTextChangeEvents(lastNameEditText), - RxTextView.afterTextChangeEvents(titleSpinner.getEditText()), - RxTextView.afterTextChangeEvents(suffixSpinner.getEditText()), - (firstName, middleName, lastName, title, suffix) -> new Name.Builder() - .firstName(firstName.editable().toString()) - .middleName(middleName.editable().toString()) - .lastName(lastName.editable().toString()) - .prefix(Prefix.fromString(title.editable().toString())) - .suffix(Suffix.fromString(suffix.editable().toString())) - .build()) - .observeOn(Schedulers.io()) - .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) - .skip(1) - .subscribe(contentValues -> { - Name.insertOrUpdate(db, rockyRequestRowId.get(), type, contentValues); - })); + if (!isInEditMode()) { + subscriptions.add(Observable.combineLatest(RxTextView.afterTextChangeEvents(firstNameEditText), + RxTextView.afterTextChangeEvents(middleNameEditText), + RxTextView.afterTextChangeEvents(lastNameEditText), + RxTextView.afterTextChangeEvents(titleSpinner.getEditText()), + RxTextView.afterTextChangeEvents(suffixSpinner.getEditText()), + (firstName, middleName, lastName, title, suffix) -> new Name.Builder() + .firstName(firstName.editable().toString()) + .middleName(middleName.editable().toString()) + .lastName(lastName.editable().toString()) + .prefix(Prefix.fromString(title.editable().toString())) + .suffix(Suffix.fromString(suffix.editable().toString())) + .build()) + .observeOn(Schedulers.io()) + .debounce(DEBOUNCE, TimeUnit.MILLISECONDS) + .skip(1) + .subscribe(contentValues -> { + Name.insertOrUpdate(db, rockyRequestRowId.get(), type, contentValues); + })); + } } @Override diff --git a/app/src/main/res/layout/fragment_assistant_info.xml b/app/src/main/res/layout/fragment_assistant_info.xml index f54a2104..b9da992b 100644 --- a/app/src/main/res/layout/fragment_assistant_info.xml +++ b/app/src/main/res/layout/fragment_assistant_info.xml @@ -1,89 +1,136 @@ - - - - - - - + android:text="@string/label_has_assistant" + /> - + tools:visibility="gone" + > - + - + android:layout_columnSpan="2" + android:layout_marginEnd="@dimen/content_margin" + android:layout_marginStart="@dimen/content_margin" + android:paddingTop="@dimen/content_area_padding" + android:text="@string/section_label_assistant_name" + android:textAppearance="@android:style/TextAppearance.Material.Subhead"/> - + - + + + + + + + + + + + + + + + + + - \ No newline at end of file + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5401d4f8..4f3508fc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -106,7 +106,10 @@ Check "I do not know" if you don\'t know your PennDOT number Check "I do not know" if you don\'t know your SSN last four Did someone helped you with this form? - Helper Info + Helper Name + Helper Address + Helper Contact Info + I have reviewed the above information, and it is true and accurate to the best of my knowledge. Review diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index f526c8d7..a9e95956 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,7 +11,8 @@ @color/colorPrimary @color/colorPrimaryDark @color/colorAccent - @android:style/Widget.Material.Spinner.Underlined + @android:color/holo_red_dark +