From 035ba899ee9d108f8c59a0fca41a5854db52ea8b Mon Sep 17 00:00:00 2001 From: greenart7c3 <115044884+greenart7c3@users.noreply.github.com> Date: Wed, 5 Jul 2023 15:12:24 -0300 Subject: [PATCH] add language picker --- .../amethyst/LocalPreferences.kt | 14 +++- .../vitorpamplona/amethyst/model/Settings.kt | 5 +- .../vitorpamplona/amethyst/ui/MainActivity.kt | 11 ++- .../ui/screen/loggedIn/SettingsScreen.kt | 71 ++++++++++++++++--- app/src/main/res/values-night/themes.xml | 2 +- app/src/main/res/values/themes.xml | 2 +- app/src/main/res/xml/locales_config.xml | 9 ++- 7 files changed, 92 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt index 2b3b08e66..83466eed0 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/LocalPreferences.kt @@ -71,6 +71,7 @@ private object PrefKeys { const val AUTOMATICALLY_SHOW_IMAGES = "automatically_show_images" const val AUTOMATICALLY_START_PLAYBACK = "automatically_start_playback" const val THEME = "theme" + const val PREFERRED_LANGUAGE = "preferred_Language" val LAST_READ: (String) -> String = { route -> "last_read_route_$route" } } @@ -254,6 +255,7 @@ object LocalPreferences { } else { putBoolean(PrefKeys.AUTOMATICALLY_START_PLAYBACK, account.settings.automaticallyStartPlayback!!) } + putString(PrefKeys.PREFERRED_LANGUAGE, account.settings.preferredLanguage ?: "") }.apply() } @@ -271,6 +273,14 @@ object LocalPreferences { return theme } + fun getPreferredLanguage(): String { + var language = "" + encryptedPreferences().apply { + language = getString(PrefKeys.PREFERRED_LANGUAGE, "") ?: "" + } + return language + } + fun loadFromEncryptedStorage(): Account? { val acc = loadFromEncryptedStorage(currentAccount()) acc?.registerObservers() @@ -373,7 +383,7 @@ object LocalPreferences { mapOf() } - val settings = Settings(null, null) + val settings = Settings() encryptedPreferences().apply { settings.automaticallyShowImages = if (contains(PrefKeys.AUTOMATICALLY_SHOW_IMAGES)) { getBoolean(PrefKeys.AUTOMATICALLY_SHOW_IMAGES, false) @@ -386,6 +396,8 @@ object LocalPreferences { } else { null } + + settings.preferredLanguage = getString(PrefKeys.PREFERRED_LANGUAGE, "") } val a = Account( diff --git a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt index 448afd677..9d539924f 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/model/Settings.kt @@ -4,6 +4,7 @@ import androidx.compose.runtime.Stable @Stable class Settings( - var automaticallyShowImages: Boolean?, - var automaticallyStartPlayback: Boolean? + var automaticallyShowImages: Boolean? = null, + var automaticallyStartPlayback: Boolean? = null, + var preferredLanguage: String? = null ) diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt index 1e5f10444..5af93a12e 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/MainActivity.kt @@ -10,11 +10,13 @@ import android.os.Bundle import android.util.Log import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts +import androidx.appcompat.app.AppCompatActivity +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.material.MaterialTheme import androidx.compose.material.Surface import androidx.compose.ui.Modifier -import androidx.fragment.app.FragmentActivity +import androidx.core.os.LocaleListCompat import androidx.lifecycle.viewmodel.compose.viewModel import com.vitorpamplona.amethyst.BuildConfig import com.vitorpamplona.amethyst.LocalPreferences @@ -42,7 +44,7 @@ import kotlinx.coroutines.launch import java.net.URLEncoder import java.nio.charset.StandardCharsets -class MainActivity : FragmentActivity() { +class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -53,6 +55,11 @@ class MainActivity : FragmentActivity() { LocalPreferences.migrateSingleUserPrefs() val themeViewModel = ThemeViewModel() themeViewModel.onChange(LocalPreferences.getTheme()) + val language = LocalPreferences.getPreferredLanguage() + if (language.isNotBlank()) { + val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(language) + AppCompatDelegate.setApplicationLocales(appLocale) + } setContent { AmethystTheme(themeViewModel) { diff --git a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt index 854a16221..9041276f1 100644 --- a/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt +++ b/app/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/SettingsScreen.kt @@ -1,10 +1,13 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn +import android.content.Context +import androidx.appcompat.app.AppCompatDelegate import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.material.Button import androidx.compose.material.DropdownMenuItem import androidx.compose.material.ExperimentalMaterialApi @@ -23,13 +26,53 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.intl.Locale +import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp +import androidx.core.os.LocaleListCompat import com.vitorpamplona.amethyst.LocalPreferences +import com.vitorpamplona.amethyst.R import com.vitorpamplona.amethyst.ServiceManager import com.vitorpamplona.amethyst.ui.theme.DoubleVertSpacer import com.vitorpamplona.amethyst.ui.theme.StdPadding import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import org.xmlpull.v1.XmlPullParser +import org.xmlpull.v1.XmlPullParserException +import java.io.IOException + +fun Context.getLocaleListFromXml(): LocaleListCompat { + val tagsList = mutableListOf() + try { + val xpp: XmlPullParser = resources.getXml(R.xml.locales_config) + while (xpp.eventType != XmlPullParser.END_DOCUMENT) { + if (xpp.eventType == XmlPullParser.START_TAG) { + if (xpp.name == "locale") { + tagsList.add(xpp.getAttributeValue(0)) + } + } + xpp.next() + } + } catch (e: XmlPullParserException) { + e.printStackTrace() + } catch (e: IOException) { + e.printStackTrace() + } + + return LocaleListCompat.forLanguageTags(tagsList.joinToString(",")) +} + +fun Context.getLangPreferenceDropdownEntries(): Map { + val localeList = getLocaleListFromXml() + val map = mutableMapOf() + + for (a in 0 until localeList.size()) { + localeList[a].let { + map.put(it!!.getDisplayName(it).replaceFirstChar { char -> char.uppercase() }, it.toLanguageTag()) + } + } + return map +} @Composable fun SettingsScreen( @@ -59,6 +102,16 @@ fun SettingsScreen( } val context = LocalContext.current + + val languageEntries = context.getLangPreferenceDropdownEntries() + val languageList = languageEntries.keys.toTypedArray() + var languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.toLanguageTag()) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf(Locale.current.language) + if (languageIndex == -1) languageIndex = languageEntries.values.toTypedArray().indexOf("en") + val selectedLanguage = remember { + mutableStateOf(languageList[languageIndex]) + } + Column( StdPadding, horizontalAlignment = Alignment.CenterHorizontally @@ -67,9 +120,10 @@ fun SettingsScreen( Section("Application preferences") - Text( - "Theme", - fontWeight = FontWeight.Bold + DropDownSettings( + selectedItem = selectedLanguage, + listItems = languageList, + title = "Language" ) DropDownSettings( @@ -78,19 +132,12 @@ fun SettingsScreen( title = "Theme" ) - Text( - "Media", - fontWeight = FontWeight.Bold - ) - DropDownSettings( selectedItem = selectedItem, listItems = selectedItens, title = "Automatically load images/gifs" ) - Spacer(modifier = DoubleVertSpacer) - DropDownSettings( selectedItem = selectedVideoItem, listItems = selectedItens, @@ -114,12 +161,15 @@ fun SettingsScreen( else -> null } accountViewModel.changeTheme(selectedTheme.value) + scope.launch(Dispatchers.IO) { accountViewModel.updateGlobalSettings(automaticallyShowImages, automaticallyStartPlayback) LocalPreferences.saveToEncryptedStorage(accountViewModel.account) LocalPreferences.updateTheme(selectedTheme.value) ServiceManager.pause() ServiceManager.start(context) + val appLocale: LocaleListCompat = LocaleListCompat.forLanguageTags(languageEntries[selectedLanguage.value]) + AppCompatDelegate.setApplicationLocales(appLocale) } } ) { @@ -140,6 +190,7 @@ fun DropDownSettings( mutableStateOf(false) } ExposedDropdownMenuBox( + modifier = Modifier.padding(8.dp), expanded = expanded, onExpandedChange = { expanded = !expanded diff --git a/app/src/main/res/values-night/themes.xml b/app/src/main/res/values-night/themes.xml index 437a0e623..196cb2c3a 100644 --- a/app/src/main/res/values-night/themes.xml +++ b/app/src/main/res/values-night/themes.xml @@ -1,6 +1,6 @@ - diff --git a/app/src/main/res/xml/locales_config.xml b/app/src/main/res/xml/locales_config.xml index 014573af0..b70b87c5e 100644 --- a/app/src/main/res/xml/locales_config.xml +++ b/app/src/main/res/xml/locales_config.xml @@ -7,17 +7,16 @@ - - + - + - - + + \ No newline at end of file