Browse Source

Worked on multi lingual, added 4 languages and working on it, created separate each resource qualifiers for each language, uptil now when selecting any language, settings heading text changes

Khubaib 10 tháng trước cách đây
mục cha
commit
1865354d44

+ 1 - 1
.idea/deploymentTargetSelector.xml

@@ -4,7 +4,7 @@
     <selectionStates>
       <SelectionState runConfigName="app">
         <option name="selectionMode" value="DROPDOWN" />
-        <DropdownSelection timestamp="2024-08-08T16:58:59.461731583Z">
+        <DropdownSelection timestamp="2024-08-09T10:30:45.536311501Z">
           <Target type="DEFAULT_BOOT">
             <handle>
               <DeviceId pluginId="LocalEmulator" identifier="path=/home/ubuntu/.android/avd/Television_1080p_API_31.avd" />

+ 12 - 0
app/src/main/AndroidManifest.xml

@@ -39,6 +39,7 @@
         android:supportsRtl="true"
         android:theme="@style/Theme.AppCompat.Light.NoActionBar.App"
         android:usesCleartextTraffic="true"
+        android:localeConfig="@xml/locales_config"
         tools:targetApi="31">
         <activity
             android:name=".activities.HomeActivityTV"
@@ -54,6 +55,7 @@
             android:exported="true"
             android:label="@string/app_name"
             android:launchMode="singleTop"
+            android:configChanges="locale|layoutDirection"
             android:theme="@style/Theme.AppCompat.Light.NoActionBar.App">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -168,6 +170,16 @@
             android:enabled="true"
             android:exported="true"
             android:foregroundServiceType="specialUse" />
+
+        <service
+            android:name="androidx.appcompat.app.AppLocalesMetadataHolderService"
+            android:enabled="false"
+            android:exported="false">
+            <meta-data
+                android:name="autoStoreLocales"
+                android:value="true" />
+        </service>
+
     </application>
 
 </manifest>

+ 3 - 0
app/src/main/java/com/vpn/fastestvpnservice/MainActivity.kt

@@ -1,5 +1,6 @@
 package com.vpn.fastestvpnservice
 
+import android.app.LocaleManager
 import android.content.Context
 import android.content.Intent
 import android.content.pm.ActivityInfo
@@ -8,6 +9,7 @@ import android.content.pm.PackageManager
 import android.net.Uri
 import android.os.Build
 import android.os.Bundle
+import android.os.LocaleList
 import android.util.Log
 import android.view.WindowInsets
 import android.view.WindowInsetsController
@@ -15,6 +17,7 @@ import android.view.WindowManager
 import android.widget.Toast
 import androidx.activity.compose.setContent
 import androidx.activity.viewModels
+import androidx.annotation.RequiresApi
 import androidx.compose.foundation.isSystemInDarkTheme
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.mutableStateOf

+ 6 - 1
app/src/main/java/com/vpn/fastestvpnservice/beans/Dark_Light_Theme.kt

@@ -4,7 +4,12 @@ import androidx.compose.runtime.MutableState
 import androidx.compose.runtime.mutableStateOf
 
 val themesList = listOf<String>(
-    "System Default", "Light Theme", "Dark Theme"
+    "System Default", "Light Mode", "Dark Mode"
+)
+
+val languages = listOf<Language>(
+    Language("English","en"), Language("French","fr"),
+    Language("German","de"), Language("Turkish","tr")
 )
 
 var isDarkTheme: MutableState<Boolean> = mutableStateOf(false)

+ 4 - 0
app/src/main/java/com/vpn/fastestvpnservice/beans/Protocol.kt

@@ -3,3 +3,7 @@ package com.vpn.fastestvpnservice.beans
 class Protocol(
     var full_name:String, var title: String, var index: Int
 )
+
+class Language(
+    var name:String, var code:String
+)

+ 186 - 2
app/src/main/java/com/vpn/fastestvpnservice/screens/bottomNavBarScreens/SettingsScreen.kt

@@ -1,11 +1,13 @@
 package com.vpn.fastestvpnservice.screens.bottomNavBarScreens
 
 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 android.widget.Toast
 import androidx.compose.foundation.ExperimentalFoundationApi
@@ -33,6 +35,7 @@ import androidx.compose.foundation.selection.selectable
 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.DockedSearchBar
 import androidx.compose.material3.ExperimentalMaterial3Api
 import androidx.compose.material3.Icon
@@ -85,6 +88,7 @@ import androidx.navigation.compose.rememberNavController
 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
@@ -141,7 +145,7 @@ fun Settings(navHostController: NavHostController) {
 
                 Spacer(modifier = Modifier.height(50.dp))
                 AddTextSettings(
-                    text = "Settings",
+                    text = context.resources.getString(R.string.settings),
                     size = 28.sp,
                     color = MaterialTheme.colorScheme.primary,
                     style = MaterialTheme.typography.headlineLarge
@@ -198,6 +202,8 @@ fun Settings(navHostController: NavHostController) {
                 AddRowDarkLightTheme(
                     icon = Icons.Default.DarkMode,
                     text = "Theme")
+
+                SelectLanguage(icon = Icons.Default.Language, text = "Language")
             }
         }
     }
@@ -774,6 +780,182 @@ fun AddRowDarkLightTheme(
     }
 }
 
+@OptIn(ExperimentalMaterial3Api::class)
+@Composable
+fun SelectLanguage(
+    icon: ImageVector,
+    text: String,
+) {
+    var isLanguageSheetOpen by remember { mutableStateOf(false) }
+    val sheetState = rememberModalBottomSheetState()
+    val context = LocalContext.current
+    val basePreferenceHelper = BasePreferenceHelper(context)
+
+    Row(
+        modifier = Modifier
+            .fillMaxWidth()
+            .padding(top = 40.dp, end = 27.dp)
+            .background(Color.Transparent)
+            .pointerInput(Unit) {
+                detectTapGestures {
+                    isLanguageSheetOpen = true
+                }
+            }
+            .height(24.dp),
+        horizontalArrangement = Arrangement.Start,
+        verticalAlignment = Alignment.CenterVertically
+    ) {
+
+        Surface(
+            modifier = Modifier.padding(start = 0.dp),
+            color = Color.Transparent
+        ) {
+            Image(
+                imageVector = icon,
+                contentDescription = "Select Language",
+                modifier = Modifier
+                    .padding(start = 0.dp)
+                    .size(24.dp)
+                    .weight(1f),
+                colorFilter = ColorFilter.tint(
+                    MaterialTheme.colorScheme.primary)                )
+        }
+
+        Surface(
+            modifier = Modifier.padding(start = 0.dp),
+            color = Color.Transparent
+        ) {
+            Text(text = text,
+                style = MaterialTheme.typography.titleMedium,
+                color = MaterialTheme.colorScheme.primary,
+                maxLines = 1,
+                modifier = Modifier
+                    .padding(start = 18.dp, end = 0.dp)
+                    .weight(1f)
+            )
+        }
+        Spacer(modifier = Modifier.weight(1f))
+
+        Surface(
+            modifier = Modifier
+                .padding(start = 15.dp)
+                .align(Alignment.CenterVertically),
+            color = Color.Transparent
+
+        ) {
+            Image(
+                painter = painterResource(id = R.drawable.frontarrow3x),
+                contentDescription = "Front_Arrow",
+                modifier = Modifier
+                    .padding(start = 0.dp, end = 0.dp)
+                    .size(10.dp, 18.dp)
+                    .weight(1f),
+                colorFilter = ColorFilter.tint(
+                    MaterialTheme.colorScheme.primary
+                )
+            )
+        }
+
+    }
+
+    if (isLanguageSheetOpen) {
+        ModalBottomSheet(
+            onDismissRequest = { isLanguageSheetOpen = false
+            },
+            sheetState = sheetState,
+            containerColor = MaterialTheme.colorScheme.onBackground
+        ) {
+            Box(modifier = Modifier
+                .background(Color.Transparent)
+                .fillMaxWidth()
+                .height(300.dp)
+                .padding(start = 0.dp, top = 10.dp),
+            ) {
+                Column(
+                    verticalArrangement = Arrangement.Top,
+                    horizontalAlignment = Alignment.Start
+                ) {
+                    AddTextSettings(
+                        text = "Language",
+                        size = 18.sp,
+                        color = MaterialTheme.colorScheme.primary,
+                        bottomPadding = 20.dp,
+                        startPadding = 16.dp,
+                        style = MaterialTheme.typography.titleSmall
+                    )
+                    languages.forEach { language ->
+
+                        Row(
+                            modifier = Modifier
+                                .fillMaxWidth()
+                                .background(Color.Transparent)
+                                .padding(start = 2.dp)
+                                .selectable(
+                                    selected = language == languages[0],
+                                    onClick = {
+                                      if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+                                          when (language.name) {
+                                              languages[0].name -> {
+                                                  context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.forLanguageTags(language.code)
+                                              }
+                                              languages[1].name -> {
+                                                  context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.forLanguageTags(language.code)
+                                              }
+                                              languages[2].name -> {
+                                                  context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.forLanguageTags(language.code)
+                                              }
+                                              languages[3].name -> {
+                                                  context.getSystemService(LocaleManager::class.java).applicationLocales = LocaleList.forLanguageTags(language.code)
+                                              }
+                                          }
+                                      }
+                                        isLanguageSheetOpen = false
+                                    },
+                                )
+//                                    .indication(
+//                                        indication = null,
+//                                        interactionSource = remember {
+//                                            MutableInteractionSource()
+//                                        }
+//                                    )
+                            ,
+                            verticalAlignment = Alignment.CenterVertically
+                        ) {
+//                            val themeState = isSystemInDarkTheme()
+//                            val isSystemInDarkTheme by remember { mutableStateOf(themeState) }
+                            RadioButton(selected = language == languages[0],
+                                onClick = {
+//                                    selectedtheme.value = theme
+//                                    basePreferenceHelper.saveTheme(selectedtheme.value)
+
+//                                    if (selectedtheme.value == themesList[0])
+//                                    {
+//                                        Log.d("test_theme", "true: -> $systemTheme")
+//                                        isDarkTheme.value = systemTheme
+//                                    }
+//                                    else {
+//                                        Log.d("test_theme", "false: -> $systemTheme")
+//                                        isDarkTheme.value = selectedtheme.value == themesList[2]
+//                                    }
+                                    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
+                            )
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
 @OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
 @Composable
 fun ColumnScope.AddRowSettingsSmart(
@@ -974,7 +1156,9 @@ fun ColumnScope.AddRowSettingsSmart(
             },
             sheetState = sheetStateAny,
             containerColor = MaterialTheme.colorScheme.onBackground,
-            modifier = Modifier.padding(top = 15.dp).fillMaxSize()
+            modifier = Modifier
+                .padding(top = 15.dp)
+                .fillMaxSize()
         ) {
             Box(modifier = Modifier
                 .background(Color.Transparent)

+ 5 - 0
app/src/main/res/values-de/strings.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">FastestVPN</string>
+    <string name="settings">Einstellungen</string>
+</resources>

+ 5 - 0
app/src/main/res/values-fr/strings.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">FastestVPN</string>
+    <string name="settings">Paramètres</string>
+</resources>

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

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">FastestVPN</string>
+    <string name="settings">Ayarlar</string>
+</resources>

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

@@ -405,7 +405,6 @@
     <string name="upgrade">Upgrade</string>
     <string name="upgrade_account">Upgrade Your Account</string>
     <string name="favourite_locations">Favorite Locations</string>
-    <string name="settings">Settings</string>
     <string name="change_password">Change Password</string>
     <string name="chat">Chat</string>
     <string name="help_faq">Help &amp; FAQ</string>
@@ -532,5 +531,7 @@
     <string name="add_widget">Add widget</string>
     <string name="app_widget_description">This is an app widget description</string>
 
+    <!-- Multi Lingual - (English-en) -->
+    <string name="settings">Settings</string>
 
 </resources>

+ 6 - 0
app/src/main/res/xml/locales_config.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
+    <locale android:name = "en" />
+    <locale android:name = "fr" />
+    <locale android:name = "de" />
+</locale-config>