Simplify locale override (#5509)

Closes #906
This commit is contained in:
Ivan Iskandar 2021-07-08 05:11:52 +07:00 committed by Jays2Kings
parent 70529c85a8
commit ae65677a37
6 changed files with 48 additions and 119 deletions

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi
import android.app.Application import android.app.Application
import android.content.Context import android.content.Context
import android.content.res.Configuration
import android.os.Build import android.os.Build
import androidx.lifecycle.Lifecycle import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver import androidx.lifecycle.LifecycleObserver
@ -14,7 +13,6 @@ import eu.kanade.tachiyomi.data.notification.Notifications
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.preference.getOrDefault
import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate
import eu.kanade.tachiyomi.util.system.LocaleHelper
import org.acra.ACRA import org.acra.ACRA
import org.acra.config.httpSender import org.acra.config.httpSender
import org.acra.data.StringFormat import org.acra.data.StringFormat
@ -54,7 +52,6 @@ open class App : Application(), LifecycleObserver {
setupAcra() setupAcra()
setupNotificationChannels() setupNotificationChannels()
LocaleHelper.updateConfiguration(this, resources.configuration)
ProcessLifecycleOwner.get().lifecycle.addObserver(this) ProcessLifecycleOwner.get().lifecycle.addObserver(this)
// Reset Incognito Mode on relaunch // Reset Incognito Mode on relaunch
@ -75,11 +72,6 @@ open class App : Application(), LifecycleObserver {
MultiDex.install(this) MultiDex.install(this)
} }
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
LocaleHelper.updateConfiguration(this, newConfig, true)
}
protected open fun setupAcra() { protected open fun setupAcra() {
initAcra { initAcra {
reportFormat = StringFormat.JSON reportFormat = StringFormat.JSON

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.base.activity package eu.kanade.tachiyomi.ui.base.activity
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.viewbinding.ViewBinding import androidx.viewbinding.ViewBinding
@ -17,9 +18,8 @@ abstract class BaseActivity<VB : ViewBinding> : AppCompatActivity() {
lateinit var binding: VB lateinit var binding: VB
val isBindingInitialized get() = this::binding.isInitialized val isBindingInitialized get() = this::binding.isInitialized
init { override fun attachBaseContext(newBase: Context) {
@Suppress("LeakingThis") super.attachBaseContext(LocaleHelper.createLocaleWrapper(newBase))
LocaleHelper.updateConfiguration(this)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.base.activity package eu.kanade.tachiyomi.ui.base.activity
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
@ -11,9 +12,8 @@ abstract class BaseRxActivity<P : BasePresenter<*>> : NucleusAppCompatActivity<P
val scope = lifecycleScope val scope = lifecycleScope
init { override fun attachBaseContext(newBase: Context) {
@Suppress("LeakingThis") super.attachBaseContext(LocaleHelper.createLocaleWrapper(newBase))
LocaleHelper.updateConfiguration(this)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {

View File

@ -1,15 +1,21 @@
package eu.kanade.tachiyomi.ui.base.activity package eu.kanade.tachiyomi.ui.base.activity
import android.content.Context
import android.os.Bundle import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.util.system.setThemeAndNight import eu.kanade.tachiyomi.util.system.setThemeAndNight
import eu.kanade.tachiyomi.util.system.LocaleHelper
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
abstract class BaseThemedActivity : AppCompatActivity() { abstract class BaseThemedActivity : AppCompatActivity() {
val preferences: PreferencesHelper by injectLazy() val preferences: PreferencesHelper by injectLazy()
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.createLocaleWrapper(newBase))
}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
setThemeAndNight(preferences) setThemeAndNight(preferences)
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)

View File

@ -252,11 +252,7 @@ class SettingsGeneralController : SettingsController() {
defaultValue = "" defaultValue = ""
onChange { newValue -> onChange { newValue ->
val activity = activity ?: return@onChange false activity?.recreate()
val app = activity.application
LocaleHelper.changeLocale(newValue.toString())
LocaleHelper.updateConfiguration(app, app.resources.configuration)
activity.recreate()
true true
} }
} }

View File

@ -1,10 +1,11 @@
package eu.kanade.tachiyomi.util.system package eu.kanade.tachiyomi.util.system
import android.app.Application
import android.content.Context import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build import android.os.Build
import android.view.ContextThemeWrapper import android.os.LocaleList
import androidx.core.os.LocaleListCompat
import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.PreferencesHelper
import eu.kanade.tachiyomi.ui.source.SourcePresenter import eu.kanade.tachiyomi.ui.source.SourcePresenter
@ -14,7 +15,6 @@ import java.util.Locale
/** /**
* Utility class to change the application's language in runtime. * Utility class to change the application's language in runtime.
*/ */
@Suppress("DEPRECATION")
object LocaleHelper { object LocaleHelper {
/** /**
@ -22,34 +22,6 @@ object LocaleHelper {
*/ */
private val preferences: PreferencesHelper by injectLazy() private val preferences: PreferencesHelper by injectLazy()
/**
* The system's locale.
*/
private var systemLocale: Locale? = null
/**
* The application's locale. When it's null, the system locale is used.
*/
private var appLocale = getLocaleFromString(preferences.lang().get())
/**
* The currently applied locale. Used to avoid losing the selected language after a non locale
* configuration change to the application.
*/
private var currentLocale: Locale? = null
/**
* Returns the locale for the value stored in preferences, or null if it's system language.
*
* @param pref the string value stored in preferences.
*/
fun getLocaleFromString(pref: String?): Locale? {
if (pref.isNullOrEmpty()) {
return null
}
return getLocale(pref)
}
/** /**
* Returns Display name of a string language code * Returns Display name of a string language code
*/ */
@ -65,18 +37,35 @@ object LocaleHelper {
/** /**
* Returns Display name of a string language code * Returns Display name of a string language code
*
* @param lang empty for system language
*/ */
fun getDisplayName(lang: String?): String { fun getDisplayName(lang: String?): String {
return when (lang) { if (lang == null) {
null -> "" return ""
"" -> {
systemLocale!!.getDisplayName(systemLocale).capitalize()
} }
else -> {
val locale = getLocale(lang) val locale = if (lang.isEmpty()) {
locale.getDisplayName(locale).capitalize() LocaleListCompat.getAdjustedDefault()[0]
} else {
getLocale(lang)
} }
return locale.getDisplayName(locale).replaceFirstChar { it.uppercase(locale) }
} }
/**
* Creates a ContextWrapper using selected Locale
*/
fun createLocaleWrapper(context: Context): ContextWrapper {
val appLocale = getLocaleFromString(preferences.lang().get())
val newConfiguration = Configuration(context.resources.configuration)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
val localeList = LocaleList(appLocale)
newConfiguration.setLocales(localeList)
} else {
newConfiguration.setLocale(appLocale)
}
return ContextWrapper(context.createConfigurationContext(newConfiguration))
} }
/*Return Locale from string language code /*Return Locale from string language code
@ -92,68 +81,14 @@ object LocaleHelper {
} }
/** /**
* Changes the application's locale with a new preference. * Returns the locale for the value stored in preferences, defaults to main system language.
* *
* @param pref the new value stored in preferences. * @param pref the string value stored in preferences.
*/ */
fun changeLocale(pref: String) { private fun getLocaleFromString(pref: String?): Locale {
appLocale = getLocaleFromString(pref) if (pref.isNullOrEmpty()) {
return LocaleListCompat.getDefault()[0]
} }
return getLocale(pref)
/**
* Updates the app's language to an activity.
*/
fun updateConfiguration(wrapper: ContextThemeWrapper) {
if (appLocale != null) {
val config = Configuration(preferences.context.resources.configuration)
config.setLocale(appLocale)
wrapper.applyOverrideConfiguration(config)
}
}
/**
* Updates the app's language to the application.
*/
fun updateConfiguration(app: Application, config: Configuration, configChange: Boolean = false) {
if (systemLocale == null) {
systemLocale = getConfigLocale(config)
}
if (configChange) {
val configLocale = getConfigLocale(config)
if (currentLocale == configLocale) {
return
}
systemLocale = configLocale
}
currentLocale = appLocale ?: systemLocale ?: Locale.getDefault()
val newConfig = updateConfigLocale(config, currentLocale!!)
val resources = app.resources
resources.updateConfiguration(newConfig, resources.displayMetrics)
Locale.setDefault(currentLocale)
}
/**
* Returns the locale applied in the given configuration.
*/
private fun getConfigLocale(config: Configuration): Locale {
return if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
config.locale
} else {
config.locales[0]
}
}
/**
* Returns a new configuration with the given locale applied.
*/
private fun updateConfigLocale(config: Configuration, locale: Locale): Configuration {
val newConfig = Configuration(config)
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
newConfig.setLocale(locale)
} else {
newConfig.setLocale(locale)
}
return newConfig
} }
} }