Play theme songs for collections (#962)

## Description
Play theme songs for collections if available

### Related issues
Closes #711

### Testing
Emulator

## Screenshots
N/A

## AI or LLM usage
None
This commit is contained in:
Ray 2026-02-23 13:38:02 -05:00 committed by GitHub
parent e1c66dfb1d
commit 3b162a2f98
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 73 additions and 36 deletions

View file

@ -41,6 +41,7 @@ import androidx.compose.ui.unit.dp
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.compose.LifecycleResumeEffect
import androidx.lifecycle.viewModelScope
import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
@ -60,6 +61,8 @@ import com.github.damontecres.wholphin.services.BackdropService
import com.github.damontecres.wholphin.services.FavoriteWatchManager
import com.github.damontecres.wholphin.services.MediaReportService
import com.github.damontecres.wholphin.services.NavigationManager
import com.github.damontecres.wholphin.services.ThemeSongPlayer
import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.ui.AspectRatios
import com.github.damontecres.wholphin.ui.RequestOrRestoreFocus
import com.github.damontecres.wholphin.ui.SlimItemFields
@ -120,7 +123,9 @@ class CollectionFolderViewModel
private val libraryDisplayInfoDao: LibraryDisplayInfoDao,
private val favoriteWatchManager: FavoriteWatchManager,
private val backdropService: BackdropService,
val navigationManager: NavigationManager,
private val navigationManager: NavigationManager,
private val themeSongPlayer: ThemeSongPlayer,
private val userPreferencesService: UserPreferencesService,
val mediaReportService: MediaReportService,
@Assisted itemId: String,
@Assisted initialSortAndDirection: SortAndDirection?,
@ -157,9 +162,10 @@ class CollectionFolderViewModel
viewModelScope.launchIO {
super.itemId = itemId
try {
itemId.toUUIDOrNull()?.let {
fetchItem(it)
}
val item =
itemId.toUUIDOrNull()?.let {
fetchItem(it)
}
val libraryDisplayInfo =
serverRepository.currentUser.value?.let { user ->
@ -184,6 +190,8 @@ class CollectionFolderViewModel
}
loadResults(true, sortAndDirection, recursive, filterToUse, useSeriesForPrimary)
.join()
// onResumePage()
} catch (ex: Exception) {
Timber.e(ex, "Error during init")
loading.setValueOnMain(DataLoadingState.Error(ex))
@ -254,34 +262,32 @@ class CollectionFolderViewModel
recursive: Boolean,
filter: GetItemsFilter,
useSeriesForPrimary: Boolean,
) {
viewModelScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
if (resetState) {
loading.value = DataLoadingState.Loading
}
backgroundLoading.value = LoadingState.Loading
this@CollectionFolderViewModel.sortAndDirection.value = sortAndDirection
this@CollectionFolderViewModel.filter.value = filter
) = viewModelScope.launch(Dispatchers.IO) {
withContext(Dispatchers.Main) {
if (resetState) {
loading.value = DataLoadingState.Loading
}
try {
val newPager =
createPager(sortAndDirection, recursive, filter, useSeriesForPrimary).init()
if (newPager.isNotEmpty()) newPager.getBlocking(0)
withContext(Dispatchers.Main) {
loading.value = DataLoadingState.Success(newPager)
backgroundLoading.value = LoadingState.Success
}
} catch (ex: Exception) {
Timber.e(
ex,
"Exception while loading data: sort=%s, filter=%s",
sortAndDirection,
filter,
)
withContext(Dispatchers.Main) {
loading.value = DataLoadingState.Error(ex)
}
backgroundLoading.value = LoadingState.Loading
this@CollectionFolderViewModel.sortAndDirection.value = sortAndDirection
this@CollectionFolderViewModel.filter.value = filter
}
try {
val newPager =
createPager(sortAndDirection, recursive, filter, useSeriesForPrimary).init()
if (newPager.isNotEmpty()) newPager.getBlocking(0)
withContext(Dispatchers.Main) {
loading.value = DataLoadingState.Success(newPager)
backgroundLoading.value = LoadingState.Success
}
} catch (ex: Exception) {
Timber.e(
ex,
"Exception while loading data: sort=%s, filter=%s",
sortAndDirection,
filter,
)
withContext(Dispatchers.Main) {
loading.value = DataLoadingState.Error(ex)
}
}
}
@ -443,6 +449,30 @@ class CollectionFolderViewModel
backdropService.submit(item)
}
}
fun navigateTo(destination: Destination) {
release()
navigationManager.navigateTo(destination)
}
fun release() {
themeSongPlayer.stop()
}
fun onResumePage() {
viewModelScope.launchIO {
item.value?.let {
Timber.v("onResumePage: %s", loading.value!!::class)
if (it.type == BaseItemKind.BOX_SET && loading.value !is DataLoadingState.Error) {
val volume =
userPreferencesService
.getCurrent()
.appPreferences.interfacePreferences.playThemeSongs
themeSongPlayer.playThemeFor(it.id, volume)
}
}
}
}
}
/**
@ -548,6 +578,13 @@ fun CollectionFolderGrid(
?: item?.data?.collectionType?.name
?: stringResource(R.string.collection)
Box(modifier = modifier) {
LifecycleResumeEffect(itemId) {
viewModel.onResumePage()
onPauseOrDispose {
viewModel.release()
}
}
CollectionFolderGridContent(
preferences = preferences,
initialPosition = viewModel.position,
@ -598,7 +635,7 @@ fun CollectionFolderGrid(
} else {
Destination.Playback(item)
}
viewModel.navigationManager.navigateTo(destination)
viewModel.navigateTo(destination)
},
onClickPlayAll = { shuffle ->
itemId.toUUIDOrNull()?.let {
@ -622,7 +659,7 @@ fun CollectionFolderGrid(
filter = filter,
)
}
viewModel.navigationManager.navigateTo(destination)
viewModel.navigateTo(destination)
}
},
)
@ -660,7 +697,7 @@ fun CollectionFolderGrid(
favorite = item.favorite,
actions =
MoreDialogActions(
navigateTo = { viewModel.navigationManager.navigateTo(it) },
navigateTo = { viewModel.navigateTo(it) },
onClickWatch = { itemId, watched ->
viewModel.setWatched(position, itemId, watched)
},

View file

@ -65,7 +65,7 @@ fun CollectionFolderPhotoAlbum(
} else {
item.destination(index)
}
viewModel.navigationManager.navigateTo(destination)
viewModel.navigateTo(destination)
},
itemId = itemId.toServerString(),
initialFilter = filter,

View file

@ -656,7 +656,7 @@
</string-array>
<string name="image_type_primary">Primary</string>
<string name="image_type_thumb">Thumbary</string>
<string name="image_type_thumb">Thumb</string>
<string-array name="image_types">
<item>@string/image_type_primary</item>
<item>@string/image_type_thumb</item>