Skip to content

Commit

Permalink
Fix Part of #4938: Introduce Onboarding Intro screen (#5385)
Browse files Browse the repository at this point in the history
<!-- 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 explain to the learner the purpose of the app.

The new learner's name is added as a greeting, passed via the intent.

Tests and placeholder tests have been added to verify that all views are
displayed and navigation works as expected.

## 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)).

## For UI-specific PRs only
||Portrait|Landscape|
|---|---|---|
|Mobile Light
Mode|![Screenshot_1718117878](https://github.com/oppia/oppia-android/assets/59600948/d01960a0-8eb4-4067-99ac-ccaa2f3b54af)|![Screenshot_1718117885](https://github.com/oppia/oppia-android/assets/59600948/29bb0cae-461e-40f1-930b-d3a2c58e1082)|
|Mobile Dark
Mode|![Screenshot_1718117908](https://github.com/oppia/oppia-android/assets/59600948/5fa43dce-fc9f-4924-ac10-1f1d55865580)|![Screenshot_1718117912](https://github.com/oppia/oppia-android/assets/59600948/e1fc1a9d-e993-4f8f-aa49-970b65dd444b)|
|Tablet Light
Mode|![Screenshot_1718118054](https://github.com/oppia/oppia-android/assets/59600948/4ebd9113-237b-4598-a1b9-982345bff8fd)|![Screenshot_1718118045](https://github.com/oppia/oppia-android/assets/59600948/bf318732-baa2-4f64-aa83-b1f0e82a8ba8)|![Screenshot_1718118119](https://github.com/oppia/oppia-android/assets/59600948/a0628419-867c-405a-b548-f487c1298e76)|
|Tablet Dark
Mode|![Screenshot_1718118119](https://github.com/oppia/oppia-android/assets/59600948/fdd40f9b-7cdf-4878-8833-f4d02500a3c2)|![Screenshot_1718118077](https://github.com/oppia/oppia-android/assets/59600948/3b4112a4-6574-432a-9d85-3a39767385a7)|
  • Loading branch information
adhiamboperes authored Jun 30, 2024
1 parent df47253 commit d8f7635
Show file tree
Hide file tree
Showing 27 changed files with 1,273 additions and 47 deletions.
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,10 @@
android:name=".app.onboarding.CreateProfileActivity"
android:label="@string/create_profile_activity_title"
android:theme="@style/OppiaThemeWithoutActionBar" />
<activity
android:name=".app.onboarding.IntroActivity"
android:label="@string/onboarding_learner_intro_activity_title"
android:theme="@style/OppiaThemeWithoutActionBar" />
<provider
android:name="androidx.work.impl.WorkManagerInitializer"
android:authorities="${applicationId}.workmanager-init"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import org.oppia.android.app.home.HomeActivity
import org.oppia.android.app.home.recentlyplayed.RecentlyPlayedActivity
import org.oppia.android.app.mydownloads.MyDownloadsActivity
import org.oppia.android.app.onboarding.CreateProfileActivity
import org.oppia.android.app.onboarding.IntroActivity
import org.oppia.android.app.onboarding.OnboardingActivity
import org.oppia.android.app.onboarding.OnboardingProfileTypeActivity
import org.oppia.android.app.ongoingtopiclist.OngoingTopicListActivity
Expand Down Expand Up @@ -224,4 +225,5 @@ interface ActivityComponentImpl :
fun inject(classroomListActivity: ClassroomListActivity)
fun inject(onboardingProfileTypeActivity: OnboardingProfileTypeActivity)
fun inject(createProfileActivity: CreateProfileActivity)
fun inject(introActivity: IntroActivity)
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import org.oppia.android.app.notice.GeneralAvailabilityUpgradeNoticeDialogFragme
import org.oppia.android.app.notice.OptionalAppDeprecationNoticeDialogFragment
import org.oppia.android.app.notice.OsDeprecationNoticeDialogFragment
import org.oppia.android.app.onboarding.CreateProfileFragment
import org.oppia.android.app.onboarding.IntroFragment
import org.oppia.android.app.onboarding.OnboardingFragment
import org.oppia.android.app.onboarding.OnboardingProfileTypeFragment
import org.oppia.android.app.ongoingtopiclist.OngoingTopicListFragment
Expand Down Expand Up @@ -200,4 +201,5 @@ interface FragmentComponentImpl : FragmentComponent, ViewComponentBuilderInjecto
fun inject(classroomListFragment: ClassroomListFragment)
fun inject(onboardingProfileTypeFragment: OnboardingProfileTypeFragment)
fun inject(createProfileFragment: CreateProfileFragment)
fun inject(introFragment: IntroFragment)
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,11 @@ class CreateProfileFragmentPresenter @Inject constructor(
val nickname = binding.createProfileNicknameEdittext.text.toString().trim()

createProfileViewModel.hasErrorMessage.set(nickname.isBlank())

if (createProfileViewModel.hasErrorMessage.get() != true) {
val intent = IntroActivity.createIntroActivity(activity, nickname)
fragment.startActivity(intent)
}
}

binding.createProfileNicknameEdittext.addTextChangedListener(object : TextWatcher {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.oppia.android.app.onboarding

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.IntroActivityParams
import org.oppia.android.app.model.ScreenName.INTRO_ACTIVITY
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 IntroActivity : InjectableAutoLocalizedAppCompatActivity() {
@Inject
lateinit var onboardingLearnerIntroActivityPresenter: IntroActivityPresenter

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 createIntroActivity(context: Context, profileNickname: String): Intent {
val params = IntroActivityParams.newBuilder()
.setProfileNickname(profileNickname)
.build()
return createOnboardingLearnerIntroActivity(context, params)
}

private fun createOnboardingLearnerIntroActivity(
context: Context,
params: IntroActivityParams
): Intent {
return Intent(context, IntroActivity::class.java).apply {
putProtoExtra(PARAMS_KEY, params)
decorateWithScreenName(INTRO_ACTIVITY)
}
}

private fun Intent.extractParams() =
getProtoExtra(PARAMS_KEY, IntroActivityParams.getDefaultInstance())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.oppia.android.app.onboarding

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.IntroActivityBinding
import javax.inject.Inject

private const val TAG_LEARNER_INTRO_FRAGMENT = "TAG_INTRO_FRAGMENT"

/** Argument key for bundling the profileId. */
const val PROFILE_NICKNAME_ARGUMENT_KEY = "profile_nickname"

/** The Presenter for [IntroActivity]. */
@ActivityScope
class IntroActivityPresenter @Inject constructor(
private val activity: AppCompatActivity
) {
private lateinit var binding: IntroActivityBinding

/** Handle creation and binding of the [IntroActivity] layout. */
fun handleOnCreate(profileNickname: String) {
binding = DataBindingUtil.setContentView(activity, R.layout.intro_activity)
binding.lifecycleOwner = activity

if (getIntroFragment() == null) {
val introFragment = IntroFragment()

val args = Bundle()
args.putString(PROFILE_NICKNAME_ARGUMENT_KEY, profileNickname)
introFragment.arguments = args

activity.supportFragmentManager.beginTransaction().add(
R.id.learner_intro_fragment_placeholder,
introFragment,
TAG_LEARNER_INTRO_FRAGMENT
)
.commitNow()
}
}

private fun getIntroFragment(): IntroFragment? {
return activity.supportFragmentManager.findFragmentByTag(
TAG_LEARNER_INTRO_FRAGMENT
) as? IntroFragment
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package org.oppia.android.app.onboarding

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 IntroFragment : InjectableFragment() {
@Inject
lateinit var introFragmentPresenter: IntroFragmentPresenter

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 =
checkNotNull(arguments?.getStringFromBundle(PROFILE_NICKNAME_ARGUMENT_KEY)) {
"Expected profileNickname to be included in the arguments for IntroFragment."
}
return introFragmentPresenter.handleCreateView(
inflater,
container,
profileNickname
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package org.oppia.android.app.onboarding

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.translation.AppLanguageResourceHandler
import org.oppia.android.databinding.LearnerIntroFragmentBinding
import javax.inject.Inject

/** The presenter for [IntroFragment]. */
class IntroFragmentPresenter @Inject constructor(
private var fragment: Fragment,
private val activity: AppCompatActivity,
private val appLanguageResourceHandler: AppLanguageResourceHandler,
) {
private lateinit var binding: LearnerIntroFragmentBinding

/** Handle creation and binding of the OnboardingLearnerIntroFragment layout. */
fun handleCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
profileNickname: String,
): View {
binding = LearnerIntroFragmentBinding.inflate(
inflater,
container,
/* attachToRoot= */ false
)
binding.lifecycleOwner = fragment

setLearnerName(profileNickname)

binding.onboardingNavigationBack.setOnClickListener {
activity.finish()
}

binding.onboardingLearnerIntroFeedback.text =
appLanguageResourceHandler.getStringInLocaleWithWrapping(
R.string.onboarding_learner_intro_feedback_text,
appLanguageResourceHandler.getStringInLocale(R.string.app_name)
)

return binding.root
}

private fun setLearnerName(profileName: String) {
binding.onboardingLearnerIntroTitle.text =
appLanguageResourceHandler.getStringInLocaleWithWrapping(
R.string.onboarding_learner_intro_activity_text, profileName
)
}
}
9 changes: 9 additions & 0 deletions app/src/main/res/drawable/ic_green_check.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="20dp"
android:height="20dp"
android:viewportWidth="20"
android:viewportHeight="20">
<path
android:pathData="M0,13.5385C0.1907,13.9557 0.5447,14.2878 0.8361,14.6375C1.32,15.2186 1.7995,15.8019 2.2679,16.396C2.8501,17.1343 3.6537,18.3712 4.1667,19.1616C4.3932,19.5105 4.4232,19.696 4.7823,19.9109C4.9976,20.0397 5.3221,19.9862 5.5614,19.9862H7.3671C7.5963,19.9862 7.9821,20.0594 8.1554,19.8687C8.4929,19.4973 8.6357,18.6971 8.8161,18.2277C9.1803,17.2804 9.6335,16.3627 10.061,15.4435C11.3427,12.6875 12.9254,10.0628 14.5898,7.5304C15.7954,5.696 17.1571,3.8561 18.7724,2.3716C19.2131,1.9667 20.3897,1.2326 19.87,0.5122C19.6045,0.1443 19.0427,0.0956 18.6344,0.0371C17.1884,-0.1701 15.7418,0.5127 14.7342,1.5226C12.207,4.0557 10.39,7.1461 8.5007,10.1681C7.9992,10.9704 7.5674,11.8236 7.1234,12.6593C6.9651,12.9573 6.7927,13.5016 6.485,13.6691C6.2234,13.8114 5.8627,13.6406 5.6337,13.5033C4.9993,13.1227 4.5233,12.5324 4.1086,11.9266C3.9712,11.7258 3.8034,11.3051 3.5324,11.2688C3.2105,11.2257 2.7761,11.6711 2.5279,11.8413C1.698,12.4104 0.8749,13.0444 0,13.5385Z"
android:fillColor="#00645C"/>
</vector>
96 changes: 96 additions & 0 deletions app/src/main/res/layout-land/learner_intro_fragment.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/component_color_onboarding_learner_intro_background_color">

<TextView
android:id="@+id/onboarding_learner_intro_title"
style="@style/OnboardingHeaderStyle"
android:layout_marginTop="@dimen/phone_shared_margin_large"
android:text="@string/onboarding_learner_intro_activity_text"
android:textColor="@color/component_color_onboarding_learner_intro_header_color"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/onboarding_learner_intro_classroom"
style="@style/OnboardingLearnerIntroBulletsStyle"
android:layout_marginTop="@dimen/phone_shared_margin_medium"
android:text="@string/onboarding_learner_intro_classroom_text"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintWidth_percent="0.7"
app:layout_constraintTop_toBottomOf="@id/onboarding_learner_intro_title" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/onboarding_learner_intro_practice"
style="@style/OnboardingLearnerIntroBulletsStyle"
android:layout_marginTop="@dimen/phone_shared_margin_small"
android:text="@string/onboarding_learner_intro_practice_text"
app:layout_constraintStart_toStartOf="@id/onboarding_learner_intro_classroom"
app:layout_constraintTop_toBottomOf="@id/onboarding_learner_intro_classroom" />

<com.google.android.material.textview.MaterialTextView
android:id="@+id/onboarding_learner_intro_feedback"
style="@style/OnboardingLearnerIntroBulletsStyle"
android:layout_marginTop="@dimen/phone_shared_margin_small"
android:text="@string/onboarding_learner_intro_feedback_text"
app:layout_constraintStart_toStartOf="@id/onboarding_learner_intro_classroom"
app:layout_constraintTop_toBottomOf="@id/onboarding_learner_intro_practice" />

<androidx.constraintlayout.widget.Guideline
android:id="@+id/learner_intro_center_guide"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.50" />

<org.oppia.android.app.customview.OppiaCurveBackgroundView
android:id="@+id/onboarding_learner_intro_background"
android:layout_width="match_parent"
android:layout_height="0dp"
app:customBackgroundColor="@{@color/component_color_onboarding_shared_white_color}"
app:layout_constraintTop_toBottomOf="@id/learner_intro_center_guide" />

<ImageView
android:id="@+id/learner_intro_otter_imageview"
android:layout_width="wrap_content"
android:layout_height="112dp"
android:layout_marginTop="@dimen/phone_shared_margin_xl"
android:contentDescription="@string/onboarding_otter_content_description"
app:layout_constraintEnd_toStartOf="@id/onboarding_navigation_continue"
app:layout_constraintStart_toEndOf="@id/onboarding_navigation_back"
app:layout_constraintTop_toBottomOf="@id/learner_intro_center_guide"
app:srcCompat="@drawable/otter" />

<Button
android:id="@+id/onboarding_navigation_back"
style="@style/OnboardingNavigationSecondaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/onboarding_navigation_back"
android:layout_marginStart="@dimen/phone_shared_margin_medium"
android:layout_marginBottom="@dimen/phone_shared_margin_medium"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/onboarding_navigation_continue"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintStart_toStartOf="parent" />

<Button
android:id="@+id/onboarding_navigation_continue"
style="@style/OnboardingNavigationPrimaryButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/onboarding_navigation_continue"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="@dimen/phone_shared_margin_medium"
android:layout_marginBottom="@dimen/phone_shared_margin_medium"
app:layout_constraintStart_toEndOf="@id/onboarding_navigation_back" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Loading

0 comments on commit d8f7635

Please sign in to comment.