Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
440f2b1
feat: add PendingSweepBalance extension functions
jvsena42 Feb 25, 2026
14db4c9
fix: improve syncTransferStates for batched force-close sweeps
jvsena42 Feb 25, 2026
28f1993
fix: add ConnectionClosed sheet variant and UI
jvsena42 Feb 25, 2026
03c9cb5
fix: update handleChannelClosed in AppViewModel
jvsena42 Feb 25, 2026
71aeef6
test: add force-close sync tests
jvsena42 Feb 25, 2026
a179821
chore: lint
jvsena42 Feb 25, 2026
33a77ec
chore: lint
jvsena42 Feb 26, 2026
356a1d7
fix: mark closing transaction as transfer activity
jvsena42 Feb 26, 2026
0fff4aa
Merge branch 'fix/reimport-channel-monitor' into fix/channel-close-ui
jvsena42 Feb 26, 2026
7e284ef
fix: sheet size medium
jvsena42 Feb 26, 2026
4030583
Merge remote-tracking branch 'origin/fix/channel-close-ui' into fix/c…
jvsena42 Feb 27, 2026
9c4f80d
fix: settle COOP_CLOSE immediately
jvsena42 Feb 27, 2026
298bdf5
fix: balance calculation includes COOP_CLOSE whole they are unsettled…
jvsena42 Feb 27, 2026
d3af0c3
test: update coop close tests to settle immediately
jvsena42 Feb 27, 2026
793e0b9
feat: add claimableAtHeight to TransferEntity
jvsena42 Feb 27, 2026
f4849a4
feat: pass claimableAtHeight when creating force close transfer
jvsena42 Feb 27, 2026
8777244
chore: create helpers to display the duration
jvsena42 Feb 27, 2026
0aa2049
feat: update banner for dynamic title
jvsena42 Feb 27, 2026
6af900c
fix: show dynamic duration for force-close
jvsena42 Feb 27, 2026
ae0f027
fix: suppress receive sheet for transfers
jvsena42 Feb 27, 2026
78efaf5
fix: claimableAtHeight type
jvsena42 Feb 27, 2026
5480492
chore: migration
jvsena42 Feb 27, 2026
37235c3
fix: claimableAtHeight type
jvsena42 Feb 27, 2026
dafdea3
test: BlockTimer helper tests
jvsena42 Feb 27, 2026
aad07e4
chore: lint
jvsena42 Feb 27, 2026
c1715b4
refactor: move force close duration calculation to TransferRepo.kt
jvsena42 Feb 27, 2026
94c86a3
fix: subtract coop closing amount from balanceInTransferToSavings
jvsena42 Feb 27, 2026
8302993
fix: transfer banner visibility
jvsena42 Feb 27, 2026
ed56df9
fix: check if this transaction is a pending sweep from a channel closure
jvsena42 Feb 27, 2026
e56d56a
Merge branch 'fix/reimport-channel-monitor' into fix/channel-close-ui
jvsena42 Feb 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
refactor: move force close duration calculation to TransferRepo.kt
  • Loading branch information
jvsena42 committed Feb 27, 2026
commit c1715b4e29fa7efd2a300524522896187a7dffc5
2 changes: 0 additions & 2 deletions app/src/main/java/to/bitkit/models/BalanceState.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package to.bitkit.models

import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient

@Serializable
data class BalanceState(
Expand All @@ -11,7 +10,6 @@ data class BalanceState(
val maxSendOnchainSats: ULong = 0uL,
val balanceInTransferToSavings: ULong = 0uL,
val balanceInTransferToSpending: ULong = 0uL,
@Transient val forceCloseRemainingDuration: String? = null,
) {
val totalSats get() = totalOnchainSats + totalLightningSats
}
15 changes: 15 additions & 0 deletions app/src/main/java/to/bitkit/repositories/TransferRepo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.synonym.bitkitcore.ActivityFilter
import com.synonym.bitkitcore.SortDirection
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
import org.lightningdevkit.ldknode.ChannelDetails
Expand All @@ -16,6 +17,7 @@ import to.bitkit.ext.channelId
import to.bitkit.ext.latestSpendingTxid
import to.bitkit.models.TransferType
import to.bitkit.services.CoreService
import to.bitkit.utils.BlockTimeHelpers
import to.bitkit.utils.Logger
import java.util.UUID
import javax.inject.Inject
Expand All @@ -35,6 +37,19 @@ class TransferRepo @Inject constructor(
) {
val activeTransfers: Flow<List<TransferEntity>> = transferDao.getActiveTransfers()

val forceCloseRemainingDuration: Flow<String?> = combine(
activeTransfers,
lightningRepo.lightningState,
) { transfers, lightningState ->
val forceClose = transfers.firstOrNull { it.type == TransferType.FORCE_CLOSE }
?: return@combine null
val targetHeight = forceClose.claimableAtHeight?.toUInt() ?: return@combine null
val currentHeight = lightningState.block()?.height ?: return@combine null
val remaining = BlockTimeHelpers.blocksRemaining(targetHeight, currentHeight)
if (remaining <= 0) return@combine null
BlockTimeHelpers.getDurationForBlocks(remaining)
}

@Suppress("LongParameterList")
suspend fun createTransfer(
type: TransferType,
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/to/bitkit/ui/ContentView.kt
Original file line number Diff line number Diff line change
Expand Up @@ -809,6 +809,7 @@ private fun NavGraphBuilder.home(
val hasSeenSpendingIntro by settingsViewModel.hasSeenSpendingIntro.collectAsStateWithLifecycle()
val isGeoBlocked by appViewModel.isGeoBlocked.collectAsStateWithLifecycle()
val onchainActivities by activityListViewModel.onchainActivities.collectAsStateWithLifecycle()
val forceCloseRemainingDuration by appViewModel.forceCloseRemainingDuration.collectAsStateWithLifecycle()

SavingsWalletScreen(
isGeoBlocked = isGeoBlocked,
Expand All @@ -824,6 +825,7 @@ private fun NavGraphBuilder.home(
}
},
onBackClick = { navController.popBackStack() },
forceCloseRemainingDuration = forceCloseRemainingDuration,
)
}
composable<Routes.Spending>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,10 @@ class HomeViewModel @Inject constructor(
private suspend fun createBannersFlow() {
combine(
transferRepo.activeTransfers,
walletRepo.balanceState,
) { transfers, balanceState ->
transferRepo.forceCloseRemainingDuration,
) { transfers, remainingDuration ->
val defaultTitle = context.getString(R.string.lightning__transfer_in_progress)
val savingsTitle = balanceState.forceCloseRemainingDuration?.let {
val savingsTitle = remainingDuration?.let {
context.getString(R.string.lightning__transfer_ready_in, it)
} ?: defaultTitle

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ fun SavingsWalletScreen(
onActivityItemClick: (String) -> Unit,
onTransferToSpendingClick: () -> Unit,
onBackClick: () -> Unit,
forceCloseRemainingDuration: String? = null,
balances: BalanceState = LocalBalances.current,
) {
val showEmptyState by remember(balances.totalOnchainSats, onchainActivities.size) {
Expand Down Expand Up @@ -102,7 +103,7 @@ fun SavingsWalletScreen(
if (balances.balanceInTransferToSavings > 0u) {
IncomingTransfer(
amount = balances.balanceInTransferToSavings,
remainingDuration = balances.forceCloseRemainingDuration,
remainingDuration = forceCloseRemainingDuration,
modifier = Modifier.padding(vertical = 8.dp),
)
}
Expand Down
14 changes: 0 additions & 14 deletions app/src/main/java/to/bitkit/usecases/DeriveBalanceStateUseCase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import to.bitkit.models.TransferType
import to.bitkit.models.safe
import to.bitkit.repositories.LightningRepo
import to.bitkit.repositories.TransferRepo
import to.bitkit.utils.BlockTimeHelpers
import to.bitkit.utils.Logger
import to.bitkit.utils.jsonLogOf
import javax.inject.Inject
Expand All @@ -40,16 +39,13 @@ class DeriveBalanceStateUseCase @Inject constructor(
val afterPendingChannels = balanceDetails.totalLightningBalanceSats.safe() - pendingChannelsSats.safe()
val totalLightningSats = afterPendingChannels.safe() - toSavingsAmount.safe()

val forceCloseRemainingDuration = getForceCloseRemainingDuration(activeTransfers)

val balanceState = BalanceState(
totalOnchainSats = totalOnchainSats,
totalLightningSats = totalLightningSats,
maxSendLightningSats = lightningRepo.getChannels().totalNextOutboundHtlcLimitSats(),
maxSendOnchainSats = getMaxSendAmount(balanceDetails),
balanceInTransferToSavings = toSavingsAmount,
balanceInTransferToSpending = toSpendingAmount,
forceCloseRemainingDuration = forceCloseRemainingDuration,
)

val height = lightningRepo.lightningState.value.block()?.height
Expand Down Expand Up @@ -120,16 +116,6 @@ class DeriveBalanceStateUseCase @Inject constructor(
return spendableOnchainSats.safe() - fee.safe()
}

private fun getForceCloseRemainingDuration(transfers: List<TransferEntity>): String? {
val forceClose = transfers.firstOrNull { it.type == TransferType.FORCE_CLOSE }
?: return null
val targetHeight = forceClose.claimableAtHeight?.toUInt() ?: return null
val currentHeight = lightningRepo.lightningState.value.block()?.height ?: return null
val remaining = BlockTimeHelpers.blocksRemaining(targetHeight, currentHeight)
if (remaining <= 0) return null
return BlockTimeHelpers.getDurationForBlocks(remaining)
}

companion object {
const val TAG = "DeriveBalanceStateUseCase"
const val FALLBACK_FEE_PERCENT = 0.1
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,9 @@ class AppViewModel @Inject constructor(
val isGeoBlocked = lightningRepo.lightningState.map { it.isGeoBlocked }
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), false)

val forceCloseRemainingDuration = transferRepo.forceCloseRemainingDuration
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), null)

private val _sendUiState = MutableStateFlow(SendUiState())
val sendUiState = _sendUiState.asStateFlow()

Expand Down