diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt index bb8d0d259..a8b112053 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/ZapPaymentHandler.kt @@ -103,7 +103,7 @@ class ZapPaymentHandler(val account: Account) { } if (account.hasWalletConnectSetup()) { - payViaNWC(it.values.map { it.second }, note, onError, onProgress = { + payViaNWC(it.values.map { it.invoice }, note, onError, onProgress = { onProgress(it * 0.25f + 0.75f) // keeps within range. }, context) { // onProgress(1f) @@ -113,9 +113,9 @@ class ZapPaymentHandler(val account: Account) { it.map { Payable( info = it.key.first, - user = null, - amountMilliSats = it.value.first, - invoice = it.value.second, + user = it.key.second.user, + amountMilliSats = it.value.zapValue, + invoice = it.value.invoice, ) }.toImmutableList(), ) @@ -136,28 +136,33 @@ class ZapPaymentHandler(val account: Account) { return roundedZapValue } + class SignAllZapRequestsReturn( + val zapRequestJson: String, + val user: User? = null, + ) + suspend fun signAllZapRequests( note: Note, pollOption: Int?, message: String, zapType: LnZapEvent.ZapType, zapsToSend: List, - onAllDone: suspend (MutableMap) -> Unit, + onAllDone: suspend (MutableMap) -> Unit, ) { - collectSuccessfulSigningOperations( + collectSuccessfulSigningOperations( operationsInput = zapsToSend, runRequestFor = { next: ZapSplitSetup, onReady -> if (next.isLnAddress) { prepareZapRequestIfNeeded(note, pollOption, message, zapType) { zapRequestJson -> if (zapRequestJson != null) { - onReady(zapRequestJson) + onReady(SignAllZapRequestsReturn(zapRequestJson)) } } } else { val user = LocalCache.getUserIfExists(next.lnAddressOrPubKeyHex) prepareZapRequestIfNeeded(note, pollOption, message, zapType, user) { zapRequestJson -> if (zapRequestJson != null) { - onReady(zapRequestJson) + onReady(SignAllZapRequestsReturn(zapRequestJson, user)) } } } @@ -167,23 +172,23 @@ class ZapPaymentHandler(val account: Account) { } suspend fun assembleAllInvoices( - invoices: List>, + invoices: List>, totalAmountMilliSats: Long, message: String, onError: (String, String) -> Unit, onProgress: (percent: Float) -> Unit, context: Context, - onAllDone: suspend (MutableMap, Pair>) -> Unit, + onAllDone: suspend (MutableMap, AssembleInvoiceReturn>) -> Unit, ) { var progressAllPayments = 0.00f val totalWeight = invoices.sumOf { it.first.weight } - collectSuccessfulSigningOperations, Pair>( + collectSuccessfulSigningOperations, AssembleInvoiceReturn>( operationsInput = invoices, - runRequestFor = { splitZapRequestPair: Pair, onReady -> + runRequestFor = { splitZapRequestPair: Pair, onReady -> assembleInvoice( splitSetup = splitZapRequestPair.first, - nostrZapRequest = splitZapRequestPair.second, + nostrZapRequest = splitZapRequestPair.second.zapRequestJson, zapValue = calculateZapValue(totalAmountMilliSats, splitZapRequestPair.first.weight, totalWeight), message = message, onError = onError, @@ -243,6 +248,11 @@ class ZapPaymentHandler(val account: Account) { ) } + class AssembleInvoiceReturn( + val zapValue: Long, + val invoice: String, + ) + private fun assembleInvoice( splitSetup: ZapSplitSetup, nostrZapRequest: String, @@ -251,7 +261,7 @@ class ZapPaymentHandler(val account: Account) { onError: (String, String) -> Unit, onProgressStep: (percent: Float) -> Unit, context: Context, - onReady: (Pair) -> Unit, + onReady: (AssembleInvoiceReturn) -> Unit, ) { var progressThisPayment = 0.00f @@ -280,7 +290,7 @@ class ZapPaymentHandler(val account: Account) { context = context, onSuccess = { onProgressStep(1 - progressThisPayment) - onReady(Pair(zapValue, it)) + onReady(AssembleInvoiceReturn(zapValue, it)) }, ) } else { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt index c9c2b3250..a46bddec4 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/ClickableWithdrawal.kt @@ -79,7 +79,7 @@ fun ClickableWithdrawal(withdrawalString: String) { ClickableText( text = withdraw, - onClick = { payViaIntent(withdrawalString, context) { showErrorMessageDialog = it } }, + onClick = { payViaIntent(withdrawalString, context, { }) { showErrorMessageDialog = it } }, style = LocalTextStyle.current.copy(color = MaterialTheme.colorScheme.primary), ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt index e761e196e..f7cc281c5 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/components/InvoicePreview.kt @@ -169,7 +169,7 @@ fun InvoicePreview( Modifier .fillMaxWidth() .padding(vertical = 10.dp), - onClick = { payViaIntent(lnInvoice, context) { showErrorMessageDialog = it } }, + onClick = { payViaIntent(lnInvoice, context, { }) { showErrorMessageDialog = it } }, shape = QuoteBorder, colors = ButtonDefaults.buttonColors( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt index 5a53f964b..956c421bd 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/PollNote.kt @@ -439,6 +439,15 @@ fun ZapVote( ) } }, + justShowError = { + scope.launch { + showErrorMessageDialog = + StringToastMsg( + context.getString(R.string.error_dialog_zap_error), + it, + ) + } + }, ) } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt index c2f6ad862..fb0765cdc 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ReactionsRow.kt @@ -985,7 +985,8 @@ fun ZapReaction( if (wantsToZap) { ZapAmountChoicePopup( baseNote = baseNote, - iconSize = iconSize, + zapAmountChoices = accountViewModel.account.zapAmountChoices, + popupYOffset = iconSize, accountViewModel = accountViewModel, onDismiss = { wantsToZap = false @@ -1042,6 +1043,11 @@ fun ZapReaction( showErrorMessageDialog = showErrorMessageDialog + it } }, + justShowError = { + scope.launch { + showErrorMessageDialog = showErrorMessageDialog + it + } + }, ) } @@ -1430,6 +1436,7 @@ private fun ActionableReactionButton( @Composable fun ZapAmountChoicePopup( baseNote: Note, + zapAmountChoices: List, accountViewModel: AccountViewModel, popupYOffset: Dp, onDismiss: () -> Unit, @@ -1449,7 +1456,7 @@ fun ZapAmountChoicePopup( onDismissRequest = { onDismiss() }, ) { FlowRow(horizontalArrangement = Arrangement.Center) { - accountViewModel.account.zapAmountChoices.forEach { amountInSats -> + zapAmountChoices.forEach { amountInSats -> Button( modifier = Modifier.padding(horizontal = 3.dp), onClick = { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt index 2c605afc7..84e592d7a 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapCustomDialog.kt @@ -347,12 +347,12 @@ fun PayViaIntentDialog( accountViewModel: AccountViewModel, onClose: () -> Unit, onError: (String) -> Unit, + justShowError: (String) -> Unit, ) { val context = LocalContext.current if (payingInvoices.size == 1) { - payViaIntent(payingInvoices.first().invoice, context, onError) - onClose() + payViaIntent(payingInvoices.first().invoice, context, onClose, onError) } else { Dialog( onDismissRequest = onClose, @@ -422,9 +422,7 @@ fun PayViaIntentDialog( Spacer(modifier = DoubleHorzSpacer) PayButton(isActive = !paid.value) { - paid.value = true - - payViaIntent(it.invoice, context, onError) + payViaIntent(it.invoice, context, { paid.value = true }, justShowError) } } } @@ -437,6 +435,7 @@ fun PayViaIntentDialog( fun payViaIntent( invoice: String, context: Context, + onPaid: () -> Unit, onError: (String) -> Unit, ) { try { @@ -444,6 +443,7 @@ fun payViaIntent( intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK ContextCompat.startActivity(context, intent, null) + onPaid() } catch (e: Exception) { if (e is CancellationException) throw e // don't display ugly error messages diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapTheDevsCard.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapTheDevsCard.kt index 645819dcb..2f6d271f8 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapTheDevsCard.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/note/ZapTheDevsCard.kt @@ -20,6 +20,7 @@ */ package com.vitorpamplona.amethyst.ui.note +import android.content.Context import androidx.compose.animation.Crossfade import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.layout.Arrangement @@ -306,7 +307,7 @@ fun ZapDonationButton( animationSize: Dp = 14.dp, nav: (String) -> Unit, ) { - var wantsToZap by remember { mutableStateOf(false) } + var wantsToZap by remember { mutableStateOf?>(null) } var showErrorMessageDialog by remember { mutableStateOf(null) } var wantsToPay by remember(baseNote) { @@ -323,14 +324,14 @@ fun ZapDonationButton( Button( onClick = { - zapClick( + customZapClick( baseNote, accountViewModel, context, onZappingProgress = { progress: Float -> scope.launch { zappingProgress = progress } }, - onMultipleChoices = { wantsToZap = true }, + onMultipleChoices = { options -> wantsToZap = options }, onError = { _, message -> scope.launch { zappingProgress = 0f @@ -342,17 +343,18 @@ fun ZapDonationButton( }, modifier = Modifier.fillMaxWidth(), ) { - if (wantsToZap) { + if (wantsToZap != null) { ZapAmountChoicePopup( baseNote = baseNote, + zapAmountChoices = wantsToZap ?: accountViewModel.account.zapAmountChoices, popupYOffset = iconSize, accountViewModel = accountViewModel, onDismiss = { - wantsToZap = false + wantsToZap = null zappingProgress = 0f }, onChangeAmount = { - wantsToZap = false + wantsToZap = null }, onError = { _, message -> scope.launch { @@ -395,6 +397,11 @@ fun ZapDonationButton( showErrorMessageDialog = it } }, + justShowError = { + scope.launch { + showErrorMessageDialog = it + } + }, ) } @@ -448,3 +455,58 @@ fun ZapDonationButton( } } } + +fun customZapClick( + baseNote: Note, + accountViewModel: AccountViewModel, + context: Context, + onZappingProgress: (Float) -> Unit, + onMultipleChoices: (List) -> Unit, + onError: (String, String) -> Unit, + onPayViaIntent: (ImmutableList) -> Unit, +) { + if (baseNote.isDraft()) { + accountViewModel.toast( + R.string.draft_note, + R.string.it_s_not_possible_to_zap_to_a_draft_note, + ) + return + } + + if (accountViewModel.account.zapAmountChoices.isEmpty()) { + accountViewModel.toast( + context.getString(R.string.error_dialog_zap_error), + context.getString(R.string.no_zap_amount_setup_long_press_to_change), + ) + } else if (!accountViewModel.isWriteable()) { + accountViewModel.toast( + context.getString(R.string.error_dialog_zap_error), + context.getString(R.string.login_with_a_private_key_to_be_able_to_send_zaps), + ) + } else if (accountViewModel.account.zapAmountChoices.size == 1) { + val amount = accountViewModel.account.zapAmountChoices.first() + + if (amount > 600) { + accountViewModel.zap( + baseNote, + amount * 1000, + null, + "", + context, + onError = onError, + onProgress = { onZappingProgress(it) }, + zapType = accountViewModel.account.defaultZapType, + onPayViaIntent = onPayViaIntent, + ) + } else { + onMultipleChoices(listOf(1000L, 5_000L, 10_000L)) + // recommends amounts for a monthly release. + } + } else if (accountViewModel.account.zapAmountChoices.size > 1) { + if (accountViewModel.account.zapAmountChoices.any { it > 600 }) { + onMultipleChoices(accountViewModel.account.zapAmountChoices) + } else { + onMultipleChoices(listOf(1000L, 5_000L, 10_000L)) + } + } +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt index c19313acf..3e8348892 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/ProfileScreen.kt @@ -1193,7 +1193,7 @@ fun DisplayLNAddress( } } } else { - payViaIntent(it, context) { showErrorMessageDialog = it } + payViaIntent(it, context, { zapExpanded = false }, { showErrorMessageDialog = it }) } }, onClose = { zapExpanded = false },