diff --git a/Habitica/res/layout/activity_login.xml b/Habitica/res/layout/activity_login.xml
index 356dfed6d..425637fff 100644
--- a/Habitica/res/layout/activity_login.xml
+++ b/Habitica/res/layout/activity_login.xml
@@ -2,7 +2,8 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- xmlns:tools="http://schemas.android.com/tools">
+ xmlns:tools="http://schemas.android.com/tools"
+ tools:context=".ui.activities.LoginActivity">
-
+ android:textColor="@color/white_75_alpha"
+ android:background="@color/transparent"/>
diff --git a/Habitica/res/values/strings.xml b/Habitica/res/values/strings.xml
index 32177106d..c47ae8e90 100644
--- a/Habitica/res/values/strings.xml
+++ b/Habitica/res/values/strings.xml
@@ -165,7 +165,6 @@
Unlock at lvl 11
You are not in a party. To join a party, please visit the website.
Forgot Password
- Forgot Password? Please use the mobile Website.
Reactivate your Dailies
Pause your Dailies
Buy
@@ -673,4 +672,8 @@
If you\'ve encountered a bug or made a mistake that unfairly changed your character (damage you shouldn\'t have taken, Gold you didn\'t really earn, etc.), you can manually correct your numbers here. Yes, this makes it possible to cheat: use this feature wisely, or you\'ll sabotage your own habit-building!
Fix Character Values
Saving
+ Email a Password Reset Link
+ Enter the email address you used to register your Habitica account.
+ If we have your email on file, instructions for setting a new password have been sent to your email.
+ OK
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
index e59d48804..7b2f0fb3d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/api/ApiService.java
@@ -334,4 +334,7 @@ public interface ApiService {
@GET("user/toggle-pinned-item/{pinType}/{path}")
Observable> togglePinnedItem(@Path("pinType") String pinType,@Path("path") String path);
+
+ @POST("user/reset-password")
+ Observable> sendPasswordResetEmail(@Body Map data);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
index 2181398ff..155ddd365 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/ApiClient.java
@@ -238,4 +238,6 @@ public interface ApiClient {
Observable deleteAccount(String password);
Observable togglePinnedItem(String pinType, String path);
+
+ Observable sendPasswordResetEmail(String email);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
index 5f24dfcff..c9611e26d 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/UserRepository.java
@@ -64,4 +64,6 @@ public interface UserRepository extends BaseRepository {
Observable resetAccount();
Observable deleteAccount(String password);
+
+ Observable sendPasswordResetEmail(String email);
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
index 2d7bdd4ee..9c663628b 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/ApiClientImpl.java
@@ -949,4 +949,11 @@ public class ApiClientImpl implements Action1, ApiClient {
public Observable togglePinnedItem(String pinType, String path) {
return apiService.togglePinnedItem(pinType, path).compose(configureApiCallObserver());
}
+
+ @Override
+ public Observable sendPasswordResetEmail(String email) {
+ Map data = new HashMap<>();
+ data.put("email", email);
+ return apiService.sendPasswordResetEmail(data).compose(configureApiCallObserver());
+ }
}
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
index 08ccefddb..4fd0e83dc 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/data/implementation/UserRepositoryImpl.java
@@ -251,6 +251,11 @@ public class UserRepositoryImpl extends BaseRepositoryImpl
return apiClient.deleteAccount(password);
}
+ @Override
+ public Observable sendPasswordResetEmail(String email) {
+ return apiClient.sendPasswordResetEmail(email);
+ }
+
@Override
public void runCron(List tasks) {
Observable> observable;
diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
index 9bf12016e..d00e45606 100644
--- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
+++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/activities/LoginActivity.java
@@ -8,6 +8,7 @@ import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Dialog;
import android.content.ActivityNotFoundException;
+import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
@@ -18,6 +19,7 @@ import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.preference.PreferenceManager;
+import android.text.InputType;
import android.text.SpannableString;
import android.text.style.UnderlineSpan;
import android.util.Log;
@@ -85,6 +87,8 @@ import rx.exceptions.Exceptions;
import rx.functions.Action1;
import rx.schedulers.Schedulers;
+import static com.habitrpg.android.habitica.R.id.password;
+
/**
* @author Mickael Goubin
*/
@@ -133,14 +137,14 @@ public class LoginActivity extends BaseActivity
ProgressBar mProgressBar;
@BindView(R.id.username)
EditText mUsernameET;
- @BindView(R.id.password)
+ @BindView(password)
EditText mPasswordET;
@BindView(R.id.email)
EditText mEmail;
@BindView(R.id.confirm_password)
EditText mConfirmPassword;
- @BindView(R.id.forgot_pw_tv)
- TextView mForgotPWTV;
+ @BindView(R.id.forgot_password)
+ Button forgotPasswordButton;
private CallbackManager callbackManager;
private String googleEmail;
private LoginManager loginManager;
@@ -165,10 +169,9 @@ public class LoginActivity extends BaseActivity
mLoginNormalBtn.setOnClickListener(mLoginNormalClick);
- mForgotPWTV.setOnClickListener(mForgotPWClick);
- SpannableString content = new SpannableString(mForgotPWTV.getText());
+ SpannableString content = new SpannableString(forgotPasswordButton.getText());
content.setSpan(new UnderlineSpan(), 0, content.length(), 0);
- mForgotPWTV.setText(content);
+ forgotPasswordButton.setText(content);
callbackManager = CallbackManager.Factory.create();
@@ -640,4 +643,38 @@ public class LoginActivity extends BaseActivity
showAnimation.start();
UiUtils.dismissKeyboard(this);
}
+
+ @OnClick(R.id.forgot_password)
+ public void onForgotPasswordClicked() {
+ final EditText input = new EditText(this);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ input.setAutofillHints(EditText.AUTOFILL_HINT_EMAIL_ADDRESS);
+ }
+ input.setInputType(InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS);
+ LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.MATCH_PARENT,
+ LinearLayout.LayoutParams.MATCH_PARENT);
+ input.setLayoutParams(lp);
+ AlertDialog.Builder alertDialog = new AlertDialog.Builder(this)
+ .setTitle(R.string.forgot_password_title)
+ .setMessage(R.string.forgot_password_description)
+ .setView(input)
+ .setPositiveButton(R.string.send, (dialog, which) -> {
+ dialog.dismiss();
+ userRepository.sendPasswordResetEmail(input.getText().toString()).subscribe(aVoid -> {
+ showPasswordEmailConfirmation();
+ }, RxErrorHandler.handleEmptyError());
+ }).setNegativeButton(R.string.action_cancel, (dialog, which) -> {
+ dialog.dismiss();
+ });
+
+ alertDialog.show();
+ }
+
+ private void showPasswordEmailConfirmation() {
+ new AlertDialog.Builder(this)
+ .setMessage(R.string.forgot_password_confirmation)
+ .setPositiveButton(R.string.ok, (dialog, which) -> dialog.dismiss())
+ .show();
+ }
}