Merge pull request #1773 from Hafizzle/Hafiz/#1523

#1523 - Update Reset/Delete Modals
This commit is contained in:
Phillip Thelen 2022-05-24 09:53:37 +02:00 committed by GitHub
commit c7ef292721
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 328 additions and 51 deletions

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:color="@color/gray_100" android:state_focused="true"/>
<item android:color="@color/gray_100" android:state_hovered="true"/>
<item android:color="@color/gray_100"/>
</selector>

View file

@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.cardview.widget.CardView
android:id="@+id/toolbar_cardview"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:cardElevation="0dp"
app:cardBackgroundColor="@color/gray_2_alpha"
app:cardCornerRadius="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/back_imagebutton"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerVertical="true"
android:layout_marginStart="@dimen/button_padding_small"
android:background="?attr/selectableItemBackgroundBorderless"
android:padding="8dp"
android:src="@drawable/ic_arrow_back_white_36dp"
app:tint="@android:color/black" />
<TextView
android:id="@+id/confirm_action_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginEnd="10dp"
android:alpha=".4"
android:background="?attr/selectableItemBackground"
android:fontFamily="@string/font_family_medium"
android:padding="8dp"
android:text="@string/delete_account"
android:textColor="@color/gray_10"
android:textSize="18sp" />
</RelativeLayout>
</androidx.cardview.widget.CardView>
<TextView
android:id="@+id/title_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar_cardview"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:fontFamily="@string/font_family_medium"
android:text="@string/are_you_sure_you_want_to_delete"
android:textColor="@color/gray_50"
android:textSize="20sp" />
<TextView
android:id="@+id/warning_description_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/title_textview"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginTop="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:alpha=".8"
android:fontFamily="@string/font_family_regular"
android:lineSpacingExtra="5dp"
android:text="@string/delete_account_description"
android:textColor="@color/gray_50"
android:textSize="16sp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/confirmation_text_input_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/layout_rounded_bg_window"
android:layout_below="@id/warning_description_textview"
android:layout_marginStart="@dimen/spacing_large"
style="@style/DialogHabiticaAccountInputLayout"
android:layout_marginTop="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:hint="@string/password"
app:hintTextColor="@color/gray_10"
android:textColorHint="@color/text_secondary"
app:hintTextAppearance="@style/DialogHabiticaAccountHintLabel">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/confirmation_input_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:background="@android:color/transparent"
android:letterSpacing=".35"
android:textSize="20sp"
android:inputType="textPassword"
android:paddingStart="@dimen/spacing_large"
android:paddingEnd="@dimen/spacing_large"
android:textColorHint="@color/text_secondary" />
</com.google.android.material.textfield.TextInputLayout>
</RelativeLayout>

View file

@ -118,6 +118,7 @@
<color name="black_20_alpha">#33000000</color>
<color name="black_50_alpha">#89000000</color>
<color name="gray_20_alpha">#331a181d</color>
<color name="gray_2_alpha">#051A181D</color>
<color name="blue_500_24">#3CA9DCF6</color>
<color name="light_gray_bg">#F6F4F8</color>

View file

@ -585,11 +585,15 @@
<string name="per_abbrv">Per</string>
<string name="int_abbrv">Int</string>
<string name="con_abbrv">Con</string>
<string name="reset_caps">RESET</string>
<string name="reset_account">Reset Account</string>
<string name="reset_account_description">WARNING! This resets many parts of your account. This is highly discouraged, but some people find it useful in the beginning after playing with the site for a short time.\n\nYou will lose all your levels, gold, and experience points. All your tasks (except those from challenges) will be deleted permanently and you will lose all of their historical data. You will lose all your equipment but you will be able to buy it all back, including all limited edition equipment or subscriber Mystery items that you already own (you will need to be in the correct class to re-buy class-specific gear). You will keep your current class and your pets and mounts. You might prefer to use an Orb of Rebirth instead, which is a much safer option and which will preserve your tasks and equipment.</string>
<string name="reset_account_title">Are you sure you want to reset?</string>
<string name="confirm_reset">Confirm reset</string>
<string name="reset_account_description">You will lose all your levels, Gold, and Experience. All your tasks and their historical data will be deleted (Challenge tasks will stay). You will lose all equipment, including limited edition or subscriber equipment, but you will be able to buy it back (you will need to be the correct class to re-buy class-specific gear). You will keep your current class and your Pets and Mounts. To confirm reset, type RESET below.</string>
<string name="delete_caps">DELETE</string>
<string name="delete_account">Delete Account</string>
<string name="delete_account_description">Deleted accounts are permanent and cannot be restored. Gems cannot be refunded. If you still want to delete, type your password below.</string>
<string name="delete_oauth_account_description">Deleted accounts are permanent and cannot be restored. Gems cannot be refunded. If you still want to delete, type DELETE below.</string>
<string name="delete_account_description">This will delete your account forever and it can never be restored! Banked or spent Gems will not be refunded. If youre absolutely certain, type your password into the text box below.</string>
<string name="delete_oauth_account_description">This will delete your account forever and it can never be restored! Banked or spent Gems will not be refunded. If youre absolutely certain, type DELETE into the text box below.</string>
<string name="reset_account_confirmation">Reset my Account</string>
<string name="delete_account_confirmation">Delete my Account</string>
<string name="danger_zone">Danger Zone</string>
@ -1226,6 +1230,7 @@
<string name="compact">Compact</string>
<string name="minimal">Minimal</string>
<string name="are_you_sure_you_want_to_delete">Are you sure you want to delete?</string>
<string name="armoire_drop_rates">Armoire drop rates</string>
<string name="armoire">Armoire</string>
<string name="equipment_remaining">Equipment Remaining: %d</string>

View file

@ -396,6 +396,15 @@
<item name="backgroundTint">@color/dialog_background</item>
</style>
<style name="HabiticaAccountDialogTheme" parent="AppTheme">
<item name="android:windowNoTitle">true</item>
<item name="android:windowFullscreen">false</item>
<item name="android:windowIsFloating">false</item>
<item name="android:statusBarColor">@color/gray_2_alpha</item>
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
<item name="android:navigationBarColor">@color/white</item>
</style>
<style name="NegativeButtonStyle" parent="Widget.MaterialComponents.Button.TextButton.Dialog">
<item name="android:textColor">@color/text_red</item>
@ -751,6 +760,18 @@
<item name="android:textColor">@color/brand_300</item>
</style>
<style name="DialogHabiticaAccountInputLayout" parent="TextAppearance.AppCompat">
<item name="android:textColorHint">@color/white</item>
<item name="colorAccent">@color/white</item>
<item name="colorControlNormal">@color/white</item>
<item name="colorControlActivated">@color/white</item>
<item name="boxStrokeColor">@color/text_input_account_stroke</item>
</style>
<style name="DialogHabiticaAccountHintLabel" parent="TextAppearance.Design.Hint">
<item name="android:textSize">10sp</item>
</style>
<style name="TaskFormTextInputLayoutAppearance" parent="Widget.MaterialComponents.TextInputLayout.FilledBox">
<!-- reference our hint & error styles -->
<item name="boxBackgroundColor">@color/white</item>

View file

