fix: improve navigation animation speed
Fixes possible crashes on slow androidTVs Closes #49
This commit is contained in:
parent
528a1f84e4
commit
3f4673b2a7
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(
|
if(showBottomBar) {
|
||||||
containerColor = if (!showBottomBar) Color.Transparent else MaterialTheme.colorScheme.background,
|
NavigationBar(
|
||||||
) {
|
containerColor = MaterialTheme.colorScheme.surface,
|
||||||
if (showBottomBar) {
|
) {
|
||||||
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
|
||||||
|
|
|
@ -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)
|
||||||
focusRequester.requestFocus()
|
kotlin.runCatching {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}.onFailure {
|
||||||
|
delay(Constants.FOCUS_REQUEST_DELAY)
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
focusRequester.requestFocus()
|
kotlin.runCatching {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}.onFailure {
|
||||||
|
delay(Constants.FOCUS_REQUEST_DELAY)
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +267,7 @@ fun MainScreen(
|
||||||
reverseLayout = false,
|
reverseLayout = false,
|
||||||
flingBehavior = ScrollableDefaults.flingBehavior(),
|
flingBehavior = ScrollableDefaults.flingBehavior(),
|
||||||
) {
|
) {
|
||||||
if(uiState.tunnels.isEmpty()) {
|
if (uiState.tunnels.isEmpty()) {
|
||||||
item {
|
item {
|
||||||
GettingStartedLabel(onClick = { context.openWebUrl(it) })
|
GettingStartedLabel(onClick = { context.openWebUrl(it) })
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
focusRequester.requestFocus()
|
kotlin.runCatching {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}.onFailure {
|
||||||
|
delay(Constants.FOCUS_REQUEST_DELAY)
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,7 @@ fun SettingsScreen(
|
||||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
||||||
checkFineLocationGranted()
|
checkFineLocationGranted()
|
||||||
}
|
}
|
||||||
if(!uiState.isLocationDisclosureShown) {
|
if (!uiState.isLocationDisclosureShown) {
|
||||||
BackgroundLocationDisclosure(
|
BackgroundLocationDisclosure(
|
||||||
onDismiss = { viewModel.setLocationDisclosureShown() },
|
onDismiss = { viewModel.setLocationDisclosureShown() },
|
||||||
onAttest = {
|
onAttest = {
|
||||||
|
@ -282,7 +282,6 @@ fun SettingsScreen(
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BackgroundLocationDialog(
|
BackgroundLocationDialog(
|
||||||
showLocationDialog,
|
showLocationDialog,
|
||||||
onDismiss = { showLocationDialog = false },
|
onDismiss = { showLocationDialog = false },
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue