support Android 13 per-app languages (#2829)
* support Android 13 per-app languages * fix tests * fix language ids in locales_config.xml * fix language setting default in ComposeActivity
This commit is contained in:
parent
9f7cd2fa32
commit
c96a81571c
11 changed files with 165 additions and 89 deletions
|
|
@ -17,25 +17,89 @@ package com.keylesspalace.tusky.util
|
|||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.content.res.Configuration
|
||||
import android.os.Build
|
||||
import androidx.appcompat.app.AppCompatDelegate
|
||||
import androidx.core.os.LocaleListCompat
|
||||
import androidx.preference.PreferenceDataStore
|
||||
import androidx.preference.PreferenceManager
|
||||
import java.util.Locale
|
||||
import com.keylesspalace.tusky.R
|
||||
import com.keylesspalace.tusky.settings.PrefKeys
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class LocaleManager(context: Context) {
|
||||
@Singleton
|
||||
class LocaleManager @Inject constructor(
|
||||
val context: Context
|
||||
) : PreferenceDataStore() {
|
||||
|
||||
private var prefs: SharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
||||
|
||||
fun setLocale(context: Context): Context {
|
||||
val language = prefs.getNonNullString("language", "default")
|
||||
if (language == "default") {
|
||||
return context
|
||||
}
|
||||
val locale = Locale.forLanguageTag(language)
|
||||
Locale.setDefault(locale)
|
||||
fun setLocale() {
|
||||
val language = prefs.getNonNullString(PrefKeys.LANGUAGE, DEFAULT)
|
||||
|
||||
val res = context.resources
|
||||
val config = Configuration(res.configuration)
|
||||
config.setLocale(locale)
|
||||
return context.createConfigurationContext(config)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (language != HANDLED_BY_SYSTEM) {
|
||||
// app is being opened on Android 13+ for the first time
|
||||
// hand over the old setting to the system and save a dummy value in Shared Preferences
|
||||
applyLanguageToApp(language)
|
||||
|
||||
prefs.edit()
|
||||
.putString(PrefKeys.LANGUAGE, HANDLED_BY_SYSTEM)
|
||||
.apply()
|
||||
}
|
||||
} else {
|
||||
// on Android < 13 we have to apply the language at every app start
|
||||
applyLanguageToApp(language)
|
||||
}
|
||||
}
|
||||
|
||||
override fun putString(key: String?, value: String?) {
|
||||
|
||||
// if we are on Android < 13 we have to save the selected language so we can apply it at appstart
|
||||
// on Android 13+ the system handles it for us
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
|
||||
prefs.edit()
|
||||
.putString(PrefKeys.LANGUAGE, value)
|
||||
.apply()
|
||||
}
|
||||
applyLanguageToApp(value)
|
||||
}
|
||||
|
||||
override fun getString(key: String?, defValue: String?): String? {
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
val selectedLanguage = AppCompatDelegate.getApplicationLocales()
|
||||
|
||||
if (selectedLanguage.isEmpty) {
|
||||
DEFAULT
|
||||
} else {
|
||||
// Android lets users select all variants of languages we support in the system settings,
|
||||
// so we need to find the closest match
|
||||
// it should not happen that we find no match, but returning null is fine (picker will show default)
|
||||
|
||||
val availableLanguages = context.resources.getStringArray(R.array.language_values)
|
||||
|
||||
return availableLanguages.find { it == selectedLanguage[0]!!.toLanguageTag() }
|
||||
?: availableLanguages.find { language ->
|
||||
language.startsWith(selectedLanguage[0]!!.language)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
prefs.getNonNullString(PrefKeys.LANGUAGE, DEFAULT)
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyLanguageToApp(language: String?) {
|
||||
val localeList = if (language == DEFAULT) {
|
||||
LocaleListCompat.getEmptyLocaleList()
|
||||
} else {
|
||||
LocaleListCompat.forLanguageTags(language)
|
||||
}
|
||||
|
||||
AppCompatDelegate.setApplicationLocales(localeList)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val DEFAULT = "default"
|
||||
private const val HANDLED_BY_SYSTEM = "handled_by_system"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue