вызвать SharedPrefrence locale прямо из навигатора - PullRequest
0 голосов
/ 13 июля 2020

У меня есть приложение с многоязычной поддержкой, вы можете установить свой язык по своему усмотрению, но

я хочу вызвать локаль прямо из навигатора, чтобы пользователь может установить язык приложения прямо из навигатора, не переходя к предпочтениям

Вот локаль

object LocaleUtils {
fun getLocalesUsedInProject(context: Context, projectLocales: Array<String>, defaultLocaleText: 
 String): LocalePair {

    val localesEntry = arrayOfNulls<String>(projectLocales.size)
    for (i in projectLocales.indices) {

        val localesEntryValue = projectLocales[i]

        val locale = getLocaleFromString(localesEntryValue)

        val displayLanguage = locale.getDisplayLanguage(locale)
        val displayCountry = locale.getDisplayCountry(locale)
        if (displayCountry.isEmpty()) {
            localesEntry[i] = displayLanguage.firstLetterUppercase()
        } else {
            localesEntry[i] = "${displayLanguage.firstLetterUppercase()} - 
 ${displayCountry.firstLetterUppercase()}"
        }
    }

    //sort
    val localeTreeMap = TreeMap<String, String>()
    for (i in projectLocales.indices) {
        localeTreeMap[localesEntry[i]!!] = projectLocales[i]
    }

    val finalLocaleEntries = ArrayList<String>(localeTreeMap.size + 1).apply { add(0, 
defaultLocaleText) }
    val finalLocaleEntryValues = ArrayList<String>(localeTreeMap.size + 1).apply { add(0, "") }

    var i = 1
    for ((key, value) in localeTreeMap) {
        finalLocaleEntries.add(i, key)
        finalLocaleEntryValues.add(i, value)
        i++
    }

    return LocalePair(finalLocaleEntries.toTypedArray(), finalLocaleEntryValues.toTypedArray())
}

private fun getLocaleFromString(string: String): Locale {

    /**
     * See [android.content.res.AssetManager.getLocales]
     */
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        return Locale.forLanguageTag(string)
    }

    //Best effort on determining the locale

    val separators = arrayOf("_", "-")

    for (separator in separators) {
        //see if there is a language and a country
        if (string.contains(separator)) {
            val splittedLocale = string.split(separator.toRegex()).dropLastWhile { it.isEmpty() 
}.toTypedArray()
            if (splittedLocale.size == 2) {
                return Locale(splittedLocale[0], splittedLocale[1])
            }
        }
    }


    return Locale(string)
   }
   }

  class LocalePair(val localeEntries: Array<String>, val localeEntryValues: Array<String>)

  @Suppress("DEPRECATION")
  fun ContextWrapper.wrap(language: String): ContextWrapper {
  val config = baseContext.resources.configuration
  val sysLocale: Locale = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    this.getSystemLocale()
} else {
    this.getSystemLocaleLegacy()
}

if (language.isNotEmpty() && sysLocale.language != language) {
    val locale = Locale(language)
    Locale.setDefault(locale)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
        this.setSystemLocale(locale)
    } else {
        this.setSystemLocaleLegacy(locale)
    }
}

return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
    val context = baseContext.createConfigurationContext(config)
    ContextWrapper(context)
} else {
    baseContext.resources.updateConfiguration(config, baseContext.resources.displayMetrics)
    ContextWrapper(baseContext)
}
}

@Suppress("DEPRECATION")
fun ContextWrapper.getSystemLocaleLegacy(): Locale = baseContext.resources.configuration.locale

@TargetApi(Build.VERSION_CODES.N)
fun ContextWrapper.getSystemLocale(): Locale = baseContext.resources.configuration.locales[0]

@Suppress("DEPRECATION")
fun Context.getLocaleLanguages(): List<String> {
val locales = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    val locales = ArrayList<Locale>()
    for (i in 0 until resources.configuration.locales.size()) {
        locales.add(resources.configuration.locales.get(i))
    }
    locales
} else arrayListOf(resources.configuration.locale)
return locales.map { it.language }
}

@Suppress("DEPRECATION")
fun ContextWrapper.setSystemLocaleLegacy(locale: Locale) {
baseContext.resources.configuration.locale = locale
}

@TargetApi(Build.VERSION_CODES.N)
fun ContextWrapper.setSystemLocale(locale: Locale) {
baseContext.resources.configuration.setLocale(locale)
}

fun Context.getContextWithLocale(appLocale: String?): Context {
appLocale.takeIf { !it.isNullOrEmpty() }?.let {
    return ContextWrapper(this).wrap(it)
}
return this
}

Действие PrefrenceUI

@ObsoleteCoroutinesApi
@ExperimentalCoroutinesApi
class PreferencesUi : BasePreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {

override fun getXml() = R.xml.preferences_ui

override fun getTitleId() = R.string.interface_prefs_screen

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    prepareLocaleList()
    setupTheme()
}

override fun onCreatePreferences(bundle: Bundle?, s: String?) {
    super.onCreatePreferences(bundle, s)
    val groupVideoPreference = preferenceManager.findPreference<EditTextPreference> 
 ("video_group_size")
    groupVideoPreference?.setOnBindEditTextListener { editText ->
        editText.inputType = InputType.TYPE_CLASS_NUMBER
    }
    groupVideoPreference?.summaryProvider = Preference.SummaryProvider<EditTextPreference> { 
preference ->
        val text = preference.text
        if (TextUtils.isEmpty(text)) {
            ""
        } else {
            getString(R.string.video_group_size_summary, text)
        }
    }
}

private fun setupTheme() {
    val prefs = preferenceScreen.sharedPreferences
    if (!prefs.contains(KEY_APP_THEME)) {
        var theme = AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM
        if (prefs.getBoolean(KEY_DAYNIGHT, false) && !AndroidDevices.canUseSystemNightMode()) {
            theme = AppCompatDelegate.MODE_NIGHT_AUTO
        } else if (prefs.contains(KEY_BLACK_THEME)) {
            theme = if (prefs.getBoolean(KEY_BLACK_THEME, false))
                AppCompatDelegate.MODE_NIGHT_YES
            else
                AppCompatDelegate.MODE_NIGHT_NO
        }
        prefs.edit().putString(KEY_APP_THEME, theme.toString()).apply()
    }
  }

override fun onStart() {
    super.onStart()
    preferenceScreen.sharedPreferences.registerOnSharedPreferenceChangeListener(this)
}

override fun onStop() {
    super.onStop()
    preferenceScreen.sharedPreferences
            .unregisterOnSharedPreferenceChangeListener(this)
}

override fun onPreferenceTreeClick(preference: Preference): Boolean {
    if (preference.key == null) return false
    when (preference.key) {
        PREF_TV_UI -> {
            Settings.tvUI = (preference as TwoStatePreference).isChecked
            (activity as PreferencesActivity).setRestartApp()
            return true
        }
        SHOW_VIDEO_THUMBNAILS -> {
            Settings.showVideoThumbs = (preference as TwoStatePreference).isChecked
            (activity as PreferencesActivity).setRestart()
            return true
        }
        "media_seen" -> requireActivity().setResult(RESULT_UPDATE_SEEN_MEDIA)
        KEY_ARTISTS_SHOW_ALL -> (activity as PreferencesActivity).updateArtists()
    }
    return super.onPreferenceTreeClick(preference)
}

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
    when (key) {
        "set_locale" -> {
            (activity as PreferencesActivity).setRestart()
            UiTools.restartDialog(requireActivity())
        }
        "browser_show_all_files", "video_min_group_length" -> (activity as 
 PreferencesActivity).setRestart()
        KEY_APP_THEME -> (activity as PreferencesActivity).exitAndRescan()
        LIST_TITLE_ELLIPSIZE -> {
            Settings.listTitleEllipsize = sharedPreferences.getString(LIST_TITLE_ELLIPSIZE, 
 "0")?.toInt() ?: 0
            (activity as PreferencesActivity).setRestart()
        }
        "video_group_size" -> {
            val goupSizeValue = try {
                Settings.getInstance(requireActivity()).getString(key, "6")?.toInt() ?: 6
            } catch (e: NumberFormatException) {
                6
            }
            Medialibrary.getInstance().setVideoGroupsPrefixLength(goupSizeValue)
            (activity as PreferencesActivity).setRestart()
        }
    }
}

