fix: improve navigation animation speed

Fixes possible crashes on slow androidTVs

Closes #49
This commit is contained in:
Zane Schepke 2024-08-17 00:43:57 -04:00
parent 528a1f84e4
commit 3f4673b2a7
10 changed files with 48 additions and 37 deletions

View File

@ -57,7 +57,13 @@ constructor(
when (val backend = backend()) { when (val backend = backend()) {
is Backend -> backend.setState(this, tunnelState.toWgState(), TunnelConfig.configFromWgQuick(tunnelConfig.wgQuick)).let { TunnelState.from(it) } is Backend -> backend.setState(this, tunnelState.toWgState(), TunnelConfig.configFromWgQuick(tunnelConfig.wgQuick)).let { TunnelState.from(it) }
is org.amnezia.awg.backend.Backend -> { is org.amnezia.awg.backend.Backend -> {
val config = if(tunnelConfig.amQuick.isBlank()) TunnelConfig.configFromAmQuick(tunnelConfig.wgQuick) else TunnelConfig.configFromAmQuick(tunnelConfig.amQuick) val config = if (tunnelConfig.amQuick.isBlank()) {
TunnelConfig.configFromAmQuick(
tunnelConfig.wgQuick,
)
} else {
TunnelConfig.configFromAmQuick(tunnelConfig.amQuick)
}
backend.setState(this, tunnelState.toAmState(), config).let { backend.setState(this, tunnelState.toAmState(), config).let {
TunnelState.from(it) TunnelState.from(it)
} }

View File

@ -5,6 +5,9 @@ import androidx.activity.SystemBarStyle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.foundation.focusable import androidx.compose.foundation.focusable
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -49,6 +52,7 @@ import com.zaneschepke.wireguardautotunnel.ui.screens.settings.SettingsScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen
import com.zaneschepke.wireguardautotunnel.ui.screens.support.logs.LogsScreen import com.zaneschepke.wireguardautotunnel.ui.screens.support.logs.LogsScreen
import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme
import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.StringValue import com.zaneschepke.wireguardautotunnel.util.StringValue
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@ -129,7 +133,6 @@ class MainActivity : AppCompatActivity() {
} }
}, },
containerColor = MaterialTheme.colorScheme.background, containerColor = MaterialTheme.colorScheme.background,
// TODO refactor
modifier = modifier =
Modifier Modifier
.focusable() .focusable()
@ -150,14 +153,12 @@ class MainActivity : AppCompatActivity() {
) )
}, },
) { padding -> ) { padding ->
Surface { Surface(modifier = Modifier.fillMaxSize().padding(padding)) {
NavHost( NavHost(
navController, navController,
enterTransition = { fadeIn(tween(Constants.TRANSITION_ANIMATION_TIME)) },
exitTransition = { fadeOut(tween(Constants.TRANSITION_ANIMATION_TIME)) },
startDestination = (if (isPinLockEnabled == true) Screen.Lock.route else Screen.Main.route), startDestination = (if (isPinLockEnabled == true) Screen.Lock.route else Screen.Main.route),
modifier =
Modifier
.padding(padding)
.fillMaxSize(),
) { ) {
composable( composable(
Screen.Main.route, Screen.Main.route,

View File

@ -6,42 +6,33 @@ import androidx.compose.material3.NavigationBar
import androidx.compose.material3.NavigationBarItem import androidx.compose.material3.NavigationBarItem
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.NavGraph.Companion.findStartDestination import androidx.navigation.NavGraph.Companion.findStartDestination
import androidx.navigation.compose.currentBackStackEntryAsState import androidx.navigation.compose.currentBackStackEntryAsState
import com.zaneschepke.wireguardautotunnel.ui.Screen
@Composable @Composable
fun BottomNavBar(navController: NavController, bottomNavItems: List<BottomNavItem>) { fun BottomNavBar(navController: NavController, bottomNavItems: List<BottomNavItem>) {
val backStackEntry = navController.currentBackStackEntryAsState()
var showBottomBar by rememberSaveable { mutableStateOf(true) } var showBottomBar by rememberSaveable { mutableStateOf(true) }
val navBackStackEntry by navController.currentBackStackEntryAsState() val navBackStackEntry by navController.currentBackStackEntryAsState()
// TODO find a better way to hide nav bar showBottomBar = bottomNavItems.firstOrNull { navBackStackEntry?.destination?.route?.contains(it.route) == true } != null
showBottomBar =
when (navBackStackEntry?.destination?.route) {
Screen.Lock.route -> false
else -> true
}
NavigationBar(
containerColor = if (!showBottomBar) Color.Transparent else MaterialTheme.colorScheme.background,
) {
if(showBottomBar) { if(showBottomBar) {
NavigationBar(
containerColor = MaterialTheme.colorScheme.surface,
) {
bottomNavItems.forEach { item -> bottomNavItems.forEach { item ->
val selected = item.route == backStackEntry.value?.destination?.route val selected = navBackStackEntry?.destination?.route?.contains(item.route) == true
NavigationBarItem( NavigationBarItem(
selected = selected, selected = selected,
onClick = { onClick = {
if(navBackStackEntry?.destination?.route == item.route) return@NavigationBarItem
navController.navigate(item.route) { navController.navigate(item.route) {
// Pop up to the start destination of the graph to // Pop up to the start destination of the graph to
// avoid building up a large stack of destinations // avoid building up a large stack of destinations

View File

@ -110,7 +110,12 @@ fun ConfigScreen(
LaunchedEffect(uiState.loading) { LaunchedEffect(uiState.loading) {
if (!uiState.loading && context.isRunningOnTv()) { if (!uiState.loading && context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching {
focusRequester.requestFocus() focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }

View File

@ -144,7 +144,12 @@ fun MainScreen(
LaunchedEffect(Unit) { LaunchedEffect(Unit) {
if (context.isRunningOnTv()) { if (context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching {
focusRequester.requestFocus() focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }

View File

@ -88,7 +88,12 @@ fun OptionsScreen(
optionsViewModel.init(tunnelId) optionsViewModel.init(tunnelId)
if (context.isRunningOnTv()) { if (context.isRunningOnTv()) {
delay(Constants.FOCUS_REQUEST_DELAY) delay(Constants.FOCUS_REQUEST_DELAY)
kotlin.runCatching {
focusRequester.requestFocus() focusRequester.requestFocus()
}.onFailure {
delay(Constants.FOCUS_REQUEST_DELAY)
focusRequester.requestFocus()
}
} }
} }

View File

@ -282,7 +282,6 @@ fun SettingsScreen(
return return
} }
BackgroundLocationDialog( BackgroundLocationDialog(
showLocationDialog, showLocationDialog,
onDismiss = { showLocationDialog = false }, onDismiss = { showLocationDialog = false },

View File

@ -28,12 +28,7 @@ import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv import com.zaneschepke.wireguardautotunnel.util.extensions.isRunningOnTv
@Composable @Composable
fun BackgroundLocationDisclosure( fun BackgroundLocationDisclosure(onDismiss: () -> Unit, onAttest: () -> Unit, scrollState: ScrollState, focusRequester: FocusRequester) {
onDismiss: () -> Unit,
onAttest: () -> Unit,
scrollState: ScrollState,
focusRequester: FocusRequester,
) {
val context = LocalContext.current val context = LocalContext.current
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,

View File

@ -20,9 +20,10 @@ private val DarkColorScheme =
darkColorScheme( darkColorScheme(
// primary = Purple80, // primary = Purple80,
primary = virdigris, primary = virdigris,
secondary = virdigris, secondary = PurpleGrey40,
// secondary = PurpleGrey80, // secondary = PurpleGrey80,
tertiary = virdigris, tertiary = Pink40,
surfaceTint = Pink80,
// tertiary = Pink80 // tertiary = Pink80
) )
@ -31,6 +32,7 @@ private val LightColorScheme =
primary = Purple40, primary = Purple40,
secondary = PurpleGrey40, secondary = PurpleGrey40,
tertiary = Pink40, tertiary = Pink40,
surfaceTint = Pink80,
/* Other default colors to override /* Other default colors to override
background = Color(0xFFFFFBFE), background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE), surface = Color(0xFFFFFBFE),

View File

@ -24,6 +24,8 @@ object Constants {
const val SUBSCRIPTION_TIMEOUT = 5_000L const val SUBSCRIPTION_TIMEOUT = 5_000L
const val FOCUS_REQUEST_DELAY = 500L const val FOCUS_REQUEST_DELAY = 500L
const val TRANSITION_ANIMATION_TIME = 200
const val DEFAULT_PING_IP = "1.1.1.1" const val DEFAULT_PING_IP = "1.1.1.1"
const val PING_TIMEOUT = 5_000L const val PING_TIMEOUT = 5_000L
const val VPN_RESTART_DELAY = 1_000L const val VPN_RESTART_DELAY = 1_000L