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.compose.material3:material3' | ||||||
|     implementation 'androidx.activity:activity-compose' |     implementation 'androidx.activity:activity-compose' | ||||||
|     implementation 'androidx.compose.ui:ui-tooling-preview' |     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' |     implementation 'com.github.nanihadesuka:LazyColumnScrollbar:2.1.0' | ||||||
|  |  | ||||||
|     // Paging |     // Paging | ||||||
|   | |||||||
| @@ -20,6 +20,7 @@ import androidx.compose.runtime.Composable | |||||||
| import androidx.compose.runtime.getValue | import androidx.compose.runtime.getValue | ||||||
| import androidx.compose.runtime.mutableStateOf | import androidx.compose.runtime.mutableStateOf | ||||||
| import androidx.compose.runtime.remember | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.runtime.rememberCoroutineScope | ||||||
| import androidx.compose.runtime.saveable.rememberSaveable | import androidx.compose.runtime.saveable.rememberSaveable | ||||||
| import androidx.compose.runtime.setValue | import androidx.compose.runtime.setValue | ||||||
| import androidx.compose.ui.Alignment | import androidx.compose.ui.Alignment | ||||||
| @@ -37,6 +38,7 @@ import androidx.compose.ui.unit.dp | |||||||
| import androidx.fragment.app.FragmentActivity | import androidx.fragment.app.FragmentActivity | ||||||
| import androidx.paging.Pager | import androidx.paging.Pager | ||||||
| import androidx.paging.PagingConfig | import androidx.paging.PagingConfig | ||||||
|  | import androidx.paging.cachedIn | ||||||
| import coil.compose.AsyncImage | import coil.compose.AsyncImage | ||||||
| import org.schabi.newpipe.R | import org.schabi.newpipe.R | ||||||
| import org.schabi.newpipe.compose.theme.AppTheme | import org.schabi.newpipe.compose.theme.AppTheme | ||||||
| @@ -141,13 +143,15 @@ fun Comment(comment: CommentsInfoItem) { | |||||||
|  |  | ||||||
|     if (showReplies) { |     if (showReplies) { | ||||||
|         ModalBottomSheet(onDismissRequest = { showReplies = false }) { |         ModalBottomSheet(onDismissRequest = { showReplies = false }) { | ||||||
|             val flow = remember(comment) { |             val coroutineScope = rememberCoroutineScope() | ||||||
|  |             val flow = remember(coroutineScope) { | ||||||
|                 Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { |                 Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { | ||||||
|                     CommentsSource(comment.serviceId, comment.url, comment.replies) |                     CommentsSource(comment.serviceId, comment.url, comment.replies) | ||||||
|                 }.flow |                 }.flow | ||||||
|  |                     .cachedIn(coroutineScope) | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             CommentSection(parentComment = comment, flow = flow) |             CommentSection(parentComment = comment, commentsData = flow) | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -36,13 +36,13 @@ import org.schabi.newpipe.paging.CommentsDisabledException | |||||||
| @Composable | @Composable | ||||||
| fun CommentSection( | fun CommentSection( | ||||||
|     parentComment: CommentsInfoItem? = null, |     parentComment: CommentsInfoItem? = null, | ||||||
|     flow: Flow<PagingData<CommentsInfoItem>> |     commentsData: Flow<PagingData<CommentsInfoItem>> | ||||||
| ) { | ) { | ||||||
|     val replies = flow.collectAsLazyPagingItems() |     val comments = commentsData.collectAsLazyPagingItems() | ||||||
|     val itemCount by remember { derivedStateOf { replies.itemCount } } |     val itemCount by remember { derivedStateOf { comments.itemCount } } | ||||||
|  |  | ||||||
|     Surface(color = MaterialTheme.colorScheme.background) { |     Surface(color = MaterialTheme.colorScheme.background) { | ||||||
|         val refresh = replies.loadState.refresh |         val refresh = comments.loadState.refresh | ||||||
|         if (itemCount == 0 && refresh !is LoadState.Loading) { |         if (itemCount == 0 && refresh !is LoadState.Loading) { | ||||||
|             NoCommentsMessage((refresh as? LoadState.Error)?.error) |             NoCommentsMessage((refresh as? LoadState.Error)?.error) | ||||||
|         } else { |         } else { | ||||||
| @@ -58,7 +58,7 @@ fun CommentSection( | |||||||
|                     } |                     } | ||||||
|  |  | ||||||
|                     items(itemCount) { |                     items(itemCount) { | ||||||
|                         Comment(comment = replies[it]!!) |                         Comment(comment = comments[it]!!) | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
| @@ -113,7 +113,7 @@ private fun CommentSectionPreview( | |||||||
|     @PreviewParameter(CommentDataProvider::class) pagingData: PagingData<CommentsInfoItem> |     @PreviewParameter(CommentDataProvider::class) pagingData: PagingData<CommentsInfoItem> | ||||||
| ) { | ) { | ||||||
|     AppTheme { |     AppTheme { | ||||||
|         CommentSection(flow = flowOf(pagingData)) |         CommentSection(commentsData = flowOf(pagingData)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -137,6 +137,6 @@ private fun CommentRepliesPreview() { | |||||||
|     val flow = flowOf(PagingData.from(replies)) |     val flow = flowOf(PagingData.from(replies)) | ||||||
|  |  | ||||||
|     AppTheme { |     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.View | ||||||
| import android.view.ViewGroup | import android.view.ViewGroup | ||||||
| import androidx.compose.runtime.remember | import androidx.compose.runtime.remember | ||||||
|  | import androidx.compose.runtime.rememberCoroutineScope | ||||||
| import androidx.compose.ui.platform.ComposeView | import androidx.compose.ui.platform.ComposeView | ||||||
| import androidx.compose.ui.platform.ViewCompositionStrategy | import androidx.compose.ui.platform.ViewCompositionStrategy | ||||||
| import androidx.core.os.bundleOf | import androidx.core.os.bundleOf | ||||||
| import androidx.fragment.app.Fragment | import androidx.fragment.app.Fragment | ||||||
| import androidx.paging.Pager | import androidx.paging.Pager | ||||||
| import androidx.paging.PagingConfig | import androidx.paging.PagingConfig | ||||||
|  | import androidx.paging.cachedIn | ||||||
| import org.schabi.newpipe.compose.comment.CommentSection | import org.schabi.newpipe.compose.comment.CommentSection | ||||||
| import org.schabi.newpipe.compose.theme.AppTheme | import org.schabi.newpipe.compose.theme.AppTheme | ||||||
| import org.schabi.newpipe.paging.CommentsSource | import org.schabi.newpipe.paging.CommentsSource | ||||||
| @@ -29,14 +31,16 @@ class CommentsFragment : Fragment() { | |||||||
|         return ComposeView(requireContext()).apply { |         return ComposeView(requireContext()).apply { | ||||||
|             setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) |             setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) | ||||||
|             setContent { |             setContent { | ||||||
|                 val flow = remember(serviceId, url) { |                 val coroutineScope = rememberCoroutineScope() | ||||||
|  |                 val flow = remember(coroutineScope) { | ||||||
|                     Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { |                     Pager(PagingConfig(pageSize = 20, enablePlaceholders = false)) { | ||||||
|                         CommentsSource(serviceId, url, null) |                         CommentsSource(serviceId, url, null) | ||||||
|                     }.flow |                     }.flow | ||||||
|  |                         .cachedIn(coroutineScope) | ||||||
|                 } |                 } | ||||||
|  |  | ||||||
|                 AppTheme { |                 AppTheme { | ||||||
|                     CommentSection(flow = flow) |                     CommentSection(commentsData = flow) | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|   | |||||||
| @@ -1,33 +1,40 @@ | |||||||
| package org.schabi.newpipe.paging | package org.schabi.newpipe.paging | ||||||
|  |  | ||||||
|  | import androidx.paging.PagingSource | ||||||
| import androidx.paging.PagingState | import androidx.paging.PagingState | ||||||
| import androidx.paging.rxjava3.RxPagingSource | import kotlinx.coroutines.Dispatchers | ||||||
| import io.reactivex.rxjava3.core.Single | import kotlinx.coroutines.withContext | ||||||
| import io.reactivex.rxjava3.schedulers.Schedulers | import org.schabi.newpipe.extractor.NewPipe | ||||||
| import org.schabi.newpipe.extractor.Page | import org.schabi.newpipe.extractor.Page | ||||||
|  | import org.schabi.newpipe.extractor.comments.CommentsInfo | ||||||
| import org.schabi.newpipe.extractor.comments.CommentsInfoItem | import org.schabi.newpipe.extractor.comments.CommentsInfoItem | ||||||
| import org.schabi.newpipe.util.ExtractorHelper | import org.schabi.newpipe.util.NO_SERVICE_ID | ||||||
|  |  | ||||||
| class CommentsSource( | class CommentsSource( | ||||||
|     private val serviceId: Int, |     serviceId: Int, | ||||||
|     private val url: String?, |     private val url: String?, | ||||||
|     private val repliesPage: Page? |     private val repliesPage: Page? | ||||||
| ) : RxPagingSource<Page, CommentsInfoItem>() { | ) : PagingSource<Page, CommentsInfoItem>() { | ||||||
|     override fun loadSingle(params: LoadParams<Page>): Single<LoadResult<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 |         // repliesPage is non-null only when used to load the comment replies | ||||||
|         val nextKey = params.key ?: repliesPage |         val nextKey = params.key ?: repliesPage | ||||||
|  |  | ||||||
|         return nextKey?.let { |         return withContext(Dispatchers.IO) { | ||||||
|             ExtractorHelper.getMoreCommentItems(serviceId, url, it) |             nextKey?.let { | ||||||
|                 .subscribeOn(Schedulers.io()) |                 val info = CommentsInfo.getMoreItems(service, url, it) | ||||||
|                 .map { LoadResult.Page(it.items, null, it.nextPage) } |                 LoadResult.Page(info.items, null, info.nextPage) | ||||||
|         } ?: ExtractorHelper.getCommentsInfo(serviceId, url, false) |             } ?: run { | ||||||
|             .subscribeOn(Schedulers.io()) |                 val info = CommentsInfo.getInfo(service, url) | ||||||
|             .map { |                 if (info.isCommentsDisabled) { | ||||||
|                 if (it.isCommentsDisabled) { |  | ||||||
|                     LoadResult.Error(CommentsDisabledException()) |                     LoadResult.Error(CommentsDisabledException()) | ||||||
|                 } else { |                 } else { | ||||||
|                     LoadResult.Page(it.relatedItems, null, it.nextPage) |                     LoadResult.Page(info.relatedItems, null, info.nextPage) | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -42,8 +42,6 @@ import org.schabi.newpipe.extractor.NewPipe; | |||||||
| import org.schabi.newpipe.extractor.Page; | import org.schabi.newpipe.extractor.Page; | ||||||
| import org.schabi.newpipe.extractor.channel.ChannelInfo; | import org.schabi.newpipe.extractor.channel.ChannelInfo; | ||||||
| import org.schabi.newpipe.extractor.channel.tabs.ChannelTabInfo; | 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.kiosk.KioskInfo; | ||||||
| import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; | import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler; | ||||||
| import org.schabi.newpipe.extractor.playlist.PlaylistInfo; | import org.schabi.newpipe.extractor.playlist.PlaylistInfo; | ||||||
| @@ -146,24 +144,6 @@ public final class ExtractorHelper { | |||||||
|                         listLinkHandler, nextPage)); |                         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, |     public static Single<PlaylistInfo> getPlaylistInfo(final int serviceId, | ||||||
|                                                        final String url, |                                                        final String url, | ||||||
|                                                        final boolean forceLoad) { |                                                        final boolean forceLoad) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Isira Seneviratne
					Isira Seneviratne