mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Updates to playlists, add more button on album/artist pages
This commit is contained in:
parent
8ddd4bd747
commit
5f5b07e861
6 changed files with 182 additions and 28 deletions
|
|
@ -186,7 +186,7 @@ class MusicService
|
||||||
updateQueueSize()
|
updateQueueSize()
|
||||||
if (player.mediaItemCount == 1) {
|
if (player.mediaItemCount == 1) {
|
||||||
// Start playing if this was the first time added
|
// Start playing if this was the first time added
|
||||||
player.play()
|
start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -295,7 +295,12 @@ class MusicService
|
||||||
|
|
||||||
suspend fun playNext(song: BaseItem) {
|
suspend fun playNext(song: BaseItem) {
|
||||||
val mediaItem = convert(song)
|
val mediaItem = convert(song)
|
||||||
onMain { player.addMediaItem(state.value.currentIndex + 1, mediaItem) }
|
onMain {
|
||||||
|
player.addMediaItem(state.value.currentIndex + 1, mediaItem)
|
||||||
|
if (player.mediaItemCount == 1) {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
updateQueueSize()
|
updateQueueSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.layout.wrapContentSize
|
||||||
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
|
||||||
|
|
@ -44,6 +45,7 @@ import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.lifecycle.MutableLiveData
|
import androidx.lifecycle.MutableLiveData
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
|
@ -67,6 +69,7 @@ import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.ui.DefaultItemFields
|
import com.github.damontecres.wholphin.ui.DefaultItemFields
|
||||||
import com.github.damontecres.wholphin.ui.TimeFormatter
|
import com.github.damontecres.wholphin.ui.TimeFormatter
|
||||||
import com.github.damontecres.wholphin.ui.cards.ItemCardImage
|
import com.github.damontecres.wholphin.ui.cards.ItemCardImage
|
||||||
|
import com.github.damontecres.wholphin.ui.components.BasicDialog
|
||||||
import com.github.damontecres.wholphin.ui.components.DialogItem
|
import com.github.damontecres.wholphin.ui.components.DialogItem
|
||||||
import com.github.damontecres.wholphin.ui.components.DialogParams
|
import com.github.damontecres.wholphin.ui.components.DialogParams
|
||||||
import com.github.damontecres.wholphin.ui.components.DialogPopup
|
import com.github.damontecres.wholphin.ui.components.DialogPopup
|
||||||
|
|
@ -77,9 +80,12 @@ import com.github.damontecres.wholphin.ui.components.FilterByButton
|
||||||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||||
import com.github.damontecres.wholphin.ui.components.OverviewText
|
import com.github.damontecres.wholphin.ui.components.OverviewText
|
||||||
import com.github.damontecres.wholphin.ui.components.SortByButton
|
import com.github.damontecres.wholphin.ui.components.SortByButton
|
||||||
|
import com.github.damontecres.wholphin.ui.components.TextButton
|
||||||
import com.github.damontecres.wholphin.ui.data.BoxSetSortOptions
|
import com.github.damontecres.wholphin.ui.data.BoxSetSortOptions
|
||||||
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
import com.github.damontecres.wholphin.ui.data.SortAndDirection
|
||||||
|
import com.github.damontecres.wholphin.ui.detail.music.MusicQueueMarker
|
||||||
import com.github.damontecres.wholphin.ui.enableMarquee
|
import com.github.damontecres.wholphin.ui.enableMarquee
|
||||||
|
import com.github.damontecres.wholphin.ui.equalsNotNull
|
||||||
import com.github.damontecres.wholphin.ui.formatDateTime
|
import com.github.damontecres.wholphin.ui.formatDateTime
|
||||||
import com.github.damontecres.wholphin.ui.ifElse
|
import com.github.damontecres.wholphin.ui.ifElse
|
||||||
import com.github.damontecres.wholphin.ui.launchDefault
|
import com.github.damontecres.wholphin.ui.launchDefault
|
||||||
|
|
@ -224,17 +230,24 @@ class PlaylistViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method tries to determine the [MediaType] of a playlist
|
||||||
|
*
|
||||||
|
* In theory, the server will set the type, but sometime it doesn't
|
||||||
|
*/
|
||||||
private suspend fun determineMediaType() {
|
private suspend fun determineMediaType() {
|
||||||
|
// Use the type the server says
|
||||||
var mediaType =
|
var mediaType =
|
||||||
super.item.value
|
super.item.value
|
||||||
?.data
|
?.data
|
||||||
?.mediaType ?: MediaType.UNKNOWN
|
?.mediaType ?: MediaType.UNKNOWN
|
||||||
mediaType =
|
mediaType =
|
||||||
if (mediaType == MediaType.UNKNOWN) {
|
if (mediaType == MediaType.UNKNOWN) {
|
||||||
|
// Otherwise, if a most of the list is one type, we can assume that type
|
||||||
val pager = (this@PlaylistViewModel.items.value as? ApiRequestPager<*>)
|
val pager = (this@PlaylistViewModel.items.value as? ApiRequestPager<*>)
|
||||||
if (pager != null && pager.size < 50) {
|
if (pager != null && pager.size <= 50) {
|
||||||
val types =
|
val types =
|
||||||
(0..<50).groupBy { index ->
|
(0..<50.coerceAtMost(pager.size)).groupBy { index ->
|
||||||
val pagerItem = pager.getBlocking(index)
|
val pagerItem = pager.getBlocking(index)
|
||||||
when (pagerItem?.type) {
|
when (pagerItem?.type) {
|
||||||
BaseItemKind.AUDIO -> MediaType.AUDIO
|
BaseItemKind.AUDIO -> MediaType.AUDIO
|
||||||
|
|
@ -259,6 +272,7 @@ class PlaylistViewModel
|
||||||
} else {
|
} else {
|
||||||
mediaType
|
mediaType
|
||||||
}
|
}
|
||||||
|
Timber.d("mediaType=%s", mediaType)
|
||||||
playlistMediaType.update { mediaType }
|
playlistMediaType.update { mediaType }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -312,7 +326,7 @@ fun PlaylistDetails(
|
||||||
val playlistMediaType by viewModel.playlistMediaType.collectAsState()
|
val playlistMediaType by viewModel.playlistMediaType.collectAsState()
|
||||||
|
|
||||||
var longClickDialog by remember { mutableStateOf<DialogParams?>(null) }
|
var longClickDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||||
var showConfirmTypeDialog by remember { mutableStateOf(false) }
|
var showConfirmTypeDialog by remember { mutableStateOf<Pair<Int, Boolean>?>(null) }
|
||||||
|
|
||||||
val goToString = stringResource(R.string.go_to)
|
val goToString = stringResource(R.string.go_to)
|
||||||
val playFromHereString = stringResource(R.string.play_from_here)
|
val playFromHereString = stringResource(R.string.play_from_here)
|
||||||
|
|
@ -340,7 +354,7 @@ fun PlaylistDetails(
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> {
|
else -> {
|
||||||
showConfirmTypeDialog = true
|
showConfirmTypeDialog = Pair(index, shuffle)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -390,6 +404,12 @@ fun PlaylistDetails(
|
||||||
onDismissRequest = { longClickDialog = null },
|
onDismissRequest = { longClickDialog = null },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
showConfirmTypeDialog?.let { (index, shuffle) ->
|
||||||
|
ConfirmMediaTypeDialog(
|
||||||
|
onConfirm = { mediaType -> play(index, shuffle, mediaType) },
|
||||||
|
onCancel = { showConfirmTypeDialog = null },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -513,10 +533,18 @@ fun PlaylistDetailsContent(
|
||||||
onLongClickIndex.invoke(index, item)
|
onLongClickIndex.invoke(index, item)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
isPlaying =
|
||||||
|
equalsNotNull(
|
||||||
|
musicState.currentItemId,
|
||||||
|
item?.id,
|
||||||
|
),
|
||||||
|
isQueued = item?.id in musicState.queuedIds,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.height(80.dp)
|
|
||||||
.ifElse(
|
.ifElse(
|
||||||
|
item?.type != BaseItemKind.AUDIO,
|
||||||
|
Modifier.height(80.dp),
|
||||||
|
).ifElse(
|
||||||
index == savedIndex,
|
index == savedIndex,
|
||||||
Modifier.focusRequester(focus),
|
Modifier.focusRequester(focus),
|
||||||
).onFocusChanged {
|
).onFocusChanged {
|
||||||
|
|
@ -646,6 +674,8 @@ fun PlaylistItem(
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
|
isPlaying: Boolean = false,
|
||||||
|
isQueued: Boolean = false,
|
||||||
) {
|
) {
|
||||||
val focused by interactionSource.collectIsFocusedAsState()
|
val focused by interactionSource.collectIsFocusedAsState()
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|
@ -658,6 +688,12 @@ fun PlaylistItem(
|
||||||
text = item?.title ?: "",
|
text = item?.title ?: "",
|
||||||
modifier = Modifier.enableMarquee(focused),
|
modifier = Modifier.enableMarquee(focused),
|
||||||
)
|
)
|
||||||
|
if (item?.type == BaseItemKind.AUDIO) {
|
||||||
|
MusicQueueMarker(
|
||||||
|
isPlaying = isPlaying,
|
||||||
|
isQueued = isQueued,
|
||||||
|
)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
supportingContent = {
|
supportingContent = {
|
||||||
Text(
|
Text(
|
||||||
|
|
@ -714,3 +750,47 @@ fun PlaylistItem(
|
||||||
modifier = modifier,
|
modifier = modifier,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun ConfirmMediaTypeDialog(
|
||||||
|
onConfirm: (MediaType) -> Unit,
|
||||||
|
onCancel: () -> Unit,
|
||||||
|
) {
|
||||||
|
BasicDialog(
|
||||||
|
onDismissRequest = onCancel,
|
||||||
|
properties = DialogProperties(),
|
||||||
|
elevation = 3.dp,
|
||||||
|
) {
|
||||||
|
LazyColumn(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
contentPadding = PaddingValues(16.dp),
|
||||||
|
modifier = Modifier.wrapContentSize(),
|
||||||
|
) {
|
||||||
|
item {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.play_as_type),
|
||||||
|
color = MaterialTheme.colorScheme.onSurface,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.fillParentMaxWidth(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
|
) {
|
||||||
|
TextButton(
|
||||||
|
stringRes = R.string.audio,
|
||||||
|
onClick = { onConfirm.invoke(MediaType.AUDIO) },
|
||||||
|
)
|
||||||
|
TextButton(
|
||||||
|
stringRes = R.string.video,
|
||||||
|
onClick = { onConfirm.invoke(MediaType.VIDEO) },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -455,6 +455,23 @@ fun AlbumDetailsPage(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onClickMore = {
|
||||||
|
if (song != null) {
|
||||||
|
moreDialog =
|
||||||
|
DialogParams(
|
||||||
|
fromLongClick = false,
|
||||||
|
title = song.name ?: "",
|
||||||
|
items =
|
||||||
|
buildMoreDialogForMusic(
|
||||||
|
context = context,
|
||||||
|
actions = moreDialogActions,
|
||||||
|
item = song,
|
||||||
|
index = index,
|
||||||
|
canRemove = false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
showArtist = state.isVariousArtists,
|
showArtist = state.isVariousArtists,
|
||||||
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
||||||
isQueued = song != null && song.id in currentMusic.queuedIds,
|
isQueued = song != null && song.id in currentMusic.queuedIds,
|
||||||
|
|
|
||||||
|
|
@ -441,6 +441,23 @@ fun ArtistDetailsPage(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
onClickMore = {
|
||||||
|
if (song != null) {
|
||||||
|
moreDialog =
|
||||||
|
DialogParams(
|
||||||
|
fromLongClick = false,
|
||||||
|
title = song.name ?: "",
|
||||||
|
items =
|
||||||
|
buildMoreDialogForMusic(
|
||||||
|
context = context,
|
||||||
|
actions = moreDialogActions,
|
||||||
|
item = song,
|
||||||
|
index = index,
|
||||||
|
canRemove = false,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
showArtist = false,
|
showArtist = false,
|
||||||
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
isPlaying = song != null && currentMusic.currentItemId == song.id,
|
||||||
isQueued = song != null && song.id in currentMusic.queuedIds,
|
isQueued = song != null && song.id in currentMusic.queuedIds,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.shape.CircleShape
|
import androidx.compose.foundation.shape.CircleShape
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.MoreVert
|
||||||
import androidx.compose.material.icons.filled.PlayArrow
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -18,14 +19,17 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.tv.material3.Icon
|
import androidx.tv.material3.Icon
|
||||||
import androidx.tv.material3.ListItem
|
import androidx.tv.material3.ListItem
|
||||||
import androidx.tv.material3.ListItemDefaults
|
import androidx.tv.material3.ListItemDefaults
|
||||||
import androidx.tv.material3.LocalContentColor
|
import androidx.tv.material3.LocalContentColor
|
||||||
import androidx.tv.material3.Text
|
import androidx.tv.material3.Text
|
||||||
|
import com.github.damontecres.wholphin.R
|
||||||
import com.github.damontecres.wholphin.data.model.BaseItem
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
import com.github.damontecres.wholphin.ui.PreviewTvSpec
|
||||||
|
import com.github.damontecres.wholphin.ui.components.Button
|
||||||
import com.github.damontecres.wholphin.ui.enableMarquee
|
import com.github.damontecres.wholphin.ui.enableMarquee
|
||||||
import com.github.damontecres.wholphin.ui.letNotEmpty
|
import com.github.damontecres.wholphin.ui.letNotEmpty
|
||||||
import com.github.damontecres.wholphin.ui.roundSeconds
|
import com.github.damontecres.wholphin.ui.roundSeconds
|
||||||
|
|
@ -40,6 +44,7 @@ fun SongListItem(
|
||||||
song: BaseItem?,
|
song: BaseItem?,
|
||||||
onClick: () -> Unit,
|
onClick: () -> Unit,
|
||||||
onLongClick: () -> Unit,
|
onLongClick: () -> Unit,
|
||||||
|
onClickMore: () -> Unit,
|
||||||
modifier: Modifier = Modifier,
|
modifier: Modifier = Modifier,
|
||||||
showArtist: Boolean = false,
|
showArtist: Boolean = false,
|
||||||
isPlaying: Boolean = false,
|
isPlaying: Boolean = false,
|
||||||
|
|
@ -62,6 +67,8 @@ fun SongListItem(
|
||||||
showArtist = showArtist,
|
showArtist = showArtist,
|
||||||
isPlaying = isPlaying,
|
isPlaying = isPlaying,
|
||||||
isQueued = isQueued,
|
isQueued = isQueued,
|
||||||
|
showMoreButton = true,
|
||||||
|
onClickMore = onClickMore,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -76,6 +83,8 @@ fun SongListItem(
|
||||||
showArtist: Boolean = false,
|
showArtist: Boolean = false,
|
||||||
isPlaying: Boolean = false,
|
isPlaying: Boolean = false,
|
||||||
isQueued: Boolean = false,
|
isQueued: Boolean = false,
|
||||||
|
showMoreButton: Boolean = false,
|
||||||
|
onClickMore: () -> Unit = {},
|
||||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||||
) {
|
) {
|
||||||
Row(
|
Row(
|
||||||
|
|
@ -90,25 +99,10 @@ fun SongListItem(
|
||||||
Text(
|
Text(
|
||||||
text = indexNumber?.toString() ?: "",
|
text = indexNumber?.toString() ?: "",
|
||||||
)
|
)
|
||||||
if (isPlaying) {
|
MusicQueueMarker(
|
||||||
Icon(
|
isPlaying = isPlaying,
|
||||||
imageVector = Icons.Default.PlayArrow,
|
isQueued = isQueued,
|
||||||
contentDescription = null,
|
|
||||||
)
|
)
|
||||||
} else if (isQueued) {
|
|
||||||
// Icon(
|
|
||||||
// imageVector = Icons.Default.Add,
|
|
||||||
// contentDescription = null,
|
|
||||||
// )
|
|
||||||
Box(
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.padding(horizontal = 8.dp)
|
|
||||||
.clip(CircleShape)
|
|
||||||
.background(LocalContentColor.current)
|
|
||||||
.size(8.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val headlineContent = @Composable {
|
val headlineContent = @Composable {
|
||||||
|
|
@ -140,7 +134,7 @@ fun SongListItem(
|
||||||
},
|
},
|
||||||
trailingContent = trailingContent,
|
trailingContent = trailingContent,
|
||||||
scale = ListItemDefaults.scale(1f, 1f, .95f),
|
scale = ListItemDefaults.scale(1f, 1f, .95f),
|
||||||
modifier = Modifier,
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
ListItem(
|
ListItem(
|
||||||
|
|
@ -153,14 +147,53 @@ fun SongListItem(
|
||||||
supportingContent = null,
|
supportingContent = null,
|
||||||
trailingContent = trailingContent,
|
trailingContent = trailingContent,
|
||||||
scale = ListItemDefaults.scale(1f, 1f, .95f),
|
scale = ListItemDefaults.scale(1f, 1f, .95f),
|
||||||
modifier = Modifier,
|
modifier = Modifier.weight(1f),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (showMoreButton) {
|
||||||
|
Button(
|
||||||
|
onClick = onClickMore,
|
||||||
|
enabled = true,
|
||||||
|
modifier = Modifier.size(32.dp),
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.MoreVert,
|
||||||
|
contentDescription = stringResource(R.string.more),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val BaseItem.artistsString: String? get() = data.artists?.letNotEmpty { it.joinToString(", ") }
|
val BaseItem.artistsString: String? get() = data.artists?.letNotEmpty { it.joinToString(", ") }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an indicator for if the item is currently playing or queued
|
||||||
|
*/
|
||||||
|
@Composable
|
||||||
|
fun MusicQueueMarker(
|
||||||
|
isPlaying: Boolean,
|
||||||
|
isQueued: Boolean,
|
||||||
|
modifier: Modifier = Modifier,
|
||||||
|
) {
|
||||||
|
if (isPlaying) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.PlayArrow,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = modifier,
|
||||||
|
)
|
||||||
|
} else if (isQueued) {
|
||||||
|
Box(
|
||||||
|
modifier =
|
||||||
|
modifier
|
||||||
|
.padding(horizontal = 8.dp)
|
||||||
|
.clip(CircleShape)
|
||||||
|
.background(LocalContentColor.current)
|
||||||
|
.size(8.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@PreviewTvSpec
|
@PreviewTvSpec
|
||||||
@Composable
|
@Composable
|
||||||
fun SongListItemPreview() {
|
fun SongListItemPreview() {
|
||||||
|
|
@ -186,6 +219,7 @@ fun SongListItemPreview() {
|
||||||
modifier = Modifier,
|
modifier = Modifier,
|
||||||
showArtist = false,
|
showArtist = false,
|
||||||
isQueued = true,
|
isQueued = true,
|
||||||
|
showMoreButton = true,
|
||||||
)
|
)
|
||||||
SongListItem(
|
SongListItem(
|
||||||
title = "Song title",
|
title = "Song title",
|
||||||
|
|
|
||||||
|
|
@ -741,6 +741,7 @@
|
||||||
<string name="show_album_cover">Show album cover</string>
|
<string name="show_album_cover">Show album cover</string>
|
||||||
<string name="show_visualizer">Show visualizer</string>
|
<string name="show_visualizer">Show visualizer</string>
|
||||||
<string name="show_backdrop">Show backdrop</string>
|
<string name="show_backdrop">Show backdrop</string>
|
||||||
|
<string name="play_as_type">Play as?</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue