@@ -16,9 +16,11 @@ import androidx.compose.foundation.layout.size
1616import androidx.compose.foundation.layout.width
1717import androidx.compose.foundation.rememberScrollState
1818import androidx.compose.foundation.verticalScroll
19+ import androidx.compose.material3.CircularProgressIndicator
1920import androidx.compose.material3.HorizontalDivider
2021import androidx.compose.material3.Icon
2122import androidx.compose.runtime.Composable
23+ import androidx.compose.runtime.DisposableEffect
2224import androidx.compose.runtime.LaunchedEffect
2325import androidx.compose.runtime.ReadOnlyComposable
2426import androidx.compose.runtime.getValue
@@ -75,7 +77,6 @@ import to.bitkit.ui.theme.AppThemeSurface
7577import to.bitkit.ui.theme.Colors
7678import to.bitkit.ui.utils.copyToClipboard
7779import to.bitkit.ui.utils.getScreenTitleRes
78- import to.bitkit.utils.Logger
7980import to.bitkit.viewmodels.ActivityDetailViewModel
8081import to.bitkit.viewmodels.ActivityListViewModel
8182
@@ -89,128 +90,185 @@ fun ActivityDetailScreen(
8990 onCloseClick : () -> Unit ,
9091 onChannelClick : ((String ) -> Unit )? = null,
9192) {
92- val activities by listViewModel.filteredActivities.collectAsStateWithLifecycle()
93- val item = activities?.find { it.rawId() == route.id }
94- if (item == null ) {
95- Logger .error(" Activity not found" )
96- return
97- }
93+ val uiState by detailViewModel.uiState.collectAsStateWithLifecycle()
9894
99- val app = appViewModel ? : return
100- val copyToastTitle = stringResource(R .string.common__copied)
101-
102- val tags by detailViewModel.tags.collectAsStateWithLifecycle()
103- val boostSheetVisible by detailViewModel.boostSheetVisible.collectAsStateWithLifecycle()
104- var showAddTagSheet by remember { mutableStateOf(false ) }
105- var isCpfpChild by remember { mutableStateOf(false ) }
106- var boostTxDoesExist by remember { mutableStateOf<Map <String , Boolean >>(emptyMap()) }
107-
108- LaunchedEffect (item) {
109- detailViewModel.setActivity(item)
110- if (item is Activity .Onchain ) {
111- isCpfpChild = detailViewModel.isCpfpChildTransaction(item.v1.txId)
112- boostTxDoesExist = if (item.v1.boostTxIds.isNotEmpty()) {
113- detailViewModel.getBoostTxDoesExist(item.v1.boostTxIds)
114- } else {
115- emptyMap()
116- }
117- } else {
118- isCpfpChild = false
119- boostTxDoesExist = emptyMap()
120- }
95+ // Load activity on composition
96+ LaunchedEffect (route.id) {
97+ detailViewModel.loadActivity(route.id)
12198 }
12299
123- // Update boostTxDoesExist when boostTxIds change
124- LaunchedEffect ( if (item is Activity . Onchain ) item.v1.boostTxIds else emptyList() ) {
125- if (item is Activity . Onchain && item.v1.boostTxIds.isNotEmpty()) {
126- boostTxDoesExist = detailViewModel.getBoostTxDoesExist(item.v1.boostTxIds )
100+ // Clear state on disposal
101+ DisposableEffect ( Unit ) {
102+ onDispose {
103+ detailViewModel.clearActivityState( )
127104 }
128105 }
129106
130- val context = LocalContext .current
131-
132107 Box (
133108 modifier = Modifier .fillMaxWidth()
134109 ) {
135- Column (
136- modifier = Modifier .background(Colors .Black )
137- ) {
138- AppTopBar (
139- titleText = stringResource(
140- if (isCpfpChild) {
141- R .string.wallet__activity_boost_fee
142- } else {
143- item.getScreenTitleRes()
144- }
145- ),
146- onBackClick = onBackClick,
147- actions = { DrawerNavIcon () },
148- )
149- ActivityDetailContent (
150- item = item,
151- tags = tags,
152- onRemoveTag = { detailViewModel.removeTag(it) },
153- onAddTagClick = { showAddTagSheet = true },
154- onClickBoost = detailViewModel::onClickBoost,
155- onExploreClick = onExploreClick,
156- onChannelClick = onChannelClick,
157- detailViewModel = detailViewModel,
158- isCpfpChild = isCpfpChild,
159- boostTxDoesExist = boostTxDoesExist,
160- onCopy = { text ->
161- app.toast(
162- type = Toast .ToastType .SUCCESS ,
163- title = copyToastTitle,
164- description = text.ellipsisMiddle(40 )
110+ when (val loadState = uiState.activityLoadState) {
111+ is ActivityDetailViewModel .ActivityLoadState .Initial ,
112+ is ActivityDetailViewModel .ActivityLoadState .Loading ,
113+ -> {
114+ Column (modifier = Modifier .background(Colors .Black )) {
115+ AppTopBar (
116+ titleText = stringResource(R .string.wallet__activity),
117+ onBackClick = onBackClick,
118+ actions = { DrawerNavIcon () },
165119 )
120+ Box (
121+ modifier = Modifier
122+ .fillMaxSize()
123+ .padding(16 .dp),
124+ contentAlignment = Alignment .Center
125+ ) {
126+ CircularProgressIndicator ()
127+ }
166128 }
167- )
168- if (showAddTagSheet) {
169- ActivityAddTagSheet (
170- listViewModel = listViewModel,
171- activityViewModel = detailViewModel,
172- onDismiss = { showAddTagSheet = false },
173- )
174129 }
175- }
176130
177- if (boostSheetVisible) {
178- (item as ? Activity .Onchain )?.let {
179- BoostTransactionSheet (
180- onDismiss = detailViewModel::onDismissBoostSheet,
181- item = it,
182- onSuccess = {
183- app.toast(
184- type = Toast .ToastType .SUCCESS ,
185- title = context.getString(R .string.wallet__boost_success_title),
186- description = context.getString(R .string.wallet__boost_success_msg)
131+ is ActivityDetailViewModel .ActivityLoadState .Error -> {
132+ Column (modifier = Modifier .background(Colors .Black )) {
133+ AppTopBar (
134+ titleText = stringResource(R .string.wallet__activity),
135+ onBackClick = onBackClick,
136+ actions = { DrawerNavIcon () },
137+ )
138+ Column (
139+ modifier = Modifier
140+ .fillMaxSize()
141+ .padding(16 .dp),
142+ horizontalAlignment = Alignment .CenterHorizontally ,
143+ verticalArrangement = Arrangement .Center
144+ ) {
145+ BodySSB (
146+ text = loadState.message,
147+ modifier = Modifier .padding(bottom = 16 .dp)
187148 )
188- listViewModel.resync()
189- onCloseClick()
190- },
191- onFailure = {
192- app.toast(
193- type = Toast .ToastType .ERROR ,
194- title = context.getString(R .string.wallet__boost_error_title),
195- description = context.getString(R .string.wallet__boost_error_msg)
149+ PrimaryButton (
150+ text = stringResource(R .string.common__back),
151+ onClick = onBackClick
196152 )
197- detailViewModel.onDismissBoostSheet()
198- },
199- onMaxFee = {
200- app.toast(
201- type = Toast .ToastType .ERROR ,
202- title = context.getString(R .string.wallet__send_fee_error),
203- description = " Unable to increase the fee any further. Otherwise, it will exceed half the current input balance" // TODO CREATE STRING RESOURCE
153+ }
154+ }
155+ }
156+
157+ is ActivityDetailViewModel .ActivityLoadState .Success -> {
158+ val item = loadState.activity
159+ val app = appViewModel ? : return @Box
160+ val copyToastTitle = stringResource(R .string.common__copied)
161+
162+ val tags by detailViewModel.tags.collectAsStateWithLifecycle()
163+ val boostSheetVisible by detailViewModel.boostSheetVisible.collectAsStateWithLifecycle()
164+ var showAddTagSheet by remember { mutableStateOf(false ) }
165+ var isCpfpChild by remember { mutableStateOf(false ) }
166+ var boostTxDoesExist by remember { mutableStateOf<Map <String , Boolean >>(emptyMap()) }
167+
168+ LaunchedEffect (item) {
169+ if (item is Activity .Onchain ) {
170+ isCpfpChild = detailViewModel.isCpfpChildTransaction(item.v1.txId)
171+ boostTxDoesExist = if (item.v1.boostTxIds.isNotEmpty()) {
172+ detailViewModel.getBoostTxDoesExist(item.v1.boostTxIds)
173+ } else {
174+ emptyMap()
175+ }
176+ } else {
177+ isCpfpChild = false
178+ boostTxDoesExist = emptyMap()
179+ }
180+ }
181+
182+ // Update boostTxDoesExist when boostTxIds change
183+ LaunchedEffect (if (item is Activity .Onchain ) item.v1.boostTxIds else emptyList()) {
184+ if (item is Activity .Onchain && item.v1.boostTxIds.isNotEmpty()) {
185+ boostTxDoesExist = detailViewModel.getBoostTxDoesExist(item.v1.boostTxIds)
186+ }
187+ }
188+
189+ val context = LocalContext .current
190+
191+ Column (
192+ modifier = Modifier .background(Colors .Black )
193+ ) {
194+ AppTopBar (
195+ titleText = stringResource(
196+ if (isCpfpChild) {
197+ R .string.wallet__activity_boost_fee
198+ } else {
199+ item.getScreenTitleRes()
200+ }
201+ ),
202+ onBackClick = onBackClick,
203+ actions = { DrawerNavIcon () },
204+ )
205+ ActivityDetailContent (
206+ item = item,
207+ tags = tags,
208+ onRemoveTag = { detailViewModel.removeTag(it) },
209+ onAddTagClick = { showAddTagSheet = true },
210+ onClickBoost = detailViewModel::onClickBoost,
211+ onExploreClick = onExploreClick,
212+ onChannelClick = onChannelClick,
213+ detailViewModel = detailViewModel,
214+ isCpfpChild = isCpfpChild,
215+ boostTxDoesExist = boostTxDoesExist,
216+ onCopy = { text ->
217+ app.toast(
218+ type = Toast .ToastType .SUCCESS ,
219+ title = copyToastTitle,
220+ description = text.ellipsisMiddle(40 )
221+ )
222+ }
223+ )
224+ if (showAddTagSheet) {
225+ ActivityAddTagSheet (
226+ listViewModel = listViewModel,
227+ activityViewModel = detailViewModel,
228+ onDismiss = { showAddTagSheet = false },
204229 )
205- },
206- onMinFee = {
207- app.toast(
208- type = Toast .ToastType .ERROR ,
209- title = context.getString(R .string.wallet__send_fee_error),
210- description = context.getString(R .string.wallet__send_fee_error_min)
230+ }
231+ }
232+
233+ if (boostSheetVisible) {
234+ (item as ? Activity .Onchain )?.let {
235+ BoostTransactionSheet (
236+ onDismiss = detailViewModel::onDismissBoostSheet,
237+ item = it,
238+ onSuccess = {
239+ app.toast(
240+ type = Toast .ToastType .SUCCESS ,
241+ title = context.getString(R .string.wallet__boost_success_title),
242+ description = context.getString(R .string.wallet__boost_success_msg)
243+ )
244+ listViewModel.resync()
245+ onCloseClick()
246+ },
247+ onFailure = {
248+ app.toast(
249+ type = Toast .ToastType .ERROR ,
250+ title = context.getString(R .string.wallet__boost_error_title),
251+ description = context.getString(R .string.wallet__boost_error_msg)
252+ )
253+ detailViewModel.onDismissBoostSheet()
254+ },
255+ onMaxFee = {
256+ app.toast(
257+ type = Toast .ToastType .ERROR ,
258+ title = context.getString(R .string.wallet__send_fee_error),
259+ description = context.getString(R .string.wallet__send_fee_error_max)
260+ )
261+ },
262+ onMinFee = {
263+ app.toast(
264+ type = Toast .ToastType .ERROR ,
265+ title = context.getString(R .string.wallet__send_fee_error),
266+ description = context.getString(R .string.wallet__send_fee_error_min)
267+ )
268+ }
211269 )
212270 }
213- )
271+ }
214272 }
215273 }
216274 }
0 commit comments