Skip to content

Commit e396d17

Browse files
committed
fix: update core activity integration
1 parent ca6504c commit e396d17

36 files changed

Lines changed: 1066 additions & 748 deletions
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package to.bitkit.models
2+
3+
import androidx.compose.runtime.Immutable
4+
import com.synonym.bitkitcore.Activity
5+
import com.synonym.bitkitcore.PaymentState
6+
import com.synonym.bitkitcore.PaymentType
7+
import com.synonym.bitkitcore.TransactionDetails
8+
import kotlinx.collections.immutable.ImmutableList
9+
import kotlinx.collections.immutable.toImmutableList
10+
import to.bitkit.R
11+
import to.bitkit.ext.rawId
12+
import to.bitkit.ext.timestamp
13+
import to.bitkit.ext.totalValue
14+
import to.bitkit.ext.walletId
15+
16+
@Immutable
17+
sealed interface ActivityDetailItem {
18+
val id: String
19+
val walletId: String
20+
val listItem: ActivityListItem
21+
val txType: PaymentType
22+
val value: ULong
23+
val fee: ULong?
24+
val totalValue: ULong
25+
val timestamp: ULong
26+
val contact: String?
27+
val isTransfer: Boolean get() = false
28+
29+
val isSent: Boolean get() = txType == PaymentType.SENT
30+
}
31+
32+
@Immutable
33+
data class LightningActivityDetailItem(
34+
override val id: String,
35+
override val walletId: String,
36+
override val listItem: ActivityListItem,
37+
override val txType: PaymentType,
38+
val status: PaymentState,
39+
override val value: ULong,
40+
override val fee: ULong?,
41+
override val totalValue: ULong,
42+
override val timestamp: ULong,
43+
override val contact: String?,
44+
val invoice: String,
45+
val message: String,
46+
val preimage: String?,
47+
) : ActivityDetailItem
48+
49+
@Immutable
50+
data class OnchainActivityDetailItem(
51+
override val id: String,
52+
override val walletId: String,
53+
override val listItem: ActivityListItem,
54+
override val txType: PaymentType,
55+
override val value: ULong,
56+
override val fee: ULong?,
57+
override val totalValue: ULong,
58+
override val timestamp: ULong,
59+
override val contact: String?,
60+
val txId: String,
61+
val address: String,
62+
val feeRate: ULong,
63+
val confirmed: Boolean,
64+
val confirmTimestamp: ULong?,
65+
val isBoosted: Boolean,
66+
val boostTxIds: ImmutableList<String>,
67+
override val isTransfer: Boolean,
68+
val doesExist: Boolean,
69+
val channelId: String?,
70+
) : ActivityDetailItem
71+
72+
@Immutable
73+
data class TransactionDetailItem(
74+
val inputs: ImmutableList<String>,
75+
val outputs: ImmutableList<String>,
76+
)
77+
78+
@Immutable
79+
data class TransferOrderAmounts(
80+
val serviceFee: ULong,
81+
val transferAmount: ULong,
82+
)
83+
84+
fun Activity.toActivityDetailItem(): ActivityDetailItem = when (this) {
85+
is Activity.Lightning -> LightningActivityDetailItem(
86+
id = rawId(),
87+
walletId = walletId(),
88+
listItem = toActivityListItem(),
89+
txType = v1.txType,
90+
status = v1.status,
91+
value = v1.value,
92+
fee = v1.fee,
93+
totalValue = totalValue(),
94+
timestamp = timestamp(),
95+
contact = v1.contact,
96+
invoice = v1.invoice,
97+
message = v1.message,
98+
preimage = v1.preimage,
99+
)
100+
101+
is Activity.Onchain -> OnchainActivityDetailItem(
102+
id = rawId(),
103+
walletId = walletId(),
104+
listItem = toActivityListItem(),
105+
txType = v1.txType,
106+
value = v1.value,
107+
fee = v1.fee,
108+
totalValue = totalValue(),
109+
timestamp = timestamp(),
110+
contact = v1.contact,
111+
txId = v1.txId,
112+
address = v1.address,
113+
feeRate = v1.feeRate,
114+
confirmed = v1.confirmed,
115+
confirmTimestamp = v1.confirmTimestamp,
116+
isBoosted = v1.isBoosted,
117+
boostTxIds = v1.boostTxIds.toImmutableList(),
118+
isTransfer = v1.isTransfer,
119+
doesExist = v1.doesExist,
120+
channelId = v1.channelId,
121+
)
122+
}
123+
124+
fun TransactionDetails.toTransactionDetailItem() = TransactionDetailItem(
125+
inputs = inputs.map { "${it.txid}:${it.vout}" }.toImmutableList(),
126+
outputs = outputs.map { it.scriptpubkeyAddress ?: "" }.toImmutableList(),
127+
)
128+
129+
fun ActivityDetailItem.getScreenTitleRes(): Int {
130+
if (this is LightningActivityDetailItem && isSent && status == PaymentState.PENDING) {
131+
return R.string.wallet__activity_pending_nav_title
132+
}
133+
134+
var resId = when {
135+
isSent -> R.string.wallet__activity_bitcoin_sent
136+
else -> R.string.wallet__activity_bitcoin_received
137+
}
138+
139+
if (isTransfer) {
140+
resId = when {
141+
isSent -> R.string.wallet__activity_transfer_spending_done
142+
else -> R.string.wallet__activity_transfer_savings_done
143+
}
144+
}
145+
146+
return resId
147+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package to.bitkit.models
2+
3+
import androidx.compose.runtime.Immutable
4+
import com.synonym.bitkitcore.Activity
5+
import com.synonym.bitkitcore.PaymentState
6+
import com.synonym.bitkitcore.PaymentType
7+
import to.bitkit.ext.rawId
8+
import to.bitkit.ext.timestamp
9+
import to.bitkit.ext.totalValue
10+
import to.bitkit.ext.walletId
11+
12+
@Immutable
13+
data class ActivityListItem(
14+
val id: String,
15+
val walletId: String,
16+
val scopedId: String,
17+
val key: String,
18+
val kind: ActivityListItemKind,
19+
val txType: PaymentType,
20+
val status: PaymentState?,
21+
val value: ULong,
22+
val fee: ULong?,
23+
val totalValue: ULong,
24+
val message: String,
25+
val timestamp: ULong,
26+
val groupTimestamp: ULong,
27+
val txId: String?,
28+
val confirmed: Boolean?,
29+
val feeRate: ULong,
30+
val isTransfer: Boolean,
31+
val isBoosted: Boolean,
32+
val doesExist: Boolean,
33+
val contact: String?,
34+
) {
35+
val isLightning: Boolean get() = kind == ActivityListItemKind.LIGHTNING
36+
val isSent: Boolean get() = txType == PaymentType.SENT
37+
val isFinished: Boolean get() = confirmed ?: (status != PaymentState.PENDING)
38+
val isBoosting: Boolean get() = isBoosted && !isFinished && doesExist
39+
}
40+
41+
enum class ActivityListItemKind {
42+
LIGHTNING,
43+
ONCHAIN,
44+
}
45+
46+
fun Activity.toActivityListItem(): ActivityListItem = when (this) {
47+
is Activity.Lightning -> ActivityListItem(
48+
id = rawId(),
49+
walletId = walletId(),
50+
scopedId = "${walletId()}:${rawId()}",
51+
key = "lightning_${walletId()}_${rawId()}",
52+
kind = ActivityListItemKind.LIGHTNING,
53+
txType = v1.txType,
54+
status = v1.status,
55+
value = v1.value,
56+
fee = v1.fee,
57+
totalValue = totalValue(),
58+
message = v1.message,
59+
timestamp = timestamp(),
60+
groupTimestamp = v1.timestamp,
61+
txId = null,
62+
confirmed = null,
63+
feeRate = 0u,
64+
isTransfer = false,
65+
isBoosted = false,
66+
doesExist = true,
67+
contact = v1.contact,
68+
)
69+
70+
is Activity.Onchain -> ActivityListItem(
71+
id = rawId(),
72+
walletId = walletId(),
73+
scopedId = "${walletId()}:${rawId()}",
74+
key = "onchain_${walletId()}_${rawId()}",
75+
kind = ActivityListItemKind.ONCHAIN,
76+
txType = v1.txType,
77+
status = null,
78+
value = v1.value,
79+
fee = v1.fee,
80+
totalValue = totalValue(),
81+
message = "",
82+
timestamp = timestamp(),
83+
groupTimestamp = v1.timestamp,
84+
txId = v1.txId,
85+
confirmed = v1.confirmed,
86+
feeRate = v1.feeRate,
87+
isTransfer = v1.isTransfer,
88+
isBoosted = v1.isBoosted,
89+
doesExist = v1.doesExist,
90+
contact = v1.contact,
91+
)
92+
}

app/src/main/java/to/bitkit/models/HardwareWallet.kt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import com.synonym.bitkitcore.AddressType
88
import kotlinx.collections.immutable.ImmutableList
99
import kotlinx.collections.immutable.ImmutableSet
1010
import kotlinx.collections.immutable.persistentSetOf
11+
import kotlinx.collections.immutable.toImmutableList
1112
import kotlinx.serialization.Serializable
1213

1314
/** A paired hardware wallet tracked as a watch-only balance. */
@@ -24,6 +25,20 @@ data class HwWallet(
2425
val deviceIds: ImmutableSet<String> = persistentSetOf(id),
2526
)
2627

28+
/** Stable hardware wallet projection for Compose screens. */
29+
@Immutable
30+
data class HwWalletItem(
31+
val id: String,
32+
val name: String,
33+
val model: String?,
34+
val transportType: TransportType,
35+
val isConnected: Boolean,
36+
val balanceSats: ULong,
37+
val activities: ImmutableList<ActivityListItem>,
38+
val fundingBalanceSats: ULong = balanceSats,
39+
val deviceIds: ImmutableSet<String> = persistentSetOf(id),
40+
)
41+
2742
/** Serializable per-device balance snapshot carried by [BalanceState]. */
2843
@Immutable
2944
@Serializable
@@ -97,3 +112,17 @@ enum class HwFundingAddressType(
97112
}
98113

99114
fun HwWallet.toBalance() = HwWalletBalance(id = id, sats = balanceSats)
115+
116+
fun HwWalletItem.toBalance() = HwWalletBalance(id = id, sats = balanceSats)
117+
118+
fun HwWallet.toItem() = HwWalletItem(
119+
id = id,
120+
name = name,
121+
model = model,
122+
transportType = transportType,
123+
isConnected = isConnected,
124+
balanceSats = balanceSats,
125+
activities = activities.map { it.toActivityListItem() }.toImmutableList(),
126+
fundingBalanceSats = fundingBalanceSats,
127+
deviceIds = deviceIds,
128+
)

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,8 +1734,7 @@ private fun Throwable.toLnurlPayInvoiceError(): Throwable {
17341734

17351735
private fun Throwable.isLnurlPayValidationError(): Boolean = when (this) {
17361736
is LnurlException.InvalidAmount,
1737-
is LnurlException.AmountMismatch,
1738-
is LnurlException.MetadataMismatch -> true
1737+
is LnurlException.AmountMismatch -> true
17391738

17401739
else -> false
17411740
}

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

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ import androidx.navigation.compose.composable
4242
import androidx.navigation.compose.currentBackStackEntryAsState
4343
import androidx.navigation.compose.rememberNavController
4444
import androidx.navigation.toRoute
45-
import com.synonym.bitkitcore.Activity
4645
import dev.chrisbanes.haze.HazeState
4746
import dev.chrisbanes.haze.hazeSource
4847
import dev.chrisbanes.haze.rememberHazeState
@@ -53,8 +52,6 @@ import kotlinx.serialization.Serializable
5352
import to.bitkit.appwidget.AppWidgetRefreshReason
5453
import to.bitkit.appwidget.appWidgetRefreshScheduler
5554
import to.bitkit.env.Env
56-
import to.bitkit.ext.rawId
57-
import to.bitkit.ext.walletId
5855
import to.bitkit.models.NodeLifecycleState
5956
import to.bitkit.models.Toast
6057
import to.bitkit.repositories.ConnectivityState
@@ -997,7 +994,7 @@ private fun NavGraphBuilder.home(
997994
isGeoBlocked = isGeoBlocked,
998995
onchainActivities = onchainActivities ?: persistentListOf(),
999996
onAllActivityButtonClick = { navController.navigateToAllActivity(activityListViewModel::clearFilters) },
1000-
onActivityItemClick = { navController.navigateToActivityItem(it) },
997+
onActivityItemClick = { id, walletId -> navController.navigateToActivityItem(id, walletId) },
1001998
onEmptyActivityRowClick = { appViewModel.showSheet(Sheet.Receive()) },
1002999
onTransferToSpendingClick = {
10031000
navController.navigateToTransferSpendingStart(hasSeenSpendingIntro)
@@ -1016,7 +1013,7 @@ private fun NavGraphBuilder.home(
10161013
channels = lightningState.channels,
10171014
lightningActivities = lightningActivities ?: persistentListOf(),
10181015
onAllActivityButtonClick = { navController.navigateToAllActivity(activityListViewModel::clearFilters) },
1019-
onActivityItemClick = { navController.navigateToActivityItem(it) },
1016+
onActivityItemClick = { id, walletId -> navController.navigateToActivityItem(id, walletId) },
10201017
onEmptyActivityRowClick = { appViewModel.showSheet(Sheet.Receive()) },
10211018
onTransferToSavingsClick = {
10221019
if (!hasSeenSavingsIntro) {
@@ -1036,7 +1033,7 @@ private fun NavGraphBuilder.home(
10361033
val hasSeenSpendingIntro by settingsViewModel.hasSeenSpendingIntro.collectAsStateWithLifecycle()
10371034
HardwareWalletScreen(
10381035
deviceId = deviceId,
1039-
onActivityItemClick = { navController.navigateToActivityItem(it) },
1036+
onActivityItemClick = { id, walletId -> navController.navigateToActivityItem(id, walletId) },
10401037
onTransferToSpendingClick = { selectedDeviceId ->
10411038
navController.navigateToTransferSpendingStart(hasSeenSpendingIntro, selectedDeviceId)
10421039
},
@@ -1053,7 +1050,7 @@ private fun NavGraphBuilder.allActivity(
10531050
AllActivityScreen(
10541051
viewModel = activityListViewModel,
10551052
onBack = { navController.popBackStack() },
1056-
onActivityItemClick = { navController.navigateToActivityItem(it) },
1053+
onActivityItemClick = { id, walletId -> navController.navigateToActivityItem(id, walletId) },
10571054
)
10581055
}
10591056
}
@@ -1211,7 +1208,7 @@ private fun NavGraphBuilder.contacts(
12111208
ContactActivityScreen(
12121209
viewModel = viewModel,
12131210
onBackClick = { navController.popBackStack() },
1214-
onActivityItemClick = { navController.navigateToActivityItem(it) },
1211+
onActivityItemClick = { id, walletId -> navController.navigateToActivityItem(id, walletId) },
12151212
)
12161213
}
12171214
}
@@ -1595,7 +1592,7 @@ private fun NavGraphBuilder.activityItem(
15951592
ActivityDetailScreen(
15961593
listViewModel = activityListViewModel,
15971594
route = it.toRoute(),
1598-
onExploreClick = { activity -> navController.navigateToActivityExplore(activity) },
1595+
onExploreClick = { id, walletId -> navController.navigateToActivityExplore(id, walletId) },
15991596
onAssignContactClick = { id -> navController.navigateTo(Routes.ActivityAssignContact(id)) },
16001597
onChannelClick = { channelId ->
16011598
navController.navigateTo(Routes.ChannelDetail(channelId))
@@ -1852,15 +1849,9 @@ fun NavController.navigateToTransferIntro() = navigateTo(Routes.TransferIntro)
18521849

18531850
fun NavController.navigateToTransferFunding() = navigateTo(Routes.Funding)
18541851

1855-
fun NavController.navigateToActivityItem(activity: Activity) =
1856-
navigateTo(Routes.ActivityDetail(activity.rawId(), activity.walletId()))
1857-
18581852
fun NavController.navigateToActivityItem(id: String, walletId: String? = null) =
18591853
navigateTo(Routes.ActivityDetail(id, walletId))
18601854

1861-
fun NavController.navigateToActivityExplore(activity: Activity) =
1862-
navigateTo(Routes.ActivityExplore(activity.rawId(), activity.walletId()))
1863-
18641855
fun NavController.navigateToActivityExplore(id: String, walletId: String? = null) =
18651856
navigateTo(Routes.ActivityExplore(id, walletId))
18661857

0 commit comments

Comments
 (0)