Last active
December 22, 2016 14:58
-
-
Save rohmanhakim/650fe0185a194da662bd112269929f49 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
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