From 37d30eb887d0580fc98eb6a6fd5d6a08bc585721 Mon Sep 17 00:00:00 2001 From: Ivan Iskandar <12537387+ivaniskandar@users.noreply.github.com> Date: Thu, 8 Jul 2021 05:11:52 +0700 Subject: [PATCH] Simplify locale override (#5509) --- app/src/main/java/eu/kanade/tachiyomi/App.kt | 9 -- .../ui/base/activity/BaseRxActivity.kt | 6 - .../ui/base/activity/BaseThemedActivity.kt | 6 + .../base/activity/BaseViewBindingActivity.kt | 6 +- .../ui/setting/SettingsGeneralController.kt | 6 +- .../tachiyomi/util/system/LocaleHelper.kt | 122 +++++------------- 6 files changed, 45 insertions(+), 110 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/App.kt b/app/src/main/java/eu/kanade/tachiyomi/App.kt index d2a1d0bc65..feeda47862 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/App.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/App.kt @@ -7,7 +7,6 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter -import android.content.res.Configuration import android.os.Build import android.webkit.WebView import androidx.core.app.NotificationManagerCompat @@ -28,7 +27,6 @@ import eu.kanade.tachiyomi.data.notification.Notifications import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.network.NetworkHelper import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate -import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.system.notification import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach @@ -68,8 +66,6 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory { setupAcra() setupNotificationChannels() - LocaleHelper.updateConfiguration(this, resources.configuration) - ProcessLifecycleOwner.get().lifecycle.addObserver(this) // Show notification to disable Incognito Mode when it's enabled @@ -106,11 +102,6 @@ open class App : Application(), LifecycleObserver, ImageLoaderFactory { MultiDex.install(this) } - override fun onConfigurationChanged(newConfig: Configuration) { - super.onConfigurationChanged(newConfig) - LocaleHelper.updateConfiguration(this, newConfig, true) - } - override fun newImageLoader(): ImageLoader { return ImageLoader.Builder(this).apply { componentRegistry { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt index 396e9e64f9..f7ab4f104a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseRxActivity.kt @@ -4,7 +4,6 @@ import android.os.Bundle import androidx.viewbinding.ViewBinding import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate -import eu.kanade.tachiyomi.util.system.LocaleHelper import nucleus.view.NucleusAppCompatActivity abstract class BaseRxActivity> : NucleusAppCompatActivity

() { @@ -14,11 +13,6 @@ abstract class BaseRxActivity> : NucleusA lateinit var binding: VB - init { - @Suppress("LeakingThis") - LocaleHelper.updateConfiguration(this) - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseThemedActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseThemedActivity.kt index 58329b9ae7..3f8ca349d4 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseThemedActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseThemedActivity.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.ui.base.activity +import android.content.Context import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate @@ -8,6 +9,7 @@ import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferenceValues import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.asImmediateFlow +import eu.kanade.tachiyomi.util.system.LocaleHelper import eu.kanade.tachiyomi.util.view.setSecureScreen import kotlinx.coroutines.flow.launchIn import uy.kohesive.injekt.Injekt @@ -18,6 +20,10 @@ abstract class BaseThemedActivity : AppCompatActivity() { val preferences: PreferencesHelper by injectLazy() + override fun attachBaseContext(newBase: Context) { + super.attachBaseContext(LocaleHelper.createLocaleWrapper(newBase)) + } + override fun onCreate(savedInstanceState: Bundle?) { applyThemePreferences(preferences) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseViewBindingActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseViewBindingActivity.kt index f72119e01e..1520ccfa8c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseViewBindingActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/activity/BaseViewBindingActivity.kt @@ -1,5 +1,6 @@ package eu.kanade.tachiyomi.ui.base.activity +import android.content.Context import android.os.Bundle import androidx.viewbinding.ViewBinding import eu.kanade.tachiyomi.ui.security.SecureActivityDelegate @@ -12,9 +13,8 @@ abstract class BaseViewBindingActivity : BaseThemedActivity() @Suppress("LeakingThis") private val secureActivityDelegate = SecureActivityDelegate(this) - init { - @Suppress("LeakingThis") - LocaleHelper.updateConfiguration(this) + override fun attachBaseContext(newBase: Context) { + super.attachBaseContext(LocaleHelper.createLocaleWrapper(newBase)) } override fun onCreate(savedInstanceState: Bundle?) { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt index 50f3d0dfae..7078473307 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsGeneralController.kt @@ -232,11 +232,7 @@ class SettingsGeneralController : SettingsController() { summary = "%s" onChange { newValue -> - val activity = activity ?: return@onChange false - val app = activity.application - LocaleHelper.changeLocale(newValue.toString()) - LocaleHelper.updateConfiguration(app, app.resources.configuration) - activity.recreate() + activity?.recreate() true } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/util/system/LocaleHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/util/system/LocaleHelper.kt index ae0ad923d1..d072e48e61 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/util/system/LocaleHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/util/system/LocaleHelper.kt @@ -1,11 +1,11 @@ package eu.kanade.tachiyomi.util.system -import android.app.Application import android.content.Context +import android.content.ContextWrapper import android.content.res.Configuration import android.os.Build -import android.view.ContextThemeWrapper -import androidx.core.os.ConfigurationCompat +import android.os.LocaleList +import androidx.core.os.LocaleListCompat import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.ui.browse.source.SourcePresenter @@ -15,36 +15,10 @@ import java.util.Locale /** * Utility class to change the application's language in runtime. */ -@Suppress("DEPRECATION") object LocaleHelper { private val preferences: PreferencesHelper by injectLazy() - 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 */ @@ -60,18 +34,35 @@ object LocaleHelper { /** * Returns Display name of a string language code + * + * @param lang empty for system language */ fun getDisplayName(lang: String?): String { - return when (lang) { - null -> "" - "" -> { - systemLocale!!.getDisplayName(systemLocale).capitalize() - } - else -> { - val locale = getLocale(lang) - locale.getDisplayName(locale).capitalize() - } + if (lang == null) { + return "" } + + val locale = if (lang.isEmpty()) { + 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)) } /** @@ -87,57 +78,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. - */ - fun changeLocale(pref: String) { - appLocale = getLocaleFromString(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 = ConfigurationCompat.getLocales(config)[0] - } - if (configChange) { - val configLocale = ConfigurationCompat.getLocales(config)[0] - 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 a new configuration with the given locale applied. + * @param pref the string value stored in preferences. */ - private fun updateConfigLocale(config: Configuration, locale: Locale): Configuration { - val newConfig = Configuration(config) - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) { - newConfig.locale = locale - } else { - newConfig.setLocale(locale) + private fun getLocaleFromString(pref: String?): Locale { + if (pref.isNullOrEmpty()) { + return LocaleListCompat.getDefault()[0] } - return newConfig + return getLocale(pref) } }