mirror of
				https://github.com/TeamNewPipe/NewPipe
				synced 2025-10-31 07:13:00 +00:00 
			
		
		
		
	Cache paging data using the cachedIn() extension
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|   | ||||
| @@ -1,35 +1,42 @@ | ||||
| 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) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     override fun getRefreshKey(state: PagingState<Page, CommentsInfoItem>) = null | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne