diff --git a/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogFragment.kt b/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogFragment.kt index 66b005b4622..97713b1f67d 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogFragment.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogFragment.kt @@ -2,31 +2,37 @@ package org.oppia.android.app.drawer import android.app.Dialog import android.content.Context +import android.content.DialogInterface import android.content.Intent import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.appcompat.view.ContextThemeWrapper import androidx.fragment.app.DialogFragment import org.oppia.android.R +import org.oppia.android.app.model.ExitProfileDialogArguments +import org.oppia.android.app.model.HighlightItem import org.oppia.android.app.profile.ProfileChooserActivity +import org.oppia.android.util.extensions.getProto +import org.oppia.android.util.extensions.putProto /** [DialogFragment] that gives option to either cancel or exit current profile. */ class ExitProfileDialogFragment : DialogFragment() { companion object { // TODO(#1655): Re-restrict access to fields in tests post-Gradle. - const val BOOL_IS_FROM_NAVIGATION_DRAWER_EXTRA_KEY = - "BOOL_IS_FROM_NAVIGATION_DRAWER_EXTRA_KEY" + const val EXIT_PROFILE_DIALOG_ARGUMENTS_PROTO = "EXIT_PROFILE_DIALOG_ARGUMENT_PROTO" /** * This function is responsible for displaying content in DialogFragment. * * @return [ExitProfileDialogFragment]: DialogFragment */ - fun newInstance(isFromNavigationDrawer: Boolean): ExitProfileDialogFragment { + fun newInstance( + exitProfileDialogArguments: ExitProfileDialogArguments + ): ExitProfileDialogFragment { val exitProfileDialogFragment = ExitProfileDialogFragment() val args = Bundle() - args.putBoolean(BOOL_IS_FROM_NAVIGATION_DRAWER_EXTRA_KEY, isFromNavigationDrawer) + args.putProto(EXIT_PROFILE_DIALOG_ARGUMENTS_PROTO, exitProfileDialogArguments) exitProfileDialogFragment.arguments = args return exitProfileDialogFragment } @@ -38,33 +44,61 @@ class ExitProfileDialogFragment : DialogFragment() { val args = checkNotNull(arguments) { "Expected arguments to be pass to ExitProfileDialogFragment" } - val isFromNavigationDrawer = args.getBoolean( - BOOL_IS_FROM_NAVIGATION_DRAWER_EXTRA_KEY, - false + val exitProfileDialogArguments = args.getProto( + EXIT_PROFILE_DIALOG_ARGUMENTS_PROTO, + ExitProfileDialogArguments.getDefaultInstance() ) - if (isFromNavigationDrawer) { - exitProfileDialogInterface = - parentFragment as ExitProfileDialogInterface + val restoreLastCheckedItem = when (exitProfileDialogArguments.highlightItem) { + HighlightItem.ADMINISTRATOR_CONTROLS_ITEM, + HighlightItem.LAST_CHECKED_MENU_ITEM -> true + else -> false } - return AlertDialog + val alertDialog = AlertDialog .Builder(ContextThemeWrapper(activity as Context, R.style.AlertDialogTheme)) .setMessage(R.string.home_activity_back_dialog_message) .setNegativeButton(R.string.home_activity_back_dialog_cancel) { dialog, _ -> - if (isFromNavigationDrawer) { - exitProfileDialogInterface.markHomeMenuCloseDrawer() - } dialog.dismiss() } .setPositiveButton(R.string.home_activity_back_dialog_exit) { _, _ -> // TODO(#322): Need to start intent for ProfileChooserActivity to get update. Change to finish when live data bug is fixed. val intent = ProfileChooserActivity.createProfileChooserActivity(activity!!) - if (!isFromNavigationDrawer) { + if (!restoreLastCheckedItem) { intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) } activity!!.startActivity(intent) } .create() + alertDialog.setCanceledOnTouchOutside(false) + return alertDialog + } + + override fun onDismiss(dialog: DialogInterface) { + super.onDismiss(dialog) + val args = + checkNotNull(arguments) { "Expected arguments to be pass to ExitProfileDialogFragment" } + + val exitProfileDialogArguments = args.getProto( + EXIT_PROFILE_DIALOG_ARGUMENTS_PROTO, + ExitProfileDialogArguments.getDefaultInstance() + ) + + val restoreLastCheckedItem = when (exitProfileDialogArguments.highlightItem) { + HighlightItem.ADMINISTRATOR_CONTROLS_ITEM, + HighlightItem.LAST_CHECKED_MENU_ITEM -> true + else -> false + } + + if (restoreLastCheckedItem) { + exitProfileDialogInterface = + parentFragment as ExitProfileDialogInterface + exitProfileDialogInterface.unhighlightSwitchProfileMenuItem() + if (exitProfileDialogArguments.highlightItem == HighlightItem.LAST_CHECKED_MENU_ITEM) { + exitProfileDialogInterface.highlightLastCheckedMenuItem() + } else { + exitProfileDialogInterface.highlightAdministratorControlsItem() + } + } } } diff --git a/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogInterface.kt b/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogInterface.kt index 3fbbcc4daab..75754b72cf9 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogInterface.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/ExitProfileDialogInterface.kt @@ -2,5 +2,7 @@ package org.oppia.android.app.drawer /** Interface to handle option selection in [ExitProfileDialogFragment]. */ interface ExitProfileDialogInterface { - fun markHomeMenuCloseDrawer() + fun highlightLastCheckedMenuItem() + fun highlightAdministratorControlsItem() + fun unhighlightSwitchProfileMenuItem() } diff --git a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragment.kt b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragment.kt index cad40d9d4a2..24cdcae5a3c 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragment.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragment.kt @@ -40,7 +40,15 @@ class NavigationDrawerFragment : navigationDrawerFragmentPresenter.openProfileProgress(profileId) } - override fun markHomeMenuCloseDrawer() { - navigationDrawerFragmentPresenter.markHomeMenuCloseDrawer() + override fun highlightLastCheckedMenuItem() { + navigationDrawerFragmentPresenter.highlightLastCheckedMenuItem() + } + + override fun highlightAdministratorControlsItem() { + navigationDrawerFragmentPresenter.highlightAdministratorControlsItem() + } + + override fun unhighlightSwitchProfileMenuItem() { + navigationDrawerFragmentPresenter.unhighlightSwitchProfileMenuItem() } } diff --git a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt index 7032676f0e8..d2abacfe43e 100644 --- a/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/drawer/NavigationDrawerFragmentPresenter.kt @@ -20,6 +20,8 @@ import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.help.HelpActivity import org.oppia.android.app.home.HomeActivity import org.oppia.android.app.model.CompletedStoryList +import org.oppia.android.app.model.ExitProfileDialogArguments +import org.oppia.android.app.model.HighlightItem import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId @@ -105,9 +107,7 @@ class NavigationDrawerFragmentPresenter @Inject constructor( return@setOnClickListener } - binding.fragmentDrawerNavView.menu.forEach { menuItem -> - menuItem.isCheckable = false - } + uncheckAllMenuItemsWhenAdministratorControlsIsSelected() drawerLayout.closeDrawers() getFooterViewModel().isAdministratorControlsSelected.set(true) @@ -199,7 +199,6 @@ class NavigationDrawerFragmentPresenter @Inject constructor( } private fun openActivityByMenuItemId(menuItemId: Int) { - getFooterViewModel().isAdministratorControlsSelected.set(false) if (previousMenuItemId != menuItemId) { when (NavigationDrawerItem.valueFromNavId(menuItemId)) { NavigationDrawerItem.HOME -> { @@ -244,8 +243,25 @@ class NavigationDrawerFragmentPresenter @Inject constructor( if (previousFragment != null) { fragment.childFragmentManager.beginTransaction().remove(previousFragment).commitNow() } + val exitProfileDialogArguments = + if (getFooterViewModel().isAdministratorControlsSelected.get() == true) { + ExitProfileDialogArguments + .newBuilder() + .setHighlightItem(HighlightItem.ADMINISTRATOR_CONTROLS_ITEM) + .build() + } else { + ExitProfileDialogArguments + .newBuilder() + .setHighlightItem(HighlightItem.LAST_CHECKED_MENU_ITEM) + .build() + } + getFooterViewModel().isAdministratorControlsSelected.set(false) + binding.fragmentDrawerNavView.menu.getItem( + NavigationDrawerItem.SWITCH_PROFILE.ordinal + ).isChecked = + true val dialogFragment = ExitProfileDialogFragment - .newInstance(isFromNavigationDrawer = true) + .newInstance(exitProfileDialogArguments = exitProfileDialogArguments) dialogFragment.showNow(fragment.childFragmentManager, TAG_SWITCH_PROFILE_DIALOG) } } @@ -263,12 +279,37 @@ class NavigationDrawerFragmentPresenter @Inject constructor( ) } - fun markHomeMenuCloseDrawer() { + fun highlightLastCheckedMenuItem() { + previousMenuItemId?.let { itemId -> + if (itemId != 0) { + binding.fragmentDrawerNavView.menu.getItem( + NavigationDrawerItem.valueFromNavId( + itemId + ).ordinal + ).isChecked = + true + } + drawerLayout.closeDrawers() + } + } + + fun highlightAdministratorControlsItem() { + getFooterViewModel().isAdministratorControlsSelected.set(true) + uncheckAllMenuItemsWhenAdministratorControlsIsSelected() + drawerLayout.closeDrawers() + } + + fun unhighlightSwitchProfileMenuItem() { binding.fragmentDrawerNavView.menu.getItem( - NavigationDrawerItem.HOME.ordinal + NavigationDrawerItem.SWITCH_PROFILE.ordinal ).isChecked = - true - drawerLayout.closeDrawers() + false + } + + private fun uncheckAllMenuItemsWhenAdministratorControlsIsSelected() { + binding.fragmentDrawerNavView.menu.forEach { + it.isCheckable = false + } } /** @@ -345,6 +386,7 @@ class NavigationDrawerFragmentPresenter @Inject constructor( } else { // For showing navigation drawer in AdministratorControlsActivity getFooterViewModel().isAdministratorControlsSelected.set(true) + uncheckAllMenuItemsWhenAdministratorControlsIsSelected() this.drawerLayout = drawerLayout drawerToggle = object : ActionBarDrawerToggle( fragment.activity, diff --git a/app/src/main/java/org/oppia/android/app/home/HomeActivity.kt b/app/src/main/java/org/oppia/android/app/home/HomeActivity.kt index 164af1622e7..fe423af43b0 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeActivity.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeActivity.kt @@ -9,6 +9,8 @@ import org.oppia.android.app.drawer.ExitProfileDialogFragment import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.drawer.TAG_SWITCH_PROFILE_DIALOG import org.oppia.android.app.home.recentlyplayed.RecentlyPlayedActivity +import org.oppia.android.app.model.ExitProfileDialogArguments +import org.oppia.android.app.model.HighlightItem import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject @@ -38,6 +40,11 @@ class HomeActivity : title = getString(R.string.menu_home) } + override fun onRestart() { + super.onRestart() + homeActivityPresenter.handleOnRestart() + } + override fun routeToTopic(internalProfileId: Int, topicId: String) { startActivity(TopicActivity.createTopicActivityIntent(this, internalProfileId, topicId)) } @@ -48,8 +55,13 @@ class HomeActivity : if (previousFragment != null) { supportFragmentManager.beginTransaction().remove(previousFragment).commitNow() } + val exitProfileDialogArguments = + ExitProfileDialogArguments + .newBuilder() + .setHighlightItem(HighlightItem.NONE) + .build() val dialogFragment = ExitProfileDialogFragment - .newInstance(isFromNavigationDrawer = false) + .newInstance(exitProfileDialogArguments = exitProfileDialogArguments) dialogFragment.showNow(supportFragmentManager, TAG_SWITCH_PROFILE_DIALOG) } diff --git a/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt index 91614a2cd81..5f32ea6c547 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeActivityPresenter.kt @@ -28,6 +28,10 @@ class HomeActivityPresenter @Inject constructor(private val activity: AppCompatA } } + fun handleOnRestart() { + setUpNavigationDrawer() + } + private fun setUpNavigationDrawer() { val toolbar = activity.findViewById(R.id.home_activity_toolbar) as Toolbar activity.setSupportActionBar(toolbar) diff --git a/app/src/main/java/org/oppia/android/app/testing/NavigationDrawerTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/NavigationDrawerTestActivity.kt index 2149dba653e..6c2fab253f9 100644 --- a/app/src/main/java/org/oppia/android/app/testing/NavigationDrawerTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/NavigationDrawerTestActivity.kt @@ -32,6 +32,11 @@ class NavigationDrawerTestActivity : InjectableAppCompatActivity(), RouteToTopic title = getString(R.string.menu_home) } + override fun onRestart() { + super.onRestart() + homeActivityPresenter.handleOnRestart() + } + override fun routeToTopic(internalProfileId: Int, topicId: String) { startActivity(TopicActivity.createTopicActivityIntent(this, internalProfileId, topicId)) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityTest.kt b/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityTest.kt index a36e7ff6165..1f629be29ba 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/testing/NavigationDrawerActivityTest.kt @@ -17,6 +17,7 @@ import androidx.test.espresso.PerformException import androidx.test.espresso.UiController import androidx.test.espresso.ViewAction import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.action.ViewActions.pressBack import androidx.test.espresso.action.ViewActions.swipeUp import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.DrawerActions.close @@ -27,6 +28,7 @@ import androidx.test.espresso.intent.Intents.intended import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent import androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra import androidx.test.espresso.matcher.RootMatchers.isDialog +import androidx.test.espresso.matcher.ViewMatchers import androidx.test.espresso.matcher.ViewMatchers.isAssignableFrom import androidx.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed import androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA @@ -37,9 +39,12 @@ import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.espresso.util.HumanReadables import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.android.material.navigation.NavigationView import dagger.Component +import org.hamcrest.Description import org.hamcrest.Matchers.allOf import org.hamcrest.Matchers.not +import org.hamcrest.TypeSafeMatcher import org.junit.After import org.junit.Before import org.junit.Ignore @@ -55,6 +60,7 @@ import org.oppia.android.app.application.ApplicationInjector import org.oppia.android.app.application.ApplicationInjectorProvider import org.oppia.android.app.application.ApplicationModule import org.oppia.android.app.application.ApplicationStartupListenerModule +import org.oppia.android.app.drawer.NavigationDrawerItem import org.oppia.android.app.help.HelpActivity import org.oppia.android.app.model.ProfileId import org.oppia.android.app.mydownloads.MyDownloadsActivity @@ -167,7 +173,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_openNavDrawer_navDrawerIsOpened() { + fun testNavDrawer_openNavDrawer_navDrawerIsOpened() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withId(R.id.home_fragment_placeholder)).check(matches(isCompletelyDisplayed())) @@ -176,7 +182,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_openNavDrawer_changeConfig_navDrawerIsDisplayed() { + fun testNavDrawer_openNavDrawer_configChange_navDrawerIsDisplayed() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(isRoot()).perform(orientationLandscape()) @@ -185,7 +191,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withAdminProfile_openNavDrawer_profileNameIsDisplayed() { + fun testNavDrawer_withAdminProfile_openNavDrawer_profileNameIsDisplayed() { launch( createNavigationDrawerActivityIntent( internalProfileId @@ -203,7 +209,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withAdminProfile_changeConfig_profileNameIsDisplayed() { + fun testNavDrawer_withAdminProfile_configChange_profileNameIsDisplayed() { launch( createNavigationDrawerActivityIntent( internalProfileId @@ -222,7 +228,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_openNavDrawer_profileProgressIsDisplayed() { + fun testNavDrawer_openNavDrawer_profileProgressIsDisplayed() { launch( createNavigationDrawerActivityIntent( internalProfileId @@ -240,7 +246,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withUserProfile_openNavDrawer_profileNameIsDisplayed() { + fun testNavDrawer_withUserProfile_openNavDrawer_profileNameIsDisplayed() { launch( createNavigationDrawerActivityIntent( internalProfileId1 @@ -258,7 +264,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_clickOnHeader_opensProfileProgressActivity() { + fun testNavDrawer_clickOnHeader_opensProfileProgressActivity() { launch( createNavigationDrawerActivityIntent( internalProfileId @@ -278,8 +284,400 @@ class NavigationDrawerActivityTest { } } + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_switchProfile_cancel_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_options_switchProfile_cancel_optionsIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_options)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.OPTIONS))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) @Test - fun testNavigationDrawerTestActivity_withAdminProfile_openNavDrawer_adminControlsIsDisplayed() { + fun testNavDrawer_openNavDrawer_help_switchProfile_cancel_helpIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_help)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HELP))) + } + } + + // TODO(#1806): Enable this once lowfi implementation is done. + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + @Ignore("My Downloads is removed until we have full download support.") + fun testNavDrawer_openNavDrawer_download_switchProfile_cancel_downloadIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_my_downloads)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.DOWNLOADS))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_admin_switchProfile_cancel_adminIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.administrator_controls)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView( + allOf( + withText(R.string.administrator_controls), + isDescendantOfA(withId(R.id.administrator_controls_linear_layout)) + ) + ).check(matches(ViewMatchers.hasTextColor(R.color.highlightedNavMenuItem))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_switchProfile_cancel_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_options_switchProfile_cancel_configChange_optionsIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_options)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.OPTIONS))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_help_switchProfile_cancel_configChange_helpIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_help)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HELP))) + } + } + + // TODO(#1806): Enable this once lowfi implementation is done. + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + @Ignore("My Downloads is removed until we have full download support.") + fun testNavDrawer_openNavDrawer_download_switchProfile_cancel_configChange_downloadIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_my_downloads)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.DOWNLOADS))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_admin_switchProfile_cancel_configChange_adminIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.administrator_controls)).perform(click()) + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(withText(R.string.home_activity_back_dialog_cancel)) + .inRoot(isDialog()) + .perform(click()) + it.openNavigationDrawer() + testCoroutineDispatchers.runCurrent() + onView(isRoot()).perform(orientationLandscape()) + testCoroutineDispatchers.runCurrent() + onView( + allOf( + withText(R.string.administrator_controls), + isDescendantOfA(withId(R.id.administrator_controls_linear_layout)) + ) + ).check(matches(ViewMatchers.hasTextColor(R.color.highlightedNavMenuItem))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_options_pressBack_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_options)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_help_pressBack_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_help)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#1806): Enable this once lowfi implementation is done. + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + @Ignore("My Downloads is removed until we have full download support.") + fun testNavDrawer_openNavDrawer_download_pressBack_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_my_downloads)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_switchProfile_pressBack_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_admin_pressBack_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.administrator_controls)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_options_pressBack_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_options)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_help_pressBack_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_help)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#1806): Enable this once lowfi implementation is done. + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + @Ignore("My Downloads is removed until we have full download support.") + fun testNavDrawer_openNavDrawer_download_pressBack_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_my_downloads)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_switchProfile_pressBack_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.menu_switch_profile)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + // TODO(#2535): Unable to open NavigationDrawer multiple times on Robolectric + @RunOn(TestPlatform.ESPRESSO) + @Test + fun testNavDrawer_openNavDrawer_admin_pressBack_configChange_homeIsSelected() { + launch( + createNavigationDrawerActivityIntent(internalProfileId) + ).use { + it.openNavigationDrawer() + onView(withText(R.string.administrator_controls)).perform(click()) + onView(isRoot()).perform(pressBack()) + it.openNavigationDrawer() + onView(isRoot()).perform(orientationLandscape()) + onView(withId(R.id.fragment_drawer_nav_view)) + .check(matches(checkNavigationViewItemStatus(NavigationDrawerItem.HOME))) + } + } + + @Test + fun testNavDrawer_withAdminProfile_openNavDrawer_adminControlsIsDisplayed() { launch( createNavigationDrawerActivityIntent(internalProfileId) ).use { @@ -289,7 +687,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withAdminProfile_changeConfig_adminControlsIsDisplayed() { + fun testNavDrawer_withAdminProfile_configChange_adminControlsIsDisplayed() { launch( createNavigationDrawerActivityIntent(internalProfileId) ).use { @@ -301,7 +699,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withAdminProfile_adminMenu_opensAdminControlsActivity() { + fun testNavDrawer_withAdminProfile_adminMenu_opensAdminControlsActivity() { launch( createNavigationDrawerActivityIntent( internalProfileId @@ -316,7 +714,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_withUserProfile_adminControlsAreNotDisplayed() { + fun testNavDrawer_withUserProfile_adminControlsAreNotDisplayed() { launch( createNavigationDrawerActivityIntent( internalProfileId1 @@ -331,7 +729,7 @@ class NavigationDrawerActivityTest { // TODO(#1806): Enable this once lowfi implementation is done. @Test @Ignore("My Downloads is removed until we have full download support.") - fun testNavigationDrawerTestActivity_myDownloadsMenu_myDownloadsFragmentIsDisplayed() { + fun testNavDrawer_myDownloadsMenu_myDownloadsFragmentIsDisplayed() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_my_downloads)).perform(click()) @@ -340,7 +738,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_switchProfileMenu_showsExitToProfileChooserDialog() { + fun testNavDrawer_switchProfileMenu_exitToProfileChooserDialogIsDisplayed() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_switch_profile)).perform(click()) @@ -351,7 +749,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_switchProfileMenu_clickExit_opensProfileChooserActivity() { + fun testNavDrawer_switchProfileMenu_clickExit_opensProfileChooserActivity() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_switch_profile)).perform(click()) @@ -367,7 +765,7 @@ class NavigationDrawerActivityTest { @RunOn(TestPlatform.ESPRESSO) @Test - fun testNavigationDrawerTestActivity_openNavDrawerAndClose_navDrawerIsClosed() { + fun testNavDrawer_openNavDrawerAndClose_navDrawerIsClosed() { launch(NavigationDrawerTestActivity::class.java).use { testCoroutineDispatchers.runCurrent() it.openNavigationDrawer() @@ -378,7 +776,7 @@ class NavigationDrawerActivityTest { @RunOn(TestPlatform.ESPRESSO) @Test - fun testNavigationDrawerTestActivity_selectSwitchProfileMenu_clickCancel_navDrawerIsClosed() { + fun testNavDrawer_selectSwitchProfileMenu_clickCancel_navDrawerIsClosed() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_switch_profile)).perform(click()) @@ -394,7 +792,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_selectSwitchProfile_changeConfig_dialogIsVisible() { + fun testNavDrawer_selectSwitchProfile_configChange_dialogIsVisible() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_switch_profile)).perform(click()) @@ -407,7 +805,7 @@ class NavigationDrawerActivityTest { } @Test - fun testNavigationDrawerTestActivity_openNavDrawer_selectHelpMenu_opensHelpActivity() { + fun testNavDrawer_openNavDrawer_selectHelpMenu_opensHelpActivity() { launch(NavigationDrawerTestActivity::class.java).use { it.openNavigationDrawer() onView(withText(R.string.menu_help)).perform(click()) @@ -496,6 +894,17 @@ class NavigationDrawerActivityTest { return view.getParent() } + private fun checkNavigationViewItemStatus(item: NavigationDrawerItem) = + object : TypeSafeMatcher() { + override fun describeTo(description: Description) { + description.appendText("NavigationViewItem is checked") + } + + override fun matchesSafely(view: View): Boolean { + return (view as NavigationView).menu.getItem(item.ordinal).isChecked + } + } + // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. // TODO(#1675): Add NetworkModule once data module is migrated off of Moshi. @Singleton diff --git a/model/BUILD.bazel b/model/BUILD.bazel index 6df6197cbca..300cf58357c 100644 --- a/model/BUILD.bazel +++ b/model/BUILD.bazel @@ -39,6 +39,16 @@ load("//model:src/main/proto/format_import_proto_library.bzl", "format_import_pr # ... # ) +proto_library( + name = "arguments_proto", + srcs = ["src/main/proto/arguments.proto"], +) + +java_lite_proto_library( + name = "arguments_java_proto_lite", + deps = [":arguments_proto"], +) + proto_library( name = "event_logger_proto", srcs = ["src/main/proto/oppia_logger.proto"], @@ -192,6 +202,7 @@ android_library( name = "model", visibility = ["//visibility:public"], exports = [ + ":arguments_java_proto_lite", ":event_logger_java_proto_lite", ":exploration_java_proto_lite", ":interaction_object_java_proto_lite", diff --git a/model/src/main/proto/arguments.proto b/model/src/main/proto/arguments.proto new file mode 100644 index 00000000000..9806d80e16e --- /dev/null +++ b/model/src/main/proto/arguments.proto @@ -0,0 +1,28 @@ +syntax = "proto3"; + +package model; + +option java_package = "org.oppia.android.app.model"; +option java_multiple_files = true; + +// The fragment arguments passed to instances of ExitProfileDialogFragment. +message ExitProfileDialogArguments { + // Decides the correct menu item to be highlighted after canceling the ExitProfileDialogFragment. + HighlightItem highlight_item = 1; +} + +// Represents the type of item/menuItem that should be highlighted after canceling the +// ExitProfileDialogFragment. +enum HighlightItem { + // Indicates that the highlight item was not set + ITEM_UNSPECIFIED = 0; + + // Indicates that none of the items needs to be highlighted. + NONE = 1; + + // Indicates that one of the NavigationDrawerItem needs to be highlighted. + LAST_CHECKED_MENU_ITEM = 2; + + // Indicates that the Administrator Controls item needs to be highlighted. + ADMINISTRATOR_CONTROLS_ITEM = 3; +}