Merge pull request #1784 from vitorpamplona/claude/improve-zap-settings-ui-D36RD

feat: improve Zap Settings UI with sections, chips, and animations
This commit is contained in:
Vitor Pamplona
2026-03-08 11:59:13 -04:00
committed by GitHub
2 changed files with 349 additions and 169 deletions
@@ -31,6 +31,19 @@ import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts import androidx.activity.result.contract.ActivityResultContracts
import androidx.biometric.BiometricManager import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt import androidx.biometric.BiometricPrompt
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.animateContentSize
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ExperimentalLayoutApi import androidx.compose.foundation.layout.ExperimentalLayoutApi
@@ -42,12 +55,18 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.imePadding import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
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.Icons
import androidx.compose.material.icons.filled.CheckCircle
import androidx.compose.material.icons.filled.Close
import androidx.compose.material.icons.filled.ExpandLess
import androidx.compose.material.icons.filled.ExpandMore
import androidx.compose.material.icons.outlined.Add import androidx.compose.material.icons.outlined.Add
import androidx.compose.material.icons.outlined.ContentPaste import androidx.compose.material.icons.outlined.ContentPaste
import androidx.compose.material.icons.outlined.RadioButtonUnchecked
import androidx.compose.material.icons.outlined.Visibility import androidx.compose.material.icons.outlined.Visibility
import androidx.compose.material.icons.outlined.VisibilityOff import androidx.compose.material.icons.outlined.VisibilityOff
import androidx.compose.material3.Button import androidx.compose.material3.Button
@@ -55,7 +74,10 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.InputChip
import androidx.compose.material3.InputChipDefaults
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -75,7 +97,6 @@ import androidx.compose.ui.text.input.KeyboardCapitalization
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.components.TextSpinner import com.vitorpamplona.amethyst.ui.components.TextSpinner
@@ -88,6 +109,9 @@ import com.vitorpamplona.amethyst.ui.stringRes
import com.vitorpamplona.amethyst.ui.theme.ButtonBorder import com.vitorpamplona.amethyst.ui.theme.ButtonBorder
import com.vitorpamplona.amethyst.ui.theme.DividerThickness import com.vitorpamplona.amethyst.ui.theme.DividerThickness
import com.vitorpamplona.amethyst.ui.theme.Font14SP import com.vitorpamplona.amethyst.ui.theme.Font14SP
import com.vitorpamplona.amethyst.ui.theme.RowColSpacing
import com.vitorpamplona.amethyst.ui.theme.SettingsCategoryFirstModifier
import com.vitorpamplona.amethyst.ui.theme.SettingsCategorySpacingModifier
import com.vitorpamplona.amethyst.ui.theme.Size24Modifier import com.vitorpamplona.amethyst.ui.theme.Size24Modifier
import com.vitorpamplona.amethyst.ui.theme.placeholderText import com.vitorpamplona.amethyst.ui.theme.placeholderText
import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent import com.vitorpamplona.quartz.nip57Zaps.LnZapEvent
@@ -103,7 +127,6 @@ fun UpdateZapAmountContent(
) { ) {
val context = LocalContext.current val context = LocalContext.current
val clipboardManager = LocalClipboardManager.current val clipboardManager = LocalClipboardManager.current
val uri = LocalUriHandler.current val uri = LocalUriHandler.current
val zapTypes = val zapTypes =
@@ -155,46 +178,82 @@ fun UpdateZapAmountContent(
} }
} }
var qrScanning by remember { mutableStateOf(false) }
// Expand manual config automatically when a wallet connection exists
var showManualConfig by remember { mutableStateOf(postViewModel.walletConnectPubkey.text.isNotBlank()) }
LaunchedEffect(postViewModel.walletConnectPubkey.text) {
if (postViewModel.walletConnectPubkey.text.isNotBlank()) {
showManualConfig = true
}
}
Column( Column(
modifier = modifier =
Modifier Modifier
.padding(10.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
.fillMaxWidth() .fillMaxWidth()
.imePadding() .imePadding()
.verticalScroll(rememberScrollState()), .verticalScroll(rememberScrollState()),
) { ) {
// ── Section 1: Quick Zap Amounts ──────────────────────────────────────
Text(
text = stringRes(R.string.quick_zap_amounts),
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleSmall,
modifier = SettingsCategoryFirstModifier,
)
Text(
text = stringRes(R.string.quick_zap_amounts_explainer),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(bottom = 12.dp),
)
// Amount chips — animateContentSize gives a smooth expand/collapse when
// chips are added or removed
FlowRow( FlowRow(
modifier = Modifier.fillMaxWidth(), modifier =
horizontalArrangement = Arrangement.Center, Modifier
.fillMaxWidth()
.animateContentSize(animationSpec = spring(stiffness = Spring.StiffnessMediumLow)),
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalArrangement = Arrangement.spacedBy(6.dp),
) { ) {
postViewModel.amountSet.forEach { amountInSats -> postViewModel.amountSet.forEach { amountInSats ->
Button( InputChip(
modifier = Modifier.padding(horizontal = 3.dp), selected = false,
shape = ButtonBorder,
colors =
ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.primary,
),
onClick = { postViewModel.removeAmount(amountInSats) }, onClick = { postViewModel.removeAmount(amountInSats) },
) { label = {
Text( Text(
"${ text = "${showAmount(amountInSats.toBigDecimal().setScale(1))}",
showAmount( )
amountInSats.toBigDecimal().setScale(1), },
) trailingIcon = {
} ", Icon(
color = Color.White, imageVector = Icons.Filled.Close,
textAlign = TextAlign.Center, contentDescription = stringRes(R.string.remove),
) modifier = Modifier.size(InputChipDefaults.AvatarSize),
} )
},
colors =
InputChipDefaults.inputChipColors(
containerColor = MaterialTheme.colorScheme.primary.copy(alpha = 0.12f),
labelColor = MaterialTheme.colorScheme.primary,
trailingIconColor = MaterialTheme.colorScheme.primary,
),
)
} }
} }
Spacer(modifier = Modifier.height(10.dp)) Spacer(modifier = Modifier.height(12.dp))
// Add new amount
Row( Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) { ) {
OutlinedTextField( OutlinedTextField(
label = { Text(text = stringRes(R.string.new_amount_in_sats)) }, label = { Text(text = stringRes(R.string.new_amount_in_sats)) },
@@ -212,7 +271,7 @@ fun UpdateZapAmountContent(
) )
}, },
singleLine = true, singleLine = true,
modifier = Modifier.padding(end = 10.dp).weight(1f), modifier = Modifier.weight(1f),
) )
Button( Button(
@@ -223,67 +282,159 @@ fun UpdateZapAmountContent(
containerColor = MaterialTheme.colorScheme.primary, containerColor = MaterialTheme.colorScheme.primary,
), ),
) { ) {
Icon(
imageVector = Icons.Outlined.Add,
contentDescription = stringRes(R.string.add),
modifier = Modifier.size(18.dp),
)
Spacer(modifier = Modifier.width(4.dp))
Text(text = stringRes(R.string.add), color = Color.White) Text(text = stringRes(R.string.add), color = Color.White)
} }
} }
Row( // ── Section 2: Zap Privacy ────────────────────────────────────────────
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
verticalAlignment = Alignment.CenterVertically,
) {
TextSpinner(
label = stringRes(id = R.string.zap_type_explainer),
placeholder = zapTypes.firstOrNull { it.first == accountViewModel.defaultZapType() }?.second ?: zapTypes.firstOrNull()?.second ?: "",
options = zapOptions,
onSelect = { postViewModel.selectedZapType = zapTypes[it].first },
modifier = Modifier.weight(1f).padding(end = 5.dp),
)
}
HorizontalDivider( Text(
modifier = Modifier.padding(vertical = 10.dp), text = stringRes(R.string.zap_privacy_section),
thickness = DividerThickness, color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleSmall,
modifier = SettingsCategorySpacingModifier,
)
Text(
text = stringRes(R.string.zap_type_section_explainer),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(bottom = 8.dp),
) )
var qrScanning by remember { mutableStateOf(false) }
Row( Row(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
Text( TextSpinner(
stringRes(id = R.string.wallet_connect_service), label = stringRes(id = R.string.zap_type_explainer),
Modifier.weight(1f), placeholder =
zapTypes
.firstOrNull { it.first == accountViewModel.defaultZapType() }
?.second
?: zapTypes.firstOrNull()?.second
?: "",
options = zapOptions,
onSelect = { postViewModel.selectedZapType = zapTypes[it].first },
modifier = Modifier.fillMaxWidth(),
) )
}
IconButton( // ── Section 3: Nostr Wallet Connect ───────────────────────────────────
HorizontalDivider(
modifier = Modifier.padding(vertical = 16.dp),
thickness = DividerThickness,
)
// Section header + connection status indicator
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = RowColSpacing,
) {
Column(modifier = Modifier.weight(1f)) {
Text(
text = stringRes(R.string.wallet_connect_service),
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleSmall,
)
Text(
text = stringRes(R.string.wallet_connect_service_explainer),
style = MaterialTheme.typography.bodySmall,
color = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.padding(top = 2.dp),
)
}
}
// Animated connection status badge
val isConnected = postViewModel.walletConnectPubkey.text.isNotBlank()
val statusColor by animateColorAsState(
targetValue = if (isConnected) Color(0xFF4CAF50) else MaterialTheme.colorScheme.placeholderText,
animationSpec = tween(durationMillis = 400),
label = "nwc_status_color",
)
AnimatedContent(
targetState = isConnected,
transitionSpec = { fadeIn(tween(300)) togetherWith fadeOut(tween(300)) },
label = "nwc_status_badge",
) { connected ->
Row(
modifier = Modifier.padding(vertical = 8.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(6.dp),
) {
Icon(
imageVector = if (connected) Icons.Filled.CheckCircle else Icons.Outlined.RadioButtonUnchecked,
contentDescription = null,
tint = statusColor,
modifier = Modifier.size(18.dp),
)
Text(
text =
if (connected) {
stringRes(R.string.wallet_connect_status_connected)
} else {
stringRes(R.string.wallet_connect_status_not_connected)
},
color = statusColor,
style = MaterialTheme.typography.bodyMedium,
)
}
}
// Connect action buttons
Row(
modifier = Modifier.fillMaxWidth().padding(bottom = 4.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp),
) {
// Primary "Connect Wallet" button — opens the NWC app deep link
OutlinedButton(
modifier = Modifier.weight(1f),
shape = ButtonBorder,
onClick = { onClick = {
onClose() onClose()
try { try {
uri.openUri("nostrnwc://connect?appname=Amethyst&appicon=https%3A%2F%2Fraw.githubusercontent.com%2Fvitorpamplona%2Famethyst%2Frefs%2Fheads%2Fmain%2Ficon.png&callback=amethyst%2Bwalletconnect%3A%2F%2Fdlnwc") uri.openUri(
"nostrnwc://connect?appname=Amethyst&appicon=https%3A%2F%2Fraw.githubusercontent.com%2Fvitorpamplona%2Famethyst%2Frefs%2Fheads%2Fmain%2Ficon.png&callback=amethyst%2Bwalletconnect%3A%2F%2Fdlnwc",
)
} catch (_: IllegalArgumentException) { } catch (_: IllegalArgumentException) {
accountViewModel.toastManager.toast(R.string.couldnt_find_nwc_wallets, R.string.couldnt_find_nwc_wallets_description) accountViewModel.toastManager.toast(
R.string.couldnt_find_nwc_wallets,
R.string.couldnt_find_nwc_wallets_description,
)
} }
}, },
) { ) {
Icon( Icon(
imageVector = Icons.Outlined.Add, imageVector = Icons.Outlined.Add,
contentDescription = stringRes(id = R.string.connect_to_new_nwc_wallet), contentDescription = null,
modifier = Size24Modifier, modifier = Modifier.size(18.dp),
tint = MaterialTheme.colorScheme.primary,
) )
Spacer(modifier = Modifier.width(4.dp))
Text(text = stringRes(R.string.wallet_connect_connect_app))
} }
// Paste from clipboard
IconButton( IconButton(
onClick = { onClick = {
val uri = clipboardManager.getText()?.text val clipText = clipboardManager.getText()?.text
try { try {
uri?.let { clipText?.let { postViewModel.copyFromClipboard(it) }
postViewModel.copyFromClipboard(it)
}
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
accountViewModel.toastManager.toast(R.string.invalid_nip47_uri_title, R.string.invalid_nip47_uri_description, uri ?: "") accountViewModel.toastManager.toast(
R.string.invalid_nip47_uri_title,
R.string.invalid_nip47_uri_description,
clipText ?: "",
)
} }
}, },
) { ) {
@@ -295,6 +446,7 @@ fun UpdateZapAmountContent(
) )
} }
// QR code scanner
IconButton(onClick = { qrScanning = true }) { IconButton(onClick = { qrScanning = true }) {
Icon( Icon(
painter = painterRes(R.drawable.ic_qrcode, 3), painter = painterRes(R.drawable.ic_qrcode, 3),
@@ -305,18 +457,6 @@ fun UpdateZapAmountContent(
} }
} }
Row(
modifier = Modifier.fillMaxWidth().padding(bottom = 5.dp),
verticalAlignment = Alignment.CenterVertically,
) {
Text(
stringRes(id = R.string.wallet_connect_service_explainer),
Modifier.weight(1f),
color = MaterialTheme.colorScheme.placeholderText,
fontSize = Font14SP,
)
}
if (qrScanning) { if (qrScanning) {
SimpleQrCodeScanner { SimpleQrCodeScanner {
qrScanning = false qrScanning = false
@@ -340,121 +480,153 @@ fun UpdateZapAmountContent(
} }
} }
// Expandable manual configuration section
Row( Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), modifier =
Modifier
.fillMaxWidth()
.clickable { showManualConfig = !showManualConfig }
.padding(vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
) { ) {
OutlinedTextField( Text(
label = { Text(text = stringRes(R.string.wallet_connect_service_pubkey)) }, text = stringRes(R.string.wallet_connect_manual_config),
value = postViewModel.walletConnectPubkey, style = MaterialTheme.typography.bodyMedium,
onValueChange = { postViewModel.walletConnectPubkey = it }, color = MaterialTheme.colorScheme.placeholderText,
keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.None,
),
placeholder = {
Text(
text = "npub, hex",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
fontSize = Font14SP,
)
Icon(
imageVector = if (showManualConfig) Icons.Filled.ExpandLess else Icons.Filled.ExpandMore,
contentDescription = null,
tint = MaterialTheme.colorScheme.placeholderText,
modifier = Modifier.size(20.dp),
) )
} }
Row( AnimatedVisibility(
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), visible = showManualConfig,
verticalAlignment = Alignment.CenterVertically, enter = expandVertically(animationSpec = spring(stiffness = Spring.StiffnessMediumLow)) + fadeIn(),
exit = shrinkVertically(animationSpec = spring(stiffness = Spring.StiffnessMediumLow)) + fadeOut(),
) { ) {
OutlinedTextField( Column {
label = { Text(text = stringRes(R.string.wallet_connect_service_relay)) }, Row(
modifier = Modifier.weight(1f), modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
value = postViewModel.walletConnectRelay, verticalAlignment = Alignment.CenterVertically,
onValueChange = { postViewModel.walletConnectRelay = it }, ) {
placeholder = { OutlinedTextField(
Text( label = { Text(text = stringRes(R.string.wallet_connect_service_pubkey)) },
text = "wss://relay.server.com", value = postViewModel.walletConnectPubkey,
color = MaterialTheme.colorScheme.placeholderText, onValueChange = { postViewModel.walletConnectPubkey = it },
maxLines = 1, keyboardOptions =
KeyboardOptions.Default.copy(
capitalization = KeyboardCapitalization.None,
),
placeholder = {
Text(
text = "npub, hex",
color = MaterialTheme.colorScheme.placeholderText,
)
},
singleLine = true,
modifier = Modifier.fillMaxWidth(),
) )
},
singleLine = true,
)
}
var showPassword by remember { mutableStateOf(false) }
val context = LocalContext.current
val keyguardLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
showPassword = true
} }
}
val authTitle = stringRes(id = R.string.wallet_connect_service_show_secret) Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
Row( verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp), ) {
verticalAlignment = Alignment.CenterVertically, OutlinedTextField(
) { label = { Text(text = stringRes(R.string.wallet_connect_service_relay)) },
OutlinedTextField( modifier = Modifier.fillMaxWidth(),
label = { Text(text = stringRes(R.string.wallet_connect_service_secret)) }, value = postViewModel.walletConnectRelay,
modifier = Modifier.weight(1f), onValueChange = { postViewModel.walletConnectRelay = it },
value = postViewModel.walletConnectSecret, placeholder = {
onValueChange = { postViewModel.walletConnectSecret = it }, Text(
keyboardOptions = text = "wss://relay.server.com",
KeyboardOptions( color = MaterialTheme.colorScheme.placeholderText,
autoCorrectEnabled = false, maxLines = 1,
keyboardType = KeyboardType.Password, )
imeAction = ImeAction.Go, },
), singleLine = true,
placeholder = {
Text(
text = stringRes(R.string.wallet_connect_service_secret_placeholder),
color = MaterialTheme.colorScheme.placeholderText,
) )
}, }
trailingIcon = {
IconButton( var showPassword by remember { mutableStateOf(false) }
onClick = {
if (!showPassword) { val secretContext = LocalContext.current
authenticate(
title = authTitle, val keyguardLauncher =
context = context, rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
keyguardLauncher = keyguardLauncher, if (result.resultCode == Activity.RESULT_OK) {
onApproved = { showPassword = true }, showPassword = true
onError = { title, message -> accountViewModel.toastManager.toast(title, message) }, }
}
val authTitle = stringRes(id = R.string.wallet_connect_service_show_secret)
Row(
modifier = Modifier.fillMaxWidth().padding(vertical = 5.dp),
verticalAlignment = Alignment.CenterVertically,
) {
OutlinedTextField(
label = { Text(text = stringRes(R.string.wallet_connect_service_secret)) },
modifier = Modifier.fillMaxWidth(),
value = postViewModel.walletConnectSecret,
onValueChange = { postViewModel.walletConnectSecret = it },
keyboardOptions =
KeyboardOptions(
autoCorrectEnabled = false,
keyboardType = KeyboardType.Password,
imeAction = ImeAction.Go,
),
placeholder = {
Text(
text = stringRes(R.string.wallet_connect_service_secret_placeholder),
color = MaterialTheme.colorScheme.placeholderText,
)
},
trailingIcon = {
IconButton(
onClick = {
if (!showPassword) {
authenticate(
title = authTitle,
context = secretContext,
keyguardLauncher = keyguardLauncher,
onApproved = { showPassword = true },
onError = { title, message -> accountViewModel.toastManager.toast(title, message) },
)
} else {
showPassword = false
}
},
) {
Icon(
imageVector =
if (showPassword) {
Icons.Outlined.VisibilityOff
} else {
Icons.Outlined.Visibility
},
contentDescription =
if (showPassword) {
stringRes(R.string.show_password)
} else {
stringRes(R.string.hide_password)
},
) )
} else {
showPassword = false
} }
}, },
) { visualTransformation =
Icon( if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
imageVector = )
if (showPassword) { }
Icons.Outlined.VisibilityOff }
} else {
Icons.Outlined.Visibility
},
contentDescription =
if (showPassword) {
stringRes(R.string.show_password)
} else {
stringRes(
R.string.hide_password,
)
},
)
}
},
visualTransformation =
if (showPassword) VisualTransformation.None else PasswordVisualTransformation(),
)
} }
Spacer(modifier = Modifier.height(16.dp))
} }
} }
+8
View File
@@ -454,6 +454,14 @@
<string name="wallet_connect_service_secret">Wallet Connect Secret</string> <string name="wallet_connect_service_secret">Wallet Connect Secret</string>
<string name="wallet_connect_service_show_secret">Show secret key</string> <string name="wallet_connect_service_show_secret">Show secret key</string>
<string name="wallet_connect_service_secret_placeholder">nsec / hex private key</string> <string name="wallet_connect_service_secret_placeholder">nsec / hex private key</string>
<string name="wallet_connect_status_connected">Connected</string>
<string name="wallet_connect_status_not_connected">Not connected</string>
<string name="wallet_connect_manual_config">Advanced: enter connection details manually</string>
<string name="quick_zap_amounts">Quick Zap Amounts</string>
<string name="quick_zap_amounts_explainer">Shown when long-pressing the zap button. Tap an amount to remove it.</string>
<string name="zap_privacy_section">Zap Privacy</string>
<string name="zap_type_section_explainer">Controls how your identity is shown when you send a zap.</string>
<string name="wallet_connect_connect_app">Connect Wallet</string>
<string name="pledge_amount_in_sats">Pledge Amount in Sats</string> <string name="pledge_amount_in_sats">Pledge Amount in Sats</string>
<string name="post_poll">Post Poll</string> <string name="post_poll">Post Poll</string>