From 2c7b33f1c76cd70e9e6e68dfb3c0877e19b5c1c5 Mon Sep 17 00:00:00 2001 From: Adhiambo Peres <59600948+adhiamboperes@users.noreply.github.com> Date: Thu, 1 Aug 2024 16:47:53 +0300 Subject: [PATCH] Add landscape carousel --- app/BUILD.bazel | 2 + .../app/fragment/FragmentComponentImpl.kt | 4 +- .../android/app/profile/AddProfileListener.kt | 7 - .../app/profile/ProfileChooserFragment.kt | 7 +- .../ProfileChooserFragmentPresenter.kt | 98 ++++++- .../ProfileChooserFragmentPresenterV1.kt | 4 +- .../app/profile/ProfileChooserViewModel.kt | 11 +- .../app/profile/ProfileClickListener.kt | 9 + .../app/profile/ProfileItemViewModel.kt | 13 +- .../android/app/profile/ProfileListView.kt | 89 +++++++ .../oppia/android/app/shim/ViewBindingShim.kt | 17 ++ .../android/app/shim/ViewBindingShimImpl.kt | 20 ++ .../android/app/view/ViewComponentImpl.kt | 2 + app/src/main/res/drawable/ic_chevron_left.xml | 5 + .../main/res/drawable/ic_chevron_right.xml | 5 + app/src/main/res/layout-land/profile_item.xml | 90 +++++++ .../profile_selection_fragment.xml | 145 +++++++++++ app/src/main/res/layout/profile_item.xml | 123 +++++---- .../res/layout/profile_selection_fragment.xml | 5 +- .../main/res/values-sw600dp-port/dimens.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- .../app/profile/ProfileChooserFragmentTest.kt | 240 +++++++++++------- .../assets/kdoc_validity_exemptions.textproto | 1 - scripts/assets/test_file_exemptions.textproto | 6 +- 24 files changed, 703 insertions(+), 204 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt create mode 100644 app/src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt create mode 100644 app/src/main/java/org/oppia/android/app/profile/ProfileListView.kt create mode 100644 app/src/main/res/drawable/ic_chevron_left.xml create mode 100644 app/src/main/res/drawable/ic_chevron_right.xml create mode 100644 app/src/main/res/layout-land/profile_item.xml create mode 100644 app/src/main/res/layout-land/profile_selection_fragment.xml diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 35036cf44fa..783a79f486e 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -146,6 +146,7 @@ LISTENERS = [ "src/main/java/org/oppia/android/app/player/state/listener/StateKeyboardButtonListener.kt", "src/main/java/org/oppia/android/app/player/state/listener/SubmitNavigationButtonListener.kt", "src/main/java/org/oppia/android/app/policies/RouteToPoliciesListener.kt", + "src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt", "src/main/java/org/oppia/android/app/profile/RouteToAdminPinListener.kt", "src/main/java/org/oppia/android/app/profileprogress/ProfilePictureClickListener.kt", "src/main/java/org/oppia/android/app/profileprogress/RouteToCompletedStoryListListener.kt", @@ -413,6 +414,7 @@ VIEWS_WITH_RESOURCE_IMPORTS = [ "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/VerticalDashedLineView.kt", + "src/main/java/org/oppia/android/app/profile/ProfileListView.kt", "src/main/java/org/oppia/android/app/survey/SurveyMultipleChoiceOptionView.kt", "src/main/java/org/oppia/android/app/survey/SurveyNpsItemOptionView.kt", "src/main/java/org/oppia/android/app/utility/ClickableAreasImage.kt", diff --git a/app/src/main/java/org/oppia/android/app/fragment/FragmentComponentImpl.kt b/app/src/main/java/org/oppia/android/app/fragment/FragmentComponentImpl.kt index 9a861937346..e67886ea54f 100644 --- a/app/src/main/java/org/oppia/android/app/fragment/FragmentComponentImpl.kt +++ b/app/src/main/java/org/oppia/android/app/fragment/FragmentComponentImpl.kt @@ -58,7 +58,7 @@ import org.oppia.android.app.player.stopplaying.StopExplorationDialogFragment import org.oppia.android.app.player.stopplaying.UnsavedExplorationDialogFragment import org.oppia.android.app.policies.PoliciesFragment import org.oppia.android.app.profile.AdminSettingsDialogFragment -import org.oppia.android.app.profile.ProfileChooserFragment +import org.oppia.android.app.profile.ProfileActionChooserFragment import org.oppia.android.app.profile.ResetPinDialogFragment import org.oppia.android.app.profileprogress.ProfilePictureEditDialogFragment import org.oppia.android.app.profileprogress.ProfileProgressFragment @@ -162,7 +162,7 @@ interface FragmentComponentImpl : FragmentComponent, ViewComponentBuilderInjecto fun inject(osDeprecationNoticeDialogFragment: OsDeprecationNoticeDialogFragment) fun inject(policiesFragment: PoliciesFragment) fun inject(profileAndDeviceIdFragment: ProfileAndDeviceIdFragment) - fun inject(profileChooserFragment: ProfileChooserFragment) + fun inject(profileChooserFragment: ProfileActionChooserFragment) fun inject(profileEditDeletionDialogFragment: ProfileEditDeletionDialogFragment) fun inject(profileEditFragment: ProfileEditFragment) fun inject(profileListFragment: ProfileListFragment) diff --git a/app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt b/app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt deleted file mode 100644 index aa343295e69..00000000000 --- a/app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.oppia.android.app.profile - -/** Listener for when an activity should route to the [AddProfileActivity]. */ -interface AddProfileListener { - /** Triggered when the add profile button is clicked. */ - fun onAddProfileClicked() -} diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragment.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragment.kt index aded1b6073a..624b0f40e49 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragment.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragment.kt @@ -7,12 +7,13 @@ 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.app.model.Profile import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject /** Fragment that allows user to select a profile or create new ones. */ -class ProfileChooserFragment : InjectableFragment(), RouteToAdminPinListener, AddProfileListener { +class ProfileChooserFragment : InjectableFragment(), RouteToAdminPinListener, ProfileClickListener { @Inject lateinit var profileChooserFragmentPresenterV1: ProfileChooserFragmentPresenterV1 @@ -48,7 +49,7 @@ class ProfileChooserFragment : InjectableFragment(), RouteToAdminPinListener, Ad } } - override fun onAddProfileClicked() { - profileChooserFragmentPresenter.addProfileClickListener() + override fun onProfileClicked(profile: Profile) { + profileChooserFragmentPresenter.onProfileClick(profile) } } diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt index 0f15edfe6d9..41bf28fa95a 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenter.kt @@ -1,6 +1,8 @@ package org.oppia.android.app.profile import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -11,6 +13,8 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.administratorcontrols.AdministratorControlsActivity import org.oppia.android.app.classroom.ClassroomListActivity @@ -21,6 +25,7 @@ import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.onboarding.IntroActivity import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.databinding.ProfileItemBinding import org.oppia.android.databinding.ProfileSelectionFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger @@ -83,24 +88,86 @@ class ProfileChooserFragmentPresenter @Inject constructor( StatusBarColor.statusBarColorUpdate( R.color.component_color_shared_profile_status_bar_color, activity, false ) - binding = ProfileSelectionFragmentBinding.inflate( - inflater, - container, - /* attachToRoot= */ false - ) - binding.apply { + + binding = ProfileSelectionFragmentBinding.inflate(inflater, container, false).apply { viewModel = chooserViewModel lifecycleOwner = fragment } + logProfileChooserEvent() - binding.profilesList.isNestedScrollingEnabled = false subscribeToWasProfileEverBeenAdded() - binding.profilesList.apply { - adapter = createRecyclerViewAdapter() + + binding.apply { + when (Resources.getSystem().configuration.orientation) { + Configuration.ORIENTATION_PORTRAIT -> setupPortraitMode() + Configuration.ORIENTATION_LANDSCAPE -> setupLandscapeMode() + } } + + binding.addProfileButton.setOnClickListener { addProfileButtonClickListener() } + binding.addProfilePrompt.setOnClickListener { addProfileButtonClickListener() } + return binding.root } + private fun ProfileSelectionFragmentBinding.setupPortraitMode() { + profilesList?.apply { + isNestedScrollingEnabled = false + adapter = createRecyclerViewAdapter() + } + } + + private fun ProfileSelectionFragmentBinding.setupLandscapeMode() { + val snapHelper = StartSnapHelper() + val layoutManager = profilesListLandscape?.layoutManager as LinearLayoutManager? + + profilesListLandscape?.onFlingListener = null + + profilesListLandscape?.viewTreeObserver?.addOnGlobalLayoutListener { + if (profilesListLandscape.shouldShowScrollArrows()) { + profileScrollLeft?.visibility = View.VISIBLE + profileScrollRight?.visibility = View.VISIBLE + } else { + profileScrollLeft?.visibility = View.GONE + profileScrollRight?.visibility = View.GONE + } + } + + profileScrollLeft?.setOnClickListener { + snapRecyclerView(layoutManager, snapHelper, true) + } + + profileScrollRight?.setOnClickListener { + snapRecyclerView(layoutManager, snapHelper, false) + } + } + + private fun RecyclerView.shouldShowScrollArrows(): Boolean { + val layoutManager = this.layoutManager as? LinearLayoutManager ?: return false + + val visibleItemCount = layoutManager.childCount + val totalItemCount = this.adapter?.itemCount + return totalItemCount != null && totalItemCount > visibleItemCount + } + + private fun snapRecyclerView( + layoutManager: LinearLayoutManager?, + snapHelper: StartSnapHelper, + isLeft: Boolean + ) { + val newLayoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) + + val targetView = snapHelper.findSnapView(layoutManager ?: newLayoutManager) + targetView?.let { + val distance = snapHelper.calculateDistanceToFinalSnap(layoutManager ?: newLayoutManager, it) + val scrollDistance = distance?.get(0) ?: 0 + val width = binding.profilesListLandscape?.width ?: 0 + + val offset = if (isLeft) scrollDistance - width else width - scrollDistance + binding.profilesListLandscape?.smoothScrollBy(offset, 0) + } + } + private fun subscribeToWasProfileEverBeenAdded() { wasProfileEverBeenAdded.observe( activity, @@ -112,7 +179,7 @@ class ProfileChooserFragmentPresenter @Inject constructor( activity.resources.getInteger(R.integer.profile_chooser_first_time_span_count) } val layoutManager = GridLayoutManager(activity, spanCount) - binding.profilesList.layoutManager = layoutManager + binding.profilesList?.layoutManager = layoutManager } ) } @@ -163,13 +230,16 @@ class ProfileChooserFragmentPresenter @Inject constructor( ) { binding.viewModel = viewModel binding.profileItemContainer.setOnClickListener { - updateLearnerIdIfAbsent(viewModel.profile) - ensureProfileOnboarded(viewModel.profile) } } - /** Click listener for the button to add a new profile. */ - fun addProfileClickListener() { + /** Click listener for handling clicks to login to a profile. */ + fun onProfileClick(profile: Profile) { + updateLearnerIdIfAbsent(profile) + ensureProfileOnboarded(profile) + } + + private fun addProfileButtonClickListener() { if (chooserViewModel.adminPin.isEmpty()) { activity.startActivity( AdminPinActivity.createAdminPinActivityIntent( diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt index 61da6c80a18..9e8be8adb45 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserFragmentPresenterV1.kt @@ -61,7 +61,7 @@ private val COLORS_LIST = listOf( R.color.component_color_avatar_background_24_color ) -/** The presenter for [ProfileChooserFragment]. */ +/** The presenter for [ProfileActionChooserFragment]. */ @FragmentScope class ProfileChooserFragmentPresenterV1 @Inject constructor( private val fragment: Fragment, @@ -130,7 +130,7 @@ class ProfileChooserFragmentPresenterV1 @Inject constructor( return when (wasProfileEverBeenAddedResult) { is AsyncResult.Failure -> { oppiaLogger.e( - "ProfileChooserFragment", + "ProfileActionChooserFragment", "Failed to retrieve the information on wasProfileEverBeenAdded", wasProfileEverBeenAddedResult.error ) diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserViewModel.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserViewModel.kt index 7c748e1b5e7..c9914357b00 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserViewModel.kt @@ -19,7 +19,7 @@ import org.oppia.android.util.platformparameter.EnableOnboardingFlowV2 import org.oppia.android.util.platformparameter.PlatformParameterValue import javax.inject.Inject -/** The ViewModel for [ProfileChooserFragment]. */ +/** The ViewModel for [ProfileActionChooserFragment]. */ @FragmentScope class ProfileChooserViewModel @Inject constructor( fragment: Fragment, @@ -30,7 +30,7 @@ class ProfileChooserViewModel @Inject constructor( ) : ObservableViewModel() { private val routeToAdminPinListener = fragment as RouteToAdminPinListener - private val addProfileListener = fragment as AddProfileListener + private val profileClickListener = fragment as ProfileClickListener /** Observable field to track if the add profile button should be shown. */ val canAddProfile = ObservableField(true) @@ -62,7 +62,7 @@ class ProfileChooserViewModel @Inject constructor( is AsyncResult.Pending -> emptyList() is AsyncResult.Success -> profilesResult.value }.map { - ProfileItemViewModel(it) + ProfileItemViewModel(it, profileClickListener::onProfileClicked) } profileList.forEach { profileItemViewModel -> @@ -144,9 +144,4 @@ class ProfileChooserViewModel @Inject constructor( fun onAdministratorControlsButtonClicked() { routeToAdminPinListener.routeToAdminPin() } - - /** Handles click events for the add profile button. */ - fun onAddProfileButtonClicked() { - addProfileListener.onAddProfileClicked() - } } diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt new file mode 100644 index 00000000000..9c0f76583f3 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt @@ -0,0 +1,9 @@ +package org.oppia.android.app.profile + +import org.oppia.android.app.model.Profile + +/** Listener for when a profile is clicked. */ +interface ProfileClickListener { + /** Triggered when the profile is clicked. */ + fun onProfileClicked(profile: Profile) +} diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileItemViewModel.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileItemViewModel.kt index b0132180cde..79e98c77238 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileItemViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileItemViewModel.kt @@ -3,4 +3,15 @@ package org.oppia.android.app.profile import org.oppia.android.app.model.Profile import org.oppia.android.app.viewmodel.ObservableViewModel -class ProfileItemViewModel(val profile: Profile) : ObservableViewModel() +/** ViewModel for binding a profile data to the UI. */ +class ProfileItemViewModel( + val profile: Profile, + val onProfileClicked: (Profile) -> Unit +) : ObservableViewModel() { + + /** Called when a profile is clicked. */ + // todo maybe remove + fun profileClicked() { + onProfileClicked(profile) + } +} diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileListView.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileListView.kt new file mode 100644 index 00000000000..6782b2ec5de --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileListView.kt @@ -0,0 +1,89 @@ +package org.oppia.android.app.profile + +import android.content.Context +import android.util.AttributeSet +import android.view.LayoutInflater +import androidx.fragment.app.Fragment +import androidx.fragment.app.FragmentManager +import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.shim.ViewBindingShim +import org.oppia.android.app.view.ViewComponentFactory +import org.oppia.android.app.view.ViewComponentImpl +import javax.inject.Inject + +/** A custom [RecyclerView] for displaying a list of profiles as a carousel. */ +class ProfileListView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RecyclerView(context, attrs, defStyleAttr) { + + @Inject + lateinit var bindingInterface: ViewBindingShim + + @Inject + lateinit var singleTypeBuilderFactory: BindableAdapter.SingleTypeBuilder.Factory + + private lateinit var profileDataList: List + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + val viewComponentFactory = FragmentManager.findFragment(this) as ViewComponentFactory + val viewComponent = viewComponentFactory.createViewComponent(this) as ViewComponentImpl + viewComponent.inject(this) + maybeInitializeAdapter() + } + + private fun maybeInitializeAdapter() { + if (::bindingInterface.isInitialized && + ::singleTypeBuilderFactory.isInitialized && + ::profileDataList.isInitialized + ) { + bindDataToAdapter() + } + } + + private fun bindDataToAdapter() { + // We manually set the data so we can first check for the adapter unlike when using an existing + // [RecyclerViewBindingAdapter]. + // This ensures that the adapter will only be created once and correctly rebinds the data. + // For more context: https://github.com/oppia/oppia-android/pull/2246#pullrequestreview-565964462 + if (adapter == null) { + adapter = createAdapter() + } + + (adapter as BindableAdapter<*>).setDataUnchecked(profileDataList) + } + + private fun createAdapter(): BindableAdapter { + return singleTypeBuilderFactory.create() + .registerViewBinder( + inflateView = { parent -> + bindingInterface.provideProfileItemInflatedView( + LayoutInflater.from(parent.context), + parent, + attachToParent = false + ) + }, + bindView = { view, viewModel -> + bindingInterface.provideProfileItemViewModel( + view, + viewModel + ) + } + ).build() + } + + /** + * Sets the list of profiles that this view shows. + * @param newDataList the new list of profiles to present + */ + + fun setProfileList(newDataList: List?) { + if (newDataList != null) { + profileDataList = newDataList + maybeInitializeAdapter() + } + } +} diff --git a/app/src/main/java/org/oppia/android/app/shim/ViewBindingShim.kt b/app/src/main/java/org/oppia/android/app/shim/ViewBindingShim.kt index acc6efcec4a..e3b5282d6c0 100644 --- a/app/src/main/java/org/oppia/android/app/shim/ViewBindingShim.kt +++ b/app/src/main/java/org/oppia/android/app/shim/ViewBindingShim.kt @@ -12,6 +12,7 @@ import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.model.WrittenTranslationContext import org.oppia.android.app.player.state.itemviewmodel.DragDropInteractionContentViewModel import org.oppia.android.app.player.state.itemviewmodel.SelectionInteractionContentViewModel +import org.oppia.android.app.profile.ProfileItemViewModel import org.oppia.android.app.survey.surveyitemviewmodel.MultipleChoiceOptionContentViewModel import org.oppia.android.util.parser.html.HtmlParser @@ -206,4 +207,20 @@ interface ViewBindingShim { view: View, viewModel: MultipleChoiceOptionContentViewModel ) + + /** Handles binding inflation for [org.oppia.android.app.profile.ProfileListView]. */ + fun provideProfileItemInflatedView( + inflater: LayoutInflater, + parent: ViewGroup, + attachToParent: Boolean + ): View + + /** + * Handles binding inflation for [org.oppia.android.app.profile.ProfileListView] + * and returns the view model. + */ + fun provideProfileItemViewModel( + view: View, + viewModel: ProfileItemViewModel + ) } diff --git a/app/src/main/java/org/oppia/android/app/shim/ViewBindingShimImpl.kt b/app/src/main/java/org/oppia/android/app/shim/ViewBindingShimImpl.kt index 69b49ac4eea..1415930c720 100644 --- a/app/src/main/java/org/oppia/android/app/shim/ViewBindingShimImpl.kt +++ b/app/src/main/java/org/oppia/android/app/shim/ViewBindingShimImpl.kt @@ -14,6 +14,7 @@ import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.model.WrittenTranslationContext import org.oppia.android.app.player.state.itemviewmodel.DragDropInteractionContentViewModel import org.oppia.android.app.player.state.itemviewmodel.SelectionInteractionContentViewModel +import org.oppia.android.app.profile.ProfileItemViewModel import org.oppia.android.app.survey.surveyitemviewmodel.MultipleChoiceOptionContentViewModel import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.databinding.ComingSoonTopicViewBinding @@ -21,6 +22,7 @@ import org.oppia.android.databinding.DragDropInteractionItemsBinding import org.oppia.android.databinding.DragDropSingleItemBinding import org.oppia.android.databinding.ItemSelectionInteractionItemsBinding import org.oppia.android.databinding.MultipleChoiceInteractionItemsBinding +import org.oppia.android.databinding.ProfileItemBinding import org.oppia.android.databinding.PromotedStoryCardBinding import org.oppia.android.databinding.SurveyMultipleChoiceItemBinding import org.oppia.android.databinding.SurveyNpsItemBinding @@ -195,6 +197,24 @@ class ViewBindingShimImpl @Inject constructor( binding.viewModel = viewModel } + override fun provideProfileItemInflatedView( + inflater: LayoutInflater, + parent: ViewGroup, + attachToParent: Boolean + ): View { + return ProfileItemBinding.inflate( + LayoutInflater.from(parent.context), + parent, + false + ).root + } + + override fun provideProfileItemViewModel(view: View, viewModel: ProfileItemViewModel) { + val binding = + DataBindingUtil.findBinding(view)!! + binding.viewModel = viewModel + } + override fun provideDragDropSortInteractionInflatedView( inflater: LayoutInflater, parent: ViewGroup, 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 dc71fc0e90a..74a5afe2e1f 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 @@ -14,6 +14,7 @@ import org.oppia.android.app.home.promotedlist.PromotedStoryListView import org.oppia.android.app.player.state.DragDropSortInteractionView import org.oppia.android.app.player.state.ImageRegionSelectionInteractionView import org.oppia.android.app.player.state.SelectionInteractionView +import org.oppia.android.app.profile.ProfileListView import org.oppia.android.app.survey.SurveyMultipleChoiceOptionView import org.oppia.android.app.survey.SurveyNpsItemOptionView @@ -45,4 +46,5 @@ interface ViewComponentImpl : ViewComponent { fun inject(oppiaCurveBackgroundView: OppiaCurveBackgroundView) fun inject(surveyMultipleChoiceOptionView: SurveyMultipleChoiceOptionView) fun inject(surveyNpsItemOptionView: SurveyNpsItemOptionView) + fun inject(profileListView: ProfileListView) } diff --git a/app/src/main/res/drawable/ic_chevron_left.xml b/app/src/main/res/drawable/ic_chevron_left.xml new file mode 100644 index 00000000000..3f7812863b3 --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_left.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_chevron_right.xml b/app/src/main/res/drawable/ic_chevron_right.xml new file mode 100644 index 00000000000..54aa85c0a3f --- /dev/null +++ b/app/src/main/res/drawable/ic_chevron_right.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/layout-land/profile_item.xml b/app/src/main/res/layout-land/profile_item.xml new file mode 100644 index 00000000000..71c7dea871b --- /dev/null +++ b/app/src/main/res/layout-land/profile_item.xml @@ -0,0 +1,90 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-land/profile_selection_fragment.xml b/app/src/main/res/layout-land/profile_selection_fragment.xml new file mode 100644 index 00000000000..8611641cdaa --- /dev/null +++ b/app/src/main/res/layout-land/profile_selection_fragment.xml @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/profile_item.xml b/app/src/main/res/layout/profile_item.xml index d77c585afa7..ef92841475e 100644 --- a/app/src/main/res/layout/profile_item.xml +++ b/app/src/main/res/layout/profile_item.xml @@ -6,79 +6,74 @@ - - - - - + android:layout_marginStart="@dimen/profile_chooser_profile_view_margin_start_profile_already_added" + android:layout_marginTop="@dimen/space_0dp" + android:layout_marginEnd="@dimen/profile_chooser_profile_view_margin_end_profile_already_added" + android:layout_marginBottom="@dimen/profile_view_already_added_margin" + android:clickable="true" + android:onClick="@{(v) -> viewModel.profileClicked()}" + android:orientation="vertical" + android:paddingStart="8dp" + android:paddingEnd="8dp"> - + - + - + - - - + + diff --git a/app/src/main/res/layout/profile_selection_fragment.xml b/app/src/main/res/layout/profile_selection_fragment.xml index a34a2cf21e6..668f06bc555 100644 --- a/app/src/main/res/layout/profile_selection_fragment.xml +++ b/app/src/main/res/layout/profile_selection_fragment.xml @@ -49,7 +49,7 @@ @@ -106,7 +105,6 @@ android:layout_height="48dp" android:layout_marginBottom="4dp" android:contentDescription="@string/profile_selection_profile_icon_description" - android:onClick="@{(v) -> viewModel.onAddProfileButtonClicked()}" android:paddingStart="4dp" android:paddingEnd="4dp" android:layout_marginEnd="12dp" @@ -127,7 +125,6 @@ android:fontFamily="sans-serif-medium" android:gravity="center" android:minHeight="48dp" - android:onClick="@{(v) -> viewModel.onAddProfileButtonClicked()}" android:text="@string/profile_selection_add_profile_text" android:textColor="@color/component_color_shared_primary_text_color" android:textSize="14sp" diff --git a/app/src/main/res/values-sw600dp-port/dimens.xml b/app/src/main/res/values-sw600dp-port/dimens.xml index d2c15feccbc..a6f002bc639 100644 --- a/app/src/main/res/values-sw600dp-port/dimens.xml +++ b/app/src/main/res/values-sw600dp-port/dimens.xml @@ -509,7 +509,7 @@ 64dp 4dp - + 64dp 24dp 124dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ab3aea2cdf..39ed09d783f 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -216,7 +216,7 @@ %s Topics in Progress \u0020|\u0020 - + Profile selection page Administrator Select your profile diff --git a/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserFragmentTest.kt index 345c4011f2e..a1460b3f573 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserFragmentTest.kt @@ -175,44 +175,50 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_initializeProfiles_checkProfilesAreShown() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(ProfileChooserActivity::class.java).use { testCoroutineDispatchers.runCurrent() - scrollToPositionV1(position = 0) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 0, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_name_text, - stringToMatch = "Admin" + stringToMatch = "Admin", + recyclerViewId = R.id.profile_recycler_view, ) - verifyTextOnProfileListItemAtPositionV1( + verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_is_admin_text, - stringToMatch = context.getString(R.string.profile_chooser_admin) + stringToMatch = context.getString(R.string.profile_chooser_admin), + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 1) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 1, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 1, targetView = R.id.profile_name_text, - stringToMatch = "Ben" + stringToMatch = "Ben", + recyclerViewId = R.id.profile_recycler_view ) onView( atPositionOnView( recyclerViewId = R.id.profile_recycler_view, position = 1, - targetViewId = R.id.profile_is_admin_text + targetViewId = R.id.profile_is_admin_text, ) ).check(matches(not(isDisplayed()))) - scrollToPositionV1(position = 3) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 3, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 4, targetView = R.id.add_profile_text, - stringToMatch = context.getString(R.string.profile_chooser_add) + stringToMatch = context.getString(R.string.profile_chooser_add), + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_afterVisitingHomeActivity_showsJustNowText() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) // Note that the auto-log in here is simulating HomeActivity having been visited before (i.e. // that a profile was previously logged in). profileTestHelper.initializeProfiles(autoLogIn = true) @@ -225,16 +231,18 @@ class ProfileChooserFragmentTest { targetViewId = R.id.profile_last_visited ) ).check(matches(isDisplayed())) - verifyTextOnProfileListItemAtPositionV1( + verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_last_visited, - stringToMatch = "${context.getString(R.string.profile_last_used)} just now" + stringToMatch = "${context.getString(R.string.profile_last_used)} just now", + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_afterVisitingHomeActivity_changeConfiguration_showsJustNowText() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) // Note that the auto-log in here is simulating HomeActivity having been visited before (i.e. // that a profile was previously logged in). profileTestHelper.initializeProfiles(autoLogIn = true) @@ -248,85 +256,98 @@ class ProfileChooserFragmentTest { targetViewId = R.id.profile_last_visited ) ).check(matches(isDisplayed())) - verifyTextOnProfileListItemAtPositionV1( + verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_last_visited, - stringToMatch = "${context.getString(R.string.profile_last_used)} just now" + stringToMatch = "${context.getString(R.string.profile_last_used)} just now", + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_addManyProfiles_checkProfilesSortedAndNoAddProfile() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) profileTestHelper.addMoreProfiles(8) launch(ProfileChooserActivity::class.java).use { testCoroutineDispatchers.runCurrent() - scrollToPositionV1(position = 0) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 0, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_name_text, - stringToMatch = "Admin" + stringToMatch = "Admin", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 1) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 1, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 1, targetView = R.id.profile_name_text, - stringToMatch = "A" + stringToMatch = "A", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 2) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 2, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 2, targetView = R.id.profile_name_text, - stringToMatch = "B" + stringToMatch = "B", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 3) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 3, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 3, targetView = R.id.profile_name_text, - stringToMatch = "Ben" + stringToMatch = "Ben", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 4) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 4, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 4, targetView = R.id.profile_name_text, - stringToMatch = "C" + stringToMatch = "C", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 5) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 5, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 5, targetView = R.id.profile_name_text, - stringToMatch = "D" + stringToMatch = "D", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 6) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 6, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 6, targetView = R.id.profile_name_text, - stringToMatch = "E" + stringToMatch = "E", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 7) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 7, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 7, targetView = R.id.profile_name_text, - stringToMatch = "F" + stringToMatch = "F", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 8) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 8, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 8, targetView = R.id.profile_name_text, - stringToMatch = "G" + stringToMatch = "G", + recyclerViewId = R.id.profile_recycler_view ) - scrollToPositionV1(position = 9) - verifyTextOnProfileListItemAtPositionV1( + scrollToPosition(position = 9, recyclerViewId = R.id.profile_recycler_view) + verifyTextOnProfileListItemAtPosition( itemPosition = 9, targetView = R.id.profile_name_text, - stringToMatch = "H" + stringToMatch = "H", + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_clickProfile_checkOpensPinPasswordActivity() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(ProfileChooserActivity::class.java).use { testCoroutineDispatchers.runCurrent() @@ -418,14 +439,8 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_clickAdminProfileWithNoPin_checkOpensAdminPinActivity() { - profileManagementController.addProfile( - name = "Admin", - pin = "", - avatarImagePath = null, - allowDownloadAccess = true, - colorRgb = -10710042, - isAdmin = true - ) + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) + profileTestHelper.addOnlyAdminProfileWithoutPin() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() onView( @@ -442,14 +457,8 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_clickAdminControlsWithNoPin_checkOpensAdminControlsActivity() { - profileManagementController.addProfile( - name = "Admin", - pin = "", - avatarImagePath = null, - allowDownloadAccess = true, - colorRgb = -10710042, - isAdmin = true - ) + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) + profileTestHelper.addOnlyAdminProfileWithoutPin() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.administrator_controls_linear_layout)).perform(click()) @@ -464,6 +473,7 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_checkLayoutManager_isLinearLayoutManager() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.addOnlyAdminProfile() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -480,19 +490,22 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_onlyAdminProfile_checkText_setUpMultipleProfilesIsVisible() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.addOnlyAdminProfile() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() - verifyTextOnProfileListItemAtPositionV1( + verifyTextOnProfileListItemAtPosition( itemPosition = 1, targetView = R.id.add_profile_text, - stringToMatch = context.getString(R.string.set_up_multiple_profiles) + stringToMatch = context.getString(R.string.set_up_multiple_profiles), + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_onlyAdminProfile_checkDescriptionText_isDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.addOnlyAdminProfile() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -508,19 +521,22 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_multipleProfiles_checkText_addProfileIsVisible() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() - verifyTextOnProfileListItemAtPositionV1( + verifyTextOnProfileListItemAtPosition( itemPosition = 4, targetView = R.id.add_profile_text, - stringToMatch = context.getString(R.string.profile_chooser_add) + stringToMatch = context.getString(R.string.profile_chooser_add), + recyclerViewId = R.id.profile_recycler_view ) } } @Test fun testProfileChooserFragment_multipleProfiles_checkDescriptionText_isDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -536,6 +552,7 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_clickAdminControls_opensAdminAuthActivity() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -547,6 +564,7 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_clickAddProfile_opensAdminAuthActivity() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.initializeProfiles(autoLogIn = false) launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -563,6 +581,7 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_clickProfile_opensHomeActivity() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) profileTestHelper.addOnlyAdminProfileWithoutPin() launch(createProfileChooserActivityIntent()).use { testCoroutineDispatchers.runCurrent() @@ -582,6 +601,7 @@ class ProfileChooserFragmentTest { @Test fun testProfileChooserFragment_enableClassrooms_clickProfile_opensClassroomListActivity() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(false) TestPlatformParameterModule.forceEnableMultipleClassrooms(true) profileTestHelper.addOnlyAdminProfileWithoutPin() launch(createProfileChooserActivityIntent()).use { @@ -600,6 +620,56 @@ class ProfileChooserFragmentTest { } } + @Test + fun testFragment_enableOnboardingV2_checkAddProfileTextIsDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) + profileTestHelper.initializeProfiles() + launch(ProfileChooserActivity::class.java).use { + testCoroutineDispatchers.runCurrent() + onView(withText(R.string.profile_selection_add_profile_text)).check(matches(isDisplayed())) + } + } + + @Test + fun testFragment_enableOnboardingV2_configChange_checkAddProfileTextIsDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) + profileTestHelper.initializeProfiles() + launch(ProfileChooserActivity::class.java).use { + testCoroutineDispatchers.runCurrent() + orientationLandscape() + testCoroutineDispatchers.runCurrent() + onView(withText(R.string.profile_selection_add_profile_text)).check(matches(isDisplayed())) + } + } + + @Test + fun testFragment_enableOnboardingV2_landscape_checkAScrollArrowsAreDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) + profileTestHelper.addOnlyAdminProfile() + profileTestHelper.addMoreProfiles(8) + launch(ProfileChooserActivity::class.java).use { + testCoroutineDispatchers.runCurrent() + orientationLandscape() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.profile_scroll_left)).check(matches(isDisplayed())) + onView(withId(R.id.profile_scroll_right)).check(matches(isDisplayed())) + } + } + + @Test + fun testFragment_enableOnboardingV2_landscape_shortList_checkScrollArrowsAreNotDisplayed() { + TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) + profileTestHelper.addOnlyAdminProfile() + profileTestHelper.addMoreProfiles(2) + launch(ProfileChooserActivity::class.java).use { + testCoroutineDispatchers.runCurrent() + orientationLandscape() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.profile_scroll_left)).check(matches(not(isDisplayed()))) + onView(withId(R.id.profile_scroll_right)).check(matches(not(isDisplayed()))) + } + } + @Test fun testProfileChooserFragment_enableOnboardingV2_clickAddProfileButton_opensAdminAuthActivity() { TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) @@ -682,7 +752,7 @@ class ProfileChooserFragmentTest { onView(isRoot()).perform(orientationLandscape()) onView( atPositionOnView( - recyclerViewId = R.id.profiles_list, + recyclerViewId = R.id.profiles_list_landscape, position = 0, targetViewId = R.id.profile_last_visited ) @@ -690,7 +760,8 @@ class ProfileChooserFragmentTest { verifyTextOnProfileListItemAtPosition( itemPosition = 0, targetView = R.id.profile_last_visited, - stringToMatch = "${context.getString(R.string.profile_last_used)} just now" + stringToMatch = "${context.getString(R.string.profile_last_used)} just now", + recyclerViewId = R.id.profiles_list_landscape, ) } } @@ -766,7 +837,7 @@ class ProfileChooserFragmentTest { } @Test - fun testProfileChooserFragment_enableOnboardingV2_clickProfile_checkOpensPinPasswordActivity() { + fun testFragment_enableOnboardingV2_clickProfileWithPin_checkOpensPinPasswordActivity() { TestPlatformParameterModule.forceEnableOnboardingFlowV2(true) profileTestHelper.addOnlyAdminProfile() launch(ProfileChooserActivity::class.java).use { @@ -781,22 +852,15 @@ class ProfileChooserFragmentTest { } } - private fun scrollToPosition(position: Int) { - onView(withId(R.id.profiles_list)).perform( - scrollToPosition( - position - ) - ) - } - private fun verifyTextOnProfileListItemAtPosition( itemPosition: Int, targetView: Int, - stringToMatch: String + stringToMatch: String, + recyclerViewId: Int = R.id.profiles_list ) { onView( atPositionOnView( - recyclerViewId = R.id.profiles_list, + recyclerViewId = recyclerViewId, position = itemPosition, targetViewId = targetView ) @@ -808,28 +872,14 @@ class ProfileChooserFragmentTest { .createProfileChooserActivity(ApplicationProvider.getApplicationContext()) } - private fun scrollToPositionV1(position: Int) { - onView(withId(R.id.profile_recycler_view)).perform( + private fun scrollToPosition(recyclerViewId: Int = R.id.profiles_list, position: Int) { + onView(withId(recyclerViewId)).perform( scrollToPosition( position ) ) } - private fun verifyTextOnProfileListItemAtPositionV1( - itemPosition: Int, - targetView: Int, - stringToMatch: String - ) { - onView( - atPositionOnView( - recyclerViewId = R.id.profile_recycler_view, - position = itemPosition, - targetViewId = targetView - ) - ).check(matches(withText(stringToMatch))) - } - // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. @Singleton @Component( diff --git a/scripts/assets/kdoc_validity_exemptions.textproto b/scripts/assets/kdoc_validity_exemptions.textproto index a67708c6d74..6b1c7deef75 100644 --- a/scripts/assets/kdoc_validity_exemptions.textproto +++ b/scripts/assets/kdoc_validity_exemptions.textproto @@ -140,7 +140,6 @@ exempted_file_path: "app/src/main/java/org/oppia/android/app/player/stopplaying/ exempted_file_path: "app/src/main/java/org/oppia/android/app/player/stopplaying/StopStatePlayingSessionListener.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AddProfileActivity.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AddProfileActivityPresenter.kt" -exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AddProfileViewModel.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AdminAuthActivity.kt" exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AdminAuthEnum.kt" diff --git a/scripts/assets/test_file_exemptions.textproto b/scripts/assets/test_file_exemptions.textproto index f5ab392c821..39f457cddff 100644 --- a/scripts/assets/test_file_exemptions.textproto +++ b/scripts/assets/test_file_exemptions.textproto @@ -1585,7 +1585,11 @@ test_file_exemption { test_file_not_required: true } test_test_file_exemption { - exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/AddProfileListener.kt" + exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/ProfileClickListener.kt" + test_file_not_required: true +} +test_test_file_exemption { + exempted_file_path: "app/src/main/java/org/oppia/android/app/profile/ProfileListView.kt" test_file_not_required: true } test_file_exemption {