Simplify profile edit screen layout

Reduce visual clutter by reordering fields, improving labels, and
collapsing rarely-used social proof fields into an expandable section.

- Rename "Name" field to "Username" with @ prefix
- Reorder: Lightning Address, Nostr Address (NIP-05), Website, Pronouns
- Remove deprecated LN URL (lud06) field
- Move social proof fields (Twitter, GitHub, Mastodon) into a
  collapsible "Social proof" section (auto-expands if data exists)
- Clearer labels: "Lightning Address", "Nostr Address (NIP-05)"
This commit is contained in:
The Daniel
2026-02-28 20:10:17 -05:00
parent 3762c8d6c3
commit 2b36858c12
@@ -20,7 +20,12 @@
*/ */
package com.vitorpamplona.amethyst.ui.actions package com.vitorpamplona.amethyst.ui.actions
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@@ -30,16 +35,24 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.ExpandLess
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
@@ -61,8 +74,15 @@ fun NewUserMetadataScreen(
postViewModel.init(accountViewModel) postViewModel.init(accountViewModel)
val context = LocalContext.current val context = LocalContext.current
val socialExpanded = rememberSaveable { mutableStateOf(false) }
LaunchedEffect(postViewModel, accountViewModel) { LaunchedEffect(postViewModel, accountViewModel) {
postViewModel.load() postViewModel.load()
// Auto-expand social proofs if any have data
if (postViewModel.twitter.value.isNotBlank() || postViewModel.mastodon.value.isNotBlank() || postViewModel.github.value.isNotBlank()) {
socialExpanded.value = true
}
} }
Scaffold( Scaffold(
@@ -95,8 +115,9 @@ fun NewUserMetadataScreen(
Column( Column(
modifier = Modifier.padding(10.dp).verticalScroll(rememberScrollState()), modifier = Modifier.padding(10.dp).verticalScroll(rememberScrollState()),
) { ) {
// -- Profile (always visible) --
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.profile_name_with_explainer)) }, label = { Text(text = stringRes(R.string.username)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = postViewModel.name.value, value = postViewModel.name.value,
onValueChange = { postViewModel.name.value = it }, onValueChange = { postViewModel.name.value = it },
@@ -106,6 +127,7 @@ fun NewUserMetadataScreen(
color = MaterialTheme.colorScheme.placeholderText, color = MaterialTheme.colorScheme.placeholderText,
) )
}, },
prefix = { Text("@") },
keyboardOptions = keyboardOptions =
KeyboardOptions.Default.copy( KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.Sentences, capitalization = KeyboardCapitalization.Sentences,
@@ -195,7 +217,7 @@ fun NewUserMetadataScreen(
SelectSingleFromGallery( SelectSingleFromGallery(
isUploading = postViewModel.isUploadingImageForBanner, isUploading = postViewModel.isUploadingImageForBanner,
tint = MaterialTheme.colorScheme.placeholderText, tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(start = 5.dp).align(Alignment.CenterHorizontally), modifier = Modifier.padding(start = 5.dp),
) { ) {
postViewModel.uploadForBanner(it, context, onError = accountViewModel.toastManager::toast) postViewModel.uploadForBanner(it, context, onError = accountViewModel.toastManager::toast)
} }
@@ -206,13 +228,29 @@ fun NewUserMetadataScreen(
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.pronouns)) }, label = { Text(text = stringRes(R.string.lightning_address)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = postViewModel.pronouns.value, value = postViewModel.lnAddress.value,
onValueChange = { postViewModel.pronouns.value = it }, onValueChange = { postViewModel.lnAddress.value = it },
placeholder = { placeholder = {
Text( Text(
text = "they/them, ...", text = "me@mylightningnode.com",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.nip_05) + " (NIP-05)") },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.nip05.value,
onValueChange = { postViewModel.nip05.value = it },
placeholder = {
Text(
text = "_@mywebsite.com",
color = MaterialTheme.colorScheme.placeholderText, color = MaterialTheme.colorScheme.placeholderText,
) )
}, },
@@ -238,94 +276,107 @@ fun NewUserMetadataScreen(
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.nip_05)) }, label = { Text(text = stringRes(R.string.pronouns)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = postViewModel.nip05.value, value = postViewModel.pronouns.value,
onValueChange = { postViewModel.nip05.value = it }, onValueChange = { postViewModel.pronouns.value = it },
placeholder = { placeholder = {
Text( Text(
text = "_@mywebsite.com", text = "they/them, ...",
color = MaterialTheme.colorScheme.placeholderText, color = MaterialTheme.colorScheme.placeholderText,
) )
}, },
singleLine = true, singleLine = true,
) )
Spacer(modifier = Modifier.height(10.dp)) // -- Social Proofs --
OutlinedTextField( ExpandableSection(
label = { Text(text = stringRes(R.string.ln_address)) }, title = "Social proof",
modifier = Modifier.fillMaxWidth(), expanded = socialExpanded,
value = postViewModel.lnAddress.value, ) {
onValueChange = { postViewModel.lnAddress.value = it }, OutlinedTextField(
placeholder = { label = { Text(text = stringRes(R.string.twitter)) },
Text( modifier = Modifier.fillMaxWidth(),
text = "me@mylightningnode.com", value = postViewModel.twitter.value,
color = MaterialTheme.colorScheme.placeholderText, onValueChange = { postViewModel.twitter.value = it },
) placeholder = {
}, Text(
singleLine = true, text = stringRes(R.string.twitter_proof_url_template),
) color = MaterialTheme.colorScheme.placeholderText,
)
},
)
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.ln_url_outdated)) }, label = { Text(text = stringRes(R.string.mastodon)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = postViewModel.lnURL.value, value = postViewModel.mastodon.value,
onValueChange = { postViewModel.lnURL.value = it }, onValueChange = { postViewModel.mastodon.value = it },
placeholder = { placeholder = {
Text( Text(
text = stringRes(R.string.lnurl), text = stringRes(R.string.mastodon_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText, color = MaterialTheme.colorScheme.placeholderText,
) )
}, },
) )
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.twitter)) }, label = { Text(text = stringRes(R.string.github)) },
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
value = postViewModel.twitter.value, value = postViewModel.github.value,
onValueChange = { postViewModel.twitter.value = it }, onValueChange = { postViewModel.github.value = it },
placeholder = { placeholder = {
Text( Text(
text = stringRes(R.string.twitter_proof_url_template), text = stringRes(R.string.github_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText, color = MaterialTheme.colorScheme.placeholderText,
) )
}, },
) )
}
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.mastodon)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.mastodon.value,
onValueChange = { postViewModel.mastodon.value = it },
placeholder = {
Text(
text = stringRes(R.string.mastodon_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText,
)
},
)
Spacer(modifier = Modifier.height(10.dp))
OutlinedTextField(
label = { Text(text = stringRes(R.string.github)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.github.value,
onValueChange = { postViewModel.github.value = it },
placeholder = {
Text(
text = stringRes(R.string.github_proof_url_template),
color = MaterialTheme.colorScheme.placeholderText,
)
},
)
} }
} }
} }
} }
@Composable
private fun ExpandableSection(
title: String,
expanded: MutableState<Boolean>,
content: @Composable () -> Unit,
) {
Row(
modifier =
Modifier
.fillMaxWidth()
.clickable { expanded.value = !expanded.value }
.padding(vertical = 12.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
text = title,
style = MaterialTheme.typography.titleSmall,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f),
)
Icon(
imageVector = if (expanded.value) Icons.Default.ExpandLess else Icons.Default.ExpandMore,
contentDescription = if (expanded.value) "Collapse" else "Expand",
tint = MaterialTheme.colorScheme.placeholderText,
)
}
AnimatedVisibility(
visible = expanded.value,
enter = expandVertically(),
exit = shrinkVertically(),
) {
Column {
content()
Spacer(modifier = Modifier.height(10.dp))
}
}
}