Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import to.bitkit.App
import to.bitkit.R
import to.bitkit.data.CacheStore
import to.bitkit.di.UiDispatcher
import to.bitkit.domain.commands.NotifyChannelReady
import to.bitkit.domain.commands.NotifyChannelReadyHandler
import to.bitkit.domain.commands.NotifyPaymentReceived
import to.bitkit.domain.commands.NotifyPaymentReceivedHandler
import to.bitkit.models.NewTransactionSheetDetails
Expand Down Expand Up @@ -51,6 +53,9 @@ class LightningNodeService : Service() {
@Inject
lateinit var notifyPaymentReceivedHandler: NotifyPaymentReceivedHandler

@Inject
lateinit var notifyChannelReadyHandler: NotifyChannelReadyHandler

@Inject
lateinit var cacheStore: CacheStore

Expand All @@ -66,6 +71,7 @@ class LightningNodeService : Service() {
eventHandler = { event ->
Logger.debug("LDK-node event received in $TAG: ${jsonLogOf(event)}", context = TAG)
handlePaymentReceived(event)
if (event is Event.ChannelReady) handleChannelReady(event)
}
).onSuccess {
walletRepo.setWalletExistsState()
Expand All @@ -86,6 +92,15 @@ class LightningNodeService : Service() {
}
}

private suspend fun handleChannelReady(event: Event.ChannelReady) {
val command = NotifyChannelReady.Command(event = event, includeNotification = true)
notifyChannelReadyHandler(command).onSuccess {
Logger.debug("Channel ready notification result: $it", context = TAG)
if (it !is NotifyChannelReady.Result.ShowNotification) return
showPaymentNotification(it.sheet, it.notification)
}
}

private fun showPaymentNotification(
sheet: NewTransactionSheetDetails,
notification: NotificationDetails,
Expand Down
26 changes: 26 additions & 0 deletions app/src/main/java/to/bitkit/domain/commands/NotifyChannelReady.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package to.bitkit.domain.commands

import org.lightningdevkit.ldknode.Event
import to.bitkit.models.NewTransactionSheetDetails
import to.bitkit.models.NotificationDetails

sealed interface NotifyChannelReady {

data class Command(
val event: Event.ChannelReady,
val includeNotification: Boolean = false,
) : NotifyChannelReady

sealed interface Result : NotifyChannelReady {
data class ShowSheet(
val sheet: NewTransactionSheetDetails,
) : Result

data class ShowNotification(
val sheet: NewTransactionSheetDetails,
val notification: NotificationDetails,
) : Result

data object Skip : Result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package to.bitkit.domain.commands

import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withContext
import to.bitkit.R
import to.bitkit.data.SettingsData
import to.bitkit.data.SettingsStore
import to.bitkit.di.IoDispatcher
import to.bitkit.ext.amountOnClose
import to.bitkit.models.BITCOIN_SYMBOL
import to.bitkit.models.NewTransactionSheetDetails
import to.bitkit.models.NewTransactionSheetDirection
import to.bitkit.models.NewTransactionSheetType
import to.bitkit.models.NotificationDetails
import to.bitkit.models.PrimaryDisplay
import to.bitkit.models.formatToModernDisplay
import to.bitkit.repositories.ActivityRepo
import to.bitkit.repositories.BlocktankRepo
import to.bitkit.repositories.CurrencyRepo
import to.bitkit.repositories.LightningRepo
import to.bitkit.utils.Logger
import javax.inject.Inject
import javax.inject.Singleton

@Suppress("LongParameterList")
@Singleton
class NotifyChannelReadyHandler @Inject constructor(
@ApplicationContext private val context: Context,
@IoDispatcher private val ioDispatcher: CoroutineDispatcher,
private val lightningRepo: LightningRepo,
private val blocktankRepo: BlocktankRepo,
private val activityRepo: ActivityRepo,
private val currencyRepo: CurrencyRepo,
private val settingsStore: SettingsStore,
) {
companion object {
const val TAG = "NotifyChannelReadyHandler"
}

suspend operator fun invoke(
command: NotifyChannelReady.Command,
): Result<NotifyChannelReady.Result> = withContext(ioDispatcher) {
runCatching {
val channel = lightningRepo.getChannels()
?.find { it.channelId == command.event.channelId }
?: return@runCatching NotifyChannelReady.Result.Skip

val cjitEntry = blocktankRepo.getCjitEntry(channel)
?: return@runCatching NotifyChannelReady.Result.Skip

val sats = channel.amountOnClose.toLong()
activityRepo.insertActivityFromCjit(cjitEntry = cjitEntry, channel = channel)

val details = NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
sats = sats,
)

if (command.includeNotification) {
val notification = buildNotificationContent(sats)
NotifyChannelReady.Result.ShowNotification(details, notification)
} else {
NotifyChannelReady.Result.ShowSheet(details)
}
}.onFailure {
Logger.error("Failed to process channel ready notification", it, context = TAG)
}
}

private suspend fun buildNotificationContent(sats: Long): NotificationDetails {
val settings = settingsStore.data.first()
val title = context.getString(R.string.notification__received__title)
val body = if (settings.showNotificationDetails) {
formatNotificationAmount(sats, settings)
} else {
context.getString(R.string.notification__received__body_hidden)
}
return NotificationDetails(title, body)
}

private fun formatNotificationAmount(sats: Long, settings: SettingsData): String {
val converted = currencyRepo.convertSatsToFiat(sats).getOrNull()

val amountText = converted?.let {
val btcDisplay = it.bitcoinDisplay(settings.displayUnit)
if (settings.primaryDisplay == PrimaryDisplay.BITCOIN) {
"${btcDisplay.symbol} ${btcDisplay.value} (${it.formattedWithSymbol()})"
} else {
"${it.formattedWithSymbol()} (${btcDisplay.symbol} ${btcDisplay.value})"
}
} ?: "$BITCOIN_SYMBOL ${sats.formatToModernDisplay()}"

return context.getString(R.string.notification__received__body_amount, amountText)
}
}
20 changes: 7 additions & 13 deletions app/src/main/java/to/bitkit/viewmodels/AppViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ import to.bitkit.data.SettingsStore
import to.bitkit.data.keychain.Keychain
import to.bitkit.data.resetPin
import to.bitkit.di.BgDispatcher
import to.bitkit.domain.commands.NotifyChannelReady
import to.bitkit.domain.commands.NotifyChannelReadyHandler
import to.bitkit.domain.commands.NotifyPaymentReceived
import to.bitkit.domain.commands.NotifyPaymentReceivedHandler
import to.bitkit.env.Defaults
import to.bitkit.env.Env
import to.bitkit.ext.WatchResult
import to.bitkit.ext.amountOnClose
import to.bitkit.ext.getClipboardText
import to.bitkit.ext.getSatsPerVByteFor
import to.bitkit.ext.maxSendableSat
Expand Down Expand Up @@ -147,6 +148,7 @@ class AppViewModel @Inject constructor(
private val blocktankRepo: BlocktankRepo,
private val appUpdaterService: AppUpdaterService,
private val notifyPaymentReceivedHandler: NotifyPaymentReceivedHandler,
private val notifyChannelReadyHandler: NotifyChannelReadyHandler,
private val cacheStore: CacheStore,
private val transferRepo: TransferRepo,
private val migrationService: MigrationService,
Expand Down Expand Up @@ -559,18 +561,10 @@ class AppViewModel @Inject constructor(
// region Notifications

private suspend fun notifyChannelReady(event: Event.ChannelReady) {
val channel = lightningRepo.getChannels()?.find { it.channelId == event.channelId }
val cjitEntry = channel?.let { blocktankRepo.getCjitEntry(it) }
if (cjitEntry != null) {
val amount = channel.amountOnClose.toLong()
showTransactionSheet(
NewTransactionSheetDetails(
type = NewTransactionSheetType.LIGHTNING,
direction = NewTransactionSheetDirection.RECEIVED,
sats = amount,
),
)
activityRepo.insertActivityFromCjit(cjitEntry = cjitEntry, channel = channel)
val command = NotifyChannelReady.Command(event = event)
val result = notifyChannelReadyHandler(command).getOrNull()
if (result is NotifyChannelReady.Result.ShowSheet) {
showTransactionSheet(result.sheet)
return
}
toast(
Expand Down
Loading
Loading