Skip to content

Commit 13d044e

Browse files
committed
Merge branch 'master' into fix/custom-numpad
# Conflicts: # app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt # app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt
2 parents 3bec3ff + 8177510 commit 13d044e

File tree

16 files changed

+124
-88
lines changed

16 files changed

+124
-88
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ class BlocktankRepo @Inject constructor(
179179
description: String = Env.DEFAULT_INVOICE_MESSAGE,
180180
): Result<IcJitEntry> = withContext(bgDispatcher) {
181181
try {
182+
if (coreService.checkGeoBlock().first) throw ServiceError.GeoBlocked
182183
val nodeId = lightningService.nodeId ?: throw ServiceError.NodeNotStarted
183184
val lspBalance = getDefaultLspBalance(clientBalance = amountSats)
184185
val channelSizeSat = amountSats + lspBalance
@@ -207,6 +208,8 @@ class BlocktankRepo @Inject constructor(
207208
channelExpiryWeeks: UInt = DEFAULT_CHANNEL_EXPIRY_WEEKS,
208209
): Result<IBtOrder> = withContext(bgDispatcher) {
209210
try {
211+
if (coreService.checkGeoBlock().first) throw ServiceError.GeoBlocked
212+
210213
val options = defaultCreateOrderOptions(clientBalanceSat = spendingBalanceSats)
211214

212215
Logger.info(

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

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ import kotlin.time.Duration
6262
import kotlin.time.Duration.Companion.minutes
6363
import kotlin.time.Duration.Companion.seconds
6464

65-
private const val SYNC_TIMEOUT_MS = 10_000L
65+
private const val SYNC_TIMEOUT_MS = 15_000L
6666

6767
@Singleton
6868
class LightningRepo @Inject constructor(
@@ -246,12 +246,11 @@ class LightningRepo @Inject constructor(
246246
}
247247

248248
/**Updates the shouldBlockLightning state and returns the current value*/
249-
private suspend fun updateGeoBlockState(): Boolean {
250-
val shouldBlock = coreService.shouldBlockLightning()
249+
suspend fun updateGeoBlockState() {
250+
val (isGeoBlocked, shouldBlockLightning) = coreService.checkGeoBlock()
251251
_lightningState.update {
252-
it.copy(shouldBlockLightning = shouldBlock)
252+
it.copy(shouldBlockLightning = shouldBlockLightning, isGeoBlocked = isGeoBlocked)
253253
}
254-
return shouldBlock
255254
}
256255

257256
fun setInitNodeLifecycleState() {
@@ -409,7 +408,9 @@ class LightningRepo @Inject constructor(
409408
}
410409

411410
suspend fun connectPeer(peer: LnPeer): Result<Unit> = executeWhenNodeRunning("connectPeer") {
412-
lightningService.connectPeer(peer)
411+
lightningService.connectPeer(peer).onFailure { e ->
412+
return@executeWhenNodeRunning Result.failure(e)
413+
}
413414
syncState()
414415
Result.success(Unit)
415416
}
@@ -430,7 +431,8 @@ class LightningRepo @Inject constructor(
430431
description: String,
431432
expirySeconds: UInt = 86_400u,
432433
): Result<String> = executeWhenNodeRunning("Create invoice") {
433-
if (updateGeoBlockState()) {
434+
updateGeoBlockState()
435+
if (lightningState.value.shouldBlockLightning) {
434436
return@executeWhenNodeRunning Result.failure(ServiceError.GeoBlocked)
435437
}
436438

@@ -682,8 +684,13 @@ class LightningRepo @Inject constructor(
682684
}
683685
}
684686

685-
fun canSend(amountSats: ULong): Boolean =
686-
_lightningState.value.nodeLifecycleState.isRunning() && lightningService.canSend(amountSats)
687+
suspend fun canSend(amountSats: ULong, fallbackToCachedBalance: Boolean = true): Boolean {
688+
return if (!_lightningState.value.nodeLifecycleState.isRunning() && fallbackToCachedBalance) {
689+
amountSats <= (cacheStore.data.first().balance?.maxSendLightningSats ?: 0u)
690+
} else {
691+
lightningService.canSend(amountSats)
692+
}
693+
}
687694

688695
fun getSyncFlow(): Flow<Unit> = lightningService.syncFlow()
689696

@@ -850,4 +857,5 @@ data class LightningState(
850857
val channels: List<ChannelDetails> = emptyList(),
851858
val isSyncingWallet: Boolean = false,
852859
val shouldBlockLightning: Boolean = false,
860+
val isGeoBlocked: Boolean = false,
853861
)

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ class WalletRepo @Inject constructor(
102102
suspend fun refreshBip21(force: Boolean = false): Result<Unit> = withContext(bgDispatcher) {
103103
Logger.debug("Refreshing bip21 (force: $force)", context = TAG)
104104

105-
if (coreService.shouldBlockLightning()) {
105+
if (coreService.checkGeoBlock().second) {
106106
_walletState.update {
107107
it.copy(receiveOnSpendingBalance = false)
108108
}
@@ -347,7 +347,7 @@ class WalletRepo @Inject constructor(
347347
}
348348

349349
suspend fun toggleReceiveOnSpendingBalance(): Result<Unit> = withContext(bgDispatcher) {
350-
if (!_walletState.value.receiveOnSpendingBalance && coreService.shouldBlockLightning()) {
350+
if (!_walletState.value.receiveOnSpendingBalance && coreService.checkGeoBlock().second) {
351351
return@withContext Result.failure(ServiceError.GeoBlocked)
352352
}
353353

@@ -419,7 +419,7 @@ class WalletRepo @Inject constructor(
419419
return@withContext try {
420420
if (!_walletState.value.receiveOnSpendingBalance) return@withContext Result.success(false)
421421

422-
if (coreService.checkGeoStatus() == true) return@withContext Result.success(false)
422+
if (coreService.checkGeoBlock().first) return@withContext Result.success(false)
423423

424424
val channels = lightningRepo.lightningState.value.channels
425425
if (channels.filterOpen().isEmpty()) return@withContext Result.success(false)

app/src/main/java/to/bitkit/services/CoreService.kt

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -112,28 +112,34 @@ class CoreService @Inject constructor(
112112
}
113113
}
114114

115-
/** Returns true if geo blocked */
116-
suspend fun checkGeoStatus(): Boolean? {
115+
private suspend fun isGeoBlocked(): Boolean {
117116
return ServiceQueue.CORE.background {
118-
Logger.verbose("Checking geo status…", context = "GeoCheck")
119-
val response = httpClient.get(Env.geoCheckUrl)
120-
121-
when (response.status.value) {
122-
HttpStatusCode.OK.value -> {
123-
Logger.verbose("Region allowed", context = "GeoCheck")
124-
false
125-
}
126-
127-
HttpStatusCode.Forbidden.value -> {
128-
Logger.warn("Region blocked", context = "GeoCheck")
129-
true
130-
}
131-
132-
else -> {
133-
Logger.warn("Unexpected status code: ${response.status.value}", context = "GeoCheck")
134-
null
117+
runCatching {
118+
Logger.verbose("Checking geo status…", context = "GeoCheck")
119+
val response = httpClient.get(Env.geoCheckUrl)
120+
121+
when (response.status.value) {
122+
HttpStatusCode.OK.value -> {
123+
Logger.verbose("Region allowed", context = "GeoCheck")
124+
false
125+
}
126+
127+
HttpStatusCode.Forbidden.value -> {
128+
Logger.warn("Region blocked", context = "GeoCheck")
129+
true
130+
}
131+
132+
else -> {
133+
Logger.warn(
134+
"Unexpected status code: ${response.status.value}, defaulting to false",
135+
context = "GeoCheck"
136+
)
137+
false
138+
}
135139
}
136-
}
140+
}.onFailure {
141+
Logger.warn("Error. defaulting isGeoBlocked to false", context = "GeoCheck")
142+
}.getOrDefault(false)
137143
}
138144
}
139145

@@ -149,7 +155,18 @@ class CoreService @Inject constructor(
149155

150156
suspend fun hasExternalNode() = getConnectedPeers().any { connectedPeer -> connectedPeer !in getLspPeers() }
151157

152-
suspend fun shouldBlockLightning() = checkGeoStatus() == true && !hasExternalNode()
158+
/**
159+
* This method checks if the device is geo blocked and if should block lighting features
160+
* @return Pair(isGeoBlocked, shouldBlockLightning)*/
161+
suspend fun checkGeoBlock(): Pair<Boolean, Boolean> {
162+
val geoBlocked = isGeoBlocked()
163+
val shouldBlockLightning = when {
164+
hasExternalNode() -> false
165+
else -> geoBlocked
166+
}
167+
168+
return Pair(geoBlocked, shouldBlockLightning)
169+
}
153170
}
154171

155172
// endregion

app/src/main/java/to/bitkit/services/LightningService.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -445,11 +445,13 @@ class LightningService @Inject constructor(
445445
.getOrElse { e -> throw LdkError(e as NodeException) }
446446

447447
return ServiceQueue.LDK.background {
448-
when (sats != null) {
449-
true -> node.bolt11Payment().sendUsingAmount(bolt11Invoice, sats * 1000u, null)
450-
else -> node.bolt11Payment().send(bolt11Invoice, null)
448+
runCatching {
449+
when (sats != null) {
450+
true -> node.bolt11Payment().sendUsingAmount(bolt11Invoice, sats * 1000u, null)
451+
else -> node.bolt11Payment().send(bolt11Invoice, null)
452+
}
451453
}
452-
}
454+
}.getOrThrow()
453455
}
454456

455457
suspend fun estimateRoutingFees(bolt11: String): Result<ULong> {

app/src/main/java/to/bitkit/ui/ContentView.kt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,8 @@ fun ContentView(
333333
ReceiveSheet(
334334
walletState = walletUiState,
335335
navigateToExternalConnection = {
336-
navController.navigate(Routes.ExternalConnection)
336+
navController.navigate(Routes.ExternalConnection())
337+
appViewModel.hideSheet()
337338
}
338339
)
339340
}
@@ -515,6 +516,8 @@ private fun RootNavHost(
515516
}
516517
composableWithDefaultTransitions<Routes.Funding> {
517518
val hasSeenSpendingIntro by settingsViewModel.hasSeenSpendingIntro.collectAsState()
519+
val isGeoBlocked by appViewModel.isGeoBlocked.collectAsStateWithLifecycle()
520+
518521
FundingScreen(
519522
onTransfer = {
520523
if (!hasSeenSpendingIntro) {
@@ -534,6 +537,7 @@ private fun RootNavHost(
534537
onAdvanced = { navController.navigate(Routes.FundingAdvanced) },
535538
onBackClick = { navController.popBackStack() },
536539
onCloseClick = { navController.navigateToHome() },
540+
isGeoBlocked = isGeoBlocked
537541
)
538542
}
539543
composableWithDefaultTransitions<Routes.FundingAdvanced> {
@@ -1352,8 +1356,8 @@ fun NavController.navigateToWidgetsSettings() = navigate(
13521356
route = Routes.WidgetsSettings,
13531357
)
13541358

1355-
fun NavController.navigateToQuickPaySettings() = navigate(
1356-
route = Routes.QuickPaySettings,
1359+
fun NavController.navigateToQuickPaySettings(hasSeenIntro: Boolean = true) = navigate(
1360+
route = if (hasSeenIntro) Routes.QuickPaySettings else Routes.QuickPayIntro,
13571361
)
13581362

13591363
fun NavController.navigateToTagsSettings() = navigate(

app/src/main/java/to/bitkit/ui/MainActivity.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package to.bitkit.ui
22

3+
import android.app.NotificationManager
34
import android.content.Intent
45
import android.os.Bundle
56
import androidx.activity.compose.setContent
@@ -70,10 +71,11 @@ class MainActivity : FragmentActivity() {
7071

7172
initNotificationChannel()
7273
initNotificationChannel(
73-
// TODO EXTRACT TO Strings
74+
// TODO Transifex
7475
id = CHANNEL_ID_NODE,
7576
name = "Lightning node notification",
7677
desc = "Channel for LightningNodeService",
78+
importance = NotificationManager.IMPORTANCE_LOW
7779
)
7880
startForegroundService(Intent(this, LightningNodeService::class.java))
7981
installSplashScreen()
@@ -191,9 +193,10 @@ private fun OnboardingNav(
191193
}
192194
composableWithDefaultTransitions<StartupRoutes.Slides> { navBackEntry ->
193195
val route = navBackEntry.toRoute<StartupRoutes.Slides>()
196+
val isGeoBlocked by appViewModel.isGeoBlocked.collectAsStateWithLifecycle()
194197
OnboardingSlidesScreen(
195198
currentTab = route.tab,
196-
isGeoBlocked = appViewModel.isGeoBlocked == true,
199+
isGeoBlocked = isGeoBlocked,
197200
onAdvancedSetupClick = { startupNavController.navigate(StartupRoutes.Advanced) },
198201
onCreateClick = {
199202
scope.launch {

app/src/main/java/to/bitkit/ui/screens/transfer/FundingScreen.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import androidx.compose.ui.unit.dp
2828
import to.bitkit.R
2929
import to.bitkit.env.Env
3030
import to.bitkit.ui.LocalBalances
31-
import to.bitkit.ui.appViewModel
3231
import to.bitkit.ui.components.BodyM
3332
import to.bitkit.ui.components.BodyMB
3433
import to.bitkit.ui.components.Display
@@ -47,13 +46,13 @@ fun FundingScreen(
4746
onAdvanced: () -> Unit = {},
4847
onBackClick: () -> Unit = {},
4948
onCloseClick: () -> Unit = {},
49+
isGeoBlocked: Boolean
5050
) {
5151
val balances = LocalBalances.current
5252
val canTransfer = remember(balances.totalOnchainSats) {
5353
balances.totalOnchainSats >= Env.TransactionDefaults.recommendedBaseFee
5454
}
5555
var showNoFundsAlert by remember { mutableStateOf(false) }
56-
val isGeoBlocked = appViewModel?.isGeoBlocked == true
5756

5857
ScreenColumn {
5958
AppTopBar(
@@ -164,6 +163,6 @@ fun FundingScreen(
164163
@Composable
165164
private fun FundingScreenPreview() {
166165
AppThemeSurface {
167-
FundingScreen()
166+
FundingScreen(isGeoBlocked = false)
168167
}
169168
}

app/src/main/java/to/bitkit/ui/screens/wallets/receive/ReceiveSheet.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ fun ReceiveSheet(
8686
walletState = walletState,
8787
onCjitToggle = { isOn ->
8888
when {
89-
isOn && lightningState.shouldBlockLightning -> {
89+
isOn && lightningState.shouldBlockLightning -> { // TODO SHOULD BLOCK HERE
9090
navController.navigate(ReceiveRoute.GeoBlock)
9191
}
9292

app/src/main/java/to/bitkit/ui/screens/wallets/send/SendAmountScreen.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ private fun SendAmountNodeRunning(
274274
PrimaryButton(
275275
text = stringResource(R.string.common__continue),
276276
enabled = uiState.isAmountInputValid,
277+
isLoading = uiState.isLoading,
277278
onClick = onContinue,
278279
modifier = Modifier.testTag("ContinueAmount")
279280
)

0 commit comments

Comments
 (0)