Skip to content

Instantly share code, notes, and snippets.

@rohmanhakim
Last active December 22, 2016 14:58
Show Gist options
  • Save rohmanhakim/650fe0185a194da662bd112269929f49 to your computer and use it in GitHub Desktop.
Save rohmanhakim/650fe0185a194da662bd112269929f49 to your computer and use it in GitHub Desktop.
package com.rohmanhakim.androidreactivedemo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import com.jakewharton.rxbinding.view.RxView;
import com.jakewharton.rxbinding.widget.RxTextView;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava.RxJavaCallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;
import rx.Observable;
import rx.Subscriber;
import rx.android.schedulers.AndroidSchedulers;
import rx.functions.Func1;
import rx.functions.Func2;
import rx.functions.Func3;
import rx.functions.Func4;
import rx.schedulers.Schedulers;
public class ReactiveRegistrationDemoActivity extends AppCompatActivity {
EditText etEmail;
TextView textEmailAlert;
EditText etPassword;
TextView textPasswordAlert;
EditText etPasswordConfirmation;
TextView textPasswordConfirmationAlert;
Button btnSubmit;
Retrofit retrofit;
SampleService service;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_registration_demo);
// Inisialisasi form
etEmail = (EditText) findViewById(R.id.et_email);
textEmailAlert = (TextView) findViewById(R.id.text_email_alert);
etPassword = (EditText) findViewById(R.id.et_password);
textPasswordAlert = (TextView) findViewById(R.id.text_password_alert);
etPasswordConfirmation = (EditText) findViewById(R.id.et_password_confirmation);
textPasswordConfirmationAlert = (TextView) findViewById(R.id.text_password_confirmation_alert);
btnSubmit = (Button) findViewById(R.id.btn_submit);
// Inisialisasi state (keadaan) default form
textEmailAlert.setVisibility(View.GONE);
textPasswordAlert.setVisibility(View.GONE);
textPasswordConfirmationAlert.setVisibility(View.GONE);
btnSubmit.setEnabled(false);
// Inisialisasi retrofit
retrofit = new Retrofit.Builder()
.baseUrl(getString(R.string.base_url))
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build();
// Inisialisasi service sample
service = retrofit.create(SampleService.class);
// ================================================================================
// OBSERVABLES
// ================================================================================
// Ketika user mengetik lebih dari 3 karakter, dan jeda 100ms, cek email dari backend
// Return true jika email user sudah terpakai
Observable<Boolean> emailStream = RxTextView.textChanges(etEmail)
.map(new Func1<CharSequence, String>() {
@Override
public String call(CharSequence charSequence) {
return charSequence.toString(); // ubah charsequence hasil ketikan user ke string
}
})
.filter(new Func1<String, Boolean>() {
@Override
public Boolean call(String input) {
return input.length() > 3; // ketika user menegetik lebih dari 3 karakter
}
})
.debounce(100,TimeUnit.MILLISECONDS) // ketika behenti 100ms
.flatMap(new Func1<String, Observable<Boolean>>() { // Ubah stream yg berisi beberap list existing user...
@Override // ke satu stream berisi existing user
public Observable<Boolean> call(String input) {
return checkIfEmailExistFromAPI(input); // panggil API dari backend dan lakukan pengecekan
}
});
// Periksa apakah password yang diketik user < 6 karakter
// Return true jika password yang diketik user < 6 karakter
Observable<Boolean> passwordStream = RxTextView.textChanges(etPassword)
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) {
return !TextUtils.isEmpty(charSequence)
&& charSequence.toString().trim().length() < 6;
}
});
// Periksa apakah password confirmation user sesuai dengan password sebelumnya
// Return true jika password confirmation tidak sesuai
Observable<Boolean> passwordConfirmationStream = Observable.merge( // Menggabungkan dua stream menjadi satu
RxTextView.textChanges(etPassword)
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) { // Periksa saat user mengetik field password
return !charSequence.toString().trim().equals(etPasswordConfirmation.getText().toString());
}
}),
RxTextView.textChanges(etPasswordConfirmation)
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) { // Periksa saat user menegtik di field password confirmation
return !charSequence.toString().trim().equals(etPassword.getText().toString());
}
})
);
// Periksa apakah ada field yang masih kosong
// Return true jika ada field yang masih kosong
Observable<Boolean> emptyFieldStream = Observable.combineLatest( // menggabungkan hasil terakhir dari beberapa stream
RxTextView.textChanges(etEmail) // Return true jika field email kosong
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) {
return TextUtils.isEmpty(charSequence);
}
}),
RxTextView.textChanges(etPassword) // Return true jika field password kosong
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) {
return TextUtils.isEmpty(charSequence);
}
}),
RxTextView.textChanges(etPasswordConfirmation) // Return true jika field password conirmation kosong
.map(new Func1<CharSequence, Boolean>() {
@Override
public Boolean call(CharSequence charSequence) {
return TextUtils.isEmpty(charSequence);
}
}),
new Func3<Boolean, Boolean, Boolean, Boolean>() {
@Override // return true jika ada salah satu dari 3 stream diatas yg me-return true
public Boolean call(Boolean emailEmpty, Boolean passwordEmpty, Boolean passwordConfirmationEmpty) {
return emailEmpty || passwordEmpty || passwordConfirmationEmpty;
}
}
);
// Periksa apakah ada filed yang masih belum valid (menggabungkan semua pengecekan)
// Return true jika ada field yang masih belum valid
Observable<Boolean> invalidFieldsStream = Observable.combineLatest(
emailStream,
passwordStream,
passwordConfirmationStream,
emptyFieldStream, new Func4<Boolean, Boolean, Boolean, Boolean, Boolean>() {
@Override
public Boolean call(Boolean emailInvalid, Boolean passwordInvalid, Boolean passwordConfirmationInvalid, Boolean emptyFieldExist) {
return !emailInvalid && !passwordInvalid && !passwordConfirmationInvalid && !emptyFieldExist;
}
});
// ================================================================================
// SUBSCRIBERS
// ================================================================================
// Inisialisasi subscriber untuk field email
// subscribe ke stream email, menampilkan peringatan ketika email yg diketik user sudah dipakai di backend
Subscriber<Boolean> emailSubscriber = new Subscriber<Boolean>() {
@Override
public void onCompleted() {
Log.d("rx","Email stream completed");
}
@Override
public void onError(Throwable e) {
Log.d("rx",e.getMessage());
}
@Override
public void onNext(Boolean emailExist) {
Log.d("emailSubscriber",String.valueOf(emailExist.booleanValue()));
showEmailExistAlert(emailExist.booleanValue());
}
};
// Inisialisasi subscriber untuk field password
Subscriber<Boolean> passwordSubscriber = new Subscriber<Boolean>() {
@Override
public void onCompleted() {
Log.d("rx","Password stream completed");
}
@Override
public void onError(Throwable e) {
Log.d("rx",e.getMessage());
}
@Override
public void onNext(Boolean passwordLessThanLimit) {
Log.d("passwordSubscriber",String.valueOf(passwordLessThanLimit.booleanValue()));
showPasswordMinimalAlert(passwordLessThanLimit.booleanValue());
}
};
// Inisialisasi subscriber untuk field password confirmation
Subscriber<Boolean> passwordConfirmationSubscriber = new Subscriber<Boolean>() {
@Override
public void onCompleted() {
Log.d("rx","Password confirmation stream completed");
}
@Override
public void onError(Throwable e) {
Log.d("rx",e.getMessage());
}
@Override
public void onNext(Boolean passwordConfirmationDontMatch) {
Log.d("passwordConfirmation",String.valueOf(passwordConfirmationDontMatch.booleanValue()));
showPasswordConfirmationAlert(passwordConfirmationDontMatch.booleanValue());
}
};
// Inisialisasi subscriber untuk field yang belum valid
// Enable tombol submit jika tidak ada lagi field yg belum valid
Subscriber<Boolean> invalidFieldsSubscriber = new Subscriber<Boolean>() {
@Override
public void onCompleted() {
Log.d("rx","All field valid stream completed");
}
@Override
public void onError(Throwable e) {
Log.d("rx",e.getMessage());
}
@Override
public void onNext(Boolean invalidFieldExist) {
Log.d("invalidFieldsStream",String.valueOf(invalidFieldExist.booleanValue()));
btnSubmit.setEnabled(invalidFieldExist);
}
};
// ================================================================================
// SUBSCRIBING
// ================================================================================
emailStream.subscribe(emailSubscriber);
passwordStream.subscribe(passwordSubscriber);
passwordConfirmationStream.subscribe(passwordConfirmationSubscriber);
invalidFieldsStream.subscribe(invalidFieldsSubscriber);
}
// Ambil daftar email dari APi, kemudian cek apakah email user sudah dipakai
public Observable<Boolean> checkIfEmailExistFromAPI(final String input){
return service.getEmails()
.flatMap(new Func1<List<String>, Observable<String>>() { // Mengubah stream of List<String> menjadi stream of String
@Override
public Observable<String> call(List<String> strings) {
return Observable.from(strings);
}
}).contains(input) // Cek apakah email di emit oleh stream sebelumnya
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
}
public void showEmailExistAlert(boolean value){
if(value) {
textEmailAlert.setText(getString(R.string.email_exist_alert));
textEmailAlert.setVisibility(View.VISIBLE);
} else {
textEmailAlert.setVisibility(View.GONE);
}
}
public void showPasswordMinimalAlert(boolean value){
if(value) {
textPasswordAlert.setText(getString(R.string.password_minimal_alert));
textPasswordAlert.setVisibility(View.VISIBLE);
} else {
textPasswordAlert.setVisibility(View.GONE);
}
}
public void showPasswordConfirmationAlert(boolean value){
if(value){
textPasswordConfirmationAlert.setText(R.string.password_confirmation_does_not_match_alert);
textPasswordConfirmationAlert.setVisibility(View.VISIBLE);
} else {
textPasswordConfirmationAlert.setVisibility(View.GONE);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment