Przeglądaj źródła

working on custom navigation on TV

Khubaib 9 miesięcy temu
rodzic
commit
14886d32ce

+ 306 - 0
app/src/main/java/com/vpn/fastestvpnservice/navigation/CustomBottomBarTV.kt

@@ -0,0 +1,306 @@
+package com.vpn.fastestvpnservice.navigation
+
+import android.util.Log
+import androidx.activity.ComponentActivity
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.focusable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material.Surface
+import androidx.compose.material3.Icon
+import androidx.compose.material3.Scaffold
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.MutableState
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableIntStateOf
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.remember
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
+import androidx.compose.ui.focus.FocusRequester
+import androidx.compose.ui.focus.focusRequester
+import androidx.compose.ui.focus.onFocusChanged
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.unit.dp
+import androidx.navigation.NavGraph.Companion.findStartDestination
+import androidx.navigation.NavHostController
+import androidx.navigation.compose.currentBackStackEntryAsState
+import androidx.navigation.compose.rememberNavController
+import com.vpn.fastestvpnservice.R
+import com.vpn.fastestvpnservice.screensTV.BottomBarTV
+import com.vpn.fastestvpnservice.sealedClass.BottomBarScreen
+import com.vpn.fastestvpnservice.utils.StaticMethods
+import com.vpn.fastestvpnservice.utils.isTablet
+
+val screens = listOf(
+    BottomBarScreen.Home,
+    BottomBarScreen.Settings,
+    BottomBarScreen.Help,
+    BottomBarScreen.Account
+)
+
+var isHomeScreenPressed: MutableState<Boolean> = mutableStateOf(true)
+var isSettingsScreenPressed: MutableState<Boolean> = mutableStateOf(false)
+var isHelpScreenPressed: MutableState<Boolean> = mutableStateOf(false)
+var isAccountScreenPressed: MutableState<Boolean> = mutableStateOf(false)
+
+var selectedItemIndex: MutableState<Int> = mutableIntStateOf(0)
+
+var isFirstItemPressed: MutableState<Boolean> = mutableStateOf(false)
+
+@Composable
+fun CustomBottomBarTV(navHostController: NavHostController, activity: ComponentActivity) {
+    val navController1 = rememberNavController()
+    var isBottomBarVisible by remember { mutableStateOf(true) }
+//    var selectedItemIndex by remember { mutableIntStateOf(0) }
+    var focusRequestersList = remember { List(screens.size) { FocusRequester() } }
+
+    navController1.addOnDestinationChangedListener { _,_,_ ->
+        isBottomBarVisible = navController1.currentDestination?.route in listOf(
+            screens[0].route, screens[1].route, screens[2].route, screens[3].route)
+    }
+
+    Scaffold (
+        modifier = Modifier.fillMaxSize(),
+        bottomBar = {
+            if (isBottomBarVisible) {
+                BottomBarNavTV(
+                    navHostController = navController1,
+                    screens = screens
+                )
+            }
+        },
+        content = { padding ->
+            Box(modifier = Modifier.padding(padding)) {
+                BottomBarNavGraphTV(
+                    navHostController = navController1,
+                    settingsNavHostController = navHostController,
+                    activity
+                )
+            }
+        }
+    )
+}
+
+@Composable
+fun BottomBarNavTV(
+    navHostController: NavHostController,
+    screens: List<BottomBarScreen>
+) {
+    var isFirstItemFocused by remember { mutableStateOf(false) }
+    var isSecondItemFocused by remember { mutableStateOf(false) }
+    var isThirdItemFocused by remember { mutableStateOf(false) }
+    var isFourthItemFocused by remember { mutableStateOf(false) }
+    val focusRequester1 = remember { FocusRequester() }
+    var isClicked by remember { mutableStateOf(false) }
+    val navBackStackEntry = navHostController.currentBackStackEntryAsState()
+    var currentDestination = navBackStackEntry.value?.destination
+    var screen: BottomBarScreen = BottomBarScreen.Home
+
+    when (selectedItemIndex.value) {
+        0 -> {
+            screen = BottomBarScreen.Home
+        }
+        1 -> {
+            screen = BottomBarScreen.Settings
+        }
+        2 -> {
+            screen = BottomBarScreen.Help
+        }
+        3 -> {
+            screen = BottomBarScreen.Account
+        }
+    }
+
+    if (isClicked) {
+        Log.d("test_bottom_navbar",
+            "Before:: currentDestination -> " + currentDestination?.route + " -> " + screen.route + " " + selectedItemIndex.value
+        )
+        if (currentDestination?.route != screen.route) {
+            Log.d("test_bottom_navbar",
+                "currentDestination -> " + currentDestination?.route
+                        + "Screen Clicked -> " + screen.route
+            )
+
+            LaunchedEffect(Unit) {
+                navHostController.navigate(screen.route)
+                {
+                    popUpTo(
+                        navHostController.graph
+                            .findStartDestination().id) {
+                        saveState = true
+                    }
+                    launchSingleTop = true
+                }
+            }
+        }
+        isClicked = false
+    }
+
+    if (isFirstItemPressed.value) {
+        LaunchedEffect(key1 = Unit) {
+            focusRequester1.requestFocus()
+        }
+        isFirstItemPressed.value = false
+    }
+
+    Box(
+        modifier = Modifier
+            .fillMaxWidth()
+            .background(colorResource(id = R.color.background_color_gray)),
+        contentAlignment = Alignment.Center
+    ) {
+        Row(
+            modifier = Modifier
+                .height(60.dp)
+                .fillMaxWidth(fraction = 0.5f)
+                .background(colorResource(id = R.color.background_color_gray)),
+            horizontalArrangement = Arrangement.SpaceEvenly,
+            verticalAlignment = Alignment.CenterVertically
+        ) {
+            Surface(
+                color = if (isFirstItemFocused) Color.LightGray
+                else colorResource(id = R.color.background_color_gray),
+                modifier = Modifier
+                    .focusRequester(focusRequester1)
+                    .onFocusChanged {
+                        Log.d("is_focused","1st")
+                        isFirstItemFocused = it.isFocused
+
+                        if (it.isFocused) {
+                            Log.d("is_focused","1st if")
+                            selectedItemIndex.value = 0
+                            isClicked = true
+                        }
+
+                    }
+                    .focusable()
+                    .clickable {
+                        isHomeScreenPressed.value = true
+                    }
+            ) {
+                val color = if (selectedItemIndex.value == 0) colorResource(id = R.color.blue_text)
+                else colorResource(id = R.color.dark_blue_gray_text)
+                val alpha = if (selectedItemIndex.value == 0) 1f else 0.5f
+                Icon(
+                    painter = painterResource(id = screens[0].icon),
+                    contentDescription = "Navigation Icon",
+                    tint = color,
+                    modifier = Modifier
+                        .size(55.dp, 55.dp)
+                        .padding(top = 9.dp, bottom = 4.dp)
+                        .alpha(alpha)
+                )
+            }
+            Surface(
+                color = if (isSecondItemFocused) Color.LightGray else colorResource(id = R.color.background_color_gray),
+                modifier = Modifier
+                    .onFocusChanged {
+                        Log.d("is_focused","2nd")
+                        isSecondItemFocused = it.isFocused
+
+                        if (it.isFocused) {
+                            Log.d("is_focused","2nd if")
+                            selectedItemIndex.value = 1
+                            isClicked = true
+                        }
+
+                    }
+                    .focusable()
+                    .clickable {
+                        isSettingsScreenPressed.value = true
+                    }
+            ) {
+                val color = if (selectedItemIndex.value == 1) colorResource(id = R.color.blue_text)
+                else colorResource(id = R.color.dark_blue_gray_text)
+                val alpha = if (selectedItemIndex.value == 1) 1f else 0.5f
+                Icon(
+                    painter = painterResource(id = screens[1].icon),
+                    contentDescription = "Navigation Icon",
+                    tint = color,
+                    modifier = Modifier
+                        .size(55.dp, 55.dp)
+                        .padding(top = 9.dp, bottom = 4.dp)
+                        .alpha(alpha)
+                )
+            }
+            Surface(
+                color = if (isThirdItemFocused) Color.LightGray else
+                    colorResource(id = R.color.background_color_gray),
+                modifier = Modifier
+                    .onFocusChanged {
+                        Log.d("is_focused","3rd")
+                        isThirdItemFocused = it.isFocused
+
+                        if (it.isFocused) {
+                            Log.d("is_focused","3rd if")
+                            selectedItemIndex.value = 2
+                            isClicked = true
+                        }
+
+                    }
+                    .focusable()
+                    .clickable {
+                        isHelpScreenPressed.value = true
+                    }
+            ) {
+                val color = if (selectedItemIndex.value == 2) colorResource(id = R.color.blue_text)
+                else colorResource(id = R.color.dark_blue_gray_text)
+                val alpha = if (selectedItemIndex.value == 2) 1f else 0.5f
+                Icon(
+                    painter = painterResource(id = screens[2].icon),
+                    contentDescription = "Navigation Icon",
+                    tint = color,
+                    modifier = Modifier
+                        .size(55.dp, 55.dp)
+                        .padding(top = 9.dp, bottom = 4.dp)
+                        .alpha(alpha)
+                )
+            }
+            Surface(
+                color = if (isFourthItemFocused) Color.LightGray else
+                    colorResource(id = R.color.background_color_gray),
+                modifier = Modifier
+                    .onFocusChanged {
+                        Log.d("is_focused","4th")
+                        isFourthItemFocused = it.isFocused
+                        if (it.isFocused) {
+                            Log.d("is_focused","4th if")
+                            selectedItemIndex.value = 3
+                            isClicked = true
+                        }
+
+                    }
+                    .focusable()
+                    .clickable {
+                        isAccountScreenPressed.value = true
+                    }
+            ) {
+                val color = if (selectedItemIndex.value == 3) colorResource(id = R.color.blue_text)
+                else colorResource(id = R.color.dark_blue_gray_text)
+                val alpha = if (selectedItemIndex.value == 3) 1f else 0.5f
+                Icon(
+                    painter = painterResource(id = screens[3].icon),
+                    contentDescription = "Navigation Icon",
+                    tint = color,
+                    modifier = Modifier
+                        .size(55.dp, 55.dp)
+                        .padding(top = 9.dp, bottom = 4.dp)
+                        .alpha(alpha)
+                )
+            }
+        }
+    }
+}

+ 1 - 1
app/src/main/java/com/vpn/fastestvpnservice/navigation/NavGraphTV.kt

@@ -51,7 +51,7 @@ fun SetUpNavGraphTV(navHostController: NavHostController, activity: ComponentAct
             HomeTV(navHostController = navHostController)
         }
         composable(route =  ScreenTV.BottomBarTV.route) {
-            BottomBarMainScreenTV(navHostController = navHostController, activity)
+            CustomBottomBarTV(navHostController = navHostController, activity)
         }
     }
 }

+ 1 - 0
app/src/main/java/com/vpn/fastestvpnservice/screensTV/AccountScreenTV.kt

@@ -70,6 +70,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation.NavHostController
 import com.vpn.fastestvpnservice.R
 import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
+import com.vpn.fastestvpnservice.navigation.isAccountScreenPressed
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.LogoutDialog
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.act
 import com.vpn.fastestvpnservice.sealedClass.Screen

+ 4 - 16
app/src/main/java/com/vpn/fastestvpnservice/screensTV/BottomBarMainScreenTV.kt

@@ -1,10 +1,8 @@
 package com.vpn.fastestvpnservice.screensTV
 
 import android.util.Log
-import android.widget.Toast
 import androidx.activity.ComponentActivity
 import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
 import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.RowScope
@@ -19,7 +17,6 @@ import androidx.compose.material3.Icon
 import androidx.compose.material3.Scaffold
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableIntStateOf
 import androidx.compose.runtime.mutableStateOf
@@ -32,9 +29,6 @@ import androidx.compose.ui.focus.FocusRequester
 import androidx.compose.ui.focus.focusRequester
 import androidx.compose.ui.focus.onFocusChanged
 import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.key.Key
-import androidx.compose.ui.input.key.key
-import androidx.compose.ui.input.key.onKeyEvent
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.colorResource
 import androidx.compose.ui.res.painterResource
@@ -47,7 +41,10 @@ import androidx.navigation.compose.currentBackStackEntryAsState
 import androidx.navigation.compose.rememberNavController
 import com.vpn.fastestvpnservice.R
 import com.vpn.fastestvpnservice.navigation.BottomBarNavGraphTV
-import com.vpn.fastestvpnservice.navigation.customNavigation
+import com.vpn.fastestvpnservice.navigation.isAccountScreenPressed
+import com.vpn.fastestvpnservice.navigation.isHelpScreenPressed
+import com.vpn.fastestvpnservice.navigation.isHomeScreenPressed
+import com.vpn.fastestvpnservice.navigation.isSettingsScreenPressed
 import com.vpn.fastestvpnservice.sealedClass.BottomBarScreen
 import com.vpn.fastestvpnservice.utils.StaticMethods
 import com.vpn.fastestvpnservice.utils.isTablet
@@ -61,12 +58,6 @@ val screens = listOf(
 val focusRequesterNav1 = FocusRequester()
 val focusRequesterSettings1 = FocusRequester()
 
-var isHomeScreenPressed: MutableState<Boolean> = mutableStateOf(true)
-var isSettingsScreenPressed: MutableState<Boolean> = mutableStateOf(false)
-var isHelpScreenPressed: MutableState<Boolean> = mutableStateOf(false)
-var isAccountScreenPressed: MutableState<Boolean> = mutableStateOf(false)
-
-
 @Composable
 fun BottomBarMainScreenTV(navHostController: NavHostController, activity: ComponentActivity) {
     val navController1 = rememberNavController()
@@ -141,7 +132,6 @@ fun BottomBarTV(
                 .height(if (StaticMethods.isTV(context)) 60.dp else if (isTablet()) 150.dp else 110.dp)
                 .fillMaxWidth(fraction = 0.5f)
                 .background(Color.LightGray)
-
         ) {
             screens.forEachIndexed { index, screen ->
                 AddItemTV(
@@ -163,8 +153,6 @@ fun BottomBarTV(
     }
 }
 
-
-
 @Composable
 fun RowScope.AddItemTV(
     screen: BottomBarScreen,

+ 1 - 0
app/src/main/java/com/vpn/fastestvpnservice/screensTV/HelpScreenTV.kt

@@ -58,6 +58,7 @@ import androidx.core.view.WindowCompat
 import androidx.navigation.NavHostController
 import com.vpn.fastestvpnservice.R
 import com.vpn.fastestvpnservice.beans.isDarkTheme
+import com.vpn.fastestvpnservice.navigation.isHelpScreenPressed
 import com.vpn.fastestvpnservice.sealedClass.Screen
 
 @OptIn(ExperimentalFoundationApi::class)

+ 13 - 29
app/src/main/java/com/vpn/fastestvpnservice/screensTV/HomeScreenTV.kt

@@ -78,6 +78,8 @@ import com.vpn.fastestvpnservice.constants.AppEnum
 import com.vpn.fastestvpnservice.constants.smartConnect
 import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
 import com.vpn.fastestvpnservice.navigation.customNavigation
+import com.vpn.fastestvpnservice.navigation.isFirstItemPressed
+import com.vpn.fastestvpnservice.navigation.isHomeScreenPressed
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.AddRowSelectServer
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.AddText
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.ColumnText
@@ -556,35 +558,17 @@ fun HomeTV(navHostController: NavHostController) {
                         .padding(horizontal = 20.dp, vertical = 5.dp)
                         .padding(top = 0.dp)
                         .height(60.dp)
-//                        .onKeyEvent {
-////                            when (it.key) {
-////                                Key.DirectionDown -> {
-////                                    Log.d("test_settings_keys", "DirectionDown")
-////                                    Toast
-////                                        .makeText(
-////                                            context, "DirectionDown", Toast.LENGTH_SHORT
-////                                        )
-////                                        .show()
-////                                    customNavigation(navHostController, BottomBarScreen.Settings)
-//////                                    focusRequesterNav1.requestFocus()
-////                                    true
-////                                }
-////                                Key.DirectionRight -> { true}
-////                                Key.DirectionLeft -> { true}
-////                                else -> { false }
-////                            }
-//                                if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
-//                                    Toast
-//                                        .makeText(
-//                                            context, "KeyDown & DirectionDown", Toast.LENGTH_SHORT
-//                                        )
-//                                        .show()
-////                                    customNavigation(navHostController, BottomBarScreen.Home)
-////                                    focusRequesterNav1.requestFocus()
-////                                    focusRequestersList[selectedItemIndex.value].requestFocus()
-//                                    true
-//                                } else { true }
-//                        }
+                        .onKeyEvent {
+                                if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
+                                    Toast
+                                        .makeText(
+                                            context, "KeyDown & DirectionDown", Toast.LENGTH_SHORT
+                                        )
+                                        .show()
+                                    isFirstItemPressed.value = true
+                                    true
+                                } else { false }
+                        }
                         .onFocusChanged {
                             isLayoutFocused = it.isFocused
                         }

+ 1 - 0
app/src/main/java/com/vpn/fastestvpnservice/screensTV/SettingsScreenTV.kt

@@ -94,6 +94,7 @@ import com.vpn.fastestvpnservice.constants.smartConnect
 import com.vpn.fastestvpnservice.customItems.ServerSpecificItem
 import com.vpn.fastestvpnservice.helpers.BasePreferenceHelper
 import com.vpn.fastestvpnservice.navigation.customNavigation
+import com.vpn.fastestvpnservice.navigation.isSettingsScreenPressed
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.AddTextSettings
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.getAvailableProtocols
 import com.vpn.fastestvpnservice.screens.bottomNavBarScreens.vpnConnectionsUtil