Removed butterknife from login activity (#5380)

* Removed butterknife view bindings

* Migrated click listeners to view binding

* Migrate onEditorAction to use ViewBinding

* Finally, removed butterknife
This commit is contained in:
Paul Hawke 2023-11-11 07:54:08 -06:00 committed by GitHub
parent 9620f6eee0
commit 861d2b9bf6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 56 additions and 110 deletions

View file

@ -14,10 +14,8 @@ import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView;
import androidx.annotation.ColorRes; import androidx.annotation.ColorRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -27,8 +25,7 @@ import androidx.appcompat.app.AppCompatDelegate;
import androidx.core.app.NavUtils; import androidx.core.app.NavUtils;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.google.android.material.textfield.TextInputLayout; import fr.free.nrw.commons.databinding.ActivityLoginBinding;
import fr.free.nrw.commons.utils.ActivityUtils; import fr.free.nrw.commons.utils.ActivityUtils;
import java.util.Locale; import java.util.Locale;
import org.wikipedia.AppAdapter; import org.wikipedia.AppAdapter;
@ -42,15 +39,9 @@ import org.wikipedia.login.LoginResult;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; import javax.inject.Named;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.OnEditorAction;
import butterknife.OnFocusChange;
import fr.free.nrw.commons.BuildConfig; import fr.free.nrw.commons.BuildConfig;
import fr.free.nrw.commons.R; import fr.free.nrw.commons.R;
import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.Utils;
import fr.free.nrw.commons.WelcomeActivity;
import fr.free.nrw.commons.contributions.MainActivity; import fr.free.nrw.commons.contributions.MainActivity;
import fr.free.nrw.commons.di.ApplicationlessInjection; import fr.free.nrw.commons.di.ApplicationlessInjection;
import fr.free.nrw.commons.kvstore.JsonKvStore; import fr.free.nrw.commons.kvstore.JsonKvStore;
@ -87,30 +78,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
@Inject @Inject
SystemThemeUtils systemThemeUtils; SystemThemeUtils systemThemeUtils;
@BindView(R.id.login_button) private ActivityLoginBinding binding;
Button loginButton;
@BindView(R.id.login_username)
EditText usernameEdit;
@BindView(R.id.login_password)
EditText passwordEdit;
@BindView(R.id.login_two_factor)
EditText twoFactorEdit;
@BindView(R.id.error_message_container)
ViewGroup errorMessageContainer;
@BindView(R.id.error_message)
TextView errorMessage;
@BindView(R.id.login_credentials)
TextView loginCredentials;
@BindView(R.id.two_factor_container)
TextInputLayout twoFactorContainer;
ProgressDialog progressDialog; ProgressDialog progressDialog;
private AppCompatDelegate delegate; private AppCompatDelegate delegate;
private LoginTextWatcher textWatcher = new LoginTextWatcher(); private LoginTextWatcher textWatcher = new LoginTextWatcher();
@ -120,6 +88,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
final String saveErrorMessage ="errorMessage"; final String saveErrorMessage ="errorMessage";
final String saveUsername="username"; final String saveUsername="username";
final String savePassword="password"; final String savePassword="password";
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
@ -133,18 +102,26 @@ public class LoginActivity extends AccountAuthenticatorActivity {
getDelegate().installViewFactory(); getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState); getDelegate().onCreate(savedInstanceState);
setContentView(R.layout.activity_login); binding = ActivityLoginBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
ButterKnife.bind(this); binding.loginUsername.addTextChangedListener(textWatcher);
binding.loginPassword.addTextChangedListener(textWatcher);
binding.loginTwoFactor.addTextChangedListener(textWatcher);
usernameEdit.addTextChangedListener(textWatcher); binding.skipLogin.setOnClickListener(view -> skipLogin());
passwordEdit.addTextChangedListener(textWatcher); binding.forgotPassword.setOnClickListener(view -> forgotPassword());
twoFactorEdit.addTextChangedListener(textWatcher); binding.aboutPrivacyPolicy.setOnClickListener(view -> onPrivacyPolicyClicked());
binding.signUpButton.setOnClickListener(view -> signUp());
binding.loginButton.setOnClickListener(view -> performLogin());
binding.loginPassword.setOnEditorActionListener(this::onEditorAction);
binding.loginPassword.setOnFocusChangeListener(this::onPasswordFocusChanged);
if (ConfigUtils.isBetaFlavour()) { if (ConfigUtils.isBetaFlavour()) {
loginCredentials.setText(getString(R.string.login_credential)); binding.loginCredentials.setText(getString(R.string.login_credential));
} else { } else {
loginCredentials.setVisibility(View.GONE); binding.loginCredentials.setVisibility(View.GONE);
} }
} }
/** /**
@ -152,16 +129,14 @@ public class LoginActivity extends AccountAuthenticatorActivity {
* @param view The keyboard * @param view The keyboard
* @param hasFocus Set to true if the keyboard has focus * @param hasFocus Set to true if the keyboard has focus
*/ */
@OnFocusChange(R.id.login_password)
void onPasswordFocusChanged(View view, boolean hasFocus) { void onPasswordFocusChanged(View view, boolean hasFocus) {
if (!hasFocus) { if (!hasFocus) {
ViewUtil.hideKeyboard(view); ViewUtil.hideKeyboard(view);
} }
} }
@OnEditorAction(R.id.login_password) boolean onEditorAction(TextView textView, int actionId, KeyEvent keyEvent) {
boolean onEditorAction(int actionId, KeyEvent keyEvent) { if (binding.loginButton.isEnabled()) {
if (loginButton.isEnabled()) {
if (actionId == IME_ACTION_DONE) { if (actionId == IME_ACTION_DONE) {
performLogin(); performLogin();
return true; return true;
@ -174,8 +149,7 @@ public class LoginActivity extends AccountAuthenticatorActivity {
} }
@OnClick(R.id.skip_login) protected void skipLogin() {
void skipLogin() {
new AlertDialog.Builder(this).setTitle(R.string.skip_login_title) new AlertDialog.Builder(this).setTitle(R.string.skip_login_title)
.setMessage(R.string.skip_login_message) .setMessage(R.string.skip_login_message)
.setCancelable(false) .setCancelable(false)
@ -187,18 +161,15 @@ public class LoginActivity extends AccountAuthenticatorActivity {
.show(); .show();
} }
@OnClick(R.id.forgot_password) protected void forgotPassword() {
void forgotPassword() {
Utils.handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL)); Utils.handleWebUrl(this, Uri.parse(BuildConfig.FORGOT_PASSWORD_URL));
} }
@OnClick(R.id.about_privacy_policy) protected void onPrivacyPolicyClicked() {
void onPrivacyPolicyClicked() {
Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL)); Utils.handleWebUrl(this, Uri.parse(BuildConfig.PRIVACY_POLICY_URL));
} }
@OnClick(R.id.sign_up_button) protected void signUp() {
void signUp() {
Intent intent = new Intent(this, SignupActivity.class); Intent intent = new Intent(this, SignupActivity.class);
startActivity(intent); startActivity(intent);
} }
@ -236,23 +207,23 @@ public class LoginActivity extends AccountAuthenticatorActivity {
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
usernameEdit.removeTextChangedListener(textWatcher); binding.loginUsername.removeTextChangedListener(textWatcher);
passwordEdit.removeTextChangedListener(textWatcher); binding.loginPassword.removeTextChangedListener(textWatcher);
twoFactorEdit.removeTextChangedListener(textWatcher); binding.loginTwoFactor.removeTextChangedListener(textWatcher);
delegate.onDestroy(); delegate.onDestroy();
if(null!=loginClient) { if(null!=loginClient) {
loginClient.cancel(); loginClient.cancel();
} }
binding = null;
super.onDestroy(); super.onDestroy();
} }
@OnClick(R.id.login_button)
public void performLogin() { public void performLogin() {
Timber.d("Login to start!"); Timber.d("Login to start!");
final String username = usernameEdit.getText().toString(); final String username = binding.loginUsername.getText().toString();
final String rawUsername = usernameEdit.getText().toString().trim(); final String rawUsername = binding.loginUsername.getText().toString().trim();
final String password = passwordEdit.getText().toString(); final String password = binding.loginPassword.getText().toString();
String twoFactorCode = twoFactorEdit.getText().toString(); String twoFactorCode = binding.loginTwoFactor.getText().toString();
showLoggingProgressBar(); showLoggingProgressBar();
doLogin(username, password, twoFactorCode); doLogin(username, password, twoFactorCode);
@ -389,9 +360,9 @@ public class LoginActivity extends AccountAuthenticatorActivity {
public void askUserForTwoFactorAuth() { public void askUserForTwoFactorAuth() {
progressDialog.dismiss(); progressDialog.dismiss();
twoFactorContainer.setVisibility(VISIBLE); binding.twoFactorContainer.setVisibility(VISIBLE);
twoFactorEdit.setVisibility(VISIBLE); binding.loginTwoFactor.setVisibility(VISIBLE);
twoFactorEdit.requestFocus(); binding.loginTwoFactor.requestFocus();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY);
showMessageAndCancelDialog(R.string.login_failed_2fa_needed); showMessageAndCancelDialog(R.string.login_failed_2fa_needed);
@ -422,15 +393,15 @@ public class LoginActivity extends AccountAuthenticatorActivity {
} }
private void showMessage(@StringRes int resId, @ColorRes int colorResId) { private void showMessage(@StringRes int resId, @ColorRes int colorResId) {
errorMessage.setText(getString(resId)); binding.errorMessage.setText(getString(resId));
errorMessage.setTextColor(ContextCompat.getColor(this, colorResId)); binding.errorMessage.setTextColor(ContextCompat.getColor(this, colorResId));
errorMessageContainer.setVisibility(VISIBLE); binding.errorMessageContainer.setVisibility(VISIBLE);
} }
private void showMessage(String message, @ColorRes int colorResId) { private void showMessage(String message, @ColorRes int colorResId) {
errorMessage.setText(message); binding.errorMessage.setText(message);
errorMessage.setTextColor(ContextCompat.getColor(this, colorResId)); binding.errorMessage.setTextColor(ContextCompat.getColor(this, colorResId));
errorMessageContainer.setVisibility(VISIBLE); binding.errorMessageContainer.setVisibility(VISIBLE);
} }
private AppCompatDelegate getDelegate() { private AppCompatDelegate getDelegate() {
@ -451,9 +422,11 @@ public class LoginActivity extends AccountAuthenticatorActivity {
@Override @Override
public void afterTextChanged(Editable editable) { public void afterTextChanged(Editable editable) {
boolean enabled = usernameEdit.getText().length() != 0 && passwordEdit.getText().length() != 0 boolean enabled = binding.loginUsername.getText().length() != 0 &&
&& (BuildConfig.DEBUG || twoFactorEdit.getText().length() != 0 || twoFactorEdit.getVisibility() != VISIBLE); binding.loginPassword.getText().length() != 0 &&
loginButton.setEnabled(enabled); (BuildConfig.DEBUG || binding.loginTwoFactor.getText().length() != 0 ||
binding.loginTwoFactor.getVisibility() != VISIBLE);
binding.loginButton.setEnabled(enabled);
} }
} }
@ -471,22 +444,22 @@ public class LoginActivity extends AccountAuthenticatorActivity {
} else { } else {
outState.putBoolean(saveProgressDailog,false); outState.putBoolean(saveProgressDailog,false);
} }
outState.putString(saveErrorMessage,errorMessage.getText().toString()); //Save the errorMessage outState.putString(saveErrorMessage,binding.errorMessage.getText().toString()); //Save the errorMessage
outState.putString(saveUsername,getUsername()); // Save the username outState.putString(saveUsername,getUsername()); // Save the username
outState.putString(savePassword,getPassword()); // Save the password outState.putString(savePassword,getPassword()); // Save the password
} }
private String getUsername() { private String getUsername() {
return usernameEdit.getText().toString(); return binding.loginUsername.getText().toString();
} }
private String getPassword(){ private String getPassword(){
return passwordEdit.getText().toString(); return binding.loginPassword.getText().toString();
} }
@Override @Override
protected void onRestoreInstanceState(final Bundle savedInstanceState) { protected void onRestoreInstanceState(final Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState); super.onRestoreInstanceState(savedInstanceState);
usernameEdit.setText(savedInstanceState.getString(saveUsername)); binding.loginUsername.setText(savedInstanceState.getString(saveUsername));
passwordEdit.setText(savedInstanceState.getString(savePassword)); binding.loginPassword.setText(savedInstanceState.getString(savePassword));
if(savedInstanceState.getBoolean(saveProgressDailog)) { if(savedInstanceState.getBoolean(saveProgressDailog)) {
performLogin(); performLogin();
} }

View file

@ -10,6 +10,7 @@ import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.Button import android.widget.Button
import android.widget.TextView
import androidx.test.core.app.ApplicationProvider import androidx.test.core.app.ApplicationProvider
import fr.free.nrw.commons.R import fr.free.nrw.commons.R
import fr.free.nrw.commons.TestAppAdapter import fr.free.nrw.commons.TestAppAdapter
@ -55,7 +56,7 @@ class LoginActivityUnitTests {
private lateinit var keyEvent: KeyEvent private lateinit var keyEvent: KeyEvent
@Mock @Mock
private lateinit var loginButton: Button private lateinit var textView: TextView
@Mock @Mock
private lateinit var bundle: Bundle private lateinit var bundle: Bundle
@ -95,40 +96,12 @@ class LoginActivityUnitTests {
fun testOnEditorActionCaseDefault() { fun testOnEditorActionCaseDefault() {
val method: Method = LoginActivity::class.java.getDeclaredMethod( val method: Method = LoginActivity::class.java.getDeclaredMethod(
"onEditorAction", "onEditorAction",
TextView::class.java,
Int::class.java, Int::class.java,
KeyEvent::class.java KeyEvent::class.java
) )
method.isAccessible = true method.isAccessible = true
method.invoke(activity, 0, keyEvent) method.invoke(activity, textView, 0, keyEvent)
}
@Test
@Throws(Exception::class)
fun testOnEditorActionCaseLoginEnabledFirstCase() {
Whitebox.setInternalState(activity, "loginButton", loginButton)
`when`(loginButton.isEnabled).thenReturn(true)
val method: Method = LoginActivity::class.java.getDeclaredMethod(
"onEditorAction",
Int::class.java,
KeyEvent::class.java
)
method.isAccessible = true
method.invoke(activity, EditorInfo.IME_ACTION_DONE, keyEvent)
}
@Test
@Throws(Exception::class)
fun testOnEditorActionCaseLoginEnabledSecondCase() {
Whitebox.setInternalState(activity, "loginButton", loginButton)
`when`(loginButton.isEnabled).thenReturn(true)
`when`(keyEvent.keyCode).thenReturn(KeyEvent.KEYCODE_ENTER)
val method: Method = LoginActivity::class.java.getDeclaredMethod(
"onEditorAction",
Int::class.java,
KeyEvent::class.java
)
method.isAccessible = true
method.invoke(activity, 0, keyEvent)
} }
@Test @Test