From d83e091088e3a5d3d21623824fd2568ccb320dab Mon Sep 17 00:00:00 2001 From: Hafiz Date: Fri, 27 Jun 2025 11:49:13 -0500 Subject: [PATCH] Populates settings forms with initial user data Populates the change email, username, about me, and photo URL settings forms with the user's current data. Also, prevent SettingsFormBottomSheet from appearing blank during configuration changes by retaining the instance. --- .../preferences/AccountPreferenceFragment.kt | 14 ++++--- .../preferences/SettingsFormBottomSheet.kt | 7 ++++ .../habitica/ui/views/SettingScreen.kt | 38 ++++++++++++++----- 3 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt index 4f63140e8..4c7b6bfa5 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/AccountPreferenceFragment.kt @@ -289,6 +289,7 @@ class AccountPreferenceFragment : val sheet = SettingsFormBottomSheet() sheet.content = { ChangeEmailScreen( + initialEmail = user?.authentication?.localAuthentication?.email ?: "", onBack = { sheet.dismiss() }, onSave = { newEmail, password -> lifecycleScope.launchCatching { @@ -317,6 +318,7 @@ class AccountPreferenceFragment : val sheet = SettingsFormBottomSheet() sheet.content = { ChangeUsernameScreen( + initial = user?.username ?: "", onBack = { sheet.dismiss() }, onSave = { newUsername -> lifecycleScope.launchCatching { @@ -383,12 +385,12 @@ class AccountPreferenceFragment : private fun showAboutMeDialog() { val sheet = SettingsFormBottomSheet() sheet.content = { - AboutMeScreen ( - onBack = { sheet.dismiss() }, - onSave = { aboutText -> + AboutMeScreen( + initial = user?.profile?.blurb.orEmpty(), + onBack = { sheet.dismiss() }, + onSave = { about -> lifecycleScope.launchCatching { - KeyboardUtil.dismissKeyboard(activity) - userRepository.updateUser("profile.blurb", aboutText) + userRepository.updateUser("profile.blurb", about) sheet.dismiss() } } @@ -397,10 +399,12 @@ class AccountPreferenceFragment : sheet.show(childFragmentManager, SettingsFormBottomSheet.TAG) } + private fun showPhotoUrlDialog() { val sheet = SettingsFormBottomSheet() sheet.content = { PhotoUrlScreen( + initial = user?.profile?.imageUrl ?: "", onBack = { sheet.dismiss() }, onSave = { photoUrl -> lifecycleScope.launchCatching { diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/SettingsFormBottomSheet.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/SettingsFormBottomSheet.kt index 491a2c616..0a5fbc7f3 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/SettingsFormBottomSheet.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/fragments/preferences/SettingsFormBottomSheet.kt @@ -24,6 +24,13 @@ class SettingsFormBottomSheet : BottomSheetDialogFragment() { var content: @Composable () -> Unit = {} + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // this is a workaround to prevent the screen from appearing blank during config changes (Light/Dark mode change for example) + retainInstance = true + } + override fun onStart() { super.onStart() val nightModeFlags = requireContext() diff --git a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SettingScreen.kt b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SettingScreen.kt index 7373c0411..51a03be82 100644 --- a/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SettingScreen.kt +++ b/Habitica/src/main/java/com/habitrpg/android/habitica/ui/views/SettingScreen.kt @@ -45,6 +45,7 @@ import androidx.core.widget.doAfterTextChanged import com.google.android.material.textfield.TextInputLayout import com.habitrpg.android.habitica.R import com.habitrpg.android.habitica.ui.theme.colors +import com.habitrpg.common.habitica.extensions.dpToPx import com.habitrpg.common.habitica.theme.HabiticaTheme @Composable @@ -240,6 +241,11 @@ fun ComponentTextInput( edit.transformationMethod = if (kind == FieldKind.PASSWORD) PasswordTransformationMethod.getInstance() else null + if (kind == FieldKind.MULTILINE) { + edit.inputType = edit.inputType or InputType.TYPE_TEXT_FLAG_MULTI_LINE + edit.height = 115.dpToPx(context = view.context) + } + fun syncColors(focused: Boolean) { val active = focused || edit.text?.isNotBlank() == true val filledNotActive = !focused && edit.text?.isNotBlank() == true @@ -356,6 +362,7 @@ fun ChangePasswordScreen( @Composable fun ChangeUsernameScreen( + initial: String, onBack: () -> Unit, onSave: (newUsername: String) -> Unit ) { @@ -364,6 +371,7 @@ fun ChangeUsernameScreen( key = "username", labelRes = R.string.username, kind = FieldKind.TEXT, + initialValue = initial, validator = { when { it.isBlank() -> R.string.username_requirements @@ -390,6 +398,7 @@ fun ChangeUsernameScreen( @Composable fun ChangeEmailScreen( + initialEmail: String, onBack: () -> Unit, onSave: (newEmail: String, password: String) -> Unit, onForgotPassword: () -> Unit @@ -399,6 +408,7 @@ fun ChangeEmailScreen( key = "email", labelRes = R.string.email, kind = FieldKind.EMAIL, + initialValue = initialEmail, validator = { if (it.isBlank()) R.string.email_invalid else null } ), FieldConfig( @@ -453,32 +463,35 @@ fun ChangeDisplayNameScreen( @Composable fun AboutMeScreen( + initial: String, onBack: () -> Unit, onSave: (aboutText: String) -> Unit ) { val fields = listOf( FieldConfig( - key = "about", - labelRes = R.string.about_me, - kind = FieldKind.MULTILINE + key = "about", + labelRes = R.string.about_me, + kind = FieldKind.MULTILINE, + initialValue = initial ) ) ConfigurableFormScreen( FormScreenConfig( - titleRes = R.string.about_me, - descriptionRes = R.string.about_me_description, - fields = fields, + titleRes = R.string.about_me, + descriptionRes = R.string.about_me_description, + fields = fields, submitButtonRes = R.string.save_about_me, - canSubmit = { true }, - onSubmit = { vals -> onSave(vals["about"]!!.trim()) }, - onBack = onBack + canSubmit = { true }, + onSubmit = { vals -> onSave(vals["about"]!!.trim()) }, + onBack = onBack ) ) } @Composable fun PhotoUrlScreen( + initial: String, onBack: () -> Unit, onSave: (photoUrl: String) -> Unit ) { @@ -486,7 +499,8 @@ fun PhotoUrlScreen( FieldConfig( key = "photoUrl", labelRes = R.string.photo_url, - kind = FieldKind.URI + kind = FieldKind.URI, + initialValue = initial ) ) @@ -512,6 +526,7 @@ fun PhotoUrlScreen( fun PreviewChangeUsernameScreenDark() { HabiticaTheme { ChangeUsernameScreen( + initial = "", onBack = {}, onSave = { } ) @@ -528,6 +543,7 @@ fun PreviewChangeEmailScreenDark() { HabiticaTheme { ChangeEmailScreen( onBack = {}, + initialEmail = "", onSave = { newEmail, password -> }, onForgotPassword = {} ) @@ -558,6 +574,7 @@ fun PreviewChangeDisplayNameScreenDark() { fun PreviewAboutMeScreenDark() { HabiticaTheme { AboutMeScreen( + initial = "", onBack = {}, onSave = { } ) @@ -573,6 +590,7 @@ fun PreviewAboutMeScreenDark() { fun PreviewPhotoUrlScreenDark() { HabiticaTheme { PhotoUrlScreen( + initial = "", onBack = {}, onSave = { } )