private fun prepareLocaleList() {
    val localePair = LocaleUtils.getLocalesUsedInProject(requireActivity(), 
BuildConfig.TRANSLATION_ARRAY, getString(R.string.device_default))
    val lp = findPreference<ListPreference>("set_locale")
    lp?.entries = localePair.localeEntries
    lp?.entryValues = localePair.localeEntryValues
   }
  }

Навигатор

class Navigator: NavigationView.OnNavigationItemSelectedListener, LifecycleObserver, INavigator {

private val defaultFragmentId= R.id.nav_video
override var currentFragmentId : Int = 0
var currentFragment: Fragment? = null
    private set
private lateinit var activity: MainActivity
private lateinit var settings: SharedPreferences
private var extensionsService: ExtensionManagerService? = null
override lateinit var navigationView: NavigationView
override lateinit var drawerLayout: HackyDrawerLayout
override lateinit var drawerToggle: ActionBarDrawerToggle

override lateinit var extensionsManager: ExtensionsManager
override var extensionServiceConnection: ServiceConnection? = null
override var extensionManagerService: ExtensionManagerService? = null
private val isExtensionServiceBinded: Boolean
    get() = extensionServiceConnection != null

override fun MainActivity.setupNavigation(state: Bundle?) {
    activity = this
    this@Navigator.settings = settings
    currentFragmentId = intent.getIntExtra(EXTRA_TARGET, 0)
    if (state !== null) {
        currentFragment = supportFragmentManager.getFragment(state, "current_fragment")
    } else {
        if (intent.getBooleanExtra(EXTRA_UPGRADE, false)) {
            /*
             * The sliding menu is automatically opened when the user closes
             * the info dialog. If (for any reason) the dialog is not shown,
             * open the menu after a short delay.
             */
            lifecycleScope.launchWhenStarted {
                delay(500L)
                drawerLayout.openDrawer(navigationView)
            }
        }
    }
    lifecycle.addObserver(this@Navigator)
    navigationView = findViewById(R.id.navigation)
    navigationView.menu.findItem(R.id.nav_history).isVisible = settings.getBoolean(PLAYBACK_HISTORY, 
true)
    drawerLayout = findViewById(R.id.root_container)

    drawerToggle = ActionBarDrawerToggle(this, drawerLayout, R.string.drawer_open, 
 R.string.drawer_close)
    drawerLayout.addDrawerListener(drawerToggle)
    drawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START)

    val headerView = navigationView.getHeaderView(0)
    if (BuildConfig.DEBUG) {
        headerView.findViewById<TextView>(R.id.nav_header_title).text = 
"${getString(R.string.app_name)} - ${BuildConfig.VERSION_NAME}"
    }
    headerView.findViewById<ImageView>(R.id.nav_header_background).setOnClickListener {
        showSecondaryFragment(SecondaryActivity.ABOUT)
    }
}

@OnLifecycleEvent(Lifecycle.Event.ON_START)
fun onStart() {
    if (currentFragment === null && !currentIdIsExtension()) showFragment(if (currentFragmentId != 0) 
currentFragmentId else settings.getInt("fragment_id", defaultFragmentId))
    navigationView.setNavigationItemSelectedListener(this)
    if (BuildConfig.DEBUG) createExtensionServiceConnection()
}

@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onStop() {
    navigationView.setNavigationItemSelectedListener(null)
    if (isExtensionServiceBinded) {
        activity.unbindService(extensionServiceConnection!!)
        extensionServiceConnection = null
    }
    if (currentIdIsExtension())
        settings.edit()
                .putString("current_extension_name", 
extensionsManager.getExtensions(activity.application, false) 
 [currentFragmentId].componentName().packageName)
                .apply()
}

private fun getNewFragment(id: Int): Fragment   {
    return when (id) {
        R.id.nav_audio -> AudioBrowserFragment()
        R.id.nav_directories -> FileBrowserFragment()
        R.id.nav_playlists -> PlaylistFragment()
        R.id.nav_history -> HistoryFragment()
        R.id.nav_network -> NetworkBrowserFragment()
        R.id.nav_mrl -> MRLPanelFragment()
        R.id.nav_about -> AboutFragment()
        R.id.nav_whatsapp -> TabActivity()
        R.id.nav_language -> LanguageNav()








        else -> {
            val group = 
 
 
 
Integer.valueOf(Settings.getInstance(activity.applicationContext).
getString("video_min_group_length", 
 "-1")!!)
            when {
                group > 0 -> VideoGridFragment().apply {
                    arguments = Bundle(1).apply {
                        putSerializable(KEY_GROUPING, VideoGroupingType.NAME)
                    }

                }
                group == 0 -> VideoGridFragment().apply {
                    arguments = Bundle(1).apply {
                        putSerializable(KEY_GROUPING, VideoGroupingType.FOLDER)
                    }
                }
                else -> VideoGridFragment()
            }
        }
    }
}


private fun showFragment(id: Int) {
    val tag = getTag(id)
    val fragment = getNewFragment(id)
    showFragment(fragment, id, tag)
}

override fun forceLoadVideoFragment() {
    showFragment(R.id.nav_video)

}

private fun showFragment(fragment: Fragment, id: Int, tag: String = getTag(id)) {
    val fm = activity.supportFragmentManager
    if (currentFragment is BaseBrowserFragment) fm.popBackStackImmediate("root", 
 FragmentManager.POP_BACK_STACK_INCLUSIVE)
    val ft = fm.beginTransaction()
    ft.replace(R.id.fragment_placeholder, fragment, tag)
    if (BuildConfig.DEBUG) ft.commit()
    else ft.commitAllowingStateLoss()
    updateCheckedItem(id)
    currentFragment = fragment
    currentFragmentId = id
}

private fun showSecondaryFragment(fragmentTag: String, param: String? = null) {
    val i = Intent(activity, SecondaryActivity::class.java)
    i.putExtra("fragment", fragmentTag)
    param?.let { i.putExtra("param", it) }
    activity.startActivityForResult(i, SecondaryActivity.ACTIVITY_RESULT_SECONDARY)
    // Slide down the audio player if needed.
    activity.slideDownAudioPlayer()
}

override fun currentIdIsExtension() = idIsExtension(currentFragmentId)

private fun idIsExtension(id: Int) = id in 1..100

private fun clearBackstackFromClass(clazz: Class<*>) {
    val fm = activity.supportFragmentManager
    while (clazz.isInstance(currentFragment)) if (!fm.popBackStackImmediate()) break
}

override fun reloadPreferences() {
    currentFragmentId = settings.getInt("fragment_id", defaultFragmentId)
}

override fun closeDrawer() {
    drawerLayout.closeDrawer(navigationView)
}

private fun getTag(id: Int) = when (id) {
    R.id.nav_settings -> ID_PREFERENCES
    R.id.nav_audio -> ID_AUDIO
    R.id.nav_playlists -> ID_PLAYLISTS
    R.id.nav_directories -> ID_DIRECTORIES
    R.id.nav_history -> ID_HISTORY
    R.id.nav_mrl -> ID_MRL
    R.id.nav_network -> ID_NETWORK
    R.id.nav_about -> ID_ABOUT
    R.id.nav_whatsapp ->ID_WHATSAPP
    R.id.nav_language -> ID_lANGUAGE
    else -> ID_VIDEO
}

override fun onNavigationItemSelected(item: MenuItem): Boolean {
    val id = item.itemId
    val current = currentFragment
    if (item.groupId == R.id.extensions_group) {
        if (currentFragmentId == id) {
            clearBackstackFromClass(ExtensionBrowser::class.java)
            activity.closeDrawer()
            return false
        } else
            extensionsService?.openExtension(id)
    } else {
        if (isExtensionServiceBinded) extensionsService?.disconnect()

        if (current == null) {
            activity.closeDrawer()
            return false
        }

        if (currentFragmentId == id) { /* Already selected */
            // Go back at root level of current mProvider
            if ((current as? BaseBrowserFragment)?.isStarted() == false) {
                activity.supportFragmentManager.popBackStackImmediate("root", 
FragmentManager.POP_BACK_STACK_INCLUSIVE)
            } else {
                activity.closeDrawer()
                return false
            }
        } else when (id) {
            R.id.nav_settings -> activity.startActivityForResult(Intent(activity, 
 PreferencesActivity::class.java), ACTIVITY_RESULT_PREFERENCES)
            else -> {
                activity.slideDownAudioPlayer()
                showFragment(id)
            }
        }
    }
    activity.closeDrawer()
    return true
}

override fun displayExtensionItems(extensionId: Int, title: String, items: List<VLCExtensionItem>, 
showParams: Boolean, refresh: Boolean) {
    if (refresh && currentFragment is ExtensionBrowser) {
        (currentFragment as ExtensionBrowser).doRefresh(title, items)
    } else {
        val fragment = ExtensionBrowser()
        fragment.arguments =  Bundle().apply {
            putParcelableArrayList(ExtensionBrowser.KEY_ITEMS_LIST, ArrayList(items))
            putBoolean(ExtensionBrowser.KEY_SHOW_FAB, showParams)
            putString(ExtensionBrowser.KEY_TITLE, title)
        }
        extensionsService?.let { fragment.setExtensionService(it) }
        when {
            currentFragment !is ExtensionBrowser -> //case: non-extension to extension root
                showFragment(fragment, extensionId, title)
            currentFragmentId == extensionId -> //case: extension root to extension sub dir
                showFragment(fragment, extensionId, title)
            else -> { //case: extension to other extension root
                clearBackstackFromClass(ExtensionBrowser::class.java)
                showFragment(fragment, extensionId, title)
            }
        }
    }
    navigationView.menu.findItem(extensionId).isCheckable = true
    updateCheckedItem(extensionId)
}

private fun updateCheckedItem(id: Int) {
    when (id) {
        R.id.nav_settings -> return
        else -> {
            val currentId = currentFragmentId
            val target = navigationView.menu.findItem(id)
            if (id != currentId && target != null) {
                val current = navigationView.menu.findItem(currentId)
                if (current != null) current.isChecked = false
                target.isChecked = true
                /* Save the tab status in pref */
                settings.edit().putInt("fragment_id", id).apply()
            }
        }
    }
}

private fun loadPlugins() {
    val plugins = extensionsManager.getExtensions(activity, true)
    if (plugins.isEmpty()) {
        extensionServiceConnection?.let { activity.unbindService(it) }
        extensionServiceConnection = null
        extensionManagerService?.stopSelf()
        return
    }
    val extensionGroup = navigationView.menu.findItem(R.id.extensions_group)
    extensionGroup.subMenu.clear()
    for (id in plugins.indices) {
        val extension = plugins[id]
        val key = "extension_" + extension.componentName().packageName
        if (settings.contains(key)) {
            extensionsManager.displayPlugin(activity, id, extension, settings.getBoolean(key, false))
        } else {
            extensionsManager.showExtensionPermissionDialog(activity, id, extension, key)
        }
    }
    if (extensionGroup.subMenu.size() == 0) extensionGroup.isVisible = false
    onPluginsLoaded()
    navigationView.invalidate()
}


private fun onPluginsLoaded() {
    if (currentFragment == null && currentIdIsExtension())
        if (extensionsManager.previousExtensionIsEnabled(activity.application))
            extensionManagerService?.openExtension(currentFragmentId)
        else
            showFragment(R.id.nav_video)
}

private fun createExtensionServiceConnection() {
    extensionServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            extensionManagerService = (service as ExtensionManagerService.LocalBinder).service.apply 
{
                setExtensionManagerActivity(activity)
            }
            loadPlugins()
        }

        override fun onServiceDisconnected(name: ComponentName) {}
    }
    // Bind service which discoverves au connects toplugins
    if (!activity.bindService(Intent(activity,
                    ExtensionManagerService::class.java), extensionServiceConnection!!, 
Context.BIND_AUTO_CREATE))
        extensionServiceConnection = null
}
}

interface INavigator {
var navigationView: NavigationView
var currentFragmentId : Int

var drawerLayout: HackyDrawerLayout
var drawerToggle: ActionBarDrawerToggle

var extensionsManager: ExtensionsManager
var extensionServiceConnection: ServiceConnection?
var extensionManagerService: ExtensionManagerService?

fun MainActivity.setupNavigation(state: Bundle?)
fun currentIdIsExtension() : Boolean
fun displayExtensionItems(extensionId: Int, title: String, items: List<VLCExtensionItem>, showParams: 
Boolean, refresh: Boolean)
fun reloadPreferences()
fun closeDrawer()
fun forceLoadVideoFragment()

вот чего я хочу достичь

...