mirror of
https://github.com/element-hq/element-android
synced 2024-11-23 18:05:36 +03:00
Locale: support locale change
This commit is contained in:
parent
9fed62e4a7
commit
f45040c405
17 changed files with 444 additions and 50 deletions
|
@ -2,7 +2,7 @@ Changes in RiotX 0.21.0 (2020-XX-XX)
|
||||||
===================================================
|
===================================================
|
||||||
|
|
||||||
Features ✨:
|
Features ✨:
|
||||||
-
|
- Switch language support (#41)
|
||||||
|
|
||||||
Improvements 🙌:
|
Improvements 🙌:
|
||||||
- Better connectivity lost indicator when airplane mode is on
|
- Better connectivity lost indicator when airplane mode is on
|
||||||
|
|
|
@ -61,8 +61,6 @@ import im.vector.riotx.features.login.LoginSplashFragment
|
||||||
import im.vector.riotx.features.login.LoginWaitForEmailFragment
|
import im.vector.riotx.features.login.LoginWaitForEmailFragment
|
||||||
import im.vector.riotx.features.login.LoginWebFragment
|
import im.vector.riotx.features.login.LoginWebFragment
|
||||||
import im.vector.riotx.features.login.terms.LoginTermsFragment
|
import im.vector.riotx.features.login.terms.LoginTermsFragment
|
||||||
import im.vector.riotx.features.userdirectory.KnownUsersFragment
|
|
||||||
import im.vector.riotx.features.userdirectory.UserDirectoryFragment
|
|
||||||
import im.vector.riotx.features.qrcode.QrCodeScannerFragment
|
import im.vector.riotx.features.qrcode.QrCodeScannerFragment
|
||||||
import im.vector.riotx.features.reactions.EmojiChooserFragment
|
import im.vector.riotx.features.reactions.EmojiChooserFragment
|
||||||
import im.vector.riotx.features.reactions.EmojiSearchResultFragment
|
import im.vector.riotx.features.reactions.EmojiSearchResultFragment
|
||||||
|
@ -92,9 +90,12 @@ import im.vector.riotx.features.settings.devtools.IncomingKeyRequestListFragment
|
||||||
import im.vector.riotx.features.settings.devtools.KeyRequestsFragment
|
import im.vector.riotx.features.settings.devtools.KeyRequestsFragment
|
||||||
import im.vector.riotx.features.settings.devtools.OutgoingKeyRequestListFragment
|
import im.vector.riotx.features.settings.devtools.OutgoingKeyRequestListFragment
|
||||||
import im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
import im.vector.riotx.features.settings.ignored.VectorSettingsIgnoredUsersFragment
|
||||||
|
import im.vector.riotx.features.settings.locale.LocalePickerFragment
|
||||||
import im.vector.riotx.features.settings.push.PushGatewaysFragment
|
import im.vector.riotx.features.settings.push.PushGatewaysFragment
|
||||||
import im.vector.riotx.features.share.IncomingShareFragment
|
import im.vector.riotx.features.share.IncomingShareFragment
|
||||||
import im.vector.riotx.features.signout.soft.SoftLogoutFragment
|
import im.vector.riotx.features.signout.soft.SoftLogoutFragment
|
||||||
|
import im.vector.riotx.features.userdirectory.KnownUsersFragment
|
||||||
|
import im.vector.riotx.features.userdirectory.UserDirectoryFragment
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
interface FragmentModule {
|
interface FragmentModule {
|
||||||
|
@ -109,6 +110,11 @@ interface FragmentModule {
|
||||||
@FragmentKey(RoomListFragment::class)
|
@FragmentKey(RoomListFragment::class)
|
||||||
fun bindRoomListFragment(fragment: RoomListFragment): Fragment
|
fun bindRoomListFragment(fragment: RoomListFragment): Fragment
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
@IntoMap
|
||||||
|
@FragmentKey(LocalePickerFragment::class)
|
||||||
|
fun bindLocalePickerFragment(fragment: LocalePickerFragment): Fragment
|
||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
@IntoMap
|
@IntoMap
|
||||||
@FragmentKey(GroupListFragment::class)
|
@FragmentKey(GroupListFragment::class)
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package im.vector.riotx.core.extensions
|
package im.vector.riotx.core.extensions
|
||||||
|
|
||||||
|
import android.app.Activity
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentTransaction
|
import androidx.fragment.app.FragmentTransaction
|
||||||
|
@ -59,3 +60,8 @@ fun <T : Fragment> VectorBaseActivity.addFragmentToBackstack(frameId: Int,
|
||||||
fun VectorBaseActivity.hideKeyboard() {
|
fun VectorBaseActivity.hideKeyboard() {
|
||||||
currentFocus?.hideKeyboard()
|
currentFocus?.hideKeyboard()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Activity.restart() {
|
||||||
|
startActivity(intent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@ import javax.inject.Inject
|
||||||
/**
|
/**
|
||||||
* Handle locale configuration change, such as theme, font size and locale chosen by the user
|
* Handle locale configuration change, such as theme, font size and locale chosen by the user
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class VectorConfiguration @Inject constructor(private val context: Context) {
|
class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
|
|
||||||
// TODO Import mLanguageReceiver From Riot?
|
// TODO Import mLanguageReceiver From Riot?
|
||||||
|
@ -98,7 +97,6 @@ class VectorConfiguration @Inject constructor(private val context: Context) {
|
||||||
*
|
*
|
||||||
* @param locale
|
* @param locale
|
||||||
*/
|
*/
|
||||||
// TODO Call from LanguagePickerActivity
|
|
||||||
fun updateApplicationLocale(locale: Locale) {
|
fun updateApplicationLocale(locale: Locale) {
|
||||||
updateApplicationSettings(locale, FontScale.getFontScalePrefValue(context), ThemeUtils.getApplicationTheme(context))
|
updateApplicationSettings(locale, FontScale.getFontScalePrefValue(context), ThemeUtils.getApplicationTheme(context))
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,8 @@ package im.vector.riotx.features.settings
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.res.Configuration
|
import android.content.res.Configuration
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.preference.PreferenceManager
|
|
||||||
import androidx.core.content.edit
|
import androidx.core.content.edit
|
||||||
import im.vector.riotx.BuildConfig
|
import androidx.preference.PreferenceManager
|
||||||
import im.vector.riotx.R
|
import im.vector.riotx.R
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
@ -75,7 +74,7 @@ object VectorLocale {
|
||||||
saveApplicationLocale(context, applicationLocale)
|
saveApplicationLocale(context, applicationLocale)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init the known locales in background, using kotlin coroutines
|
// init the known locales in background
|
||||||
GlobalScope.launch(Dispatchers.IO) {
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
initApplicationLocales(context)
|
initApplicationLocales(context)
|
||||||
}
|
}
|
||||||
|
@ -144,6 +143,7 @@ object VectorLocale {
|
||||||
} else {
|
} else {
|
||||||
val resources = context.resources
|
val resources = context.resources
|
||||||
val conf = resources.configuration
|
val conf = resources.configuration
|
||||||
|
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
val savedLocale = conf.locale
|
val savedLocale = conf.locale
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
|
@ -235,22 +235,29 @@ object VectorLocale {
|
||||||
append(locale.getDisplayCountry(locale))
|
append(locale.getDisplayCountry(locale))
|
||||||
append(")")
|
append(")")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// In debug mode, also display information about the locale in the current locale.
|
/**
|
||||||
if (BuildConfig.DEBUG) {
|
* Information about the locale in the current locale
|
||||||
append("\n[")
|
*
|
||||||
append(locale.displayLanguage)
|
* @param locale the locale to get info from
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && locale.script != "Latn") {
|
* @return the string
|
||||||
append(" - ")
|
*/
|
||||||
append(locale.displayScript)
|
fun localeToLocalisedStringInfo(locale: Locale): String {
|
||||||
}
|
return buildString {
|
||||||
if (locale.displayCountry.isNotEmpty()) {
|
append("[")
|
||||||
append(" (")
|
append(locale.displayLanguage)
|
||||||
append(locale.displayCountry)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && locale.script != "Latn") {
|
||||||
append(")")
|
append(" - ")
|
||||||
}
|
append(locale.displayScript)
|
||||||
append("]")
|
|
||||||
}
|
}
|
||||||
|
if (locale.displayCountry.isNotEmpty()) {
|
||||||
|
append(" (")
|
||||||
|
append(locale.displayCountry)
|
||||||
|
append(")")
|
||||||
|
}
|
||||||
|
append("]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ package im.vector.riotx.features.settings
|
||||||
|
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
|
||||||
import android.widget.CheckedTextView
|
import android.widget.CheckedTextView
|
||||||
import android.widget.LinearLayout
|
import android.widget.LinearLayout
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
|
@ -129,21 +128,6 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
|
||||||
super.onActivityResult(requestCode, resultCode, data)
|
|
||||||
|
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
|
||||||
when (requestCode) {
|
|
||||||
REQUEST_LOCALE -> {
|
|
||||||
activity?.let {
|
|
||||||
startActivity(it.intent)
|
|
||||||
it.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
// user interface management
|
// user interface management
|
||||||
// ==============================================================================================================
|
// ==============================================================================================================
|
||||||
|
@ -152,12 +136,6 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
// Selected language
|
// Selected language
|
||||||
selectedLanguagePreference.summary = VectorLocale.localeToLocalisedString(VectorLocale.applicationLocale)
|
selectedLanguagePreference.summary = VectorLocale.localeToLocalisedString(VectorLocale.applicationLocale)
|
||||||
|
|
||||||
selectedLanguagePreference.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
|
||||||
notImplemented()
|
|
||||||
// TODO startActivityForResult(LanguagePickerActivity.getIntent(activity), REQUEST_LOCALE)
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
// Text size
|
// Text size
|
||||||
textSizePreference.summary = FontScale.getFontScaleDescription(activity!!)
|
textSizePreference.summary = FontScale.getFontScaleDescription(activity!!)
|
||||||
|
|
||||||
|
@ -199,8 +177,4 @@ class VectorSettingsPreferencesFragment @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val REQUEST_LOCALE = 777
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import android.widget.TextView
|
||||||
|
import com.airbnb.epoxy.EpoxyAttribute
|
||||||
|
import com.airbnb.epoxy.EpoxyModelClass
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.epoxy.ClickListener
|
||||||
|
import im.vector.riotx.core.epoxy.VectorEpoxyHolder
|
||||||
|
import im.vector.riotx.core.epoxy.VectorEpoxyModel
|
||||||
|
import im.vector.riotx.core.epoxy.onClick
|
||||||
|
import im.vector.riotx.core.extensions.setTextOrHide
|
||||||
|
|
||||||
|
@EpoxyModelClass(layout = R.layout.item_locale)
|
||||||
|
abstract class LocaleItem : VectorEpoxyModel<LocaleItem.Holder>() {
|
||||||
|
|
||||||
|
@EpoxyAttribute var title: String? = null
|
||||||
|
@EpoxyAttribute var subtitle: String? = null
|
||||||
|
@EpoxyAttribute var clickListener: ClickListener? = null
|
||||||
|
|
||||||
|
override fun bind(holder: Holder) {
|
||||||
|
super.bind(holder)
|
||||||
|
|
||||||
|
holder.view.onClick { clickListener?.invoke() }
|
||||||
|
holder.titleView.setTextOrHide(title)
|
||||||
|
holder.subtitleView.setTextOrHide(subtitle)
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder : VectorEpoxyHolder() {
|
||||||
|
val titleView by bind<TextView>(R.id.localeTitle)
|
||||||
|
val subtitleView by bind<TextView>(R.id.localeSubtitle)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import im.vector.riotx.core.platform.VectorViewModelAction
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
sealed class LocalePickerAction : VectorViewModelAction {
|
||||||
|
data class SelectLocale(val locale: Locale) : LocalePickerAction()
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import com.airbnb.epoxy.TypedEpoxyController
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.epoxy.noResultItem
|
||||||
|
import im.vector.riotx.core.epoxy.profiles.profileSectionItem
|
||||||
|
import im.vector.riotx.core.resources.StringProvider
|
||||||
|
import im.vector.riotx.features.settings.VectorLocale
|
||||||
|
import im.vector.riotx.features.settings.VectorPreferences
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LocalePickerController @Inject constructor(
|
||||||
|
private val vectorPreferences: VectorPreferences,
|
||||||
|
private val stringProvider: StringProvider
|
||||||
|
) : TypedEpoxyController<LocalePickerViewState>() {
|
||||||
|
|
||||||
|
var listener: Listener? = null
|
||||||
|
|
||||||
|
@ExperimentalStdlibApi
|
||||||
|
override fun buildModels(data: LocalePickerViewState?) {
|
||||||
|
val list = data?.locales ?: return
|
||||||
|
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
noResultItem {
|
||||||
|
id("noResult")
|
||||||
|
text(stringProvider.getString(R.string.no_result_placeholder))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
profileSectionItem {
|
||||||
|
id("currentTitle")
|
||||||
|
title(stringProvider.getString(R.string.choose_locale_current_locale_title))
|
||||||
|
}
|
||||||
|
localeItem {
|
||||||
|
id(data.currentLocale.toString())
|
||||||
|
title(VectorLocale.localeToLocalisedString(data.currentLocale).capitalize(data.currentLocale))
|
||||||
|
if (vectorPreferences.developerMode()) {
|
||||||
|
subtitle(VectorLocale.localeToLocalisedStringInfo(data.currentLocale))
|
||||||
|
}
|
||||||
|
clickListener { listener?.onUseCurrentClicked() }
|
||||||
|
}
|
||||||
|
profileSectionItem {
|
||||||
|
id("otherTitle")
|
||||||
|
title(stringProvider.getString(R.string.choose_locale_other_locales_title))
|
||||||
|
}
|
||||||
|
list
|
||||||
|
.filter { it != data.currentLocale }
|
||||||
|
.sortedBy { VectorLocale.localeToLocalisedString(it).toLowerCase(it) }
|
||||||
|
.forEach {
|
||||||
|
localeItem {
|
||||||
|
id(it.toString())
|
||||||
|
title(VectorLocale.localeToLocalisedString(it).capitalize(it))
|
||||||
|
if (vectorPreferences.developerMode()) {
|
||||||
|
subtitle(VectorLocale.localeToLocalisedStringInfo(it))
|
||||||
|
}
|
||||||
|
clickListener { listener?.onLocaleClicked(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Listener {
|
||||||
|
fun onUseCurrentClicked()
|
||||||
|
fun onLocaleClicked(locale: Locale)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.View
|
||||||
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.riotx.R
|
||||||
|
import im.vector.riotx.core.extensions.cleanup
|
||||||
|
import im.vector.riotx.core.extensions.configureWith
|
||||||
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
|
import im.vector.riotx.core.extensions.restart
|
||||||
|
import im.vector.riotx.core.platform.VectorBaseActivity
|
||||||
|
import im.vector.riotx.core.platform.VectorBaseFragment
|
||||||
|
import kotlinx.android.synthetic.main.fragment_locale_picker.*
|
||||||
|
import java.util.Locale
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class LocalePickerFragment @Inject constructor(
|
||||||
|
private val viewModelFactory: LocalePickerViewModel.Factory,
|
||||||
|
private val controller: LocalePickerController
|
||||||
|
) : VectorBaseFragment(), LocalePickerViewModel.Factory by viewModelFactory, LocalePickerController.Listener {
|
||||||
|
|
||||||
|
private val viewModel: LocalePickerViewModel by fragmentViewModel()
|
||||||
|
|
||||||
|
override fun getLayoutResId() = R.layout.fragment_locale_picker
|
||||||
|
|
||||||
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
localeRecyclerView.configureWith(controller)
|
||||||
|
controller.listener = this
|
||||||
|
|
||||||
|
viewModel.observeViewEvents {
|
||||||
|
when (it) {
|
||||||
|
LocalePickerViewEvents.RestartActivity -> {
|
||||||
|
activity?.restart()
|
||||||
|
}
|
||||||
|
}.exhaustive
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroyView() {
|
||||||
|
super.onDestroyView()
|
||||||
|
localeRecyclerView.cleanup()
|
||||||
|
controller.listener = null
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun invalidate() = withState(viewModel) { state ->
|
||||||
|
controller.setData(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUseCurrentClicked() {
|
||||||
|
// Just close the fragment
|
||||||
|
parentFragmentManager.popBackStack()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onLocaleClicked(locale: Locale) {
|
||||||
|
viewModel.handle(LocalePickerAction.SelectLocale(locale))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onResume() {
|
||||||
|
super.onResume()
|
||||||
|
(activity as? VectorBaseActivity)?.supportActionBar?.setTitle(R.string.settings_select_language)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import im.vector.riotx.core.platform.VectorViewEvents
|
||||||
|
|
||||||
|
sealed class LocalePickerViewEvents : VectorViewEvents {
|
||||||
|
object RestartActivity : LocalePickerViewEvents()
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.ActivityViewModelContext
|
||||||
|
import com.airbnb.mvrx.FragmentViewModelContext
|
||||||
|
import com.airbnb.mvrx.MvRxViewModelFactory
|
||||||
|
import com.airbnb.mvrx.ViewModelContext
|
||||||
|
import com.squareup.inject.assisted.Assisted
|
||||||
|
import com.squareup.inject.assisted.AssistedInject
|
||||||
|
import im.vector.riotx.core.extensions.exhaustive
|
||||||
|
import im.vector.riotx.core.platform.VectorViewModel
|
||||||
|
import im.vector.riotx.features.configuration.VectorConfiguration
|
||||||
|
import im.vector.riotx.features.settings.VectorLocale
|
||||||
|
|
||||||
|
class LocalePickerViewModel @AssistedInject constructor(
|
||||||
|
@Assisted initialState: LocalePickerViewState,
|
||||||
|
private val vectorConfiguration: VectorConfiguration
|
||||||
|
) : VectorViewModel<LocalePickerViewState, LocalePickerAction, LocalePickerViewEvents>(initialState) {
|
||||||
|
|
||||||
|
@AssistedInject.Factory
|
||||||
|
interface Factory {
|
||||||
|
fun create(initialState: LocalePickerViewState): LocalePickerViewModel
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object : MvRxViewModelFactory<LocalePickerViewModel, LocalePickerViewState> {
|
||||||
|
|
||||||
|
override fun initialState(viewModelContext: ViewModelContext): LocalePickerViewState? {
|
||||||
|
return LocalePickerViewState(
|
||||||
|
locales = VectorLocale.supportedLocales
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
override fun create(viewModelContext: ViewModelContext, state: LocalePickerViewState): LocalePickerViewModel? {
|
||||||
|
val factory = when (viewModelContext) {
|
||||||
|
is FragmentViewModelContext -> viewModelContext.fragment as? Factory
|
||||||
|
is ActivityViewModelContext -> viewModelContext.activity as? Factory
|
||||||
|
}
|
||||||
|
return factory?.create(state) ?: error("You should let your activity/fragment implements Factory interface")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun handle(action: LocalePickerAction) {
|
||||||
|
when (action) {
|
||||||
|
is LocalePickerAction.SelectLocale -> handleSelectLocale(action)
|
||||||
|
}.exhaustive
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleSelectLocale(action: LocalePickerAction.SelectLocale) {
|
||||||
|
vectorConfiguration.updateApplicationLocale(action.locale)
|
||||||
|
_viewEvents.post(LocalePickerViewEvents.RestartActivity)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotx.features.settings.locale
|
||||||
|
|
||||||
|
import com.airbnb.mvrx.MvRxState
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
data class LocalePickerViewState(
|
||||||
|
val currentLocale: Locale = Locale.getDefault(),
|
||||||
|
val locales: List<Locale> = emptyList()
|
||||||
|
) : MvRxState
|
8
vector/src/main/res/layout/fragment_locale_picker.xml
Normal file
8
vector/src/main/res/layout/fragment_locale_picker.xml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/localeRecyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:background="?riotx_background"
|
||||||
|
tools:listitem="@layout/item_locale" />
|
41
vector/src/main/res/layout/item_locale.xml
Normal file
41
vector/src/main/res/layout/item_locale.xml
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:foreground="?attr/selectableItemBackground"
|
||||||
|
android:minHeight="64dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/localeTitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:textColor="?riotx_text_primary"
|
||||||
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintBottom_toTopOf="@+id/localeSubtitle"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
tools:text="English" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/localeSubtitle"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingStart="@dimen/layout_horizontal_margin"
|
||||||
|
android:paddingEnd="@dimen/layout_horizontal_margin"
|
||||||
|
android:textColor="?riotx_text_secondary"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/localeTitle"
|
||||||
|
tools:text="details"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -2393,4 +2393,7 @@ Not all features in Riot are implemented in RiotX yet. Main missing (and coming
|
||||||
</plurals>
|
</plurals>
|
||||||
<string name="invite_users_to_room_failure">We could not invite users. Please check the users you want to invite and try again.</string>
|
<string name="invite_users_to_room_failure">We could not invite users. Please check the users you want to invite and try again.</string>
|
||||||
|
|
||||||
|
<string name="choose_locale_current_locale_title">Current language</string>
|
||||||
|
<string name="choose_locale_other_locales_title">Other available languages</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
|
@ -7,9 +7,10 @@
|
||||||
android:title="@string/settings_user_interface">
|
android:title="@string/settings_user_interface">
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorPreference
|
<im.vector.riotx.core.preference.VectorPreference
|
||||||
android:dialogTitle="@string/settings_select_language"
|
|
||||||
android:key="SETTINGS_INTERFACE_LANGUAGE_PREFERENCE_KEY"
|
android:key="SETTINGS_INTERFACE_LANGUAGE_PREFERENCE_KEY"
|
||||||
android:title="@string/settings_interface_language" />
|
android:persistent="false"
|
||||||
|
android:title="@string/settings_interface_language"
|
||||||
|
app:fragment="im.vector.riotx.features.settings.locale.LocalePickerFragment" />
|
||||||
|
|
||||||
<im.vector.riotx.core.preference.VectorListPreference
|
<im.vector.riotx.core.preference.VectorListPreference
|
||||||
android:defaultValue="light"
|
android:defaultValue="light"
|
||||||
|
|
Loading…
Reference in a new issue