Skip to content

Commit 1c4b17a

Browse files
Fix Part of #4938: Introduce Onboarding Audio language screen (#5386)
<!-- READ ME FIRST: Please fill in the explanation section below and check off every point from the Essential Checklist! --> ## Explanation Fix Part of #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 <!-- Please tick the relevant boxes by putting an "x" in them. --> - [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)).
1 parent fcd75ef commit 1c4b17a

19 files changed

+813
-51
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package org.oppia.android.app.onboarding
2+
3+
import android.view.LayoutInflater
4+
import android.view.View
5+
import android.view.ViewGroup
6+
import android.view.inputmethod.EditorInfo
7+
import android.widget.ArrayAdapter
8+
import androidx.appcompat.app.AppCompatActivity
9+
import androidx.fragment.app.Fragment
10+
import com.google.android.material.appbar.AppBarLayout
11+
import org.oppia.android.R
12+
import org.oppia.android.app.options.AudioLanguageSelectionViewModel
13+
import org.oppia.android.app.translation.AppLanguageResourceHandler
14+
import org.oppia.android.databinding.AudioLanguageSelectionFragmentBinding
15+
import javax.inject.Inject
16+
17+
/** The presenter for [AudioLanguageFragment]. */
18+
class AudioLanguageFragmentPresenter @Inject constructor(
19+
private val fragment: Fragment,
20+
private val activity: AppCompatActivity,
21+
private val appLanguageResourceHandler: AppLanguageResourceHandler,
22+
private val audioLanguageSelectionViewModel: AudioLanguageSelectionViewModel
23+
) {
24+
private lateinit var binding: AudioLanguageSelectionFragmentBinding
25+
26+
/**
27+
* Returns a newly inflated view to render the fragment with an evaluated audio language as the
28+
* initial selected language, based on current locale.
29+
*/
30+
fun handleCreateView(
31+
inflater: LayoutInflater,
32+
container: ViewGroup?
33+
): View {
34+
35+
// Hide toolbar as it's not needed in this layout. The toolbar is created by a shared activity
36+
// and is required in OptionsFragment.
37+
activity.findViewById<AppBarLayout>(R.id.reading_list_app_bar_layout).visibility = View.GONE
38+
39+
binding = AudioLanguageSelectionFragmentBinding.inflate(
40+
inflater,
41+
container,
42+
/* attachToRoot= */ false
43+
)
44+
binding.lifecycleOwner = fragment
45+
46+
binding.audioLanguageText.text = appLanguageResourceHandler.getStringInLocaleWithWrapping(
47+
R.string.audio_language_fragment_text,
48+
appLanguageResourceHandler.getStringInLocale(R.string.app_name)
49+
)
50+
51+
binding.onboardingNavigationBack.setOnClickListener {
52+
activity.finish()
53+
}
54+
55+
val adapter = ArrayAdapter(
56+
fragment.requireContext(),
57+
R.layout.onboarding_language_dropdown_item,
58+
R.id.onboarding_language_text_view,
59+
audioLanguageSelectionViewModel.availableAudioLanguages
60+
)
61+
62+
binding.audioLanguageDropdownList.apply {
63+
setAdapter(adapter)
64+
setText(
65+
audioLanguageSelectionViewModel.defaultLanguageSelection,
66+
false
67+
)
68+
setRawInputType(EditorInfo.TYPE_NULL)
69+
}
70+
71+
return binding.root
72+
}
73+
}

app/src/main/java/org/oppia/android/app/onboarding/IntroFragmentPresenter.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import android.view.ViewGroup
66
import androidx.appcompat.app.AppCompatActivity
77
import androidx.fragment.app.Fragment
88
import org.oppia.android.R
9+
import org.oppia.android.app.model.AudioLanguage
10+
import org.oppia.android.app.options.AudioLanguageActivity
911
import org.oppia.android.app.translation.AppLanguageResourceHandler
1012
import org.oppia.android.databinding.LearnerIntroFragmentBinding
1113
import javax.inject.Inject
@@ -29,6 +31,7 @@ class IntroFragmentPresenter @Inject constructor(
2931
container,
3032
/* attachToRoot= */ false
3133
)
34+
3235
binding.lifecycleOwner = fragment
3336

3437
setLearnerName(profileNickname)
@@ -43,6 +46,14 @@ class IntroFragmentPresenter @Inject constructor(
4346
appLanguageResourceHandler.getStringInLocale(R.string.app_name)
4447
)
4548

49+
binding.onboardingNavigationContinue.setOnClickListener {
50+
val intent = AudioLanguageActivity.createAudioLanguageActivityIntent(
51+
fragment.requireContext(),
52+
AudioLanguage.ENGLISH_AUDIO_LANGUAGE
53+
)
54+
fragment.startActivity(intent)
55+
}
56+
4657
return binding.root
4758
}
4859

app/src/main/java/org/oppia/android/app/options/AudioLanguageFragment.kt

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,23 @@ import org.oppia.android.app.fragment.InjectableFragment
1010
import org.oppia.android.app.model.AudioLanguage
1111
import org.oppia.android.app.model.AudioLanguageFragmentArguments
1212
import org.oppia.android.app.model.AudioLanguageFragmentStateBundle
13+
import org.oppia.android.app.onboarding.AudioLanguageFragmentPresenter
1314
import org.oppia.android.util.extensions.getProto
1415
import org.oppia.android.util.extensions.putProto
16+
import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2
17+
import org.oppia.android.util.platformparameter.PlatformParameterValue
1518
import javax.inject.Inject
1619

1720
/** The fragment to change the default audio language of the app. */
1821
class AudioLanguageFragment : InjectableFragment(), AudioLanguageRadioButtonListener {
22+
@Inject lateinit var audioLanguageFragmentPresenterV1: AudioLanguageFragmentPresenterV1
23+
1924
@Inject lateinit var audioLanguageFragmentPresenter: AudioLanguageFragmentPresenter
2025

26+
@Inject
27+
@field:EnableOnboardingFlowV2
28+
lateinit var enableOnboardingFlowV2: PlatformParameterValue<Boolean>
29+
2130
override fun onAttach(context: Context) {
2231
super.onAttach(context)
2332
(fragmentComponent as FragmentComponentImpl).inject(this)
@@ -33,19 +42,27 @@ class AudioLanguageFragment : InjectableFragment(), AudioLanguageRadioButtonList
3342
savedInstanceState?.retrieveLanguageFromSavedState()
3443
?: arguments?.retrieveLanguageFromArguments()
3544
) { "Expected arguments to be passed to AudioLanguageFragment" }
36-
return audioLanguageFragmentPresenter.handleOnCreateView(inflater, container, audioLanguage)
45+
return if (enableOnboardingFlowV2.value) {
46+
audioLanguageFragmentPresenter.handleCreateView(inflater, container)
47+
} else {
48+
audioLanguageFragmentPresenterV1.handleOnCreateView(inflater, container, audioLanguage)
49+
}
3750
}
3851

3952
override fun onSaveInstanceState(outState: Bundle) {
4053
super.onSaveInstanceState(outState)
41-
val state = AudioLanguageFragmentStateBundle.newBuilder().apply {
42-
audioLanguage = audioLanguageFragmentPresenter.getLanguageSelected()
43-
}.build()
44-
outState.putProto(FRAGMENT_SAVED_STATE_KEY, state)
54+
if (!enableOnboardingFlowV2.value) {
55+
val state = AudioLanguageFragmentStateBundle.newBuilder().apply {
56+
audioLanguage = audioLanguageFragmentPresenterV1.getLanguageSelected()
57+
}.build()
58+
outState.putProto(FRAGMENT_SAVED_STATE_KEY, state)
59+
}
4560
}
4661

4762
override fun onLanguageSelected(audioLanguage: AudioLanguage) {
48-
audioLanguageFragmentPresenter.onLanguageSelected(audioLanguage)
63+
if (!enableOnboardingFlowV2.value) {
64+
audioLanguageFragmentPresenterV1.onLanguageSelected(audioLanguage)
65+
}
4966
}
5067

5168
companion object {

app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenter.kt renamed to app/src/main/java/org/oppia/android/app/options/AudioLanguageFragmentPresenterV1.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import org.oppia.android.databinding.AudioLanguageItemBinding
1111
import javax.inject.Inject
1212

1313
/** The presenter for [AudioLanguageFragment]. */
14-
class AudioLanguageFragmentPresenter @Inject constructor(
14+
class AudioLanguageFragmentPresenterV1 @Inject constructor(
1515
private val fragment: Fragment,
1616
private val audioLanguageSelectionViewModel: AudioLanguageSelectionViewModel,
1717
private val singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory

app/src/main/java/org/oppia/android/app/options/AudioLanguageSelectionViewModel.kt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ class AudioLanguageSelectionViewModel @Inject constructor(
3131
)
3232
}
3333

34+
// TODO(#4938): Update the pre-selection logic.
35+
/** The pre-selected [AudioLanguage] to be shown in the language selection dropdown. */
36+
val defaultLanguageSelection = getLanguageDisplayName(AudioLanguage.ENGLISH_AUDIO_LANGUAGE)
37+
38+
/** The list of [AudioLanguage]s supported by the app. */
39+
val availableAudioLanguages: List<String> by lazy {
40+
AudioLanguage.values().filter { it !in IGNORED_AUDIO_LANGUAGES }.map(::getLanguageDisplayName)
41+
}
42+
43+
private fun getLanguageDisplayName(audioLanguage: AudioLanguage): String {
44+
return appLanguageResourceHandler.computeLocalizedDisplayName(audioLanguage)
45+
}
46+
3447
private companion object {
3548
private val IGNORED_AUDIO_LANGUAGES =
3649
listOf(
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:app="http://schemas.android.com/apk/res-auto"
4+
xmlns:card_view="http://schemas.android.com/apk/res-auto">
5+
6+
<androidx.constraintlayout.widget.ConstraintLayout
7+
android:layout_width="match_parent"
8+
android:layout_height="match_parent"
9+
android:background="@color/component_color_onboarding_shared_green_color">
10+
11+
<androidx.constraintlayout.widget.Guideline
12+
android:id="@+id/audio_language_background_guide"
13+
android:layout_width="wrap_content"
14+
android:layout_height="wrap_content"
15+
android:orientation="horizontal"
16+
app:layout_constraintGuide_percent="0.55" />
17+
18+
<org.oppia.android.app.customview.OppiaCurveBackgroundView
19+
android:layout_width="match_parent"
20+
android:layout_height="0dp"
21+
app:customBackgroundColor="@{@color/component_color_onboarding_shared_white_color}"
22+
app:layout_constraintBottom_toBottomOf="parent"
23+
app:layout_constraintTop_toBottomOf="@id/audio_language_background_guide" />
24+
25+
<TextView
26+
android:id="@+id/audio_language_text"
27+
style="@style/AudioLanguageTextStyle"
28+
android:layout_marginTop="@dimen/phone_shared_margin_xl"
29+
android:layout_marginEnd="@dimen/phone_shared_margin_large"
30+
android:text="@string/audio_language_fragment_text"
31+
android:textColor="@color/component_color_onboarding_shared_white_color"
32+
app:layout_constraintBottom_toTopOf="@id/audio_language_subtitle"
33+
app:layout_constraintEnd_toEndOf="parent"
34+
app:layout_constraintStart_toStartOf="parent"
35+
app:layout_constraintTop_toTopOf="parent" />
36+
37+
<TextView
38+
android:id="@+id/audio_language_subtitle"
39+
style="@style/AudioLanguageSubtitleStyle"
40+
android:layout_marginStart="@dimen/phone_shared_margin_xl"
41+
android:layout_marginTop="@dimen/phone_shared_margin_small"
42+
android:layout_marginEnd="@dimen/phone_shared_margin_xl"
43+
android:text="@string/audio_language_fragment_subtitle"
44+
android:textColor="@color/component_color_onboarding_shared_white_color"
45+
app:layout_constraintEnd_toEndOf="parent"
46+
app:layout_constraintStart_toStartOf="parent"
47+
app:layout_constraintTop_toBottomOf="@id/audio_language_text"
48+
app:layout_constraintWidth_percent="0.50" />
49+
50+
<com.google.android.material.card.MaterialCardView
51+
android:id="@+id/audio_language_dropdown_background"
52+
android:layout_width="0dp"
53+
android:layout_height="wrap_content"
54+
android:layout_marginStart="@dimen/phone_shared_margin_xl"
55+
android:layout_marginTop="@dimen/phone_shared_margin_large"
56+
android:layout_marginEnd="@dimen/phone_shared_margin_xl"
57+
app:layout_constraintEnd_toEndOf="parent"
58+
app:layout_constraintStart_toStartOf="parent"
59+
app:layout_constraintTop_toBottomOf="@id/audio_language_subtitle"
60+
app:layout_constraintWidth_percent="0.50"
61+
card_view:cardCornerRadius="@dimen/onboarding_shared_corner_radius"
62+
card_view:cardElevation="@dimen/onboarding_shared_elevation"
63+
card_view:cardUseCompatPadding="false">
64+
65+
<com.google.android.material.textfield.TextInputLayout style="@style/LanguageDropdownStyle">
66+
67+
<AutoCompleteTextView
68+
android:id="@+id/audio_language_dropdown_list"
69+
android:layout_width="match_parent"
70+
android:layout_height="wrap_content"
71+
android:inputType="none"
72+
android:padding="@dimen/onboarding_shared_padding_small" />
73+
</com.google.android.material.textfield.TextInputLayout>
74+
</com.google.android.material.card.MaterialCardView>
75+
76+
<Button
77+
android:id="@+id/onboarding_navigation_back"
78+
style="@style/OnboardingNavigationSecondaryButton"
79+
android:layout_width="0dp"
80+
android:layout_height="wrap_content"
81+
android:layout_margin="@dimen/phone_shared_margin_large"
82+
android:text="@string/onboarding_navigation_back"
83+
app:layout_constraintBottom_toBottomOf="parent"
84+
app:layout_constraintStart_toStartOf="parent" />
85+
86+
<Button
87+
android:id="@+id/onboarding_navigation_continue"
88+
style="@style/OnboardingNavigationPrimaryButton"
89+
android:layout_width="0dp"
90+
android:layout_height="wrap_content"
91+
android:layout_margin="@dimen/phone_shared_margin_large"
92+
android:text="@string/onboarding_navigation_continue"
93+
app:layout_constraintBottom_toBottomOf="parent"
94+
app:layout_constraintEnd_toEndOf="parent" />
95+
</androidx.constraintlayout.widget.ConstraintLayout>
96+
</layout>

app/src/main/res/layout-land/onboarding_app_language_selection_fragment.xml

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -91,15 +91,7 @@
9191
card_view:cardUseCompatPadding="false">
9292

9393
<com.google.android.material.textfield.TextInputLayout
94-
style="@style/Widget.MaterialComponents.TextInputLayout.FilledBox.ExposedDropdownMenu"
95-
android:layout_width="match_parent"
96-
android:layout_height="wrap_content"
97-
android:textColor="@color/component_color_onboarding_shared_text_color"
98-
app:boxBackgroundColor="@color/component_color_onboarding_shared_white_color"
99-
app:boxStrokeWidth="0dp"
100-
app:boxStrokeWidthFocused="0dp"
101-
app:endIconDrawable="@drawable/ic_arrow_drop_down_black_24dp"
102-
app:endIconTint="@color/component_color_shared_black_background_color"
94+
style="@style/LanguageDropdownStyle"
10395
app:startIconDrawable="@drawable/ic_language_icon_black_24dp"
10496
app:startIconTint="@color/component_color_shared_black_background_color">
10597

0 commit comments

Comments
 (0)