mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Simplify locale override (#5509)
This commit is contained in:
		@@ -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 {
 | 
			
		||||
 
 | 
			
		||||
@@ -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<VB : ViewBinding, P : BasePresenter<*>> : NucleusAppCompatActivity<P>() {
 | 
			
		||||
@@ -14,11 +13,6 @@ abstract class BaseRxActivity<VB : ViewBinding, P : BasePresenter<*>> : NucleusA
 | 
			
		||||
 | 
			
		||||
    lateinit var binding: VB
 | 
			
		||||
 | 
			
		||||
    init {
 | 
			
		||||
        @Suppress("LeakingThis")
 | 
			
		||||
        LocaleHelper.updateConfiguration(this)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun onCreate(savedInstanceState: Bundle?) {
 | 
			
		||||
        super.onCreate(savedInstanceState)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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)
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -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<VB : ViewBinding> : 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?) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
@@ -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.
 | 
			
		||||
     * @param pref the string 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)
 | 
			
		||||
    private fun getLocaleFromString(pref: String?): Locale {
 | 
			
		||||
        if (pref.isNullOrEmpty()) {
 | 
			
		||||
            return LocaleListCompat.getDefault()[0]
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 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.
 | 
			
		||||
     */
 | 
			
		||||
    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)
 | 
			
		||||
        }
 | 
			
		||||
        return newConfig
 | 
			
		||||
        return getLocale(pref)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user