diff --git a/app/src/main/java/com/github/damontecres/wholphin/services/HomeDataService.kt b/app/src/main/java/com/github/damontecres/wholphin/services/HomeDataService.kt index fddd4be7..fe462b98 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/services/HomeDataService.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/services/HomeDataService.kt @@ -260,6 +260,7 @@ class HomeDataService Success( title, studios, + rowType = row, viewOptions = row.viewOptions, showViewMore = studios.size >= limit, ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt index bc07af92..af67f12c 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt @@ -198,10 +198,10 @@ val CollectionType.baseItemKinds: List 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 listOf(BaseItemKind.PLAYLIST) } - CollectionType.PHOTOS -> { - listOf(BaseItemKind.PHOTO, BaseItemKind.PHOTO_ALBUM) - } - CollectionType.LIVETV -> { listOf( BaseItemKind.TV_CHANNEL, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt index f383ed5e..afd23273 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderView.kt @@ -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)?.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 + 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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/FavoritesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/FavoritesViewModel.kt index adbd9a44..5690fadc 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/FavoritesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/FavoritesViewModel.kt @@ -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)?.randomBlocking() - Timber.d("Got random item: %s", random?.id) - random?.destination()?.let { - navigateTo(random.destination()) + val list = + collectionState.items.successValue as? BlockingList + 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) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt index a65c97e8..110cb637 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/Destination.kt @@ -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, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt index efbf1a4b..100b6caf 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/nav/NavDrawer.kt @@ -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, ) diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt index c5ac22b3..dd972f9b 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchServerContent.kt @@ -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(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, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/slideshow/SlideshowViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/slideshow/SlideshowViewModel.kt index 7e742235..8172b049 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/slideshow/SlideshowViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/slideshow/SlideshowViewModel.kt @@ -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 diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/util/RandomButtonUtils.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/util/RandomButtonUtils.kt new file mode 100644 index 00000000..31f4f6fa --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/util/RandomButtonUtils.kt @@ -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, +) { + 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) + } +}