mirror of
https://github.com/JustinZeus/Wholphin.git
synced 2026-07-08 15:50:16 +02:00
Optional to automatically go to new page on focus instead of clicking (#127)
Closes #95 Adds a setting (defaults to enabled) to automatically go to a page when the navigation drawer item is focused after a brief delay. Basically, if you open the left nav drawer, and scroll down to "Movies" after a brief delay (600ms), the app will switch to the Movies page without having to click. It can be disabled in advanced settings.
This commit is contained in:
parent
26cc092402
commit
9f3691fd1b
6 changed files with 137 additions and 17 deletions
|
|
@ -590,13 +590,25 @@ sealed interface AppPreference<T> {
|
|||
getter = { },
|
||||
setter = { prefs, _ -> prefs },
|
||||
)
|
||||
|
||||
val NavDrawerSwitchOnFocus =
|
||||
AppSwitchPreference(
|
||||
title = R.string.nav_drawer_switch_on_focus,
|
||||
defaultValue = true,
|
||||
getter = { it.interfacePreferences.navDrawerSwitchOnFocus },
|
||||
setter = { prefs, value ->
|
||||
prefs.updateInterfacePreferences { navDrawerSwitchOnFocus = value }
|
||||
},
|
||||
summaryOn = R.string.enabled,
|
||||
summaryOff = R.string.nav_drawer_switch_on_focus_summary_off,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val basicPreferences =
|
||||
listOf(
|
||||
PreferenceGroup(
|
||||
title = R.string.basic_interface,
|
||||
title = R.string.ui_interface,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.HomePageItems,
|
||||
|
|
@ -648,6 +660,13 @@ val uiPreferences = listOf<PreferenceGroup>()
|
|||
|
||||
val advancedPreferences =
|
||||
listOf(
|
||||
PreferenceGroup(
|
||||
title = R.string.ui_interface,
|
||||
preferences =
|
||||
listOf(
|
||||
AppPreference.NavDrawerSwitchOnFocus,
|
||||
),
|
||||
),
|
||||
PreferenceGroup(
|
||||
title = R.string.playback,
|
||||
preferences =
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ class AppPreferencesSerializer
|
|||
.apply {
|
||||
playThemeSongs = AppPreference.PlayThemeMusic.defaultValue
|
||||
appThemeColors = AppPreference.ThemeColors.defaultValue
|
||||
navDrawerSwitchOnFocus =
|
||||
AppPreference.NavDrawerSwitchOnFocus.defaultValue
|
||||
}.build()
|
||||
}.build()
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,13 @@ import androidx.compose.material.icons.filled.Search
|
|||
import androidx.compose.material.icons.filled.Settings
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.derivedStateOf
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.livedata.observeAsState
|
||||
import androidx.compose.runtime.mutableIntStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.focus.FocusRequester
|
||||
|
|
@ -67,14 +70,17 @@ import com.github.damontecres.wholphin.ui.FontAwesome
|
|||
import com.github.damontecres.wholphin.ui.ifElse
|
||||
import com.github.damontecres.wholphin.ui.launchIO
|
||||
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
|
||||
import com.github.damontecres.wholphin.ui.setValueOnMain
|
||||
import com.github.damontecres.wholphin.ui.spacedByWithFooter
|
||||
import com.github.damontecres.wholphin.ui.toServerString
|
||||
import com.github.damontecres.wholphin.ui.tryRequestFocus
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.jellyfin.sdk.model.api.CollectionType
|
||||
import org.jellyfin.sdk.model.api.DeviceProfile
|
||||
import timber.log.Timber
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
|
||||
|
|
@ -96,12 +102,47 @@ class NavDrawerViewModel
|
|||
val all = all ?: navDrawerItemRepository.getNavDrawerItems()
|
||||
this@NavDrawerViewModel.all = all
|
||||
val libraries = navDrawerItemRepository.getFilteredNavDrawerItems(all)
|
||||
val moreLibraries = all.toMutableList().apply { removeAll(libraries) }
|
||||
|
||||
withContext(Dispatchers.Main) {
|
||||
this@NavDrawerViewModel.moreLibraries.value =
|
||||
all.toMutableList().apply { removeAll(libraries) }
|
||||
this@NavDrawerViewModel.moreLibraries.value = moreLibraries
|
||||
this@NavDrawerViewModel.libraries.value = libraries
|
||||
}
|
||||
val asDestinations =
|
||||
(libraries + listOf(NavDrawerItem.More) + moreLibraries).map {
|
||||
if (it is ServerNavDrawerItem) {
|
||||
it.destination
|
||||
} else if (it is NavDrawerItem.Favorites) {
|
||||
Destination.Favorites
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
val backstack = navigationManager.backStack.toList().reversed()
|
||||
for (i in 0..<backstack.size) {
|
||||
val key = backstack[i]
|
||||
if (key is Destination) {
|
||||
val index =
|
||||
if (key is Destination.Home) {
|
||||
-1
|
||||
} else if (key is Destination.Search) {
|
||||
-2
|
||||
} else {
|
||||
val idx = asDestinations.indexOf(key)
|
||||
if (idx >= 0) {
|
||||
idx
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
Timber.v("Found $index => $key")
|
||||
if (index != null) {
|
||||
selectedIndex.setValueOnMain(index)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -182,6 +223,8 @@ fun NavDrawer(
|
|||
// val libraries = if (showPinnedOnly) pinnedLibraries else allLibraries
|
||||
// A negative index is a built in page, >=0 is a library
|
||||
val selectedIndex by viewModel.selectedIndex.observeAsState(-1)
|
||||
var focusedIndex by remember { mutableIntStateOf(Int.MIN_VALUE) }
|
||||
val derivedFocusedIndex by remember { derivedStateOf { focusedIndex } }
|
||||
|
||||
fun setShowMore(value: Boolean) {
|
||||
viewModel.setShowMore(value)
|
||||
|
|
@ -210,6 +253,31 @@ fun NavDrawer(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (preferences.appPreferences.interfacePreferences.navDrawerSwitchOnFocus) {
|
||||
LaunchedEffect(derivedFocusedIndex) {
|
||||
val index = derivedFocusedIndex
|
||||
delay(600)
|
||||
if (index != selectedIndex) {
|
||||
if (index == -1) {
|
||||
viewModel.setIndex(-1)
|
||||
viewModel.navigationManager.goToHome()
|
||||
} else if (index in libraries.indices) {
|
||||
if (moreLibraries.isEmpty() || index != libraries.lastIndex) {
|
||||
libraries.getOrNull(index)?.let {
|
||||
onClick.invoke(index, it)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val newIndex = libraries.size - index + 1
|
||||
if (newIndex in moreLibraries.indices) {
|
||||
moreLibraries.getOrNull(newIndex)?.let {
|
||||
onClick.invoke(index, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NavigationDrawer(
|
||||
modifier =
|
||||
|
|
@ -234,11 +302,16 @@ fun NavDrawer(
|
|||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(1.dp)),
|
||||
) {
|
||||
item {
|
||||
// Even though some must be clicked, focusing on it should clear other focused items
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = Int.MIN_VALUE }
|
||||
IconNavItem(
|
||||
text = user?.name ?: "",
|
||||
subtext = server?.name ?: server?.url,
|
||||
icon = Icons.Default.AccountCircle,
|
||||
selected = false,
|
||||
interactionSource = interactionSource,
|
||||
onClick = {
|
||||
viewModel.navigationManager.navigateTo(Destination.UserList)
|
||||
},
|
||||
|
|
@ -246,10 +319,14 @@ fun NavDrawer(
|
|||
)
|
||||
}
|
||||
item {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = -2 }
|
||||
IconNavItem(
|
||||
text = "Search",
|
||||
icon = Icons.Default.Search,
|
||||
selected = selectedIndex == -2,
|
||||
interactionSource = interactionSource,
|
||||
onClick = {
|
||||
viewModel.setIndex(-2)
|
||||
viewModel.navigationManager.navigateToFromDrawer(Destination.Search)
|
||||
|
|
@ -263,10 +340,14 @@ fun NavDrawer(
|
|||
)
|
||||
}
|
||||
item {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = -1 }
|
||||
IconNavItem(
|
||||
text = "Home",
|
||||
icon = Icons.Default.Home,
|
||||
selected = selectedIndex == -1,
|
||||
interactionSource = interactionSource,
|
||||
onClick = {
|
||||
viewModel.setIndex(-1)
|
||||
if (destination is Destination.Home) {
|
||||
|
|
@ -284,10 +365,14 @@ fun NavDrawer(
|
|||
)
|
||||
}
|
||||
itemsIndexed(libraries) { index, it ->
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = index }
|
||||
NavItem(
|
||||
library = it,
|
||||
selected = selectedIndex == index,
|
||||
moreExpanded = showMore,
|
||||
interactionSource = interactionSource,
|
||||
onClick = {
|
||||
onClick.invoke(index, it)
|
||||
if (it !is NavDrawerItem.More) setShowMore(false)
|
||||
|
|
@ -302,26 +387,35 @@ fun NavDrawer(
|
|||
}
|
||||
if (showMore) {
|
||||
itemsIndexed(moreLibraries) { index, it ->
|
||||
val adjustedIndex = (index + libraries.size + 1)
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = adjustedIndex }
|
||||
NavItem(
|
||||
library = it,
|
||||
selected = selectedIndex == (index + libraries.size),
|
||||
selected = selectedIndex == adjustedIndex,
|
||||
moreExpanded = showMore,
|
||||
onClick = { onClick.invoke(index + libraries.size, it) },
|
||||
onClick = { onClick.invoke(adjustedIndex, it) },
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(3.dp),
|
||||
interactionSource = interactionSource,
|
||||
modifier =
|
||||
Modifier
|
||||
.ifElse(
|
||||
selectedIndex == (index + libraries.size),
|
||||
selectedIndex == adjustedIndex,
|
||||
Modifier.focusRequester(focusRequester),
|
||||
).animateItem(),
|
||||
)
|
||||
}
|
||||
}
|
||||
item {
|
||||
val interactionSource = remember { MutableInteractionSource() }
|
||||
val focused by interactionSource.collectIsFocusedAsState()
|
||||
LaunchedEffect(focused) { if (focused) focusedIndex = Int.MIN_VALUE }
|
||||
IconNavItem(
|
||||
text = "Settings",
|
||||
icon = Icons.Default.Settings,
|
||||
selected = false,
|
||||
interactionSource = interactionSource,
|
||||
onClick = {
|
||||
viewModel.navigationManager.navigateTo(
|
||||
Destination.Settings(
|
||||
|
|
@ -364,8 +458,8 @@ fun NavigationDrawerScope.IconNavItem(
|
|||
leadingContent = {
|
||||
val color =
|
||||
when {
|
||||
isFocused -> LocalContentColor.current
|
||||
selected -> MaterialTheme.colorScheme.border
|
||||
isFocused -> LocalContentColor.current
|
||||
else -> LocalContentColor.current
|
||||
}
|
||||
Icon(
|
||||
|
|
@ -422,13 +516,6 @@ fun NavigationDrawerScope.NavItem(
|
|||
else -> R.string.fa_film
|
||||
}
|
||||
}
|
||||
val isFocused = interactionSource.collectIsFocusedAsState().value
|
||||
val color =
|
||||
when {
|
||||
isFocused -> Color.Unspecified
|
||||
selected -> MaterialTheme.colorScheme.border
|
||||
else -> Color.Unspecified
|
||||
}
|
||||
NavigationDrawerItem(
|
||||
modifier = modifier,
|
||||
selected = false,
|
||||
|
|
@ -445,12 +532,13 @@ fun NavigationDrawerScope.NavItem(
|
|||
textAlign = TextAlign.Center,
|
||||
fontSize = 16.sp,
|
||||
fontFamily = FontAwesome,
|
||||
color = color,
|
||||
color = if (selected) MaterialTheme.colorScheme.border else LocalContentColor.current,
|
||||
)
|
||||
} else {
|
||||
Icon(
|
||||
painter = painterResource(icon),
|
||||
contentDescription = null,
|
||||
tint = if (selected) MaterialTheme.colorScheme.border else LocalContentColor.current,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -463,7 +551,7 @@ fun NavigationDrawerScope.NavItem(
|
|||
)
|
||||
}
|
||||
},
|
||||
interactionSource = null,
|
||||
interactionSource = interactionSource,
|
||||
) {
|
||||
Text(
|
||||
modifier = Modifier,
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import androidx.preference.PreferenceManager
|
|||
import com.github.damontecres.wholphin.WholphinApplication
|
||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.updateInterfacePreferences
|
||||
import com.github.damontecres.wholphin.preferences.updatePlaybackOverrides
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import timber.log.Timber
|
||||
|
|
@ -81,4 +82,11 @@ suspend fun upgradeApp(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (previous.isEqualOrBefore(Version.fromString("0.2.3-6-g0"))) {
|
||||
appPreferences.updateData {
|
||||
it.updateInterfacePreferences {
|
||||
navDrawerSwitchOnFocus = AppPreference.NavDrawerSwitchOnFocus.defaultValue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ message InterfacePreferences {
|
|||
bool remember_selected_tab = 2;
|
||||
map<string, int32> remembered_tabs = 3;
|
||||
AppThemeColors app_theme_colors = 4;
|
||||
bool nav_drawer_switch_on_focus = 5;
|
||||
}
|
||||
|
||||
message AppPreferences {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<string name="cancel">Cancel</string>
|
||||
<string name="save">Save</string>
|
||||
<string name="app_name_long">Wholphin</string>
|
||||
<string name="basic_interface">Basic Interface</string>
|
||||
<string name="ui_interface">Interface</string>
|
||||
<string name="playback">Playback</string>
|
||||
<string name="about">About</string>
|
||||
<string name="advanced_settings">Advanced Settings</string>
|
||||
|
|
@ -98,5 +98,7 @@
|
|||
<string name="send_app_logs_summary">Useful for debugging</string>
|
||||
<string name="global_content_scale">Default content scale</string>
|
||||
<string name="ffmpeg_extension_pref">Use FFmpeg decoder module</string>
|
||||
<string name="nav_drawer_switch_on_focus">Switch nav drawer pages on focus</string>
|
||||
<string name="nav_drawer_switch_on_focus_summary_off">Click to switch pages</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue