mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 23:51:21 +02:00
Customize now playing page
This commit is contained in:
parent
29269faa63
commit
7233ffa0d9
7 changed files with 278 additions and 74 deletions
|
|
@ -207,21 +207,8 @@ class AlbumViewModel
|
||||||
fun updateBackDrop() {
|
fun updateBackDrop() {
|
||||||
state.value.album?.let { album ->
|
state.value.album?.let { album ->
|
||||||
viewModelScope.launchDefault {
|
viewModelScope.launchDefault {
|
||||||
if (album.data.imageTags?.contains(ImageType.BACKDROP) == true) {
|
getBackdropItemForAlbum(api, album)?.let {
|
||||||
backdropService.submit(album)
|
backdropService.submit(it)
|
||||||
} else {
|
|
||||||
val artistIds =
|
|
||||||
album.data.albumArtists
|
|
||||||
?.shuffled()
|
|
||||||
?.take(50)
|
|
||||||
?.map { it.id }
|
|
||||||
api.itemsApi
|
|
||||||
.getItems(
|
|
||||||
ids = artistIds,
|
|
||||||
imageTypes = listOf(ImageType.BACKDROP),
|
|
||||||
).content.items
|
|
||||||
.firstOrNull()
|
|
||||||
?.let { backdropService.submit(BaseItem(it, false)) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -249,6 +236,28 @@ class AlbumViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getBackdropItemForAlbum(
|
||||||
|
api: ApiClient,
|
||||||
|
album: BaseItem,
|
||||||
|
): BaseItem? {
|
||||||
|
if (album.data.backdropImageTags?.isNotEmpty() == true) {
|
||||||
|
return album
|
||||||
|
} else {
|
||||||
|
val artistIds =
|
||||||
|
album.data.albumArtists
|
||||||
|
?.shuffled()
|
||||||
|
?.take(50)
|
||||||
|
?.map { it.id }
|
||||||
|
return api.itemsApi
|
||||||
|
.getItems(
|
||||||
|
ids = artistIds,
|
||||||
|
imageTypes = listOf(ImageType.BACKDROP),
|
||||||
|
).content.items
|
||||||
|
.firstOrNull()
|
||||||
|
?.let { BaseItem(it, false) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data class AlbumState(
|
data class AlbumState(
|
||||||
val album: BaseItem?,
|
val album: BaseItem?,
|
||||||
val isVariousArtists: Boolean,
|
val isVariousArtists: Boolean,
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,35 @@ import com.github.damontecres.wholphin.preferences.updateMusicPreferences
|
||||||
fun getMusicPreferences() =
|
fun getMusicPreferences() =
|
||||||
listOf(
|
listOf(
|
||||||
AppSwitchPreference<AppPreferences>(
|
AppSwitchPreference<AppPreferences>(
|
||||||
title = R.string.bold_font,
|
title = R.string.show_album_cover,
|
||||||
defaultValue = false,
|
defaultValue = false,
|
||||||
getter = { it.musicPreferences.showAlbumArt },
|
getter = { it.musicPreferences.showAlbumArt },
|
||||||
setter = { prefs, value ->
|
setter = { prefs, value ->
|
||||||
prefs.updateMusicPreferences { showAlbumArt = value }
|
prefs.updateMusicPreferences { showAlbumArt = value }
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
AppSwitchPreference<AppPreferences>(
|
||||||
|
title = R.string.show_visualizer,
|
||||||
|
defaultValue = false,
|
||||||
|
getter = { it.musicPreferences.showVisualizer },
|
||||||
|
setter = { prefs, value ->
|
||||||
|
prefs.updateMusicPreferences { showVisualizer = value }
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AppSwitchPreference<AppPreferences>(
|
||||||
|
title = R.string.show_backdrop,
|
||||||
|
defaultValue = false,
|
||||||
|
getter = { it.musicPreferences.showBackdrop },
|
||||||
|
setter = { prefs, value ->
|
||||||
|
prefs.updateMusicPreferences { showBackdrop = value }
|
||||||
|
},
|
||||||
|
),
|
||||||
|
AppSwitchPreference<AppPreferences>(
|
||||||
|
title = R.string.show_lyrics,
|
||||||
|
defaultValue = false,
|
||||||
|
getter = { it.musicPreferences.showLyrics },
|
||||||
|
setter = { prefs, value ->
|
||||||
|
prefs.updateMusicPreferences { showLyrics = value }
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package com.github.damontecres.wholphin.ui.detail.music
|
||||||
|
|
||||||
|
import android.view.Gravity
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.heightIn
|
||||||
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.focus.focusRequester
|
||||||
|
import androidx.compose.ui.platform.LocalView
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import androidx.compose.ui.window.Dialog
|
||||||
|
import androidx.compose.ui.window.DialogProperties
|
||||||
|
import androidx.compose.ui.window.DialogWindowProvider
|
||||||
|
import androidx.tv.material3.MaterialTheme
|
||||||
|
import androidx.tv.material3.Text
|
||||||
|
import androidx.tv.material3.surfaceColorAtElevation
|
||||||
|
import com.github.damontecres.wholphin.R
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
|
import com.github.damontecres.wholphin.ui.preferences.ComposablePreference
|
||||||
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun MusicViewOptionsDialog(
|
||||||
|
appPreferences: AppPreferences,
|
||||||
|
onDismissRequest: () -> Unit,
|
||||||
|
onViewOptionsChange: (AppPreferences) -> Unit,
|
||||||
|
) {
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() }
|
||||||
|
val columnState = rememberLazyListState()
|
||||||
|
val items = remember { getMusicPreferences() }
|
||||||
|
Dialog(
|
||||||
|
onDismissRequest = onDismissRequest,
|
||||||
|
properties =
|
||||||
|
DialogProperties(
|
||||||
|
usePlatformDefaultWidth = false,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
val dialogWindowProvider = LocalView.current.parent as? DialogWindowProvider
|
||||||
|
dialogWindowProvider?.window?.let { window ->
|
||||||
|
window.setGravity(Gravity.END)
|
||||||
|
window.setDimAmount(0f)
|
||||||
|
}
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.view_options),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
LazyColumn(
|
||||||
|
state = columnState,
|
||||||
|
contentPadding = PaddingValues(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(0.dp),
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.width(256.dp)
|
||||||
|
.heightIn(max = 380.dp)
|
||||||
|
.focusRequester(focusRequester)
|
||||||
|
.background(
|
||||||
|
MaterialTheme.colorScheme.surfaceColorAtElevation(6.dp),
|
||||||
|
shape = RoundedCornerShape(8.dp),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
items(items) { pref ->
|
||||||
|
pref as AppPreference<AppPreferences, Any>
|
||||||
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
val value = pref.getter.invoke(appPreferences)
|
||||||
|
ComposablePreference(
|
||||||
|
preference = pref,
|
||||||
|
value = value,
|
||||||
|
onNavigate = {},
|
||||||
|
onValueChange = { newValue ->
|
||||||
|
onViewOptionsChange.invoke(pref.setter(appPreferences, newValue))
|
||||||
|
},
|
||||||
|
interactionSource = interactionSource,
|
||||||
|
modifier = Modifier,
|
||||||
|
onClickPreference = { pref ->
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ import android.view.Gravity
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
|
import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.animation.expandHorizontally
|
import androidx.compose.animation.expandHorizontally
|
||||||
import androidx.compose.animation.shrinkHorizontally
|
import androidx.compose.animation.shrinkHorizontally
|
||||||
import androidx.compose.animation.slideInVertically
|
import androidx.compose.animation.slideInVertically
|
||||||
|
|
@ -12,10 +13,10 @@ import androidx.compose.foundation.focusable
|
||||||
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
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
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.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -85,6 +86,7 @@ fun NowPlayingPage(
|
||||||
AppPreferences.getDefaultInstance(),
|
AppPreferences.getDefaultInstance(),
|
||||||
),
|
),
|
||||||
).value.appPreferences
|
).value.appPreferences
|
||||||
|
val musicPrefs = preferences.musicPreferences
|
||||||
|
|
||||||
val keyHandler =
|
val keyHandler =
|
||||||
remember(preferences) {
|
remember(preferences) {
|
||||||
|
|
@ -120,9 +122,7 @@ fun NowPlayingPage(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
var showMoreDialog by remember { mutableStateOf(false) }
|
var showViewOptionsDialog by remember { mutableStateOf(false) }
|
||||||
var lyricsActive by remember { mutableStateOf(true) }
|
|
||||||
var showDebugInfo by remember { mutableStateOf(true) }
|
|
||||||
var itemMoreDialog by remember { mutableStateOf<DialogParams?>(null) }
|
var itemMoreDialog by remember { mutableStateOf<DialogParams?>(null) }
|
||||||
|
|
||||||
val focusRequester = remember { FocusRequester() }
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
@ -136,55 +136,25 @@ fun NowPlayingPage(
|
||||||
.focusRequester(focusRequester)
|
.focusRequester(focusRequester)
|
||||||
.focusable(),
|
.focusable(),
|
||||||
) {
|
) {
|
||||||
Row(
|
AnimatedVisibility(
|
||||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
musicPrefs.showAlbumArt,
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.padding(32.dp)
|
||||||
|
.fillMaxWidth(.5f)
|
||||||
|
.align(Alignment.CenterStart),
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
|
||||||
visible = lyricsActive && state.hasLyrics,
|
|
||||||
enter = expandHorizontally(expandFrom = Alignment.Start),
|
|
||||||
exit = shrinkHorizontally(shrinkTowards = Alignment.Start),
|
|
||||||
modifier = Modifier,
|
|
||||||
) {
|
|
||||||
LyricsContent(
|
|
||||||
synced = true,
|
|
||||||
lyrics = state.lyrics,
|
|
||||||
currentLyricPosition = state.currentLyricIndex,
|
|
||||||
onClick = {},
|
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.padding(vertical = 120.dp, horizontal = 32.dp)
|
|
||||||
.fillMaxHeight()
|
|
||||||
.width(320.dp),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Column(
|
Column(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
verticalArrangement = Arrangement.spacedBy(16.dp),
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
modifier =
|
|
||||||
Modifier
|
|
||||||
.padding(40.dp)
|
|
||||||
.fillMaxSize()
|
|
||||||
.weight(1f),
|
|
||||||
) {
|
) {
|
||||||
Box(
|
AsyncImage(
|
||||||
contentAlignment = Alignment.Center,
|
contentDescription = null,
|
||||||
|
model = current?.imageUrl,
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.fillMaxWidth()
|
.height(320.dp),
|
||||||
.fillMaxHeight(.75f),
|
)
|
||||||
) {
|
|
||||||
AsyncImage(
|
|
||||||
contentDescription = null,
|
|
||||||
model = current?.imageUrl,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
|
|
||||||
BarVisualizer(
|
|
||||||
data = viz,
|
|
||||||
modifier = Modifier.fillMaxSize(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
current?.title?.let {
|
current?.title?.let {
|
||||||
Text(
|
Text(
|
||||||
text = it,
|
text = it,
|
||||||
|
|
@ -205,6 +175,50 @@ fun NowPlayingPage(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
AnimatedVisibility(
|
||||||
|
musicPrefs.showVisualizer,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.padding(horizontal = 32.dp)
|
||||||
|
.fillMaxHeight(.75f)
|
||||||
|
.align(Alignment.CenterStart),
|
||||||
|
) {
|
||||||
|
val visualizerWidth by animateFloatAsState(if (musicPrefs.showLyrics && state.hasLyrics) .5f else 1f)
|
||||||
|
BarVisualizer(
|
||||||
|
data = viz,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxHeight()
|
||||||
|
.fillMaxWidth(visualizerWidth)
|
||||||
|
.align(Alignment.CenterStart),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = musicPrefs.showLyrics && state.hasLyrics,
|
||||||
|
enter = expandHorizontally(expandFrom = Alignment.End),
|
||||||
|
exit = shrinkHorizontally(shrinkTowards = Alignment.End),
|
||||||
|
modifier = Modifier.align(Alignment.CenterEnd),
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.fillMaxWidth(.5f)
|
||||||
|
.fillMaxHeight(),
|
||||||
|
) {
|
||||||
|
LyricsContent(
|
||||||
|
synced = true,
|
||||||
|
lyrics = state.lyrics,
|
||||||
|
currentLyricPosition = state.currentLyricIndex,
|
||||||
|
onClick = {},
|
||||||
|
modifier =
|
||||||
|
Modifier
|
||||||
|
.padding(vertical = 120.dp)
|
||||||
|
.fillMaxHeight()
|
||||||
|
.width(320.dp),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
val showContextForItem =
|
val showContextForItem =
|
||||||
remember {
|
remember {
|
||||||
|
|
@ -243,7 +257,7 @@ fun NowPlayingPage(
|
||||||
queue = queue,
|
queue = queue,
|
||||||
controllerViewState = controllerViewState,
|
controllerViewState = controllerViewState,
|
||||||
onMoveQueue = { index, direction -> viewModel.moveQueue(index, direction) },
|
onMoveQueue = { index, direction -> viewModel.moveQueue(index, direction) },
|
||||||
onClickMore = { showMoreDialog = true },
|
onClickMore = { showViewOptionsDialog = true },
|
||||||
onClickSong = { index, _ -> viewModel.play(index) },
|
onClickSong = { index, _ -> viewModel.play(index) },
|
||||||
onClickMoreItem = { index, song -> showContextForItem.invoke(false, index, song) },
|
onClickMoreItem = { index, song -> showContextForItem.invoke(false, index, song) },
|
||||||
onLongClickSong = { index, song -> showContextForItem.invoke(true, index, song) },
|
onLongClickSong = { index, song -> showContextForItem.invoke(true, index, song) },
|
||||||
|
|
@ -277,14 +291,11 @@ fun NowPlayingPage(
|
||||||
waitToLoad = params.fromLongClick,
|
waitToLoad = params.fromLongClick,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (showMoreDialog) {
|
if (showViewOptionsDialog) {
|
||||||
NowPlayingBottomDialog(
|
MusicViewOptionsDialog(
|
||||||
showDebugInfo = showDebugInfo,
|
appPreferences = preferences,
|
||||||
lyricsActive = lyricsActive,
|
onDismissRequest = { showViewOptionsDialog = false },
|
||||||
songHasLyrics = state.hasLyrics,
|
onViewOptionsChange = { viewModel.updatePreferences(it) },
|
||||||
onDismissRequest = { showMoreDialog = false },
|
|
||||||
onClickShowDebug = { showDebugInfo = !showDebugInfo },
|
|
||||||
onClickLyrics = { lyricsActive = !lyricsActive },
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,18 @@ package com.github.damontecres.wholphin.ui.detail.music
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.media.audiofx.Visualizer
|
import android.media.audiofx.Visualizer
|
||||||
|
import androidx.datastore.core.DataStore
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
import androidx.media3.common.Player
|
import androidx.media3.common.Player
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
import com.github.damontecres.wholphin.data.model.AudioItem
|
import com.github.damontecres.wholphin.data.model.AudioItem
|
||||||
|
import com.github.damontecres.wholphin.data.model.BaseItem
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||||
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
|
import com.github.damontecres.wholphin.services.BackdropService
|
||||||
|
import com.github.damontecres.wholphin.services.ImageUrlService
|
||||||
import com.github.damontecres.wholphin.services.MusicService
|
import com.github.damontecres.wholphin.services.MusicService
|
||||||
import com.github.damontecres.wholphin.services.NavigationManager
|
import com.github.damontecres.wholphin.services.NavigationManager
|
||||||
import com.github.damontecres.wholphin.services.UserPreferencesService
|
import com.github.damontecres.wholphin.services.UserPreferencesService
|
||||||
|
|
@ -29,6 +35,7 @@ import kotlinx.coroutines.flow.update
|
||||||
import kotlinx.coroutines.isActive
|
import kotlinx.coroutines.isActive
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.api.client.extensions.lyricsApi
|
import org.jellyfin.sdk.api.client.extensions.lyricsApi
|
||||||
|
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
|
||||||
import org.jellyfin.sdk.model.api.LyricDto
|
import org.jellyfin.sdk.model.api.LyricDto
|
||||||
import org.jellyfin.sdk.model.extensions.ticks
|
import org.jellyfin.sdk.model.extensions.ticks
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -38,6 +45,7 @@ import kotlin.math.ceil
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
import kotlin.time.Duration.Companion.milliseconds
|
import kotlin.time.Duration.Companion.milliseconds
|
||||||
|
|
||||||
|
@UnstableApi
|
||||||
@HiltViewModel(assistedFactory = NowPlayingViewModel.Factory::class)
|
@HiltViewModel(assistedFactory = NowPlayingViewModel.Factory::class)
|
||||||
class NowPlayingViewModel
|
class NowPlayingViewModel
|
||||||
@AssistedInject
|
@AssistedInject
|
||||||
|
|
@ -46,6 +54,9 @@ class NowPlayingViewModel
|
||||||
@param:ApplicationContext private val context: Context,
|
@param:ApplicationContext private val context: Context,
|
||||||
val navigationManager: NavigationManager,
|
val navigationManager: NavigationManager,
|
||||||
private val musicService: MusicService,
|
private val musicService: MusicService,
|
||||||
|
private val imageUrlService: ImageUrlService,
|
||||||
|
private val backdropService: BackdropService,
|
||||||
|
private val preferencesDataStore: DataStore<AppPreferences>,
|
||||||
val userPreferencesService: UserPreferencesService,
|
val userPreferencesService: UserPreferencesService,
|
||||||
) : ViewModel(),
|
) : ViewModel(),
|
||||||
Visualizer.OnDataCaptureListener,
|
Visualizer.OnDataCaptureListener,
|
||||||
|
|
@ -103,6 +114,9 @@ class NowPlayingViewModel
|
||||||
}.join()
|
}.join()
|
||||||
controllerViewState.pulseControls()
|
controllerViewState.pulseControls()
|
||||||
}
|
}
|
||||||
|
viewModelScope.launchDefault {
|
||||||
|
updateBackdrop(getCurrent())
|
||||||
|
}
|
||||||
playbackLoop()
|
playbackLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -163,9 +177,10 @@ class NowPlayingViewModel
|
||||||
mediaItem: MediaItem?,
|
mediaItem: MediaItem?,
|
||||||
reason: Int,
|
reason: Int,
|
||||||
) {
|
) {
|
||||||
|
val audio = mediaItem?.localConfiguration?.tag as? AudioItem
|
||||||
|
Timber.v("onMediaItemTransition to %s", audio?.id)
|
||||||
|
updateBackdrop(audio)
|
||||||
viewModelScope.launchDefault {
|
viewModelScope.launchDefault {
|
||||||
val audio = mediaItem?.localConfiguration?.tag as? AudioItem
|
|
||||||
Timber.v("onMediaItemTransition to %s", audio?.id)
|
|
||||||
state.update {
|
state.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
lyrics = null,
|
lyrics = null,
|
||||||
|
|
@ -190,6 +205,32 @@ class NowPlayingViewModel
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun updateBackdrop(audio: AudioItem?) {
|
||||||
|
viewModelScope.launchDefault {
|
||||||
|
val showBackdrop =
|
||||||
|
userPreferencesService
|
||||||
|
.getCurrent()
|
||||||
|
.appPreferences.musicPreferences.showBackdrop
|
||||||
|
if (audio?.albumId != null && showBackdrop) {
|
||||||
|
try {
|
||||||
|
api.userLibraryApi.getItem(audio.albumId).content.let {
|
||||||
|
val backdropItem = getBackdropItemForAlbum(api, BaseItem(it, false))
|
||||||
|
if (backdropItem != null) {
|
||||||
|
backdropService.submit(backdropItem)
|
||||||
|
} else {
|
||||||
|
backdropService.clearBackdrop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex: Exception) {
|
||||||
|
Timber.e(ex, "Error fetching backdrop")
|
||||||
|
backdropService.clearBackdrop()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
backdropService.clearBackdrop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun moveQueue(
|
fun moveQueue(
|
||||||
index: Int,
|
index: Int,
|
||||||
direction: MoveDirection,
|
direction: MoveDirection,
|
||||||
|
|
@ -239,4 +280,22 @@ class NowPlayingViewModel
|
||||||
}
|
}
|
||||||
viz.update { processed }
|
viz.update { processed }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun updatePreferences(prefs: AppPreferences) {
|
||||||
|
viewModelScope.launchDefault {
|
||||||
|
var backdropChanged = false
|
||||||
|
preferencesDataStore.updateData {
|
||||||
|
backdropChanged =
|
||||||
|
it.musicPreferences.showBackdrop != prefs.musicPreferences.showBackdrop
|
||||||
|
prefs
|
||||||
|
}
|
||||||
|
if (backdropChanged) {
|
||||||
|
if (prefs.musicPreferences.showBackdrop) {
|
||||||
|
updateBackdrop(getCurrent())
|
||||||
|
} else {
|
||||||
|
backdropService.clearBackdrop()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -182,6 +182,7 @@ message MusicPreferences {
|
||||||
bool show_lyrics = 1;
|
bool show_lyrics = 1;
|
||||||
bool show_visualizer = 2;
|
bool show_visualizer = 2;
|
||||||
bool show_album_Art = 3;
|
bool show_album_Art = 3;
|
||||||
|
bool show_backdrop = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
message AppPreferences {
|
message AppPreferences {
|
||||||
|
|
|
||||||
|
|
@ -738,6 +738,9 @@
|
||||||
<string name="show_lyrics">Show lyrics</string>
|
<string name="show_lyrics">Show lyrics</string>
|
||||||
<string name="song_has_lyrics">Song has lyrics</string>
|
<string name="song_has_lyrics">Song has lyrics</string>
|
||||||
<string name="remove_from_queue">Remove from queue</string>
|
<string name="remove_from_queue">Remove from queue</string>
|
||||||
|
<string name="show_album_cover">Show album cover</string>
|
||||||
|
<string name="show_visualizer">Show visualizer</string>
|
||||||
|
<string name="show_backdrop">Show backdrop</string>
|
||||||
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue