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.
This commit is contained in:
Hafiz 2025-06-27 11:49:13 -05:00
parent 971bf37374
commit d83e091088
3 changed files with 44 additions and 15 deletions

View file

@ -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 {

View file

@ -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()

View file

@ -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 = { }
)