diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 78ac8495b48..1e435dfc707 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,15 +11,16 @@ android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/OppiaTheme"> - - + + - + + @@ -34,4 +35,4 @@ android:theme="@style/SplashScreenTheme" /> - + \ No newline at end of file diff --git a/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt b/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt index 1038aecf0ba..e1dbd77de7d 100644 --- a/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt +++ b/app/src/main/java/org/oppia/app/activity/ActivityComponent.kt @@ -10,6 +10,7 @@ import org.oppia.app.player.exploration.ExplorationActivity import org.oppia.app.topic.conceptcard.testing.ConceptCardFragmentTestActivity import org.oppia.app.player.state.testing.StateFragmentTestActivity import org.oppia.app.profile.ProfileActivity +import org.oppia.app.story.StoryActivity import org.oppia.app.testing.BindableAdapterTestActivity import org.oppia.app.topic.TopicActivity import org.oppia.app.topic.questionplayer.QuestionPlayerActivity @@ -27,13 +28,14 @@ interface ActivityComponent { fun getFragmentComponentBuilderProvider(): Provider + fun inject(audioFragmentTestActivity: AudioFragmentTestActivity) fun inject(bindableAdapterTestActivity: BindableAdapterTestActivity) + fun inject(conceptCardFragmentTestActivity: ConceptCardFragmentTestActivity) fun inject(explorationActivity: ExplorationActivity) fun inject(homeActivity: HomeActivity) - fun inject(conceptCardFragmentTestActivity: ConceptCardFragmentTestActivity) + fun inject(profileActivity: ProfileActivity) fun inject(questionPlayerActivity: QuestionPlayerActivity) - fun inject(topicActivity: TopicActivity) - fun inject(audioFragmentTestActivity: AudioFragmentTestActivity) fun inject(stateFragmentTestActivity: StateFragmentTestActivity) - fun inject(profileActivity: ProfileActivity) + fun inject(storyActivity: StoryActivity) + fun inject(topicActivity: TopicActivity) } diff --git a/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt b/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt index e982ef2160f..885957b3028 100644 --- a/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt +++ b/app/src/main/java/org/oppia/app/fragment/FragmentComponent.kt @@ -10,6 +10,7 @@ import org.oppia.app.player.audio.AudioFragment import org.oppia.app.profile.AddProfileFragment import org.oppia.app.profile.AdminAuthFragment import org.oppia.app.profile.ProfileChooserFragment +import org.oppia.app.story.StoryFragment import org.oppia.app.testing.BindableAdapterTestFragment import org.oppia.app.topic.TopicFragment import org.oppia.app.topic.conceptcard.ConceptCardFragment @@ -25,23 +26,26 @@ import org.oppia.app.topic.train.TopicTrainFragment interface FragmentComponent { @Subcomponent.Builder interface Builder { - @BindsInstance fun setFragment(fragment: Fragment): Builder + @BindsInstance + fun setFragment(fragment: Fragment): Builder + fun build(): FragmentComponent } + fun inject(addProfileFragment: AddProfileFragment) + fun inject(adminAuthFragment: AdminAuthFragment) fun inject(audioFragment: AudioFragment) + fun inject(bindableAdapterTestFragment: BindableAdapterTestFragment) fun inject(conceptCardFragment: ConceptCardFragment) fun inject(explorationFragment: ExplorationFragment) fun inject(homeFragment: HomeFragment) + fun inject(profileChooserFragment: ProfileChooserFragment) fun inject(questionPlayerFragment: QuestionPlayerFragment) fun inject(stateFragment: StateFragment) - fun inject(bindableAdapterTestFragment: BindableAdapterTestFragment) + fun inject(storyFragment: StoryFragment) fun inject(topicFragment: TopicFragment) fun inject(topicOverviewFragment: TopicOverviewFragment) fun inject(topicPlayFragment: TopicPlayFragment) fun inject(topicReviewFragment: TopicReviewFragment) fun inject(topicTrainFragment: TopicTrainFragment) - fun inject(profileChooserFragment: ProfileChooserFragment) - fun inject(adminAuthFragment: AdminAuthFragment) - fun inject(addProfileFragment: AddProfileFragment) } diff --git a/app/src/main/java/org/oppia/app/story/StoryActivity.kt b/app/src/main/java/org/oppia/app/story/StoryActivity.kt new file mode 100644 index 00000000000..63e9178f5c9 --- /dev/null +++ b/app/src/main/java/org/oppia/app/story/StoryActivity.kt @@ -0,0 +1,29 @@ +package org.oppia.app.story + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import org.oppia.app.activity.InjectableAppCompatActivity +import javax.inject.Inject + +/** Activity for stories. */ +class StoryActivity : InjectableAppCompatActivity() { + @Inject lateinit var storyActivityPresenter: StoryActivityPresenter + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activityComponent.inject(this) + storyActivityPresenter.handleOnCreate() + } + + companion object { + const val STORY_ACTIVITY_STORY_ID_ARGUMENT_KEY = "StoryActivity.story_id" + + /** Returns a new [Intent] to route to [StoryActivity] for a specified story ID. */ + fun createStoryActivityIntent(context: Context, storyId: String): Intent { + val intent = Intent(context, StoryActivity::class.java) + intent.putExtra(STORY_ACTIVITY_STORY_ID_ARGUMENT_KEY, storyId) + return intent + } + } +} diff --git a/app/src/main/java/org/oppia/app/story/StoryActivityPresenter.kt b/app/src/main/java/org/oppia/app/story/StoryActivityPresenter.kt new file mode 100644 index 00000000000..e867d336650 --- /dev/null +++ b/app/src/main/java/org/oppia/app/story/StoryActivityPresenter.kt @@ -0,0 +1,24 @@ +package org.oppia.app.story + +import androidx.appcompat.app.AppCompatActivity +import org.oppia.app.R +import org.oppia.app.activity.ActivityScope +import javax.inject.Inject + +/** The presenter for [StoryActivity]. */ +@ActivityScope +class StoryActivityPresenter @Inject constructor(private val activity: AppCompatActivity) { + fun handleOnCreate() { + activity.setContentView(R.layout.story_activity) + if (getStoryFragment() == null) { + activity.supportFragmentManager.beginTransaction().add( + R.id.story_fragment_placeholder, + StoryFragment() + ).commitNow() + } + } + + private fun getStoryFragment(): StoryFragment? { + return activity.supportFragmentManager.findFragmentById(R.id.story_fragment_placeholder) as StoryFragment? + } +} diff --git a/app/src/main/java/org/oppia/app/story/StoryFragment.kt b/app/src/main/java/org/oppia/app/story/StoryFragment.kt new file mode 100644 index 00000000000..6938d216a6d --- /dev/null +++ b/app/src/main/java/org/oppia/app/story/StoryFragment.kt @@ -0,0 +1,24 @@ +package org.oppia.app.story + +import android.content.Context +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import org.oppia.app.fragment.InjectableFragment +import javax.inject.Inject + +/** Fragment that displays story with chapter list. */ +class StoryFragment : InjectableFragment() { + @Inject + lateinit var storyFragmentPresenter: StoryFragmentPresenter + + override fun onAttach(context: Context?) { + super.onAttach(context) + fragmentComponent.inject(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + return storyFragmentPresenter.handleCreateView(inflater, container) + } +} diff --git a/app/src/main/java/org/oppia/app/story/StoryFragmentPresenter.kt b/app/src/main/java/org/oppia/app/story/StoryFragmentPresenter.kt new file mode 100644 index 00000000000..5d9404ca29a --- /dev/null +++ b/app/src/main/java/org/oppia/app/story/StoryFragmentPresenter.kt @@ -0,0 +1,23 @@ +package org.oppia.app.story + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.fragment.app.Fragment +import org.oppia.app.databinding.StoryFragmentBinding +import org.oppia.app.fragment.FragmentScope +import javax.inject.Inject + +/** The presenter for [StoryFragment]. */ +@FragmentScope +class StoryFragmentPresenter @Inject constructor( + private val fragment: Fragment +) { + fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { + val binding = StoryFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) + binding.let { + it.lifecycleOwner = fragment + } + return binding.root + } +} diff --git a/app/src/main/java/org/oppia/app/topic/RouteToStoryListener.kt b/app/src/main/java/org/oppia/app/topic/RouteToStoryListener.kt new file mode 100755 index 00000000000..efd5b10d063 --- /dev/null +++ b/app/src/main/java/org/oppia/app/topic/RouteToStoryListener.kt @@ -0,0 +1,6 @@ +package org.oppia.app.topic + +/** Listener for when an [TopicActivity] should route to a [StoryActivity]. */ +interface RouteToStoryListener { + fun routeToStory(storyId: String) +} diff --git a/app/src/main/java/org/oppia/app/topic/TopicActivity.kt b/app/src/main/java/org/oppia/app/topic/TopicActivity.kt index 0b0ad44d29e..b4bb533aa44 100644 --- a/app/src/main/java/org/oppia/app/topic/TopicActivity.kt +++ b/app/src/main/java/org/oppia/app/topic/TopicActivity.kt @@ -2,13 +2,15 @@ package org.oppia.app.topic import android.os.Bundle import org.oppia.app.activity.InjectableAppCompatActivity +import org.oppia.app.story.StoryActivity import org.oppia.app.topic.conceptcard.ConceptCardFragment import org.oppia.app.topic.questionplayer.QuestionPlayerActivity import javax.inject.Inject /** The activity for tabs in Topic. */ + class TopicActivity : InjectableAppCompatActivity(), RouteToQuestionPlayerListener, RouteToConceptCardListener, - RouteToTopicPlayListener { + RouteToTopicPlayListener, RouteToStoryListener { @Inject lateinit var topicActivityPresenter: TopicActivityPresenter @@ -22,6 +24,10 @@ class TopicActivity : InjectableAppCompatActivity(), RouteToQuestionPlayerListen startActivity(QuestionPlayerActivity.createQuestionPlayerActivityIntent(this, skillIdList)) } + override fun routeToStory(storyId: String) { + startActivity(StoryActivity.createStoryActivityIntent(this, storyId)) + } + override fun routeToTopicPlayFragment() { // TODO(#135): Change to play tab in this function. } diff --git a/app/src/main/java/org/oppia/app/topic/TopicFragmentPresenter.kt b/app/src/main/java/org/oppia/app/topic/TopicFragmentPresenter.kt index 24e7b205070..4976ed43017 100644 --- a/app/src/main/java/org/oppia/app/topic/TopicFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/app/topic/TopicFragmentPresenter.kt @@ -8,7 +8,7 @@ import org.oppia.app.databinding.TopicFragmentBinding import org.oppia.app.fragment.FragmentScope import javax.inject.Inject -/** The controller for [TopicFragment]. */ +/** The presenter for [TopicFragment]. */ @FragmentScope class TopicFragmentPresenter @Inject constructor( private val fragment: Fragment diff --git a/app/src/main/java/org/oppia/app/topic/play/StorySummaryAdapter.kt b/app/src/main/java/org/oppia/app/topic/play/StorySummaryAdapter.kt new file mode 100644 index 00000000000..99de7512d37 --- /dev/null +++ b/app/src/main/java/org/oppia/app/topic/play/StorySummaryAdapter.kt @@ -0,0 +1,46 @@ +package org.oppia.app.topic.play + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.databinding.DataBindingUtil +import androidx.databinding.library.baseAdapters.BR +import androidx.recyclerview.widget.RecyclerView +import org.oppia.app.R +import org.oppia.app.databinding.TopicPlayStorySummaryBinding +import org.oppia.app.model.StorySummary + +// TODO(#216): Make use of generic data-binding-enabled RecyclerView adapter. +/** Adapter to bind StorySummary to [RecyclerView] inside [TopicPlayFragment]. */ +class StorySummaryAdapter( + private var storyList: MutableList, + private val storySummarySelector: StorySummarySelector +) : + RecyclerView.Adapter() { + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StorySummaryViewHolder { + val storySummaryListItemBinding = DataBindingUtil.inflate( + LayoutInflater.from(parent.context), + R.layout.topic_play_story_summary, parent, + /* attachToRoot= */ false + ) + return StorySummaryViewHolder(storySummaryListItemBinding) + } + + override fun onBindViewHolder(storySummaryViewHolder: StorySummaryViewHolder, i: Int) { + storySummaryViewHolder.bind(storyList[i], i) + } + + override fun getItemCount(): Int { + return storyList.size + } + + inner class StorySummaryViewHolder(private val binding: TopicPlayStorySummaryBinding) : + RecyclerView.ViewHolder(binding.root) { + internal fun bind(storySummary: StorySummary, @Suppress("UNUSED_PARAMETER") position: Int) { + binding.setVariable(BR.storySummary, storySummary) + binding.root.setOnClickListener { + storySummarySelector.selectedStorySummary(storySummary) + } + } + } +} diff --git a/app/src/main/java/org/oppia/app/topic/play/StorySummarySelector.kt b/app/src/main/java/org/oppia/app/topic/play/StorySummarySelector.kt new file mode 100644 index 00000000000..f7974b3ae90 --- /dev/null +++ b/app/src/main/java/org/oppia/app/topic/play/StorySummarySelector.kt @@ -0,0 +1,8 @@ +package org.oppia.app.topic.play + +import org.oppia.app.model.StorySummary + +/** Interface to transfer the selected story summary to [TopicPlayFragmentPresenter]. */ +interface StorySummarySelector { + fun selectedStorySummary(storySummary: StorySummary) +} diff --git a/app/src/main/java/org/oppia/app/topic/play/TopicPlayFragmentPresenter.kt b/app/src/main/java/org/oppia/app/topic/play/TopicPlayFragmentPresenter.kt index fd863ef33a0..3c989d6c1b7 100644 --- a/app/src/main/java/org/oppia/app/topic/play/TopicPlayFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/app/topic/play/TopicPlayFragmentPresenter.kt @@ -3,21 +3,73 @@ package org.oppia.app.topic.play import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.Transformations import org.oppia.app.databinding.TopicPlayFragmentBinding import org.oppia.app.fragment.FragmentScope +import org.oppia.app.model.StorySummary +import org.oppia.app.model.Topic +import org.oppia.app.topic.RouteToStoryListener +import org.oppia.domain.topic.TEST_TOPIC_ID_0 +import org.oppia.domain.topic.TopicController +import org.oppia.util.data.AsyncResult +import org.oppia.util.logging.Logger import javax.inject.Inject /** The presenter for [TopicPlayFragment]. */ @FragmentScope class TopicPlayFragmentPresenter @Inject constructor( - private val fragment: Fragment -) { + activity: AppCompatActivity, + private val fragment: Fragment, + private val logger: Logger, + private val topicController: TopicController +) : StorySummarySelector { + + private val routeToStoryListener = activity as RouteToStoryListener + + private lateinit var binding: TopicPlayFragmentBinding + fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { - val binding = TopicPlayFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) + binding = TopicPlayFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) + binding.let { it.lifecycleOwner = fragment } + subscribeToTopicLiveData() return binding.root } + + private val topicLiveData: LiveData by lazy { getTopicList() } + + // TODO(#135): Get this topic-id or get storyList from [StoryFragment]. + private val topicResultLiveData: LiveData> by lazy { + topicController.getTopic(TEST_TOPIC_ID_0) + } + + private fun subscribeToTopicLiveData() { + topicLiveData.observe(fragment, Observer { + val storySummaryAdapter = StorySummaryAdapter(it.storyList, this as StorySummarySelector) + binding.storySummaryRecyclerView.apply { + adapter = storySummaryAdapter + } + }) + } + + private fun getTopicList(): LiveData { + return Transformations.map(topicResultLiveData, ::processTopicResult) + } + + private fun processTopicResult(topic: AsyncResult): Topic { + if (topic.isFailure()) { + logger.e("TopicPlayFragment", "Failed to retrieve topic", topic.getErrorOrNull()!!) + } + return topic.getOrDefault(Topic.getDefaultInstance()) + } + + override fun selectedStorySummary(storySummary: StorySummary) { + routeToStoryListener.routeToStory(storySummary.storyId) + } } diff --git a/app/src/main/res/drawable/circular_progress.xml b/app/src/main/res/drawable/circular_progress.xml new file mode 100755 index 00000000000..def50eeaa3e --- /dev/null +++ b/app/src/main/res/drawable/circular_progress.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml new file mode 100644 index 00000000000..b7de895ec0f --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_down_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml new file mode 100644 index 00000000000..16a9974a1a7 --- /dev/null +++ b/app/src/main/res/drawable/ic_keyboard_arrow_up_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/layout/story_activity.xml b/app/src/main/res/layout/story_activity.xml new file mode 100644 index 00000000000..4c2d686433c --- /dev/null +++ b/app/src/main/res/layout/story_activity.xml @@ -0,0 +1,8 @@ + + diff --git a/app/src/main/res/layout/story_fragment.xml b/app/src/main/res/layout/story_fragment.xml new file mode 100644 index 00000000000..e9b0824c1b7 --- /dev/null +++ b/app/src/main/res/layout/story_fragment.xml @@ -0,0 +1,18 @@ + + + + + + diff --git a/app/src/main/res/layout/topic_play_fragment.xml b/app/src/main/res/layout/topic_play_fragment.xml index e9b0824c1b7..6a6aaba035e 100644 --- a/app/src/main/res/layout/topic_play_fragment.xml +++ b/app/src/main/res/layout/topic_play_fragment.xml @@ -1,18 +1,20 @@ - - + + app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout/topic_play_story_summary.xml b/app/src/main/res/layout/topic_play_story_summary.xml new file mode 100644 index 00000000000..27dc2d14906 --- /dev/null +++ b/app/src/main/res/layout/topic_play_story_summary.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index bb9d73eb258..f33f78064f6 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -25,6 +25,14 @@ LEARN AGAIN See More (%s MB) + + + 1 Chapter + + + %d Chapters + + 1 Story diff --git a/app/src/sharedTest/java/org/oppia/app/topic/play/TopicPlayFragmentTest.kt b/app/src/sharedTest/java/org/oppia/app/topic/play/TopicPlayFragmentTest.kt index 7c6f9a4b465..87aeed9e9a1 100644 --- a/app/src/sharedTest/java/org/oppia/app/topic/play/TopicPlayFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/app/topic/play/TopicPlayFragmentTest.kt @@ -2,21 +2,37 @@ package org.oppia.app.topic.play import android.app.Application import android.content.Context -import androidx.test.core.app.ActivityScenario +import android.content.res.Configuration import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.action.ViewActions +import androidx.test.espresso.action.ViewActions.click import androidx.test.espresso.assertion.ViewAssertions.matches -import androidx.test.espresso.matcher.ViewMatchers.withId +import androidx.test.espresso.intent.Intents +import androidx.test.espresso.intent.Intents.intended +import androidx.test.espresso.intent.matcher.IntentMatchers +import androidx.test.espresso.intent.matcher.IntentMatchers.hasComponent +import androidx.test.espresso.intent.matcher.IntentMatchers.hasExtra +import androidx.test.espresso.matcher.ViewMatchers +import androidx.test.espresso.matcher.ViewMatchers.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.withText import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.rule.ActivityTestRule import dagger.BindsInstance import dagger.Component import dagger.Module import dagger.Provides import kotlinx.coroutines.CoroutineDispatcher +import org.hamcrest.Matchers.containsString +import org.junit.After +import org.junit.Before +import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith import org.oppia.app.R +import org.oppia.app.recyclerview.RecyclerViewMatcher.Companion.atPosition +import org.oppia.app.story.StoryActivity import org.oppia.app.topic.TopicActivity +import org.oppia.app.topic.questionplayer.QuestionPlayerActivity import org.oppia.util.threading.BackgroundDispatcher import org.oppia.util.threading.BlockingDispatcher import javax.inject.Singleton @@ -25,11 +41,81 @@ import javax.inject.Singleton @RunWith(AndroidJUnit4::class) class TopicPlayFragmentTest { + // TODO(#137): Add following test-cases once story-progress function is implemented and expandable list is introduced. + // - Story progress is displayed correctly. + // - Click on arrow to show and hide expandable list is working correctly. + // - Expandable list is showing correct chapter names. + // - Upon configuration change expanded list should remain expanded. + // - Click on story-title or entire item should open [StoryActivity]. + // - Click on chapter in expandable list should start exploration. + + @get:Rule + var activityTestRule: ActivityTestRule = ActivityTestRule( + TopicActivity::class.java, /* initialTouchMode= */ true, /* launchActivity= */ false + ) + private var storyId = "test_story_id_0" + + @Before + fun setUp() { + Intents.init() + } + @Test - fun testTopicPlayFragment_loadFragment_textIsDisplayed() { - ActivityScenario.launch(TopicActivity::class.java).use { - onView(withId(R.id.dummy_text_view)).check(matches(withText("This is dummy TextView for testing"))) - } + fun testTopicPlayFragment_loadFragmentWithTopicTestId0_storyName_isCorrect() { + activityTestRule.launchActivity(null) + onView( + atPosition( + R.id.story_summary_recycler_view, + 0 + ) + ).check(matches(hasDescendant(withText(containsString("First Story"))))) + } + + @Test + fun testTopicPlayFragment_loadFragmentWithTopicTestId0_chapterCountTextSingle_isCorrect() { + activityTestRule.launchActivity(null) + onView( + atPosition( + R.id.story_summary_recycler_view, + 0 + ) + ).check(matches(hasDescendant(withText(containsString("1 Chapter"))))) + } + + @Test + fun testTopicPlayFragment_loadFragmentWithTopicTestId0_chapterCountTextMultiple_isCorrect() { + activityTestRule.launchActivity(null) + onView( + atPosition( + R.id.story_summary_recycler_view, + 1 + ) + ).check(matches(hasDescendant(withText(containsString("3 Chapters"))))) + } + + @Test + fun testTopicPlayFragment_loadFragmentWithTopicTestId0_configurationChange_storyName_isCorrect() { + activityTestRule.launchActivity(null) + activityTestRule.activity.requestedOrientation = Configuration.ORIENTATION_LANDSCAPE + onView( + atPosition( + R.id.story_summary_recycler_view, + 0 + ) + ).check(matches(hasDescendant(withText(containsString("First Story"))))) + } + + @Test + fun testTopicPlayFragment_loadFragmentWithTopicTestId0_clickStoryItem_opensStoryActivityWithCorrectIntent() { + activityTestRule.launchActivity(null) + onView(atPosition(R.id.story_summary_recycler_view, 0)).perform(click()) + intended(hasComponent(StoryActivity::class.java.name)) + intended(hasExtra(StoryActivity.STORY_ACTIVITY_STORY_ID_ARGUMENT_KEY, storyId)) + } + + @After + fun tearDown() { + Intents.release() } @Module