1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2024-12-23 16:40:32 +00:00

Cache paging data using the cachedIn() extension

This commit is contained in:
Isira Seneviratne 2024-06-30 21:34:42 +05:30
parent 369a46f8fe
commit 02c5f2607a
6 changed files with 43 additions and 48 deletions

View File

@ -293,7 +293,7 @@ dependencies {
implementation 'androidx.compose.material3:material3'
implementation 'androidx.activity:activity-compose'
implementation 'androidx.compose.ui:ui-tooling-preview'
implementation 'androidx.compose.ui:ui-text:1.7.0-beta03' // Needed for parsing HTML to AnnotatedString
implementation 'androidx.compose.ui:ui-text:1.7.0-beta04' // Needed for parsing HTML to AnnotatedString
implementation 'com.github.nanihadesuka:LazyColumnScrollbar:2.1.0'
// Paging

View File

@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
@ -37,6 +38,7 @@ import androidx.compose.ui.unit.dp
import androidx.fragment.app.FragmentActivity
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import coil.compose.AsyncImage
import org.schabi.newpipe.R
import org.schabi.newpipe.compose.theme.AppTheme
@ -141,13 +143,15 @@ fun Comment(comment: CommentsInfoItem) {
if (showReplies) {
ModalBottomSheet(onDismissRequest = { showReplies = false }) {
val flow = remember(comment) {
val coroutineScope = rememberCoroutineScope()
val flow = remember(coroutineScope) {
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
CommentsSource(comment.serviceId, comment.url, comment.replies)
}.flow
.cachedIn(coroutineScope)
}
CommentSection(parentComment = comment, flow = flow)
CommentSection(parentComment = comment, commentsData = flow)
}
}
}

View File

@ -36,13 +36,13 @@ import org.schabi.newpipe.paging.CommentsDisabledException
@Composable
fun CommentSection(
parentComment: CommentsInfoItem? = null,
flow: Flow<PagingData<CommentsInfoItem>>
commentsData: Flow<PagingData<CommentsInfoItem>>
) {
val replies = flow.collectAsLazyPagingItems()
val itemCount by remember { derivedStateOf { replies.itemCount } }
val comments = commentsData.collectAsLazyPagingItems()
val itemCount by remember { derivedStateOf { comments.itemCount } }
Surface(color = MaterialTheme.colorScheme.background) {
val refresh = replies.loadState.refresh
val refresh = comments.loadState.refresh
if (itemCount == 0 && refresh !is LoadState.Loading) {
NoCommentsMessage((refresh as? LoadState.Error)?.error)
} else {
@ -58,7 +58,7 @@ fun CommentSection(
}
items(itemCount) {
Comment(comment = replies[it]!!)
Comment(comment = comments[it]!!)
}
}
}
@ -113,7 +113,7 @@ private fun CommentSectionPreview(
@PreviewParameter(CommentDataProvider::class) pagingData: PagingData<CommentsInfoItem>
) {
AppTheme {
CommentSection(flow = flowOf(pagingData))
CommentSection(commentsData = flowOf(pagingData))
}
}
@ -137,6 +137,6 @@ private fun CommentRepliesPreview() {
val flow = flowOf(PagingData.from(replies))
AppTheme {
CommentSection(parentComment = comment, flow = flow)
CommentSection(parentComment = comment, commentsData = flow)
}
}

View File

@ -5,12 +5,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.cachedIn
import org.schabi.newpipe.compose.comment.CommentSection
import org.schabi.newpipe.compose.theme.AppTheme
import org.schabi.newpipe.paging.CommentsSource
@ -29,14 +31,16 @@ class CommentsFragment : Fragment() {
return ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
val flow = remember(serviceId, url) {
val coroutineScope = rememberCoroutineScope()
val flow = remember(coroutineScope) {
Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) {
CommentsSource(serviceId, url, null)
}.flow
.cachedIn(coroutineScope)
}
AppTheme {
CommentSection(flow = flow)
CommentSection(commentsData = flow)
}
}
}

View File

@ -1,33 +1,40 @@
package org.schabi.newpipe.paging
import androidx.paging.PagingSource
import androidx.paging.PagingState
import androidx.paging.rxjava3.RxPagingSource
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.Page
import org.schabi.newpipe.extractor.comments.CommentsInfo
import org.schabi.newpipe.extractor.comments.CommentsInfoItem
import org.schabi.newpipe.util.ExtractorHelper
import org.schabi.newpipe.util.NO_SERVICE_ID
class CommentsSource(
private val serviceId: Int,
serviceId: Int,
private val url: String?,
private val repliesPage: Page?
) : RxPagingSource<Page, CommentsInfoItem>() {
override fun loadSingle(params: LoadParams<Page>): Single<LoadResult<Page, CommentsInfoItem>> {
) : PagingSource<Page, CommentsInfoItem>() {
init {
require(serviceId != NO_SERVICE_ID) { "serviceId is NO_SERVICE_ID" }
}
private val service = NewPipe.getService(serviceId)
override suspend fun load(params: LoadParams<Page>): LoadResult<Page, CommentsInfoItem> {
// repliesPage is non-null only when used to load the comment replies
val nextKey = params.key ?: repliesPage
return nextKey?.let {
ExtractorHelper.getMoreCommentItems(serviceId, url, it)
.subscribeOn(Schedulers.io())
.map { LoadResult.Page(it.items, null, it.nextPage) }
} ?: ExtractorHelper.getCommentsInfo(serviceId, url, false)
.subscribeOn(Schedulers.io())
.map {
if (it.isCommentsDisabled) {
return withContext(Dispatchers.IO) {
nextKey?.let {
val info = CommentsInfo.getMoreItems(service, url, it)
LoadResult.Page(info.items, null, info.nextPage)
} ?: run {
val info = CommentsInfo.getInfo(service, url)
if (info.isCommentsDisabled) {
LoadResult.Error(CommentsDisabledException())
} else {
LoadResult.Page(it.relatedItems, null, it.nextPage)
LoadResult.Page(info.relatedItems, null, info.nextPage)
}
}
}
}

View File

@ -42,8 +42,6 @@ import org.schabi.newpipe.extractor.NewPipe;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.channel.ChannelInfo;
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabInfo;
import org.schabi.newpipe.extractor.comments.CommentsInfo;
import org.schabi.newpipe.extractor.comments.CommentsInfoItem;
import org.schabi.newpipe.extractor.kiosk.KioskInfo;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
@ -146,24 +144,6 @@ public final class ExtractorHelper {
listLinkHandler, nextPage));
}
public static Single<CommentsInfo> getCommentsInfo(final int serviceId,
final String url,
final boolean forceLoad) {
checkServiceId(serviceId);
return checkCache(forceLoad, serviceId, url, InfoCache.Type.COMMENTS,
Single.fromCallable(() ->
CommentsInfo.getInfo(NewPipe.getService(serviceId), url)));
}
public static Single<InfoItemsPage<CommentsInfoItem>> getMoreCommentItems(
final int serviceId,
final String url,
final Page nextPage) {
checkServiceId(serviceId);
return Single.fromCallable(() ->
CommentsInfo.getMoreItems(NewPipe.getService(serviceId), url, nextPage));
}
public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId,
final String url,
final boolean forceLoad) {