This commit is contained in:
Vitor Pamplona
2023-11-28 16:07:24 -05:00
parent 5356d869fd
commit e2aaa8efe0
10 changed files with 109 additions and 158 deletions
@@ -152,9 +152,7 @@ class Account(
data class PaymentRequest( data class PaymentRequest(
val relayUrl: String, val relayUrl: String,
val lnInvoice: String?, val description: String
val description: String?,
val otherOptionsUrl: String?
) )
var transientPaymentRequestDismissals: Set<PaymentRequest> = emptySet() var transientPaymentRequestDismissals: Set<PaymentRequest> = emptySet()
val transientPaymentRequests: MutableStateFlow<Set<PaymentRequest>> = MutableStateFlow(emptySet()) val transientPaymentRequests: MutableStateFlow<Set<PaymentRequest>> = MutableStateFlow(emptySet())
@@ -245,11 +245,11 @@ object NostrAccountDataSource : NostrDataSource("AccountData") {
} }
} }
override fun pay(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) { override fun notify(relay: Relay, description: String) {
super.pay(relay, lnInvoice, description, otherOptionsUrl) super.notify(relay, description)
if (this::account.isInitialized) { if (this::account.isInitialized) {
account.addPaymentRequestIfNew(Account.PaymentRequest(relay.url, lnInvoice, description, otherOptionsUrl)) account.addPaymentRequestIfNew(Account.PaymentRequest(relay.url, description))
} }
} }
} }
@@ -77,13 +77,11 @@ abstract class NostrDataSource(val debugName: String) {
auth(relay, challenge) auth(relay, challenge)
} }
override fun onPaymentRequired( override fun onNotify(
relay: Relay, relay: Relay,
lnInvoice: String?, description: String
description: String?,
otherOptionsUrl: String?
) { ) {
pay(relay, lnInvoice, description, otherOptionsUrl) notify(relay, description)
} }
} }
@@ -199,5 +197,5 @@ abstract class NostrDataSource(val debugName: String) {
abstract fun updateChannelFilters() abstract fun updateChannelFilters()
open fun auth(relay: Relay, challenge: String) = Unit 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
} }
@@ -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. // Releases the Web thread for the new payload.
// May need to add a processing queue if processing new events become too costly. // May need to add a processing queue if processing new events become too costly.
GlobalScope.launch(Dispatchers.Default) { 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 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
} }
} }
@@ -244,9 +244,9 @@ class Relay(
// Log.w("Relay", "Relay$url, ${msg[1].asString}") // Log.w("Relay", "Relay$url, ${msg[1].asString}")
it.onAuth(this@Relay, msgArray[1].asText()) it.onAuth(this@Relay, msgArray[1].asText())
} }
"PAY" -> listeners.forEach { "NOTIFY" -> listeners.forEach {
// Log.w("Relay", "Relay$url, ${msg[1].asString}") // 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 { else -> listeners.forEach {
Log.w("Relay", "Unsupported message: $newMessage") Log.w("Relay", "Unsupported message: $newMessage")
@@ -326,27 +326,23 @@ class Relay(
eventUploadCounterInBytes += event.bytesUsedInMemory() eventUploadCounterInBytes += event.bytesUsedInMemory()
} else { } else {
if (write) { if (write) {
val event = """["EVENT",${signedEvent.toJson()}]"""
if (isConnected()) { if (isConnected()) {
if (isReady) { if (isReady) {
val event = """["EVENT",${signedEvent.toJson()}]"""
socket?.send(event) socket?.send(event)
eventUploadCounterInBytes += event.bytesUsedInMemory() eventUploadCounterInBytes += event.bytesUsedInMemory()
} }
} else { } else {
// waits 60 seconds to reconnect after disconnected. // sends all filters after connection is successful.
if (TimeUtils.now() > closingTimeInSeconds + RECONNECTING_IN_SECONDS) { connectAndRun {
// sends all filters after connection is successful. checkNotInMainThread()
connectAndRun {
checkNotInMainThread()
val event = """["EVENT",${signedEvent.toJson()}]""" socket?.send(event)
socket?.send(event) eventUploadCounterInBytes += event.bytesUsedInMemory()
eventUploadCounterInBytes += event.bytesUsedInMemory()
// Sends everything. // Sends everything.
Client.allSubscriptions().forEach { Client.allSubscriptions().forEach {
sendFilter(requestId = it) sendFilter(requestId = it)
}
} }
} }
} }
@@ -401,6 +397,6 @@ class Relay(
/** /**
* Relay sent an invoice * Relay sent an invoice
*/ */
fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) fun onNotify(relay: Relay, description: String)
} }
} }
@@ -113,7 +113,7 @@ object RelayPool : Relay.Listener {
fun onAuth(relay: Relay, challenge: String) 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) { override fun onEvent(relay: Relay, subscriptionId: String, event: Event) {
@@ -140,8 +140,8 @@ object RelayPool : Relay.Listener {
listeners.forEach { it.onAuth(relay, challenge) } listeners.forEach { it.onAuth(relay, challenge) }
} }
override fun onPaymentRequired(relay: Relay, lnInvoice: String?, description: String?, otherOptionsUrl: String?) { override fun onNotify(relay: Relay, description: String) {
listeners.forEach { it.onPaymentRequired(relay, lnInvoice, description, otherOptionsUrl) } listeners.forEach { it.onNotify(relay, description) }
} }
private fun updateStatus() { private fun updateStatus() {
@@ -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))
}
}
}
)
}
@@ -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))
}
}
)
}
@@ -56,7 +56,7 @@ import androidx.navigation.compose.rememberNavController
import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.model.BooleanType import com.vitorpamplona.amethyst.model.BooleanType
import com.vitorpamplona.amethyst.ui.actions.InformationDialog 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.ChannelFabColumn
import com.vitorpamplona.amethyst.ui.buttons.NewCommunityNoteButton import com.vitorpamplona.amethyst.ui.buttons.NewCommunityNoteButton
import com.vitorpamplona.amethyst.ui.buttons.NewImageButton import com.vitorpamplona.amethyst.ui.buttons.NewImageButton
@@ -136,7 +136,7 @@ fun MainScreen(
} }
DisplayErrorMessages(accountViewModel) DisplayErrorMessages(accountViewModel)
DisplayPayMessages(accountViewModel) DisplayNotifyMessages(accountViewModel, nav)
val navPopBack = remember(navController) { val navPopBack = remember(navController) {
{ {
@@ -421,18 +421,15 @@ private fun DisplayErrorMessages(accountViewModel: AccountViewModel) {
} }
@Composable @Composable
private fun DisplayPayMessages(accountViewModel: AccountViewModel) { private fun DisplayNotifyMessages(accountViewModel: AccountViewModel, nav: (String) -> Unit) {
val openDialogMsg = accountViewModel.account.transientPaymentRequests.collectAsStateWithLifecycle(null) val openDialogMsg = accountViewModel.account.transientPaymentRequests.collectAsStateWithLifecycle(null)
openDialogMsg.value?.firstOrNull()?.let { request -> openDialogMsg.value?.firstOrNull()?.let { request ->
PayRequestDialog( NotifyRequestDialog(
stringResource(id = R.string.payment_required_title, request.relayUrl.removePrefix("wss://").removeSuffix("/")), title = stringResource(id = R.string.payment_required_title, request.relayUrl.removePrefix("wss://").removeSuffix("/")),
request.description?.let { textContent = request.description,
stringResource(id = R.string.payment_required_explain, it) accountViewModel = accountViewModel,
} ?: stringResource(id = R.string.payment_required_explain_null_description), nav = nav
request.lnInvoice,
stringResource(id = R.string.payment_required_explain2),
request.otherOptionsUrl
) { ) {
accountViewModel.dismissPaymentRequest(request) accountViewModel.dismissPaymentRequest(request)
} }
+1 -6
View File
@@ -662,10 +662,5 @@
After installing, select the app you want to use in the Settings. After installing, select the app you want to use in the Settings.
</string> </string>
<string name="payment_required_title">Payment Required for %1$s</string> <string name="payment_required_title">Message from %1$s</string>
<string name="payment_required_explain">Relay has requested a payment of the invoice below for the %1$s.</string>
<string name="payment_required_explain_null_description">Relay has requested a payment of the invoice below</string>
<string name="payment_required_explain2">If you do not intend to use this relay anymore, please remove it from your relay list</string>
<string name="dismiss">Dismiss</string>
<string name="other_options">See other options</string>
</resources> </resources>