Last active
May 14, 2019 23:02
-
-
Save swanson/10695086 to your computer and use it in GitHub Desktop.
Tungsten: A simple, rock-for-brains validation mini-library for Android.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LoginActivity extends Activity { | |
@InjectView(R.id.login_form) | |
private LoginForm mLoginForm; | |
// SNIP | |
public void onLoginButtonPressed() { | |
LoginFormValidator validator = new LoginFormValidator(); | |
validator.validate(mLoginForm.getUsername(), | |
mLoginForm.getPassword(), | |
mLoginForm.getPasswordConfirmation()); | |
if (validator.hasErrors()) { | |
// Apply errors to each field | |
// EditText use setError() | |
// Other views are displayed in an error dialog or in a summary TextView | |
Tungsten.showErrors(this, validator); | |
} else { | |
// POST to API | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LoginFormValidator extends BaseValidator { | |
public void validate(String username, String password, String passwordConfirmation) { | |
resetErrors(); | |
if (isNullOrEmpty(username)) { | |
addError(R.id.email, R.string.error_field_required); | |
} | |
if (isNullOrEmpty(password)) { | |
addError(R.id.password, R.string.error_field_required); | |
} | |
if (!password.equals(passwordConfirmation)) { | |
addError(R.id.password_confirmation, R.string.error_password_does_not_match); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.junit.Test; | |
public class LoginFormValidatorTest { | |
private final LoginFormValidator validator = new LoginFormValidator(); | |
@Test | |
public void testThatEmptyUsernameIsInvalid() { | |
validator.validate("", "pw", "pw"); | |
assertThat(validator).hasError(R.id.email); | |
} | |
@Test | |
public void testThatEmptyPasswordIsInvalid() { | |
validator.validate("username", "", "pw"); | |
assertThat(validator).hasError(R.id.password) | |
.withMessage(R.string.error_field_required); | |
} | |
@Test | |
public void testThatPasswordConfirmationMustMatch() { | |
validator.validate("username", "pw", "wp"); | |
assertThat(validator).hasError(R.id.password); | |
assertThat(validator).hasError(R.id.password_confirmation); | |
} | |
@Test | |
public void testThatAllCorrectFieldsHasNoErrors() { | |
validator.validate("username", "pw", "pw"); | |
assertThat(validator).hasNoErrors(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class LoginForm extends BaseForm { | |
@InjectView(R.id.username) | |
private EditText mUsername; | |
@InjectView(R.id.password) | |
private EditText mPassword; | |
@InjectView(R.id.password_confirm) | |
private EditText mPasswordConfirmation; | |
public LoginForm(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
@Override | |
protected void onLayoutInflated(View view) { | |
ButterKnife.inject(this, view); | |
} | |
public String getUsername() { | |
return mUsername.getText().toString(); | |
} | |
public String getPassword() { | |
return mPassword.getText().toString(); | |
} | |
public String getPasswordConfirmation() { | |
return mPasswordConfirmation.getText().toString(); | |
} | |
@Override | |
protected int getLayoutId() { | |
return R.layout.login_form; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Tungsten
A simple, rock-for-brains validation mini-library for Android.
Why?
I think there is value in separating Form models from activities and Validator objects from Form models. In the same spirit as
ActiveRecord::Validations
, we "link" errors to field based on the id - in Rails-land this is the#id
of the HTML element, in Android-land this is the@+id
of the XML element.Because we only rely on Android's R class (for view Ids and string resources) to set errors, we can test Validators in pure jUnit tests (yah fast tests!) and rely on
Tungsten.showErrors()
to wire everything up in our activity.Why not?
The downside is that Validator will only work with non-Android inputs (if you want to use jUnit, if you use Robolectric then it's good to go).
A Form model will probably have references to Android widgets (see example), so there is a bit of cruft in order to get the String values out of the EditTexts.
Why not use Android Saripaar?
I don't really like annotations for validation - it gets weird for non-trivial cases, especially if you need to combine multiple fields. I'd rather just write some simple Java code. Having to specify an order on everything is weird.
The ValidationListener interface seems Android-ish but overly complicated. Asynchronous stuff seems like API response handling rather than validation to me.
This is stupid.
I'm not in love with it either, but hey - just playing around with this idea!