Skip to content

Commit 3851847

Browse files
committed
fix: stabilize send scan routing
1 parent e6c4fff commit 3851847

2 files changed

Lines changed: 68 additions & 70 deletions

File tree

app/src/main/java/to/bitkit/repositories/LightningRepo.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1019,12 +1019,20 @@ class LightningRepo @Inject constructor(
10191019
}
10201020

10211021
suspend fun waitForUsableChannels() = withContext(bgDispatcher) {
1022-
if (_lightningState.value.channels.any { it.isUsable }) return@withContext
1022+
val state = _lightningState.value
1023+
if (!state.nodeLifecycleState.canRun()) return@withContext
1024+
1025+
if (state.channels.isEmpty()) return@withContext // no channel exists, don't wait
1026+
if (state.channels.any { it.isUsable }) return@withContext
10231027

10241028
Logger.info("Waiting for usable channels before sending payment", context = TAG)
10251029

10261030
withTimeoutOrNull(CHANNELS_USABLE_TIMEOUT_MS) {
1027-
_lightningState.first { state -> state.channels.any { it.isUsable } }
1031+
_lightningState.first {
1032+
!it.nodeLifecycleState.canRun() ||
1033+
it.channels.isEmpty() ||
1034+
it.channels.any { channel -> channel.isUsable }
1035+
}
10281036
} ?: Logger.warn("Timed out waiting for usable channels", context = TAG)
10291037
}
10301038

app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt

