fix: AndroidTV D-pad control and banner
Fix Android TV D-pad access to elements on screen without reloading screen Update AndroidTV banner
This commit is contained in:
parent
9952e97e1c
commit
08d11a53b4
|
@ -17,7 +17,7 @@ android {
|
||||||
|
|
||||||
val versionMajor = 2
|
val versionMajor = 2
|
||||||
val versionMinor = 3
|
val versionMinor = 3
|
||||||
val versionPatch = 0
|
val versionPatch = 1
|
||||||
val versionBuild = 0
|
val versionBuild = 0
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings
|
import android.provider.Settings
|
||||||
|
import android.view.KeyEvent
|
||||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
|
@ -22,6 +23,9 @@ import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.focus.FocusRequester
|
||||||
|
import androidx.compose.ui.input.key.onKeyEvent
|
||||||
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
import com.google.accompanist.navigation.animation.AnimatedNavHost
|
||||||
import com.google.accompanist.navigation.animation.composable
|
import com.google.accompanist.navigation.animation.composable
|
||||||
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
import com.google.accompanist.navigation.animation.rememberAnimatedNavController
|
||||||
|
@ -40,6 +44,8 @@ import com.zaneschepke.wireguardautotunnel.ui.screens.support.SupportScreen
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.theme.TransparentSystemBars
|
import com.zaneschepke.wireguardautotunnel.ui.theme.TransparentSystemBars
|
||||||
import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme
|
import com.zaneschepke.wireguardautotunnel.ui.theme.WireguardAutoTunnelTheme
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class MainActivity : AppCompatActivity() {
|
class MainActivity : AppCompatActivity() {
|
||||||
|
@ -51,6 +57,8 @@ class MainActivity : AppCompatActivity() {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setContent {
|
setContent {
|
||||||
val navController = rememberAnimatedNavController()
|
val navController = rememberAnimatedNavController()
|
||||||
|
val focusRequester = remember { FocusRequester() }
|
||||||
|
|
||||||
WireguardAutoTunnelTheme {
|
WireguardAutoTunnelTheme {
|
||||||
TransparentSystemBars()
|
TransparentSystemBars()
|
||||||
|
|
||||||
|
@ -81,6 +89,24 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Scaffold(snackbarHost = { SnackbarHost(snackbarHostState)},
|
Scaffold(snackbarHost = { SnackbarHost(snackbarHostState)},
|
||||||
|
modifier = Modifier.onKeyEvent {
|
||||||
|
if (it.nativeKeyEvent.action == KeyEvent.ACTION_UP) {
|
||||||
|
when (it.nativeKeyEvent.keyCode) {
|
||||||
|
KeyEvent.KEYCODE_DPAD_UP -> {
|
||||||
|
try {
|
||||||
|
focusRequester.requestFocus()
|
||||||
|
} catch(e : IllegalStateException) {
|
||||||
|
Timber.e("No D-Pad focus request modifier added to element on screen")
|
||||||
|
}
|
||||||
|
false
|
||||||
|
} else -> {
|
||||||
|
false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
},
|
||||||
bottomBar = if (vpnIntent == null && notificationPermissionState.status.isGranted) {
|
bottomBar = if (vpnIntent == null && notificationPermissionState.status.isGranted) {
|
||||||
{ BottomNavBar(navController, Routes.navItems) }
|
{ BottomNavBar(navController, Routes.navItems) }
|
||||||
} else {
|
} else {
|
||||||
|
@ -126,7 +152,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) {
|
}) {
|
||||||
MainScreen(padding = padding, snackbarHostState = snackbarHostState, navController = navController)
|
MainScreen(padding = padding, snackbarHostState = snackbarHostState, navController = navController, focusRequester = focusRequester)
|
||||||
}
|
}
|
||||||
composable(Routes.Settings.name, enterTransition = {
|
composable(Routes.Settings.name, enterTransition = {
|
||||||
when (initialState.destination.route) {
|
when (initialState.destination.route) {
|
||||||
|
@ -147,7 +173,7 @@ class MainActivity : AppCompatActivity() {
|
||||||
fadeIn(animationSpec = tween(1000))
|
fadeIn(animationSpec = tween(1000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) { SettingsScreen(padding = padding, snackbarHostState = snackbarHostState, navController = navController) }
|
}) { SettingsScreen(padding = padding, snackbarHostState = snackbarHostState, navController = navController, focusRequester = focusRequester) }
|
||||||
composable(Routes.Support.name, enterTransition = {
|
composable(Routes.Support.name, enterTransition = {
|
||||||
when (initialState.destination.route) {
|
when (initialState.destination.route) {
|
||||||
Routes.Settings.name, Routes.Main.name ->
|
Routes.Settings.name, Routes.Main.name ->
|
||||||
|
@ -160,10 +186,10 @@ class MainActivity : AppCompatActivity() {
|
||||||
fadeIn(animationSpec = tween(1000))
|
fadeIn(animationSpec = tween(1000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}) { SupportScreen(padding = padding) }
|
}) { SupportScreen(padding = padding, focusRequester) }
|
||||||
composable("${Routes.Config.name}/{id}", enterTransition = {
|
composable("${Routes.Config.name}/{id}", enterTransition = {
|
||||||
fadeIn(animationSpec = tween(1000))
|
fadeIn(animationSpec = tween(1000))
|
||||||
}) { ConfigScreen(padding = padding, navController = navController, id = it.arguments?.getString("id"))}
|
}) { ConfigScreen(padding = padding, navController = navController, id = it.arguments?.getString("id"), focusRequester = focusRequester)}
|
||||||
composable("${Routes.Detail.name}/{id}", enterTransition = {
|
composable("${Routes.Detail.name}/{id}", enterTransition = {
|
||||||
fadeIn(animationSpec = tween(1000))
|
fadeIn(animationSpec = tween(1000))
|
||||||
}) { DetailScreen(padding = padding, id = it.arguments?.getString("id")) }
|
}) { DetailScreen(padding = padding, id = it.arguments?.getString("id")) }
|
||||||
|
|
|
@ -52,13 +52,13 @@ import kotlinx.coroutines.launch
|
||||||
fun ConfigScreen(
|
fun ConfigScreen(
|
||||||
viewModel: ConfigViewModel = hiltViewModel(),
|
viewModel: ConfigViewModel = hiltViewModel(),
|
||||||
padding: PaddingValues,
|
padding: PaddingValues,
|
||||||
|
focusRequester: FocusRequester,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
id : String?
|
id : String?
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val focusRequester = remember { FocusRequester() }
|
|
||||||
|
|
||||||
val keyboardController = LocalSoftwareKeyboardController.current
|
val keyboardController = LocalSoftwareKeyboardController.current
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
@ -228,10 +228,5 @@ fun ConfigScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
focusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -82,17 +82,17 @@ import com.zaneschepke.wireguardautotunnel.ui.theme.mint
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
@SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
|
||||||
@OptIn(ExperimentalMaterial3Api::class, ExperimentalComposeUiApi::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun MainScreen(
|
fun MainScreen(
|
||||||
viewModel: MainViewModel = hiltViewModel(), padding: PaddingValues,
|
viewModel: MainViewModel = hiltViewModel(), padding: PaddingValues,
|
||||||
|
focusRequester: FocusRequester,
|
||||||
snackbarHostState: SnackbarHostState, navController: NavController
|
snackbarHostState: SnackbarHostState, navController: NavController
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val haptic = LocalHapticFeedback.current
|
val haptic = LocalHapticFeedback.current
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val isVisible = rememberSaveable { mutableStateOf(true) }
|
val isVisible = rememberSaveable { mutableStateOf(true) }
|
||||||
val focusRequester = remember { FocusRequester() }
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
val sheetState = rememberModalBottomSheetState()
|
val sheetState = rememberModalBottomSheetState()
|
||||||
|
|
|
@ -80,12 +80,12 @@ fun SettingsScreen(
|
||||||
viewModel: SettingsViewModel = hiltViewModel(),
|
viewModel: SettingsViewModel = hiltViewModel(),
|
||||||
padding: PaddingValues,
|
padding: PaddingValues,
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
|
focusRequester: FocusRequester,
|
||||||
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
|
snackbarHostState: SnackbarHostState = remember { SnackbarHostState() }
|
||||||
) {
|
) {
|
||||||
|
|
||||||
val scope = rememberCoroutineScope()
|
val scope = rememberCoroutineScope()
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val focusRequester = remember { FocusRequester() }
|
|
||||||
val focusManager = LocalFocusManager.current
|
val focusManager = LocalFocusManager.current
|
||||||
val interactionSource = remember { MutableInteractionSource() }
|
val interactionSource = remember { MutableInteractionSource() }
|
||||||
|
|
||||||
|
@ -163,11 +163,6 @@ fun SettingsScreen(
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.turn_on))
|
Text(stringResource(id = R.string.turn_on))
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
focusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -192,11 +187,6 @@ fun SettingsScreen(
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.request))
|
Text(stringResource(id = R.string.request))
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
focusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -244,11 +234,6 @@ fun SettingsScreen(
|
||||||
}) {
|
}) {
|
||||||
Text(stringResource(id = R.string.check_again))
|
Text(stringResource(id = R.string.check_again))
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
focusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -282,11 +267,6 @@ fun SettingsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
LaunchedEffect(Unit) {
|
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
|
||||||
focusRequester.requestFocus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
stringResource(id = R.string.select_tunnel),
|
stringResource(id = R.string.select_tunnel),
|
||||||
|
|
|
@ -37,10 +37,9 @@ import androidx.compose.ui.unit.sp
|
||||||
import com.zaneschepke.wireguardautotunnel.R
|
import com.zaneschepke.wireguardautotunnel.R
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun SupportScreen(padding : PaddingValues) {
|
fun SupportScreen(padding : PaddingValues, focusRequester: FocusRequester) {
|
||||||
|
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
val focusRequester = remember { FocusRequester() }
|
|
||||||
|
|
||||||
fun openWebPage(url: String) {
|
fun openWebPage(url: String) {
|
||||||
val webpage: Uri = Uri.parse(url)
|
val webpage: Uri = Uri.parse(url)
|
||||||
|
@ -73,11 +72,11 @@ fun SupportScreen(padding : PaddingValues) {
|
||||||
}) {
|
}) {
|
||||||
Icon(imageVector = ImageVector.vectorResource(R.drawable.github), "Github")
|
Icon(imageVector = ImageVector.vectorResource(R.drawable.github), "Github")
|
||||||
}
|
}
|
||||||
LaunchedEffect(Unit) {
|
// LaunchedEffect(Unit) {
|
||||||
if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
// if(context.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
|
||||||
focusRequester.requestFocus()
|
// focusRequester.requestFocus()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
Spacer(modifier = Modifier.weight(1f))
|
Spacer(modifier = Modifier.weight(1f))
|
||||||
Text(stringResource(id = R.string.privacy_policy), style = TextStyle(textDecoration = TextDecoration.Underline),
|
Text(stringResource(id = R.string.privacy_policy), style = TextStyle(textDecoration = TextDecoration.Underline),
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.1 KiB After Width: | Height: | Size: 3.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 28 KiB |
Loading…
Reference in New Issue