Updates to nav drawer

This commit is contained in:
Damontecres 2025-10-06 22:57:03 -04:00
parent 126530ab73
commit 864fc5b9dd
No known key found for this signature in database
5 changed files with 72 additions and 12 deletions

View file

@ -113,7 +113,7 @@ class CollectionFolderViewModel
val newPager = val newPager =
ApiRequestPager(api, request, GetItemsRequestHandler, viewModelScope) ApiRequestPager(api, request, GetItemsRequestHandler, viewModelScope)
newPager.init() newPager.init()
newPager.getBlocking(0) if (newPager.isNotEmpty()) newPager.getBlocking(0)
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
pager.value = newPager pager.value = newPager
loading.value = LoadingState.Success loading.value = LoadingState.Success

View file

@ -38,6 +38,7 @@ fun CollectionFolderMovie(
var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) } var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) }
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
val firstTabFocusRequester = remember { FocusRequester() } val firstTabFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { firstTabFocusRequester.tryRequestFocus() }
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() } LaunchedEffect(Unit) { focusRequester.tryRequestFocus() }
Column( Column(
@ -62,7 +63,10 @@ fun CollectionFolderMovie(
modifier = modifier =
Modifier Modifier
.padding(8.dp) .padding(8.dp)
.ifElse(index == 0, Modifier.focusRequester(firstTabFocusRequester)), .ifElse(
index == 0,
Modifier.focusRequester(firstTabFocusRequester),
),
) )
} }
} }

View file

@ -38,6 +38,7 @@ fun CollectionFolderTv(
var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) } var selectedTabIndex by rememberSaveable { mutableIntStateOf(0) }
val focusRequester = remember { FocusRequester() } val focusRequester = remember { FocusRequester() }
val firstTabFocusRequester = remember { FocusRequester() } val firstTabFocusRequester = remember { FocusRequester() }
LaunchedEffect(Unit) { firstTabFocusRequester.tryRequestFocus() }
LaunchedEffect(Unit) { focusRequester.tryRequestFocus() } LaunchedEffect(Unit) { focusRequester.tryRequestFocus() }
Column( Column(
@ -62,7 +63,10 @@ fun CollectionFolderTv(
modifier = modifier =
Modifier Modifier
.padding(8.dp) .padding(8.dp)
.ifElse(index == 0, Modifier.focusRequester(firstTabFocusRequester)), .ifElse(
index == 0,
Modifier.focusRequester(firstTabFocusRequester),
),
) )
} }
} }

View file

