mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Basic show/hide now playing nav drawer item
This commit is contained in:
parent
cd06c0380e
commit
1d47220991
4 changed files with 82 additions and 17 deletions
|
|
@ -179,7 +179,7 @@ private class MusicPlayerListener(
|
||||||
Timber.v("MusicPlayerListener init")
|
Timber.v("MusicPlayerListener init")
|
||||||
state.update {
|
state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
queue = PlayerMediaItemList(player),
|
queue = PlayerMediaItemList(player, player.mediaItemCount),
|
||||||
currentIndex = player.currentMediaItemIndex,
|
currentIndex = player.currentMediaItemIndex,
|
||||||
isPlaying = player.isPlaying,
|
isPlaying = player.isPlaying,
|
||||||
)
|
)
|
||||||
|
|
@ -215,7 +215,7 @@ private class MusicPlayerListener(
|
||||||
if (reason == Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
|
if (reason == Player.TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED) {
|
||||||
state.update {
|
state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
queue = PlayerMediaItemList(player),
|
queue = PlayerMediaItemList(player, player.mediaItemCount),
|
||||||
currentIndex = player.currentMediaItemIndex,
|
currentIndex = player.currentMediaItemIndex,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -225,15 +225,28 @@ private class MusicPlayerListener(
|
||||||
|
|
||||||
private class PlayerMediaItemList(
|
private class PlayerMediaItemList(
|
||||||
private val player: Player,
|
private val player: Player,
|
||||||
|
override val size: Int,
|
||||||
) : AbstractList<AudioItem>() {
|
) : AbstractList<AudioItem>() {
|
||||||
override fun get(index: Int): AudioItem {
|
override fun get(index: Int): AudioItem {
|
||||||
// Timber.v("get %s", index)
|
// Timber.v("get %s", index)
|
||||||
return player.getMediaItemAt(index).localConfiguration?.tag as AudioItem
|
return player.getMediaItemAt(index).localConfiguration?.tag as AudioItem
|
||||||
}
|
}
|
||||||
|
|
||||||
override val size: Int
|
override fun equals(other: Any?): Boolean {
|
||||||
get() {
|
if (this === other) return true
|
||||||
// Timber.v("size %s", player.mediaItemCount)
|
if (other !is PlayerMediaItemList) return false
|
||||||
return player.mediaItemCount
|
if (!super.equals(other)) return false
|
||||||
}
|
|
||||||
|
if (size != other.size) return false
|
||||||
|
if (player != other.player) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = super.hashCode()
|
||||||
|
result = 31 * result + size
|
||||||
|
result = 31 * result + player.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import com.github.damontecres.wholphin.data.ServerRepository
|
||||||
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
||||||
import com.github.damontecres.wholphin.data.model.NavPinType
|
import com.github.damontecres.wholphin.data.model.NavPinType
|
||||||
import com.github.damontecres.wholphin.services.hilt.DefaultCoroutineScope
|
import com.github.damontecres.wholphin.services.hilt.DefaultCoroutineScope
|
||||||
|
import com.github.damontecres.wholphin.ui.launchDefault
|
||||||
import com.github.damontecres.wholphin.ui.main.settings.Library
|
import com.github.damontecres.wholphin.ui.main.settings.Library
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
||||||
|
|
@ -14,8 +15,10 @@ import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
|
||||||
import com.github.damontecres.wholphin.util.supportedCollectionTypes
|
import com.github.damontecres.wholphin.util.supportedCollectionTypes
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.flow.MutableStateFlow
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
import kotlinx.coroutines.flow.StateFlow
|
import kotlinx.coroutines.flow.StateFlow
|
||||||
|
import kotlinx.coroutines.flow.collectLatest
|
||||||
import kotlinx.coroutines.flow.combine
|
import kotlinx.coroutines.flow.combine
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
|
@ -40,6 +43,7 @@ class NavDrawerService
|
||||||
private val serverRepository: ServerRepository,
|
private val serverRepository: ServerRepository,
|
||||||
private val serverPreferencesDao: ServerPreferencesDao,
|
private val serverPreferencesDao: ServerPreferencesDao,
|
||||||
private val seerrServerRepository: SeerrServerRepository,
|
private val seerrServerRepository: SeerrServerRepository,
|
||||||
|
private val musicService: MusicService,
|
||||||
) {
|
) {
|
||||||
private val _state = MutableStateFlow(NavDrawerItemState.EMPTY)
|
private val _state = MutableStateFlow(NavDrawerItemState.EMPTY)
|
||||||
val state: StateFlow<NavDrawerItemState> = _state
|
val state: StateFlow<NavDrawerItemState> = _state
|
||||||
|
|
@ -65,6 +69,23 @@ class NavDrawerService
|
||||||
.onEach { discoverActive ->
|
.onEach { discoverActive ->
|
||||||
_state.update { it.copy(discoverEnabled = discoverActive) }
|
_state.update { it.copy(discoverEnabled = discoverActive) }
|
||||||
}.launchIn(coroutineScope)
|
}.launchIn(coroutineScope)
|
||||||
|
coroutineScope.launchDefault {
|
||||||
|
musicService.state.collectLatest {
|
||||||
|
Timber.v("MusicService updated")
|
||||||
|
if (it.isPlaying) {
|
||||||
|
_state.update {
|
||||||
|
it.copy(nowPlayingEnabled = true)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Don't immediately remove the now playing
|
||||||
|
// TODO need better now playing state to distinguish between paused & stopped
|
||||||
|
delay(30_000)
|
||||||
|
_state.update {
|
||||||
|
it.copy(nowPlayingEnabled = false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getAllUserLibraries(
|
suspend fun getAllUserLibraries(
|
||||||
|
|
@ -175,9 +196,10 @@ data class NavDrawerItemState(
|
||||||
val items: List<NavDrawerItem>,
|
val items: List<NavDrawerItem>,
|
||||||
val moreItems: List<NavDrawerItem>,
|
val moreItems: List<NavDrawerItem>,
|
||||||
val discoverEnabled: Boolean,
|
val discoverEnabled: Boolean,
|
||||||
|
val nowPlayingEnabled: Boolean,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = NavDrawerItemState(emptyList(), emptyList(), false)
|
val EMPTY = NavDrawerItemState(emptyList(), emptyList(), false, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,10 +190,11 @@ class RecommendedMusicViewModel
|
||||||
override fun update(
|
override fun update(
|
||||||
@StringRes title: Int,
|
@StringRes title: Int,
|
||||||
row: HomeRowLoadingState,
|
row: HomeRowLoadingState,
|
||||||
) {
|
): HomeRowLoadingState {
|
||||||
rows.update { current ->
|
rows.update { current ->
|
||||||
current.toMutableList().apply { set(rowTitles[title]!!, row) }
|
current.toMutableList().apply { set(rowTitles[title]!!, row) }
|
||||||
}
|
}
|
||||||
|
return row
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.ArrowDropDown
|
import androidx.compose.material.icons.filled.ArrowDropDown
|
||||||
import androidx.compose.material.icons.filled.Home
|
import androidx.compose.material.icons.filled.Home
|
||||||
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
import androidx.compose.material.icons.filled.KeyboardArrowLeft
|
||||||
|
import androidx.compose.material.icons.filled.PlayArrow
|
||||||
import androidx.compose.material.icons.filled.Search
|
import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -178,9 +179,11 @@ class NavDrawerViewModel
|
||||||
if (key is Destination) {
|
if (key is Destination) {
|
||||||
val index =
|
val index =
|
||||||
if (key is Destination.Home) {
|
if (key is Destination.Home) {
|
||||||
-1
|
HOME_INDEX
|
||||||
} else if (key is Destination.Search) {
|
} else if (key is Destination.Search) {
|
||||||
-2
|
SEARCH_INDEX
|
||||||
|
} else if (key is Destination.NowPlaying) {
|
||||||
|
NOW_PLAYING_INDEX
|
||||||
} else {
|
} else {
|
||||||
val idx = asDestinations.indexOf(key)
|
val idx = asDestinations.indexOf(key)
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
|
|
@ -242,6 +245,10 @@ data class ServerNavDrawerItem(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const val HOME_INDEX = -1
|
||||||
|
private const val SEARCH_INDEX = -2
|
||||||
|
private const val NOW_PLAYING_INDEX = -3
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display the left side navigation drawer with [DestinationContent] on the right
|
* Display the left side navigation drawer with [DestinationContent] on the right
|
||||||
*/
|
*/
|
||||||
|
|
@ -353,32 +360,54 @@ fun NavDrawer(
|
||||||
IconNavItem(
|
IconNavItem(
|
||||||
text = stringResource(R.string.search),
|
text = stringResource(R.string.search),
|
||||||
icon = Icons.Default.Search,
|
icon = Icons.Default.Search,
|
||||||
selected = selectedIndex == -2,
|
selected = selectedIndex == SEARCH_INDEX,
|
||||||
drawerOpen = isOpen,
|
drawerOpen = isOpen,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setIndex(-2)
|
viewModel.setIndex(SEARCH_INDEX)
|
||||||
viewModel.navigationManager.navigateToFromDrawer(Destination.Search)
|
viewModel.navigationManager.navigateToFromDrawer(Destination.Search)
|
||||||
},
|
},
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.focusRequester(searchFocusRequester)
|
.focusRequester(searchFocusRequester)
|
||||||
.ifElse(
|
.ifElse(
|
||||||
selectedIndex == -2,
|
selectedIndex == SEARCH_INDEX,
|
||||||
Modifier.focusRequester(focusRequester),
|
Modifier.focusRequester(focusRequester),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
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(
|
||||||
text = stringResource(R.string.home),
|
text = stringResource(R.string.home),
|
||||||
icon = Icons.Default.Home,
|
icon = Icons.Default.Home,
|
||||||
selected = selectedIndex == -1,
|
selected = selectedIndex == HOME_INDEX,
|
||||||
drawerOpen = isOpen,
|
drawerOpen = isOpen,
|
||||||
interactionSource = interactionSource,
|
interactionSource = interactionSource,
|
||||||
onClick = {
|
onClick = {
|
||||||
viewModel.setIndex(-1)
|
viewModel.setIndex(HOME_INDEX)
|
||||||
if (destination is Destination.Home) {
|
if (destination is Destination.Home) {
|
||||||
viewModel.navigationManager.reloadHome()
|
viewModel.navigationManager.reloadHome()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -388,7 +417,7 @@ fun NavDrawer(
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.ifElse(
|
.ifElse(
|
||||||
selectedIndex == -1,
|
selectedIndex == HOME_INDEX,
|
||||||
Modifier.focusRequester(focusRequester),
|
Modifier.focusRequester(focusRequester),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue