mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
update in-app language picker (#538)
This commit is contained in:
parent
8dca9ea8b6
commit
c9a81c72e0
16 changed files with 141 additions and 183 deletions
|
|
@ -1,49 +0,0 @@
|
|||
package com.geeksville.mesh
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.model.UIViewModel
|
||||
import java.util.*
|
||||
|
||||
open class BaseActivity: AppCompatActivity(), Logging {
|
||||
|
||||
override fun attachBaseContext(newBase: Context) {
|
||||
val res = newBase.resources
|
||||
val config = res.configuration
|
||||
|
||||
// get chosen language from preference
|
||||
val prefs = UIViewModel.getPreferences(newBase)
|
||||
val langCode: String = prefs.getString("lang","zz") ?: ""
|
||||
debug("langCode is $langCode")
|
||||
|
||||
if (Build.VERSION.SDK_INT >= 17) {
|
||||
val locale = if (langCode == "zz")
|
||||
Locale.getDefault()
|
||||
else
|
||||
createLocale(langCode)
|
||||
config.setLocale(locale)
|
||||
|
||||
if(Build.VERSION.SDK_INT > 24) {
|
||||
//Using createNewConfigurationContext will cause CompanionDeviceManager to crash
|
||||
applyOverrideConfiguration(config)
|
||||
super.attachBaseContext(newBase)
|
||||
}else {
|
||||
super.attachBaseContext(newBase.createConfigurationContext(config))
|
||||
}
|
||||
} else {
|
||||
super.attachBaseContext(newBase)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createLocale(language: String): Locale {
|
||||
val langArray = language.split("_")
|
||||
return if (langArray.size == 2) {
|
||||
Locale(langArray[0], langArray[1])
|
||||
} else {
|
||||
Locale(langArray[0])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@ import android.widget.TextView
|
|||
import android.widget.Toast
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.activity.viewModels
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.content.ContextCompat
|
||||
|
|
@ -42,6 +43,7 @@ import com.geeksville.mesh.repository.radio.SerialInterface
|
|||
import com.geeksville.mesh.service.*
|
||||
import com.geeksville.mesh.ui.*
|
||||
import com.geeksville.mesh.util.Exceptions
|
||||
import com.geeksville.mesh.util.LanguageUtils
|
||||
import com.geeksville.mesh.util.exceptionReporter
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
|
@ -106,7 +108,7 @@ eventually:
|
|||
*/
|
||||
|
||||
@AndroidEntryPoint
|
||||
class MainActivity : BaseActivity(), Logging {
|
||||
class MainActivity : AppCompatActivity(), Logging {
|
||||
|
||||
private lateinit var binding: ActivityMainBinding
|
||||
|
||||
|
|
@ -200,6 +202,11 @@ class MainActivity : BaseActivity(), Logging {
|
|||
if (!prefs.getBoolean("app_intro_completed", false)) {
|
||||
startActivity(Intent(this, AppIntroduction::class.java))
|
||||
}
|
||||
// First run: migrate in-app language prefs to appcompat
|
||||
if (prefs.getString("lang", LanguageUtils.SYSTEM_DEFAULT) != LanguageUtils.SYSTEM_MANAGED) {
|
||||
LanguageUtils.migrateLanguagePrefs(prefs)
|
||||
}
|
||||
info("in-app language is ${LanguageUtils.getLocale()}")
|
||||
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
|
||||
|
|
@ -843,7 +850,6 @@ class MainActivity : BaseActivity(), Logging {
|
|||
editor.putInt("theme", 0)
|
||||
editor.apply()
|
||||
|
||||
delegate.applyDayNight()
|
||||
dialog.dismiss()
|
||||
}
|
||||
1 -> {
|
||||
|
|
@ -851,15 +857,13 @@ class MainActivity : BaseActivity(), Logging {
|
|||
editor.putInt("theme", 1)
|
||||
editor.apply()
|
||||
|
||||
delegate.applyDayNight()
|
||||
dialog.dismiss()
|
||||
}
|
||||
2 -> {
|
||||
else -> {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
editor.putInt("theme", 2)
|
||||
editor.apply()
|
||||
|
||||
delegate.applyDayNight()
|
||||
dialog.dismiss()
|
||||
}
|
||||
|
||||
|
|
@ -875,34 +879,23 @@ class MainActivity : BaseActivity(), Logging {
|
|||
/// If nothing is found set FOLLOW SYSTEM option
|
||||
|
||||
when (prefs.getInt("theme", 2)) {
|
||||
0 -> {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
delegate.applyDayNight()
|
||||
}
|
||||
1 -> {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
delegate.applyDayNight()
|
||||
}
|
||||
2 -> {
|
||||
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
delegate.applyDayNight()
|
||||
}
|
||||
0 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
|
||||
1 -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
|
||||
else -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
|
||||
}
|
||||
}
|
||||
|
||||
private fun chooseLangDialog() {
|
||||
|
||||
/// Prepare dialog and its items
|
||||
val builder = MaterialAlertDialogBuilder(this)
|
||||
builder.setTitle(getString(R.string.preferences_language))
|
||||
|
||||
val languageLabels by lazy { resources.getStringArray(R.array.language_entries) }
|
||||
val languageValues by lazy { resources.getStringArray(R.array.language_values) }
|
||||
val languageTags = LanguageUtils.getLanguageTags(this)
|
||||
val languageLabels = languageTags.map { it.first }.toTypedArray()
|
||||
val languageValues = languageTags.map { it.second }
|
||||
|
||||
/// Load preferences and its value
|
||||
val prefs = UIViewModel.getPreferences(this)
|
||||
val editor: SharedPreferences.Editor = prefs.edit()
|
||||
val lang = prefs.getString("lang", "zz")
|
||||
val lang = LanguageUtils.getLocale()
|
||||
debug("Lang from prefs: $lang")
|
||||
|
||||
builder.setSingleChoiceItems(
|
||||
|
|
@ -911,8 +904,7 @@ class MainActivity : BaseActivity(), Logging {
|
|||
) { dialog, which ->
|
||||
val selectedLang = languageValues[which]
|
||||
debug("Set lang pref to $selectedLang")
|
||||
editor.putString("lang", selectedLang)
|
||||
editor.apply()
|
||||
LanguageUtils.setLocale(selectedLang)
|
||||
dialog.dismiss()
|
||||
}
|
||||
val dialog = builder.create()
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
package com.geeksville.mesh.ui
|
||||
|
||||
import com.geeksville.mesh.android.Logging
|
||||
|
||||
|
||||
object UILog : Logging
|
||||
66
app/src/main/java/com/geeksville/mesh/util/LanguageUtils.kt
Normal file
66
app/src/main/java/com/geeksville/mesh/util/LanguageUtils.kt
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
package com.geeksville.mesh.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import com.geeksville.mesh.android.Logging
|
||||
import com.geeksville.mesh.R
|
||||
import org.xmlpull.v1.XmlPullParser
|
||||
import java.util.Locale
|
||||
|
||||
object LanguageUtils : Logging {
|
||||
|
||||
const val SYSTEM_DEFAULT = "zz"
|
||||
const val SYSTEM_MANAGED = "appcompat"
|
||||
|
||||
fun getLocale(): String {
|
||||
return AppCompatDelegate.getApplicationLocales().toLanguageTags().ifEmpty { SYSTEM_DEFAULT }
|
||||
}
|
||||
|
||||
fun setLocale(lang: String) {
|
||||
AppCompatDelegate.setApplicationLocales(
|
||||
if (lang == SYSTEM_DEFAULT) LocaleListCompat.getEmptyLocaleList()
|
||||
else LocaleListCompat.forLanguageTags(lang)
|
||||
)
|
||||
}
|
||||
|
||||
fun migrateLanguagePrefs(prefs: SharedPreferences) {
|
||||
val currentLang = prefs.getString("lang", SYSTEM_DEFAULT) ?: SYSTEM_DEFAULT
|
||||
debug("Migrating in-app language prefs: $currentLang")
|
||||
prefs.edit { putString("lang", SYSTEM_MANAGED) }
|
||||
setLocale(currentLang)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a list from locales_config.xml
|
||||
* of native language names paired to its Locale tag (ex: "English", "en")
|
||||
*/
|
||||
fun getLanguageTags(context: Context): List<Pair<String, String>> {
|
||||
val languageTags = mutableListOf(SYSTEM_DEFAULT)
|
||||
try {
|
||||
context.resources.getXml(R.xml.locales_config).use {
|
||||
while (it.eventType != XmlPullParser.END_DOCUMENT) {
|
||||
if (it.eventType == XmlPullParser.START_TAG && it.name == "locale") {
|
||||
languageTags += it.getAttributeValue(0)
|
||||
}
|
||||
it.next()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
errormsg("Error parsing locale_config.xml ${e.message}")
|
||||
}
|
||||
fun getDisplayLanguage(tag: String): String {
|
||||
val loc = Locale(tag)
|
||||
return when (tag) {
|
||||
SYSTEM_DEFAULT -> context.getString(R.string.preferences_system_default)
|
||||
"fr-HT" -> context.getString(R.string.fr_HT)
|
||||
"pt-BR" -> context.getString(R.string.pt_BR)
|
||||
else -> loc.getDisplayLanguage(loc)
|
||||
.replaceFirstChar { if (it.isLowerCase()) it.titlecase(loc) else it.toString() }
|
||||
}
|
||||
}
|
||||
return languageTags.map { getDisplayLanguage(it) to it }
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue