mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Handle shuffling playlists
This commit is contained in:
parent
9148ca0719
commit
a93f183f5f
6 changed files with 65 additions and 4 deletions
|
|
@ -64,6 +64,7 @@ class PlaylistCreator
|
|||
suspend fun createFromPlaylistId(
|
||||
playlistId: UUID,
|
||||
startIndex: Int?,
|
||||
shuffled: Boolean,
|
||||
): Playlist {
|
||||
val request =
|
||||
GetPlaylistItemsRequest(
|
||||
|
|
@ -73,6 +74,10 @@ class PlaylistCreator
|
|||
limit = Playlist.MAX_SIZE,
|
||||
)
|
||||
val items = GetPlaylistItemsRequestHandler.execute(api, request).content.items
|
||||
return Playlist(items.map { BaseItem.from(it, api) }, 0)
|
||||
var baseItems = items.map { BaseItem.from(it, api) }
|
||||
if (shuffled) {
|
||||
baseItems = baseItems.shuffled()
|
||||
}
|
||||
return Playlist(baseItems, 0)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.drawWithContent
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
import androidx.compose.ui.focus.focusProperties
|
||||
import androidx.compose.ui.focus.focusRequester
|
||||
import androidx.compose.ui.focus.focusRestorer
|
||||
import androidx.compose.ui.focus.onFocusChanged
|
||||
|
|
@ -51,6 +52,7 @@ import androidx.tv.material3.MaterialTheme
|
|||
import androidx.tv.material3.Text
|
||||
import androidx.tv.material3.surfaceColorAtElevation
|
||||
import coil3.compose.AsyncImage
|
||||
import com.github.damontecres.dolphin.R
|
||||
import com.github.damontecres.dolphin.data.model.BaseItem
|
||||
import com.github.damontecres.dolphin.data.model.Library
|
||||
import com.github.damontecres.dolphin.ui.DefaultItemFields
|
||||
|
|
@ -59,6 +61,8 @@ 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.ExpandableFaButton
|
||||
import com.github.damontecres.dolphin.ui.components.ExpandablePlayButton
|
||||
import com.github.damontecres.dolphin.ui.components.LoadingPage
|
||||
import com.github.damontecres.dolphin.ui.components.OverviewText
|
||||
import com.github.damontecres.dolphin.ui.enableMarquee
|
||||
|
|
@ -81,6 +85,7 @@ import org.jellyfin.sdk.model.api.request.GetPlaylistItemsRequest
|
|||
import org.jellyfin.sdk.model.extensions.ticks
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.Duration
|
||||
|
||||
@HiltViewModel
|
||||
class PlaylistViewModel
|
||||
|
|
@ -148,6 +153,16 @@ fun PlaylistDetails(
|
|||
),
|
||||
)
|
||||
},
|
||||
onClickPlay = { shuffle ->
|
||||
viewModel.navigationManager.navigateTo(
|
||||
Destination.Playback(
|
||||
itemId = it.id,
|
||||
positionMs = 0L,
|
||||
startIndex = 0,
|
||||
shuffle = shuffle,
|
||||
),
|
||||
)
|
||||
},
|
||||
onLongClickIndex = { index, item ->
|
||||
longClickDialog =
|
||||
DialogParams(
|
||||
|
|
@ -200,6 +215,7 @@ fun PlaylistDetailsContent(
|
|||
items: List<BaseItem?>,
|
||||
onClickIndex: (Int, BaseItem) -> Unit,
|
||||
onLongClickIndex: (Int, BaseItem) -> Unit,
|
||||
onClickPlay: (shuffle: Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
focusRequester: FocusRequester = remember { FocusRequester() },
|
||||
) {
|
||||
|
|
@ -208,6 +224,8 @@ fun PlaylistDetailsContent(
|
|||
val focus = remember { FocusRequester() }
|
||||
val focusedItem = items.getOrNull(focusedIndex)
|
||||
|
||||
val playButtonFocusRequester = remember { FocusRequester() }
|
||||
|
||||
Box(
|
||||
modifier = modifier,
|
||||
) {
|
||||
|
|
@ -248,6 +266,7 @@ fun PlaylistDetailsContent(
|
|||
.fillMaxSize(),
|
||||
) {
|
||||
Row(
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(32.dp),
|
||||
modifier =
|
||||
Modifier
|
||||
|
|
@ -256,6 +275,8 @@ fun PlaylistDetailsContent(
|
|||
) {
|
||||
PlaylistDetailsHeader(
|
||||
focusedItem = focusedItem,
|
||||
onClickPlay = onClickPlay,
|
||||
playButtonFocusRequester = playButtonFocusRequester,
|
||||
modifier =
|
||||
Modifier
|
||||
.padding(start = 16.dp)
|
||||
|
|
@ -283,7 +304,9 @@ fun PlaylistDetailsContent(
|
|||
// .fillMaxWidth(.8f)
|
||||
.weight(1f)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp),
|
||||
MaterialTheme.colorScheme
|
||||
.surfaceColorAtElevation(1.dp)
|
||||
.copy(alpha = .75f),
|
||||
shape = RoundedCornerShape(16.dp),
|
||||
).focusRequester(focusRequester)
|
||||
.focusGroup()
|
||||
|
|
@ -315,6 +338,9 @@ fun PlaylistDetailsContent(
|
|||
if (it.isFocused) {
|
||||
focusedIndex = index
|
||||
}
|
||||
}.focusProperties {
|
||||
left = playButtonFocusRequester
|
||||
previous = playButtonFocusRequester
|
||||
},
|
||||
)
|
||||
}
|
||||
|
|
@ -328,12 +354,30 @@ fun PlaylistDetailsContent(
|
|||
@Composable
|
||||
fun PlaylistDetailsHeader(
|
||||
focusedItem: BaseItem?,
|
||||
onClickPlay: (shuffle: Boolean) -> Unit,
|
||||
playButtonFocusRequester: FocusRequester,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = modifier,
|
||||
) {
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
modifier = Modifier.focusRequester(playButtonFocusRequester),
|
||||
) {
|
||||
ExpandablePlayButton(
|
||||
title = R.string.play,
|
||||
resume = Duration.ZERO,
|
||||
icon = Icons.Default.PlayArrow,
|
||||
onClick = { onClickPlay.invoke(false) },
|
||||
)
|
||||
ExpandableFaButton(
|
||||
title = R.string.shuffle,
|
||||
iconStringRes = R.string.fa_shuffle,
|
||||
onClick = { onClickPlay.invoke(true) },
|
||||
)
|
||||
}
|
||||
Text(
|
||||
text = focusedItem?.title ?: "",
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ sealed class Destination(
|
|||
val positionMs: Long,
|
||||
@Transient val item: BaseItem? = null,
|
||||
val startIndex: Int? = null,
|
||||
val shuffle: Boolean = false,
|
||||
) : Destination(true) {
|
||||
override fun toString(): String = "Playback(itemId=$itemId, positionMs=$positionMs)"
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
package com.github.damontecres.dolphin.ui.playback
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.OptIn
|
||||
import androidx.core.net.toUri
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
|
|
@ -144,6 +145,7 @@ class PlaybackViewModel
|
|||
playlistCreator.createFromPlaylistId(
|
||||
queriedItem.id,
|
||||
destination.startIndex,
|
||||
destination.shuffle,
|
||||
)
|
||||
withContext(Dispatchers.Main) {
|
||||
this@PlaybackViewModel.playlist.value = playlist
|
||||
|
|
@ -154,7 +156,10 @@ class PlaybackViewModel
|
|||
queriedItem
|
||||
}
|
||||
|
||||
play(base, destination.positionMs)
|
||||
val played = play(base, destination.positionMs)
|
||||
if (!played) {
|
||||
playUpNextUp()
|
||||
}
|
||||
|
||||
if (!isPlaylist && queriedItem.type == BaseItemKind.EPISODE) {
|
||||
val playlist =
|
||||
|
|
@ -174,7 +179,11 @@ class PlaybackViewModel
|
|||
withContext(Dispatchers.IO) {
|
||||
Timber.i("Playing ${base.id}")
|
||||
if (base.type !in supportItemKinds) {
|
||||
showToast(context, "Unsupported type '${base.type}', skipping...")
|
||||
showToast(
|
||||
context,
|
||||
"Unsupported type '${base.type}', skipping...",
|
||||
Toast.LENGTH_SHORT,
|
||||
)
|
||||
return@withContext false
|
||||
}
|
||||
dto = base
|
||||
|
|
|
|||
|
|
@ -31,4 +31,5 @@
|
|||
<string name="fa_eye" translatable="false"></string>
|
||||
<string name="fa_eye_slash" translatable="false"></string>
|
||||
<string name="fa_arrow_left_arrow_right" translatable="false"></string>
|
||||
<string name="fa_shuffle" translatable="false"></string>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -75,5 +75,6 @@
|
|||
<string name="updates">Updates</string>
|
||||
<string name="no_update_available">No update available</string>
|
||||
<string name="clear_image_cache">Clear image cache</string>
|
||||
<string name="shuffle">Shuffle</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue