Skip to content

Commit 6b8861e

Browse files
ovitrifclaude
andcommitted
fix: use immutable collections in home redesign
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 91cc9ac commit 6b8861e

6 files changed

Lines changed: 57 additions & 31 deletions

File tree

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

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import androidx.compose.material3.IconButton
2020
import androidx.compose.material3.pulltorefresh.PullToRefreshBox
2121
import androidx.compose.runtime.Composable
2222
import androidx.compose.runtime.getValue
23+
2324
import androidx.compose.ui.Alignment
2425
import androidx.compose.ui.Modifier
2526
import androidx.compose.ui.platform.LocalContext
@@ -34,7 +35,7 @@ import androidx.navigation.NavController
3435
import com.synonym.bitkitcore.ILspNode
3536
import kotlinx.collections.immutable.ImmutableList
3637
import kotlinx.collections.immutable.persistentListOf
37-
import kotlinx.collections.immutable.toImmutableList
38+
3839
import org.lightningdevkit.ldknode.BalanceDetails
3940
import org.lightningdevkit.ldknode.BalanceSource
4041
import org.lightningdevkit.ldknode.BestBlock
@@ -90,10 +91,12 @@ fun NodeInfoScreen(
9091

9192
val isRefreshing by wallet.isRefreshing.collectAsStateWithLifecycle()
9293
val lightningState by wallet.lightningState.collectAsStateWithLifecycle()
94+
val lightningBalances by viewModel.lightningBalances.collectAsStateWithLifecycle()
9395
val peers by viewModel.peers.collectAsStateWithLifecycle()
9496

9597
Content(
9698
lightningState = lightningState,
99+
lightningBalances = lightningBalances,
97100
peers = peers,
98101
isRefreshing = isRefreshing,
99102
onBack = navController::popBackStack,
@@ -107,6 +110,7 @@ fun NodeInfoScreen(
107110
@Composable
108111
private fun Content(
109112
lightningState: LightningState,
113+
lightningBalances: ImmutableList<LightningBalance> = persistentListOf(),
110114
isRefreshing: Boolean = false,
111115
peers: ImmutableList<NodePeer> = persistentListOf(),
112116
onBack: () -> Unit = {},
@@ -139,10 +143,9 @@ private fun Content(
139143
)
140144
lightningState.balances?.let { details ->
141145
WalletBalancesSection(balanceDetails = details)
142-
143-
if (details.lightningBalances.isNotEmpty()) {
144-
LightningBalancesSection(balances = details.lightningBalances.toImmutableList())
145-
}
146+
}
147+
if (lightningBalances.isNotEmpty()) {
148+
LightningBalancesSection(balances = lightningBalances)
146149
}
147150
if (lightningState.channels.isNotEmpty()) {
148151
ChannelsSection(
@@ -528,8 +531,8 @@ private fun Preview() {
528531
latestPathfindingScoresSyncTimestamp = null,
529532
),
530533
nodeId = "0348a2b7c2d3f4e5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9",
531-
peers = listOf(Peers.stag).toImmutableList(),
532-
channels = listOf(
534+
peers = persistentListOf(Peers.stag),
535+
channels = persistentListOf(
533536
createChannelDetails().copy(
534537
channelId = "abc123def456789012345678901234567890123456789012345678901234567890",
535538
channelValueSats = 1000000UL,
@@ -557,7 +560,7 @@ private fun Preview() {
557560
inboundHtlcMinimumMsat = 1000UL,
558561
inboundHtlcMaximumMsat = 200000000UL,
559562
),
560-
).toImmutableList(),
563+
),
561564
balances = BalanceDetails(
562565
totalOnchainBalanceSats = 1000000UL,
563566
spendableOnchainBalanceSats = 900000UL,

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import kotlinx.coroutines.flow.distinctUntilChanged
1515
import kotlinx.coroutines.flow.map
1616
import kotlinx.coroutines.flow.stateIn
1717
import kotlinx.coroutines.launch
18+
import org.lightningdevkit.ldknode.LightningBalance
1819
import org.lightningdevkit.ldknode.PeerDetails
1920
import to.bitkit.R
2021
import to.bitkit.env.Peers
@@ -32,6 +33,12 @@ class NodeInfoViewModel @Inject constructor(
3233
blocktankRepo: BlocktankRepo,
3334
private val lightningRepo: LightningRepo,
3435
) : ViewModel() {
36+
val lightningBalances: StateFlow<ImmutableList<LightningBalance>> =
37+
lightningRepo.lightningState
38+
.map { it.balances?.lightningBalances?.toImmutableList() ?: persistentListOf() }
39+
.distinctUntilChanged()
40+
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), persistentListOf())
41+
3542
val peers: StateFlow<ImmutableList<NodePeer>> = combine(
3643
lightningRepo.lightningState.map { it.peers },
3744
blocktankRepo.blocktankState.map { it.info?.nodes },

app/src/main/java/to/bitkit/ui/screens/wallets/HomeScreen.kt

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ import dev.chrisbanes.haze.hazeSource
7676
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
7777
import dev.chrisbanes.haze.rememberHazeState
7878
import kotlinx.collections.immutable.ImmutableList
79+
import kotlinx.collections.immutable.persistentListOf
7980
import kotlinx.collections.immutable.toImmutableList
8081
import kotlinx.coroutines.launch
8182
import to.bitkit.R
@@ -420,7 +421,7 @@ private fun Content(
420421
private fun WalletPage(
421422
isRefreshing: Boolean,
422423
homeUiState: HomeUiState,
423-
latestActivities: List<Activity>?,
424+
latestActivities: ImmutableList<Activity>?,
424425
balances: BalanceState,
425426
onRefresh: () -> Unit,
426427
onNavigateToSettingUp: () -> Unit,
@@ -619,7 +620,7 @@ private fun WidgetsPage(
619620

620621
@Composable
621622
private fun SuggestionsSection(
622-
suggestions: List<Suggestion>,
623+
suggestions: ImmutableList<Suggestion>,
623624
onRemoveSuggestion: (Suggestion) -> Unit,
624625
onClickSuggestion: (Suggestion) -> Unit,
625626
modifier: Modifier = Modifier,
@@ -882,7 +883,7 @@ private val previewBalances = BalanceState(
882883
totalLightningSats = 45_000u,
883884
)
884885

885-
private val previewWidgets = listOf(
886+
private val previewWidgets = persistentListOf(
886887
WidgetWithPosition(type = WidgetType.SUGGESTIONS, position = 0),
887888
WidgetWithPosition(type = WidgetType.PRICE, position = 1),
888889
WidgetWithPosition(type = WidgetType.BLOCK, position = 2),
@@ -926,6 +927,10 @@ private val previewWeather = WeatherModel(
926927
icon = "\u2600\uFE0F",
927928
)
928929

930+
private val previewLatestActivities = previewActivityItems.take(3).toImmutableList()
931+
private val previewBanners = ActivityBannerType.entries.map { BannerItem(type = it, title = "") }.toImmutableList()
932+
private val previewSuggestions = Suggestion.entries.take(4).toImmutableList()
933+
929934
@Preview(showSystemUi = true)
930935
@Composable
931936
private fun PreviewWithActivity() {
@@ -937,7 +942,7 @@ private fun PreviewWithActivity() {
937942
showWidgets = true,
938943
),
939944
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
940-
latestActivities = previewActivityItems.take(3).toImmutableList(),
945+
latestActivities = previewLatestActivities,
941946
balances = previewBalances,
942947
)
943948
TabBar()
@@ -956,7 +961,7 @@ private fun PreviewEmpty() {
956961
showEmptyState = true,
957962
),
958963
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
959-
latestActivities = previewActivityItems.take(3).toImmutableList(),
964+
latestActivities = previewLatestActivities,
960965
balances = BalanceState(),
961966
)
962967
TabBar()
@@ -973,10 +978,10 @@ private fun PreviewWithBanners() {
973978
isRefreshing = false,
974979
homeUiState = HomeUiState(
975980
showWidgets = true,
976-
banners = ActivityBannerType.entries.map { BannerItem(type = it, title = "") },
981+
banners = previewBanners,
977982
),
978983
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
979-
latestActivities = previewActivityItems.take(3).toImmutableList(),
984+
latestActivities = previewLatestActivities,
980985
balances = previewBalances,
981986
)
982987
TabBar()
@@ -996,7 +1001,7 @@ private fun PreviewWithOnboardingHint() {
9961001
showWidgetsOnboardingHint = true,
9971002
),
9981003
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
999-
latestActivities = previewActivityItems.take(3).toImmutableList(),
1004+
latestActivities = previewLatestActivities,
10001005
balances = previewBalances,
10011006
)
10021007
TabBar()
@@ -1019,10 +1024,10 @@ private fun PreviewWidgetsPage() {
10191024
currentArticle = previewArticle,
10201025
currentPrice = previewPrice,
10211026
currentWeather = previewWeather,
1022-
suggestions = Suggestion.entries.take(4),
1027+
suggestions = previewSuggestions,
10231028
),
10241029
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
1025-
latestActivities = previewActivityItems.take(3).toImmutableList(),
1030+
latestActivities = previewLatestActivities,
10261031
balances = previewBalances,
10271032
)
10281033
TabBar()
@@ -1048,7 +1053,7 @@ private fun PreviewWidgetsEditing() {
10481053
currentWeather = previewWeather,
10491054
),
10501055
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
1051-
latestActivities = previewActivityItems.take(3).toImmutableList(),
1056+
latestActivities = previewLatestActivities,
10521057
balances = previewBalances,
10531058
)
10541059
TabBar()
@@ -1067,7 +1072,7 @@ private fun PreviewTabletLandscape() {
10671072
showWidgets = true,
10681073
),
10691074
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
1070-
latestActivities = previewActivityItems.take(3).toImmutableList(),
1075+
latestActivities = previewLatestActivities,
10711076
balances = previewBalances,
10721077
)
10731078
TabBar()
@@ -1086,7 +1091,7 @@ private fun PreviewTabletPortrait() {
10861091
showWidgets = true,
10871092
),
10881093
drawerState = rememberDrawerState(initialValue = DrawerValue.Closed),
1089-
latestActivities = previewActivityItems.take(3).toImmutableList(),
1094+
latestActivities = previewLatestActivities,
10901095
balances = previewBalances,
10911096
)
10921097
TabBar()

app/src/main/java/to/bitkit/ui/screens/wallets/HomeViewModel.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,8 @@ class HomeViewModel @Inject constructor(
246246
_uiState.update {
247247
it.copy(
248248
widgetsWithPosition = it.widgetsWithPosition
249-
.filterNot { widget -> widget.type == widgetType },
249+
.filterNot { widget -> widget.type == widgetType }
250+
.toImmutableList(),
250251
deleteWidgetAlert = null,
251252
)
252253
}

app/src/main/java/to/bitkit/ui/settings/lightning/ChannelDetailViewModel.kt

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package to.bitkit.ui.settings.lightning
22

33
import android.content.Context
4+
import androidx.compose.runtime.Stable
45
import androidx.lifecycle.ViewModel
56
import androidx.lifecycle.viewModelScope
67
import com.synonym.bitkitcore.Activity
@@ -11,6 +12,9 @@ import com.synonym.bitkitcore.PaymentType
1112
import com.synonym.bitkitcore.SortDirection
1213
import dagger.hilt.android.lifecycle.HiltViewModel
1314
import dagger.hilt.android.qualifiers.ApplicationContext
15+
import kotlinx.collections.immutable.ImmutableList
16+
import kotlinx.collections.immutable.persistentListOf
17+
import kotlinx.collections.immutable.toImmutableList
1418
import kotlinx.coroutines.Job
1519
import kotlinx.coroutines.delay
1620
import kotlinx.coroutines.flow.MutableStateFlow
@@ -71,8 +75,8 @@ class ChannelDetailViewModel @Inject constructor(
7175
_uiState.update {
7276
it.copy(
7377
channelLoadState = ChannelLoadState.Success(channelUi),
74-
paidOrders = blocktankRepo.blocktankState.value.paidOrders,
75-
cjitEntries = blocktankRepo.blocktankState.value.cjitEntries,
78+
paidOrders = blocktankRepo.blocktankState.value.paidOrders.toImmutableList(),
79+
cjitEntries = blocktankRepo.blocktankState.value.cjitEntries.toImmutableList(),
7680
isClosedChannel = isClosedChannel,
7781
nodeId = lightningRepo.getNodeId().orEmpty(),
7882
)
@@ -171,8 +175,8 @@ class ChannelDetailViewModel @Inject constructor(
171175
_uiState.update {
172176
it.copy(
173177
channelLoadState = ChannelLoadState.Success(updatedChannel),
174-
paidOrders = blocktankState.paidOrders,
175-
cjitEntries = blocktankState.cjitEntries,
178+
paidOrders = blocktankState.paidOrders.toImmutableList(),
179+
cjitEntries = blocktankState.cjitEntries.toImmutableList(),
176180
nodeId = lightningRepo.getNodeId().orEmpty(),
177181
)
178182
}
@@ -186,8 +190,8 @@ class ChannelDetailViewModel @Inject constructor(
186190
it.copy(
187191
channelLoadState = ChannelLoadState.Success(closedChannel),
188192
isClosedChannel = true,
189-
paidOrders = blocktankState.paidOrders,
190-
cjitEntries = blocktankState.cjitEntries,
193+
paidOrders = blocktankState.paidOrders.toImmutableList(),
194+
cjitEntries = blocktankState.cjitEntries.toImmutableList(),
191195
nodeId = lightningRepo.getNodeId().orEmpty(),
192196
)
193197
}
@@ -200,10 +204,11 @@ class ChannelDetailViewModel @Inject constructor(
200204
}
201205
}
202206

207+
@Stable
203208
data class ChannelDetailUiState(
204209
val channelLoadState: ChannelLoadState = ChannelLoadState.Loading,
205-
val paidOrders: List<IBtOrder> = emptyList(),
206-
val cjitEntries: List<IcJitEntry> = emptyList(),
210+
val paidOrders: ImmutableList<IBtOrder> = persistentListOf(),
211+
val cjitEntries: ImmutableList<IcJitEntry> = persistentListOf(),
207212
val txTime: ULong? = null,
208213
val isRefreshing: Boolean = false,
209214
val isClosedChannel: Boolean = false,

app/src/main/java/to/bitkit/viewmodels/ActivityListViewModel.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ import com.synonym.bitkitcore.ActivityFilter
77
import com.synonym.bitkitcore.PaymentType
88
import dagger.hilt.android.lifecycle.HiltViewModel
99
import kotlinx.collections.immutable.ImmutableList
10+
import kotlinx.collections.immutable.ImmutableSet
1011
import kotlinx.collections.immutable.persistentListOf
12+
import kotlinx.collections.immutable.persistentSetOf
1113
import kotlinx.collections.immutable.toImmutableList
14+
import kotlinx.collections.immutable.toImmutableSet
1215
import kotlinx.coroutines.CoroutineDispatcher
1316
import kotlinx.coroutines.FlowPreview
1417
import kotlinx.coroutines.flow.Flow
@@ -56,7 +59,9 @@ class ActivityListViewModel @Inject constructor(
5659
val searchText: StateFlow<String> = _filters.map { it.searchText }.stateInScope("")
5760
val startDate: StateFlow<Long?> = _filters.map { it.startDate }.stateInScope(null)
5861
val endDate: StateFlow<Long?> = _filters.map { it.endDate }.stateInScope(null)
59-
val selectedTags: StateFlow<Set<String>> = _filters.map { it.tags }.stateInScope(emptySet())
62+
val selectedTags: StateFlow<ImmutableSet<String>> = _filters.map { it.tags.toImmutableSet() }.stateInScope(
63+
persistentSetOf()
64+
)
6065
val selectedTab: StateFlow<ActivityTab> = _filters.map { it.tab }.stateInScope(ActivityTab.ALL)
6166

6267
fun setSearchText(text: String) = _filters.update { it.copy(searchText = text) }

0 commit comments

Comments
 (0)