From 1a6a1494423a0532db6bf5e9c0fac94e74beae54 Mon Sep 17 00:00:00 2001 From: Guzinowich Date: Sat, 22 Aug 2026 11:23:10 +0300 Subject: [PATCH 1/4] feat: deep link spending hw sign --- app/src/main/java/to/bitkit/ui/ContentView.kt | 18 +++++-- .../to/bitkit/ui/utils/ScreenDeepLinks.kt | 17 ++++++ .../to/bitkit/viewmodels/TransferViewModel.kt | 26 +++++++++- .../to/bitkit/ui/utils/ScreenDeepLinksTest.kt | 31 +++++++++++ .../viewmodels/TransferViewModelTest.kt | 52 +++++++++++++++++++ changelog.d/next/1126.added.md | 1 + 6 files changed, 141 insertions(+), 4 deletions(-) create mode 100644 changelog.d/next/1126.added.md diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index ba977db73..2c26f6f19 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -322,6 +322,14 @@ fun ContentView( return@LaunchedEffect } + ScreenDeepLinks.spendingHwSignLink(uri)?.let { link -> + val prepared = transferViewModel.prepareSpendingHwSign(link.walletId, link.orderId) + if (!prepared) { + Logger.warn("Unhandled screen deeplink '$uri'", context = "ContentView") + return@LaunchedEffect + } + } + val request = Intent(Intent.ACTION_VIEW, uri) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) val handled = navController.handleDeepLink(request) @@ -840,10 +848,14 @@ private fun RootNavHost( viewModel = transferViewModel, isOffline = connectivityState != ConnectivityState.CONNECTED, onBackClick = { navController.popBackStack() }, - onOrderCreated = { navController.navigateTo(Routes.SpendingHwSign(walletId)) }, + onOrderCreated = { + transferViewModel.spendingUiState.value.order?.id?.let { orderId -> + navController.navigateTo(Routes.SpendingHwSign(walletId, orderId)) + } + }, ) } - composableWithDefaultTransitions { entry -> + deepLinkableComposable { entry -> val walletId = entry.toRoute().walletId SpendingHwSignScreen( walletId = walletId, @@ -2126,7 +2138,7 @@ sealed interface Routes { data class SpendingAmountHw(val walletId: String) : Routes.DeepLinkable @Serializable - data class SpendingHwSign(val walletId: String) : Routes.InternalOnly + data class SpendingHwSign(val walletId: String, val orderId: String) : Routes.DeepLinkable @Serializable data object SpendingHwSigned : Routes.InternalOnly diff --git a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt index e727b0f2d..d5af11641 100644 --- a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt +++ b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt @@ -11,6 +11,7 @@ object ScreenDeepLinks { const val HOST = "screen" private const val BASE_URI = "$SCHEME://$HOST" + private const val SPENDING_HW_SIGN_ID = "spending-hw-sign" private val CAMEL_HUMP = Regex("(?<=[a-z0-9])(?=[A-Z])") @@ -38,6 +39,17 @@ object ScreenDeepLinks { fun isScreenDeepLink(uri: Uri): Boolean = uri.scheme?.lowercase() == SCHEME && uri.host?.lowercase() == HOST + fun spendingHwSignLink(uri: Uri): SpendingHwSignLink? { + if (!isScreenDeepLink(uri)) return null + val segments = uri.pathSegments.orEmpty() + if (segments.size != 3) return null + if (!segments[0].equals(SPENDING_HW_SIGN_ID, ignoreCase = true)) return null + val walletId = segments[1] + val orderId = segments[2] + if (walletId.isBlank() || orderId.isBlank()) return null + return SpendingHwSignLink(walletId = walletId, orderId = orderId) + } + fun detachScreenUri(intent: Intent): Boolean { val uri = intent.data ?: return false if (!isScreenDeepLink(uri)) return false @@ -46,3 +58,8 @@ object ScreenDeepLinks { return true } } + +data class SpendingHwSignLink( + val walletId: String, + val orderId: String, +) diff --git a/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt index 5333266ec..f12409d12 100644 --- a/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt @@ -581,6 +581,31 @@ class TransferViewModel @Inject constructor( private suspend fun onOrderCreated(order: IBtOrder) { settingsStore.update { it.copy(lightningSetupStep = 0) } + adoptSpendingOrder(order) + setTransferEffect(TransferEffect.OnOrderCreated) + } + + suspend fun prepareSpendingHwSign(walletId: String, orderId: String): Boolean { + if (walletId.isBlank() || orderId.isBlank()) return false + if (hwWalletRepo.wallets.value.none { it.id == walletId }) { + Logger.warn("Refused spending hw sign deeplink, unknown wallet '$walletId'", context = TAG) + return false + } + val current = _spendingUiState.value.order + if (current?.id == orderId) return true + + val order = blocktankRepo.getOrder(orderId, refresh = true).getOrNull() + if (order == null) { + Logger.warn("Refused spending hw sign deeplink, missing order '$orderId'", context = TAG) + return false + } + + settingsStore.update { it.copy(lightningSetupStep = 0) } + adoptSpendingOrder(order) + return true + } + + private fun adoptSpendingOrder(order: IBtOrder) { pendingHwFundingBroadcast = null hwFeeEstimateJob?.cancel() hwFeeEstimateJob = null @@ -593,7 +618,6 @@ class TransferViewModel @Inject constructor( hwMiningFeeSats = 0uL, ) } - setTransferEffect(TransferEffect.OnOrderCreated) } private fun updateAvailableAmount() { diff --git a/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt b/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt index 03803aa52..e93ef204b 100644 --- a/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt +++ b/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt @@ -45,6 +45,37 @@ class ScreenDeepLinksTest : BaseUnitTest() { assertEquals("bitkit://screen/activity-assign-contact/{id}", links.single().uriPattern) } + @Test + fun `SpendingHwSign required arguments are wallet and order path segments`() { + if (!ScreenDeepLinks.isEnabled) return + val links = ScreenDeepLinks.linksFor(Routes.SpendingHwSign::class) + + assertEquals( + "bitkit://screen/spending-hw-sign/{walletId}/{orderId}", + links.single().uriPattern, + ) + } + + @Test + fun `spendingHwSignLink reads wallet and order ids from the path`() { + val uri = Uri.parse("bitkit://screen/spending-hw-sign/hardware-wallet/order-1") + + val link = ScreenDeepLinks.spendingHwSignLink(uri) + + assertNotNull(link) + assertEquals("hardware-wallet", link.walletId) + assertEquals("order-1", link.orderId) + } + + @Test + fun `spendingHwSignLink returns null when the order id is missing`() { + val uri = Uri.parse("bitkit://screen/spending-hw-sign/hardware-wallet") + + val link = ScreenDeepLinks.spendingHwSignLink(uri) + + assertNull(link) + } + @Test fun `a route with both argument kinds keeps the required one in the path`() { if (!ScreenDeepLinks.isEnabled) return diff --git a/app/src/test/java/to/bitkit/viewmodels/TransferViewModelTest.kt b/app/src/test/java/to/bitkit/viewmodels/TransferViewModelTest.kt index a1f0f7d56..7b852ec85 100644 --- a/app/src/test/java/to/bitkit/viewmodels/TransferViewModelTest.kt +++ b/app/src/test/java/to/bitkit/viewmodels/TransferViewModelTest.kt @@ -330,6 +330,58 @@ class TransferViewModelTest : BaseUnitTest() { verify(hwWalletRepo, never()).signFunding(any(), any()) } + @Test + fun `prepareSpendingHwSign loads the named order when the wallet is known`() = test { + val order = previewBtOrder() + whenever(hwWalletRepo.wallets) + .thenReturn(MutableStateFlow(persistentListOf(hwWallet(HARDWARE_WALLET_ID, connected = true)))) + whenever { blocktankRepo.getOrder(eq(order.id), eq(true)) }.thenReturn(Result.success(order)) + + val prepared = sut.prepareSpendingHwSign(HARDWARE_WALLET_ID, order.id) + + assertTrue(prepared) + assertEquals(order.id, sut.spendingUiState.value.order?.id) + } + + @Test + fun `prepareSpendingHwSign refuses an unknown wallet`() = test { + val order = previewBtOrder() + whenever(hwWalletRepo.wallets).thenReturn(MutableStateFlow(persistentListOf())) + + val prepared = sut.prepareSpendingHwSign(HARDWARE_WALLET_ID, order.id) + + assertFalse(prepared) + assertNull(sut.spendingUiState.value.order) + verify(blocktankRepo, never()).getOrder(any(), any()) + } + + @Test + fun `prepareSpendingHwSign refuses a missing order`() = test { + val order = previewBtOrder() + whenever(hwWalletRepo.wallets) + .thenReturn(MutableStateFlow(persistentListOf(hwWallet(HARDWARE_WALLET_ID, connected = true)))) + whenever { blocktankRepo.getOrder(eq(order.id), eq(true)) }.thenReturn(Result.success(null)) + + val prepared = sut.prepareSpendingHwSign(HARDWARE_WALLET_ID, order.id) + + assertFalse(prepared) + assertNull(sut.spendingUiState.value.order) + } + + @Test + fun `prepareSpendingHwSign reuses the in-memory order without fetching`() = test { + val order = previewBtOrder() + whenever(hwWalletRepo.wallets) + .thenReturn(MutableStateFlow(persistentListOf(hwWallet(HARDWARE_WALLET_ID, connected = true)))) + whenever { blocktankRepo.getOrder(eq(order.id), eq(true)) }.thenReturn(Result.success(order)) + sut.prepareSpendingHwSign(HARDWARE_WALLET_ID, order.id) + + val prepared = sut.prepareSpendingHwSign(HARDWARE_WALLET_ID, order.id) + + assertTrue(prepared) + verify(blocktankRepo, times(1)).getOrder(eq(order.id), eq(true)) + } + @Test fun `updateHwFundingFeeEstimate ignores superseded estimate`() = test { val orderA = previewBtOrder() diff --git a/changelog.d/next/1126.added.md b/changelog.d/next/1126.added.md new file mode 100644 index 000000000..8a84858b5 --- /dev/null +++ b/changelog.d/next/1126.added.md @@ -0,0 +1 @@ +Dev-mode deep links can open the hardware-wallet transfer sign screen from a wallet id and Blocktank order id. From f405cd3de691b5fcf1a61b0e0f84752bea23136d Mon Sep 17 00:00:00 2001 From: Guzinowich Date: Sat, 22 Aug 2026 11:48:12 +0300 Subject: [PATCH 2/4] fix: consume deeplink after prepare --- app/src/main/java/to/bitkit/ui/ContentView.kt | 15 ++++++++------- .../ui/screens/transfer/SpendingAdvancedScreen.kt | 2 +- .../ui/screens/transfer/SpendingAmountScreen.kt | 2 +- .../transfer/hardware/SpendingAmountHwScreen.kt | 4 ++-- .../transfer/hardware/SpendingHwSignScreen.kt | 3 ++- .../java/to/bitkit/ui/utils/ScreenDeepLinks.kt | 4 ++-- .../to/bitkit/viewmodels/TransferViewModel.kt | 6 +++--- app/src/test/java/to/bitkit/ui/ContentViewTest.kt | 2 +- .../to/bitkit/ui/utils/ScreenDeepLinksTest.kt | 3 ++- 9 files changed, 22 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/ContentView.kt b/app/src/main/java/to/bitkit/ui/ContentView.kt index 2c26f6f19..0be3ca485 100644 --- a/app/src/main/java/to/bitkit/ui/ContentView.kt +++ b/app/src/main/java/to/bitkit/ui/ContentView.kt @@ -315,10 +315,10 @@ fun ContentView( val uri = pendingScreenDeepLink ?: return@LaunchedEffect navController.currentBackStackEntryFlow.first() - appViewModel.consumeScreenDeepLink() SheetDeepLinks.sheetFor(uri)?.let { appViewModel.showSheet(it) + appViewModel.consumeScreenDeepLink() return@LaunchedEffect } @@ -326,6 +326,7 @@ fun ContentView( val prepared = transferViewModel.prepareSpendingHwSign(link.walletId, link.orderId) if (!prepared) { Logger.warn("Unhandled screen deeplink '$uri'", context = "ContentView") + appViewModel.consumeScreenDeepLink() return@LaunchedEffect } } @@ -340,6 +341,7 @@ fun ContentView( if (!handled) { Logger.warn("Unhandled screen deeplink '$uri'", context = "ContentView") } + appViewModel.consumeScreenDeepLink() } LaunchedEffect(appViewModel) { @@ -848,17 +850,16 @@ private fun RootNavHost( viewModel = transferViewModel, isOffline = connectivityState != ConnectivityState.CONNECTED, onBackClick = { navController.popBackStack() }, - onOrderCreated = { - transferViewModel.spendingUiState.value.order?.id?.let { orderId -> - navController.navigateTo(Routes.SpendingHwSign(walletId, orderId)) - } + onOrderCreated = { orderId -> + navController.navigateTo(Routes.SpendingHwSign(walletId, orderId)) }, ) } deepLinkableComposable { entry -> - val walletId = entry.toRoute().walletId + val route = entry.toRoute() SpendingHwSignScreen( - walletId = walletId, + walletId = route.walletId, + orderId = route.orderId, viewModel = transferViewModel, onBackClick = { navController.popBackStack() }, onCloseClick = { navController.navigateToHome() }, diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt index d91a05306..38732f282 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAdvancedScreen.kt @@ -92,7 +92,7 @@ fun SpendingAdvancedScreen( LaunchedEffect(Unit) { viewModel.transferEffects.collect { effect -> when (effect) { - TransferEffect.OnOrderCreated -> currentOnOrderCreated() + is TransferEffect.OnOrderCreated -> currentOnOrderCreated() is TransferEffect.ToastException -> { isLoading = false app.toast(effect.e) diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt index ec1b4349d..f9e9cc81c 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/SpendingAmountScreen.kt @@ -82,7 +82,7 @@ fun SpendingAmountScreen( LaunchedEffect(Unit) { viewModel.transferEffects.collect { effect -> when (effect) { - TransferEffect.OnOrderCreated -> onOrderCreated() + is TransferEffect.OnOrderCreated -> onOrderCreated() is TransferEffect.ToastError -> toast(effect.title, effect.description) is TransferEffect.ToastException -> toastException(effect.e) else -> Unit diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingAmountHwScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingAmountHwScreen.kt index eef71f839..cd7ac3456 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingAmountHwScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingAmountHwScreen.kt @@ -65,7 +65,7 @@ fun SpendingAmountHwScreen( viewModel: TransferViewModel, isOffline: Boolean, onBackClick: () -> Unit = {}, - onOrderCreated: () -> Unit = {}, + onOrderCreated: (String) -> Unit = {}, currencies: CurrencyState = LocalCurrencies.current, amountInputViewModel: AmountInputViewModel = hiltViewModel(), ) { @@ -83,7 +83,7 @@ fun SpendingAmountHwScreen( LaunchedEffect(Unit) { viewModel.transferEffects.collect { effect -> when (effect) { - TransferEffect.OnOrderCreated -> onOrderCreated() + is TransferEffect.OnOrderCreated -> onOrderCreated(effect.orderId) is TransferEffect.ToastError -> ToastEventBus.send( type = Toast.ToastType.ERROR, title = effect.title, diff --git a/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingHwSignScreen.kt b/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingHwSignScreen.kt index 65901f5a1..9ad9504d6 100644 --- a/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingHwSignScreen.kt +++ b/app/src/main/java/to/bitkit/ui/screens/transfer/hardware/SpendingHwSignScreen.kt @@ -42,6 +42,7 @@ import to.bitkit.viewmodels.TransferViewModel @Composable fun SpendingHwSignScreen( walletId: String, + orderId: String, viewModel: TransferViewModel, onBackClick: () -> Unit, onCloseClick: () -> Unit, @@ -50,7 +51,7 @@ fun SpendingHwSignScreen( ) { val state by viewModel.spendingUiState.collectAsStateWithLifecycle() - val order = state.order ?: run { + val order = state.order?.takeIf { it.id == orderId } ?: run { onCloseClick() return } diff --git a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt index d5af11641..bea955fea 100644 --- a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt +++ b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt @@ -11,7 +11,6 @@ object ScreenDeepLinks { const val HOST = "screen" private const val BASE_URI = "$SCHEME://$HOST" - private const val SPENDING_HW_SIGN_ID = "spending-hw-sign" private val CAMEL_HUMP = Regex("(?<=[a-z0-9])(?=[A-Z])") @@ -43,7 +42,8 @@ object ScreenDeepLinks { if (!isScreenDeepLink(uri)) return null val segments = uri.pathSegments.orEmpty() if (segments.size != 3) return null - if (!segments[0].equals(SPENDING_HW_SIGN_ID, ignoreCase = true)) return null + val screenId = kebabId(Routes.SpendingHwSign::class) ?: return null + if (!segments[0].equals(screenId, ignoreCase = true)) return null val walletId = segments[1] val orderId = segments[2] if (walletId.isBlank() || orderId.isBlank()) return null diff --git a/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt b/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt index f12409d12..c8b61dea4 100644 --- a/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt +++ b/app/src/main/java/to/bitkit/viewmodels/TransferViewModel.kt @@ -225,7 +225,7 @@ class TransferViewModel @Inject constructor( hwMiningFeeSats = 0uL, ) } - setTransferEffect(TransferEffect.OnOrderCreated) + setTransferEffect(TransferEffect.OnOrderCreated(newOrder.id)) }.onFailure { e -> setTransferEffect(TransferEffect.ToastException(e)) } @@ -582,7 +582,7 @@ class TransferViewModel @Inject constructor( private suspend fun onOrderCreated(order: IBtOrder) { settingsStore.update { it.copy(lightningSetupStep = 0) } adoptSpendingOrder(order) - setTransferEffect(TransferEffect.OnOrderCreated) + setTransferEffect(TransferEffect.OnOrderCreated(order.id)) } suspend fun prepareSpendingHwSign(walletId: String, orderId: String): Boolean { @@ -1697,7 +1697,7 @@ data class TransferValues( ) sealed interface TransferEffect { - data object OnOrderCreated : TransferEffect + data class OnOrderCreated(val orderId: String) : TransferEffect data object OnSpendingFundingPaid : TransferEffect data object OnHwTxSigned : TransferEffect data class ToastException(val e: Throwable) : TransferEffect diff --git a/app/src/test/java/to/bitkit/ui/ContentViewTest.kt b/app/src/test/java/to/bitkit/ui/ContentViewTest.kt index 3ca936d62..001a9bb92 100644 --- a/app/src/test/java/to/bitkit/ui/ContentViewTest.kt +++ b/app/src/test/java/to/bitkit/ui/ContentViewTest.kt @@ -32,7 +32,7 @@ class ContentViewTest { fun `transfer effect destinations cover funding paid and hw signed`() { assertEquals(Routes.SettingUp, transferEffectDestination(TransferEffect.OnSpendingFundingPaid)) assertEquals(Routes.SpendingHwSigned, transferEffectDestination(TransferEffect.OnHwTxSigned)) - assertNull(transferEffectDestination(TransferEffect.OnOrderCreated)) + assertNull(transferEffectDestination(TransferEffect.OnOrderCreated("order"))) } @Test diff --git a/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt b/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt index e93ef204b..60cae8221 100644 --- a/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt +++ b/app/src/test/java/to/bitkit/ui/utils/ScreenDeepLinksTest.kt @@ -58,7 +58,8 @@ class ScreenDeepLinksTest : BaseUnitTest() { @Test fun `spendingHwSignLink reads wallet and order ids from the path`() { - val uri = Uri.parse("bitkit://screen/spending-hw-sign/hardware-wallet/order-1") + val screenId = ScreenDeepLinks.kebabId(Routes.SpendingHwSign::class) + val uri = Uri.parse("bitkit://screen/$screenId/hardware-wallet/order-1") val link = ScreenDeepLinks.spendingHwSignLink(uri) From b268d9151b4ec937d9475557490eb2273ff47e1a Mon Sep 17 00:00:00 2001 From: Guzinowich Date: Sat, 22 Aug 2026 12:02:15 +0300 Subject: [PATCH 3/4] chore: rename changelog fragment --- changelog.d/next/{1126.added.md => 1176.added.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog.d/next/{1126.added.md => 1176.added.md} (100%) diff --git a/changelog.d/next/1126.added.md b/changelog.d/next/1176.added.md similarity index 100% rename from changelog.d/next/1126.added.md rename to changelog.d/next/1176.added.md From e9139a96e11cedc2c859662f6ade1d297c106a98 Mon Sep 17 00:00:00 2001 From: Guzinowich Date: Sat, 22 Aug 2026 12:07:56 +0300 Subject: [PATCH 4/4] fix: fold hw sign link returns --- app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt index bea955fea..73ccea57a 100644 --- a/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt +++ b/app/src/main/java/to/bitkit/ui/utils/ScreenDeepLinks.kt @@ -41,9 +41,10 @@ object ScreenDeepLinks { fun spendingHwSignLink(uri: Uri): SpendingHwSignLink? { if (!isScreenDeepLink(uri)) return null val segments = uri.pathSegments.orEmpty() - if (segments.size != 3) return null - val screenId = kebabId(Routes.SpendingHwSign::class) ?: return null - if (!segments[0].equals(screenId, ignoreCase = true)) return null + val screenId = kebabId(Routes.SpendingHwSign::class) + if (segments.size != 3 || screenId == null || !segments[0].equals(screenId, ignoreCase = true)) { + return null + } val walletId = segments[1] val orderId = segments[2] if (walletId.isBlank() || orderId.isBlank()) return null