refactor: language selection

fix: amnezia edit bug
closes #425
This commit is contained in:
Zane Schepke 2024-11-23 00:32:30 -05:00
parent a9d5994070
commit f79f922838
14 changed files with 65 additions and 170 deletions

View File

@ -68,7 +68,9 @@
<activity <activity
android:name=".ui.MainActivity" android:name=".ui.MainActivity"
android:exported="true" android:exported="true"
android:theme="@style/Theme.WireguardAutoTunnel"> android:theme="@style/Theme.WireguardAutoTunnel"
android:configChanges="orientation|screenSize|keyboardHidden"
>
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />

View File

@ -1,11 +1,11 @@
package com.zaneschepke.wireguardautotunnel package com.zaneschepke.wireguardautotunnel
import android.app.Application import android.app.Application
import android.content.Context
import android.os.StrictMode import android.os.StrictMode
import android.os.StrictMode.ThreadPolicy import android.os.StrictMode.ThreadPolicy
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import com.zaneschepke.logcatter.LogReader import com.zaneschepke.logcatter.LogReader
import com.zaneschepke.wireguardautotunnel.data.datastore.LocaleStorage
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.module.ApplicationScope import com.zaneschepke.wireguardautotunnel.module.ApplicationScope
import com.zaneschepke.wireguardautotunnel.module.IoDispatcher import com.zaneschepke.wireguardautotunnel.module.IoDispatcher
@ -22,10 +22,6 @@ import javax.inject.Inject
@HiltAndroidApp @HiltAndroidApp
class WireGuardAutoTunnel : Application() { class WireGuardAutoTunnel : Application() {
val localeStorage: LocaleStorage by lazy {
LocaleStorage(this)
}
@Inject @Inject
@ApplicationScope @ApplicationScope
lateinit var applicationScope: CoroutineScope lateinit var applicationScope: CoroutineScope
@ -56,6 +52,13 @@ class WireGuardAutoTunnel : Application() {
} else { } else {
Timber.plant(ReleaseTree()) Timber.plant(ReleaseTree())
} }
applicationScope.launch {
appStateRepository.getLocale()?.let {
val locale = LocaleUtil.getLocaleFromPrefCode(it)
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(locale)
AppCompatDelegate.setApplicationLocales(appLocale)
}
}
if (!isRunningOnTv()) { if (!isRunningOnTv()) {
applicationScope.launch(ioDispatcher) { applicationScope.launch(ioDispatcher) {
if (appStateRepository.isLocalLogsEnabled()) { if (appStateRepository.isLocalLogsEnabled()) {
@ -66,10 +69,6 @@ class WireGuardAutoTunnel : Application() {
} }
} }
override fun attachBaseContext(base: Context) {
super.attachBaseContext(LocaleUtil.getLocalizedContext(base, LocaleStorage(base).getPreferredLocale()))
}
companion object { companion object {
lateinit var instance: WireGuardAutoTunnel lateinit var instance: WireGuardAutoTunnel
private set private set

View File

@ -27,6 +27,7 @@ class DataStoreManager(
val pinLockEnabled = booleanPreferencesKey("PIN_LOCK_ENABLED") val pinLockEnabled = booleanPreferencesKey("PIN_LOCK_ENABLED")
val tunnelStatsExpanded = booleanPreferencesKey("TUNNEL_STATS_EXPANDED") val tunnelStatsExpanded = booleanPreferencesKey("TUNNEL_STATS_EXPANDED")
val isLocalLogsEnabled = booleanPreferencesKey("LOCAL_LOGS_ENABLED") val isLocalLogsEnabled = booleanPreferencesKey("LOCAL_LOGS_ENABLED")
val locale = stringPreferencesKey("LOCALE")
val theme = stringPreferencesKey("THEME") val theme = stringPreferencesKey("THEME")
} }

View File

@ -1,17 +0,0 @@
package com.zaneschepke.wireguardautotunnel.data.datastore
import android.content.Context
import android.content.SharedPreferences
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil
class LocaleStorage(context: Context) {
private var preferences: SharedPreferences = context.getSharedPreferences("sp", Context.MODE_PRIVATE)
fun getPreferredLocale(): String {
return preferences.getString("preferred_locale", LocaleUtil.OPTION_PHONE_LANGUAGE)!!
}
fun setPreferredLocale(localeCode: String) {
preferences.edit().putString("preferred_locale", localeCode).apply()
}
}

View File

@ -8,6 +8,7 @@ data class GeneralState(
val isPinLockEnabled: Boolean = PIN_LOCK_ENABLED_DEFAULT, val isPinLockEnabled: Boolean = PIN_LOCK_ENABLED_DEFAULT,
val isTunnelStatsExpanded: Boolean = IS_TUNNEL_STATS_EXPANDED, val isTunnelStatsExpanded: Boolean = IS_TUNNEL_STATS_EXPANDED,
val isLocalLogsEnabled: Boolean = IS_LOGS_ENABLED_DEFAULT, val isLocalLogsEnabled: Boolean = IS_LOGS_ENABLED_DEFAULT,
val locale: String? = null,
val theme: Theme = Theme.AUTOMATIC, val theme: Theme = Theme.AUTOMATIC,
) { ) {
companion object { companion object {

View File

@ -33,5 +33,9 @@ interface AppStateRepository {
suspend fun setLocalLogsEnabled(enabled: Boolean) suspend fun setLocalLogsEnabled(enabled: Boolean)
suspend fun setLocale(localeTag: String)
suspend fun getLocale(): String?
val generalStateFlow: Flow<GeneralState> val generalStateFlow: Flow<GeneralState>
} }

View File

@ -77,6 +77,14 @@ class DataStoreAppStateRepository(
dataStoreManager.saveToDataStore(DataStoreManager.isLocalLogsEnabled, enabled) dataStoreManager.saveToDataStore(DataStoreManager.isLocalLogsEnabled, enabled)
} }
override suspend fun setLocale(localeTag: String) {
dataStoreManager.saveToDataStore(DataStoreManager.locale, localeTag)
}
override suspend fun getLocale(): String? {
return dataStoreManager.getFromStore(DataStoreManager.locale)
}
override val generalStateFlow: Flow<GeneralState> = override val generalStateFlow: Flow<GeneralState> =
dataStoreManager.preferencesFlow.map { prefs -> dataStoreManager.preferencesFlow.map { prefs ->
prefs?.let { pref -> prefs?.let { pref ->
@ -93,6 +101,7 @@ class DataStoreAppStateRepository(
?: GeneralState.PIN_LOCK_ENABLED_DEFAULT, ?: GeneralState.PIN_LOCK_ENABLED_DEFAULT,
isTunnelStatsExpanded = pref[DataStoreManager.tunnelStatsExpanded] ?: GeneralState.IS_TUNNEL_STATS_EXPANDED, isTunnelStatsExpanded = pref[DataStoreManager.tunnelStatsExpanded] ?: GeneralState.IS_TUNNEL_STATS_EXPANDED,
isLocalLogsEnabled = pref[DataStoreManager.isLocalLogsEnabled] ?: GeneralState.IS_LOGS_ENABLED_DEFAULT, isLocalLogsEnabled = pref[DataStoreManager.isLocalLogsEnabled] ?: GeneralState.IS_LOGS_ENABLED_DEFAULT,
locale = pref[DataStoreManager.locale],
theme = getTheme(), theme = getTheme(),
) )
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {

View File

@ -1,5 +1,7 @@
package com.zaneschepke.wireguardautotunnel.ui package com.zaneschepke.wireguardautotunnel.ui
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.os.LocaleListCompat
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.wireguard.android.backend.WgQuickBackend import com.wireguard.android.backend.WgQuickBackend
@ -15,6 +17,8 @@ import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelState
import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController import com.zaneschepke.wireguardautotunnel.ui.common.snackbar.SnackbarController
import com.zaneschepke.wireguardautotunnel.util.Constants import com.zaneschepke.wireguardautotunnel.util.Constants
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil.OPTION_PHONE_LANGUAGE
import com.zaneschepke.wireguardautotunnel.util.StringValue import com.zaneschepke.wireguardautotunnel.util.StringValue
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
@ -147,6 +151,14 @@ constructor(
} }
} }
fun onLocaleChange(localeTag: String) = viewModelScope.launch {
val locale = LocaleUtil.getLocaleFromPrefCode(localeTag)
val storageLocale = if (localeTag == OPTION_PHONE_LANGUAGE) OPTION_PHONE_LANGUAGE else locale
appDataRepository.appState.setLocale(storageLocale)
val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(locale)
AppCompatDelegate.setApplicationLocales(appLocale)
}
fun onToggleRestartAtBoot() = viewModelScope.launch { fun onToggleRestartAtBoot() = viewModelScope.launch {
with(uiState.value.settings) { with(uiState.value.settings) {
appDataRepository.settings.save( appDataRepository.settings.save(

View File

@ -1,6 +1,5 @@
package com.zaneschepke.wireguardautotunnel.ui package com.zaneschepke.wireguardautotunnel.ui
import android.content.Context
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
import androidx.activity.compose.setContent import androidx.activity.compose.setContent
@ -35,8 +34,6 @@ import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import androidx.navigation.toRoute import androidx.navigation.toRoute
import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.WireGuardAutoTunnel
import com.zaneschepke.wireguardautotunnel.data.datastore.LocaleStorage
import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository import com.zaneschepke.wireguardautotunnel.data.repository.AppStateRepository
import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService import com.zaneschepke.wireguardautotunnel.service.tunnel.TunnelService
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar import com.zaneschepke.wireguardautotunnel.ui.common.navigation.BottomNavBar
@ -59,7 +56,6 @@ 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.Constants
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil
import com.zaneschepke.wireguardautotunnel.util.extensions.requestAutoTunnelTileServiceUpdate import com.zaneschepke.wireguardautotunnel.util.extensions.requestAutoTunnelTileServiceUpdate
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject import javax.inject.Inject
@ -68,12 +64,6 @@ import kotlin.system.exitProcess
@AndroidEntryPoint @AndroidEntryPoint
class MainActivity : AppCompatActivity() { class MainActivity : AppCompatActivity() {
private val localeStorage: LocaleStorage by lazy {
(application as WireGuardAutoTunnel).localeStorage
}
private lateinit var oldPrefLocaleCode: String
@Inject @Inject
lateinit var appStateRepository: AppStateRepository lateinit var appStateRepository: AppStateRepository
@ -185,7 +175,7 @@ class MainActivity : AppCompatActivity() {
AppearanceScreen() AppearanceScreen()
} }
composable<Route.Language> { composable<Route.Language> {
LanguageScreen(localeStorage) LanguageScreen(appUiState, viewModel)
} }
composable<Route.Display> { composable<Route.Display> {
DisplayScreen(appUiState) DisplayScreen(appUiState)
@ -225,19 +215,4 @@ class MainActivity : AppCompatActivity() {
} }
} }
} }
override fun attachBaseContext(newBase: Context) {
oldPrefLocaleCode = LocaleStorage(newBase).getPreferredLocale()
applyOverrideConfiguration(LocaleUtil.getLocalizedConfiguration(oldPrefLocaleCode))
super.attachBaseContext(newBase)
}
override fun onResume() {
val currentLocaleCode = LocaleStorage(this).getPreferredLocale()
if (oldPrefLocaleCode != currentLocaleCode) {
recreate() // locale is changed, restart the activity to update
oldPrefLocaleCode = currentLocaleCode
}
super.onResume()
}
} }

View File

@ -25,7 +25,6 @@ import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.ui.theme.iconSize import com.zaneschepke.wireguardautotunnel.ui.theme.iconSize
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
import kotlin.let
@androidx.compose.runtime.Composable @androidx.compose.runtime.Composable
fun IconSurfaceButton(title: String, onClick: () -> Unit, selected: Boolean, leadingIcon: ImageVector? = null, description: String? = null) { fun IconSurfaceButton(title: String, onClick: () -> Unit, selected: Boolean, leadingIcon: ImageVector? = null, description: String? = null) {

View File

@ -90,8 +90,8 @@ fun ConfigScreen(tunnelId: Int) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle() val uiState by viewModel.uiState.collectAsStateWithLifecycle()
var configType by remember { mutableStateOf<ConfigType?>(null) } var configType by remember { mutableStateOf<ConfigType?>(null) }
val derivedConfigType = remember { val derivedConfigType = remember {
derivedStateOf<ConfigType> { derivedStateOf {
configType ?: if (!uiState.hasAmneziaProperties()) ConfigType.WIREGUARD else ConfigType.AMNEZIA configType ?: if (!uiState.isAmneziaEnabled) ConfigType.WIREGUARD else ConfigType.AMNEZIA
} }
} }
val saved by viewModel.saved.collectAsStateWithLifecycle(null) val saved by viewModel.saved.collectAsStateWithLifecycle(null)
@ -181,8 +181,8 @@ fun ConfigScreen(tunnelId: Int) {
) )
} }
}, },
) { ) { padding ->
Column(Modifier.padding(it)) { Column(Modifier.padding(padding)) {
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top, verticalArrangement = Arrangement.Top,
@ -243,12 +243,12 @@ fun ConfigScreen(tunnelId: Int) {
.clickable { showAuthPrompt = true }, .clickable { showAuthPrompt = true },
value = uiState.interfaceProxy.privateKey, value = uiState.interfaceProxy.privateKey,
visualTransformation = visualTransformation =
if ((tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID.toInt()) || isAuthenticated) { if ((tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated) {
VisualTransformation.None VisualTransformation.None
} else { } else {
PasswordVisualTransformation() PasswordVisualTransformation()
}, },
enabled = (tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID.toInt()) || isAuthenticated, enabled = (tunnelId == Constants.MANUAL_TUNNEL_CONFIG_ID) || isAuthenticated,
onValueChange = { value -> viewModel.onPrivateKeyChange(value) }, onValueChange = { value -> viewModel.onPrivateKeyChange(value) },
trailingIcon = { trailingIcon = {
IconButton( IconButton(

View File

@ -18,9 +18,6 @@ data class ConfigUiState(
var tunnelName: String = "", var tunnelName: String = "",
val isAmneziaEnabled: Boolean = false, val isAmneziaEnabled: Boolean = false,
) { ) {
fun hasAmneziaProperties(): Boolean {
return this.interfaceProxy.junkPacketCount != ""
}
companion object { companion object {
fun from(config: Config): ConfigUiState { fun from(config: Config): ConfigUiState {
val proxyPeers = config.peers.map { PeerProxy.from(it) } val proxyPeers = config.peers.map { PeerProxy.from(it) }
@ -77,6 +74,7 @@ data class ConfigUiState(
return from(config).copy( return from(config).copy(
tunnelName = tunnel.name, tunnelName = tunnel.name,
tunnel = tunnel, tunnel = tunnel,
isAmneziaEnabled = config.`interface`.junkPacketCount.isPresent,
) )
} }
} }

View File

@ -11,39 +11,27 @@ import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items import androidx.compose.foundation.lazy.items
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.zaneschepke.wireguardautotunnel.R import com.zaneschepke.wireguardautotunnel.R
import com.zaneschepke.wireguardautotunnel.data.datastore.LocaleStorage import com.zaneschepke.wireguardautotunnel.ui.AppUiState
import com.zaneschepke.wireguardautotunnel.ui.Route import com.zaneschepke.wireguardautotunnel.ui.AppViewModel
import com.zaneschepke.wireguardautotunnel.ui.common.SelectedLabel import com.zaneschepke.wireguardautotunnel.ui.common.SelectedLabel
import com.zaneschepke.wireguardautotunnel.ui.common.button.SelectionItemButton import com.zaneschepke.wireguardautotunnel.ui.common.button.SelectionItemButton
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.LocalNavController
import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar import com.zaneschepke.wireguardautotunnel.ui.common.navigation.TopNavBar
import com.zaneschepke.wireguardautotunnel.util.LocaleUtil import com.zaneschepke.wireguardautotunnel.util.LocaleUtil
import com.zaneschepke.wireguardautotunnel.util.extensions.navigateAndForget
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight import com.zaneschepke.wireguardautotunnel.util.extensions.scaledHeight
import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth import com.zaneschepke.wireguardautotunnel.util.extensions.scaledWidth
import timber.log.Timber
import java.text.Collator import java.text.Collator
import java.util.Locale import java.util.Locale
@Composable @Composable
fun LanguageScreen(localeStorage: LocaleStorage) { fun LanguageScreen(appUiState: AppUiState, appViewModel: AppViewModel) {
val navController = LocalNavController.current
val context = LocalContext.current
val collator = Collator.getInstance(Locale.getDefault()) val collator = Collator.getInstance(Locale.getDefault())
val currentLocale = remember { mutableStateOf(LocaleUtil.OPTION_PHONE_LANGUAGE) }
val locales = LocaleUtil.supportedLocales.map { val locales = LocaleUtil.supportedLocales.map {
val tag = it.replace("_", "-") val tag = it.replace("_", "-")
Locale.forLanguageTag(tag) Locale.forLanguageTag(tag)
@ -54,28 +42,17 @@ fun LanguageScreen(localeStorage: LocaleStorage) {
locales.sortedWith(compareBy(collator) { it.getDisplayName(it) }).toList() locales.sortedWith(compareBy(collator) { it.getDisplayName(it) }).toList()
} }
LaunchedEffect(Unit) {
currentLocale.value = localeStorage.getPreferredLocale()
}
fun onChangeLocale(locale: String) {
Timber.d("Setting preferred locale: $locale")
localeStorage.setPreferredLocale(locale)
LocaleUtil.applyLocalizedContext(context, locale)
navController.navigateAndForget(Route.Main)
}
Scaffold( Scaffold(
topBar = { topBar = {
TopNavBar(stringResource(R.string.language)) TopNavBar(stringResource(R.string.language))
}, },
) { ) { padding ->
LazyColumn( LazyColumn(
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top, verticalArrangement = Arrangement.Top,
modifier = modifier =
Modifier Modifier
.fillMaxSize().padding(it) .fillMaxSize().padding(padding)
.padding(horizontal = 24.dp.scaledWidth()).windowInsetsPadding(WindowInsets.navigationBars), .padding(horizontal = 24.dp.scaledWidth()).windowInsetsPadding(WindowInsets.navigationBars),
) { ) {
item { item {
@ -83,10 +60,10 @@ fun LanguageScreen(localeStorage: LocaleStorage) {
SelectionItemButton( SelectionItemButton(
buttonText = stringResource(R.string.automatic), buttonText = stringResource(R.string.automatic),
onClick = { onClick = {
onChangeLocale(LocaleUtil.OPTION_PHONE_LANGUAGE) appViewModel.onLocaleChange(LocaleUtil.OPTION_PHONE_LANGUAGE)
}, },
trailing = { trailing = {
if (currentLocale.value == LocaleUtil.OPTION_PHONE_LANGUAGE) { if (appUiState.generalState.locale == LocaleUtil.OPTION_PHONE_LANGUAGE) {
SelectedLabel() SelectedLabel()
} }
}, },
@ -96,13 +73,18 @@ fun LanguageScreen(localeStorage: LocaleStorage) {
} }
items(sortedLocales, key = { it }) { locale -> items(sortedLocales, key = { it }) { locale ->
SelectionItemButton( SelectionItemButton(
buttonText = locale.getDisplayLanguage(locale).capitalize(locale) + buttonText = locale.getDisplayLanguage(locale).replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() } +
if (locale.toLanguageTag().contains("-")) " (${locale.getDisplayCountry(locale).capitalize(locale)})" else "", if (locale.toLanguageTag().contains("-")) {
" (${locale.getDisplayCountry(locale)
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(locale) else it.toString() }})"
} else {
""
},
onClick = { onClick = {
onChangeLocale(locale.toLanguageTag()) appViewModel.onLocaleChange(locale.toLanguageTag())
}, },
trailing = { trailing = {
if (locale.toLanguageTag() == currentLocale.value) { if (locale.toLanguageTag() == appUiState.generalState.locale) {
SelectedLabel() SelectedLabel()
} }
}, },

View File

@ -1,13 +1,8 @@
package com.zaneschepke.wireguardautotunnel.util package com.zaneschepke.wireguardautotunnel.util
import android.content.Context
import android.content.res.Configuration
import android.content.res.Resources import android.content.res.Resources
import android.os.Build
import android.os.LocaleList
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import com.zaneschepke.wireguardautotunnel.BuildConfig import com.zaneschepke.wireguardautotunnel.BuildConfig
import java.util.Locale
object LocaleUtil { object LocaleUtil {
private const val DEFAULT_LANG = "en" private const val DEFAULT_LANG = "en"
@ -19,7 +14,7 @@ object LocaleUtil {
* when preference value = "sys_def" returns the locale of current system * when preference value = "sys_def" returns the locale of current system
* else it returns the locale code e.g. "en", "bn" etc. * else it returns the locale code e.g. "en", "bn" etc.
*/ */
fun getLocaleFromPrefCode(prefCode: String): Locale { fun getLocaleFromPrefCode(prefCode: String): String {
val localeCode = if (prefCode != OPTION_PHONE_LANGUAGE) { val localeCode = if (prefCode != OPTION_PHONE_LANGUAGE) {
prefCode prefCode
} else { } else {
@ -30,71 +25,6 @@ object LocaleUtil {
DEFAULT_LANG DEFAULT_LANG
} }
} }
return Locale.forLanguageTag(localeCode) return localeCode
}
fun getLocalizedConfiguration(prefLocaleCode: String): Configuration {
val locale = getLocaleFromPrefCode(prefLocaleCode)
return getLocalizedConfiguration(locale)
}
private fun getLocalizedConfiguration(locale: Locale): Configuration {
val config = Configuration()
return config.apply {
config.setLayoutDirection(locale)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
config.setLocale(locale)
val localeList = LocaleList(locale)
LocaleList.setDefault(localeList)
config.setLocales(localeList)
} else {
config.setLocale(locale)
}
}
}
fun getLocalizedContext(baseContext: Context, prefLocaleCode: String?): Context {
if (prefLocaleCode == null) return baseContext
val currentLocale = getLocaleFromPrefCode(prefLocaleCode)
val baseLocale = getLocaleFromConfiguration(baseContext.resources.configuration)
Locale.setDefault(currentLocale)
return if (!baseLocale.toString().equals(currentLocale.toString(), ignoreCase = true)) {
val config = getLocalizedConfiguration(currentLocale)
baseContext.createConfigurationContext(config)
baseContext
} else {
baseContext
}
}
fun applyLocalizedContext(baseContext: Context, prefLocaleCode: String) {
val currentLocale = getLocaleFromPrefCode(prefLocaleCode)
val baseLocale = getLocaleFromConfiguration(baseContext.resources.configuration)
Locale.setDefault(currentLocale)
if (!baseLocale.toString().equals(currentLocale.toString(), ignoreCase = true)) {
val config = getLocalizedConfiguration(currentLocale)
baseContext.resources.updateConfiguration(config, baseContext.resources.displayMetrics)
}
}
@Suppress("DEPRECATION")
private fun getLocaleFromConfiguration(configuration: Configuration): Locale {
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
configuration.locales.get(0)
} else {
configuration.locale
}
}
fun getLocalizedResources(resources: Resources, prefLocaleCode: String): Resources {
val locale = getLocaleFromPrefCode(prefLocaleCode)
val config = resources.configuration
@Suppress("DEPRECATION")
config.locale = locale
config.setLayoutDirection(locale)
@Suppress("DEPRECATION")
resources.updateConfiguration(config, resources.displayMetrics)
return resources
} }
} }