/**
* Wire
* Copyright (C) 2016 Wire Swiss GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.waz.zclient.pages.main.profile.preferences.dialogs;
import android.os.Bundle;
import android.support.design.widget.TextInputLayout;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.animation.AnimationUtils;
import com.waz.api.CredentialsUpdateListener;
import com.waz.api.UsernameValidation;
import com.waz.api.UsernameValidationError;
import com.waz.api.UsernamesRequestCallback;
import com.waz.zclient.BaseActivity;
import com.waz.zclient.R;
import com.waz.zclient.core.controllers.tracking.events.settings.SetUsernameEvent;
import com.waz.zclient.core.stores.IStoreFactory;
import com.waz.zclient.pages.BaseDialogFragment;
import com.waz.zclient.tracking.GlobalTrackingController;
import com.waz.zclient.utils.ViewUtils;
import com.waz.zclient.views.LoadingIndicatorView;
import java.util.Locale;
public class ChangeUsernamePreferenceDialogFragment extends BaseDialogFragment<ChangeUsernamePreferenceDialogFragment.Container> {
public static final String TAG = ChangeUsernamePreferenceDialogFragment.class.getSimpleName();
private static final String ARG_USERNAME = "ARG_USERNAME";
private static final String ARG_CANCEL_ENABLED = "ARG_CANCEL_ENABLED";
private TextInputLayout usernameInputLayout;
private AppCompatEditText usernameEditText;
private LoadingIndicatorView usernameVerifyingIndicator;
private View okButton;
private View backButton;
private String inputUsername = "";
private String suggestedUsername;
private boolean editingEnabled = true;
private boolean cancelEnabled = true;
private TextWatcher usernameTextWatcher = new TextWatcher() {
private String lastText = "";
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
String currentText = charSequence.toString();
if (getStoreFactory() != null &&
getStoreFactory().getZMessagingApiStore().getApi().getUsernames().isUsernameValid(charSequence.toString()).reason() != UsernameValidationError.INVALID_CHARACTERS) {
lastText = currentText;
}
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void afterTextChanged(Editable editable) {
String normalText = editable.toString();
String lowercaseString = normalText.toLowerCase(Locale.getDefault());
if (!lowercaseString.equals(normalText)) {
usernameEditText.setText(lowercaseString);
} else {
IStoreFactory storeFactory = getStoreFactory();
if (storeFactory == null || storeFactory.isTornDown()) {
return;
}
UsernameValidation validation = storeFactory.getZMessagingApiStore().getApi().getUsernames().isUsernameValid(normalText);
if (!validation.isValid()) {
usernameInputLayout.setError(getErrorMessage(validation.reason()));
if (validation.reason() == UsernameValidationError.INVALID_CHARACTERS) {
usernameEditText.setText(lastText);
editBoxShakeAnimation();
} else if (validation.reason() == UsernameValidationError.TOO_LONG) {
usernameEditText.setText(lastText);
}
} else {
usernameInputLayout.setError("");
if (!storeFactory.getZMessagingApiStore().getApi().getSelf().getUsername().equals(normalText)) {
storeFactory.getZMessagingApiStore().getApi().getUsernames().isUsernameAvailable(normalText, usernameAvailableCallback);
}
}
}
usernameEditText.setSelection(usernameEditText.getText().length());
}
};
private CredentialsUpdateListener setUsernameCallback = new CredentialsUpdateListener() {
@Override
public void onUpdated() {
getContainer().onUsernameChanged(inputUsername);
dismiss();
}
@Override
public void onUpdateFailed(int code, String message, String label) {
usernameInputLayout.setError(getString(R.string.pref__account_action__dialog__change_username__error_unknown));
enableEditing();
}
};
private UsernamesRequestCallback usernameAvailableCallback = new UsernamesRequestCallback() {
@Override
public void onUsernameRequestResult(final UsernameValidation[] validation) {
if (!validation[0].username().equals(usernameEditText.getText().toString())) {
return;
}
if (validation[0].isValid()) {
usernameInputLayout.setError("");
okButton.setEnabled(editingEnabled);
} else {
usernameInputLayout.setError(getErrorMessage(validation[0].reason()));
okButton.setEnabled(false);
}
}
@Override
public void onRequestFailed(Integer errorCode) {
usernameInputLayout.setError(getString(R.string.pref__account_action__dialog__change_username__error_unknown));
enableEditing();
editBoxShakeAnimation();
}
};
private View.OnClickListener okButtonClickListener = new View.OnClickListener() {
@Override
public void onClick(View view) {
inputUsername = usernameEditText.getText().toString();
if (TextUtils.isEmpty(inputUsername)) {
return;
}
IStoreFactory storeFactory = getStoreFactory();
if (storeFactory != null &&
!storeFactory.isTornDown() &&
storeFactory.getZMessagingApiStore().getApi().getSelf().getUsername().equals(inputUsername)) {
dismiss();
return;
}
UsernameValidation validation = getStoreFactory().getZMessagingApiStore().getApi().getUsernames().isUsernameValid(inputUsername);
if (!validation.isValid()) {
editBoxShakeAnimation();
return;
}
((BaseActivity) getActivity()).injectJava(GlobalTrackingController.class).tagEvent(new SetUsernameEvent(inputUsername.length()));
disableEditing();
getStoreFactory().getZMessagingApiStore().getApi().getSelf().setUsername(inputUsername, setUsernameCallback);
}
};
private void disableEditing() {
editingEnabled = false;
usernameEditText.setEnabled(false);
usernameVerifyingIndicator.show();
okButton.setEnabled(false);
backButton.setEnabled(false);
}
private void enableEditing() {
editingEnabled = true;
usernameVerifyingIndicator.hide();
okButton.setEnabled(true);
backButton.setEnabled(true);
usernameEditText.setEnabled(true);
}
public ChangeUsernamePreferenceDialogFragment() {
}
public static ChangeUsernamePreferenceDialogFragment newInstance(String currentUsername, boolean cancellable) {
ChangeUsernamePreferenceDialogFragment fragment = new ChangeUsernamePreferenceDialogFragment();
Bundle args = new Bundle();
args.putString(ARG_USERNAME, currentUsername);
args.putBoolean(ARG_CANCEL_ENABLED, cancellable);
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setStyle(STYLE_NO_FRAME, R.style.Theme_Dark_Preferences);
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
if (getDialog() != null && getDialog().getWindow() != null) {
getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
}
super.onViewCreated(view, savedInstanceState);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
suggestedUsername = getArguments().getString(ARG_USERNAME, "");
cancelEnabled = getArguments().getBoolean(ARG_CANCEL_ENABLED);
View view = inflater.inflate(R.layout.fragment_change_username_preference_dialog, container, false);
usernameInputLayout = ViewUtils.getView(view, R.id.til__change_username);
usernameEditText = ViewUtils.getView(view, R.id.acet__change_username);
usernameVerifyingIndicator = ViewUtils.getView(view, R.id.liv__username_verifying_indicator);
okButton = ViewUtils.getView(view, R.id.tv__ok_button);
backButton = ViewUtils.getView(view, R.id.tv__back_button);
usernameEditText.setText(suggestedUsername);
usernameEditText.setSelection(suggestedUsername.length());
usernameVerifyingIndicator.setType(LoadingIndicatorView.SPINNER);
usernameVerifyingIndicator.hide();
setCancelable(false);
return view;
}
@Override
public void onStart() {
super.onStart();
usernameEditText.addTextChangedListener(usernameTextWatcher);
backButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (!cancelEnabled && getStoreFactory() != null) {
CredentialsUpdateListener emptyCredentialsListener = new CredentialsUpdateListener() {
@Override
public void onUpdated() {
}
@Override
public void onUpdateFailed(int code, String message, String label) {
}
};
getStoreFactory().getZMessagingApiStore().getApi().getSelf().setUsername(suggestedUsername, emptyCredentialsListener);
}
dismiss();
}
});
okButton.setOnClickListener(okButtonClickListener);
usernameEditText.requestFocus();
}
@Override
public void onStop() {
super.onStop();
usernameEditText.removeTextChangedListener(usernameTextWatcher);
backButton.setOnClickListener(null);
okButton.setOnClickListener(null);
}
private String getErrorMessage(UsernameValidationError errorCode) {
switch (errorCode) {
case TOO_LONG:
return " ";
case TOO_SHORT:
return " ";
case INVALID_CHARACTERS:
return " ";
case ALREADY_TAKEN:
return getString(R.string.pref__account_action__dialog__change_username__error_already_taken);
default:
return getString(R.string.pref__account_action__dialog__change_username__error_unknown);
}
}
private void editBoxShakeAnimation() {
usernameEditText.startAnimation(AnimationUtils.loadAnimation(getContext(), R.anim.shake_animation));
}
public interface Container {
void onUsernameChanged(String username);
}
}