Fixes to v1.0.9 (#2072)
## Description As usual, a PR to fix various smaller bugs in the latest release. - Fixes not showing the Videos tab on favorites page - Fixes the Random button not working for photos - Long nav drawer item names use a marquee scroll if needed - Fixes a crash when clicking "View More" on a studios rows on the home page ### Related issues Fixes #2070 Fixes #2069 Fixes #2135 ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
811eaed87e
commit
5f2f9a8106
9 changed files with 120 additions and 52 deletions
|
|
@ -260,6 +260,7 @@ class HomeDataService
|
|||
Success(
|
||||
title,
|
||||
studios,
|
||||
rowType = row,
|
||||
viewOptions = row.viewOptions,
|
||||
showViewMore = studios.size >= limit,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -198,10 +198,10 @@ val CollectionType.baseItemKinds: List<BaseItemKind>
|
|||
listOf(BaseItemKind.SERIES, BaseItemKind.SEASON, BaseItemKind.EPISODE)
|
||||
}
|
||||
|
||||
CollectionType.HOMEVIDEOS -> {
|
||||
listOf(BaseItemKind.VIDEO)
|
||||
listOf(BaseItemKind.PHOTO)
|
||||
listOf(BaseItemKind.PHOTO_ALBUM)
|
||||
CollectionType.PHOTOS,
|
||||
CollectionType.HOMEVIDEOS,
|
||||
-> {
|
||||
listOf(BaseItemKind.VIDEO, BaseItemKind.PHOTO, BaseItemKind.PHOTO_ALBUM)
|
||||
}
|
||||
|
||||
CollectionType.MUSIC -> {
|
||||
|
|
@ -224,10 +224,6 @@ val CollectionType.baseItemKinds: List<BaseItemKind>
|
|||
listOf(BaseItemKind.PLAYLIST)
|
||||
}
|
||||
|
||||
CollectionType.PHOTOS -> {
|
||||
listOf(BaseItemKind.PHOTO, BaseItemKind.PHOTO_ALBUM)
|
||||
}
|
||||
|
||||
CollectionType.LIVETV -> {
|
||||
listOf(
|
||||
BaseItemKind.TV_CHANNEL,
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ import com.github.damontecres.wholphin.ui.rememberInt
|
|||
import com.github.damontecres.wholphin.ui.showToast
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import com.github.damontecres.wholphin.ui.util.goToRandom
|
||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||
import com.github.damontecres.wholphin.util.BlockingList
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
|
|
@ -302,11 +303,19 @@ class CollectionFolderViewModel
|
|||
override fun onClickRandom() {
|
||||
viewModelScope.launchIO {
|
||||
try {
|
||||
val random =
|
||||
(state.value.items.successValue as? BlockingList<BaseItem?>)?.randomBlocking()
|
||||
Timber.d("Got random item: %s", random?.id)
|
||||
random?.destination()?.let {
|
||||
navigateTo(random.destination())
|
||||
val state = state.value
|
||||
val list = state.items.successValue as? BlockingList<BaseItem?>
|
||||
if (list != null) {
|
||||
goToRandom(
|
||||
navigateTo = ::navigateTo,
|
||||
parentId = itemId,
|
||||
filter = state.filter,
|
||||
sortAndDirection = state.sortAndDirection,
|
||||
recursive = recursive,
|
||||
list = list,
|
||||
)
|
||||
} else {
|
||||
Timber.w("state.value.items is not successful: %s", state.items)
|
||||
}
|
||||
} catch (ex: CancellationException) {
|
||||
throw ex
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ import com.github.damontecres.wholphin.ui.main.settings.Library
|
|||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.ui.nav.NavDrawerItem
|
||||
import com.github.damontecres.wholphin.ui.showToast
|
||||
import com.github.damontecres.wholphin.ui.util.goToRandom
|
||||
import com.github.damontecres.wholphin.util.ApiRequestPager
|
||||
import com.github.damontecres.wholphin.util.BlockingList
|
||||
import com.github.damontecres.wholphin.util.DataLoadingState
|
||||
|
|
@ -700,11 +701,25 @@ class FavoritesViewModel
|
|||
viewModelScope.launchIO {
|
||||
try {
|
||||
collectionStateFor(type)?.let { collectionState ->
|
||||
val random =
|
||||
(collectionState.items.successValue as? BlockingList<BaseItem?>)?.randomBlocking()
|
||||
Timber.d("Got random item: %s", random?.id)
|
||||
random?.destination()?.let {
|
||||
navigateTo(random.destination())
|
||||
val list =
|
||||
collectionState.items.successValue as? BlockingList<BaseItem?>
|
||||
if (list != null) {
|
||||
goToRandom(
|
||||
navigateTo = ::navigateTo,
|
||||
parentId = libraryDisplayItemId(type),
|
||||
filter =
|
||||
collectionState.filter.copy(
|
||||
includeItemTypes = listOf(type),
|
||||
),
|
||||
sortAndDirection = collectionState.sortAndDirection,
|
||||
recursive = true,
|
||||
list = list,
|
||||
)
|
||||
} else {
|
||||
Timber.w(
|
||||
"state.value.items is not successful: %s",
|
||||
collectionState.items,
|
||||
)
|
||||
}
|
||||
}
|
||||
} catch (ex: CancellationException) {
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ sealed class Destination(
|
|||
|
||||
@Serializable
|
||||
data class Slideshow(
|
||||
val parentId: UUID,
|
||||
val parentId: UUID?,
|
||||
val index: Int,
|
||||
val filter: CollectionFolderFilter,
|
||||
val sortAndDirection: SortAndDirection,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ import com.github.damontecres.wholphin.services.SetupDestination
|
|||
import com.github.damontecres.wholphin.services.SetupNavigationManager
|
||||
import com.github.damontecres.wholphin.ui.FontAwesome
|
||||
import com.github.damontecres.wholphin.ui.components.TimeDisplay
|
||||
import com.github.damontecres.wholphin.ui.enableMarquee
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
import com.github.damontecres.wholphin.ui.launchDefault
|
||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
|
||||
|
|
@ -573,6 +574,7 @@ fun NavigationDrawerScope.ProfileIcon(
|
|||
modifier: Modifier = Modifier,
|
||||
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
NavigationDrawerItem(
|
||||
modifier = modifier,
|
||||
selected = false,
|
||||
|
|
@ -595,7 +597,7 @@ fun NavigationDrawerScope.ProfileIcon(
|
|||
interactionSource = interactionSource,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.enableMarquee(focused),
|
||||
text = user.name ?: user.id.toString(),
|
||||
maxLines = 1,
|
||||
)
|
||||
|
|
@ -639,7 +641,7 @@ fun NavigationDrawerScope.IconNavItem(
|
|||
interactionSource = interactionSource,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.enableMarquee(focused),
|
||||
text = text,
|
||||
maxLines = 1,
|
||||
)
|
||||
|
|
@ -733,7 +735,7 @@ fun NavigationDrawerScope.NavItem(
|
|||
interactionSource = interactionSource,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
modifier = Modifier.enableMarquee(focused),
|
||||
text = library.name(context),
|
||||
maxLines = 1,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ import com.github.damontecres.wholphin.ui.components.ErrorMessage
|
|||
import com.github.damontecres.wholphin.ui.components.LoadingPage
|
||||
import com.github.damontecres.wholphin.ui.components.TextButton
|
||||
import com.github.damontecres.wholphin.ui.dimAndBlur
|
||||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
import com.github.damontecres.wholphin.ui.isNotNullOrBlank
|
||||
import com.github.damontecres.wholphin.ui.rememberInt
|
||||
import com.github.damontecres.wholphin.ui.serverSupportedMessage
|
||||
|
|
@ -104,6 +103,8 @@ private fun SwitchServerContentInternal(
|
|||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
val resources = LocalResources.current
|
||||
val focusRequesters =
|
||||
remember(state.servers.size) { List(state.servers.size + 1) { FocusRequester() } }
|
||||
var showAddServer by remember { mutableStateOf(false) }
|
||||
var showDeleteDialog by remember { mutableStateOf<JellyfinServer?>(null) }
|
||||
var focusedIndex by rememberInt(0)
|
||||
|
|
@ -147,10 +148,13 @@ private fun SwitchServerContentInternal(
|
|||
val firstServerFocus = remember { FocusRequester() }
|
||||
LaunchedEffect(state.loading) {
|
||||
val state = state
|
||||
if (state.loading == LoadingState.Success && state.servers.isNotEmpty()) {
|
||||
firstServerFocus.tryRequestFocus()
|
||||
} else if (state.loading == LoadingState.Pending) {
|
||||
firstServerFocus.tryRequestFocus()
|
||||
when (state.loading) {
|
||||
is LoadingState.Error,
|
||||
LoadingState.Loading,
|
||||
LoadingState.Pending,
|
||||
-> Unit
|
||||
|
||||
LoadingState.Success -> focusRequesters.firstOrNull()?.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
LazyRow(
|
||||
|
|
@ -191,10 +195,7 @@ private fun SwitchServerContentInternal(
|
|||
Modifier
|
||||
.onFocusChanged {
|
||||
if (it.isFocused) focusedIndex = index
|
||||
}.ifElse(
|
||||
index == 0,
|
||||
Modifier.focusRequester(firstServerFocus),
|
||||
),
|
||||
}.focusRequester(focusRequesters[index]),
|
||||
)
|
||||
}
|
||||
// Add Server card - always rightmost
|
||||
|
|
@ -205,10 +206,7 @@ private fun SwitchServerContentInternal(
|
|||
Modifier
|
||||
.onFocusChanged {
|
||||
if (it.isFocused) focusedIndex = -1
|
||||
}.ifElse(
|
||||
state.servers.isEmpty(),
|
||||
Modifier.focusRequester(firstServerFocus),
|
||||
),
|
||||
}.focusRequester(focusRequesters.last()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -317,12 +315,12 @@ private fun AddServerDialog(
|
|||
}
|
||||
}
|
||||
|
||||
val firstDiscoveredServerFocusRequester = remember { FocusRequester() }
|
||||
val buttonFocusRequester = remember { FocusRequester() }
|
||||
|
||||
// Default focus to first discovered server if available
|
||||
LaunchedEffect(state.discoveredServers.isNotEmpty(), showEnterAddress) {
|
||||
if (!showEnterAddress && state.discoveredServers.isNotEmpty()) {
|
||||
firstDiscoveredServerFocusRequester.tryRequestFocus()
|
||||
LaunchedEffect(showEnterAddress) {
|
||||
if (!showEnterAddress) {
|
||||
buttonFocusRequester.tryRequestFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -369,12 +367,8 @@ private fun AddServerDialog(
|
|||
key = { state.discoveredServers[it].url },
|
||||
) { index ->
|
||||
val server = state.discoveredServers[index]
|
||||
val focusRequester =
|
||||
if (index == 0) {
|
||||
firstDiscoveredServerFocusRequester
|
||||
} else {
|
||||
remember { FocusRequester() }
|
||||
}
|
||||
val focusRequester = remember { FocusRequester() }
|
||||
LaunchedEffect(Unit) { if (index == 0) focusRequester.tryRequestFocus() }
|
||||
|
||||
ListItem(
|
||||
enabled = true,
|
||||
|
|
|
|||
|
|
@ -143,13 +143,16 @@ class SlideshowViewModel
|
|||
),
|
||||
)
|
||||
serverRepository.currentUser?.let { user ->
|
||||
|
||||
val filter =
|
||||
playbackEffectDao
|
||||
.getPlaybackEffect(
|
||||
user.rowId,
|
||||
slideshowSettings.parentId,
|
||||
BaseItemKind.PHOTO_ALBUM,
|
||||
)?.videoFilter
|
||||
slideshowSettings.parentId?.let {
|
||||
playbackEffectDao
|
||||
.getPlaybackEffect(
|
||||
user.rowId,
|
||||
slideshowSettings.parentId,
|
||||
BaseItemKind.PHOTO_ALBUM,
|
||||
)?.videoFilter
|
||||
}
|
||||
if (filter != null) {
|
||||
Timber.v("Got filter for album %s", slideshowSettings.parentId)
|
||||
albumImageFilter = filter
|
||||
|
|
@ -441,7 +444,7 @@ class SlideshowViewModel
|
|||
fun saveGalleryFilter() {
|
||||
viewModelScope.launchIO(ExceptionHandler(autoToast = true)) {
|
||||
val vf = _imageFilter.value
|
||||
if (vf != null) {
|
||||
if (slideshowSettings.parentId != null) {
|
||||
albumImageFilter = vf
|
||||
serverRepository.currentUser?.let { user ->
|
||||
playbackEffectDao
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
package com.github.damontecres.wholphin.ui.util
|
||||
|
||||
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.ui.data.SortAndDirection
|
||||
import com.github.damontecres.wholphin.ui.nav.Destination
|
||||
import com.github.damontecres.wholphin.util.BlockingList
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import timber.log.Timber
|
||||
import kotlin.random.Random
|
||||
|
||||
/**
|
||||
* Navigate to a random item in the given list
|
||||
*/
|
||||
suspend fun goToRandom(
|
||||
navigateTo: (Destination) -> Unit,
|
||||
parentId: String,
|
||||
filter: GetItemsFilter,
|
||||
sortAndDirection: SortAndDirection,
|
||||
recursive: Boolean,
|
||||
list: BlockingList<BaseItem?>,
|
||||
) {
|
||||
val randomIndex = Random.nextInt(list.size)
|
||||
val random = list.getBlocking(randomIndex)
|
||||
|
||||
Timber.d("Got random item #%s: %s", randomIndex, random?.id)
|
||||
if (random != null) {
|
||||
val destination =
|
||||
if (random.type == BaseItemKind.PHOTO) {
|
||||
Destination.Slideshow(
|
||||
parentId = parentId.toUUIDOrNull(),
|
||||
index = randomIndex,
|
||||
filter =
|
||||
CollectionFolderFilter(
|
||||
filter = filter,
|
||||
),
|
||||
sortAndDirection = sortAndDirection,
|
||||
recursive = recursive,
|
||||
startSlideshow = false,
|
||||
)
|
||||
} else {
|
||||
random.destination()
|
||||
}
|
||||
navigateTo(destination)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue