Refactoring the DVM payment code.
This commit is contained in:
@@ -143,17 +143,17 @@ object LocalCache {
|
|||||||
|
|
||||||
val deletionIndex = DeletionIndex()
|
val deletionIndex = DeletionIndex()
|
||||||
|
|
||||||
val observablesByKindAndETag = ConcurrentHashMap<Int, ConcurrentHashMap<HexKey, LatestByKindWithETag>>(10)
|
val observablesByKindAndETag = ConcurrentHashMap<Int, ConcurrentHashMap<HexKey, LatestByKindWithETag<Event>>>(10)
|
||||||
|
|
||||||
fun observeETag(
|
fun <T : Event> observeETag(
|
||||||
kind: Int,
|
kind: Int,
|
||||||
eventId: HexKey,
|
eventId: HexKey,
|
||||||
onCreate: () -> LatestByKindWithETag,
|
onCreate: () -> LatestByKindWithETag<T>,
|
||||||
): LatestByKindWithETag {
|
): LatestByKindWithETag<T> {
|
||||||
var eTagList = observablesByKindAndETag.get(kind)
|
var eTagList = observablesByKindAndETag.get(kind)
|
||||||
|
|
||||||
if (eTagList == null) {
|
if (eTagList == null) {
|
||||||
eTagList = ConcurrentHashMap<HexKey, LatestByKindWithETag>(1)
|
eTagList = ConcurrentHashMap<HexKey, LatestByKindWithETag<T>>(1) as ConcurrentHashMap<HexKey, LatestByKindWithETag<Event>>
|
||||||
observablesByKindAndETag.put(kind, eTagList)
|
observablesByKindAndETag.put(kind, eTagList)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,10 +162,10 @@ object LocalCache {
|
|||||||
return if (value != null) {
|
return if (value != null) {
|
||||||
value
|
value
|
||||||
} else {
|
} else {
|
||||||
val newObject = onCreate()
|
val newObject = onCreate() as LatestByKindWithETag<Event>
|
||||||
val obj = eTagList.putIfAbsent(eventId, newObject) ?: newObject
|
val obj = eTagList.putIfAbsent(eventId, newObject) ?: newObject
|
||||||
obj
|
obj
|
||||||
}
|
} as LatestByKindWithETag<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateObservables(event: Event) {
|
fun updateObservables(event: Event) {
|
||||||
|
|||||||
+4
-4
@@ -26,11 +26,11 @@ import com.vitorpamplona.quartz.events.Event
|
|||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.asStateFlow
|
import kotlinx.coroutines.flow.asStateFlow
|
||||||
|
|
||||||
class LatestByKindWithETag(private val kind: Int, private val eTag: String) {
|
class LatestByKindWithETag<T : Event>(private val kind: Int, private val eTag: String) {
|
||||||
private val _latest = MutableStateFlow<Event?>(null)
|
private val _latest = MutableStateFlow<T?>(null)
|
||||||
val latest = _latest.asStateFlow()
|
val latest = _latest.asStateFlow()
|
||||||
|
|
||||||
fun updateIfMatches(event: Event) {
|
fun updateIfMatches(event: T) {
|
||||||
if (event.kind == kind && event.isTaggedEvent(eTag)) {
|
if (event.kind == kind && event.isTaggedEvent(eTag)) {
|
||||||
if (event.createdAt > (_latest.value?.createdAt ?: 0)) {
|
if (event.createdAt > (_latest.value?.createdAt ?: 0)) {
|
||||||
_latest.tryEmit(event)
|
_latest.tryEmit(event)
|
||||||
@@ -65,7 +65,7 @@ class LatestByKindWithETag(private val kind: Int, private val eTag: String) {
|
|||||||
firstEvent.createdAt().compareTo(secondEvent.createdAt())
|
firstEvent.createdAt().compareTo(secondEvent.createdAt())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)?.event as? Event
|
)?.event as? T
|
||||||
|
|
||||||
_latest.tryEmit(latestNote)
|
_latest.tryEmit(latestNote)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,16 +176,16 @@ class AccountViewModel(val account: Account, val settings: SettingsState) : View
|
|||||||
account.reactTo(note, reaction)
|
account.reactTo(note, reaction)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observeByETag(
|
fun <T : Event> observeByETag(
|
||||||
kind: Int,
|
kind: Int,
|
||||||
eTag: HexKey,
|
eTag: HexKey,
|
||||||
): StateFlow<Event?> {
|
): StateFlow<T?> {
|
||||||
val observable =
|
val observable =
|
||||||
LocalCache.observeETag(
|
LocalCache.observeETag<T>(
|
||||||
kind = kind,
|
kind = kind,
|
||||||
eventId = eTag,
|
eventId = eTag,
|
||||||
) {
|
) {
|
||||||
LatestByKindWithETag(kind, eTag)
|
LatestByKindWithETag<T>(kind, eTag)
|
||||||
}
|
}
|
||||||
|
|
||||||
viewModelScope.launch(Dispatchers.IO) {
|
viewModelScope.launch(Dispatchers.IO) {
|
||||||
|
|||||||
+119
-77
@@ -22,7 +22,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn
|
|||||||
|
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.animation.core.animateFloatAsState
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
|
||||||
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.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
@@ -71,7 +70,6 @@ import com.vitorpamplona.amethyst.ui.components.LoadNote
|
|||||||
import com.vitorpamplona.amethyst.ui.navigation.routeToMessage
|
import com.vitorpamplona.amethyst.ui.navigation.routeToMessage
|
||||||
import com.vitorpamplona.amethyst.ui.note.DVMCard
|
import com.vitorpamplona.amethyst.ui.note.DVMCard
|
||||||
import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog
|
import com.vitorpamplona.amethyst.ui.note.ErrorMessageDialog
|
||||||
import com.vitorpamplona.amethyst.ui.note.LoadUser
|
|
||||||
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
import com.vitorpamplona.amethyst.ui.note.NoteAuthorPicture
|
||||||
import com.vitorpamplona.amethyst.ui.note.ObserveZapIcon
|
import com.vitorpamplona.amethyst.ui.note.ObserveZapIcon
|
||||||
import com.vitorpamplona.amethyst.ui.note.PayViaIntentDialog
|
import com.vitorpamplona.amethyst.ui.note.PayViaIntentDialog
|
||||||
@@ -92,10 +90,11 @@ import com.vitorpamplona.amethyst.ui.theme.QuoteBorder
|
|||||||
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
import com.vitorpamplona.amethyst.ui.theme.Size20Modifier
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
import com.vitorpamplona.amethyst.ui.theme.Size35dp
|
||||||
import com.vitorpamplona.amethyst.ui.theme.Size75dp
|
import com.vitorpamplona.amethyst.ui.theme.Size75dp
|
||||||
|
import com.vitorpamplona.quartz.encoders.LnInvoiceUtil
|
||||||
import com.vitorpamplona.quartz.events.AppDefinitionEvent
|
import com.vitorpamplona.quartz.events.AppDefinitionEvent
|
||||||
import com.vitorpamplona.quartz.events.Event
|
|
||||||
import com.vitorpamplona.quartz.events.NIP90ContentDiscoveryResponseEvent
|
import com.vitorpamplona.quartz.events.NIP90ContentDiscoveryResponseEvent
|
||||||
import com.vitorpamplona.quartz.events.NIP90StatusEvent
|
import com.vitorpamplona.quartz.events.NIP90StatusEvent
|
||||||
|
import com.vitorpamplona.quartz.events.PayInvoiceErrorResponse
|
||||||
import kotlinx.collections.immutable.ImmutableList
|
import kotlinx.collections.immutable.ImmutableList
|
||||||
import kotlinx.collections.immutable.persistentListOf
|
import kotlinx.collections.immutable.persistentListOf
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -116,7 +115,7 @@ fun NIP90ContentDiscoveryScreen(
|
|||||||
NIP90ContentDiscoveryScreen(baseNote, accountViewModel, nav)
|
NIP90ContentDiscoveryScreen(baseNote, accountViewModel, nav)
|
||||||
},
|
},
|
||||||
onBlank = {
|
onBlank = {
|
||||||
FeedDVM(baseNote, null, accountViewModel, nav)
|
FeedEmptyWithStatus(baseNote, stringResource(R.string.dvm_looking_for_app), accountViewModel, nav)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -160,7 +159,8 @@ fun NIP90ContentDiscoveryScreen(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
// TODO: Make a good splash screen with loading animation for this DVM.
|
// TODO: Make a good splash screen with loading animation for this DVM.
|
||||||
FeedDVM(appDefinition, null, accountViewModel, nav)
|
// FeedDVM(appDefinition, null, accountViewModel, nav)
|
||||||
|
FeedEmptyWithStatus(appDefinition, stringResource(R.string.dvm_requesting_job), accountViewModel, nav)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -178,7 +178,7 @@ fun ObserverContentDiscoveryResponse(
|
|||||||
|
|
||||||
val resultFlow =
|
val resultFlow =
|
||||||
remember(dvmRequestId) {
|
remember(dvmRequestId) {
|
||||||
accountViewModel.observeByETag(NIP90ContentDiscoveryResponseEvent.KIND, dvmRequestId.idHex)
|
accountViewModel.observeByETag<NIP90ContentDiscoveryResponseEvent>(NIP90ContentDiscoveryResponseEvent.KIND, dvmRequestId.idHex)
|
||||||
}
|
}
|
||||||
|
|
||||||
val latestResponse by resultFlow.collectAsStateWithLifecycle()
|
val latestResponse by resultFlow.collectAsStateWithLifecycle()
|
||||||
@@ -210,12 +210,20 @@ fun ObserverDvmStatusResponse(
|
|||||||
) {
|
) {
|
||||||
val statusFlow =
|
val statusFlow =
|
||||||
remember(dvmRequestId) {
|
remember(dvmRequestId) {
|
||||||
accountViewModel.observeByETag(NIP90StatusEvent.KIND, dvmRequestId)
|
accountViewModel.observeByETag<NIP90StatusEvent>(NIP90StatusEvent.KIND, dvmRequestId)
|
||||||
}
|
}
|
||||||
|
|
||||||
val latestStatus by statusFlow.collectAsStateWithLifecycle()
|
val latestStatus by statusFlow.collectAsStateWithLifecycle()
|
||||||
// TODO: Make a good splash screen with loading animation for this DVM.
|
// TODO: Make a good splash screen with loading animation for this DVM.
|
||||||
FeedDVM(appDefinition, latestStatus, accountViewModel, nav)
|
if (latestStatus != null) {
|
||||||
|
// TODO: Make a good splash screen with loading animation for this DVM.
|
||||||
|
latestStatus?.let {
|
||||||
|
FeedDVM(appDefinition, it, accountViewModel, nav)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO: Make a good splash screen with loading animation for this DVM.
|
||||||
|
FeedEmptyWithStatus(appDefinition, stringResource(R.string.dvm_waiting_status), accountViewModel, nav)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
@@ -265,56 +273,16 @@ fun RenderNostrNIP90ContentDiscoveryScreen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun FeedDVM(
|
fun FeedDVM(
|
||||||
appDefinitionNote: Note,
|
appDefinitionNote: Note,
|
||||||
latestStatus: Event?,
|
latestStatus: NIP90StatusEvent,
|
||||||
accountViewModel: AccountViewModel,
|
accountViewModel: AccountViewModel,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
var status = "waiting"
|
val status = latestStatus.status() ?: return
|
||||||
var content = ""
|
|
||||||
var lninvoice = ""
|
|
||||||
var amount: Long = 0
|
|
||||||
var statusNote: Note? = null
|
|
||||||
|
|
||||||
if (latestStatus == null) {
|
var currentStatus = status.description
|
||||||
content = stringResource(R.string.dvm_waiting_status)
|
|
||||||
} else {
|
|
||||||
latestStatus.let {
|
|
||||||
LoadNote(baseNoteHex = it.id, accountViewModel = accountViewModel) { stateNote ->
|
|
||||||
if (stateNote != null) {
|
|
||||||
statusNote = stateNote
|
|
||||||
}
|
|
||||||
}
|
|
||||||
content = it.content()
|
|
||||||
|
|
||||||
val statusTag =
|
|
||||||
it.tags().first { it2 ->
|
|
||||||
it2.size > 1 && (it2[0] == "status")
|
|
||||||
}
|
|
||||||
status = statusTag[1]
|
|
||||||
|
|
||||||
if (statusTag.size > 2 && content == "") {
|
|
||||||
// Some DVMs *might* send a the content in the second status tag (even though the NIP says otherwise)
|
|
||||||
content = statusTag[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status == "payment-required") {
|
|
||||||
val amountTag =
|
|
||||||
it.tags().first { it2 ->
|
|
||||||
it2.size > 1 && (it2[0] == "amount")
|
|
||||||
}
|
|
||||||
amount = amountTag[1].toLong()
|
|
||||||
|
|
||||||
if (amountTag.size > 2) {
|
|
||||||
// DVM *might* send a lninvoice in the second tag
|
|
||||||
lninvoice = amountTag[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(
|
Column(
|
||||||
Modifier
|
Modifier
|
||||||
@@ -347,35 +315,69 @@ fun FeedDVM(
|
|||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = DoubleVertSpacer)
|
Spacer(modifier = DoubleVertSpacer)
|
||||||
Text(content, textAlign = TextAlign.Center)
|
Text(currentStatus, textAlign = TextAlign.Center)
|
||||||
|
|
||||||
if (status == "payment-required") {
|
if (status.code == "payment-required") {
|
||||||
if (lninvoice != "") {
|
val amountTag = latestStatus.firstAmount()
|
||||||
|
val amount = amountTag?.amount
|
||||||
|
|
||||||
|
val invoice = amountTag?.lnInvoice
|
||||||
|
|
||||||
|
val thankYou = stringResource(id = R.string.dvm_waiting_to_confim_payment)
|
||||||
|
val nwcPaymentRequest = stringResource(id = R.string.nwc_payment_request)
|
||||||
|
|
||||||
|
if (invoice != null) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
Button(onClick = {
|
Button(onClick = {
|
||||||
if (accountViewModel.account.hasWalletConnectSetup()) {
|
if (accountViewModel.account.hasWalletConnectSetup()) {
|
||||||
// ZapPaymentHandler.payViaNWC(lninvoice, statusNote ...)
|
accountViewModel.account.sendZapPaymentRequestFor(
|
||||||
// TODO is there a way to use payViaNWC instead of this? It's suspended.
|
bolt11 = invoice,
|
||||||
|
zappedNote = null,
|
||||||
payViaIntent(
|
onSent = {
|
||||||
lninvoice,
|
currentStatus = nwcPaymentRequest
|
||||||
context,
|
},
|
||||||
onPaid = { println("paid") },
|
onResponse = { response ->
|
||||||
onError = { println("error") },
|
currentStatus =
|
||||||
|
if (response is PayInvoiceErrorResponse) {
|
||||||
|
context.getString(
|
||||||
|
R.string.wallet_connect_pay_invoice_error_error,
|
||||||
|
response.error?.message
|
||||||
|
?: response.error?.code?.toString() ?: "Error parsing error message",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
thankYou
|
||||||
|
}
|
||||||
|
},
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
payViaIntent(
|
payViaIntent(
|
||||||
lninvoice,
|
invoice,
|
||||||
context,
|
context,
|
||||||
onPaid = { println("paid") },
|
onPaid = {
|
||||||
onError = { println("error") },
|
currentStatus = thankYou
|
||||||
|
},
|
||||||
|
onError = {
|
||||||
|
currentStatus = it
|
||||||
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
Text(text = "Pay " + (amount / 1000).toString() + " Sats to the DVM")
|
val amountInInvoice =
|
||||||
|
try {
|
||||||
|
LnInvoiceUtil.getAmountInSats(invoice).toLong()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (amountInInvoice != null) {
|
||||||
|
Text(text = "Pay " + (amountInInvoice / 1000).toString() + " sats to the DVM")
|
||||||
} else {
|
} else {
|
||||||
statusNote?.let {
|
Text(text = "Pay Invoice from the DVM")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (amount != null) {
|
||||||
|
LoadNote(baseNoteHex = latestStatus.id, accountViewModel = accountViewModel) { stateNote ->
|
||||||
|
stateNote?.let {
|
||||||
ZapDVMButton(
|
ZapDVMButton(
|
||||||
baseNote = it,
|
baseNote = it,
|
||||||
amount = amount,
|
amount = amount,
|
||||||
@@ -388,6 +390,7 @@ fun FeedDVM(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ZapDVMButton(
|
fun ZapDVMButton(
|
||||||
@@ -400,6 +403,8 @@ fun ZapDVMButton(
|
|||||||
animationSize: Dp = 14.dp,
|
animationSize: Dp = 14.dp,
|
||||||
nav: (String) -> Unit,
|
nav: (String) -> Unit,
|
||||||
) {
|
) {
|
||||||
|
val noteAuthor = baseNote.author ?: return
|
||||||
|
|
||||||
var wantsToZap by remember { mutableStateOf<List<Long>?>(null) }
|
var wantsToZap by remember { mutableStateOf<List<Long>?>(null) }
|
||||||
var showErrorMessageDialog by remember { mutableStateOf<String?>(null) }
|
var showErrorMessageDialog by remember { mutableStateOf<String?>(null) }
|
||||||
var wantsToPay by
|
var wantsToPay by
|
||||||
@@ -408,15 +413,9 @@ fun ZapDVMButton(
|
|||||||
persistentListOf(),
|
persistentListOf(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
baseNote.author?.let {
|
|
||||||
LoadUser(baseUserHex = it.pubkeyHex, accountViewModel = accountViewModel) { author ->
|
// Makes sure the user is loaded to get his ln address
|
||||||
if (author != null) {
|
val userState = noteAuthor.live().metadata.observeAsState()
|
||||||
author.live().metadata.observeAsState()
|
|
||||||
println(author.info?.lnAddress())
|
|
||||||
println(author.info?.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
@@ -553,11 +552,54 @@ fun ZapDVMButton(
|
|||||||
if (hasZapped) {
|
if (hasZapped) {
|
||||||
Text(text = stringResource(id = R.string.thank_you))
|
Text(text = stringResource(id = R.string.thank_you))
|
||||||
} else {
|
} else {
|
||||||
Text(text = "Zap " + (amount / 1000).toString() + " Sats to the DVM") // stringResource(id = R.string.donate_now))
|
Text(text = "Zap " + (amount / 1000).toString() + " sats to the DVM") // stringResource(id = R.string.donate_now))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun FeedEmptyWithStatus(
|
||||||
|
appDefinitionNote: Note,
|
||||||
|
status: String,
|
||||||
|
accountViewModel: AccountViewModel,
|
||||||
|
nav: (String) -> Unit,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(20.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
) {
|
||||||
|
val card = observeAppDefinition(appDefinitionNote)
|
||||||
|
|
||||||
|
card.cover?.let {
|
||||||
|
AsyncImage(
|
||||||
|
model = it,
|
||||||
|
contentDescription = null,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.size(Size75dp)
|
||||||
|
.clip(QuoteBorder),
|
||||||
|
)
|
||||||
|
} ?: run { NoteAuthorPicture(appDefinitionNote, nav, accountViewModel, Size75dp) }
|
||||||
|
|
||||||
|
Spacer(modifier = DoubleVertSpacer)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = card.name,
|
||||||
|
fontWeight = FontWeight.Bold,
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = DoubleVertSpacer)
|
||||||
|
|
||||||
|
Text(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun observeAppDefinition(appDefinitionNote: Note): DVMCard {
|
fun observeAppDefinition(appDefinitionNote: Note): DVMCard {
|
||||||
val noteEvent =
|
val noteEvent =
|
||||||
|
|||||||
@@ -850,4 +850,6 @@
|
|||||||
<string name="dvm_looking_for_app">Looking for Application</string>
|
<string name="dvm_looking_for_app">Looking for Application</string>
|
||||||
<string name="dvm_waiting_status">Job Requested, waiting for a reply</string>
|
<string name="dvm_waiting_status">Job Requested, waiting for a reply</string>
|
||||||
<string name="dvm_requesting_job">Requesting Job from DVM</string>
|
<string name="dvm_requesting_job">Requesting Job from DVM</string>
|
||||||
|
<string name="nwc_payment_request">Payment request sent, waiting for confirmation from your wallet</string>
|
||||||
|
<string name="dvm_waiting_to_confim_payment">Waiting for DVM to confirm payment or send results</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -34,6 +34,39 @@ class NIP90StatusEvent(
|
|||||||
content: String,
|
content: String,
|
||||||
sig: HexKey,
|
sig: HexKey,
|
||||||
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
) : Event(id, pubKey, createdAt, KIND, tags, content, sig) {
|
||||||
|
class StatusCode(val code: String, val description: String)
|
||||||
|
|
||||||
|
class AmountInvoice(val amount: Long?, val lnInvoice: String?)
|
||||||
|
|
||||||
|
fun status(): StatusCode? {
|
||||||
|
return tags.firstOrNull { it.size > 1 && it[0] == "status" }?.let {
|
||||||
|
if (it.size > 2 && content == "") {
|
||||||
|
StatusCode(it[1], it[2])
|
||||||
|
} else {
|
||||||
|
StatusCode(it[1], content)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun firstAmount(): AmountInvoice? {
|
||||||
|
return tags.firstOrNull { it.size > 1 && it[0] == "amount" }?.let {
|
||||||
|
val amount = it[1].toLongOrNull()
|
||||||
|
if (it.size > 2) {
|
||||||
|
if (it[2].isNotBlank()) {
|
||||||
|
AmountInvoice(amount, it[2])
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (amount != null) {
|
||||||
|
AmountInvoice(amount, null)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val KIND = 7000
|
const val KIND = 7000
|
||||||
const val ALT = "NIP90 Status update"
|
const val ALT = "NIP90 Status update"
|
||||||
|
|||||||
Reference in New Issue
Block a user