Improves configuration of Zap types (double click and click and hold)
This commit is contained in:
@@ -5,8 +5,11 @@ import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.itemsIndexed
|
||||
@@ -29,7 +32,7 @@ import androidx.compose.ui.unit.dp
|
||||
import androidx.compose.ui.window.Dialog
|
||||
|
||||
@Composable
|
||||
fun TextSpinner(label: String, placeholder: String, options: List<String>, onSelect: (Int) -> Unit, modifier: Modifier = Modifier) {
|
||||
fun TextSpinner(label: String, placeholder: String, options: List<String>, explainers: List<String>? = null, onSelect: (Int) -> Unit, modifier: Modifier = Modifier) {
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
var optionsShowing by remember { mutableStateOf(false) }
|
||||
@@ -62,7 +65,7 @@ fun TextSpinner(label: String, placeholder: String, options: List<String>, onSel
|
||||
|
||||
if (optionsShowing) {
|
||||
options.isNotEmpty().also {
|
||||
SpinnerSelectionDialog(options = options, onDismiss = { optionsShowing = false }) {
|
||||
SpinnerSelectionDialog(options = options, explainers = explainers, onDismiss = { optionsShowing = false }) {
|
||||
currentText = options[it]
|
||||
optionsShowing = false
|
||||
onSelect(it)
|
||||
@@ -72,7 +75,7 @@ fun TextSpinner(label: String, placeholder: String, options: List<String>, onSel
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SpinnerSelectionDialog(options: List<String>, onDismiss: () -> Unit, onSelect: (Int) -> Unit) {
|
||||
fun SpinnerSelectionDialog(options: List<String>, explainers: List<String>?, onDismiss: () -> Unit, onSelect: (Int) -> Unit) {
|
||||
Dialog(onDismissRequest = onDismiss) {
|
||||
Surface(
|
||||
border = BorderStroke(0.25.dp, Color.LightGray),
|
||||
@@ -81,16 +84,33 @@ fun SpinnerSelectionDialog(options: List<String>, onDismiss: () -> Unit, onSelec
|
||||
LazyColumn() {
|
||||
itemsIndexed(options) { index, item ->
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(16.dp, 16.dp)
|
||||
.clickable {
|
||||
onSelect(index)
|
||||
}
|
||||
) {
|
||||
Column() {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text(text = item, color = MaterialTheme.colors.onSurface)
|
||||
}
|
||||
explainers?.getOrNull(index)?.let {
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.Start,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Text(text = it, color = Color.Gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (index < options.lastIndex) {
|
||||
Divider(color = Color.LightGray, thickness = 0.25.dp)
|
||||
}
|
||||
|
||||
@@ -239,7 +239,9 @@ private fun AuthorPictureAndComment(
|
||||
accountUser: User,
|
||||
accountViewModel: AccountViewModel
|
||||
) {
|
||||
var content by remember { mutableStateOf<Pair<User, String?>>(Pair(zapRequest.author!!, null)) }
|
||||
val author = zapRequest.author ?: return
|
||||
|
||||
var content by remember { mutableStateOf<Pair<User, String?>>(Pair(author, null)) }
|
||||
|
||||
LaunchedEffect(key1 = zapRequest.idHex) {
|
||||
(zapRequest.event as? LnZapRequestEvent)?.let {
|
||||
@@ -249,7 +251,7 @@ private fun AuthorPictureAndComment(
|
||||
content = Pair(author, decryptedContent.content)
|
||||
} else {
|
||||
if (!zapRequest.event?.content().isNullOrBlank()) {
|
||||
content = Pair(zapRequest.author!!, zapRequest.event?.content())
|
||||
content = Pair(author, zapRequest.event?.content())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.imePadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
@@ -69,9 +70,11 @@ import com.vitorpamplona.amethyst.R
|
||||
import com.vitorpamplona.amethyst.model.Account
|
||||
import com.vitorpamplona.amethyst.model.decodePublicKey
|
||||
import com.vitorpamplona.amethyst.model.toHexKey
|
||||
import com.vitorpamplona.amethyst.service.model.LnZapEvent
|
||||
import com.vitorpamplona.amethyst.ui.actions.CloseButton
|
||||
import com.vitorpamplona.amethyst.ui.actions.SaveButton
|
||||
import com.vitorpamplona.amethyst.ui.qrcode.SimpleQrCodeScanner
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.TextSpinner
|
||||
import com.vitorpamplona.amethyst.ui.screen.loggedIn.getFragmentActivity
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -85,6 +88,7 @@ class UpdateZapAmountViewModel : ViewModel() {
|
||||
var walletConnectRelay by mutableStateOf(TextFieldValue(""))
|
||||
var walletConnectPubkey by mutableStateOf(TextFieldValue(""))
|
||||
var walletConnectSecret by mutableStateOf(TextFieldValue(""))
|
||||
var selectedZapType by mutableStateOf(LnZapEvent.ZapType.PRIVATE)
|
||||
|
||||
fun load(account: Account) {
|
||||
this.account = account
|
||||
@@ -92,6 +96,7 @@ class UpdateZapAmountViewModel : ViewModel() {
|
||||
this.walletConnectPubkey = account.zapPaymentRequest?.pubKeyHex?.let { TextFieldValue(it) } ?: TextFieldValue("")
|
||||
this.walletConnectRelay = account.zapPaymentRequest?.relayUri?.let { TextFieldValue(it) } ?: TextFieldValue("")
|
||||
this.walletConnectSecret = account.zapPaymentRequest?.secret?.let { TextFieldValue(it) } ?: TextFieldValue("")
|
||||
this.selectedZapType = account.defaultZapType
|
||||
}
|
||||
|
||||
fun toListOfAmounts(commaSeparatedAmounts: String): List<Long> {
|
||||
@@ -113,6 +118,7 @@ class UpdateZapAmountViewModel : ViewModel() {
|
||||
|
||||
fun sendPost() {
|
||||
account?.changeZapAmounts(amountSet)
|
||||
account?.changeDefaultZapType(selectedZapType)
|
||||
|
||||
if (walletConnectRelay.text.isNotBlank() && walletConnectPubkey.text.isNotBlank()) {
|
||||
val pubkeyHex = try {
|
||||
@@ -160,6 +166,7 @@ class UpdateZapAmountViewModel : ViewModel() {
|
||||
|
||||
fun hasChanged(): Boolean {
|
||||
return (
|
||||
selectedZapType != account?.defaultZapType ||
|
||||
amountSet != account?.zapAmountChoices ||
|
||||
walletConnectPubkey.text != (account?.zapPaymentRequest?.pubKeyHex ?: "") ||
|
||||
walletConnectRelay.text != (account?.zapPaymentRequest?.relayUri ?: "") ||
|
||||
@@ -188,6 +195,16 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
val postViewModel: UpdateZapAmountViewModel = viewModel()
|
||||
val uri = LocalUriHandler.current
|
||||
|
||||
val zapTypes = listOf(
|
||||
Triple(LnZapEvent.ZapType.PUBLIC, stringResource(id = R.string.zap_type_public), stringResource(id = R.string.zap_type_public_explainer)),
|
||||
Triple(LnZapEvent.ZapType.PRIVATE, stringResource(id = R.string.zap_type_private), stringResource(id = R.string.zap_type_private_explainer)),
|
||||
Triple(LnZapEvent.ZapType.ANONYMOUS, stringResource(id = R.string.zap_type_anonymous), stringResource(id = R.string.zap_type_anonymous_explainer)),
|
||||
Triple(LnZapEvent.ZapType.NONZAP, stringResource(id = R.string.zap_type_nonzap), stringResource(id = R.string.zap_type_nonzap_explainer))
|
||||
)
|
||||
|
||||
val zapOptions = zapTypes.map { it.second }
|
||||
val zapOptionExplainers = zapTypes.map { it.third }
|
||||
|
||||
LaunchedEffect(account) {
|
||||
postViewModel.load(account)
|
||||
if (nip47uri != null) {
|
||||
@@ -205,12 +222,16 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
Dialog(
|
||||
onDismissRequest = { onClose() },
|
||||
properties = DialogProperties(
|
||||
usePlatformDefaultWidth = false,
|
||||
dismissOnClickOutside = false,
|
||||
usePlatformDefaultWidth = false
|
||||
decorFitsSystemWindows = false
|
||||
)
|
||||
) {
|
||||
Surface() {
|
||||
Column(modifier = Modifier.padding(10.dp)) {
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Column(modifier = Modifier.padding(10.dp).imePadding()) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
@@ -232,6 +253,10 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
|
||||
Spacer(modifier = Modifier.height(10.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
@@ -308,6 +333,27 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
}
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(vertical = 5.dp),
|
||||
verticalAlignment = Alignment.CenterVertically
|
||||
) {
|
||||
TextSpinner(
|
||||
label = stringResource(id = R.string.zap_type_explainer),
|
||||
placeholder = zapTypes.filter { it.first == account.defaultZapType }
|
||||
.first().second,
|
||||
options = zapOptions,
|
||||
explainers = zapOptionExplainers,
|
||||
onSelect = {
|
||||
postViewModel.selectedZapType = zapTypes[it].first
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 5.dp)
|
||||
)
|
||||
}
|
||||
|
||||
Divider(
|
||||
modifier = Modifier.padding(vertical = 10.dp),
|
||||
thickness = 0.25.dp
|
||||
@@ -439,7 +485,8 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
}
|
||||
}
|
||||
|
||||
val authTitle = stringResource(id = R.string.wallet_connect_service_show_secret)
|
||||
val authTitle =
|
||||
stringResource(id = R.string.wallet_connect_service_show_secret)
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -466,7 +513,12 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
trailingIcon = {
|
||||
IconButton(onClick = {
|
||||
if (!showPassword) {
|
||||
authenticate(authTitle, context, scope, keyguardLauncher) {
|
||||
authenticate(
|
||||
authTitle,
|
||||
context,
|
||||
scope,
|
||||
keyguardLauncher
|
||||
) {
|
||||
showPassword = true
|
||||
}
|
||||
} else {
|
||||
@@ -493,6 +545,7 @@ fun UpdateZapAmountDialog(onClose: () -> Unit, account: Account, nip47uri: Strin
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun authenticate(
|
||||
title: String,
|
||||
|
||||
@@ -60,6 +60,7 @@ fun ZapCustomDialog(onClose: () -> Unit, account: Account, accountViewModel: Acc
|
||||
val context = LocalContext.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val postViewModel: ZapOptionstViewModel = viewModel()
|
||||
|
||||
LaunchedEffect(account) {
|
||||
postViewModel.load(account)
|
||||
}
|
||||
@@ -67,13 +68,14 @@ fun ZapCustomDialog(onClose: () -> Unit, account: Account, accountViewModel: Acc
|
||||
var zappingProgress by remember { mutableStateOf(0f) }
|
||||
|
||||
val zapTypes = listOf(
|
||||
Pair(LnZapEvent.ZapType.PUBLIC, "Public"),
|
||||
Pair(LnZapEvent.ZapType.PRIVATE, "Private"),
|
||||
Pair(LnZapEvent.ZapType.ANONYMOUS, "Anonymous"),
|
||||
Pair(LnZapEvent.ZapType.NONZAP, "Non-Zap")
|
||||
Triple(LnZapEvent.ZapType.PUBLIC, stringResource(id = R.string.zap_type_public), stringResource(id = R.string.zap_type_public_explainer)),
|
||||
Triple(LnZapEvent.ZapType.PRIVATE, stringResource(id = R.string.zap_type_private), stringResource(id = R.string.zap_type_private_explainer)),
|
||||
Triple(LnZapEvent.ZapType.ANONYMOUS, stringResource(id = R.string.zap_type_anonymous), stringResource(id = R.string.zap_type_anonymous_explainer)),
|
||||
Triple(LnZapEvent.ZapType.NONZAP, stringResource(id = R.string.zap_type_nonzap), stringResource(id = R.string.zap_type_nonzap_explainer))
|
||||
)
|
||||
|
||||
val zapOptions = zapTypes.map { it.second }
|
||||
val zapOptionExplainers = zapTypes.map { it.third }
|
||||
var selectedZapType by remember { mutableStateOf(account.defaultZapType) }
|
||||
|
||||
Dialog(
|
||||
@@ -150,11 +152,23 @@ fun ZapCustomDialog(onClose: () -> Unit, account: Account, accountViewModel: Acc
|
||||
},
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.padding(end = 10.dp)
|
||||
.padding(end = 5.dp)
|
||||
.weight(1f)
|
||||
)
|
||||
|
||||
TextSpinner(
|
||||
label = stringResource(id = R.string.zap_type),
|
||||
placeholder = zapTypes.filter { it.first == account.defaultZapType }.first().second,
|
||||
options = zapOptions,
|
||||
explainers = zapOptionExplainers,
|
||||
onSelect = {
|
||||
selectedZapType = zapTypes[it].first
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(end = 5.dp)
|
||||
)
|
||||
}
|
||||
Spacer(modifier = Modifier.height(5.dp))
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
@@ -189,20 +203,10 @@ fun ZapCustomDialog(onClose: () -> Unit, account: Account, accountViewModel: Acc
|
||||
},
|
||||
singleLine = true,
|
||||
modifier = Modifier
|
||||
.padding(end = 10.dp)
|
||||
.padding(end = 5.dp)
|
||||
.weight(1f)
|
||||
)
|
||||
}
|
||||
TextSpinner(
|
||||
label = "Zap Type",
|
||||
placeholder = zapTypes.filter { it.first == account.defaultZapType }.first().second,
|
||||
options = zapOptions,
|
||||
onSelect = {
|
||||
selectedZapType = zapTypes[it].first
|
||||
account.changeDefaultZapType(selectedZapType)
|
||||
},
|
||||
modifier = Modifier.fillMaxWidth()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -307,4 +307,19 @@
|
||||
<string name="content_description">Description of the contents</string>
|
||||
<string name="content_description_example">A blue boat in a white sandy beach at sunset</string>
|
||||
|
||||
<string name="zap_type">Zap Type</string>
|
||||
<string name="zap_type_explainer">Zap Type for all options</string>
|
||||
|
||||
<string name="zap_type_public">Public</string>
|
||||
<string name="zap_type_public_explainer">Everybody can see the transaction and message</string>
|
||||
|
||||
<string name="zap_type_private">Private</string>
|
||||
<string name="zap_type_private_explainer">Sender and Receiver can see each other and read the message</string>
|
||||
|
||||
<string name="zap_type_anonymous">Anonymous</string>
|
||||
<string name="zap_type_anonymous_explainer">Receiver and the public does not know who sent the payment</string>
|
||||
|
||||
<string name="zap_type_nonzap">Non-Zap</string>
|
||||
<string name="zap_type_nonzap_explainer">No trace in Nostr, only in Lightning</string>
|
||||
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user