mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-09 08:01:20 +02:00
Move now playing song title to page
This commit is contained in:
parent
4de4144648
commit
7044b4aa32
4 changed files with 66 additions and 37 deletions
|
|
@ -21,6 +21,7 @@ import com.github.damontecres.wholphin.ui.main.settings.MoveDirection
|
||||||
import com.github.damontecres.wholphin.ui.onMain
|
import com.github.damontecres.wholphin.ui.onMain
|
||||||
import com.github.damontecres.wholphin.ui.toServerString
|
import com.github.damontecres.wholphin.ui.toServerString
|
||||||
import com.github.damontecres.wholphin.util.BlockingList
|
import com.github.damontecres.wholphin.util.BlockingList
|
||||||
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
import com.github.damontecres.wholphin.util.profile.Codec
|
import com.github.damontecres.wholphin.util.profile.Codec
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
|
@ -71,18 +72,19 @@ class MusicService
|
||||||
/**
|
/**
|
||||||
* Fetches instant mix items, replaces the queue, and begins playback
|
* Fetches instant mix items, replaces the queue, and begins playback
|
||||||
*/
|
*/
|
||||||
suspend fun startInstantMix(itemId: UUID) {
|
suspend fun startInstantMix(itemId: UUID) =
|
||||||
val items =
|
loading {
|
||||||
api.instantMixApi
|
val items =
|
||||||
.getInstantMixFromItem(
|
api.instantMixApi
|
||||||
userId = serverRepository.currentUser.value?.id,
|
.getInstantMixFromItem(
|
||||||
itemId = itemId,
|
userId = serverRepository.currentUser.value?.id,
|
||||||
limit = 200,
|
itemId = itemId,
|
||||||
fields = DefaultItemFields,
|
limit = 200,
|
||||||
).content.items
|
fields = DefaultItemFields,
|
||||||
.map { BaseItem(it, false) }
|
).content.items
|
||||||
setQueue(items, false)
|
.map { BaseItem(it, false) }
|
||||||
}
|
setQueue(items, false)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replace the queue with the given list and starting playing the song as startIndex as soon as its ready
|
* Replace the queue with the given list and starting playing the song as startIndex as soon as its ready
|
||||||
|
|
@ -144,7 +146,7 @@ class MusicService
|
||||||
suspend fun addAllToQueue(
|
suspend fun addAllToQueue(
|
||||||
list: BlockingList<BaseItem?>,
|
list: BlockingList<BaseItem?>,
|
||||||
startIndex: Int,
|
startIndex: Int,
|
||||||
) {
|
) = loading {
|
||||||
var remaining = startIndex
|
var remaining = startIndex
|
||||||
list.indices
|
list.indices
|
||||||
.chunked(25)
|
.chunked(25)
|
||||||
|
|
@ -215,6 +217,13 @@ class MusicService
|
||||||
onMain { player.addMediaItem(state.value.currentIndex + 1, mediaItem) }
|
onMain { player.addMediaItem(state.value.currentIndex + 1, mediaItem) }
|
||||||
updateQueueSize()
|
updateQueueSize()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private suspend fun <T> loading(block: suspend () -> T): T {
|
||||||
|
_state.update { it.copy(loadingState = LoadingState.Loading) }
|
||||||
|
val result = block.invoke()
|
||||||
|
_state.update { it.copy(loadingState = LoadingState.Success) }
|
||||||
|
return result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Stable
|
@Stable
|
||||||
|
|
@ -224,6 +233,7 @@ data class MusicServiceState(
|
||||||
val currentItemId: UUID?,
|
val currentItemId: UUID?,
|
||||||
val isPlaying: Boolean,
|
val isPlaying: Boolean,
|
||||||
val currentItemTitle: String?,
|
val currentItemTitle: String?,
|
||||||
|
val loadingState: LoadingState = LoadingState.Pending,
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = MusicServiceState(0, 0, null, false, null)
|
val EMPTY = MusicServiceState(0, 0, null, false, null)
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import com.github.damontecres.wholphin.ui.launchIO
|
||||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||||
import com.github.damontecres.wholphin.util.BlockingList
|
import com.github.damontecres.wholphin.util.BlockingList
|
||||||
|
import kotlinx.coroutines.delay
|
||||||
import org.jellyfin.sdk.api.client.ApiClient
|
import org.jellyfin.sdk.api.client.ApiClient
|
||||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
@ -93,6 +94,10 @@ abstract class MusicViewModel(
|
||||||
viewModelScope.launchIO {
|
viewModelScope.launchIO {
|
||||||
Timber.v("Starting instant mix for %s", itemId)
|
Timber.v("Starting instant mix for %s", itemId)
|
||||||
musicService.startInstantMix(itemId)
|
musicService.startInstantMix(itemId)
|
||||||
|
}
|
||||||
|
viewModelScope.launchDefault {
|
||||||
|
// TODO better way to wait for query above to start
|
||||||
|
delay(250)
|
||||||
navigationManager.navigateTo(Destination.NowPlaying)
|
navigationManager.navigateTo(Destination.NowPlaying)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ fun NowPlayingOverlay(
|
||||||
if (queueHasFocus) {
|
if (queueHasFocus) {
|
||||||
1f
|
1f
|
||||||
} else {
|
} else {
|
||||||
.5f
|
.33f
|
||||||
},
|
},
|
||||||
animationSpec = tween(durationMillis = 500),
|
animationSpec = tween(durationMillis = 500),
|
||||||
)
|
)
|
||||||
|
|
@ -111,24 +111,6 @@ fun NowPlayingOverlay(
|
||||||
.padding(16.dp)
|
.padding(16.dp)
|
||||||
.fillMaxHeight(height),
|
.fillMaxHeight(height),
|
||||||
) {
|
) {
|
||||||
current?.title?.let {
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
current?.albumTitle?.let {
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
style = MaterialTheme.typography.titleSmall,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
current?.artistNames?.let {
|
|
||||||
Text(
|
|
||||||
text = it,
|
|
||||||
style = MaterialTheme.typography.titleSmall,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
SeekBar(
|
SeekBar(
|
||||||
player = player,
|
player = player,
|
||||||
controllerViewState = controllerViewState,
|
controllerViewState = controllerViewState,
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.focusable
|
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.Row
|
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
|
||||||
|
|
@ -29,13 +30,17 @@ import androidx.compose.ui.input.key.onPreviewKeyEvent
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import androidx.tv.material3.MaterialTheme
|
||||||
|
import androidx.tv.material3.Text
|
||||||
import coil3.compose.AsyncImage
|
import coil3.compose.AsyncImage
|
||||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||||
import com.github.damontecres.wholphin.services.rememberQueue
|
import com.github.damontecres.wholphin.services.rememberQueue
|
||||||
import com.github.damontecres.wholphin.ui.AppColors
|
import com.github.damontecres.wholphin.ui.AppColors
|
||||||
|
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||||
import com.github.damontecres.wholphin.ui.playback.PlaybackKeyHandler
|
import com.github.damontecres.wholphin.ui.playback.PlaybackKeyHandler
|
||||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||||
|
import com.github.damontecres.wholphin.util.LoadingState
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
|
|
@ -118,15 +123,39 @@ fun NowPlayingPage(
|
||||||
.width(320.dp),
|
.width(320.dp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
AsyncImage(
|
Column(
|
||||||
contentDescription = null,
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
model = current?.imageUrl,
|
verticalArrangement = Arrangement.spacedBy(16.dp),
|
||||||
modifier =
|
modifier =
|
||||||
Modifier
|
Modifier
|
||||||
.padding(80.dp)
|
.padding(40.dp)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.weight(1f),
|
.weight(1f),
|
||||||
)
|
) {
|
||||||
|
AsyncImage(
|
||||||
|
contentDescription = null,
|
||||||
|
model = current?.imageUrl,
|
||||||
|
modifier = Modifier.fillMaxSize(.7f),
|
||||||
|
)
|
||||||
|
current?.title?.let {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
style = MaterialTheme.typography.titleLarge,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
current?.albumTitle?.let {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
current?.artistNames?.let {
|
||||||
|
Text(
|
||||||
|
text = it,
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,5 +183,8 @@ fun NowPlayingPage(
|
||||||
.align(Alignment.BottomCenter),
|
.align(Alignment.BottomCenter),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
if (state.musicServiceState.loadingState is LoadingState.Loading) {
|
||||||
|
LoadingPage(focusEnabled = false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue