UI changes to now playing nav drawer item

This commit is contained in:
Damontecres 2026-02-28 19:02:14 -05:00
parent dd7795e2fd
commit 6fa3f550b0
No known key found for this signature in database
5 changed files with 50 additions and 35 deletions

View file

@ -325,8 +325,8 @@ class MainActivity : AppCompatActivity() {
// ?: Destination.Home(), // ?: Destination.Home(),
// TODO undo // TODO undo
?: Destination.MediaItem( ?: Destination.MediaItem(
itemId = "011ef0c7-ca45-684f-2cd9-dd3b020ca5f6".toUUID(), itemId = "bbc3e562-6045-5521-dfda-7effa56e14f2".toUUID(),
type = BaseItemKind.MUSIC_ALBUM, type = BaseItemKind.MUSIC_ARTIST,
), ),
navigationManager = navigationManager, navigationManager = navigationManager,
preferences = preferences, preferences = preferences,

View file

@ -208,9 +208,10 @@ data class MusicServiceState(
val currentIndex: Int, val currentIndex: Int,
val currentItemId: UUID?, val currentItemId: UUID?,
val isPlaying: Boolean, val isPlaying: Boolean,
val currentItemTitle: String?,
) { ) {
companion object { companion object {
val EMPTY = MusicServiceState(0, 0, null, false) val EMPTY = MusicServiceState(0, 0, null, false, null)
} }
} }
@ -263,9 +264,12 @@ private class MusicPlayerListener(
state.update { state -> state.update { state ->
player.currentMediaItemIndex.takeIf { it >= 0 }?.let { currentMediaItemIndex -> player.currentMediaItemIndex.takeIf { it >= 0 }?.let { currentMediaItemIndex ->
if (currentMediaItemIndex in (0..<player.mediaItemCount)) { if (currentMediaItemIndex in (0..<player.mediaItemCount)) {
val item =
player.getMediaItemAt(currentMediaItemIndex).localConfiguration?.tag as? AudioItem
state.copy( state.copy(
currentIndex = currentMediaItemIndex, currentIndex = currentMediaItemIndex,
currentItemId = player.getMediaItemAt(currentMediaItemIndex).mediaId.toUUIDOrNull(), currentItemId = player.getMediaItemAt(currentMediaItemIndex).mediaId.toUUIDOrNull(),
currentItemTitle = item?.title,
) )
} else { } else {
state state

View file

@ -76,18 +76,24 @@ class NavDrawerService
_state.update { it.copy(discoverEnabled = discoverActive) } _state.update { it.copy(discoverEnabled = discoverActive) }
}.launchIn(coroutineScope) }.launchIn(coroutineScope)
coroutineScope.launchDefault { coroutineScope.launchDefault {
musicService.state.collectLatest { musicService.state.collectLatest { music ->
Timber.v("MusicService updated") Timber.v("MusicService updated")
if (it.isPlaying) { if (music.isPlaying) {
_state.update { _state.update {
it.copy(nowPlayingEnabled = true) it.copy(
nowPlayingEnabled = true,
nowPlayingTitle = music.currentItemTitle,
)
} }
} else { } else {
// Don't immediately remove the now playing // Don't immediately remove the now playing
// TODO need better now playing state to distinguish between paused & stopped // TODO need better now playing state to distinguish between paused & stopped
delay(30_000) delay(30_000)
_state.update { _state.update {
it.copy(nowPlayingEnabled = false) it.copy(
nowPlayingEnabled = false,
nowPlayingTitle = null,
)
} }
} }
} }
@ -203,9 +209,10 @@ data class NavDrawerItemState(
val moreItems: List<NavDrawerItem>, val moreItems: List<NavDrawerItem>,
val discoverEnabled: Boolean, val discoverEnabled: Boolean,
val nowPlayingEnabled: Boolean, val nowPlayingEnabled: Boolean,
val nowPlayingTitle: String?,
) { ) {
companion object { companion object {
val EMPTY = NavDrawerItemState(emptyList(), emptyList(), false, false) val EMPTY = NavDrawerItemState(emptyList(), emptyList(), false, false, null)
} }
} }

View file

@ -75,6 +75,7 @@ import kotlinx.coroutines.launch
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.itemsApi import org.jellyfin.sdk.api.client.extensions.itemsApi
import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.model.api.BaseItemKind
import org.jellyfin.sdk.model.api.ImageType import org.jellyfin.sdk.model.api.ImageType
import org.jellyfin.sdk.model.api.ItemSortBy import org.jellyfin.sdk.model.api.ItemSortBy
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
@ -122,6 +123,7 @@ class AlbumViewModel
val request = val request =
GetItemsRequest( GetItemsRequest(
parentId = itemId, parentId = itemId,
includeItemTypes = listOf(BaseItemKind.AUDIO),
fields = DefaultItemFields, fields = DefaultItemFields,
sortBy = sortBy =
listOf( listOf(
@ -196,11 +198,7 @@ class AlbumViewModel
viewModelScope.launchIO { viewModelScope.launchIO {
val songs = state.value.songs as ApiRequestPager<*> val songs = state.value.songs as ApiRequestPager<*>
if (itemId == this@AlbumViewModel.itemId) { if (itemId == this@AlbumViewModel.itemId) {
songs.indices.forEach { musicService.addAllToQueue(songs, 0)
songs.getBlocking(it)?.let {
musicService.addToQueue(it)
}
}
} else { } else {
songs.getBlocking(index)?.let { songs.getBlocking(index)?.let {
musicService.addToQueue(it) musicService.addToQueue(it)

View file

@ -2,9 +2,12 @@ package com.github.damontecres.wholphin.ui.nav
import android.content.Context import android.content.Context
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.VisibilityThreshold import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.animateIntOffsetAsState import androidx.compose.animation.core.animateIntOffsetAsState
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.animation.expandVertically
import androidx.compose.animation.shrinkVertically
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.interaction.collectIsFocusedAsState
@ -337,6 +340,31 @@ fun NavDrawer(
}, },
modifier = Modifier, modifier = Modifier,
) )
AnimatedVisibility(
visible = state.nowPlayingEnabled,
enter = expandVertically(expandFrom = Alignment.Top),
exit = shrinkVertically(shrinkTowards = Alignment.Top),
) {
val interactionSource = remember { MutableInteractionSource() }
IconNavItem(
text = stringResource(R.string.now_playing),
subtext = state.nowPlayingTitle,
icon = Icons.Default.PlayArrow,
selected = selectedIndex == NOW_PLAYING_INDEX,
drawerOpen = isOpen,
interactionSource = interactionSource,
onClick = {
viewModel.setIndex(NOW_PLAYING_INDEX)
viewModel.navigationManager.navigateToFromDrawer(Destination.NowPlaying)
},
modifier =
Modifier
.ifElse(
selectedIndex == NOW_PLAYING_INDEX,
Modifier.focusRequester(focusRequester),
),
)
}
LazyColumn( LazyColumn(
state = navDrawerListState, state = navDrawerListState,
contentPadding = PaddingValues(0.dp), contentPadding = PaddingValues(0.dp),
@ -376,28 +404,6 @@ fun NavDrawer(
), ),
) )
} }
if (state.nowPlayingEnabled) {
item {
val interactionSource = remember { MutableInteractionSource() }
IconNavItem(
text = stringResource(R.string.now_playing),
icon = Icons.Default.PlayArrow,
selected = selectedIndex == NOW_PLAYING_INDEX,
drawerOpen = isOpen,
interactionSource = interactionSource,
onClick = {
viewModel.setIndex(NOW_PLAYING_INDEX)
viewModel.navigationManager.navigateToFromDrawer(Destination.NowPlaying)
},
modifier =
Modifier
.ifElse(
selectedIndex == NOW_PLAYING_INDEX,
Modifier.focusRequester(focusRequester),
).animateItem(),
)
}
}
item { item {
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
IconNavItem( IconNavItem(