From 70b44820fdbb1500ee5087c4086f90fa76d5467c Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Thu, 1 Feb 2018 08:24:08 +0100 Subject: [PATCH] Start applying MVP --- .idea/misc.xml | 2 +- .../slam/AfterTextChangedListener.java | 19 +++ .../slam/EditorActionDoneListener.java | 21 ++++ .../slam/activity/DummyLoginPresenter.java | 62 ++++++++++ .../slam/activity/LoginActivity.java | 109 ++++++++++++++++-- .../slam/activity/MainActivity.java | 5 +- .../{ => abstr}/ThemedAppCompatActivity.java | 4 +- .../slam/mvp_contracts/LoginContract.java | 26 +++++ mobile/src/main/res/layout/activity_login.xml | 17 ++- mobile/src/main/res/values/strings.xml | 1 + 10 files changed, 245 insertions(+), 21 deletions(-) create mode 100644 mobile/src/main/java/de/vanitasvitae/slam/AfterTextChangedListener.java create mode 100644 mobile/src/main/java/de/vanitasvitae/slam/EditorActionDoneListener.java create mode 100644 mobile/src/main/java/de/vanitasvitae/slam/activity/DummyLoginPresenter.java rename mobile/src/main/java/de/vanitasvitae/slam/activity/{ => abstr}/ThemedAppCompatActivity.java (96%) create mode 100644 mobile/src/main/java/de/vanitasvitae/slam/mvp_contracts/LoginContract.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 635999d..ba7052b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -24,7 +24,7 @@ - + diff --git a/mobile/src/main/java/de/vanitasvitae/slam/AfterTextChangedListener.java b/mobile/src/main/java/de/vanitasvitae/slam/AfterTextChangedListener.java new file mode 100644 index 0000000..77101ac --- /dev/null +++ b/mobile/src/main/java/de/vanitasvitae/slam/AfterTextChangedListener.java @@ -0,0 +1,19 @@ +package de.vanitasvitae.slam; + +import android.text.Editable; +import android.text.TextWatcher; + +/** + * Abstract TextWatcher, that has method stubs for all methods except {@link TextWatcher#afterTextChanged(Editable)}. + */ +public abstract class AfterTextChangedListener implements TextWatcher { + @Override + public void beforeTextChanged(CharSequence s, int start, int count, int after) { + // Do nothing + } + + @Override + public void onTextChanged(CharSequence s, int start, int before, int count) { + // Do nothing + } +} diff --git a/mobile/src/main/java/de/vanitasvitae/slam/EditorActionDoneListener.java b/mobile/src/main/java/de/vanitasvitae/slam/EditorActionDoneListener.java new file mode 100644 index 0000000..d09a827 --- /dev/null +++ b/mobile/src/main/java/de/vanitasvitae/slam/EditorActionDoneListener.java @@ -0,0 +1,21 @@ +package de.vanitasvitae.slam; + +import android.view.KeyEvent; +import android.view.inputmethod.EditorInfo; +import android.widget.TextView; + +/** + * Abstract listener, that listens on a TextView for ActionDone events. + */ +public abstract class EditorActionDoneListener implements TextView.OnEditorActionListener { + @Override + public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { + if (actionId == EditorInfo.IME_ACTION_DONE) { + onEditorActionDone(v); + return true; + } + return false; + } + + public abstract void onEditorActionDone(TextView v); +} diff --git a/mobile/src/main/java/de/vanitasvitae/slam/activity/DummyLoginPresenter.java b/mobile/src/main/java/de/vanitasvitae/slam/activity/DummyLoginPresenter.java new file mode 100644 index 0000000..3a71c0f --- /dev/null +++ b/mobile/src/main/java/de/vanitasvitae/slam/activity/DummyLoginPresenter.java @@ -0,0 +1,62 @@ +package de.vanitasvitae.slam.activity; + +import android.os.Handler; + +import de.vanitasvitae.slam.mvp_contracts.LoginContract; + +/** + * Dummy presenter, that has no model. + * This is used to demonstrate the capabilities of the view. + * Created by Paul Schaub on 01.02.18. + */ +public class DummyLoginPresenter implements LoginContract.Presenter { + + private LoginContract.View view; + + public DummyLoginPresenter(LoginContract.View view) { + this.view = view; + } + + @Override + public void jidChanged(String jid) { + if (jid.length() < 10) { + view.showInvalidJidError(); + } else { + view.hideInvalidJidError(); + } + } + + @Override + public void passwordChanged(String password) { + if (password.length() < 5) { + view.showInvalidPasswordError(); + } else if(!password.equals("swordfish")) { + view.showIncorrectPasswordError(); + } else { + view.hidePasswordError(); + } + } + + @Override + public void loginClicked() { + // show indicator + view.showProgressIndicator(); + final Handler handler = new Handler(); + + // Hide indicator + handler.postDelayed(new Runnable() { + @Override + public void run() { + view.hideProgressIndicator(); + } + }, 2000); + + // startActivity + handler.postDelayed(new Runnable() { + @Override + public void run() { + view.navigateToMainActivity(); + } + }, 2500); + } +} diff --git a/mobile/src/main/java/de/vanitasvitae/slam/activity/LoginActivity.java b/mobile/src/main/java/de/vanitasvitae/slam/activity/LoginActivity.java index 1bf23d1..062ab2b 100644 --- a/mobile/src/main/java/de/vanitasvitae/slam/activity/LoginActivity.java +++ b/mobile/src/main/java/de/vanitasvitae/slam/activity/LoginActivity.java @@ -3,28 +3,52 @@ package de.vanitasvitae.slam.activity; import android.content.Intent; import android.os.Bundle; import android.support.design.widget.TextInputEditText; +import android.support.design.widget.TextInputLayout; import android.support.v7.widget.Toolbar; -import android.view.KeyEvent; +import android.text.Editable; import android.view.Menu; -import android.view.inputmethod.EditorInfo; +import android.view.View; +import android.view.WindowManager; +import android.widget.Button; +import android.widget.ProgressBar; import android.widget.TextView; +import android.widget.Toast; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; +import de.vanitasvitae.slam.AfterTextChangedListener; +import de.vanitasvitae.slam.EditorActionDoneListener; import de.vanitasvitae.slam.R; +import de.vanitasvitae.slam.activity.abstr.ThemedAppCompatActivity; +import de.vanitasvitae.slam.mvp_contracts.LoginContract; -public class LoginActivity extends ThemedAppCompatActivity { +public class LoginActivity extends ThemedAppCompatActivity implements LoginContract.View { + + // Presenter of this view + private LoginContract.Presenter presenter; @BindView(R.id.toolbar) Toolbar toolbar; + @BindView(R.id.progressbar) + ProgressBar progressBar; + + @BindView(R.id.login_username_layout) + TextInputLayout inputUsernameLayout; + @BindView(R.id.login_username) TextInputEditText inputUsername; + @BindView(R.id.login_password_layout) + TextInputLayout inputPasswordLayout; + @BindView(R.id.login_password) TextInputEditText inputPassword; + @BindView(R.id.button_login) + Button buttonLogin; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -33,22 +57,34 @@ public class LoginActivity extends ThemedAppCompatActivity { setSupportActionBar(toolbar); - inputPassword.setOnEditorActionListener(new TextView.OnEditorActionListener() { + this.presenter = new DummyLoginPresenter(this); + + // attempt login on editor action done + inputPassword.setOnEditorActionListener(new EditorActionDoneListener() { @Override - public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { - if (actionId == EditorInfo.IME_ACTION_DONE) { - login(); - return true; - } - return false; + public void onEditorActionDone(TextView v) { + login(); + } + }); + + inputUsername.addTextChangedListener(new AfterTextChangedListener() { + @Override + public void afterTextChanged(Editable s) { + presenter.jidChanged(s.toString()); + } + }); + + inputPassword.addTextChangedListener(new AfterTextChangedListener() { + @Override + public void afterTextChanged(Editable s) { + presenter.passwordChanged(s.toString()); } }); } @OnClick(R.id.button_login) void login() { - startActivity(new Intent(this, MainActivity.class)); - finish(); + presenter.loginClicked(); } @Override @@ -56,5 +92,54 @@ public class LoginActivity extends ThemedAppCompatActivity { getMenuInflater().inflate(R.menu.menu_login, menu); return true; } + + @Override + public void showInvalidJidError() { + inputUsernameLayout.setError(getResources().getText(R.string.error_invalid_jid)); + } + + @Override + public void showInvalidPasswordError() { + inputPasswordLayout.setError(getResources().getText(R.string.error_invalid_password)); + } + + @Override + public void showIncorrectPasswordError() { + inputPasswordLayout.setError(getResources().getText(R.string.error_incorrect_password)); + } + + @Override + public void hideInvalidJidError() { + inputUsernameLayout.setError(null); + } + + @Override + public void hidePasswordError() { + inputPasswordLayout.setError(null); + } + + @Override + public void showServerNotFoundError() { + Toast.makeText(this, R.string.error_server_not_found, Toast.LENGTH_LONG).show(); + } + + @Override + public void showProgressIndicator() { + progressBar.setVisibility(View.VISIBLE); + getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE, + WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + } + + @Override + public void hideProgressIndicator() { + progressBar.setVisibility(View.GONE); + getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); + } + + @Override + public void navigateToMainActivity() { + startActivity(new Intent(this, MainActivity.class)); + finish(); + } } diff --git a/mobile/src/main/java/de/vanitasvitae/slam/activity/MainActivity.java b/mobile/src/main/java/de/vanitasvitae/slam/activity/MainActivity.java index 0cf04c5..643d478 100644 --- a/mobile/src/main/java/de/vanitasvitae/slam/activity/MainActivity.java +++ b/mobile/src/main/java/de/vanitasvitae/slam/activity/MainActivity.java @@ -7,16 +7,13 @@ import android.support.v4.widget.DrawerLayout; import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.Toolbar; import android.util.Log; -import android.view.LayoutInflater; import android.view.Menu; -import android.view.View; import android.widget.FrameLayout; -import android.widget.ImageView; -import android.widget.TextView; import butterknife.BindView; import butterknife.ButterKnife; import de.vanitasvitae.slam.R; +import de.vanitasvitae.slam.activity.abstr.ThemedAppCompatActivity; /** * Created by vanitas on 22.01.18. diff --git a/mobile/src/main/java/de/vanitasvitae/slam/activity/ThemedAppCompatActivity.java b/mobile/src/main/java/de/vanitasvitae/slam/activity/abstr/ThemedAppCompatActivity.java similarity index 96% rename from mobile/src/main/java/de/vanitasvitae/slam/activity/ThemedAppCompatActivity.java rename to mobile/src/main/java/de/vanitasvitae/slam/activity/abstr/ThemedAppCompatActivity.java index a7cefe8..dfba76e 100644 --- a/mobile/src/main/java/de/vanitasvitae/slam/activity/ThemedAppCompatActivity.java +++ b/mobile/src/main/java/de/vanitasvitae/slam/activity/abstr/ThemedAppCompatActivity.java @@ -1,4 +1,4 @@ -package de.vanitasvitae.slam.activity; +package de.vanitasvitae.slam.activity.abstr; import android.annotation.SuppressLint; import android.content.Intent; @@ -13,7 +13,7 @@ import java.util.Arrays; import de.vanitasvitae.slam.R; /** - * Created by Paul Schaub on 27.01.18. + * AppCompatActivity that can easily be themed. */ public abstract class ThemedAppCompatActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener { diff --git a/mobile/src/main/java/de/vanitasvitae/slam/mvp_contracts/LoginContract.java b/mobile/src/main/java/de/vanitasvitae/slam/mvp_contracts/LoginContract.java new file mode 100644 index 0000000..f3c8b7b --- /dev/null +++ b/mobile/src/main/java/de/vanitasvitae/slam/mvp_contracts/LoginContract.java @@ -0,0 +1,26 @@ +package de.vanitasvitae.slam.mvp_contracts; + +/** + * Model-View-Presenter contract of the login screen. + * Created by Paul Schaub on 01.02.18. + */ +public interface LoginContract { + + interface View { + void showInvalidJidError(); + void hideInvalidJidError(); + void showInvalidPasswordError(); + void showIncorrectPasswordError(); + void hidePasswordError(); + void showServerNotFoundError(); + void showProgressIndicator(); + void hideProgressIndicator(); + void navigateToMainActivity(); + } + + interface Presenter { + void jidChanged(String jid); + void passwordChanged(String password); + void loginClicked(); + } +} diff --git a/mobile/src/main/res/layout/activity_login.xml b/mobile/src/main/res/layout/activity_login.xml index b698cc0..12f00c1 100644 --- a/mobile/src/main/res/layout/activity_login.xml +++ b/mobile/src/main/res/layout/activity_login.xml @@ -52,8 +52,10 @@ + android:layout_height="wrap_content" + app:errorEnabled="true"> + android:layout_height="wrap_content" + app:errorEnabled="true"> + + diff --git a/mobile/src/main/res/values/strings.xml b/mobile/src/main/res/values/strings.xml index 42dfe4a..349d211 100644 --- a/mobile/src/main/res/values/strings.xml +++ b/mobile/src/main/res/values/strings.xml @@ -27,5 +27,6 @@ Contacts Bookmarks Settings + Server not found