Lines changed: 58 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1306,6 +1306,7 @@ class AppViewModel @Inject constructor(
13061306
resetSendState()
13071307
resetQuickPay()
13081308

1309+
val fromMainScanner = isMainScanner
13091310
val input = result.removeLightningSchemes()
13101311

13111312
// TODO Workaround for https://github.com/synonymdev/bitkit-core/issues/63
@@ -1343,16 +1344,12 @@ class AppViewModel @Inject constructor(
13431344
.onSuccess { Logger.info("Handling decoded scan data: $it", context = TAG) }
13441345
.getOrNull()
13451346

1346-
if (isMainScanner && scan.isLightningRelated()) {
1347-
showSheet(Sheet.Send())
1348-
}
1349-
13501347
when (scan) {
1351-
is Scanner.OnChain -> onScanOnchain(scan.invoice, input)
1352-
is Scanner.Lightning -> onScanLightning(scan.invoice, input)
1353-
is Scanner.LnurlPay -> onScanLnurlPay(scan.data)
1354-
is Scanner.LnurlWithdraw -> onScanLnurlWithdraw(scan.data)
1355-
is Scanner.LnurlAuth -> onScanLnurlAuth(scan.data)
1348+
is Scanner.OnChain -> onScanOnchain(scan.invoice, input, fromMainScanner)
1349+
is Scanner.Lightning -> onScanLightning(scan.invoice, input, fromMainScanner)
1350+
is Scanner.LnurlPay -> onScanLnurlPay(scan.data, fromMainScanner)
1351+
is Scanner.LnurlWithdraw -> onScanLnurlWithdraw(scan.data, fromMainScanner)
1352+
is Scanner.LnurlAuth -> onScanLnurlAuth(scan.data, fromMainScanner)
13561353
is Scanner.LnurlChannel -> onScanLnurlChannel(scan.data)
13571354
is Scanner.NodeId -> onScanNodeId(scan)
13581355
is Scanner.Gift -> onScanGift(scan.code, scan.amount)
@@ -1369,7 +1366,11 @@ class AppViewModel @Inject constructor(
13691366
}
13701367

13711368
@Suppress("LongMethod", "CyclomaticComplexMethod", "ReturnCount")
1372-
private suspend fun onScanOnchain(invoice: OnChainInvoice, scanResult: String) {
1369+
private suspend fun onScanOnchain(
1370+
invoice: OnChainInvoice,
1371+
scanResult: String,
1372+
fromMainScanner: Boolean,
1373+
) {
13731374
val validatedAddress = runCatching { validateBitcoinAddress(invoice.address) }
13741375
.getOrElse {
13751376
hideSheet()
@@ -1416,14 +1417,11 @@ class AppViewModel @Inject constructor(
14161417
val quickPayHandled = handleQuickPayIfApplicable(
14171418
amountSats = lnAmountSats,
14181419
invoice = lnInvoice,
1420+
fromMainScanner = fromMainScanner,
14191421
)
14201422
if (quickPayHandled) return
14211423

1422-
if (isMainScanner) {
1423-
showSheet(Sheet.Send(SendRoute.Confirm))
1424-
} else {
1425-
setSendEffect(SendEffect.NavigateToConfirm)
1426-
}
1424+
navigateToSendRoute(fromMainScanner, SendRoute.Confirm, SendEffect.NavigateToConfirm)
14271425
refreshOnchainSendIfNeeded()
14281426
estimateLightningRoutingFeesIfNeeded()
14291427
return
@@ -1465,14 +1463,14 @@ class AppViewModel @Inject constructor(
14651463
context = TAG,
14661464
)
14671465

1468-
if (isMainScanner) {
1469-
showSheet(Sheet.Send(SendRoute.Amount))
1470-
} else {
1471-
setSendEffect(SendEffect.NavigateToAmount)
1472-
}
1466+
navigateToSendRoute(fromMainScanner, SendRoute.Amount, SendEffect.NavigateToAmount)
14731467
}
14741468

1475-
private suspend fun onScanLightning(invoice: LightningInvoice, scanResult: String) {
1469+
private suspend fun onScanLightning(
1470+
invoice: LightningInvoice,
1471+
scanResult: String,
1472+
fromMainScanner: Boolean,
1473+
) {
14761474
if (invoice.isExpired) {
14771475
hideSheet()
14781476
toast(
@@ -1484,7 +1482,11 @@ class AppViewModel @Inject constructor(
14841482
return
14851483
}
14861484

1487-
val quickPayHandled = handleQuickPayIfApplicable(amountSats = invoice.amountSatoshis, invoice = invoice)
1485+
val quickPayHandled = handleQuickPayIfApplicable(
1486+
amountSats = invoice.amountSatoshis,
1487+
invoice = invoice,
1488+
fromMainScanner = fromMainScanner,
1489+
)
14881490
if (quickPayHandled) return
14891491

14901492
lightningRepo.waitForUsableChannels()
@@ -1515,23 +1517,15 @@ class AppViewModel @Inject constructor(
15151517
if (invoice.amountSatoshis > 0uL) {
15161518
Logger.info("Found amount in invoice, proceeding with payment", context = TAG)
15171519

1518-
if (isMainScanner) {
1519-
showSheet(Sheet.Send(SendRoute.Confirm))
1520-
} else {
1521-
setSendEffect(SendEffect.NavigateToConfirm)
1522-
}
1520+
navigateToSendRoute(fromMainScanner, SendRoute.Confirm, SendEffect.NavigateToConfirm)
15231521
return
15241522
}
15251523
Logger.info("No amount found in invoice, proceeding to enter amount", context = TAG)
15261524

1527-
if (isMainScanner) {
1528-
showSheet(Sheet.Send(SendRoute.Amount))
1529-
} else {
1530-
setSendEffect(SendEffect.NavigateToAmount)
1531-
}
1525+
navigateToSendRoute(fromMainScanner, SendRoute.Amount, SendEffect.NavigateToAmount)
15321526
}
15331527

1534-
private suspend fun onScanLnurlPay(data: LnurlPayData) {
1528+
private suspend fun onScanLnurlPay(data: LnurlPayData, fromMainScanner: Boolean) {
15351529
Logger.debug("LNURL: $data", context = TAG)
15361530

15371531
val isFixed = data.isFixedAmount()
@@ -1561,26 +1555,22 @@ class AppViewModel @Inject constructor(
15611555
if (isFixed) {
15621556
Logger.info("Found fixed amount '$displaySats' sats in lnurlPay, proceeding with payment", context = TAG)
15631557

1564-
val quickPayHandled = handleQuickPayIfApplicable(amountSats = displaySats, lnurlPay = data)
1558+
val quickPayHandled = handleQuickPayIfApplicable(
1559+
amountSats = displaySats,
1560+
lnurlPay = data,
1561+
fromMainScanner = fromMainScanner,
1562+
)
15651563
if (quickPayHandled) return
15661564

1567-
if (isMainScanner) {
1568-
showSheet(Sheet.Send(SendRoute.Confirm))
1569-
} else {
1570-
setSendEffect(SendEffect.NavigateToConfirm)
1571-
}
1565+
navigateToSendRoute(fromMainScanner, SendRoute.Confirm, SendEffect.NavigateToConfirm)
15721566
return
15731567
}
15741568

15751569
Logger.info("No amount found in lnurlPay, proceeding to enter amount manually", context = TAG)
1576-
if (isMainScanner) {
1577-
showSheet(Sheet.Send(SendRoute.Amount))
1578-
} else {
1579-
setSendEffect(SendEffect.NavigateToAmount)
1580-
}
1570+
navigateToSendRoute(fromMainScanner, SendRoute.Amount, SendEffect.NavigateToAmount)
15811571
}
15821572

1583-
private suspend fun onScanLnurlWithdraw(data: LnurlWithdrawData) {
1573+
private suspend fun onScanLnurlWithdraw(data: LnurlWithdrawData, fromMainScanner: Boolean) {
15841574
Logger.debug("LNURL: $data", context = TAG)
15851575

15861576
val isFixed = data.isFixedAmount()
@@ -1609,30 +1599,39 @@ class AppViewModel @Inject constructor(
16091599

16101600
if (isFixed || minWithdrawable == maxWithdrawable) {
16111601
delay(TRANSITION_SCREEN_MS)
1612-
if (isMainScanner) {
1613-
showSheet(Sheet.Send(SendRoute.WithdrawConfirm))
1614-
} else {
1615-
setSendEffect(SendEffect.NavigateToWithdrawConfirm)
1616-
}
1602+
navigateToSendRoute(
1603+
fromMainScanner,
1604+
SendRoute.WithdrawConfirm,
1605+
SendEffect.NavigateToWithdrawConfirm,
1606+
)
16171607
return
16181608
}
16191609

1620-
if (isMainScanner) {
1621-
showSheet(Sheet.Send(SendRoute.Amount))
1622-
} else {
1623-
setSendEffect(SendEffect.NavigateToAmount)
1624-
}
1610+
navigateToSendRoute(fromMainScanner, SendRoute.Amount, SendEffect.NavigateToAmount)
16251611
}
16261612

1627-
private suspend fun onScanLnurlAuth(data: LnurlAuthData) {
1613+
private suspend fun onScanLnurlAuth(data: LnurlAuthData, fromMainScanner: Boolean) {
16281614
Logger.debug("LNURL: $data", context = TAG)
1629-
if (!isMainScanner) {
1615+
if (!fromMainScanner) {
16301616
hideSheet()
16311617
delay(TRANSITION_SCREEN_MS)
16321618
}
16331619
showSheet(Sheet.LnurlAuth(domain = data.domain, lnurl = data.uri, k1 = data.k1))
16341620
}
16351621

1622+
private fun navigateToSendRoute(
1623+
fromMainScanner: Boolean,
1624+
route: SendRoute,
1625+
effect: SendEffect,
1626+
) {
1627+
if (fromMainScanner) {
1628+
showSheet(Sheet.Send(route))
1629+
return
1630+
}
1631+
1632+
setSendEffect(effect)
1633+
}
1634+
16361635
fun requestLnurlAuth(callback: String, k1: String, domain: String) {
16371636
viewModelScope.launch {
16381637
lightningRepo.requestLnurlAuth(
@@ -1700,6 +1699,7 @@ class AppViewModel @Inject constructor(
17001699

17011700
private suspend fun handleQuickPayIfApplicable(
17021701
amountSats: ULong,
1702+
fromMainScanner: Boolean,
17031703
lnurlPay: LnurlPayData? = null,
17041704
invoice: LightningInvoice? = null,
17051705
): Boolean {
@@ -1733,11 +1733,7 @@ class AppViewModel @Inject constructor(
17331733

17341734
Logger.debug("QuickPayData: $quickPayData", context = TAG)
17351735

1736-
if (isMainScanner) {
1737-
showSheet(Sheet.Send(SendRoute.QuickPay))
1738-
} else {
1739-
setSendEffect(SendEffect.NavigateToQuickPay)
1740-
}
1736+
navigateToSendRoute(fromMainScanner, SendRoute.QuickPay, SendEffect.NavigateToQuickPay)
17411737
return true
17421738
}
17431739

@@ -2627,12 +2623,6 @@ class AppViewModel @Inject constructor(
26272623
}
26282624
}
26292625

2630-
private fun Scanner?.isLightningRelated(): Boolean = when (this) {
2631-
is Scanner.Lightning, is Scanner.LnurlPay -> true
2632-
is Scanner.OnChain -> invoice.params?.containsKey("lightning") == true
2633-
else -> false
2634-
}
2635-
26362626
// region send contract
26372627
@Stable
26382628
data class SendUiState(

0 commit comments

Comments
 (0)