mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2025-01-09 17:00:32 +00:00
Remove playlist preview dependency on external HTTP calls
This commit is contained in:
parent
b9556a1331
commit
82e5b6b1e9
@ -10,26 +10,35 @@ import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.paging.PagingData
|
||||
import androidx.paging.compose.collectAsLazyPagingItems
|
||||
import org.schabi.newpipe.DownloaderImpl
|
||||
import org.schabi.newpipe.compose.status.LoadingIndicator
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOf
|
||||
import org.schabi.newpipe.compose.common.LoadingIndicator
|
||||
import org.schabi.newpipe.compose.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.compose.stream.StreamList
|
||||
import org.schabi.newpipe.compose.theme.AppTheme
|
||||
import org.schabi.newpipe.extractor.NewPipe
|
||||
import org.schabi.newpipe.extractor.ServiceList
|
||||
import org.schabi.newpipe.util.KEY_SERVICE_ID
|
||||
import org.schabi.newpipe.util.KEY_URL
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.extractor.stream.StreamType
|
||||
import org.schabi.newpipe.viewmodels.PlaylistViewModel
|
||||
|
||||
@Composable
|
||||
fun Playlist(playlistViewModel: PlaylistViewModel = viewModel()) {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
val playlistInfo by playlistViewModel.playlistInfo.collectAsState()
|
||||
Playlist(playlistInfo, playlistViewModel.streamItems)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun Playlist(
|
||||
playlistInfo: PlaylistInfo?,
|
||||
streamFlow: Flow<PagingData<StreamInfoItem>>
|
||||
) {
|
||||
playlistInfo?.let {
|
||||
val streams = playlistViewModel.streamItems.collectAsLazyPagingItems()
|
||||
val streams = streamFlow.collectAsLazyPagingItems()
|
||||
val totalDuration by remember {
|
||||
derivedStateOf {
|
||||
streams.itemSnapshotList.sumOf { it!!.duration }
|
||||
@ -50,22 +59,23 @@ fun Playlist(playlistViewModel: PlaylistViewModel = viewModel()) {
|
||||
}
|
||||
)
|
||||
} ?: LoadingIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(name = "Light mode", uiMode = Configuration.UI_MODE_NIGHT_NO)
|
||||
@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PlaylistPreview() {
|
||||
NewPipe.init(DownloaderImpl.init(null))
|
||||
|
||||
val params = mapOf(
|
||||
KEY_SERVICE_ID to ServiceList.YouTube.serviceId,
|
||||
KEY_URL to "https://www.youtube.com/playlist?list=PLAIcZs9N4171hRrG_4v32Ca2hLvSuQ6QI"
|
||||
val description = Description("Example description", Description.PLAIN_TEXT)
|
||||
val playlistInfo = PlaylistInfo(
|
||||
"", 1, "", "Example playlist", description, listOf(), 1L,
|
||||
null, "Uploader", listOf(), null
|
||||
)
|
||||
val stream = StreamInfoItem(streamType = StreamType.VIDEO_STREAM)
|
||||
val streamFlow = flowOf(PagingData.from(listOf(stream)))
|
||||
|
||||
AppTheme {
|
||||
Surface(color = MaterialTheme.colorScheme.background) {
|
||||
Playlist(PlaylistViewModel(SavedStateHandle(params)))
|
||||
Playlist(playlistInfo, streamFlow)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,14 +34,11 @@ import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import coil.compose.AsyncImage
|
||||
import org.schabi.newpipe.DownloaderImpl
|
||||
import org.schabi.newpipe.R
|
||||
import org.schabi.newpipe.compose.common.DescriptionText
|
||||
import org.schabi.newpipe.compose.theme.AppTheme
|
||||
import org.schabi.newpipe.error.ErrorUtil
|
||||
import org.schabi.newpipe.extractor.NewPipe
|
||||
import org.schabi.newpipe.extractor.ServiceList
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.util.Localization
|
||||
@ -67,7 +64,7 @@ fun PlaylistHeader(playlistInfo: PlaylistInfo, totalDuration: Long) {
|
||||
NavigationHelper.openChannelFragment(
|
||||
(context as FragmentActivity).supportFragmentManager,
|
||||
playlistInfo.serviceId, playlistInfo.uploaderUrl,
|
||||
playlistInfo.uploaderName
|
||||
playlistInfo.uploaderName!!
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
ErrorUtil.showUiErrorSnackbar(context, "Opening channel fragment", e)
|
||||
@ -108,14 +105,13 @@ fun PlaylistHeader(playlistInfo: PlaylistInfo, totalDuration: Long) {
|
||||
Text(text = "$count • $formattedDuration", style = MaterialTheme.typography.bodySmall)
|
||||
}
|
||||
|
||||
val description = playlistInfo.description ?: Description.EMPTY_DESCRIPTION
|
||||
if (description != Description.EMPTY_DESCRIPTION) {
|
||||
if (playlistInfo.description != Description.EMPTY_DESCRIPTION) {
|
||||
var isExpanded by rememberSaveable { mutableStateOf(false) }
|
||||
var isExpandable by rememberSaveable { mutableStateOf(false) }
|
||||
|
||||
DescriptionText(
|
||||
modifier = Modifier.animateContentSize(),
|
||||
description = description,
|
||||
description = playlistInfo.description,
|
||||
maxLines = if (isExpanded) Int.MAX_VALUE else 5,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
overflow = TextOverflow.Ellipsis,
|
||||
@ -144,10 +140,10 @@ fun PlaylistHeader(playlistInfo: PlaylistInfo, totalDuration: Long) {
|
||||
@Preview(name = "Dark mode", uiMode = Configuration.UI_MODE_NIGHT_YES)
|
||||
@Composable
|
||||
private fun PlaylistHeaderPreview() {
|
||||
NewPipe.init(DownloaderImpl.init(null))
|
||||
val playlistInfo = PlaylistInfo.getInfo(
|
||||
ServiceList.YouTube,
|
||||
"https://www.youtube.com/playlist?list=PLAIcZs9N4171hRrG_4v32Ca2hLvSuQ6QI"
|
||||
val description = Description("Example description", Description.PLAIN_TEXT)
|
||||
val playlistInfo = PlaylistInfo(
|
||||
"", 1, "", "Example playlist", description, listOf(), 1L,
|
||||
null, "Uploader", listOf(), null
|
||||
)
|
||||
|
||||
AppTheme {
|
||||
|
@ -0,0 +1,22 @@
|
||||
package org.schabi.newpipe.compose.playlist
|
||||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import org.schabi.newpipe.extractor.Image
|
||||
import org.schabi.newpipe.extractor.Page
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
|
||||
@Immutable
|
||||
class PlaylistInfo(
|
||||
val id: String,
|
||||
val serviceId: Int,
|
||||
val url: String,
|
||||
val name: String,
|
||||
val description: Description,
|
||||
val relatedItems: List<StreamInfoItem>,
|
||||
val streamCount: Long,
|
||||
val uploaderUrl: String?,
|
||||
val uploaderName: String?,
|
||||
val uploaderAvatars: List<Image>,
|
||||
val nextPage: Page?
|
||||
)
|
@ -26,10 +26,10 @@ import org.schabi.newpipe.util.NavigationHelper
|
||||
@Composable
|
||||
fun StreamList(
|
||||
streams: LazyPagingItems<StreamInfoItem>,
|
||||
itemViewMode: ItemViewMode = determineItemViewMode(),
|
||||
gridHeader: LazyGridScope.() -> Unit = {},
|
||||
listHeader: LazyListScope.() -> Unit = {}
|
||||
) {
|
||||
val mode = determineItemViewMode()
|
||||
val context = LocalContext.current
|
||||
val onClick = remember {
|
||||
{ stream: StreamInfoItem ->
|
||||
@ -54,7 +54,7 @@ fun StreamList(
|
||||
}
|
||||
}
|
||||
|
||||
if (mode == ItemViewMode.GRID) {
|
||||
if (itemViewMode == ItemViewMode.GRID) {
|
||||
val gridState = rememberLazyGridState()
|
||||
|
||||
LazyVerticalGridScrollbar(state = gridState) {
|
||||
@ -82,7 +82,7 @@ fun StreamList(
|
||||
val stream = streams[it]!!
|
||||
val isSelected = selectedStream == stream
|
||||
|
||||
if (mode == ItemViewMode.CARD) {
|
||||
if (itemViewMode == ItemViewMode.CARD) {
|
||||
StreamCardItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
|
||||
} else {
|
||||
StreamListItem(stream, isSelected, onClick, onLongClick, onDismissPopup)
|
||||
|
@ -4,10 +4,11 @@ import androidx.paging.PagingSource
|
||||
import androidx.paging.PagingState
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.schabi.newpipe.compose.playlist.PlaylistInfo
|
||||
import org.schabi.newpipe.extractor.NewPipe
|
||||
import org.schabi.newpipe.extractor.Page
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo as ExtractorPlaylistInfo
|
||||
|
||||
class PlaylistItemsSource(
|
||||
private val playlistInfo: PlaylistInfo,
|
||||
@ -17,7 +18,8 @@ class PlaylistItemsSource(
|
||||
override suspend fun load(params: LoadParams<Page>): LoadResult<Page, StreamInfoItem> {
|
||||
return params.key?.let {
|
||||
withContext(Dispatchers.IO) {
|
||||
val response = PlaylistInfo.getMoreItems(service, playlistInfo.url, playlistInfo.nextPage)
|
||||
val response = ExtractorPlaylistInfo
|
||||
.getMoreItems(service, playlistInfo.url, playlistInfo.nextPage)
|
||||
LoadResult.Page(response.items, null, response.nextPage)
|
||||
}
|
||||
} ?: LoadResult.Page(playlistInfo.relatedItems, null, playlistInfo.nextPage)
|
||||
|
@ -11,7 +11,9 @@ import androidx.compose.ui.Modifier
|
||||
@Composable
|
||||
fun LoadingIndicator(modifier: Modifier = Modifier) {
|
||||
CircularProgressIndicator(
|
||||
modifier = modifier.fillMaxSize().wrapContentSize(Alignment.Center),
|
||||
modifier = modifier
|
||||
.fillMaxSize()
|
||||
.wrapContentSize(Alignment.Center),
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
trackColor = MaterialTheme.colorScheme.surfaceVariant,
|
||||
)
|
||||
|
@ -14,19 +14,27 @@ import kotlinx.coroutines.flow.filterNotNull
|
||||
import kotlinx.coroutines.flow.flatMapLatest
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import org.schabi.newpipe.compose.playlist.PlaylistInfo
|
||||
import org.schabi.newpipe.extractor.NewPipe
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo
|
||||
import org.schabi.newpipe.extractor.stream.Description
|
||||
import org.schabi.newpipe.paging.PlaylistItemsSource
|
||||
import org.schabi.newpipe.util.KEY_SERVICE_ID
|
||||
import org.schabi.newpipe.util.KEY_URL
|
||||
import org.schabi.newpipe.util.NO_SERVICE_ID
|
||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo as ExtractorPlaylistInfo
|
||||
|
||||
class PlaylistViewModel(savedStateHandle: SavedStateHandle) : ViewModel() {
|
||||
private val serviceIdState = savedStateHandle.getStateFlow(KEY_SERVICE_ID, NO_SERVICE_ID)
|
||||
private val urlState = savedStateHandle.getStateFlow(KEY_URL, "")
|
||||
|
||||
val playlistInfo = serviceIdState.combine(urlState) { id, url ->
|
||||
PlaylistInfo.getInfo(NewPipe.getService(id), url)
|
||||
val info = ExtractorPlaylistInfo.getInfo(NewPipe.getService(id), url)
|
||||
val description = info.description ?: Description.EMPTY_DESCRIPTION
|
||||
PlaylistInfo(
|
||||
info.id, info.serviceId, info.url, info.name, description, info.relatedItems,
|
||||
info.streamCount, info.uploaderUrl, info.uploaderName, info.uploaderAvatars,
|
||||
info.nextPage
|
||||
)
|
||||
}
|
||||
.flowOn(Dispatchers.IO)
|
||||
.stateIn(viewModelScope, SharingStarted.Eagerly, null)
|
||||
|
Loading…
Reference in New Issue
Block a user