Updated on 2026-08-14
This commit is contained in:
parent
7d9da40464
commit
519f5332f1
23 changed files with 379 additions and 132 deletions
|
|
@ -10,6 +10,8 @@ android {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.data.common)
|
||||
|
||||
implementation(projects.core.utils)
|
||||
implementation(projects.core.datasource)
|
||||
implementation(projects.domain.legacy)
|
||||
|
|
@ -20,7 +22,8 @@ dependencies {
|
|||
|
||||
implementation(deps.kotlin.coroutines)
|
||||
implementation(deps.androidx.paging.runtime)
|
||||
implementation(deps.arrow.core)
|
||||
implementation(deps.timber)
|
||||
implementation(deps.jodatime)
|
||||
|
||||
implementation(deps.hilt.core)
|
||||
kapt(deps.hilt.kapt)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
package com.tangem.data.txhistory.di
|
||||
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.txhistory.repository.DefaultTxHistoryRepository
|
||||
import com.tangem.datasource.local.txhistory.TxHistoryItemsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.txhistory.repository.TxHistoryRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
|
|
@ -17,10 +19,14 @@ internal object TxHistoryDataModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
fun provideTxHistoryRepository(
|
||||
cacheRegistry: CacheRegistry,
|
||||
walletManagersFacade: WalletManagersFacade,
|
||||
userWalletsStore: UserWalletsStore,
|
||||
txHistoryItemsStore: TxHistoryItemsStore,
|
||||
): TxHistoryRepository = DefaultTxHistoryRepository(
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
userWalletsStore = userWalletsStore,
|
||||
cacheRegistry,
|
||||
walletManagersFacade,
|
||||
userWalletsStore,
|
||||
txHistoryItemsStore,
|
||||
)
|
||||
}
|
||||
|
|
@ -3,7 +3,9 @@ package com.tangem.data.txhistory.repository
|
|||
import androidx.paging.Pager
|
||||
import androidx.paging.PagingConfig
|
||||
import androidx.paging.PagingData
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.data.txhistory.repository.paging.TxHistoryPagingSource
|
||||
import com.tangem.datasource.local.txhistory.TxHistoryItemsStore
|
||||
import com.tangem.datasource.local.userwallet.UserWalletsStore
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.tokens.model.Network
|
||||
|
|
@ -13,50 +15,57 @@ import com.tangem.domain.txhistory.models.TxHistoryStateError
|
|||
import com.tangem.domain.txhistory.repository.TxHistoryRepository
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWallet
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
class DefaultTxHistoryRepository(
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val userWalletsStore: UserWalletsStore,
|
||||
private val txHistoryItemsStore: TxHistoryItemsStore,
|
||||
) : TxHistoryRepository {
|
||||
|
||||
override suspend fun getTxHistoryItemsCount(network: Network): Int {
|
||||
val userWallet = getUserWallet()
|
||||
override suspend fun getTxHistoryItemsCount(userWalletId: UserWalletId, network: Network): Int {
|
||||
val userWallet = getUserWallet(userWalletId)
|
||||
val state = walletManagersFacade.getTxHistoryState(
|
||||
userWalletId = userWallet.walletId,
|
||||
network = network,
|
||||
)
|
||||
return when (state) {
|
||||
is TxHistoryState.Failed.FetchError -> throw TxHistoryStateError.DataError(state.exception)
|
||||
TxHistoryState.NotImplemented -> throw TxHistoryStateError.TxHistoryNotImplemented
|
||||
TxHistoryState.Success.Empty -> throw TxHistoryStateError.EmptyTxHistories
|
||||
is TxHistoryState.NotImplemented -> throw TxHistoryStateError.TxHistoryNotImplemented
|
||||
is TxHistoryState.Success.Empty -> throw TxHistoryStateError.EmptyTxHistories
|
||||
is TxHistoryState.Success.HasTransactions -> state.txCount
|
||||
}
|
||||
}
|
||||
|
||||
override fun getTxHistoryItems(currency: CryptoCurrency, pageSize: Int): Flow<PagingData<TxHistoryItem>> {
|
||||
val userWallet = getUserWallet()
|
||||
return Pager(
|
||||
override fun getTxHistoryItems(
|
||||
userWalletId: UserWalletId,
|
||||
currency: CryptoCurrency,
|
||||
pageSize: Int,
|
||||
refresh: Boolean,
|
||||
): Flow<PagingData<TxHistoryItem>> {
|
||||
val pager = Pager(
|
||||
config = PagingConfig(
|
||||
pageSize = pageSize,
|
||||
initialLoadSize = pageSize,
|
||||
),
|
||||
pagingSourceFactory = {
|
||||
TxHistoryPagingSource(
|
||||
loadPage = { page: Int, pageSize: Int ->
|
||||
walletManagersFacade.getTxHistoryItems(
|
||||
userWalletId = userWallet.walletId,
|
||||
currency = currency,
|
||||
page = page,
|
||||
pageSize = pageSize,
|
||||
)
|
||||
},
|
||||
sourceParams = TxHistoryPagingSource.Params(userWalletId, currency, pageSize, refresh),
|
||||
txHistoryItemsStore = txHistoryItemsStore,
|
||||
walletManagersFacade = walletManagersFacade,
|
||||
cacheRegistry = cacheRegistry,
|
||||
)
|
||||
},
|
||||
).flow
|
||||
)
|
||||
|
||||
return pager.flow
|
||||
}
|
||||
|
||||
private fun getUserWallet(): UserWallet = requireNotNull(userWalletsStore.selectedUserWalletOrNull) {
|
||||
"Selected wallet must not be null"
|
||||
private suspend fun getUserWallet(userWalletId: UserWalletId): UserWallet {
|
||||
return requireNotNull(userWalletsStore.getSyncOrNull(userWalletId)) {
|
||||
"Unable to find user wallet with provided ID: $userWalletId"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,34 +2,96 @@ package com.tangem.data.txhistory.repository.paging
|
|||
|
||||
import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import com.tangem.data.common.cache.CacheRegistry
|
||||
import com.tangem.datasource.local.txhistory.TxHistoryItemsStore
|
||||
import com.tangem.domain.tokens.model.CryptoCurrency
|
||||
import com.tangem.domain.txhistory.models.PaginationWrapper
|
||||
import com.tangem.domain.txhistory.models.TxHistoryItem
|
||||
|
||||
private const val INITIAL_PAGE = 1
|
||||
import com.tangem.domain.walletmanager.WalletManagersFacade
|
||||
import com.tangem.domain.wallets.models.UserWalletId
|
||||
import timber.log.Timber
|
||||
|
||||
internal class TxHistoryPagingSource(
|
||||
private val loadPage: suspend (page: Int, pageSize: Int) -> PaginationWrapper<TxHistoryItem>,
|
||||
private val sourceParams: Params,
|
||||
private val txHistoryItemsStore: TxHistoryItemsStore,
|
||||
private val walletManagersFacade: WalletManagersFacade,
|
||||
private val cacheRegistry: CacheRegistry,
|
||||
) : PagingSource<Int, TxHistoryItem>() {
|
||||
|
||||
private val storeKey = TxHistoryItemsStore.Key(sourceParams.userWalletId, sourceParams.currency)
|
||||
|
||||
override fun getRefreshKey(state: PagingState<Int, TxHistoryItem>): Int? {
|
||||
return state.anchorPosition?.let { anchorPosition ->
|
||||
state.closestPageToPosition(anchorPosition)?.prevKey?.plus(other = 1)
|
||||
?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(other = 1)
|
||||
val anchorPage = state.closestPageToPosition(anchorPosition)
|
||||
anchorPage?.prevKey?.inc() ?: anchorPage?.nextKey?.dec()
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, TxHistoryItem> {
|
||||
val currentPage = params.key ?: INITIAL_PAGE
|
||||
return try {
|
||||
val result = loadPage(currentPage, params.loadSize)
|
||||
val pageToLoad = params.key ?: INITIAL_PAGE
|
||||
|
||||
LoadResult.Page(
|
||||
data = result.items,
|
||||
prevKey = if (currentPage > INITIAL_PAGE) currentPage.minus(1) else null,
|
||||
nextKey = if (result.page < result.totalPages) currentPage.plus(1) else null,
|
||||
return try {
|
||||
val wrappedItems = loadItems(
|
||||
pageToLoad = pageToLoad,
|
||||
pageSize = sourceParams.pageSize,
|
||||
refresh = sourceParams.refresh && params is LoadParams.Refresh,
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
|
||||
val items = wrappedItems.items
|
||||
val prevPage = when {
|
||||
items.isEmpty() -> null
|
||||
pageToLoad > INITIAL_PAGE -> pageToLoad.dec()
|
||||
else -> null
|
||||
}
|
||||
val nextPage = when {
|
||||
items.isEmpty() -> INITIAL_PAGE
|
||||
pageToLoad < wrappedItems.totalPages -> pageToLoad.inc()
|
||||
else -> null
|
||||
}
|
||||
|
||||
LoadResult.Page(items, prevKey = prevPage, nextKey = nextPage)
|
||||
} catch (e: Throwable) {
|
||||
Timber.e(e, "Unable to load the transaction history for the requested page: $pageToLoad")
|
||||
|
||||
LoadResult.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadItems(pageToLoad: Int, pageSize: Int, refresh: Boolean): PaginationWrapper<TxHistoryItem> {
|
||||
cacheRegistry.invokeOnExpire(
|
||||
key = getTxHistoryPageKey(pageToLoad),
|
||||
skipCache = refresh,
|
||||
block = { fetch(pageToLoad, pageSize) },
|
||||
)
|
||||
|
||||
return requireNotNull(txHistoryItemsStore.getSyncOrNull(storeKey, pageToLoad)) {
|
||||
"The transaction history page #$pageToLoad could not be retrieved"
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetch(pageToLoad: Int, pageSize: Int) {
|
||||
val wrappedItems = walletManagersFacade.getTxHistoryItems(
|
||||
userWalletId = sourceParams.userWalletId,
|
||||
currency = sourceParams.currency,
|
||||
page = pageToLoad,
|
||||
pageSize = pageSize,
|
||||
)
|
||||
|
||||
txHistoryItemsStore.store(storeKey, wrappedItems)
|
||||
}
|
||||
|
||||
private fun getTxHistoryPageKey(page: Int): String {
|
||||
return "tx_history_page_${sourceParams.currency}_${sourceParams.userWalletId}_$page"
|
||||
}
|
||||
|
||||
data class Params(
|
||||
val userWalletId: UserWalletId,
|
||||
val currency: CryptoCurrency,
|
||||
val pageSize: Int,
|
||||
val refresh: Boolean,
|
||||
)
|
||||
|
||||
private companion object {
|
||||
private const val INITIAL_PAGE = 1
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue