diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt index 053b87757c..e4904101e8 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/TokenDetailsStateFactory.kt @@ -8,6 +8,7 @@ import com.tangem.core.ui.components.bottomsheets.TangemBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.chooseaddress.ChooseAddressBottomSheetConfig import com.tangem.core.ui.components.bottomsheets.tokenreceive.AddressModel import com.tangem.core.ui.components.bottomsheets.tokenreceive.TokenReceiveBottomSheetConfig +import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.tokens.error.CurrencyStatusError import com.tangem.domain.tokens.model.CryptoCurrency @@ -23,6 +24,7 @@ import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.t import com.tangem.feature.tokendetails.presentation.tokendetails.state.factory.txhistory.TokenDetailsLoadingTxHistoryConverter import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow internal class TokenDetailsStateFactory( private val currentStateProvider: Provider, @@ -89,6 +91,16 @@ internal class TokenDetailsStateFactory( return tokenDetailsButtonsConverter.convert(actions) } + fun getLoadingTxHistoryState(): TokenDetailsState { + return currentStateProvider().copy( + txHistoryState = TxHistoryState.Content( + contentItems = MutableStateFlow( + value = TxHistoryState.getDefaultLoadingTransactions(clickIntents::onExploreClick), + ), + ), + ) + } + fun getLoadingTxHistoryState(itemsCountEither: Either): TokenDetailsState { return loadingTransactionsStateConverter.convert(value = itemsCountEither) } diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt index 599d55f418..591a42c218 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsLoadingTxHistoryConverter.kt @@ -9,6 +9,7 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError import com.tangem.feature.tokendetails.presentation.tokendetails.state.TokenDetailsState import com.tangem.feature.tokendetails.presentation.tokendetails.viewmodels.TokenDetailsClickIntents import com.tangem.utils.converter.Converter +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update internal class TokenDetailsLoadingTxHistoryConverter( @@ -34,22 +35,28 @@ internal class TokenDetailsLoadingTxHistoryConverter( private fun convert(value: Int): TokenDetailsState { val state = currentStateProvider() - val txHistoryContent = state.txHistoryState as TxHistoryState.Content - txHistoryContent.contentItems.update { - PagingData.from( - data = listOf(TxHistoryState.TxHistoryItemState.Title(onExploreClick = clickIntents::onExploreClick)) + - MutableList( - size = value, - init = { - TxHistoryState.TxHistoryItemState.Transaction( - state = TransactionState.Loading(it.toString()), - ) - }, - ), + return if (state.txHistoryState is TxHistoryState.Content) { + state.txHistoryState.contentItems.update { + PagingData.from(data = createLoadingItems(value)) + } + state + } else { + val txHistoryContent = TxHistoryState.Content( + contentItems = MutableStateFlow( + value = PagingData.from(data = createLoadingItems(value)), + ), ) + state.copy(txHistoryState = txHistoryContent) } + } - return state + private fun createLoadingItems(size: Int): List { + return buildList { + add(TxHistoryState.TxHistoryItemState.Title(onExploreClick = clickIntents::onExploreClick)) + (1..size).forEach { + add(TxHistoryState.TxHistoryItemState.Transaction(state = TransactionState.Loading(it.toString()))) + } + } } } \ No newline at end of file diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt index b4e618aeb3..0f700b9373 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/state/factory/txhistory/TokenDetailsTxHistoryItemFlowConverter.kt @@ -15,10 +15,7 @@ import com.tangem.utils.extensions.isToday import com.tangem.utils.extensions.isYesterday import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.flow.update +import kotlinx.coroutines.flow.* import org.joda.time.DateTime import org.joda.time.DateTimeZone @@ -37,8 +34,12 @@ internal class TokenDetailsTxHistoryItemFlowConverter( } override fun convert(value: Flow>): TxHistoryState { - val txHistoryContent = currentStateProvider().txHistoryState as TxHistoryState.Content - + val state = currentStateProvider() + val txHistoryContent = if (state.txHistoryState is TxHistoryState.Content) { + state.txHistoryState + } else { + TxHistoryState.Content(contentItems = MutableStateFlow(PagingData.empty())) + } // FIXME: TxHistoryRepository should send loading transactions // [REDACTED_JIRA] value diff --git a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt index c2c671b82d..fcb13d0d4c 100644 --- a/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt +++ b/features/tokendetails/impl/src/main/kotlin/com/tangem/feature/tokendetails/presentation/tokendetails/viewmodels/TokenDetailsViewModel.kt @@ -9,6 +9,7 @@ import arrow.core.getOrElse import com.tangem.blockchain.common.address.AddressType import com.tangem.common.Provider import com.tangem.core.analytics.api.AnalyticsEventHandler +import com.tangem.core.ui.components.transactions.state.TxHistoryState import com.tangem.domain.appcurrency.GetSelectedAppCurrencyUseCase import com.tangem.domain.appcurrency.model.AppCurrency import com.tangem.domain.balancehiding.IsBalanceHiddenUseCase @@ -35,6 +36,8 @@ import com.tangem.utils.coroutines.CoroutineDispatcherProvider import com.tangem.utils.coroutines.JobHolder import com.tangem.utils.coroutines.saveIn import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.async +import kotlinx.coroutines.awaitAll import kotlinx.coroutines.flow.* import kotlinx.coroutines.launch import timber.log.Timber @@ -103,7 +106,7 @@ internal class TokenDetailsViewModel @Inject constructor( private fun updateContent(selectedWallet: UserWallet) { updateMarketPrice(selectedWallet = selectedWallet) - updateTxHistory() + updateTxHistory(refresh = false, showItemsLoading = true) updateWarnings(selectedWallet = selectedWallet) } @@ -162,13 +165,19 @@ internal class TokenDetailsViewModel @Inject constructor( .saveIn(marketPriceJobHolder) } - private fun updateTxHistory(refresh: Boolean = false) { + /** + * @param refresh - invalidate cache and get data from remote + * @param showItemsLoading - show loading items placeholder. + */ + @Suppress("UnusedPrivateMember") // will be removed after implement caching + private fun updateTxHistory(refresh: Boolean, showItemsLoading: Boolean) { viewModelScope.launch(dispatchers.io) { val txHistoryItemsCountEither = txHistoryItemsCountUseCase( network = cryptoCurrency.network, ) - if (!refresh) { + // if countEither is left, handling error state run inside getLoadingTxHistoryState + if (showItemsLoading || txHistoryItemsCountEither.isLeft()) { uiState = stateFactory.getLoadingTxHistoryState(itemsCountEither = txHistoryItemsCountEither) } @@ -211,7 +220,8 @@ internal class TokenDetailsViewModel @Inject constructor( override fun onReloadClick() { analyticsEventsHandler.send(TokenScreenEvent.ButtonReload(cryptoCurrency.symbol)) - updateTxHistory() + uiState = stateFactory.getLoadingTxHistoryState() + updateTxHistory(refresh = true, showItemsLoading = true) } override fun onSendClick() { @@ -358,13 +368,22 @@ internal class TokenDetailsViewModel @Inject constructor( uiState = stateFactory.getRefreshingState() viewModelScope.launch(dispatchers.io) { - fetchCurrencyStatusUseCase.invoke( - userWalletId = wallet.walletId, - id = cryptoCurrency.id, - refresh = true, - ) - updateTxHistory(refresh = true) - updateWarnings(wallet) + listOf( + async { + fetchCurrencyStatusUseCase.invoke( + userWalletId = wallet.walletId, + id = cryptoCurrency.id, + refresh = true, + ) + }, + async { + updateTxHistory( + refresh = true, + showItemsLoading = uiState.txHistoryState !is TxHistoryState.Content, + ) + }, + async { updateWarnings(wallet) }, + ).awaitAll() uiState = stateFactory.getRefreshedState() }.saveIn(refreshStateJobHolder) }