@ -3,6 +3,8 @@ package com.github.damontecres.dolphin.ui.nav
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.focusGroup import androidx.compose.foundation.focusGroup
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
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.Column
@ -10,7 +12,7 @@ import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.AccountCircle import androidx.compose.material.icons.filled.AccountCircle
@ -27,6 +29,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.focus.focusRestorer import androidx.compose.ui.focus.focusRestorer
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView import androidx.compose.ui.platform.LocalView
@ -41,6 +44,7 @@ import androidx.lifecycle.findViewTreeViewModelStoreOwner
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.tv.material3.DrawerValue import androidx.tv.material3.DrawerValue
import androidx.tv.material3.Icon import androidx.tv.material3.Icon
import androidx.tv.material3.LocalContentColor
import androidx.tv.material3.MaterialTheme import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.NavigationDrawer import androidx.tv.material3.NavigationDrawer
import androidx.tv.material3.NavigationDrawerItem import androidx.tv.material3.NavigationDrawerItem
@ -57,6 +61,7 @@ import com.github.damontecres.dolphin.data.model.BaseItem
import com.github.damontecres.dolphin.preferences.UserPreferences import com.github.damontecres.dolphin.preferences.UserPreferences
import com.github.damontecres.dolphin.ui.FontAwesome import com.github.damontecres.dolphin.ui.FontAwesome
import com.github.damontecres.dolphin.util.ExceptionHandler import com.github.damontecres.dolphin.util.ExceptionHandler
import com.github.damontecres.dolphin.util.supportedCollectionTypes
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
@ -73,6 +78,7 @@ class NavDrawerViewModel
val api: ApiClient, val api: ApiClient,
) : ViewModel() { ) : ViewModel() {
val libraries = MutableLiveData<List<BaseItem>>(listOf()) val libraries = MutableLiveData<List<BaseItem>>(listOf())
val selectedIndex = MutableLiveData<Int>(-1)
init { init {
viewModelScope.launch(ExceptionHandler()) { viewModelScope.launch(ExceptionHandler()) {
@ -80,10 +86,16 @@ class NavDrawerViewModel
api.userViewsApi api.userViewsApi
.getUserViews() .getUserViews()
.content.items .content.items
// Timber.v("userViews: $userViews") libraries.value =
libraries.value = userViews.map { BaseItem.from(it, api) } userViews
.filter { it.collectionType in supportedCollectionTypes }
.map { BaseItem.from(it, api) }
} }
} }
fun setIndex(index: Int) {
selectedIndex.value = index
}
} }
@Composable @Composable
@ -111,6 +123,7 @@ fun NavDrawer(
drawerFocusRequester.requestFocus() drawerFocusRequester.requestFocus()
} }
val libraries by viewModel.libraries.observeAsState(listOf()) val libraries by viewModel.libraries.observeAsState(listOf())
val selectedIndex by viewModel.selectedIndex.observeAsState(-1)
NavigationDrawer( NavigationDrawer(
modifier = modifier =
@ -133,17 +146,26 @@ fun NavDrawer(
text = user?.name ?: "", text = user?.name ?: "",
subtext = server?.name ?: server?.url, subtext = server?.name ?: server?.url,
icon = Icons.Default.AccountCircle, icon = Icons.Default.AccountCircle,
onClick = { navigationManager.navigateTo(Destination.UserList) }, selected = false,
onClick = {
navigationManager.navigateTo(Destination.UserList)
},
) )
IconNavItem( IconNavItem(
text = "Search", text = "Search",
icon = Icons.Default.Search, icon = Icons.Default.Search,
onClick = { navigationManager.navigateTo(Destination.Search) }, selected = selectedIndex == -2,
onClick = {
viewModel.setIndex(-2)
navigationManager.navigateToFromDrawer(Destination.Search)
},
) )
IconNavItem( IconNavItem(
text = "Home", text = "Home",
icon = Icons.Default.Home, icon = Icons.Default.Home,
selected = selectedIndex == -1,
onClick = { onClick = {
viewModel.setIndex(-1)
if (destination is Destination.Main) { if (destination is Destination.Main) {
navigationManager.reloadHome() navigationManager.reloadHome()
} else { } else {
@ -160,11 +182,13 @@ fun NavDrawer(
Modifier Modifier
.weight(1f), .weight(1f),
) { ) {
items(libraries) { itemsIndexed(libraries) { index, it ->
LibraryNavItem( LibraryNavItem(
library = it, library = it,
selected = selectedIndex == index,
onClick = { onClick = {
navigationManager.navigateTo(it.destination()) viewModel.setIndex(index)
navigationManager.navigateToFromDrawer(it.destination())
}, },
) )
} }
@ -172,7 +196,10 @@ fun NavDrawer(
IconNavItem( IconNavItem(
text = "Settings", text = "Settings",
icon = Icons.Default.Settings, icon = Icons.Default.Settings,
onClick = { navigationManager.navigateTo(Destination.Settings) }, selected = false,
onClick = {
navigationManager.navigateTo(Destination.Settings)
},
modifier = Modifier, modifier = Modifier,
) )
} }
@ -195,17 +222,27 @@ fun NavigationDrawerScope.IconNavItem(
text: String, text: String,
icon: ImageVector, icon: ImageVector,
onClick: () -> Unit, onClick: () -> Unit,
selected: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
subtext: String? = null, subtext: String? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
val isFocused = interactionSource.collectIsFocusedAsState().value
NavigationDrawerItem( NavigationDrawerItem(
modifier = modifier, modifier = modifier,
selected = false, selected = false,
onClick = onClick, onClick = onClick,
leadingContent = { leadingContent = {
val color =
when {
isFocused -> LocalContentColor.current
selected -> MaterialTheme.colorScheme.border
else -> LocalContentColor.current
}
Icon( Icon(
icon, icon,
contentDescription = null, contentDescription = null,
tint = color,
) )
}, },
supportingContent = supportingContent =
@ -217,7 +254,7 @@ fun NavigationDrawerScope.IconNavItem(
) )
} }
}, },
interactionSource = null, interactionSource = interactionSource,
) { ) {
Text( Text(
modifier = Modifier, modifier = Modifier,
@ -231,7 +268,9 @@ fun NavigationDrawerScope.IconNavItem(
fun NavigationDrawerScope.LibraryNavItem( fun NavigationDrawerScope.LibraryNavItem(
library: BaseItem, library: BaseItem,
onClick: () -> Unit, onClick: () -> Unit,
selected: Boolean,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
) { ) {
// TODO // TODO
val icon = val icon =
@ -243,6 +282,13 @@ fun NavigationDrawerScope.LibraryNavItem(
CollectionType.MUSIC -> R.string.fa_music CollectionType.MUSIC -> R.string.fa_music
else -> R.string.fa_film else -> R.string.fa_film
} }
val isFocused = interactionSource.collectIsFocusedAsState().value
val color =
when {
isFocused -> Color.Unspecified
selected -> MaterialTheme.colorScheme.border
else -> Color.Unspecified
}
NavigationDrawerItem( NavigationDrawerItem(
modifier = modifier, modifier = modifier,
selected = false, selected = false,
@ -254,6 +300,7 @@ fun NavigationDrawerScope.LibraryNavItem(
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontSize = 16.sp, fontSize = 16.sp,
fontFamily = FontAwesome, fontFamily = FontAwesome,
color = color,
) )
} }
}, },

View file

@ -10,6 +10,11 @@ class NavigationManager(
backStack.add(destination) backStack.add(destination)
} }
fun navigateToFromDrawer(destination: Destination) {
goToHome()
backStack.add(destination)
}
fun goBack() { fun goBack() {
backStack.removeLastOrNull() backStack.removeLastOrNull()
} }