add chapter select preview
This commit is contained in:
parent
cb122306c6
commit
22d7bcf552
|
@ -24,7 +24,7 @@ import android.net.Uri
|
|||
import androidx.media3.common.PlaybackException
|
||||
import net.newpipe.newplayer.utils.Thumbnail
|
||||
|
||||
data class Chapter(val chapterStartInMs: Long, val chapterTitle: String?)
|
||||
data class Chapter(val chapterStartInMs: Long, val chapterTitle: String?, val thumbnail: Thumbnail?)
|
||||
|
||||
data class MetaInfo(
|
||||
val title: String,
|
||||
|
@ -46,7 +46,6 @@ interface MediaRepository {
|
|||
|
||||
suspend fun getPreviewThumbnails(item: String): HashMap<Long, Thumbnail>?
|
||||
suspend fun getChapters(item: String): List<Chapter>
|
||||
suspend fun getChapterThumbnail(item: String, chapter: Long): Thumbnail?
|
||||
|
||||
suspend fun getTimestampLink(item: String, timestampInSeconds: Long): String
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.os.Bundle
|
|||
import androidx.media3.common.Player
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import net.newpipe.newplayer.Chapter
|
||||
import net.newpipe.newplayer.NewPlayer
|
||||
import net.newpipe.newplayer.ui.ContentScale
|
||||
import net.newpipe.newplayer.utils.Thumbnail
|
||||
|
@ -58,4 +59,6 @@ interface VideoPlayerViewModel {
|
|||
fun volumeChange(changeRate: Float)
|
||||
fun openStreamSelection(selectChapter: Boolean, embeddedUiConfig: EmbeddedUiConfig)
|
||||
fun closeStreamSelection()
|
||||
fun chapterSelected(chapter: Chapter)
|
||||
fun streamSelected(streamId: Int)
|
||||
}
|
|
@ -43,6 +43,7 @@ import javax.inject.Inject
|
|||
import kotlinx.coroutines.flow.asStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
import kotlinx.coroutines.launch
|
||||
import net.newpipe.newplayer.Chapter
|
||||
import net.newpipe.newplayer.utils.VideoSize
|
||||
import net.newpipe.newplayer.NewPlayer
|
||||
import net.newpipe.newplayer.playerInternals.getPlaylistItemsFromItemList
|
||||
|
@ -399,6 +400,14 @@ class VideoPlayerViewModelImpl @Inject constructor(
|
|||
updateUiMode(UIModeState.FULLSCREEN_VIDEO)
|
||||
}
|
||||
|
||||
override fun chapterSelected(chapter: Chapter) {
|
||||
println("gurken chapter selectd: $chapter")
|
||||
}
|
||||
|
||||
override fun streamSelected(streamId: Int) {
|
||||
println("stream selected: $streamId")
|
||||
}
|
||||
|
||||
private fun updateUiMode(newState: UIModeState) {
|
||||
val newPlayMode = newState.toPlayMode()
|
||||
val currentPlayMode = mutableUiState.value.uiMode.toPlayMode()
|
||||
|
|
|
@ -6,6 +6,7 @@ import kotlinx.coroutines.flow.MutableSharedFlow
|
|||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.SharedFlow
|
||||
import kotlinx.coroutines.flow.asSharedFlow
|
||||
import net.newpipe.newplayer.Chapter
|
||||
import net.newpipe.newplayer.NewPlayer
|
||||
import net.newpipe.newplayer.ui.ContentScale
|
||||
|
||||
|
@ -83,6 +84,14 @@ open class VideoPlayerViewModelDummy : VideoPlayerViewModel {
|
|||
println("dummy impl")
|
||||
}
|
||||
|
||||
override fun chapterSelected(chapter: Chapter) {
|
||||
println("dummp impl chapter selected: $chapter")
|
||||
}
|
||||
|
||||
override fun streamSelected(streamId: Int) {
|
||||
println("dummy impl stream selected: $streamId")
|
||||
}
|
||||
|
||||
override fun pause() {
|
||||
println("dummy pause")
|
||||
}
|
||||
|
|
|
@ -21,29 +21,32 @@
|
|||
package net.newpipe.newplayer.ui.videoplayer
|
||||
|
||||
import android.view.MotionEvent
|
||||
import android.view.Surface
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.aspectRatio
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||
import androidx.compose.foundation.layout.wrapContentSize
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.filled.Close
|
||||
import androidx.compose.material.icons.filled.DragHandle
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.Surface
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.ExperimentalComposeUiApi
|
||||
|
@ -65,6 +68,7 @@ import net.newpipe.newplayer.ui.theme.VideoPlayerTheme
|
|||
import net.newpipe.newplayer.utils.getLocale
|
||||
import net.newpipe.newplayer.utils.getTimeStringFromMs
|
||||
import coil.compose.AsyncImage
|
||||
import net.newpipe.newplayer.Chapter
|
||||
import net.newpipe.newplayer.utils.BitmapThumbnail
|
||||
import net.newpipe.newplayer.utils.OnlineThumbnail
|
||||
import net.newpipe.newplayer.utils.Thumbnail
|
||||
|
@ -79,12 +83,14 @@ fun StreamSelectUI(
|
|||
) {
|
||||
val insets = getInsets()
|
||||
Surface(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.windowInsetsPadding(insets),
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
color = CONTROLLER_UI_BACKGROUND_COLOR
|
||||
) {
|
||||
Scaffold(
|
||||
modifier = Modifier
|
||||
.fillMaxSize()
|
||||
.windowInsetsPadding(insets),
|
||||
containerColor = Color.Transparent,
|
||||
topBar = {
|
||||
if (isChapterSelect) {
|
||||
ChapterSelectTopBar(onClose = {
|
||||
|
@ -95,37 +101,50 @@ fun StreamSelectUI(
|
|||
}
|
||||
}
|
||||
) { innerPadding ->
|
||||
Surface(
|
||||
LazyColumn(
|
||||
modifier = Modifier
|
||||
.padding(innerPadding)
|
||||
.fillMaxSize(), color = Color.Red
|
||||
.fillMaxSize(),
|
||||
) {
|
||||
if (isChapterSelect) {
|
||||
items(uiState.chapters.size) { chapterIndex ->
|
||||
val chapter = uiState.chapters[chapterIndex]
|
||||
ChapterItem(
|
||||
id = chapterIndex,
|
||||
chapterTitle = chapter.chapterTitle ?: "",
|
||||
chapterStartInMs = chapter.chapterStartInMs,
|
||||
thumbnail = chapter.thumbnail,
|
||||
onClicked = {
|
||||
viewModel.chapterSelected(chapter)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
private fun ChapterSelectTopBar(modifier: Modifier = Modifier, onClose: () -> Unit) {
|
||||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.SpaceBetween
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(20.dp))
|
||||
//Text(stringResource(R.string.chapter))
|
||||
Text("Chapter TODO")
|
||||
Spacer(modifier = Modifier.weight(1F))
|
||||
IconButton(
|
||||
onClick = onClose
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Close,
|
||||
contentDescription = stringResource(R.string.close_chapter_selection)
|
||||
)
|
||||
}
|
||||
}
|
||||
TopAppBar(modifier = modifier,
|
||||
colors = topAppBarColors(containerColor = Color.Transparent),
|
||||
title = {
|
||||
Text("Chapter TODO")
|
||||
//Text(stringResource(R.string.chapter))
|
||||
}, actions = {
|
||||
IconButton(
|
||||
onClick = onClose
|
||||
) {
|
||||
Icon(
|
||||
imageVector = Icons.Filled.Close,
|
||||
contentDescription = stringResource(R.string.close_chapter_selection)
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -150,7 +169,7 @@ private fun ChapterItem(
|
|||
top = 4.dp,
|
||||
bottom = 4.dp,
|
||||
end = 4.dp
|
||||
)
|
||||
).height(80.dp)
|
||||
.clickable { onClicked(id) }
|
||||
) {
|
||||
val contentDescription = stringResource(R.string.chapter)
|
||||
|
@ -348,11 +367,29 @@ fun ChapterTopBarPreview() {
|
|||
@Composable
|
||||
fun VideoPlayerStreamSelectUIPreview() {
|
||||
VideoPlayerTheme {
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = Color.Green) {
|
||||
Surface(modifier = Modifier.fillMaxSize(), color = Color.Red) {
|
||||
StreamSelectUI(
|
||||
isChapterSelect = true,
|
||||
viewModel = VideoPlayerViewModelDummy(),
|
||||
uiState = VideoPlayerUIState.DEFAULT
|
||||
uiState = VideoPlayerUIState.DEFAULT.copy(
|
||||
chapters = arrayListOf(
|
||||
Chapter(
|
||||
chapterStartInMs = 5000,
|
||||
chapterTitle = "First Chapter",
|
||||
thumbnail = null
|
||||
),
|
||||
Chapter(
|
||||
chapterStartInMs = 10000,
|
||||
chapterTitle = "Second Chapter",
|
||||
thumbnail = null
|
||||
),
|
||||
Chapter(
|
||||
chapterStartInMs = 20000,
|
||||
chapterTitle = "Third Chapter",
|
||||
thumbnail = null
|
||||
),
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,12 +30,14 @@ class TestMediaRepository(val context: Context) : MediaRepository {
|
|||
thumbnail = OnlineThumbnail(context.getString(R.string.ccc_6502_thumbnail)),
|
||||
lengthInS = context.resources.getInteger(R.integer.ccc_6502_length)
|
||||
)
|
||||
|
||||
"imu" -> MetaInfo(
|
||||
title = context.getString(R.string.ccc_imu_title),
|
||||
channelName = context.getString(R.string.ccc_imu_channel),
|
||||
thumbnail = OnlineThumbnail(context.getString(R.string.ccc_imu_thumbnail)),
|
||||
lengthInS = context.resources.getInteger(R.integer.ccc_imu_length)
|
||||
)
|
||||
|
||||
"portrait" -> MetaInfo(
|
||||
title = context.getString(R.string.portrait_title),
|
||||
channelName = context.getString(R.string.portrait_channel),
|
||||
|
@ -113,29 +115,29 @@ class TestMediaRepository(val context: Context) : MediaRepository {
|
|||
override suspend fun getChapters(item: String) =
|
||||
when (item) {
|
||||
"6502" -> context.resources.getIntArray(R.array.ccc_6502_chapters)
|
||||
"imu" -> TODO()
|
||||
"imu" -> context.resources.getIntArray(R.array.ccc_imu_chapters)
|
||||
else -> intArrayOf()
|
||||
}.map {
|
||||
Chapter(it.toLong(), "Dummy Chapter at timestamp $it")
|
||||
}
|
||||
Chapter(
|
||||
it.toLong(), chapterTitle = "Dummy Chapter at timestamp $it",
|
||||
thumbnail = when (item) {
|
||||
"6502" -> OnlineThumbnail(
|
||||
String.format(
|
||||
context.getString(R.string.ccc_6502_preview_thumbnails),
|
||||
it / (10 * 1000)
|
||||
)
|
||||
)
|
||||
|
||||
override suspend fun getChapterThumbnail(item: String, chapter: Long) =
|
||||
when (item) {
|
||||
"6502" -> OnlineThumbnail(
|
||||
String.format(
|
||||
context.getString(R.string.ccc_6502_preview_thumbnails),
|
||||
chapter / (10 * 1000)
|
||||
)
|
||||
"imu" -> OnlineThumbnail(
|
||||
String.format(
|
||||
context.getString(R.string.ccc_imu_preview_thumbnails),
|
||||
it / (10 * 1000)
|
||||
)
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
)
|
||||
|
||||
"imu" -> OnlineThumbnail(
|
||||
String.format(
|
||||
context.getString(R.string.ccc_imu_preview_thumbnails),
|
||||
chapter / (10 * 1000)
|
||||
)
|
||||
)
|
||||
|
||||
else -> null
|
||||
}
|
||||
|
||||
override suspend fun getTimestampLink(item: String, timestampInSeconds: Long) =
|
||||
|
|
Loading…
Reference in New Issue