11package org.schabi.newpipe.ui.components.video
22
3+ import android.content.Context
34import android.content.res.Configuration
45import androidx.compose.foundation.layout.Arrangement
56import androidx.compose.foundation.layout.Row
@@ -21,80 +22,100 @@ import androidx.compose.ui.res.stringResource
2122import androidx.compose.ui.tooling.preview.Preview
2223import androidx.compose.ui.unit.dp
2324import androidx.core.content.edit
25+ import androidx.paging.PagingData
26+ import androidx.paging.compose.collectAsLazyPagingItems
2427import androidx.preference.PreferenceManager
28+ import kotlinx.coroutines.flow.flowOf
2529import org.schabi.newpipe.R
2630import org.schabi.newpipe.extractor.Image
2731import org.schabi.newpipe.extractor.playlist.PlaylistInfoItem
32+ import org.schabi.newpipe.extractor.stream.StreamInfo
2833import org.schabi.newpipe.extractor.stream.StreamInfoItem
2934import org.schabi.newpipe.extractor.stream.StreamType
3035import org.schabi.newpipe.info_list.ItemViewMode
3136import org.schabi.newpipe.ui.components.items.ItemList
3237import org.schabi.newpipe.ui.components.items.Playlist
3338import org.schabi.newpipe.ui.components.items.Stream
34- import org.schabi.newpipe.ui.emptystate.EmptyStateComposable
35- import org.schabi.newpipe.ui.emptystate.EmptyStateSpec
39+ import org.schabi.newpipe.ui.components.items.Unknown
3640import org.schabi.newpipe.ui.theme.AppTheme
41+ import org.schabi.newpipe.util.Localization
3742import org.schabi.newpipe.util.NO_SERVICE_ID
3843import java.util.concurrent.TimeUnit
39- import org.schabi.newpipe.extractor.stream.StreamInfo as ExtractorStreamInfo
4044
4145@Composable
42- fun RelatedItems (info : ExtractorStreamInfo ) {
43- val sharedPreferences = PreferenceManager .getDefaultSharedPreferences(LocalContext .current)
46+ fun RelatedItems (info : StreamInfo ) {
47+ val context = LocalContext .current
48+ val sharedPreferences = PreferenceManager .getDefaultSharedPreferences(context)
4449 val key = stringResource(R .string.auto_queue_key)
4550 // TODO: AndroidX DataStore might be a better option.
4651 var isAutoQueueEnabled by rememberSaveable {
4752 mutableStateOf(sharedPreferences.getBoolean(key, false ))
4853 }
54+ val displayItems = info.relatedItems.map {
55+ if (it is StreamInfoItem ) {
56+ Stream (it, getStreamDetailText(context, it))
57+ } else if (it is PlaylistInfoItem ) {
58+ Playlist (it)
59+ } else {
60+ Unknown
61+ }
62+ }
4963
5064 ItemList (
51- items = info.relatedItems.map {
52- if (it is StreamInfoItem ) {
53- Stream (it)
54- } else if (it is PlaylistInfoItem ) {
55- Playlist (it)
56- } else {
57- throw IllegalArgumentException ()
58- }
59- },
65+ items = flowOf(PagingData .from(displayItems)).collectAsLazyPagingItems(),
6066 mode = ItemViewMode .LIST ,
61- listHeader = {
62- item {
67+ header = {
68+ Row (
69+ modifier = Modifier
70+ .fillMaxWidth()
71+ .padding(start = 12 .dp, end = 12 .dp),
72+ horizontalArrangement = Arrangement .SpaceBetween ,
73+ verticalAlignment = Alignment .CenterVertically ,
74+ ) {
75+ Text (text = stringResource(R .string.auto_queue_description))
76+
6377 Row (
64- modifier = Modifier
65- .fillMaxWidth()
66- .padding(start = 12 .dp, end = 12 .dp),
67- horizontalArrangement = Arrangement .SpaceBetween ,
68- verticalAlignment = Alignment .CenterVertically ,
78+ horizontalArrangement = Arrangement .spacedBy(4 .dp),
79+ verticalAlignment = Alignment .CenterVertically
6980 ) {
70- Text (text = stringResource(R .string.auto_queue_description))
71-
72- Row (
73- horizontalArrangement = Arrangement .spacedBy(4 .dp),
74- verticalAlignment = Alignment .CenterVertically
75- ) {
76- Text (text = stringResource(R .string.auto_queue_toggle))
77- Switch (
78- checked = isAutoQueueEnabled,
79- onCheckedChange = {
80- isAutoQueueEnabled = it
81- sharedPreferences.edit {
82- putBoolean(key, it)
83- }
81+ Text (text = stringResource(R .string.auto_queue_toggle))
82+ Switch (
83+ checked = isAutoQueueEnabled,
84+ onCheckedChange = {
85+ isAutoQueueEnabled = it
86+ sharedPreferences.edit {
87+ putBoolean(key, it)
8488 }
85- )
86- }
87- }
88- }
89- if (info.relatedItems.isEmpty()) {
90- item {
91- EmptyStateComposable (EmptyStateSpec .NoVideos )
89+ }
90+ )
9291 }
9392 }
9493 }
9594 )
9695}
9796
97+ private fun getStreamDetailText (context : Context , stream : StreamInfoItem ): String {
98+ val count = stream.viewCount
99+ val views = if (count >= 0 ) {
100+ when (stream.streamType) {
101+ StreamType .AUDIO_LIVE_STREAM -> Localization .listeningCount(context, count)
102+ StreamType .LIVE_STREAM -> Localization .shortWatchingCount(context, count)
103+ else -> Localization .shortViewCount(context, count)
104+ }
105+ } else {
106+ " "
107+ }
108+ val date = Localization .relativeTimeOrTextual(context, stream.uploadDate, stream.textualUploadDate)
109+
110+ return if (views.isEmpty()) {
111+ date.orEmpty()
112+ } else if (date.isNullOrEmpty()) {
113+ views
114+ } else {
115+ " $views • $date "
116+ }
117+ }
118+
98119private fun StreamInfoItem (
99120 serviceId : Int = NO_SERVICE_ID ,
100121 url : String = "",
@@ -119,7 +140,7 @@ private fun StreamInfoItem(
119140@Preview(name = " Dark mode" , uiMode = Configuration .UI_MODE_NIGHT_YES )
120141@Composable
121142private fun RelatedItemsPreview () {
122- val info = ExtractorStreamInfo (NO_SERVICE_ID , " " , " " , StreamType .VIDEO_STREAM , " " , " " , 0 )
143+ val info = StreamInfo (NO_SERVICE_ID , " " , " " , StreamType .VIDEO_STREAM , " " , " " , 0 )
123144 info.relatedItems = listOf (
124145 StreamInfoItem (streamType = StreamType .NONE ),
125146 StreamInfoItem (streamType = StreamType .LIVE_STREAM ),
0 commit comments