mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Playlist UI updates & more handling of unsupported playback
This commit is contained in:
parent
aab7e2eb17
commit
9148ca0719
3 changed files with 337 additions and 201 deletions
|
|
@ -236,6 +236,24 @@ fun DialogPopup(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun DialogPopup(
|
||||||
|
params: DialogParams,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
dismissOnClick: Boolean = true,
|
||||||
|
properties: DialogProperties = DialogProperties(),
|
||||||
|
elevation: Dp = 3.dp,
|
||||||
|
) = DialogPopup(
|
||||||
|
showDialog = true,
|
||||||
|
waitToLoad = params.fromLongClick,
|
||||||
|
title = params.title,
|
||||||
|
dialogItems = params.items,
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
dismissOnClick = dismissOnClick,
|
||||||
|
properties = properties,
|
||||||
|
elevation = elevation,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dialog that can be scrolled, typically for longer text content
|
* A dialog that can be scrolled, typically for longer text content
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package com.github.damontecres.dolphin.ui.detail
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.focusGroup
|
import androidx.compose.foundation.focusGroup
|
||||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.interaction.collectIsFocusedAsState
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
|
@ -17,11 +18,15 @@ import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.itemsIndexed
|
import androidx.compose.foundation.lazy.itemsIndexed
|
||||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.livedata.observeAsState
|
import androidx.compose.runtime.livedata.observeAsState
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
|
@ -36,6 +41,7 @@ import androidx.compose.ui.focus.onFocusChanged
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
|
|
@ -49,9 +55,13 @@ import com.github.damontecres.dolphin.data.model.BaseItem
|
||||||
import com.github.damontecres.dolphin.data.model.Library
|
import com.github.damontecres.dolphin.data.model.Library
|
||||||
import com.github.damontecres.dolphin.ui.DefaultItemFields
|
import com.github.damontecres.dolphin.ui.DefaultItemFields
|
||||||
import com.github.damontecres.dolphin.ui.cards.ItemCardImage
|
import com.github.damontecres.dolphin.ui.cards.ItemCardImage
|
||||||
|
import com.github.damontecres.dolphin.ui.components.DialogItem
|
||||||
|
import com.github.damontecres.dolphin.ui.components.DialogParams
|
||||||
|
import com.github.damontecres.dolphin.ui.components.DialogPopup
|
||||||
import com.github.damontecres.dolphin.ui.components.ErrorMessage
|
import com.github.damontecres.dolphin.ui.components.ErrorMessage
|
||||||
import com.github.damontecres.dolphin.ui.components.LoadingPage
|
import com.github.damontecres.dolphin.ui.components.LoadingPage
|
||||||
import com.github.damontecres.dolphin.ui.components.OverviewText
|
import com.github.damontecres.dolphin.ui.components.OverviewText
|
||||||
|
import com.github.damontecres.dolphin.ui.enableMarquee
|
||||||
import com.github.damontecres.dolphin.ui.ifElse
|
import com.github.damontecres.dolphin.ui.ifElse
|
||||||
import com.github.damontecres.dolphin.ui.isNotNullOrBlank
|
import com.github.damontecres.dolphin.ui.isNotNullOrBlank
|
||||||
import com.github.damontecres.dolphin.ui.nav.Destination
|
import com.github.damontecres.dolphin.ui.nav.Destination
|
||||||
|
|
@ -116,6 +126,8 @@ fun PlaylistDetails(
|
||||||
val playlist by viewModel.item.observeAsState(null)
|
val playlist by viewModel.item.observeAsState(null)
|
||||||
val items by viewModel.items.observeAsState(listOf())
|
val items by viewModel.items.observeAsState(listOf())
|
||||||
|
|
||||||
|
var longClickDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||||
|
|
||||||
when (val st = loading) {
|
when (val st = loading) {
|
||||||
is LoadingState.Error -> ErrorMessage(st, modifier)
|
is LoadingState.Error -> ErrorMessage(st, modifier)
|
||||||
LoadingState.Pending, LoadingState.Loading -> LoadingPage(modifier)
|
LoadingState.Pending, LoadingState.Loading -> LoadingPage(modifier)
|
||||||
|
|
@ -126,7 +138,8 @@ fun PlaylistDetails(
|
||||||
PlaylistDetailsContent(
|
PlaylistDetailsContent(
|
||||||
playlist = it,
|
playlist = it,
|
||||||
items = items,
|
items = items,
|
||||||
onClickIndex = { index ->
|
focusRequester = focusRequester,
|
||||||
|
onClickIndex = { index, _ ->
|
||||||
viewModel.navigationManager.navigateTo(
|
viewModel.navigationManager.navigateTo(
|
||||||
Destination.Playback(
|
Destination.Playback(
|
||||||
itemId = it.id,
|
itemId = it.id,
|
||||||
|
|
@ -135,23 +148,64 @@ fun PlaylistDetails(
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = modifier.focusRequester(focusRequester),
|
onLongClickIndex = { index, item ->
|
||||||
|
longClickDialog =
|
||||||
|
DialogParams(
|
||||||
|
fromLongClick = true,
|
||||||
|
title = item.name ?: "",
|
||||||
|
items =
|
||||||
|
listOf(
|
||||||
|
DialogItem(
|
||||||
|
"Go to",
|
||||||
|
Icons.Default.ArrowForward,
|
||||||
|
) {
|
||||||
|
viewModel.navigationManager.navigateTo(
|
||||||
|
Destination.MediaItem(
|
||||||
|
itemId = item.id,
|
||||||
|
type = item.type,
|
||||||
|
item = item,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
DialogItem(
|
||||||
|
"Play from here",
|
||||||
|
Icons.Default.PlayArrow,
|
||||||
|
) {
|
||||||
|
viewModel.navigationManager.navigateTo(
|
||||||
|
Destination.Playback(
|
||||||
|
itemId = it.id,
|
||||||
|
positionMs = 0L,
|
||||||
|
startIndex = index,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
longClickDialog?.let { params ->
|
||||||
|
DialogPopup(
|
||||||
|
params = params,
|
||||||
|
onDismissRequest = { longClickDialog = null },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun PlaylistDetailsContent(
|
fun PlaylistDetailsContent(
|
||||||
playlist: BaseItem,
|
playlist: BaseItem,
|
||||||
items: List<BaseItem?>,
|
items: List<BaseItem?>,
|
||||||
onClickIndex: (Int) -> Unit,
|
onClickIndex: (Int, BaseItem) -> Unit,
|
||||||
|
onLongClickIndex: (Int, BaseItem) -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
|
focusRequester: FocusRequester = remember { FocusRequester() },
|
||||||
) {
|
) {
|
||||||
var savedIndex by rememberSaveable { mutableIntStateOf(0) }
|
var savedIndex by rememberSaveable { mutableIntStateOf(0) }
|
||||||
var focusedIndex by remember { mutableIntStateOf(savedIndex) }
|
var focusedIndex by remember { mutableIntStateOf(savedIndex) }
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focus = remember { FocusRequester() }
|
||||||
|
|
||||||
val focusedItem = items.getOrNull(focusedIndex)
|
val focusedItem = items.getOrNull(focusedIndex)
|
||||||
|
|
||||||
Box(
|
Box(
|
||||||
|
|
@ -190,52 +244,142 @@ fun PlaylistDetailsContent(
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(start = 16.dp, top = 16.dp)
|
.padding(top = 16.dp)
|
||||||
.fillMaxSize(),
|
.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
Text(
|
Row(
|
||||||
text = playlist.name ?: "Playlist",
|
horizontalArrangement = Arrangement.spacedBy(32.dp),
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
modifier =
|
||||||
style = MaterialTheme.typography.displayMedium,
|
Modifier
|
||||||
)
|
.padding(horizontal = 16.dp)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
) {
|
||||||
PlaylistDetailsHeader(
|
PlaylistDetailsHeader(
|
||||||
focusedItem = focusedItem,
|
focusedItem = focusedItem,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(start = 16.dp)
|
.padding(start = 16.dp)
|
||||||
.fillMaxWidth(.66f),
|
.fillMaxWidth(.25f),
|
||||||
|
)
|
||||||
|
Column(
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 16.dp),
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = playlist.name ?: "Playlist",
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.displayMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
LazyColumn(
|
LazyColumn(
|
||||||
contentPadding = PaddingValues(8.dp),
|
contentPadding = PaddingValues(8.dp),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth(.8f)
|
.padding(bottom = 32.dp)
|
||||||
.align(Alignment.CenterHorizontally)
|
.fillMaxHeight()
|
||||||
|
// .fillMaxWidth(.8f)
|
||||||
|
.weight(1f)
|
||||||
.background(
|
.background(
|
||||||
MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
|
MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
|
||||||
shape = RoundedCornerShape(16.dp),
|
shape = RoundedCornerShape(16.dp),
|
||||||
).focusGroup()
|
).focusRequester(focusRequester)
|
||||||
.focusRestorer(focusRequester),
|
.focusGroup()
|
||||||
|
.focusRestorer(focus),
|
||||||
) {
|
) {
|
||||||
itemsIndexed(items) { index, item ->
|
itemsIndexed(items) { index, item ->
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
PlaylistItem(
|
||||||
ListItem(
|
item = item,
|
||||||
selected = false,
|
index = index,
|
||||||
onClick = {
|
onClick = {
|
||||||
savedIndex = index
|
savedIndex = index
|
||||||
onClickIndex.invoke(index)
|
item?.let {
|
||||||
|
onClickIndex.invoke(index, item)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
onLongClick = {
|
||||||
|
savedIndex = index
|
||||||
|
item?.let {
|
||||||
|
onLongClickIndex.invoke(index, item)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.height(80.dp)
|
||||||
|
.ifElse(
|
||||||
|
index == savedIndex,
|
||||||
|
Modifier.focusRequester(focus),
|
||||||
|
).onFocusChanged {
|
||||||
|
if (it.isFocused) {
|
||||||
|
focusedIndex = index
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PlaylistDetailsHeader(
|
||||||
|
focusedItem: BaseItem?,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
modifier = modifier,
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = focusedItem?.title ?: "",
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.headlineLarge,
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = focusedItem?.subtitle ?: "",
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
|
)
|
||||||
|
OverviewText(
|
||||||
|
overview = focusedItem?.data?.overview ?: "",
|
||||||
|
maxLines = 10,
|
||||||
|
onClick = {},
|
||||||
|
enabled = false,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun PlaylistItem(
|
||||||
|
item: BaseItem?,
|
||||||
|
index: Int,
|
||||||
|
onClick: () -> Unit,
|
||||||
|
onLongClick: () -> Unit,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
) {
|
||||||
|
val focused by interactionSource.collectIsFocusedAsState()
|
||||||
|
ListItem(
|
||||||
|
selected = false,
|
||||||
|
onClick = onClick,
|
||||||
|
onLongClick = onLongClick,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
text = item?.title ?: "",
|
text = item?.title ?: "",
|
||||||
style = MaterialTheme.typography.titleLarge,
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
modifier = Modifier.enableMarquee(focused),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
supportingContent = {
|
supportingContent = {
|
||||||
Text(
|
Text(
|
||||||
text = item?.subtitle ?: "",
|
text = item?.subtitle ?: "",
|
||||||
style = MaterialTheme.typography.titleSmall,
|
style = MaterialTheme.typography.titleSmall,
|
||||||
|
modifier = Modifier.enableMarquee(focused),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
trailingContent = {
|
trailingContent = {
|
||||||
|
|
@ -267,48 +411,6 @@ fun PlaylistDetailsContent(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.height(80.dp)
|
|
||||||
.ifElse(
|
|
||||||
index == savedIndex,
|
|
||||||
Modifier.focusRequester(focusRequester),
|
|
||||||
).onFocusChanged {
|
|
||||||
if (it.isFocused) {
|
|
||||||
focusedIndex = index
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun PlaylistDetailsHeader(
|
|
||||||
focusedItem: BaseItem?,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
) {
|
|
||||||
Column(
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = focusedItem?.title ?: "",
|
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
|
||||||
style = MaterialTheme.typography.headlineLarge,
|
|
||||||
)
|
)
|
||||||
Text(
|
|
||||||
text = focusedItem?.subtitle ?: "",
|
|
||||||
color = MaterialTheme.colorScheme.onSurface,
|
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
|
||||||
)
|
|
||||||
OverviewText(
|
|
||||||
overview = focusedItem?.data?.overview ?: "",
|
|
||||||
maxLines = 2,
|
|
||||||
onClick = {},
|
|
||||||
enabled = false,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import com.github.damontecres.dolphin.preferences.SkipSegmentBehavior
|
||||||
import com.github.damontecres.dolphin.preferences.UserPreferences
|
import com.github.damontecres.dolphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.dolphin.ui.nav.Destination
|
import com.github.damontecres.dolphin.ui.nav.Destination
|
||||||
import com.github.damontecres.dolphin.ui.nav.NavigationManager
|
import com.github.damontecres.dolphin.ui.nav.NavigationManager
|
||||||
|
import com.github.damontecres.dolphin.ui.showToast
|
||||||
import com.github.damontecres.dolphin.util.EqualityMutableLiveData
|
import com.github.damontecres.dolphin.util.EqualityMutableLiveData
|
||||||
import com.github.damontecres.dolphin.util.ExceptionHandler
|
import com.github.damontecres.dolphin.util.ExceptionHandler
|
||||||
import com.github.damontecres.dolphin.util.TrackActivityPlaybackListener
|
import com.github.damontecres.dolphin.util.TrackActivityPlaybackListener
|
||||||
|
|
@ -31,6 +32,7 @@ import com.github.damontecres.dolphin.util.checkForSupport
|
||||||
import com.github.damontecres.dolphin.util.formatDateTime
|
import com.github.damontecres.dolphin.util.formatDateTime
|
||||||
import com.github.damontecres.dolphin.util.seasonEpisodePadded
|
import com.github.damontecres.dolphin.util.seasonEpisodePadded
|
||||||
import com.github.damontecres.dolphin.util.subtitleMimeTypes
|
import com.github.damontecres.dolphin.util.subtitleMimeTypes
|
||||||
|
import com.github.damontecres.dolphin.util.supportItemKinds
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
@ -81,7 +83,7 @@ data class StreamDecision(
|
||||||
class PlaybackViewModel
|
class PlaybackViewModel
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
@ApplicationContext context: Context,
|
@param:ApplicationContext val context: Context,
|
||||||
val api: ApiClient,
|
val api: ApiClient,
|
||||||
val playlistCreator: PlaylistCreator,
|
val playlistCreator: PlaylistCreator,
|
||||||
val navigationManager: NavigationManager,
|
val navigationManager: NavigationManager,
|
||||||
|
|
@ -168,8 +170,13 @@ class PlaybackViewModel
|
||||||
private suspend fun play(
|
private suspend fun play(
|
||||||
base: BaseItemDto,
|
base: BaseItemDto,
|
||||||
positionMs: Long,
|
positionMs: Long,
|
||||||
) = withContext(Dispatchers.IO) {
|
): Boolean =
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
Timber.i("Playing ${base.id}")
|
Timber.i("Playing ${base.id}")
|
||||||
|
if (base.type !in supportItemKinds) {
|
||||||
|
showToast(context, "Unsupported type '${base.type}', skipping...")
|
||||||
|
return@withContext false
|
||||||
|
}
|
||||||
dto = base
|
dto = base
|
||||||
val title =
|
val title =
|
||||||
if (base.type == BaseItemKind.EPISODE) {
|
if (base.type == BaseItemKind.EPISODE) {
|
||||||
|
|
@ -294,6 +301,7 @@ class PlaybackViewModel
|
||||||
Timber.v("chapters=${this@PlaybackViewModel.chapters.value?.size}")
|
Timber.v("chapters=${this@PlaybackViewModel.chapters.value?.size}")
|
||||||
}
|
}
|
||||||
listenForSegments()
|
listenForSegments()
|
||||||
|
return@withContext true
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
|
|
@ -582,7 +590,11 @@ class PlaybackViewModel
|
||||||
if (it.hasNext()) {
|
if (it.hasNext()) {
|
||||||
viewModelScope.launch(ExceptionHandler()) {
|
viewModelScope.launch(ExceptionHandler()) {
|
||||||
cancelUpNextEpisode()
|
cancelUpNextEpisode()
|
||||||
play(it.getAndAdvance().data, 0)
|
val item = it.getAndAdvance()
|
||||||
|
val played = play(item.data, 0)
|
||||||
|
if (!played) {
|
||||||
|
playUpNextUp()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -593,7 +605,11 @@ class PlaybackViewModel
|
||||||
if (it.hasPrevious()) {
|
if (it.hasPrevious()) {
|
||||||
viewModelScope.launch(ExceptionHandler()) {
|
viewModelScope.launch(ExceptionHandler()) {
|
||||||
cancelUpNextEpisode()
|
cancelUpNextEpisode()
|
||||||
play(it.getPreviousAndReverse().data, 0)
|
val item = it.getPreviousAndReverse()
|
||||||
|
val played = play(item.data, 0)
|
||||||
|
if (!played) {
|
||||||
|
playPrevious()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -602,6 +618,9 @@ class PlaybackViewModel
|
||||||
fun cancelUpNextEpisode() {
|
fun cancelUpNextEpisode() {
|
||||||
nextUp.value = null
|
nextUp.value = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun toastUnsupported(item: BaseItemDto) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class CurrentPlayback(
|
data class CurrentPlayback(
|
||||||
|
|
@ -687,6 +706,3 @@ private fun applyTrackSelections(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val singlePlays =
|
|
||||||
setOf(BaseItemKind.EPISODE, BaseItemKind.MOVIE, BaseItemKind.VIDEO, BaseItemKind.MUSIC_VIDEO)
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue