瀏覽代碼

Created UI of select language on TV and added focus

Khubaib 8 月之前
父節點
當前提交
b0098143d1

+ 2 - 2
.idea/deploymentTargetSelector.xml

@@ -4,10 +4,10 @@
     <selectionStates>
       <SelectionState runConfigName="app">
         <option name="selectionMode" value="DROPDOWN" />
-        <DropdownSelection timestamp="2024-08-30T10:13:20.724208211Z">
+        <DropdownSelection timestamp="2024-08-30T10:29:54.285497104Z">
           <Target type="DEFAULT_BOOT">
             <handle>
-              <DeviceId pluginId="LocalEmulator" identifier="path=/home/ubuntu/.android/avd/Small_Phone_API_27.avd" />
+              <DeviceId pluginId="LocalEmulator" identifier="path=/home/ubuntu/.android/avd/Television_1080p_API_31.avd" />
             </handle>
           </Target>
         </DropdownSelection>

+ 7 - 3
app/src/main/java/com/vpn/fastestvpnservice/screens/bottomNavBarScreens/SettingsScreen.kt

@@ -17,6 +17,7 @@ import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.LocalOverscrollConfiguration
 import androidx.compose.foundation.background
+import androidx.compose.foundation.focusable
 import androidx.compose.foundation.gestures.detectTapGestures
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.foundation.layout.Arrangement
@@ -1184,7 +1185,7 @@ fun SelectLanguage(
                         color = MaterialTheme.colorScheme.primary,
                         bottomPadding = 20.dp,
                         startPadding = 16.dp,
-                        style = MaterialTheme.typography.titleSmall
+                        style = MaterialTheme.typography.titleSmall,
                     )
                     languages.forEach { language ->
 
@@ -1622,13 +1623,16 @@ fun ColumnScope.AddTextSettings(
     color: Color,
     bottomPadding: Dp = 0.dp,
     startPadding: Dp = 0.dp,
-    style: TextStyle
+    style: TextStyle,
+    isFocusable:Boolean = false
 ) {
     Text(
         text = text,
         style = style,
         color = color,
-        modifier = Modifier.padding(bottom = bottomPadding, start = startPadding)
+        modifier = Modifier
+            .padding(bottom = bottomPadding, start = startPadding)
+            .focusable(isFocusable)
     )
 }
 

+ 252 - 9
app/src/main/java/com/vpn/fastestvpnservice/screensTV/SettingsScreenTV.kt

@@ -1,12 +1,16 @@
 package com.vpn.fastestvpnservice.screensTV
 
 import android.app.Activity
+import android.app.LocaleManager
 import android.content.Context
 import android.content.Intent
+import android.os.Build
 import android.os.Bundle
 import android.os.Handler
+import android.os.LocaleList
 import android.util.Log
 import androidx.activity.compose.BackHandler
+import androidx.appcompat.app.AppCompatDelegate
 import androidx.compose.foundation.ExperimentalFoundationApi
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.LocalOverscrollConfiguration
@@ -34,6 +38,8 @@ import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.material.icons.Icons
 import androidx.compose.material.icons.filled.DarkMode
+import androidx.compose.material.icons.filled.Language
+import androidx.compose.material3.BottomSheetDefaults
 import androidx.compose.material3.DockedSearchBar
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
@@ -85,12 +91,14 @@ import androidx.compose.ui.unit.TextUnit
 import androidx.compose.ui.unit.dp
 import androidx.compose.ui.unit.sp
 import androidx.core.content.ContextCompat
+import androidx.core.os.LocaleListCompat
 import androidx.lifecycle.viewmodel.compose.viewModel
 import androidx.navigation.NavHostController
 import androidx.navigation.compose.currentBackStackEntryAsState
 import com.vpn.fastestvpnservice.R
 import com.vpn.fastestvpnservice.beans.Protocol
 import com.vpn.fastestvpnservice.beans.isDarkTheme
+import com.vpn.fastestvpnservice.beans.languages
 import com.vpn.fastestvpnservice.beans.themesList
 import com.vpn.fastestvpnservice.constants.AppEnum
 import com.vpn.fastestvpnservice.constants.smartConnect
@@ -117,6 +125,7 @@ import com.vpn.fastestvpnservice.viewmodels.SplashViewModel
 import de.blinkt.openvpn.core.App
 import kotlinx.coroutines.delay
 import kotlinx.coroutines.launch
+import java.util.Locale
 
 @OptIn(ExperimentalFoundationApi::class)
 @Composable
@@ -195,7 +204,8 @@ fun SettingsTV(navHostController: NavHostController) {
                     text = "Settings",
                     size = 28.sp,
                     color = MaterialTheme.colorScheme.primary,
-                    style = MaterialTheme.typography.headlineLarge
+                    style = MaterialTheme.typography.headlineLarge,
+                    isfocusable = true
                 )
                 Spacer(modifier = Modifier.height(22.dp))
 
@@ -244,7 +254,12 @@ fun SettingsTV(navHostController: NavHostController) {
                 )
                 AddRowDarkLightThemeTV(
                     icon = Icons.Default.DarkMode,
-                    text = "Appearance")
+                    text = "Appearance"
+                )
+                AddLanguageTV(
+                    icon = Icons.Default.Language,
+                    text = "Language"
+                )
             }
         }
     }
@@ -372,13 +387,15 @@ fun ColumnScope.AddTextSettingsTV(
     color: Color,
     bottomPadding: Dp = 0.dp,
     startPadding: Dp = 0.dp,
-    style: TextStyle
+    style: TextStyle,
+    isfocusable: Boolean = false
 ) {
     Text(
         text = text,
         style = style,
         color = color,
         modifier = Modifier.padding(bottom = bottomPadding, start = startPadding)
+            .focusable(isfocusable)
     )
 }
 
@@ -1181,12 +1198,9 @@ fun AddRowDarkLightThemeTV(
             .clickable {
                 isThemeSheetOpen = true
             }
-            .onKeyEvent {
-                if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
-                    isSecondItemPressed.value = true
-                }
-                false
-            }
+//            .onKeyEvent {
+//                false
+//            }
             .height(61.dp),
         horizontalArrangement = Arrangement.Start,
         verticalAlignment = Alignment.CenterVertically
@@ -1347,4 +1361,233 @@ fun AddRowDarkLightThemeTV(
             }
         }
     }
+}
+
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun AddLanguageTV(
+    icon: ImageVector,
+    text: String,
+) {
+    var isRowFocused by remember { mutableStateOf(false) }
+    var isButtonFocused by remember { mutableStateOf(false) }
+    var isAnyItemFocused by remember { mutableStateOf(false) }
+    var isLanguageSheetOpen by remember { mutableStateOf(false) }
+    var isSelectedLanguage by remember { mutableStateOf(languages[0]) }
+    val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
+    val context = LocalContext.current
+    val basePreferenceHelper = BasePreferenceHelper(context)
+    var selectedLanguage by remember { mutableStateOf(basePreferenceHelper.getLanguage()) }
+
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(top = 5.dp, end = 27.dp)
+            .clip(RoundedCornerShape(4.dp))
+            .background(
+                if (isRowFocused) MaterialTheme.colorScheme.inverseOnSurface
+                else MaterialTheme.colorScheme.onBackground
+            )
+            .onFocusChanged {
+                isRowFocused = it.isFocused
+            }
+            .focusable()
+            .clickable {
+                isLanguageSheetOpen = true
+            }
+            .onKeyEvent {
+                if (it.type == KeyEventType.KeyDown && it.key == Key.DirectionDown) {
+                    isSecondItemPressed.value = true
+                }
+                false
+            }
+            .height(61.dp),
+        horizontalArrangement = Arrangement.Start,
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+
+        Surface(
+            modifier = Modifier.padding(start = 20.dp),
+            color = Color.Transparent
+        ) {
+            Image(
+                imageVector = icon,
+                contentDescription = "Select Theme",
+                modifier = Modifier
+                    .padding(start = 0.dp)
+                    .size(24.dp)
+                    .weight(1f),
+                colorFilter = ColorFilter.tint(
+                    MaterialTheme.colorScheme.primary)                )
+        }
+
+        Surface(
+            modifier = Modifier.padding(start = 18.dp),
+            color = Color.Transparent
+        ) {
+            Text(text = text,
+                style = MaterialTheme.typography.titleMedium,
+                color = MaterialTheme.colorScheme.primary,
+                maxLines = 1,
+                modifier = Modifier
+                    .padding(start = 0.dp, end = 0.dp)
+                    .weight(1f)
+            )
+        }
+        Spacer(modifier = Modifier.weight(1f))
+
+        Surface(
+            modifier = Modifier
+                .padding(end = 20.dp)
+                .align(Alignment.CenterVertically),
+            color = Color.Transparent
+
+        ) {
+            Image(
+                painter = painterResource(id = R.drawable.frontarrow3x),
+                contentDescription = "Front_Arrow",
+                modifier = Modifier
+                    .padding(start = 0.dp, end = 3.dp)
+                    .size(10.dp, 18.dp)
+                    .weight(1f),
+                colorFilter = ColorFilter.tint(
+                    MaterialTheme.colorScheme.primary
+                )
+            )
+        }
+
+    }
+
+    if (isLanguageSheetOpen) {
+        ModalBottomSheet(
+            onDismissRequest = { isLanguageSheetOpen = false
+            },
+            dragHandle = {
+                BottomSheetDefaults.DragHandle(
+                    color = MaterialTheme.colorScheme.primary,
+                )
+            },
+            sheetState = sheetState,
+            containerColor = MaterialTheme.colorScheme.onBackground,
+            modifier = Modifier
+                .padding(top = 15.dp)
+                .fillMaxSize()
+        ) {
+            Box(
+                modifier = Modifier
+                    .background(Color.Transparent)
+                    .fillMaxSize()
+                    .padding(start = 0.dp, top = 10.dp, bottom = 20.dp),
+            ) {
+                Column(
+                    verticalArrangement = Arrangement.Top,
+                    horizontalAlignment = Alignment.Start,
+                    modifier = Modifier
+                        .verticalScroll(rememberScrollState())
+                        .padding(bottom = 10.dp)
+                ) {
+                    AddTextSettings(
+                        text = context.getString(R.string.language),
+                        size = 18.sp,
+                        color = MaterialTheme.colorScheme.primary,
+                        bottomPadding = 20.dp,
+                        startPadding = 16.dp,
+                        style = MaterialTheme.typography.titleSmall,
+                        isFocusable = true
+                    )
+                    languages.forEach { language ->
+                        isButtonFocused = isSelectedLanguage == language
+                        Row(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .background(
+                                    if (isButtonFocused && isAnyItemFocused) MaterialTheme.colorScheme.inverseOnSurface
+                                    else Color.Transparent
+                                )
+                                .padding(start = 2.dp)
+                                .onFocusChanged {
+                                    if (it.isFocused) {
+                                        isSelectedLanguage = language
+                                    }
+                                    isAnyItemFocused = it.isFocused
+                                }
+                                .selectable(
+                                    selected = language.name == selectedLanguage,
+                                    onClick = {
+                                        selectedLanguage = language.name
+                                        basePreferenceHelper.saveLanguage(selectedLanguage)
+
+                                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                                            context.getSystemService(LocaleManager::class.java).applicationLocales =
+                                                LocaleList.forLanguageTags(language.code)
+                                        } else {
+                                            AppCompatDelegate.setApplicationLocales(
+                                                LocaleListCompat.forLanguageTags(
+                                                    language.code
+                                                )
+                                            )
+                                            context.resources.updateConfiguration(
+                                                context.resources.configuration.apply {
+                                                    setLocale(Locale.forLanguageTag(language.code))
+                                                },
+                                                context.resources.displayMetrics
+                                            )
+//                                            changeLanguage(context.getString(R.string.settings))
+                                        }
+                                        isLanguageSheetOpen = false
+                                    },
+                                )
+//                                    .indication(
+//                                        indication = null,
+//                                        interactionSource = remember {
+//                                            MutableInteractionSource()
+//                                        }
+//                                    )
+                            ,
+                            verticalAlignment = Alignment.CenterVertically
+                        ) {
+//                            val themeState = isSystemInDarkTheme()
+//                            val isSystemInDarkTheme by remember { mutableStateOf(themeState) }
+                            RadioButton(
+                                selected = language.name == selectedLanguage,
+                                onClick = {
+                                    selectedLanguage = language.name
+                                    basePreferenceHelper.saveLanguage(selectedLanguage)
+
+                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                                        context.getSystemService(LocaleManager::class.java).applicationLocales =
+                                            LocaleList.forLanguageTags(language.code)
+                                    }
+                                    else {
+                                        AppCompatDelegate.setApplicationLocales(
+                                            LocaleListCompat.forLanguageTags(
+                                                language.code
+                                            )
+                                        )
+                                        context.resources.updateConfiguration(
+                                            context.resources.configuration.apply {
+                                                setLocale(Locale.forLanguageTag(language.code))
+                                            },
+                                            context.resources.displayMetrics
+                                        )
+//                                        changeLanguage(context.getString(R.string.settings))
+                                    }
+                                    isLanguageSheetOpen = false
+                                },
+                                colors = RadioButtonDefaults.colors(
+                                    selectedColor = colorResource(id = R.color.radio_button_blue),
+                                    unselectedColor = colorResource(id = R.color.gray_icon),
+                                )
+                            )
+                            Text(text = language.name,
+                                modifier = Modifier.padding(start = 12.dp),
+                                style = MaterialTheme.typography.bodySmall,
+                                color = MaterialTheme.colorScheme.primary
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
 }

+ 1 - 1
app/src/main/res/values-ja/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Japan-ja) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">安全。速い。安定しています。</string>

+ 1 - 1
app/src/main/res/values-nl/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Netherland-nl) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">Beveiligd. Snel. Stabiel.</string>

+ 1 - 1
app/src/main/res/values-pt/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Portuguese-pt) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">Seguro. Rápido. Estável.</string>

+ 1 - 1
app/src/main/res/values-sv/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Swedish-sv) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">Säkert. Snabb. Stabil.</string>

+ 1 - 1
app/src/main/res/values-tr/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Turkish-tr) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">Güvenli. Hızlı. Kararlı.</string>

+ 1 - 1
app/src/main/res/values-zh-rCN/strings.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
 
-    <!-- Multi Lingual - (English-en) -->
+    <!-- Multi Lingual - (Chinese-zh-CN) -->
 
     <!-- Started Screen -->
     <string name="secure_fast">安全。快速地。稳定。</string>