diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragmentPresenter.kt index b0e38373b8f..5c9e237c630 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragmentPresenter.kt @@ -21,8 +21,11 @@ import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileType +import org.oppia.android.app.model.Spotlight import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.spotlight.SpotlightManager +import org.oppia.android.app.spotlight.SpotlightTarget import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.app.utility.datetime.DateTimeUtil @@ -194,7 +197,24 @@ class HomeFragmentPresenter @Inject constructor( .registerViewDataBinder( viewType = ViewType.ALL_TOPICS, inflateDataBinding = AllTopicsBinding::inflate, - setViewModel = AllTopicsBinding::setViewModel, + setViewModel = { binding, viewModel -> + binding.viewModel = viewModel + // Request spotlight against the All Topics header for all users. + binding.allTopicsTextView.let { headerView -> + val manager = activity.supportFragmentManager.findFragmentByTag( + SpotlightManager.SPOTLIGHT_FRAGMENT_TAG + ) as? SpotlightManager + manager?.requestSpotlightViewWithDelayedLayout( + SpotlightTarget( + anchor = headerView, + hint = resourceHandler.getStringInLocale( + R.string.home_all_topics_spotlight_hint + ), + feature = Spotlight.FeatureCase.HOME_ALL_TOPICS_HEADER + ) + ) + } + }, transformViewModel = { it as AllTopicsViewModel } ) .registerViewDataBinder( diff --git a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt index 24a3770fbd5..b8650c9624b 100644 --- a/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/profile/ProfileChooserActivityPresenter.kt @@ -6,6 +6,8 @@ import org.oppia.android.app.activity.ActivityScope import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.ProfileChooserActivityParams.ParentScreen import org.oppia.android.app.model.ProfileChooserFragmentArguments +import org.oppia.android.app.spotlight.SpotlightFragment +import org.oppia.android.app.spotlight.SpotlightManager import org.oppia.android.app.testing.ProfileChooserFragmentTestActivity import org.oppia.android.app.ui.R import org.oppia.android.domain.profile.ProfileManagementController @@ -62,6 +64,15 @@ class ProfileChooserActivityPresenter @Inject constructor( ProfileChooserFragmentTestActivity.TAG_PROFILE_CHOOSER_FRAGMENT ).commitNow() } + + // Ensure spotlight fragment is attached similar to HomeActivity. + if (getSpotlightFragment() == null) { + activity.supportFragmentManager.beginTransaction().add( + R.id.profile_spotlight_fragment_placeholder, + SpotlightFragment.newInstance(profileId.internalId), + SpotlightManager.SPOTLIGHT_FRAGMENT_TAG + ).commitNow() + } } private fun getProfileChooserFragment(): ProfileChooserFragment? { @@ -71,4 +82,10 @@ class ProfileChooserActivityPresenter @Inject constructor( R.id.profile_chooser_fragment_placeholder ) as ProfileChooserFragment? } + + private fun getSpotlightFragment(): SpotlightFragment? { + return activity.supportFragmentManager.findFragmentById( + R.id.profile_spotlight_fragment_placeholder + ) as? SpotlightFragment + } } 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 f21016afef2..5543c155710 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 @@ -24,9 +24,12 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileChooserActivityParams.ParentScreen import org.oppia.android.app.model.ProfileType +import org.oppia.android.app.model.Spotlight 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.app.spotlight.SpotlightManager +import org.oppia.android.app.spotlight.SpotlightTarget import org.oppia.android.app.translation.AppLanguageResourceHandler import org.oppia.android.app.ui.R import org.oppia.android.domain.oppialogger.OppiaLogger @@ -112,6 +115,34 @@ class ProfileChooserFragmentPresenter @Inject constructor( logProfileChooserEvent() + // Request admin controls spotlight (use icon as the single anchor) when laid out. + binding.profileSelectionSettingIcon.let { iconView -> + getSpotlightManager()?.requestSpotlightViewWithDelayedLayout( + SpotlightTarget( + anchor = iconView, + hint = resourceHandler.getStringInLocale( + R.string.profile_chooser_spotlight_admin_controls + ), + feature = Spotlight.FeatureCase.PROFILE_ADMIN_CONTROLS_ITEM + ) + ) + } + + // Request add-learner FAB spotlight when laid out and visible. + binding.addProfileButton.let { fab -> + if (fab.visibility == View.VISIBLE) { + getSpotlightManager()?.requestSpotlightViewWithDelayedLayout( + SpotlightTarget( + anchor = fab, + hint = resourceHandler.getStringInLocale( + R.string.profile_chooser_spotlight_add_learner + ), + feature = Spotlight.FeatureCase.PROFILE_ADD_LEARNER_FAB + ) + ) + } + } + binding.apply { when (Resources.getSystem().configuration.orientation) { Configuration.ORIENTATION_PORTRAIT -> setUpPortraitMode() @@ -257,6 +288,18 @@ class ProfileChooserFragmentPresenter @Inject constructor( viewModel: ProfileItemViewModel ) { binding.viewModel = viewModel + // Spotlight the admin profile item (first item) using delayed-layout request (avoids View.post). + if (viewModel.profile.profileType == ProfileType.SUPERVISOR) { + getSpotlightManager()?.requestSpotlightViewWithDelayedLayout( + SpotlightTarget( + anchor = binding.root, + hint = resourceHandler.getStringInLocale( + R.string.profile_chooser_spotlight_admin_profile + ), + feature = Spotlight.FeatureCase.PROFILE_ADMIN_ITEM + ) + ) + } } private fun addProfileButtonClickListener() { @@ -279,6 +322,12 @@ class ProfileChooserFragmentPresenter @Inject constructor( } } + private fun getSpotlightManager(): SpotlightManager? { + return activity.supportFragmentManager.findFragmentByTag( + SpotlightManager.SPOTLIGHT_FRAGMENT_TAG + ) as? SpotlightManager + } + private fun logProfileChooserEvent() { analyticsController.logImportantEvent( oppiaLogger.createOpenProfileChooserContext(), diff --git a/app/src/main/res/layout/profile_chooser_activity.xml b/app/src/main/res/layout/profile_chooser_activity.xml index e2d3de8424f..641033ed743 100644 --- a/app/src/main/res/layout/profile_chooser_activity.xml +++ b/app/src/main/res/layout/profile_chooser_activity.xml @@ -1,7 +1,27 @@ - + tools:context=".app.profile.ProfileChooserActivity"> + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ee7f44f8c0..8427619a3ae 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -759,4 +759,10 @@ Type a 5-Digit PIN Your PIN should be 5 digits long Please make sure that both PINs match + + + Click here to explore administrator controls + Click here to enter your account and explore lessons as a learner + Click here to create a profile for a learner + Select a Topic to start learning diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt index 211bf66fc2b..005ab1987af 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeActivityTest.kt @@ -2079,6 +2079,38 @@ class HomeActivityTest { testCoroutineDispatchers.runCurrent() } + @Test + fun testHomeSpotlight_allTopicsHeader_whenNotSeen_showsHint() { + TestPlatformParameterModule.forceEnableSpotlightUi(true) + setUpTestApplicationComponent() + profileTestHelper.initializeProfiles(autoLogIn = false) + // Launch HomeActivity directly for admin profile 0. + launch(createHomeActivityIntent(0)).use { + testCoroutineDispatchers.runCurrent() + onView(withText(R.string.home_all_topics_spotlight_hint)).check(matches(isDisplayed())) + } + } + + @Test + fun testHomeSpotlight_allTopicsHeader_whenMarkedSeen_notShown() { + TestPlatformParameterModule.forceEnableSpotlightUi(true) + setUpTestApplicationComponent() + profileTestHelper.initializeProfiles(autoLogIn = false) + val profileId = ProfileId.newBuilder().setInternalId(0).build() + dataProviderTestMonitor + .waitForNextSuccessfulResult( + spotlightStateController.markSpotlightViewed( + profileId, + Spotlight.FeatureCase.HOME_ALL_TOPICS_HEADER + ) + ) + + launch(createHomeActivityIntent(0)).use { + testCoroutineDispatchers.runCurrent() + onView(withText(R.string.home_all_topics_spotlight_hint)).check(doesNotExist()) + } + } + private fun createHomeActivityIntent(internalProfileId: Int): Intent { val profileId = LegacyProfileId.newBuilder().setInternalId(internalProfileId).build() return HomeActivity.createHomeActivity(context, profileId) diff --git a/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserSpotlightTest.kt b/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserSpotlightTest.kt new file mode 100644 index 00000000000..feb7949a103 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/profile/ProfileChooserSpotlightTest.kt @@ -0,0 +1,172 @@ +package org.oppia.android.app.profile + +import android.app.Activity +import android.app.Application +import android.content.Context +import androidx.test.core.app.ActivityScenario.launch +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist +import androidx.test.espresso.assertion.ViewAssertions.matches +import androidx.test.espresso.matcher.ViewMatchers.isDisplayed +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.MediumTest +import dagger.BindsInstance +import dagger.Component +import dagger.Module +import dagger.Provides +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.model.ProfileChooserActivityParams +import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.Spotlight +import org.oppia.android.app.ui.R +import org.oppia.android.domain.spotlight.SpotlightStateController +import org.oppia.android.testing.TestOppiaClockRule +import org.oppia.android.testing.data.DataProviderTestMonitor +import org.oppia.android.testing.espresso.EspressoHelpers.onViewWithText +import org.oppia.android.testing.junit.InitializeDefaultLocaleRule +import org.oppia.android.testing.platformparameter.TestPlatformParameterModule +import org.oppia.android.testing.robolectric.RobolectricModule +import org.oppia.android.testing.threading.TestCoroutineDispatchers +import org.oppia.android.testing.threading.TestDispatcherModule +import org.oppia.android.util.data.DataProvidersInjector +import org.oppia.android.util.data.DataProvidersInjectorProvider +import org.oppia.android.util.locale.LocaleProdModule +import org.oppia.android.util.logging.EnableConsoleLog +import org.oppia.android.util.logging.EnableFileLog +import org.oppia.android.util.logging.GlobalLogLevel +import org.oppia.android.util.logging.LogLevel +import javax.inject.Inject +import javax.inject.Singleton + +@RunWith(AndroidJUnit4::class) +@MediumTest +class ProfileChooserSpotlightTest { + + @get:Rule val initializeDefaultLocaleRule = InitializeDefaultLocaleRule() + @get:Rule val oppiaClockRule = TestOppiaClockRule() + + @Inject lateinit var spotlightStateController: SpotlightStateController + @Inject lateinit var dataProviderTestMonitor: DataProviderTestMonitor.Factory + @Inject lateinit var testCoroutineDispatchers: TestCoroutineDispatchers + + private val adminProfileId: ProfileId = ProfileId.newBuilder().setInternalId(0).build() + + @Before + fun setUp() { + setUpTestApplicationComponent() + // Ensure spotlight UI is enabled for these tests. + TestPlatformParameterModule.forceEnableSpotlightUi(true) + } + + @Test + fun testAdminControlsSpotlight_whenNotSeen_showsHint() { + // Ensure state is not seen. + // Launch chooser. + launchProfileChooser() + + // Verify hint is shown. + onViewWithText(R.string.profile_chooser_spotlight_admin_controls).check(matches(isDisplayed())) + } + + @Test + fun testAdminControlsSpotlight_whenMarkedSeen_notShownOnReopen() { + dataProviderTestMonitor.waitForNextSuccessfulResult( + spotlightStateController.markSpotlightViewed( + adminProfileId, Spotlight.FeatureCase.PROFILE_ADMIN_CONTROLS_ITEM + ) + ) + // Launch chooser. + launchProfileChooser() + + // Hint should not appear. + onViewWithText(R.string.profile_chooser_spotlight_admin_controls).check(doesNotExist()) + } + + @Test + fun testAddLearnerFabSpotlight_whenNotSeen_showsHint() { + launchProfileChooser() + onViewWithText(R.string.profile_chooser_spotlight_add_learner).check(matches(isDisplayed())) + } + + @Test + fun testAdminProfileItemSpotlight_whenNotSeen_showsHint() { + launchProfileChooser() + onViewWithText(R.string.profile_chooser_spotlight_admin_profile).check(matches(isDisplayed())) + } + + private fun launchProfileChooser(): ActivityScenarioRuleProxy { + val context = ApplicationProvider.getApplicationContext() + val params = ProfileChooserActivityParams.newBuilder() + .setParentScreen(ProfileChooserActivityParams.ParentScreen.SPLASH_SCREEN) + .build() + val intent = ProfileChooserActivity.createProfileChooserActivity(context).apply { + org.oppia.android.util.extensions.putProtoExtra( + "ProfileChooserActivity.params", params + ) + } + val scenario = launch(intent) + testCoroutineDispatchers.runCurrent() + return ActivityScenarioRuleProxy(scenario) + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + // Helpers & DI setup + + data class ActivityScenarioRuleProxy( + val scenario: androidx.test.core.app.ActivityScenario + ) + + @Module + class TestModule { + @Provides + @Singleton + fun provideContext(application: Application): Context = application + + @EnableConsoleLog + @Provides + fun provideEnableConsoleLog(): Boolean = true + + @EnableFileLog + @Provides + fun provideEnableFileLog(): Boolean = false + + @GlobalLogLevel + @Provides + fun provideGlobalLogLevel(): LogLevel = LogLevel.VERBOSE + } + + @Singleton + @Component( + modules = [ + RobolectricModule::class, + LocaleProdModule::class, + TestDispatcherModule::class, + TestModule::class, + TestPlatformParameterModule::class + ] + ) + interface TestApplicationComponent : DataProvidersInjector { + @Component.Builder + interface Builder { + @BindsInstance fun setApplication(application: Application): Builder + fun build(): TestApplicationComponent + } + fun inject(test: ProfileChooserSpotlightTest) + } + + class TestApplication : Application(), DataProvidersInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerProfileChooserSpotlightTest_TestApplicationComponent.builder() + .setApplication(this) + .build() + } + fun inject(test: ProfileChooserSpotlightTest) = component.inject(test) + override fun getDataProvidersInjector(): DataProvidersInjector = component + } +} diff --git a/domain/src/main/java/org/oppia/android/domain/spotlight/SpotlightStateController.kt b/domain/src/main/java/org/oppia/android/domain/spotlight/SpotlightStateController.kt index 7b26510ecee..e8049500f44 100644 --- a/domain/src/main/java/org/oppia/android/domain/spotlight/SpotlightStateController.kt +++ b/domain/src/main/java/org/oppia/android/domain/spotlight/SpotlightStateController.kt @@ -5,7 +5,11 @@ import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.Spotlight import org.oppia.android.app.model.Spotlight.FeatureCase.FEATURE_NOT_SET import org.oppia.android.app.model.Spotlight.FeatureCase.FIRST_CHAPTER +import org.oppia.android.app.model.Spotlight.FeatureCase.HOME_ALL_TOPICS_HEADER import org.oppia.android.app.model.Spotlight.FeatureCase.LESSONS_BACK_BUTTON +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADD_LEARNER_FAB +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADMIN_CONTROLS_ITEM +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADMIN_ITEM import org.oppia.android.app.model.Spotlight.FeatureCase.PROMOTED_STORIES import org.oppia.android.app.model.Spotlight.FeatureCase.TOPIC_LESSON_TAB import org.oppia.android.app.model.Spotlight.FeatureCase.TOPIC_REVISION_TAB @@ -92,6 +96,10 @@ class SpotlightStateController @Inject constructor( LESSONS_BACK_BUTTON -> it.lessonsBackButton VOICEOVER_PLAY_ICON -> it.voiceoverPlayIcon VOICEOVER_LANGUAGE_ICON -> it.voiceoverLanguageIcon + PROFILE_ADMIN_CONTROLS_ITEM -> it.profileAdminControlsItem + PROFILE_ADMIN_ITEM -> it.profileAdminItem + PROFILE_ADD_LEARNER_FAB -> it.profileAddLearnerFab + HOME_ALL_TOPICS_HEADER -> it.homeAllTopicsHeader FEATURE_NOT_SET -> { return@transformAsync AsyncResult.Failure( SpotlightFeatureNotFoundException("Spotlight feature requested was not found") @@ -122,6 +130,10 @@ class SpotlightStateController @Inject constructor( LESSONS_BACK_BUTTON -> this.setLessonsBackButton(viewState) VOICEOVER_PLAY_ICON -> this.setVoiceoverPlayIcon(viewState) VOICEOVER_LANGUAGE_ICON -> this.setVoiceoverLanguageIcon(viewState) + PROFILE_ADMIN_CONTROLS_ITEM -> this.setProfileAdminControlsItem(viewState) + PROFILE_ADMIN_ITEM -> this.setProfileAdminItem(viewState) + PROFILE_ADD_LEARNER_FAB -> this.setProfileAddLearnerFab(viewState) + HOME_ALL_TOPICS_HEADER -> this.setHomeAllTopicsHeader(viewState) FEATURE_NOT_SET -> { throw SpotlightFeatureNotFoundException("Spotlight feature was not found") } diff --git a/domain/src/test/java/org/oppia/android/domain/spotlight/SpotlightStateControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/spotlight/SpotlightStateControllerTest.kt index 9ffd5bdd14f..bfffa4da7c0 100644 --- a/domain/src/test/java/org/oppia/android/domain/spotlight/SpotlightStateControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/spotlight/SpotlightStateControllerTest.kt @@ -15,7 +15,11 @@ import org.junit.runner.RunWith import org.oppia.android.app.model.LegacyProfileId import org.oppia.android.app.model.Spotlight import org.oppia.android.app.model.Spotlight.FeatureCase.FIRST_CHAPTER +import org.oppia.android.app.model.Spotlight.FeatureCase.HOME_ALL_TOPICS_HEADER import org.oppia.android.app.model.Spotlight.FeatureCase.LESSONS_BACK_BUTTON +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADD_LEARNER_FAB +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADMIN_CONTROLS_ITEM +import org.oppia.android.app.model.Spotlight.FeatureCase.PROFILE_ADMIN_ITEM import org.oppia.android.app.model.Spotlight.FeatureCase.PROMOTED_STORIES import org.oppia.android.app.model.Spotlight.FeatureCase.TOPIC_LESSON_TAB import org.oppia.android.app.model.Spotlight.FeatureCase.TOPIC_REVISION_TAB @@ -245,6 +249,74 @@ class SpotlightStateControllerTest { assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_SEEN) } + @Test + fun testRetrieveSpotlightViewState_profileAdminControls_notMarked_returnsNotSeen() { + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADMIN_CONTROLS_ITEM) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_NOT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_profileAdminControls_marked_returnsSeen() { + markSpotlightSeen(PROFILE_ADMIN_CONTROLS_ITEM) + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADMIN_CONTROLS_ITEM) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_profileAdminItem_notMarked_returnsNotSeen() { + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADMIN_ITEM) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_NOT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_profileAdminItem_marked_returnsSeen() { + markSpotlightSeen(PROFILE_ADMIN_ITEM) + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADMIN_ITEM) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_profileAddLearnerFab_notMarked_returnsNotSeen() { + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADD_LEARNER_FAB) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_NOT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_profileAddLearnerFab_marked_returnsSeen() { + markSpotlightSeen(PROFILE_ADD_LEARNER_FAB) + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, PROFILE_ADD_LEARNER_FAB) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_homeAllTopicsHeader_notMarked_returnsNotSeen() { + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, HOME_ALL_TOPICS_HEADER) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_NOT_SEEN) + } + + @Test + fun testRetrieveSpotlightViewState_homeAllTopicsHeader_marked_returnsSeen() { + markSpotlightSeen(HOME_ALL_TOPICS_HEADER) + val provider = + spotlightStateController.retrieveSpotlightViewState(profileId0, HOME_ALL_TOPICS_HEADER) + val result = dataProviderTestMonitor.waitForNextSuccessfulResult(provider) + assertThat(result).isEqualTo(SpotlightViewState.SPOTLIGHT_SEEN) + } + @Test fun testRetrieveSpotlightViewState_invalidFeature_returnsFailure() { val invalidFeature = Spotlight.FeatureCase.FEATURE_NOT_SET diff --git a/model/src/main/proto/spotlight.proto b/model/src/main/proto/spotlight.proto index f6bad25532a..3deeb317b0f 100644 --- a/model/src/main/proto/spotlight.proto +++ b/model/src/main/proto/spotlight.proto @@ -34,6 +34,18 @@ message Spotlight { // Corresponds to the voice-over language option in audio player. SpotlightViewState voiceover_language_icon = 8; + + // Corresponds to the Admin Controls entry on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_admin_controls_item = 9; + + // Corresponds to the Admin profile item on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_admin_item = 10; + + // Corresponds to the Add Learner Floating Action Button on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_add_learner_fab = 11; + + // Corresponds to the All Topics header on the Home screen. + SpotlightViewState home_all_topics_header = 12; } } @@ -75,4 +87,16 @@ message SpotlightStateDatabase { // Corresponds to the voice-over language option in audio player. SpotlightViewState voiceover_language_icon = 8; + + // Corresponds to the Admin Controls entry on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_admin_controls_item = 9; + + // Corresponds to the Admin profile item on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_admin_item = 10; + + // Corresponds to the Add Learner Floating Action Button on the profile chooser screen (Onboarding V2). + SpotlightViewState profile_add_learner_fab = 11; + + // Corresponds to the All Topics header on the Home screen. + SpotlightViewState home_all_topics_header = 12; }