Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #3821: Ensure Portuguese can be a default audio language #4575

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions app/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ LISTENERS = [
"src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryClickListener.kt",
"src/main/java/org/oppia/android/app/onboarding/OnboardingNavigationListener.kt",
"src/main/java/org/oppia/android/app/onboarding/RouteToProfileListListener.kt",
"src/main/java/org/oppia/android/app/options/LanguageRadioButtonListener.kt",
"src/main/java/org/oppia/android/app/options/AppLanguageRadioButtonListener.kt",
"src/main/java/org/oppia/android/app/options/AudioLanguageRadioButtonListener.kt",
"src/main/java/org/oppia/android/app/options/LoadAppLanguageListListener.kt",
"src/main/java/org/oppia/android/app/options/LoadAudioLanguageListListener.kt",
"src/main/java/org/oppia/android/app/options/LoadReadingTextSizeListener.kt",
Expand Down Expand Up @@ -293,8 +294,10 @@ VIEW_MODELS = [
"src/main/java/org/oppia/android/app/onboarding/OnboardingViewPagerViewModel.kt",
"src/main/java/org/oppia/android/app/onboarding/ViewPagerSlide.kt",
"src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicListViewModel.kt",
"src/main/java/org/oppia/android/app/options/LanguageItemViewModel.kt",
"src/main/java/org/oppia/android/app/options/LanguageSelectionViewModel.kt",
"src/main/java/org/oppia/android/app/options/AppLanguageItemViewModel.kt",
"src/main/java/org/oppia/android/app/options/AppLanguageSelectionViewModel.kt",
"src/main/java/org/oppia/android/app/options/AudioLanguageItemViewModel.kt",
"src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt",
"src/main/java/org/oppia/android/app/options/OptionControlsViewModel.kt",
"src/main/java/org/oppia/android/app/options/OptionsAppLanguageViewModel.kt",
"src/main/java/org/oppia/android/app/options/OptionsAudioLanguageViewModel.kt",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,7 @@ private const val APP_LANGUAGE_PREFERENCE_SUMMARY_VALUE_ARGUMENT_KEY =
private const val SELECTED_LANGUAGE_SAVED_KEY = "AppLanguageFragment.selected_language"

/** The fragment to change the language of the app. */
class AppLanguageFragment :
InjectableFragment(),
LanguageRadioButtonListener {
class AppLanguageFragment : InjectableFragment(), AppLanguageRadioButtonListener {

@Inject
lateinit var appLanguageFragmentPresenter: AppLanguageFragmentPresenter
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import android.view.ViewGroup
import androidx.fragment.app.Fragment
import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.databinding.AppLanguageFragmentBinding
import org.oppia.android.databinding.LanguageItemsBinding
import org.oppia.android.databinding.AppLanguageItemBinding
import javax.inject.Inject

/** The presenter for [AppLanguageFragment]. */
class AppLanguageFragmentPresenter @Inject constructor(
private val fragment: Fragment,
private val languageSelectionViewModel: LanguageSelectionViewModel
private val appLanguageSelectionViewModel: AppLanguageSelectionViewModel
) {
private lateinit var prefSummaryValue: String
fun handleOnCreateView(
Expand All @@ -27,8 +27,8 @@ class AppLanguageFragmentPresenter @Inject constructor(
/* attachToRoot= */ false
)
this.prefSummaryValue = prefSummaryValue
binding.viewModel = languageSelectionViewModel
languageSelectionViewModel.selectedLanguage.value = prefSummaryValue
binding.viewModel = appLanguageSelectionViewModel
appLanguageSelectionViewModel.selectedLanguage.value = prefSummaryValue
binding.languageRecyclerView.apply {
adapter = createRecyclerViewAdapter()
}
Expand All @@ -37,16 +37,16 @@ class AppLanguageFragmentPresenter @Inject constructor(
}

fun getLanguageSelected(): String? {
return languageSelectionViewModel.selectedLanguage.value
return appLanguageSelectionViewModel.selectedLanguage.value
}

private fun createRecyclerViewAdapter(): BindableAdapter<LanguageItemViewModel> {
private fun createRecyclerViewAdapter(): BindableAdapter<AppLanguageItemViewModel> {
return BindableAdapter.SingleTypeBuilder
.newBuilder<LanguageItemViewModel>()
.newBuilder<AppLanguageItemViewModel>()
.setLifecycleOwner(fragment)
.registerViewDataBinderWithSameModelType(
inflateDataBinding = LanguageItemsBinding::inflate,
setViewModel = LanguageItemsBinding::setViewModel
inflateDataBinding = AppLanguageItemBinding::inflate,
setViewModel = AppLanguageItemBinding::setViewModel
).build()
}

Expand All @@ -61,7 +61,7 @@ class AppLanguageFragmentPresenter @Inject constructor(
}

fun onLanguageSelected(selectedLanguage: String) {
languageSelectionViewModel.selectedLanguage.value = selectedLanguage
appLanguageSelectionViewModel.selectedLanguage.value = selectedLanguage
updateAppLanguage(selectedLanguage)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.oppia.android.app.options

import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import org.oppia.android.app.viewmodel.ObservableViewModel

/**
* Language item view model for the recycler view in [AppLanguageFragment] and.
*
* @property language the app language corresponding to this language item to be displayed
* @property currentSelectedLanguage the [LiveData] tracking the currently selected language
* @property appLanguageRadioButtonListener the listener which will be called if this language is
* selected by the user
*/
class AppLanguageItemViewModel(
val language: String,
private val currentSelectedLanguage: LiveData<String>,
val appLanguageRadioButtonListener: AppLanguageRadioButtonListener
) : ObservableViewModel() {
/**
* Indicates whether the language corresponding to this view model is _currently_ selected in the
* radio button list.
*/
val isLanguageSelected: LiveData<Boolean> by lazy {
Transformations.map(currentSelectedLanguage) { it == language }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.oppia.android.app.options

/** Listener for when a language is selected for the [AppLanguageFragment]. */
interface AppLanguageRadioButtonListener {
/** Called when the user selected a new app language to use as their default preference. */
fun onLanguageSelected(appLanguage: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package org.oppia.android.app.options

import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import org.oppia.android.app.fragment.FragmentScope
import org.oppia.android.app.viewmodel.ObservableViewModel
import javax.inject.Inject

/** Language list view model for the recycler view in [AppLanguageFragment]. */
@FragmentScope
class AppLanguageSelectionViewModel @Inject constructor(
val fragment: Fragment
) : ObservableViewModel() {
/** The name of the app language currently selected in the radio button list. */
val selectedLanguage = MutableLiveData<String>()
private val appLanguageRadioButtonListener = fragment as AppLanguageRadioButtonListener

private val appLanguagesList = listOf(
AppLanguageItemViewModel("English", selectedLanguage, appLanguageRadioButtonListener),
AppLanguageItemViewModel("French", selectedLanguage, appLanguageRadioButtonListener),
AppLanguageItemViewModel("Hindi", selectedLanguage, appLanguageRadioButtonListener),
AppLanguageItemViewModel("Chinese", selectedLanguage, appLanguageRadioButtonListener)
)

/** The list of [AppLanguageItemViewModel]s which can be bound to a recycler view. */
val recyclerViewAppLanguageList: List<AppLanguageItemViewModel> by lazy { appLanguagesList }
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,72 +5,64 @@ import android.content.Intent
import android.os.Bundle
import org.oppia.android.app.activity.ActivityComponentImpl
import org.oppia.android.app.activity.InjectableAppCompatActivity
import org.oppia.android.app.model.AudioLanguage
import org.oppia.android.app.model.AudioLanguageActivityParams
import org.oppia.android.app.model.AudioLanguageActivityStateBundle
import org.oppia.android.util.extensions.getProto
import org.oppia.android.util.extensions.getProtoExtra
import org.oppia.android.util.extensions.putProto
import org.oppia.android.util.extensions.putProtoExtra
import javax.inject.Inject

/** The activity to change the Default Audio language of the app. */
class AudioLanguageActivity : InjectableAppCompatActivity() {

@Inject
lateinit var audioLanguageActivityPresenter: AudioLanguageActivityPresenter
private lateinit var prefKey: String
private lateinit var prefSummaryValue: String
@Inject lateinit var audioLanguageActivityPresenter: AudioLanguageActivityPresenter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
(activityComponent as ActivityComponentImpl).inject(this)
prefKey = checkNotNull(intent.getStringExtra(AUDIO_LANGUAGE_PREFERENCE_TITLE_EXTRA_KEY)) {
"Expected $AUDIO_LANGUAGE_PREFERENCE_TITLE_EXTRA_KEY to be in intent extras."
}
prefSummaryValue = if (savedInstanceState != null) {
savedInstanceState.get(AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY) as String
} else {
checkNotNull(intent.getStringExtra(AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY)) {
"Expected $AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY to be in intent extras."
}
}
audioLanguageActivityPresenter.handleOnCreate(prefKey, prefSummaryValue)
audioLanguageActivityPresenter.handleOnCreate(
savedInstanceState?.retrieveLanguageFromSavedState() ?: intent.retrieveLanguageFromParams()
)
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
val state = AudioLanguageActivityStateBundle.newBuilder().apply {
audioLanguage = audioLanguageActivityPresenter.getLanguageSelected()
}.build()
outState.putProto(ACTIVITY_SAVED_STATE_KEY, state)
}

override fun onBackPressed() = audioLanguageActivityPresenter.finishWithResult()

companion object {
internal const val AUDIO_LANGUAGE_PREFERENCE_TITLE_EXTRA_KEY =
"AudioLanguageActivity.audio_language_preference_title"
const val AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY =
"AudioLanguageActivity.audio_language_preference_summary_value"
private const val ACTIVITY_PARAMS_KEY = "AudioLanguageActivity.params"
private const val ACTIVITY_SAVED_STATE_KEY = "AudioLanguageActivity.saved_state"

/** Returns a new [Intent] to route to [AudioLanguageActivity]. */
fun createAudioLanguageActivityIntent(
context: Context,
prefKey: String,
summaryValue: String?
audioLanguage: AudioLanguage
): Intent {
val intent = Intent(context, AudioLanguageActivity::class.java)
intent.putExtra(AUDIO_LANGUAGE_PREFERENCE_TITLE_EXTRA_KEY, prefKey)
intent.putExtra(AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY, summaryValue)
return intent
return Intent(context, AudioLanguageActivity::class.java).apply {
val arguments = AudioLanguageActivityParams.newBuilder().apply {
this.audioLanguage = audioLanguage
}.build()
putProtoExtra(ACTIVITY_PARAMS_KEY, arguments)
}
}

fun getKeyAudioLanguagePreferenceTitle(): String {
return AUDIO_LANGUAGE_PREFERENCE_TITLE_EXTRA_KEY
private fun Intent.retrieveLanguageFromParams(): AudioLanguage {
return getProtoExtra(
ACTIVITY_PARAMS_KEY, AudioLanguageActivityParams.getDefaultInstance()
).audioLanguage
}

fun getKeyAudioLanguagePreferenceSummaryValue(): String {
return AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY
private fun Bundle.retrieveLanguageFromSavedState(): AudioLanguage {
return getProto(
ACTIVITY_SAVED_STATE_KEY, AudioLanguageActivityStateBundle.getDefaultInstance()
).audioLanguage
}
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(
AUDIO_LANGUAGE_PREFERENCE_SUMMARY_VALUE_EXTRA_KEY,
audioLanguageActivityPresenter.getLanguageSelected()
)
}

override fun onBackPressed() {
val message = audioLanguageActivityPresenter.getLanguageSelected()
val intent = Intent()
intent.putExtra(MESSAGE_AUDIO_LANGUAGE_ARGUMENT_KEY, message)
setResult(REQUEST_CODE_AUDIO_LANGUAGE, intent)
finish()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,46 +5,60 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import org.oppia.android.R
import org.oppia.android.app.activity.ActivityScope
import org.oppia.android.app.model.AudioLanguage
import org.oppia.android.app.model.AudioLanguageActivityResultBundle
import org.oppia.android.databinding.AudioLanguageActivityBinding
import org.oppia.android.util.extensions.putProtoExtra
import javax.inject.Inject

/** The presenter for [AudioLanguageActivity]. */
@ActivityScope
class AudioLanguageActivityPresenter @Inject constructor(private val activity: AppCompatActivity) {
private lateinit var audioLanguage: AudioLanguage

private lateinit var prefSummaryValue: String

fun handleOnCreate(prefKey: String, prefValue: String) {
val binding: AudioLanguageActivityBinding = DataBindingUtil.setContentView(
activity,
R.layout.audio_language_activity,
)
val toolbar = binding.audioLanguageToolbar
toolbar.setNavigationOnClickListener {
val intent = Intent().apply {
putExtra(MESSAGE_AUDIO_LANGUAGE_ARGUMENT_KEY, prefSummaryValue)
}
(activity as AudioLanguageActivity).setResult(REQUEST_CODE_AUDIO_LANGUAGE, intent)
activity.finish()
/** Handles when the activity is first created. */
fun handleOnCreate(audioLanguage: AudioLanguage) {
this.audioLanguage = audioLanguage

val binding: AudioLanguageActivityBinding =
DataBindingUtil.setContentView(activity, R.layout.audio_language_activity)
binding.audioLanguageToolbar.setNavigationOnClickListener {
finishWithResult()
}
setLanguageSelected(prefValue)
if (getAudioLanguageFragment() == null) {
val audioLanguageFragment = AudioLanguageFragment.newInstance(prefKey, prefValue)
val audioLanguageFragment = AudioLanguageFragment.newInstance(audioLanguage)
activity.supportFragmentManager.beginTransaction()
.add(R.id.audio_language_fragment_container, audioLanguageFragment).commitNow()
}
}

fun setLanguageSelected(audioLanguage: String) {
prefSummaryValue = audioLanguage
/** Updates the currently selected [AudioLanguage] to the specified [audioLanguage]. */
fun setLanguageSelected(audioLanguage: AudioLanguage) {
this.audioLanguage = audioLanguage
}

fun getLanguageSelected(): String {
return prefSummaryValue
/** Returns the current [AudioLanguage] selected in the activity. */
fun getLanguageSelected(): AudioLanguage = audioLanguage

/**
* Finishes the current activity with a result (specifically, an intent result with
* [AudioLanguageActivityResultBundle] populated with the [AudioLanguage] that was selected in the
* activity).
*/
fun finishWithResult() {
val intent = Intent().apply {
val result = AudioLanguageActivityResultBundle.newBuilder().apply {
this.audioLanguage = [email protected]
}.build()
putProtoExtra(MESSAGE_AUDIO_LANGUAGE_RESULTS_KEY, result)
}

activity.setResult(REQUEST_CODE_AUDIO_LANGUAGE, intent)
activity.finish()
}

private fun getAudioLanguageFragment(): AudioLanguageFragment? {
return activity.supportFragmentManager
.findFragmentById(R.id.audio_language_fragment_container) as AudioLanguageFragment?
.findFragmentById(R.id.audio_language_fragment_container) as? AudioLanguageFragment
}
}
Loading