@ -113,14 +113,7 @@ class PurchaseHandler(
override fun onBillingSetupFinished(billingResult: BillingResult) {
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
billingClientState = BillingClientState.READY
billingClient.queryPurchasesAsync(
BillingClient.SkuType.SUBS,
this@PurchaseHandler
)
billingClient.queryPurchasesAsync(
BillingClient.SkuType.INAPP,
this@PurchaseHandler
)
queryPurchases()
} else {
billingClientState = BillingClientState.UNAVAILABLE
}
@ -136,6 +129,19 @@ class PurchaseHandler(
billingClient.endConnection()
}
fun queryPurchases(){
if (billingClientState == BillingClientState.READY){
billingClient.queryPurchasesAsync(
BillingClient.SkuType.SUBS,
this@PurchaseHandler
)
billingClient.queryPurchasesAsync(
BillingClient.SkuType.INAPP,
this@PurchaseHandler
)
}
}
suspend fun getAllGemSKUs(): List<SkuDetails> =
getSKUs(BillingClient.SkuType.INAPP, PurchaseTypes.allGemTypes)

View file

@ -7,10 +7,8 @@ import android.content.ClipboardManager
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.text.InputType
import android.view.View
import android.widget.EditText
import android.widget.LinearLayout
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.ContextCompat
import androidx.core.content.ContextCompat.getSystemService
@ -28,6 +26,7 @@ import com.habitrpg.android.habitica.extensions.layoutInflater
import com.habitrpg.android.habitica.helpers.RxErrorHandler
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.FixCharacterValuesActivity
import com.habitrpg.android.habitica.ui.fragments.preferences.HabiticaAccountDialog.AccountUpdateConfirmed
import com.habitrpg.android.habitica.ui.helpers.KeyboardUtil
import com.habitrpg.android.habitica.ui.viewmodels.AuthenticationViewModel
import com.habitrpg.android.habitica.ui.views.ExtraLabelPreference
@ -40,13 +39,15 @@ import javax.inject.Inject
class AccountPreferenceFragment :
BasePreferencesFragment(),
SharedPreferences.OnSharedPreferenceChangeListener {
SharedPreferences.OnSharedPreferenceChangeListener,
AccountUpdateConfirmed {
@Inject
lateinit var hostConfig: HostConfig
@Inject
lateinit var apiClient: ApiClient
private lateinit var viewModel: AuthenticationViewModel
private lateinit var accountDialog: HabiticaAccountDialog
override var user: User? = null
set(value) {
@ -182,8 +183,8 @@ class AccountPreferenceFragment :
disconnect("facebook", "Facebook")
}
}
"reset_account" -> showAccountResetConfirmation()
"delete_account" -> showAccountDeleteConfirmation()
"reset_account" -> showAccountResetConfirmation(user)
"delete_account" -> showAccountDeleteConfirmation(user)
"fixCharacterValues" -> {
val intent = Intent(activity, FixCharacterValuesActivity::class.java)
activity?.startActivity(intent)
@ -402,29 +403,12 @@ class AccountPreferenceFragment :
}
}
private fun showAccountDeleteConfirmation() {
val view = context?.layoutInflater?.inflate(R.layout.dialog_edittext, null)
var deleteMessage = getString(R.string.delete_account_description)
val editText = view?.findViewById<EditText>(R.id.editText)
if (user?.authentication?.localAuthentication?.email != null) {
editText?.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
} else {
deleteMessage = getString(R.string.delete_oauth_account_description)
editText?.inputType = InputType.TYPE_CLASS_TEXT
}
view?.findViewById<TextInputLayout>(R.id.input_layout)?.hint = context?.getString(R.string.confirm_deletion)
context?.let { context ->
val dialog = HabiticaAlertDialog(context)
dialog.setTitle(R.string.delete_account)
dialog.setMessage(deleteMessage)
dialog.addCancelButton()
dialog.addButton(R.string.delete, isPrimary = true, isDestructive = true) { _, _ ->
deleteAccount(editText?.text?.toString() ?: "")
}
dialog.setAdditionalContentView(view)
dialog.setAdditionalContentSidePadding(12.dpToPx(context))
dialog.buttonAxis = LinearLayout.HORIZONTAL
dialog.show()
private fun showAccountDeleteConfirmation(user: User?) {
val habiticaAccountDialog = context?.let { HabiticaAccountDialog(it, "delete_account", this, user) }
habiticaAccountDialog?.show(parentFragmentManager, "account")
if (habiticaAccountDialog != null) {
accountDialog = habiticaAccountDialog
}
}
@ -433,6 +417,7 @@ class AccountPreferenceFragment :
compositeSubscription.add(
userRepository.deleteAccount(password).subscribe({ _ ->
dialog?.dismiss()
accountDialog.dismiss()
context?.let { HabiticaBaseApplication.logout(it) }
activity?.finish()
}) { throwable ->
@ -442,18 +427,14 @@ class AccountPreferenceFragment :
)
}
private fun showAccountResetConfirmation() {
val context = context ?: return
private fun showAccountResetConfirmation(user: User?) {
val habiticaAccountDialog = context?.let { HabiticaAccountDialog(it, "reset_account", this, user) }
habiticaAccountDialog?.show(parentFragmentManager, "account")
val dialog = HabiticaAlertDialog(context)
dialog.setTitle(R.string.reset_account)
dialog.setMessage(R.string.reset_account_description)
dialog.addButton(R.string.reset_account_confirmation, true, true) { _, _ ->
resetAccount()
if (habiticaAccountDialog != null) {
accountDialog = habiticaAccountDialog
}
dialog.addCancelButton()
dialog.setAdditionalContentSidePadding(12.dpToPx(context))
dialog.show()
}
private fun showConfirmUsernameDialog() {
@ -472,7 +453,10 @@ class AccountPreferenceFragment :
private fun resetAccount() {
val dialog = HabiticaProgressDialog.show(context, R.string.resetting_account)
compositeSubscription.add(
userRepository.resetAccount().subscribe({ dialog?.dismiss() }) { throwable ->
userRepository.resetAccount().subscribe({
dialog?.dismiss()
accountDialog.dismiss()
}) { throwable ->
dialog?.dismiss()
RxErrorHandler.reportError(throwable)
}
@ -490,4 +474,13 @@ class AccountPreferenceFragment :
override fun onSharedPreferenceChanged(p0: SharedPreferences?, p1: String?) {
}
override fun resetConfirmedClicked() {
resetAccount()
}
override fun deletionConfirmClicked(confirmationString: String) {
deleteAccount(confirmationString)
}
}

View file

@ -0,0 +1,128 @@
package com.habitrpg.android.habitica.ui.fragments.preferences
import android.content.Context
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.ContextCompat
import androidx.fragment.app.DialogFragment
import com.habitrpg.android.habitica.R
import com.habitrpg.android.habitica.databinding.DialogHabiticaAccountBinding
import com.habitrpg.android.habitica.models.user.User
class HabiticaAccountDialog(private var thisContext: Context, private val accountAction: String, val accountUpdateConfirmed: AccountUpdateConfirmed, val user: User?) : DialogFragment(R.layout.dialog_habitica_account) {
private var _binding: DialogHabiticaAccountBinding? = null
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
_binding = DialogHabiticaAccountBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
when (accountAction) {
"reset_account" -> setResetAccountViews()
"delete_account" -> setDeleteAccountViews()
}
}
private fun setResetAccountViews() {
binding.titleTextview.setText(R.string.reset_account_title)
binding.warningDescriptionTextview.setText(R.string.reset_account_description)
binding.confirmationTextInputLayout.setHint(R.string.confirm_reset)
binding.confirmActionTextview.setText(R.string.reset_account)
binding.confirmationInputEdittext.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.gray_10))
binding.confirmActionTextview.alpha = .4f
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (binding.confirmationInputEdittext.text.toString() == context?.getString(R.string.reset_caps)) {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.red_100))
binding.confirmActionTextview.alpha = 1.0f
} else {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.gray_10))
binding.confirmActionTextview.alpha = .4f
}
}
override fun afterTextChanged(p0: Editable?) {
}
})
binding.confirmActionTextview.setOnClickListener {
if (binding.confirmationInputEdittext.text.toString() == context?.getString(R.string.reset_caps)) {
accountUpdateConfirmed.resetConfirmedClicked()
}
}
}
private fun setDeleteAccountViews() {
binding.titleTextview.setText(R.string.are_you_sure_you_want_to_delete)
binding.confirmationTextInputLayout.setHint(R.string.password)
binding.confirmActionTextview.setText(R.string.delete_account)
binding.warningDescriptionTextview.text = context?.getString(R.string.delete_account_description)
if (user?.authentication?.hasPassword != true) {
binding.warningDescriptionTextview.text = context?.getString(R.string.delete_oauth_account_description)
binding.confirmationTextInputLayout.setHint(R.string.confirm_deletion)
}
binding.confirmationInputEdittext.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.gray_10))
binding.confirmActionTextview.alpha = .4f
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
if (binding.confirmationInputEdittext.text.toString().length > 5) {
if ((user?.authentication?.hasPassword != true && binding.confirmationInputEdittext.text.toString() == context?.getString(R.string.delete_caps)) ||
user?.authentication?.hasPassword == true) {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.red_100))
binding.confirmActionTextview.alpha = 1.0f
}
} else {
binding.confirmActionTextview.setTextColor(ContextCompat.getColor(thisContext, R.color.gray_10))
binding.confirmActionTextview.alpha = .4f
}
}
override fun afterTextChanged(p0: Editable?) {
}
})
binding.confirmActionTextview.setOnClickListener {
if (user?.authentication?.hasPassword != true) {
if (binding.confirmActionTextview.text.toString() == context?.getString(R.string.delete_caps)) {
accountUpdateConfirmed.deletionConfirmClicked(binding.confirmationInputEdittext.text.toString())
}
} else {
if (binding.confirmationInputEdittext.text.toString().length > 5) {
accountUpdateConfirmed.deletionConfirmClicked(binding.confirmationInputEdittext.text.toString())
}
}
}
}
override fun getTheme(): Int {
return R.style.HabiticaAccountDialogTheme
}
interface AccountUpdateConfirmed {
fun resetConfirmedClicked()
fun deletionConfirmClicked(confirmationString: String)
}
}

View file

@ -91,6 +91,7 @@ class GemsPurchaseFragment : BaseFragment<FragmentGemPurchaseBinding>() {
override fun onResume() {
super.onResume()
purchaseHandler.queryPurchases()
loadInventory()
}

View file

@ -102,6 +102,7 @@ class SubscriptionFragment : BaseFragment<FragmentSubscriptionBinding>() {
override fun onResume() {
super.onResume()
purchaseHandler.queryPurchases()
refresh()
loadInventory()
}

View file

@ -225,7 +225,9 @@ class PartyDetailFragment : BaseFragment<FragmentPartyDetailBinding>() {
} else {
context?.let { context ->
DataBindingUtils.loadImage(context, "quest_" + questContent.key) {
binding?.questImageView?.setImageDrawable(it)
if (binding?.questImageView?.drawable?.constantState != it.constantState || binding?.questImageView?.drawable == null){
binding?.questImageView?.setImageDrawable(it)
}
val params = binding?.questImageView?.layoutParams ?: return@loadImage
params.height = it.intrinsicHeight.dpToPx(context)
binding?.questImageView?.layoutParams = params

View file

@ -49,6 +49,8 @@ class InsufficientGemsDialog(context: Context, var gemPrice: Int) : Insufficient
addCloseButton()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
getActivity()?.let { activity ->