From 1c4b17a10fc42dd8efb14d7e7f4841ddff598607 Mon Sep 17 00:00:00 2001 From: Adhiambo Peres <59600948+adhiamboperes@users.noreply.github.com> Date: Wed, 3 Jul 2024 03:07:57 +0300 Subject: [PATCH] Fix Part of #4938: Introduce Onboarding Audio language screen (#5386) ## Explanation Fix Part of https://github.com/oppia/oppia-android/issues/4938: New screen to allow a user to select an audio language during the onboarding process. This PR only adds the layout and navigation functions without implementing the language selection functionality. ||Portrait|Landscape| |--|--|--| |Mobile|![Screenshot_1719963278](https://github.com/oppia/oppia-android/assets/59600948/8f6e9f7b-0362-4172-9a46-036661b71598)|![Screenshot_1719963292](https://github.com/oppia/oppia-android/assets/59600948/19c1124c-1c63-4b71-b678-597db2f005d8)| ||![Screenshot_1719963273](https://github.com/oppia/oppia-android/assets/59600948/324726d9-8fdb-466d-82d0-71b7ddc3581a)|![Screenshot_1719963301](https://github.com/oppia/oppia-android/assets/59600948/8d3c1b27-217e-4e1d-b633-20368a057569)| |Tablet|![Screenshot_1719963641](https://github.com/oppia/oppia-android/assets/59600948/1b53195b-2c17-4a15-8c95-6090fa77470e)|![Screenshot_1719963651](https://github.com/oppia/oppia-android/assets/59600948/49300ebf-bfae-4a42-922d-64b591bbf138)| ||![Screenshot_1719963670](https://github.com/oppia/oppia-android/assets/59600948/cf4e37d3-56f0-47c4-9f0d-b01d75cceb8d)|![Screenshot_1719963660](https://github.com/oppia/oppia-android/assets/59600948/c4b8f6f7-a41e-44a0-af7f-1c8bfca9fa4f)| ## Essential Checklist - [x] The PR title and explanation each start with "Fix #bugnum: " (If this PR fixes part of an issue, prefix the title with "Fix part of #bugnum: ...".) - [x] Any changes to [scripts/assets](https://github.com/oppia/oppia-android/tree/develop/scripts/assets) files have their rationale included in the PR explanation. - [x] The PR follows the [style guide](https://github.com/oppia/oppia-android/wiki/Coding-style-guide). - [x] The PR does not contain any unnecessary code changes from Android Studio ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#undo-unnecessary-changes)). - [x] The PR is made from a branch that's **not** called "develop" and is up-to-date with "develop". - [x] The PR is **assigned** to the appropriate reviewers ([reference](https://github.com/oppia/oppia-android/wiki/Guidance-on-submitting-a-PR#clarification-regarding-assignees-and-reviewers-section)). --- .../AudioLanguageFragmentPresenter.kt | 73 ++++++++ .../app/onboarding/IntroFragmentPresenter.kt | 11 ++ .../app/options/AudioLanguageFragment.kt | 29 ++- ...kt => AudioLanguageFragmentPresenterV1.kt} | 2 +- .../AudioLanguageSelectionViewModel.kt | 13 ++ .../audio_language_selection_fragment.xml | 96 ++++++++++ ...arding_app_language_selection_fragment.xml | 10 +- .../audio_language_selection_fragment.xml | 112 ++++++++++++ ...arding_app_language_selection_fragment.xml | 10 +- .../audio_language_selection_fragment.xml | 121 +++++++++++++ ...arding_app_language_selection_fragment.xml | 10 +- .../audio_language_selection_fragment.xml | 126 +++++++++++++ ...arding_app_language_selection_fragment.xml | 10 +- .../onboarding_language_dropdown_item.xml | 17 ++ app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/values/styles.xml | 28 +++ .../app/options/AudioLanguageFragmentTest.kt | 165 +++++++++++++++++- scripts/assets/test_file_exemptions.textproto | 25 ++- 19 files changed, 813 insertions(+), 51 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/onboarding/AudioLanguageFragmentPresenter.kt rename app/src/main/java/org/oppia/android/app/options/{AudioLanguageFragmentPresenter.kt => AudioLanguageFragmentPresenterV1.kt} (97%) create mode 100644 app/src/main/res/layout-land/audio_language_selection_fragment.xml create mode 100644 app/src/main/res/layout-sw600dp-land/audio_language_selection_fragment.xml create mode 100644 app/src/main/res/layout-sw600dp-port/audio_language_selection_fragment.xml create mode 100644 app/src/main/res/layout/audio_language_selection_fragment.xml create mode 100644 app/src/main/res/layout/onboarding_language_dropdown_item.xml diff --git a/app/src/main/java/org/oppia/android/app/onboarding/AudioLanguageFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/AudioLanguageFragmentPresenter.kt new file mode 100644 index 00000000000..3a238d4b010 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/onboarding/AudioLanguageFragmentPresenter.kt @@ -0,0 +1,73 @@ +package org.oppia.android.app.onboarding + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.view.inputmethod.EditorInfo +import android.widget.ArrayAdapter +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import com.google.android.material.appbar.AppBarLayout +import org.oppia.android.R +import org.oppia.android.app.options.AudioLanguageSelectionViewModel +import org.oppia.android.app.translation.AppLanguageResourceHandler +import org.oppia.android.databinding.AudioLanguageSelectionFragmentBinding +import javax.inject.Inject + +/** The presenter for [AudioLanguageFragment]. */ +class AudioLanguageFragmentPresenter @Inject constructor( + private val fragment: Fragment, + private val activity: AppCompatActivity, + private val appLanguageResourceHandler: AppLanguageResourceHandler, + private val audioLanguageSelectionViewModel: AudioLanguageSelectionViewModel +) { + private lateinit var binding: AudioLanguageSelectionFragmentBinding + + /** + * Returns a newly inflated view to render the fragment with an evaluated audio language as the + * initial selected language, based on current locale. + */ + fun handleCreateView( + inflater: LayoutInflater, + container: ViewGroup? + ): View { + + // Hide toolbar as it's not needed in this layout. The toolbar is created by a shared activity + // and is required in OptionsFragment. + activity.findViewById(R.id.reading_list_app_bar_layout).visibility = View.GONE + + binding = AudioLanguageSelectionFragmentBinding.inflate( + inflater, + container, + /* attachToRoot= */ false + ) + binding.lifecycleOwner = fragment + + binding.audioLanguageText.text = appLanguageResourceHandler.getStringInLocaleWithWrapping( + R.string.audio_language_fragment_text, + appLanguageResourceHandler.getStringInLocale(R.string.app_name) + ) + + binding.onboardingNavigationBack.setOnClickListener { + activity.finish() + } + + val adapter = ArrayAdapter( + fragment.requireContext(), + R.layout.onboarding_language_dropdown_item, + R.id.onboarding_language_text_view, + audioLanguageSelectionViewModel.availableAudioLanguages + ) + + binding.audioLanguageDropdownList.apply { + setAdapter(adapter) + setText( + audioLanguageSelectionViewModel.defaultLanguageSelection, + false + ) + setRawInputType(EditorInfo.TYPE_NULL) + } + + return binding.root + } +} diff --git a/app/src/main/java/org/oppia/android/app/onboarding/IntroFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/IntroFragmentPresenter.kt index ac0b9d04401..50fa51300c7 100644 --- a/app/src/main/java/org/oppia/android/app/onboarding/IntroFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/onboarding/IntroFragmentPresenter.kt @@ -6,6 +6,8 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import org.oppia.android.R +import org.oppia.android.app.model.AudioLanguage +import org.oppia.android.app.options.AudioLanguageActivity import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.databinding.LearnerIntroFragmentBinding import javax.inject.Inject @@ -29,6 +31,7 @@ class IntroFragmentPresenter @Inject constructor( container, /* attachToRoot= */ false ) + binding.lifecycleOwner = fragment setLearnerName(profileNickname) @@ -43,6 +46,14 @@ class IntroFragmentPresenter @Inject constructor( appLanguageResourceHandler.getStringInLocale(R.string.app_name) ) + binding.onboardingNavigationContinue.setOnClickListener { + val intent = AudioLanguageActivity.createAudioLanguageActivityIntent( + fragment.requireContext(), + AudioLanguage.ENGLISH_AUDIO_LANGUAGE + ) + fragment.startActivity(intent) + } + return binding.root } diff --git a/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragment.kt b/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragment.kt index fd98e6259cd..71ea48ca09e 100644 --- a/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragment.kt +++ b/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragment.kt @@ -10,14 +10,23 @@ import org.oppia.android.app.fragment.InjectableFragment import org.oppia.android.app.model.AudioLanguage import org.oppia.android.app.model.AudioLanguageFragmentArguments import org.oppia.android.app.model.AudioLanguageFragmentStateBundle +import org.oppia.android.app.onboarding.AudioLanguageFragmentPresenter import org.oppia.android.util.extensions.getProto import org.oppia.android.util.extensions.putProto +import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 +import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** The fragment to change the default audio language of the app. */ class AudioLanguageFragment : InjectableFragment(), AudioLanguageRadioButtonListener { + @Inject lateinit var audioLanguageFragmentPresenterV1: AudioLanguageFragmentPresenterV1 + @Inject lateinit var audioLanguageFragmentPresenter: AudioLanguageFragmentPresenter + @Inject + @field:EnableOnboardingFlowV2 + lateinit var enableOnboardingFlowV2: PlatformParameterValue + override fun onAttach(context: Context) { super.onAttach(context) (fragmentComponent as FragmentComponentImpl).inject(this) @@ -33,19 +42,27 @@ class AudioLanguageFragment : InjectableFragment(), AudioLanguageRadioButtonList savedInstanceState?.retrieveLanguageFromSavedState() ?: arguments?.retrieveLanguageFromArguments() ) { "Expected arguments to be passed to AudioLanguageFragment" } - return audioLanguageFragmentPresenter.handleOnCreateView(inflater, container, audioLanguage) + return if (enableOnboardingFlowV2.value) { + audioLanguageFragmentPresenter.handleCreateView(inflater, container) + } else { + audioLanguageFragmentPresenterV1.handleOnCreateView(inflater, container, audioLanguage) + } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - val state = AudioLanguageFragmentStateBundle.newBuilder().apply { - audioLanguage = audioLanguageFragmentPresenter.getLanguageSelected() - }.build() - outState.putProto(FRAGMENT_SAVED_STATE_KEY, state) + if (!enableOnboardingFlowV2.value) { + val state = AudioLanguageFragmentStateBundle.newBuilder().apply { + audioLanguage = audioLanguageFragmentPresenterV1.getLanguageSelected() + }.build() + outState.putProto(FRAGMENT_SAVED_STATE_KEY, state) + } } override fun onLanguageSelected(audioLanguage: AudioLanguage) { - audioLanguageFragmentPresenter.onLanguageSelected(audioLanguage) + if (!enableOnboardingFlowV2.value) { + audioLanguageFragmentPresenterV1.onLanguageSelected(audioLanguage) + } } companion object { diff --git a/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenterV1.kt similarity index 97% rename from app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenter.kt rename to app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenterV1.kt index 5195adcebe1..72774fec6ba 100644 --- a/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenterV1.kt @@ -11,7 +11,7 @@ import org.oppia.android.databinding.AudioLanguageItemBinding import javax.inject.Inject /** The presenter for [AudioLanguageFragment]. */ -class AudioLanguageFragmentPresenter @Inject constructor( +class AudioLanguageFragmentPresenterV1 @Inject constructor( private val fragment: Fragment, private val audioLanguageSelectionViewModel: AudioLanguageSelectionViewModel, private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory diff --git a/app/src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt b/app/src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt index c9e0d998e1b..5e25aaabf5d 100644 --- a/app/src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt @@ -31,6 +31,19 @@ class AudioLanguageSelectionViewModel @Inject constructor( ) } + // TODO(#4938): Update the pre-selection logic. + /** The pre-selected [AudioLanguage] to be shown in the language selection dropdown. */ + val defaultLanguageSelection = getLanguageDisplayName(AudioLanguage.ENGLISH_AUDIO_LANGUAGE) + + /** The list of [AudioLanguage]s supported by the app. */ + val availableAudioLanguages: List by lazy { + AudioLanguage.values().filter { it !in IGNORED_AUDIO_LANGUAGES }.map(::getLanguageDisplayName) + } + + private fun getLanguageDisplayName(audioLanguage: AudioLanguage): String { + return appLanguageResourceHandler.computeLocalizedDisplayName(audioLanguage) + } + private companion object { private val IGNORED_AUDIO_LANGUAGES = listOf( diff --git a/app/src/main/res/layout-land/audio_language_selection_fragment.xml b/app/src/main/res/layout-land/audio_language_selection_fragment.xml new file mode 100644 index 00000000000..ed683db064e --- /dev/null +++ b/app/src/main/res/layout-land/audio_language_selection_fragment.xml @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + +