Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
57207f8
feat: use serializable types from updated ldk-node
ovitrif Oct 10, 2025
a1db6f8
refactor: replace LnPeer with direct use of PeerDetails
ovitrif Oct 13, 2025
8818e16
chore: use new ldk-node version from jitpack
ovitrif Oct 13, 2025
97729fa
chore: lint
ovitrif Oct 13, 2025
c3da66f
chore: update baseline
ovitrif Oct 13, 2025
698d954
fix: has external peers check efficiency
ovitrif Oct 14, 2025
4e622f9
refactor: pass copy to clipboard text to callback
ovitrif Oct 15, 2025
1e3c044
fix: peer details in ln node screen
ovitrif Oct 15, 2025
4e13133
refactor: rename to trustedPeers & trustedPeerNodeIds
ovitrif Oct 15, 2025
a18e264
refactor: extract uri as var
ovitrif Oct 15, 2025
4dffac9
feat: add quiet zone to qr code
ovitrif Oct 15, 2025
7d4c1b2
fix: clear qr bitmap early on change
ovitrif Oct 15, 2025
a616a91
fix: prevent tooltip from consuming tap events
ovitrif Oct 15, 2025
71af030
feat: polish qr transitions
ovitrif Oct 15, 2025
905987b
chore: upgrade to bitkit-core 0.1.18
ovitrif Oct 15, 2025
23b156e
refactor: add section header parameters
ovitrif Oct 16, 2025
9e58ac8
Merge pull request #441 from synonymdev/feat/qr-quiet-zone
jvsena42 Oct 16, 2025
a0717bb
feat: polish channel orders dev settings screen
ovitrif Oct 16, 2025
96f49e0
fix: print 'null'
ovitrif Oct 16, 2025
059fd2c
Merge pull request #442 from synonymdev/bitkit-core-serializable
jvsena42 Oct 16, 2025
d8465b3
fix: handle potential empty address error
ovitrif Oct 16, 2025
7826c49
Merge branch 'master' into feat/ldk-node-serializable
ovitrif Oct 16, 2025
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
131 changes: 0 additions & 131 deletions app/detekt-baseline.xml

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions app/src/main/java/to/bitkit/env/Env.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package to.bitkit.env
import android.os.Build
import org.lightningdevkit.ldknode.LogLevel
import org.lightningdevkit.ldknode.Network
import org.lightningdevkit.ldknode.PeerDetails
import to.bitkit.BuildConfig
import to.bitkit.ext.ensureDir
import to.bitkit.ext.parse
import to.bitkit.models.BlocktankNotificationType
import to.bitkit.models.LnPeer
import to.bitkit.utils.Logger
import java.io.File
import kotlin.io.path.Path
Expand All @@ -24,8 +25,8 @@ internal object Env {
// TODO: remove this to load from BT API instead
val trustedLnPeers
get() = when (network) {
Network.REGTEST -> listOf(Peers.btStaging)
Network.TESTNET -> listOf(Peers.btStaging)
Network.REGTEST -> listOf(Peers.staging)
Network.TESTNET -> listOf(Peers.staging)
else -> TODO("Not yet implemented")
}

Expand Down Expand Up @@ -143,10 +144,8 @@ internal object Env {
}

object Peers {
val btStaging = LnPeer(
nodeId = "028a8910b0048630d4eb17af25668cdd7ea6f2d8ae20956e7a06e2ae46ebcb69fc",
address = "34.65.86.104:9400",
)
val staging =
PeerDetails.parse("028a8910b0048630d4eb17af25668cdd7ea6f2d8ae20956e7a06e2ae46ebcb69fc@34.65.86.104:9400")
}

object ElectrumServers {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/to/bitkit/ext/LightningBalance.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package to.bitkit.ext

import to.bitkit.models.LightningBalance
import org.lightningdevkit.ldknode.LightningBalance

fun LightningBalance.amountSats(): ULong {
return when (this) {
Expand Down
37 changes: 37 additions & 0 deletions app/src/main/java/to/bitkit/ext/PeerDetails.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package to.bitkit.ext

import org.lightningdevkit.ldknode.PeerDetails

val PeerDetails.host get() = address.substringBefore(":")

val PeerDetails.port get() = address.substringAfter(":")

val PeerDetails.uri get() = "$nodeId@$address"

fun PeerDetails.Companion.parse(uri: String): PeerDetails {
val parts = uri.split("@")
require(parts.size == 2) { "Invalid uri format, expected: '<nodeId>@<host>:<port>', got: '$uri'" }

val nodeId = parts[0]

val addressParts = parts[1].split(":")
require(addressParts.size == 2) { "Invalid uri format, expected: '<nodeId>@<host>:<port>', got: '$uri'" }

val host = addressParts[0]
val port = addressParts[1]
val address = "$host:$port"

return PeerDetails(
nodeId = nodeId,
address = address,
isConnected = false,
isPersisted = false,
)
}
Comment thread
ovitrif marked this conversation as resolved.

fun PeerDetails.Companion.from(nodeId: String, host: String, port: String) = PeerDetails(
nodeId = nodeId,
address = "$host:$port",
isConnected = false,
isPersisted = false,
)
138 changes: 76 additions & 62 deletions app/src/main/java/to/bitkit/fcm/WakeNodeWorker.kt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import to.bitkit.utils.Logger
import to.bitkit.utils.withPerformanceLogging
import kotlin.time.Duration.Companion.minutes

@Suppress("LongParameterList")
@HiltWorker
class WakeNodeWorker @AssistedInject constructor(
@Assisted private val appContext: Context,
Expand Down Expand Up @@ -120,75 +121,16 @@ class WakeNodeWorker @AssistedInject constructor(
val showDetails = settingsStore.data.first().showNotificationDetails
val openBitkitMessage = "Open Bitkit to see details"
when (event) {
is Event.PaymentReceived -> {
bestAttemptContent?.title = "Payment Received"
val sats = event.amountMsat / 1000u
// Save for UI to pick up
NewTransactionSheetDetails.save(
appContext,
NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
paymentHashOrTxId = event.paymentHash,
sats = sats.toLong(),
)
)
val content = if (showDetails) "$BITCOIN_SYMBOL $sats" else openBitkitMessage
bestAttemptContent?.body = content
if (self.notificationType == incomingHtlc) {
self.deliver()
}
}
is Event.PaymentReceived -> onPaymentReceived(event, showDetails, openBitkitMessage)

is Event.ChannelPending -> {
self.bestAttemptContent?.title = "Channel Opened"
self.bestAttemptContent?.body = "Pending"
// Don't deliver, give a chance for channelReady event to update the content if it's a turbo channel
}

is Event.ChannelReady -> {
if (self.notificationType == cjitPaymentArrived) {
self.bestAttemptContent?.title = "Payment received"
self.bestAttemptContent?.body = "Via new channel"

lightningRepo.getChannels()?.find { it.channelId == event.channelId }?.let { channel ->
val sats = channel.amountOnClose
val content = if (showDetails) "$BITCOIN_SYMBOL $sats" else openBitkitMessage
self.bestAttemptContent?.title = content
val cjitEntry = channel.let { blocktankRepo.getCjitEntry(it) }
if (cjitEntry != null) {
// Save for UI to pick up
NewTransactionSheetDetails.save(
appContext,
NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
sats = sats.toLong(),
)
)
activityRepo.insertActivityFromCjit(cjitEntry = cjitEntry, channel = channel)
}
}
} else if (self.notificationType == orderPaymentConfirmed) {
self.bestAttemptContent?.title = "Channel opened"
self.bestAttemptContent?.body = "Ready to send"
}
self.deliver()
}

is Event.ChannelClosed -> {
self.bestAttemptContent?.title = "Channel closed"
self.bestAttemptContent?.body = "Reason: ${event.reason}"

if (self.notificationType == mutualClose) {
self.bestAttemptContent?.body = "Balance moved from spending to savings"
} else if (self.notificationType == orderPaymentConfirmed) {
self.bestAttemptContent?.title = "Channel failed to open in the background"
self.bestAttemptContent?.body = "Please try again"
}

self.deliver()
}
is Event.ChannelReady -> onChannelReady(event, showDetails, openBitkitMessage)
is Event.ChannelClosed -> onChannelClosed(event)

is Event.PaymentSuccessful -> Unit
is Event.PaymentClaimable -> Unit
Expand All @@ -205,6 +147,78 @@ class WakeNodeWorker @AssistedInject constructor(
}
}

private suspend fun onChannelClosed(event: Event.ChannelClosed) {
self.bestAttemptContent?.title = "Channel closed"
self.bestAttemptContent?.body = "Reason: ${event.reason}"

if (self.notificationType == mutualClose) {
self.bestAttemptContent?.body = "Balance moved from spending to savings"
} else if (self.notificationType == orderPaymentConfirmed) {
self.bestAttemptContent?.title = "Channel failed to open in the background"
self.bestAttemptContent?.body = "Please try again"
}

self.deliver()
}

private suspend fun onPaymentReceived(
event: Event.PaymentReceived,
showDetails: Boolean,
openBitkitMessage: String,
) {
bestAttemptContent?.title = "Payment Received"
val sats = event.amountMsat / 1000u
// Save for UI to pick up
NewTransactionSheetDetails.save(
appContext,
NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
paymentHashOrTxId = event.paymentHash,
sats = sats.toLong(),
)
)
val content = if (showDetails) "$BITCOIN_SYMBOL $sats" else openBitkitMessage
bestAttemptContent?.body = content
if (self.notificationType == incomingHtlc) {
self.deliver()
}
}

private suspend fun onChannelReady(
event: Event.ChannelReady,
showDetails: Boolean,
openBitkitMessage: String,
) {
if (self.notificationType == cjitPaymentArrived) {
self.bestAttemptContent?.title = "Payment received"
self.bestAttemptContent?.body = "Via new channel"

lightningRepo.getChannels()?.find { it.channelId == event.channelId }?.let { channel ->
val sats = channel.amountOnClose
val content = if (showDetails) "$BITCOIN_SYMBOL $sats" else openBitkitMessage
self.bestAttemptContent?.title = content
val cjitEntry = channel.let { blocktankRepo.getCjitEntry(it) }
if (cjitEntry != null) {
// Save for UI to pick up
NewTransactionSheetDetails.save(
appContext,
NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
sats = sats.toLong(),
)
)
activityRepo.insertActivityFromCjit(cjitEntry = cjitEntry, channel = channel)
}
}
} else if (self.notificationType == orderPaymentConfirmed) {
self.bestAttemptContent?.title = "Channel opened"
self.bestAttemptContent?.body = "Ready to send"
}
self.deliver()
}

private suspend fun deliver() {
lightningRepo.stop()

Expand Down
Loading
Loading