From e2aaa8efe0962879dc90d814e3f882193c0f2d24 Mon Sep 17 00:00:00 2001 From: Vitor Pamplona Date: Tue, 28 Nov 2023 16:07:24 -0500 Subject: [PATCH] Migrates from PAY to NOTIFY as per https://github.com/nostr-protocol/nips/pull/901 --- .../vitorpamplona/amethyst/model/Account.kt | 4 +- .../service/NostrAccountDataSource.kt | 6 +- .../amethyst/service/NostrDataSource.kt | 10 +- .../amethyst/service/relays/Client.kt | 6 +- .../amethyst/service/relays/Relay.kt | 28 ++--- .../amethyst/service/relays/RelayPool.kt | 6 +- .../ui/actions/NotifyRequestDialog.kt | 74 ++++++++++++ .../amethyst/ui/actions/PayRequestDialog.kt | 107 ------------------ .../amethyst/ui/screen/loggedIn/MainScreen.kt | 19 ++-- app/src/main/res/values/strings.xml | 7 +- 10 files changed, 109 insertions(+), 158 deletions(-) create mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt delete mode 100644 app/src/main/java/com/vitorpamplona/amethyst/ui/actions/PayRequestDialog.kt diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt index d91b65b47..c3b21e614 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Account.kt @@ -152,9 +152,7 @@ class Account( data class PaymentRequest( val relayUrl: String, - val lnInvoice: String?, - val description: String?, - val otherOptionsUrl: String? + val description: String ) var transientPaymentRequestDismissals: Set = emptySet() val transientPaymentRequests: MutableStateFlow> = MutableStateFlow(emptySet()) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt index edd2ee124..f472eb414 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrAccountDataSource.kt @@ -245,11 +245,11 @@ object NostrAccountDataSource : NostrDataSource("AccountData") { } } - override fun pay(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) { - super.pay(relay, lnInvoice, description, otherOptionsUrl) + override fun notify(relay: Relay, description: String) { + super.notify(relay, description) if (this::account.isInitialized) { - account.addPaymentRequestIfNew(Account.PaymentRequest(relay.url, lnInvoice, description, otherOptionsUrl)) + account.addPaymentRequestIfNew(Account.PaymentRequest(relay.url, description)) } } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt index 5941293a8..2181bb509 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/NostrDataSource.kt @@ -77,13 +77,11 @@ abstract class NostrDataSource(val debugName: String) { auth(relay, challenge) } - override fun onPaymentRequired( + override fun onNotify( relay: Relay, - lnInvoice: String?, - description: String?, - otherOptionsUrl: String? + description: String ) { - pay(relay, lnInvoice, description, otherOptionsUrl) + notify(relay, description) } } @@ -199,5 +197,5 @@ abstract class NostrDataSource(val debugName: String) { abstract fun updateChannelFilters() open fun auth(relay: Relay, challenge: String) = Unit - open fun pay(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) = Unit + open fun notify(relay: Relay, description: String) = Unit } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt index c33a5c79b..3c2047c0c 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Client.kt @@ -177,11 +177,11 @@ object Client : RelayPool.Listener { } } - override fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) { + override fun onNotify(relay: Relay, description: String) { // Releases the Web thread for the new payload. // May need to add a processing queue if processing new events become too costly. GlobalScope.launch(Dispatchers.Default) { - listeners.forEach { it.onPaymentRequired(relay, lnInvoice, description, otherOptionsUrl) } + listeners.forEach { it.onNotify(relay, description) } } } @@ -224,6 +224,6 @@ object Client : RelayPool.Listener { open fun onAuth(relay: Relay, challenge: String) = Unit - open fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) = Unit + open fun onNotify(relay: Relay, description: String) = Unit } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt index 8acf2cdc4..42b06c67d 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/Relay.kt @@ -244,9 +244,9 @@ class Relay( // Log.w("Relay", "Relay$url, ${msg[1].asString}") it.onAuth(this@Relay, msgArray[1].asText()) } - "PAY" -> listeners.forEach { + "NOTIFY" -> listeners.forEach { // Log.w("Relay", "Relay$url, ${msg[1].asString}") - it.onPaymentRequired(this@Relay, msgArray[1].asText(), msgArray[2].asText(), msgArray[3].asText()) + it.onNotify(this@Relay, msgArray[1].asText()) } else -> listeners.forEach { Log.w("Relay", "Unsupported message: $newMessage") @@ -326,27 +326,23 @@ class Relay( eventUploadCounterInBytes += event.bytesUsedInMemory() } else { if (write) { + val event = """["EVENT",${signedEvent.toJson()}]""" if (isConnected()) { if (isReady) { - val event = """["EVENT",${signedEvent.toJson()}]""" socket?.send(event) eventUploadCounterInBytes += event.bytesUsedInMemory() } } else { - // waits 60 seconds to reconnect after disconnected. - if (TimeUtils.now() > closingTimeInSeconds + RECONNECTING_IN_SECONDS) { - // sends all filters after connection is successful. - connectAndRun { - checkNotInMainThread() + // sends all filters after connection is successful. + connectAndRun { + checkNotInMainThread() - val event = """["EVENT",${signedEvent.toJson()}]""" - socket?.send(event) - eventUploadCounterInBytes += event.bytesUsedInMemory() + socket?.send(event) + eventUploadCounterInBytes += event.bytesUsedInMemory() - // Sends everything. - Client.allSubscriptions().forEach { - sendFilter(requestId = it) - } + // Sends everything. + Client.allSubscriptions().forEach { + sendFilter(requestId = it) } } } @@ -401,6 +397,6 @@ class Relay( /** * Relay sent an invoice */ - fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) + fun onNotify(relay: Relay, description: String) } } diff --git a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt index dcc08bc83..24d64e359 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/service/relays/RelayPool.kt @@ -113,7 +113,7 @@ object RelayPool : Relay.Listener { fun onAuth(relay: Relay, challenge: String) - fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) + fun onNotify(relay: Relay, description: String) } override fun onEvent(relay: Relay, subscriptionId: String, event: Event) { @@ -140,8 +140,8 @@ object RelayPool : Relay.Listener { listeners.forEach { it.onAuth(relay, challenge) } } - override fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) { - listeners.forEach { it.onPaymentRequired(relay, lnInvoice, description, otherOptionsUrl) } + override fun onNotify(relay: Relay, description: String) { + listeners.forEach { it.onNotify(relay, description) } } private fun updateStatus() { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt new file mode 100644 index 000000000..da71d0db5 --- /dev/null +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/NotifyRequestDialog.kt @@ -0,0 +1,74 @@ +package com.vitorpamplona.amethyst.ui.actions + +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.outlined.Done +import androidx.compose.material3.AlertDialog +import androidx.compose.material3.Button +import androidx.compose.material3.ButtonColors +import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Icon +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import com.vitorpamplona.amethyst.R +import com.vitorpamplona.amethyst.ui.components.TranslatableRichTextViewer +import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel +import com.vitorpamplona.amethyst.ui.theme.Size16dp +import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer +import com.vitorpamplona.quartz.events.EmptyTagList + +@Composable +fun NotifyRequestDialog( + title: String, + textContent: String, + buttonColors: ButtonColors = ButtonDefaults.buttonColors(), + accountViewModel: AccountViewModel, + nav: (String) -> Unit, + onDismiss: () -> Unit +) { + AlertDialog( + onDismissRequest = onDismiss, + title = { + Text(title) + }, + text = { + val defaultBackground = MaterialTheme.colorScheme.background + val background = remember { + mutableStateOf(defaultBackground) + } + + TranslatableRichTextViewer( + textContent, + canPreview = true, + Modifier.fillMaxWidth(), + EmptyTagList, + background, + accountViewModel, + nav + ) + }, + confirmButton = { + Button(onClick = onDismiss, colors = buttonColors, contentPadding = PaddingValues(horizontal = Size16dp)) { + Row( + verticalAlignment = Alignment.CenterVertically + ) { + Icon( + imageVector = Icons.Outlined.Done, + contentDescription = null + ) + Spacer(StdHorzSpacer) + Text(stringResource(R.string.error_dialog_button_ok)) + } + } + } + ) +} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/PayRequestDialog.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/PayRequestDialog.kt deleted file mode 100644 index cb0fc32a5..000000000 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/actions/PayRequestDialog.kt +++ /dev/null @@ -1,107 +0,0 @@ -package com.vitorpamplona.amethyst.ui.actions - -import androidx.compose.animation.Crossfade -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.Spacer -import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.outlined.OpenInNew -import androidx.compose.material3.AlertDialog -import androidx.compose.material3.Button -import androidx.compose.material3.ButtonColors -import androidx.compose.material3.ButtonDefaults -import androidx.compose.material3.Icon -import androidx.compose.material3.LocalTextStyle -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton -import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment -import androidx.compose.ui.platform.LocalUriHandler -import androidx.compose.ui.res.stringResource -import androidx.compose.ui.text.style.TextDirection -import com.vitorpamplona.amethyst.R -import com.vitorpamplona.amethyst.ui.components.InvoicePreview -import com.vitorpamplona.amethyst.ui.components.LoadValueFromInvoice -import com.vitorpamplona.amethyst.ui.theme.Size16dp -import com.vitorpamplona.amethyst.ui.theme.StdHorzSpacer -import com.vitorpamplona.amethyst.ui.theme.StdVertSpacer - -@Composable -fun PayRequestDialog( - title: String, - textContent: String, - lnInvoice: String?, - textContent2: String, - otherOptions: String?, - buttonColors: ButtonColors = ButtonDefaults.buttonColors(), - onDismiss: () -> Unit -) { - val uri = LocalUriHandler.current - - val uriOpener: @Composable (() -> Unit) = otherOptions?.let { - { - Button( - onClick = { - runCatching { - uri.openUri(it) - } - }, - colors = buttonColors, - contentPadding = PaddingValues(horizontal = Size16dp) - ) { - Row( - verticalAlignment = Alignment.CenterVertically - ) { - Icon( - imageVector = Icons.Outlined.OpenInNew, - contentDescription = null - ) - Spacer(StdHorzSpacer) - Text(stringResource(R.string.other_options)) - } - } - } - } ?: { - Row() {} - } - - AlertDialog( - onDismissRequest = onDismiss, - title = { - Text(title) - }, - text = { - Column { - Text(textContent) - Spacer(modifier = StdVertSpacer) - if (lnInvoice != null) { - LoadValueFromInvoice(lnbcWord = lnInvoice) { invoiceAmount -> - Crossfade(targetState = invoiceAmount, label = "PayRequestDialog") { - if (it != null) { - InvoicePreview(it.invoice, it.amount) - } else { - Text( - text = lnInvoice, - style = LocalTextStyle.current.copy(textDirection = TextDirection.Content) - ) - } - } - } - } - Spacer(modifier = StdVertSpacer) - Text(textContent2) - } - }, - confirmButton = uriOpener, - dismissButton = { - TextButton( - onClick = { - onDismiss() - } - ) { - Text(text = stringResource(R.string.dismiss)) - } - } - ) -} diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt index 8ca25403d..ca440a832 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/MainScreen.kt @@ -56,7 +56,7 @@ import androidx.navigation.compose.rememberNavController import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.model.BooleanType import com.vitorpamplona.amethyst.ui.actions.InformationDialog -import com.vitorpamplona.amethyst.ui.actions.PayRequestDialog +import com.vitorpamplona.amethyst.ui.actions.NotifyRequestDialog import com.vitorpamplona.amethyst.ui.buttons.ChannelFabColumn import com.vitorpamplona.amethyst.ui.buttons.NewCommunityNoteButton import com.vitorpamplona.amethyst.ui.buttons.NewImageButton @@ -136,7 +136,7 @@ fun MainScreen( } DisplayErrorMessages(accountViewModel) - DisplayPayMessages(accountViewModel) + DisplayNotifyMessages(accountViewModel, nav) val navPopBack = remember(navController) { { @@ -421,18 +421,15 @@ private fun DisplayErrorMessages(accountViewModel: AccountViewModel) { } @Composable -private fun DisplayPayMessages(accountViewModel: AccountViewModel) { +private fun DisplayNotifyMessages(accountViewModel: AccountViewModel, nav: (String) -> Unit) { val openDialogMsg = accountViewModel.account.transientPaymentRequests.collectAsStateWithLifecycle(null) openDialogMsg.value?.firstOrNull()?.let { request -> - PayRequestDialog( - stringResource(id = R.string.payment_required_title, request.relayUrl.removePrefix("wss://").removeSuffix("/")), - request.description?.let { - stringResource(id = R.string.payment_required_explain, it) - } ?: stringResource(id = R.string.payment_required_explain_null_description), - request.lnInvoice, - stringResource(id = R.string.payment_required_explain2), - request.otherOptionsUrl + NotifyRequestDialog( + title = stringResource(id = R.string.payment_required_title, request.relayUrl.removePrefix("wss://").removeSuffix("/")), + textContent = request.description, + accountViewModel = accountViewModel, + nav = nav ) { accountViewModel.dismissPaymentRequest(request) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1dc5d0d92..70a9add65 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -662,10 +662,5 @@ After installing, select the app you want to use in the Settings. - Payment Required for %1$s - Relay has requested a payment of the invoice below for the %1$s. - Relay has requested a payment of the invoice below - If you do not intend to use this relay anymore, please remove it from your relay list - Dismiss - See other options + Message from %1$s