Created
February 27, 2024 17:23
-
-
Save electrolobzik/a52637aae091acc23d88a1bdf6a4e885 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ReceivedMediaRepository( | |
private val receivedMediaApiHelper: ReceivedMediaApiHelper, | |
private val receivedMediaDbHelper: ReceivedMediaDbHelper, | |
coroutineContext: CoroutineContext, | |
) : CoroutineScope by CoroutineScope(coroutineContext) { | |
private val coroutineScope = CoroutineScope(coroutineContext) | |
private val factory = ReceivedMediaStoreFactory(api = receivedMediaApiHelper, db = receivedMediaDbHelper) | |
private val mutableStore = factory.create() | |
private val paginator = Paginator<ReceivedMedia, PaginationPosition>(coroutineContext = coroutineContext) | |
private val pager = Pager.create(coroutineScope, mutableStore, ReceivedMediaJoiner(), ReceivedMediaKeyFactory()) | |
val state = paginator.state.map { it.toExternalState() } | |
private val errorsFlow = MutableSharedFlow<LoadingError>() | |
val loadingErrors: Flow<LoadingError> = errorsFlow | |
init { | |
launch { | |
paginator.sideEffects.collect { sideEffect -> | |
when (sideEffect) { | |
is Paginator.SideEffect.NeedToPerformRefresh, | |
is Paginator.SideEffect.NeedToPerformInitialLoad -> getReceivedMediaInitial().collect { storeResponse -> | |
when (storeResponse) { | |
StoreReadResponse.Initial, | |
is StoreReadResponse.Loading -> { | |
// doing nothing | |
} | |
is StoreReadResponse.Data -> { | |
val data = storeResponse.value | |
when (data) { | |
is ReceivedMediaStoreData.Collection -> { | |
paginator.sendAction( | |
Paginator.Action.InitialDataLoaded( | |
lastPage = data.getPaginationPosition(), | |
items = data.items.asMediaList() | |
) | |
) | |
} | |
is ReceivedMediaStoreData.Single -> throw IllegalStateException("Initial data can't be single") | |
} | |
} | |
is StoreReadResponse.Error -> { | |
val loadingError = storeResponse.toLoadingError("Initial load for ReceivedMediaRepository") | |
errorsFlow.emit(loadingError) | |
paginator.sendAction(Paginator.Action.InitialDataLoadingError(loadingError)) | |
} | |
is StoreReadResponse.NoNewData -> TODO() | |
} | |
} | |
is Paginator.SideEffect.NeedToLoadNewPage -> { | |
val newKey = ReceivedMediaStoreKey.Page(cursor = sideEffect.lastPage.nextPageKey, size = MIN_PAGE_SIZE) | |
val storeResponse = pager.load(newKey) | |
when (storeResponse) { | |
StoreReadResponse.Initial, | |
is StoreReadResponse.Loading -> { | |
// doing nothing | |
} | |
is StoreReadResponse.Data -> { | |
val data = storeResponse.value | |
when (data) { | |
is ReceivedMediaStoreData.Collection -> { | |
paginator.sendAction( | |
Paginator.Action.NewPageLoaded( | |
lastPage = data.getPaginationPosition(), | |
items = data.items.asMediaList() | |
) | |
) | |
} | |
is ReceivedMediaStoreData.Single -> throw IllegalStateException("Page data can't be single") | |
} | |
} | |
is StoreReadResponse.Error -> { | |
val loadingError = storeResponse.toLoadingError("New page load for ReceivedMediaRepository") | |
paginator.sendAction(Paginator.Action.NewPageLoadingError(loadingError)) | |
} | |
is StoreReadResponse.NoNewData -> TODO() | |
} | |
} | |
is Paginator.SideEffect.NewPageLoadErrorEvent -> errorsFlow.emit(sideEffect.error) | |
} | |
} | |
} | |
} | |
fun loadInitially() { | |
paginator.sendAction(Paginator.Action.InitialLoad()) | |
} | |
fun getNextPage() { | |
paginator.sendAction(Paginator.Action.LoadMore()) | |
} | |
fun refresh() { | |
paginator.sendAction(Paginator.Action.Refresh()) | |
} | |
private fun getReceivedMediaInitial(): Flow<StoreReadResponse<ReceivedMediaStoreData>> { | |
return mutableStore.stream<Any>(request = StoreReadRequest.cached(ReceivedMediaStoreKey.Heap(), refresh = true)) | |
} | |
data class PaginationPosition( | |
val lastLoadedMediaId: MediaId?, | |
val nextPageKey: ReceivedMediaPageKey? | |
) | |
fun ReceivedMediaStoreData.Collection.getPaginationPosition() = PaginationPosition( | |
lastLoadedMediaId = singles.lastOrNull()?.data?.receivedMediaId, | |
nextPageKey = lastPageKey | |
) | |
fun StoreReadResponse<*>.toLoadingError(actionDescription: String): LoadingError{ | |
return if (this is StoreReadResponse.Error.Custom<*> && this.error is DataResult.ConnectionIssue<*>) { | |
LoadingError.NoConnection(actionDescription) | |
} else { | |
LoadingError.UnknownError(e = (this as StoreReadResponse.Error.Exception).error, actionDescription = actionDescription) | |
} | |
} | |
companion object { | |
const val MIN_PAGE_SIZE = 50 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment