Various fixes

This commit is contained in:
Damontecres 2026-03-04 16:03:40 -05:00
parent d8a58a6d96
commit 2879cd477c
No known key found for this signature in database
7 changed files with 72 additions and 22 deletions

View file

@ -149,15 +149,15 @@ class MusicService
shuffled: Boolean,
) {
Timber.d("setQueue: %s items, shuffled=%s", items.size, shuffled)
start()
val mediaItems =
items
.filter { it.type == BaseItemKind.AUDIO }
.map(::convert)
withContext(Dispatchers.Main) {
updateQueueSize()
player.setMediaItems(mediaItems)
player.shuffleModeEnabled = shuffled
updateQueueSize()
start()
}
}

View file

@ -19,6 +19,7 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager
@ -105,13 +106,14 @@ abstract class RecommendedViewModel(
fun update(
@StringRes title: Int,
viewOptions: HomeRowViewOptions = HomeRowViewOptions(),
block: suspend () -> List<BaseItem>,
): Deferred<HomeRowLoadingState> =
viewModelScope.async(Dispatchers.IO) {
val titleStr = context.getString(title)
val row =
try {
HomeRowLoadingState.Success(titleStr, block.invoke())
HomeRowLoadingState.Success(titleStr, block.invoke(), viewOptions)
} catch (ex: Exception) {
HomeRowLoadingState.Error(titleStr, null, ex)
}

View file

@ -9,6 +9,7 @@ import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.preferences.AppPreferences
import com.github.damontecres.wholphin.preferences.UserPreferences
@ -18,6 +19,8 @@ import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.SuggestionService
import com.github.damontecres.wholphin.services.SuggestionsResource
import com.github.damontecres.wholphin.ui.AspectRatio
import com.github.damontecres.wholphin.ui.Cards
import com.github.damontecres.wholphin.ui.SlimItemFields
import com.github.damontecres.wholphin.ui.data.RowColumn
import com.github.damontecres.wholphin.ui.setValueOnMain
@ -31,6 +34,7 @@ import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.firstOrNull
@ -88,7 +92,15 @@ class RecommendedMusicViewModel
?.maxItemsPerRow
?: AppPreference.HomePageItems.defaultValue.toInt()
update(R.string.recently_released) {
val jobs = mutableListOf<Deferred<HomeRowLoadingState>>()
val viewOptions =
HomeRowViewOptions(
aspectRatio = AspectRatio.SQUARE,
heightDp = Cards.HEIGHT_EPISODE,
showTitles = true,
)
update(R.string.recently_released, viewOptions) {
val request =
GetItemsRequest(
parentId = parentId,
@ -103,9 +115,9 @@ class RecommendedMusicViewModel
enableTotalRecordCount = false,
)
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
}
}.also(jobs::add)
update(R.string.recently_added) {
update(R.string.recently_added, viewOptions) {
val request =
GetItemsRequest(
parentId = parentId,
@ -120,9 +132,9 @@ class RecommendedMusicViewModel
enableTotalRecordCount = false,
)
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
}
}.also(jobs::add)
update(R.string.top_unwatched) {
update(R.string.top_unwatched, viewOptions) {
val request =
GetItemsRequest(
parentId = parentId,
@ -138,7 +150,7 @@ class RecommendedMusicViewModel
enableTotalRecordCount = false,
)
GetItemsRequestHandler.execute(api, request).toBaseItems(api, false)
}
}.also(jobs::add)
viewModelScope.launch(Dispatchers.IO) {
try {
@ -181,8 +193,13 @@ class RecommendedMusicViewModel
}
}
if (loading.value == LoadingState.Loading || loading.value == LoadingState.Pending) {
loading.setValueOnMain(LoadingState.Success)
for (i in 0..<jobs.size) {
val result = jobs[i].await()
if (result.completed) {
Timber.v("First success")
loading.setValueOnMain(LoadingState.Success)
}
break
}
}
}

View file

@ -20,10 +20,14 @@ import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.CollectionFolderFilter
import com.github.damontecres.wholphin.data.model.GetItemsFilter
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.MusicService
import com.github.damontecres.wholphin.ui.components.CollectionFolderGrid
import com.github.damontecres.wholphin.ui.components.ErrorMessage
import com.github.damontecres.wholphin.ui.components.GenreCardGrid
@ -33,16 +37,35 @@ import com.github.damontecres.wholphin.ui.components.ViewOptionsSquare
import com.github.damontecres.wholphin.ui.data.AlbumSortOptions
import com.github.damontecres.wholphin.ui.data.ArtistSortOptions
import com.github.damontecres.wholphin.ui.data.SongSortOptions
import com.github.damontecres.wholphin.ui.launchDefault
import com.github.damontecres.wholphin.ui.logTab
import com.github.damontecres.wholphin.ui.nav.Destination
import com.github.damontecres.wholphin.ui.preferences.PreferencesViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import org.jellyfin.sdk.model.api.BaseItemKind
import javax.inject.Inject
@HiltViewModel
class CollectionFolderMusicViewModel
@Inject
constructor(
private val musicService: MusicService,
) : ViewModel() {
fun play(item: BaseItem) {
if (item.type == BaseItemKind.AUDIO) {
viewModelScope.launchDefault {
musicService.setQueue(listOf(item), false)
}
}
}
}
@Composable
fun CollectionFolderMusic(
preferences: UserPreferences,
destination: Destination.MediaItem,
modifier: Modifier = Modifier,
viewModel: CollectionFolderMusicViewModel = hiltViewModel(),
preferencesViewModel: PreferencesViewModel = hiltViewModel(),
) {
val rememberedTabIndex =
@ -174,7 +197,7 @@ fun CollectionFolderMusic(
3 -> {
GenreCardGrid(
itemId = destination.itemId,
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM, BaseItemKind.AUDIO),
includeItemTypes = listOf(BaseItemKind.MUSIC_ALBUM),
modifier =
Modifier
.fillMaxSize()
@ -187,7 +210,7 @@ fun CollectionFolderMusic(
CollectionFolderGrid(
preferences = preferences,
onClickItem = { _, item ->
preferencesViewModel.navigationManager.navigateTo(item.destination())
viewModel.play(item)
},
itemId = destination.itemId,
viewModelKey = "${destination.itemId}_songs",

View file

@ -370,6 +370,9 @@ fun AlbumDetailsPage(
)
},
favorite = album.favorite,
buttonOnFocusChanged = {
if (it.isFocused) scope.launch { bringIntoViewRequester.bringIntoView() }
},
modifier =
Modifier
.onFocusChanged {
@ -389,7 +392,7 @@ fun AlbumDetailsPage(
itemsIndexed(state.songs) { index, song ->
Box(
modifier = Modifier.fillMaxWidth(),
contentAlignment = Alignment.Center,
contentAlignment = Alignment.TopStart,
) {
SongListItem(
song = song,
@ -415,9 +418,7 @@ fun AlbumDetailsPage(
isPlaying = song != null && currentMusic.currentItemId == song.id,
modifier =
Modifier
// .padding(horizontal = 16.dp)
.fillMaxWidth(.75f)
.align(Alignment.Center)
.ifElse(
index == 0,
Modifier

View file

@ -377,6 +377,9 @@ fun ArtistDetailsPage(
)
},
favorite = artist.favorite,
buttonOnFocusChanged = {
if (it.isFocused) scope.launch { bringIntoViewRequester.bringIntoView() }
},
modifier =
Modifier
.onFocusChanged {
@ -415,7 +418,7 @@ fun ArtistDetailsPage(
)
}
},
modifier = Modifier.padding(horizontal = 16.dp),
modifier = Modifier.fillMaxWidth(.75f),
showArtist = false,
isPlaying = song != null && currentMusic.currentItemId == song.id,
)

View file

@ -11,8 +11,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.FocusState
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.github.damontecres.wholphin.R
@ -24,6 +26,7 @@ import kotlin.time.Duration
fun MusicExpandableButtons(
actions: MusicButtonActions,
favorite: Boolean,
buttonOnFocusChanged: (FocusState) -> Unit,
modifier: Modifier = Modifier,
) {
val firstFocus = remember { FocusRequester() }
@ -43,7 +46,8 @@ fun MusicExpandableButtons(
onClick = { actions.onClickPlay.invoke(false) },
modifier =
Modifier
.focusRequester(firstFocus),
.focusRequester(firstFocus)
.onFocusChanged(buttonOnFocusChanged),
)
}
item("shuffle") {
@ -51,7 +55,7 @@ fun MusicExpandableButtons(
title = R.string.shuffle,
iconStringRes = R.string.fa_shuffle,
onClick = { actions.onClickPlay.invoke(true) },
modifier = Modifier,
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
)
}
item("instant_mix") {
@ -59,7 +63,7 @@ fun MusicExpandableButtons(
title = R.string.instant_mix,
iconStringRes = R.string.fa_compass,
onClick = actions.onClickInstantMix,
modifier = Modifier,
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
)
}
item("favorite") {
@ -68,7 +72,7 @@ fun MusicExpandableButtons(
iconStringRes = R.string.fa_heart,
onClick = actions.onClickFavorite,
iconColor = if (favorite) Color.Red else Color.Unspecified,
modifier = Modifier,
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
)
}
item("more") {
@ -77,7 +81,7 @@ fun MusicExpandableButtons(
resume = Duration.ZERO,
icon = Icons.Default.MoreVert,
onClick = { actions.onClickMore.invoke() },
modifier = Modifier,
modifier = Modifier.onFocusChanged(buttonOnFocusChanged),
)
}
}