diff --git a/app/BUILD.bazel b/app/BUILD.bazel
index 48ab86b20b1..2e155aeb696 100644
--- a/app/BUILD.bazel
+++ b/app/BUILD.bazel
@@ -214,6 +214,7 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [
"src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt",
"src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt",
"src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt",
+ "src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateLearnerProfileViewModel.kt",
"src/main/java/org/oppia/android/app/ongoingtopiclist/OngoingTopicItemViewModel.kt",
"src/main/java/org/oppia/android/app/options/OptionsReadingTextSizeViewModel.kt",
"src/main/java/org/oppia/android/app/options/TextSizeItemViewModel.kt",
@@ -409,9 +410,9 @@ VIEWS_WITH_RESOURCE_IMPORTS = [
"src/main/java/org/oppia/android/app/customview/ChapterNotStartedContainerConstraintLayout.kt",
"src/main/java/org/oppia/android/app/customview/ContinueButtonView.kt",
"src/main/java/org/oppia/android/app/customview/LessonThumbnailImageView.kt",
+ "src/main/java/org/oppia/android/app/customview/OppiaCurveBackgroundView.kt",
"src/main/java/org/oppia/android/app/customview/PromotedStoryCardView.kt",
"src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt",
- "src/main/java/org/oppia/android/app/customview/SurveyOnboardingBackgroundView.kt",
"src/main/java/org/oppia/android/app/customview/VerticalDashedLineView.kt",
"src/main/java/org/oppia/android/app/survey/SurveyMultipleChoiceOptionView.kt",
"src/main/java/org/oppia/android/app/survey/SurveyNpsItemOptionView.kt",
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 41d1ce55918..1dee1b80db5 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -24,6 +24,7 @@
+
+ android:theme="@style/OppiaThemeWithoutActionBar" />
+
+
+
+
override fun onAttach(context: Context) {
super.onAttach(context)
(fragmentComponent as FragmentComponentImpl).inject(this)
@@ -24,6 +34,10 @@ class OnboardingFragment : InjectableFragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
- return onboardingFragmentPresenter.handleCreateView(inflater, container)
+ return if (enableOnboardingFlowV2.value) {
+ onboardingFragmentPresenterV2.handleCreateView(inflater, container)
+ } else {
+ onboardingFragmentPresenter.handleCreateView(inflater, container)
+ }
}
}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/AudioLanguageFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/AudioLanguageFragmentPresenter.kt
new file mode 100644
index 00000000000..bf934d926fe
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/AudioLanguageFragmentPresenter.kt
@@ -0,0 +1,123 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+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.home.HomeActivity
+import org.oppia.android.app.model.AudioLanguage
+import org.oppia.android.app.model.ProfileId
+import org.oppia.android.app.translation.AppLanguageResourceHandler
+import org.oppia.android.databinding.AudioLanguageSelectionFragmentBinding
+import org.oppia.android.domain.oppialogger.OppiaLogger
+import org.oppia.android.domain.profile.ProfileManagementController
+import org.oppia.android.util.data.AsyncResult
+import org.oppia.android.util.data.DataProviders.Companion.toLiveData
+import javax.inject.Inject
+
+/** The presenter for [AudioLanguageFragment] V2. */
+class AudioLanguageFragmentPresenter @Inject constructor(
+ private val fragment: Fragment,
+ private val activity: AppCompatActivity,
+ private val appLanguageResourceHandler: AppLanguageResourceHandler,
+ private val profileManagementController: ProfileManagementController,
+ private val oppiaLogger: OppiaLogger
+) {
+ private lateinit var binding: AudioLanguageSelectionFragmentBinding
+ private val orientation = Resources.getSystem().configuration.orientation
+
+ /**
+ * Returns a newly inflated view to render the fragment with the specified [audioLanguage] as the
+ * initial selected language.
+ */
+ fun handleCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?
+ ): View {
+
+ 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.audioLanguageDropdown.adapter = ArrayAdapter(
+ fragment.requireContext(),
+ R.layout.onboarding_language_dropdown_item,
+ R.id.onboarding_language_text_view,
+ getAudioLanguageList()
+ )
+
+ val currentUserProfileId = retrieveNewProfileId()
+
+ binding.onboardingNavigationContinue.setOnClickListener {
+ val intent =
+ HomeActivity.createHomeActivity(fragment.requireContext(), currentUserProfileId.internalId)
+ fragment.startActivity(intent)
+ fragment.activity?.finish()
+ }
+
+ binding.onboardingNavigationBack.setOnClickListener {
+ activity.finish()
+ }
+
+ binding.onboardingStepsCount?.visibility =
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) View.VISIBLE else View.GONE
+
+ return binding.root
+ }
+
+ private fun retrieveNewProfileId(): ProfileId {
+ var profileId: ProfileId = ProfileId.getDefaultInstance()
+ profileManagementController.getProfiles().toLiveData().observe(
+ fragment,
+ { profilesResult ->
+ when (profilesResult) {
+ is AsyncResult.Failure -> {
+ oppiaLogger.e(
+ "AudioLanguageFragmentPresenter",
+ "Failed to retrieve the list of profiles",
+ profilesResult.error
+ )
+ }
+ is AsyncResult.Pending -> {}
+ is AsyncResult.Success -> {
+ val sortedProfileList = profilesResult.value.sortedBy { it.id.internalId }
+ profileId = sortedProfileList.last().id
+ }
+ }
+ }
+ )
+ return profileId
+ }
+
+ private fun getAudioLanguageList(): List {
+ return AudioLanguage.values()
+ .filter { it.isValid() }
+ .map { audioLanguage ->
+ appLanguageResourceHandler.computeLocalizedDisplayName(audioLanguage)
+ }
+ }
+
+ private fun AudioLanguage.isValid(): Boolean {
+ return when (this) {
+ AudioLanguage.UNRECOGNIZED, AudioLanguage.AUDIO_LANGUAGE_UNSPECIFIED,
+ AudioLanguage.NO_AUDIO -> false
+ else -> true
+ }
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateLearnerProfileViewModel.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateLearnerProfileViewModel.kt
new file mode 100644
index 00000000000..c3ae8b184a3
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateLearnerProfileViewModel.kt
@@ -0,0 +1,21 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.view.View
+import androidx.databinding.ObservableField
+import org.oppia.android.app.fragment.FragmentScope
+import org.oppia.android.app.viewmodel.ObservableViewModel
+import javax.inject.Inject
+
+/** The ViewModel for [CreateProfileFragment]. */
+@FragmentScope
+class CreateLearnerProfileViewModel @Inject constructor() : ObservableViewModel() {
+ private val orientation = Resources.getSystem().configuration.orientation
+
+ /** ObservableField that tracks whether a nickname has been entered. */
+ val hasError = ObservableField(false)
+
+ val onboardingStepsCount =
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) View.VISIBLE else View.GONE
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivity.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivity.kt
new file mode 100644
index 00000000000..52e1dfa8729
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivity.kt
@@ -0,0 +1,32 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import org.oppia.android.app.activity.ActivityComponentImpl
+import org.oppia.android.app.activity.InjectableAutoLocalizedAppCompatActivity
+import org.oppia.android.app.model.ScreenName
+import org.oppia.android.util.logging.CurrentAppScreenNameIntentDecorator.decorateWithScreenName
+import javax.inject.Inject
+
+/** Activity for displaying a new learner profile creation flow. */
+class CreateProfileActivity : InjectableAutoLocalizedAppCompatActivity() {
+ @Inject
+ lateinit var learnerProfileActivityPresenter: CreateProfileActivityPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ (activityComponent as ActivityComponentImpl).inject(this)
+
+ learnerProfileActivityPresenter.handleOnCreate()
+ }
+
+ companion object {
+ /** Returns a new [Intent] open a [CreateProfileActivity] with the specified params. */
+ fun createNewLearnerProfileActivity(context: Context): Intent {
+ return Intent(context, CreateProfileActivity::class.java).apply {
+ decorateWithScreenName(ScreenName.CREATE_NEW_LEARNER_PROFILE_ACTIVITY)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivityPresenter.kt
new file mode 100644
index 00000000000..2727e648415
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileActivityPresenter.kt
@@ -0,0 +1,40 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import androidx.appcompat.app.AppCompatActivity
+import androidx.databinding.DataBindingUtil
+import org.oppia.android.R
+import org.oppia.android.databinding.CreateProfileActivityBinding
+import javax.inject.Inject
+
+private const val TAG_CREATE_PROFILE_ACTIVITY_FRAGMENT = "TAG_CREATE_PROFILE_ACTIVITY_FRAGMENT"
+
+/** Presenter for [CreateProfileActivity]. */
+class CreateProfileActivityPresenter @Inject constructor(
+ private val activity: AppCompatActivity
+) {
+ private lateinit var binding: CreateProfileActivityBinding
+
+ /** Handle creation and binding of the CreateProfileActivity layout. */
+ fun handleOnCreate() {
+ binding = DataBindingUtil.setContentView(activity, R.layout.create_profile_activity)
+ binding.apply {
+ lifecycleOwner = activity
+ }
+
+ if (getNewLearnerProfileFragment() == null) {
+ val createLearnerProfileFragment = CreateProfileFragment()
+ activity.supportFragmentManager.beginTransaction().add(
+ R.id.profile_fragment_placeholder,
+ createLearnerProfileFragment,
+ TAG_CREATE_PROFILE_ACTIVITY_FRAGMENT
+ )
+ .commitNow()
+ }
+ }
+
+ private fun getNewLearnerProfileFragment(): CreateProfileFragment? {
+ return activity.supportFragmentManager.findFragmentByTag(
+ TAG_CREATE_PROFILE_ACTIVITY_FRAGMENT
+ ) as? CreateProfileFragment
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragment.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragment.kt
new file mode 100644
index 00000000000..6ad586d2f46
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragment.kt
@@ -0,0 +1,35 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.android.app.fragment.FragmentComponentImpl
+import org.oppia.android.app.fragment.InjectableFragment
+import javax.inject.Inject
+
+/** Fragment for displaying a new learner profile creation flow. */
+class CreateProfileFragment : InjectableFragment() {
+ @Inject
+ lateinit var learnerProfileFragmentPresenter: CreateProfileFragmentPresenter
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ (fragmentComponent as FragmentComponentImpl).inject(this)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return learnerProfileFragmentPresenter.handleCreateView(inflater, container)
+ }
+
+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ super.onActivityResult(requestCode, resultCode, data)
+ learnerProfileFragmentPresenter.handleOnActivityResult(requestCode, resultCode, data)
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragmentPresenter.kt
new file mode 100644
index 00000000000..e139bf63d5f
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/CreateProfileFragmentPresenter.kt
@@ -0,0 +1,170 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.app.Activity
+import android.content.Intent
+import android.graphics.PorterDuff
+import android.graphics.drawable.Drawable
+import android.net.Uri
+import android.provider.MediaStore
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.res.ResourcesCompat
+import androidx.fragment.app.Fragment
+import com.bumptech.glide.Glide
+import com.bumptech.glide.load.DataSource
+import com.bumptech.glide.load.engine.GlideException
+import com.bumptech.glide.request.RequestListener
+import com.bumptech.glide.request.RequestOptions
+import com.bumptech.glide.request.target.Target
+import org.oppia.android.R
+import org.oppia.android.app.fragment.FragmentScope
+import org.oppia.android.app.translation.AppLanguageResourceHandler
+import org.oppia.android.databinding.CreateProfileFragmentBinding
+import org.oppia.android.domain.profile.ProfileManagementController
+import org.oppia.android.util.data.AsyncResult
+import org.oppia.android.util.data.DataProviders.Companion.toLiveData
+import javax.inject.Inject
+
+const val GALLERY_INTENT_RESULT_CODE = 1
+
+/** Presenter for [CreateProfileFragment]. */
+@FragmentScope
+class CreateProfileFragmentPresenter @Inject constructor(
+ private val fragment: Fragment,
+ private val activity: AppCompatActivity,
+ private val createLearnerProfileViewModel: CreateLearnerProfileViewModel,
+ private val profileManagementController: ProfileManagementController,
+ private val resourceHandler: AppLanguageResourceHandler
+) {
+ private lateinit var binding: CreateProfileFragmentBinding
+ private lateinit var uploadImageView: ImageView
+ private var selectedImage: Uri? = null
+
+ /** Initialize layout bindings. */
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
+ binding = CreateProfileFragmentBinding.inflate(
+ inflater,
+ container,
+ /* attachToRoot= */ false
+ )
+ binding.let {
+ it.lifecycleOwner = fragment
+ it.viewModel = createLearnerProfileViewModel
+ }
+
+ uploadImageView = binding.createProfileUserImageView
+ Glide.with(activity)
+ .load(R.drawable.ic_default_avatar)
+ .listener(object : RequestListener {
+ override fun onLoadFailed(
+ e: GlideException?,
+ model: Any?,
+ target: Target?,
+ isFirstResource: Boolean
+ ): Boolean {
+ return false
+ }
+
+ override fun onResourceReady(
+ resource: Drawable?,
+ model: Any?,
+ target: Target?,
+ dataSource: DataSource?,
+ isFirstResource: Boolean
+ ): Boolean {
+ uploadImageView.setColorFilter(
+ ResourcesCompat.getColor(
+ activity.resources,
+ R.color.component_color_avatar_background_25_color,
+ null
+ ),
+ PorterDuff.Mode.DST_OVER
+ )
+ return false
+ }
+ })
+ .into(uploadImageView)
+
+ binding.onboardingNavigationContinue.setOnClickListener {
+ val nickname = binding.createProfileNicknameEdittext.text.toString().trim()
+
+ if (nickname.isNotBlank()) {
+ createLearnerProfileViewModel.hasError.set(false)
+ profileManagementController.addProfile(
+ name = nickname,
+ pin = "",
+ avatarImagePath = selectedImage,
+ allowDownloadAccess = true,
+ colorRgb = -10710042,
+ isAdmin = false
+ )
+ .toLiveData()
+ .observe(
+ fragment,
+ {
+ handleAddProfileResult(it, nickname)
+ }
+ )
+ } else {
+ createLearnerProfileViewModel.hasError.set(true)
+ }
+ }
+
+ binding.onboardingNavigationBack.setOnClickListener { activity.finish() }
+ binding.createProfileEditPictureIcon.setOnClickListener { openGalleryIntent() }
+ binding.createProfilePicturePrompt.setOnClickListener { openGalleryIntent() }
+ binding.createProfileUserImageView.setOnClickListener { openGalleryIntent() }
+
+ return binding.root
+ }
+
+ fun handleOnActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
+ if (requestCode == GALLERY_INTENT_RESULT_CODE && resultCode == Activity.RESULT_OK) {
+ binding.createProfilePicturePrompt.visibility = View.GONE
+ data?.let {
+ selectedImage = data.data
+ Glide.with(activity)
+ .load(selectedImage)
+ .centerCrop()
+ .apply(RequestOptions.circleCropTransform())
+ .into(uploadImageView)
+ }
+ }
+ }
+
+ private fun openGalleryIntent() {
+ val galleryIntent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
+ fragment.startActivityForResult(galleryIntent, GALLERY_INTENT_RESULT_CODE)
+ }
+
+ private fun handleAddProfileResult(result: AsyncResult, nickName: String) {
+ when (result) {
+ is AsyncResult.Success -> {
+ val intent =
+ OnboardingLearnerIntroActivity.createOnboardingLearnerIntroActivity(activity, nickName)
+ fragment.startActivity(intent)
+ }
+ is AsyncResult.Failure -> {
+ createLearnerProfileViewModel.hasError.set(true)
+ when (result.error) {
+ is ProfileManagementController.ProfileNameNotUniqueException ->
+ binding.createProfileNicknameError.text =
+ resourceHandler.getStringInLocale(
+ R.string.add_profile_error_name_not_unique
+ )
+
+ is ProfileManagementController.ProfileNameOnlyLettersException ->
+ binding.createProfileNicknameError.text =
+ resourceHandler.getStringInLocale(
+ R.string.add_profile_error_name_only_letters
+ )
+ else -> binding.createProfileNicknameError.text = result.error.message
+ }
+ }
+ is AsyncResult.Pending -> {} // Wait for an actual result.
+ }
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingFragmentPresenter.kt
new file mode 100644
index 00000000000..26671f02a1e
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingFragmentPresenter.kt
@@ -0,0 +1,47 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import org.oppia.android.R
+import org.oppia.android.app.fragment.FragmentScope
+import org.oppia.android.app.translation.AppLanguageResourceHandler
+import org.oppia.android.databinding.OnboardingAppLanguageSelectionFragmentBinding
+import javax.inject.Inject
+
+/** The presenter for [OnboardingFragment] V2. */
+@FragmentScope
+class OnboardingFragmentPresenter @Inject constructor(
+ private val activity: AppCompatActivity,
+ private val fragment: Fragment,
+ private val appLanguageResourceHandler: AppLanguageResourceHandler
+) {
+ private lateinit var binding: OnboardingAppLanguageSelectionFragmentBinding
+
+ /** Handle creation and binding of the [OnboardingFragment] V2 layout. */
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
+ binding = OnboardingAppLanguageSelectionFragmentBinding.inflate(
+ inflater,
+ container,
+ /* attachToRoot= */ false
+ )
+
+ binding.let {
+ it.lifecycleOwner = fragment
+ }
+
+ binding.onboardingLanguageTitle.text = appLanguageResourceHandler.getStringInLocaleWithWrapping(
+ R.string.onboarding_language_activity_title,
+ appLanguageResourceHandler.getStringInLocale(R.string.app_name)
+ )
+
+ binding.onboardingLanguageLetsGoButton.setOnClickListener {
+ val intent = OnboardingProfileTypeActivity.createOnboardingProfileTypeActivityIntent(activity)
+ fragment.startActivity(intent)
+ }
+
+ return binding.root
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivity.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivity.kt
new file mode 100644
index 00000000000..d8ab2e417fa
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivity.kt
@@ -0,0 +1,59 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import org.oppia.android.app.activity.ActivityComponentImpl
+import org.oppia.android.app.activity.InjectableAutoLocalizedAppCompatActivity
+import org.oppia.android.app.model.OnboardingIntroActivityParams
+import org.oppia.android.app.model.ScreenName
+import org.oppia.android.util.extensions.getProtoExtra
+import org.oppia.android.util.extensions.putProtoExtra
+import org.oppia.android.util.logging.CurrentAppScreenNameIntentDecorator.decorateWithScreenName
+import javax.inject.Inject
+
+/** The activity for showing the learner welcome screen. */
+class OnboardingLearnerIntroActivity : InjectableAutoLocalizedAppCompatActivity() {
+ @Inject
+ lateinit var onboardingLearnerIntroActivityPresenter: OnboardingLearnerIntroActivityPresenter
+
+ private lateinit var profileNickname: String
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ (activityComponent as ActivityComponentImpl).inject(this)
+
+ val params = intent.extractParams()
+ this.profileNickname = params.profileNickname
+
+ onboardingLearnerIntroActivityPresenter.handleOnCreate(profileNickname)
+ }
+
+ companion object {
+ private const val PARAMS_KEY = "OnboardingIntroActivity.params"
+
+ /**
+ * A convenience function for creating a new [OnboardingLearnerIntroActivity] intent by prefilling
+ * common params needed by the activity.
+ */
+ fun createOnboardingLearnerIntroActivity(context: Context, profileNickname: String): Intent {
+ val params = OnboardingIntroActivityParams.newBuilder()
+ .setProfileNickname(profileNickname)
+ .build()
+ return createOnboardingLearnerIntroActivity(context, params)
+ }
+
+ private fun createOnboardingLearnerIntroActivity(
+ context: Context,
+ params: OnboardingIntroActivityParams
+ ): Intent {
+ return Intent(context, OnboardingLearnerIntroActivity::class.java).apply {
+ putProtoExtra(PARAMS_KEY, params)
+ decorateWithScreenName(ScreenName.ONBOARDING_LEARNER_INTRO_ACTIVITY)
+ }
+ }
+
+ private fun Intent.extractParams() =
+ getProtoExtra(PARAMS_KEY, OnboardingIntroActivityParams.getDefaultInstance())
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivityPresenter.kt
new file mode 100644
index 00000000000..fab8ad9cda8
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroActivityPresenter.kt
@@ -0,0 +1,51 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.os.Bundle
+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.databinding.OnboardingLearnerIntroActivityBinding
+import javax.inject.Inject
+
+private const val TAG_LEARNER_INTRO_FRAGMENT = "TAG_LEARNER_INTRO_FRAGMENT"
+
+/** Argument key for bundling the profileId. */
+const val PROFILE_NICKNAME_ARGUMENT_KEY = "profile_nickname"
+
+/** The Presenter for [OnboardingLearnerIntroActivity]. */
+@ActivityScope
+class OnboardingLearnerIntroActivityPresenter @Inject constructor(
+ private val activity: AppCompatActivity
+) {
+ private lateinit var binding: OnboardingLearnerIntroActivityBinding
+
+ /** Handle creation and binding of the OnboardingLearnerIntroActivity layout. */
+ fun handleOnCreate(profileNickname: String) {
+ binding = DataBindingUtil.setContentView(activity, R.layout.onboarding_learner_intro_activity)
+ binding.apply {
+ lifecycleOwner = activity
+ }
+
+ if (getOnboardingLearnerIntroFragment() == null) {
+ val onboardingLearnerIntroFragment = OnboardingLearnerIntroFragment()
+
+ val args = Bundle()
+ args.putString(PROFILE_NICKNAME_ARGUMENT_KEY, profileNickname)
+ onboardingLearnerIntroFragment.arguments = args
+
+ activity.supportFragmentManager.beginTransaction().add(
+ R.id.learner_intro_fragment_placeholder,
+ onboardingLearnerIntroFragment,
+ TAG_LEARNER_INTRO_FRAGMENT
+ )
+ .commitNow()
+ }
+ }
+
+ private fun getOnboardingLearnerIntroFragment(): OnboardingLearnerIntroFragment? {
+ return activity.supportFragmentManager.findFragmentByTag(
+ TAG_LEARNER_INTRO_FRAGMENT
+ ) as? OnboardingLearnerIntroFragment
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragment.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragment.kt
new file mode 100644
index 00000000000..fd6aea347db
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragment.kt
@@ -0,0 +1,35 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.android.app.fragment.FragmentComponentImpl
+import org.oppia.android.app.fragment.InjectableFragment
+import org.oppia.android.util.extensions.getStringFromBundle
+import javax.inject.Inject
+
+/** Fragment that contains the introduction message for new learners. */
+class OnboardingLearnerIntroFragment : InjectableFragment() {
+ @Inject
+ lateinit var onboardingLearnerIntroFragmentPresenter: OnboardingLearnerIntroFragmentPresenter
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ (fragmentComponent as FragmentComponentImpl).inject(this)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ val profileNickname = arguments!!.getStringFromBundle(PROFILE_NICKNAME_ARGUMENT_KEY)!!
+ return onboardingLearnerIntroFragmentPresenter.handleCreateView(
+ inflater,
+ container,
+ profileNickname
+ )
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragmentPresenter.kt
new file mode 100644
index 00000000000..ba9c2791d8a
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingLearnerIntroFragmentPresenter.kt
@@ -0,0 +1,72 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.res.Configuration
+import android.content.res.Resources
+import android.view.LayoutInflater
+import android.view.View
+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.OnboardingLearnerIntroFragmentBinding
+import javax.inject.Inject
+
+/** The presenter for [OnboardingLearnerIntroFragment]. */
+class OnboardingLearnerIntroFragmentPresenter @Inject constructor(
+ private var fragment: Fragment,
+ private val activity: AppCompatActivity,
+ private val appLanguageResourceHandler: AppLanguageResourceHandler,
+) {
+ private lateinit var binding: OnboardingLearnerIntroFragmentBinding
+
+ private val orientation = Resources.getSystem().configuration.orientation
+
+ /** Handle creation and binding of the OnboardingLearnerIntroFragment layout. */
+ fun handleCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ profileNickname: String,
+ ): View {
+ binding = OnboardingLearnerIntroFragmentBinding.inflate(
+ inflater,
+ container,
+ /* attachToRoot= */ false
+ )
+ binding.lifecycleOwner = fragment
+
+ setLearnerName(profileNickname)
+
+ binding.onboardingNavigationBack.setOnClickListener {
+ activity.finish()
+ }
+
+ binding.onboardingNavigationContinue.setOnClickListener {
+ val intent = AudioLanguageActivity.createAudioLanguageActivityIntent(
+ fragment.requireContext(),
+ AudioLanguage.ENGLISH_AUDIO_LANGUAGE
+ )
+ fragment.startActivity(intent)
+ }
+
+ binding.onboardingLearnerIntroFeedback.text =
+ appLanguageResourceHandler.getStringInLocaleWithWrapping(
+ R.string.onboarding_learner_intro_feedback_text,
+ appLanguageResourceHandler.getStringInLocale(R.string.app_name)
+ )
+
+ binding.onboardingStepsCount.visibility =
+ if (orientation == Configuration.ORIENTATION_PORTRAIT) View.VISIBLE else View.GONE
+
+ return binding.root
+ }
+
+ private fun setLearnerName(profileName: String) {
+ binding.onboardingLearnerIntroTitle.text =
+ appLanguageResourceHandler.getStringInLocaleWithWrapping(
+ R.string.onboarding_learner_intro_activity_text, profileName
+ )
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivity.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivity.kt
new file mode 100644
index 00000000000..bea2bc36c83
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivity.kt
@@ -0,0 +1,32 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.content.Intent
+import android.os.Bundle
+import org.oppia.android.app.activity.ActivityComponentImpl
+import org.oppia.android.app.activity.InjectableAutoLocalizedAppCompatActivity
+import org.oppia.android.app.model.ScreenName
+import org.oppia.android.util.logging.CurrentAppScreenNameIntentDecorator.decorateWithScreenName
+import javax.inject.Inject
+
+/** The activity for showing the profile type selection screen. */
+class OnboardingProfileTypeActivity : InjectableAutoLocalizedAppCompatActivity() {
+ @Inject
+ lateinit var onboardingProfileTypeActivityPresenter: OnboardingProfileTypeActivityPresenter
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ (activityComponent as ActivityComponentImpl).inject(this)
+
+ onboardingProfileTypeActivityPresenter.handleOnCreate()
+ }
+
+ companion object {
+ /** Returns a new [Intent] open a [OnboardingProfileTypeActivity] with the specified params. */
+ fun createOnboardingProfileTypeActivityIntent(context: Context): Intent {
+ return Intent(context, OnboardingProfileTypeActivity::class.java).apply {
+ decorateWithScreenName(ScreenName.ONBOARDING_PROFILE_TYPE_ACTIVITY)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivityPresenter.kt
new file mode 100644
index 00000000000..f678ed058c3
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeActivityPresenter.kt
@@ -0,0 +1,42 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+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.databinding.OnboardingProfileTypeActivityBinding
+import javax.inject.Inject
+
+private const val TAG_PROFILE_TYPE_FRAGMENT = "TAG_PROFILE_TYPE_FRAGMENT"
+
+/** The Presenter for [OnboardingProfileTypeActivity]. */
+@ActivityScope
+class OnboardingProfileTypeActivityPresenter @Inject constructor(
+ private val activity: AppCompatActivity
+) {
+ private lateinit var binding: OnboardingProfileTypeActivityBinding
+
+ /** Handle creation and binding of the OnboardingProfileTypeActivity layout. */
+ fun handleOnCreate() {
+ binding = DataBindingUtil.setContentView(activity, R.layout.onboarding_profile_type_activity)
+ binding.apply {
+ lifecycleOwner = activity
+ }
+
+ if (getOnboardingProfileTypeFragment() == null) {
+ val onboardingProfileTypeFragment = OnboardingProfileTypeFragment()
+ activity.supportFragmentManager.beginTransaction().add(
+ R.id.profile_type_fragment_placeholder,
+ onboardingProfileTypeFragment,
+ TAG_PROFILE_TYPE_FRAGMENT
+ )
+ .commitNow()
+ }
+ }
+
+ private fun getOnboardingProfileTypeFragment(): OnboardingProfileTypeFragment? {
+ return activity.supportFragmentManager.findFragmentByTag(
+ TAG_PROFILE_TYPE_FRAGMENT
+ ) as? OnboardingProfileTypeFragment
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragment.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragment.kt
new file mode 100644
index 00000000000..21bf3750217
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragment.kt
@@ -0,0 +1,29 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import org.oppia.android.app.fragment.FragmentComponentImpl
+import org.oppia.android.app.fragment.InjectableFragment
+import javax.inject.Inject
+
+/** Fragment that contains the profile type selection flow of the app. */
+class OnboardingProfileTypeFragment : InjectableFragment() {
+ @Inject
+ lateinit var onboardingProfileTypeFragmentPresenter: OnboardingProfileTypeFragmentPresenter
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ (fragmentComponent as FragmentComponentImpl).inject(this)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ return onboardingProfileTypeFragmentPresenter.handleCreateView(inflater, container)
+ }
+}
diff --git a/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragmentPresenter.kt
new file mode 100644
index 00000000000..47f5242909a
--- /dev/null
+++ b/app/src/main/java/org/oppia/android/app/onboarding/onboardingv2/OnboardingProfileTypeFragmentPresenter.kt
@@ -0,0 +1,45 @@
+package org.oppia.android.app.onboarding.onboardingv2
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.appcompat.app.AppCompatActivity
+import androidx.fragment.app.Fragment
+import org.oppia.android.app.profile.ProfileChooserActivity
+import org.oppia.android.databinding.OnboardingProfileTypeFragmentBinding
+import javax.inject.Inject
+
+/** The presenter for [OnboardingProfileTypeFragment]. */
+class OnboardingProfileTypeFragmentPresenter @Inject constructor(
+ private val fragment: Fragment,
+ private val activity: AppCompatActivity
+) {
+ private lateinit var binding: OnboardingProfileTypeFragmentBinding
+
+ /** Handle creation and binding of the OnboardingProfileTypeFragment layout. */
+ fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View {
+ binding = OnboardingProfileTypeFragmentBinding.inflate(
+ inflater,
+ container,
+ /* attachToRoot= */ false
+ )
+ binding.let {
+ it.lifecycleOwner = fragment
+ }
+
+ binding.profileTypeLearnerNavigationCard.setOnClickListener {
+ val intent = CreateProfileActivity.createNewLearnerProfileActivity(activity)
+ fragment.startActivity(intent)
+ }
+
+ binding.profileTypeSupervisorNavigationCard.setOnClickListener {
+ val intent = ProfileChooserActivity.createProfileChooserActivity(activity)
+ fragment.startActivity(intent)
+ }
+
+ binding.onboardingNavigationBack.setOnClickListener {
+ activity.finish()
+ }
+ 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..95621e93602 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
@@ -12,11 +12,22 @@ import org.oppia.android.app.model.AudioLanguageFragmentArguments
import org.oppia.android.app.model.AudioLanguageFragmentStateBundle
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
+import org.oppia.android.app.onboarding.onboardingv2.AudioLanguageFragmentPresenter as AudioLanguageFragmentPresenterV2
/** The fragment to change the default audio language of the app. */
class AudioLanguageFragment : InjectableFragment(), AudioLanguageRadioButtonListener {
- @Inject lateinit var audioLanguageFragmentPresenter: AudioLanguageFragmentPresenter
+ @Inject
+ lateinit var audioLanguageFragmentPresenter: AudioLanguageFragmentPresenter
+
+ @Inject
+ lateinit var audioLanguageFragmentPresenterV2: AudioLanguageFragmentPresenterV2
+
+ @Inject
+ @field:EnableOnboardingFlowV2
+ lateinit var enableOnboardingFlowV2: PlatformParameterValue
override fun onAttach(context: Context) {
super.onAttach(context)
@@ -33,7 +44,11 @@ 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) {
+ audioLanguageFragmentPresenterV2.handleCreateView(inflater, container)
+ } else {
+ audioLanguageFragmentPresenter.handleOnCreateView(inflater, container, audioLanguage)
+ }
}
override fun onSaveInstanceState(outState: Bundle) {
diff --git a/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt
index 8020dfe8796..c0b7847dfe7 100644
--- a/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt
+++ b/app/src/main/java/org/oppia/android/app/survey/SurveyActivityPresenter.kt
@@ -11,8 +11,13 @@ import javax.inject.Inject
private const val TAG_SURVEY_FRAGMENT = "TAG_SURVEY_FRAGMENT"
+/** Argument key for bundling the profileId. */
const val PROFILE_ID_ARGUMENT_KEY = "profile_id"
+
+/** Argument key for bundling the topicId. */
const val TOPIC_ID_ARGUMENT_KEY = "topic_id"
+
+/** Argument key for bundling the explorationId. */
const val EXPLORATION_ID_ARGUMENT_KEY = "exploration_id"
/** The Presenter for [SurveyActivity]. */
@@ -20,6 +25,7 @@ const val EXPLORATION_ID_ARGUMENT_KEY = "exploration_id"
class SurveyActivityPresenter @Inject constructor(private val activity: AppCompatActivity) {
private lateinit var binding: SurveyActivityBinding
+ /** Handle creation and binding of the SurveyActivity layout. */
fun handleOnCreate(
profileId: ProfileId,
topicId: String,
diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt
index 08726cc7f49..ecb07ff3e28 100644
--- a/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt
+++ b/app/src/main/java/org/oppia/android/app/view/ViewComponentImpl.kt
@@ -6,9 +6,9 @@ import dagger.Subcomponent
import org.oppia.android.app.customview.ChapterNotStartedContainerConstraintLayout
import org.oppia.android.app.customview.ContinueButtonView
import org.oppia.android.app.customview.LessonThumbnailImageView
+import org.oppia.android.app.customview.OppiaCurveBackgroundView
import org.oppia.android.app.customview.PromotedStoryCardView
import org.oppia.android.app.customview.SegmentedCircularProgressView
-import org.oppia.android.app.customview.SurveyOnboardingBackgroundView
import org.oppia.android.app.home.promotedlist.ComingSoonTopicsListView
import org.oppia.android.app.home.promotedlist.PromotedStoryListView
import org.oppia.android.app.player.state.DragDropSortInteractionView
@@ -42,7 +42,7 @@ interface ViewComponentImpl : ViewComponent {
fun inject(promotedStoryCardView: PromotedStoryCardView)
fun inject(promotedStoryListView: PromotedStoryListView)
fun inject(segmentedCircularProgressView: SegmentedCircularProgressView)
- fun inject(surveyOnboardingBackgroundView: SurveyOnboardingBackgroundView)
+ fun inject(curveBackgroundView: OppiaCurveBackgroundView)
fun inject(surveyMultipleChoiceOptionView: SurveyMultipleChoiceOptionView)
fun inject(surveyNpsItemOptionView: SurveyNpsItemOptionView)
}
diff --git a/app/src/main/res/drawable/create_profile_picture_icon.xml b/app/src/main/res/drawable/create_profile_picture_icon.xml
new file mode 100644
index 00000000000..487cfa6f97f
--- /dev/null
+++ b/app/src/main/res/drawable/create_profile_picture_icon.xml
@@ -0,0 +1,33 @@
+
+
+ -
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/dropdown_background.xml b/app/src/main/res/drawable/dropdown_background.xml
new file mode 100644
index 00000000000..3eca06cfe8c
--- /dev/null
+++ b/app/src/main/res/drawable/dropdown_background.xml
@@ -0,0 +1,23 @@
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/edit_text_error_border.xml b/app/src/main/res/drawable/edit_text_error_border.xml
new file mode 100644
index 00000000000..6a42f9c1956
--- /dev/null
+++ b/app/src/main/res/drawable/edit_text_error_border.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/edit_text_white_background_error_border.xml b/app/src/main/res/drawable/edit_text_white_background_error_border.xml
new file mode 100644
index 00000000000..2851e1fc4cb
--- /dev/null
+++ b/app/src/main/res/drawable/edit_text_white_background_error_border.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/edit_text_white_background_with_border.xml b/app/src/main/res/drawable/edit_text_white_background_with_border.xml
new file mode 100644
index 00000000000..90e111c7c1a
--- /dev/null
+++ b/app/src/main/res/drawable/edit_text_white_background_with_border.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_green_check.xml b/app/src/main/res/drawable/ic_green_check.xml
new file mode 100644
index 00000000000..67bb482c387
--- /dev/null
+++ b/app/src/main/res/drawable/ic_green_check.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_language_icon_black_24dp.xml b/app/src/main/res/drawable/ic_language_icon_black_24dp.xml
new file mode 100644
index 00000000000..e89dd7a2a58
--- /dev/null
+++ b/app/src/main/res/drawable/ic_language_icon_black_24dp.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_outline_edit_24.xml b/app/src/main/res/drawable/ic_outline_edit_24.xml
new file mode 100644
index 00000000000..cd18181145e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_outline_edit_24.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/learner_otter.png b/app/src/main/res/drawable/learner_otter.png
new file mode 100644
index 00000000000..7d492965cda
Binary files /dev/null and b/app/src/main/res/drawable/learner_otter.png differ
diff --git a/app/src/main/res/drawable/onboarding_back_button_white_background.xml b/app/src/main/res/drawable/onboarding_back_button_white_background.xml
new file mode 100644
index 00000000000..47b0bf7daa1
--- /dev/null
+++ b/app/src/main/res/drawable/onboarding_back_button_white_background.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/app/src/main/res/drawable/otter.png b/app/src/main/res/drawable/otter.png
new file mode 100644
index 00000000000..9f42e7f8dcc
Binary files /dev/null and b/app/src/main/res/drawable/otter.png differ
diff --git a/app/src/main/res/drawable/parent_teacher_otter.png b/app/src/main/res/drawable/parent_teacher_otter.png
new file mode 100644
index 00000000000..ec2c4a546c7
Binary files /dev/null and b/app/src/main/res/drawable/parent_teacher_otter.png differ
diff --git a/app/src/main/res/drawable/rounded_primary_button_grey_shadow_color.xml b/app/src/main/res/drawable/rounded_primary_button_grey_shadow_color.xml
index 1566be1839b..b9b38dc514d 100644
--- a/app/src/main/res/drawable/rounded_primary_button_grey_shadow_color.xml
+++ b/app/src/main/res/drawable/rounded_primary_button_grey_shadow_color.xml
@@ -7,9 +7,9 @@
- -
+
-
-
+
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..fb0dcb54f48
--- /dev/null
+++ b/app/src/main/res/layout-land/audio_language_selection_fragment.xml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout-land/onboarding_app_language_selection_fragment.xml b/app/src/main/res/layout-land/onboarding_app_language_selection_fragment.xml
new file mode 100644
index 00000000000..f33dbad10d1
--- /dev/null
+++ b/app/src/main/res/layout-land/onboarding_app_language_selection_fragment.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout-land/onboarding_profile_type_fragment.xml b/app/src/main/res/layout-land/onboarding_profile_type_fragment.xml
new file mode 100644
index 00000000000..4b58a3b475b
--- /dev/null
+++ b/app/src/main/res/layout-land/onboarding_profile_type_fragment.xml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout-land/survey_welcome_dialog_fragment.xml b/app/src/main/res/layout-land/survey_welcome_dialog_fragment.xml
index 9a41b4cf558..86fd12d45b6 100644
--- a/app/src/main/res/layout-land/survey_welcome_dialog_fragment.xml
+++ b/app/src/main/res/layout-land/survey_welcome_dialog_fragment.xml
@@ -10,9 +10,10 @@
android:id="@+id/survey_onboarding_title_text"
style="@style/SurveyPopupHeaderStyle"
android:text="@string/survey_onboarding_title_text"
+
+ app:layout_constraintBottom_toTopOf="@id/survey_onboarding_title_guide"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintBottom_toTopOf="@id/survey_onboarding_title_guide"
app:layout_constraintTop_toTopOf="parent" />
-