From a979440d9402c0915556e1a2df1616dc09c75c4c Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Mon, 7 Dec 2020 20:01:01 -0800 Subject: [PATCH 001/248] Use BindableAdapter for displaying Welcome layout, still updating PromotedStoryList layout --- .../android/app/home/HomeFragmentPresenter.kt | 187 +++++++++++------- .../android/app/home/WelcomeViewModel.kt | 53 ++++- .../topiclist/PromotedStoryListViewModel.kt | 79 +++++++- app/src/main/res/layout/all_topics.xml | 6 + app/src/main/res/layout/welcome.xml | 2 +- 5 files changed, 246 insertions(+), 81 deletions(-) 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 39a2d07e6d1..3d27f2ddb67 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 @@ -1,5 +1,6 @@ package org.oppia.android.app.home +import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -9,10 +10,12 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Observer import androidx.lifecycle.Transformations import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.LinearLayoutManager import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel +import org.oppia.android.app.home.topiclist.PromotedStoryListAdapter import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicListAdapter @@ -20,19 +23,22 @@ import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.OngoingStoryList -import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.IntentFactoryShim +import org.oppia.android.app.viewmodel.ViewModelProvider +import org.oppia.android.databinding.AllTopicsBinding +import org.oppia.android.databinding.PromotedStoryListBinding +import org.oppia.android.databinding.TopicSummaryViewBinding +import org.oppia.android.databinding.WelcomeBinding import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger -import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData -import org.oppia.android.util.datetime.DateTimeUtil -import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.StoryHtmlParserEntityType import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock @@ -43,10 +49,12 @@ import javax.inject.Inject class HomeFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - private val profileManagementController: ProfileManagementController, + private val WelcomeViewModelProvider: ViewModelProvider, + private val HomeItemViewModelProvider: ViewModelProvider, + private val PromotedStoryListViewModelProvider: ViewModelProvider, + private val AllTopicsViewModelProvider: ViewModelProvider, private val topicListController: TopicListController, private val oppiaClock: OppiaClock, - private val logger: ConsoleLogger, private val oppiaLogger: OppiaLogger, private val intentFactoryShim: IntentFactoryShim, @TopicHtmlParserEntityType private val topicEntityType: String, @@ -54,36 +62,33 @@ class HomeFragmentPresenter @Inject constructor( ) { private val routeToTopicListener = activity as RouteToTopicListener private val itemList: MutableList = ArrayList() - private val promotedStoryList: MutableList = ArrayList() - private lateinit var welcomeViewModel: WelcomeViewModel - private lateinit var promotedStoryListViewModel: PromotedStoryListViewModel - private lateinit var allTopicsViewModel: AllTopicsViewModel - private lateinit var topicListAdapter: TopicListAdapter +// private val promotedStoryList: MutableList = ArrayList() private lateinit var binding: HomeFragmentBinding private var internalProfileId: Int = -1 private lateinit var profileId: ProfileId - private lateinit var profileName: String + private lateinit var topicListAdapter: TopicListAdapter + fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) // NB: Both the view model and lifecycle owner must be set in order to correctly bind LiveData elements to // data-bound view models. + val welcomeViewModel = getWelcomeViewModel() internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) - profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + welcomeViewModel.setInternalProfileId(internalProfileId) logHomeActivityEvent() - welcomeViewModel = WelcomeViewModel() - promotedStoryListViewModel = PromotedStoryListViewModel( - activity, - internalProfileId, - intentFactoryShim - ) - allTopicsViewModel = AllTopicsViewModel() + val promotedStoryListViewModel = getPromotedStoryListViewModel() + promotedStoryListViewModel.setInternalProfileId(internalProfileId) + promotedStoryListViewModel.setActivity(activity) + promotedStoryListViewModel.setIntentFactoryShim(intentFactoryShim) + val allTopicsViewModel = getAllTopicsViewModel() itemList.add(welcomeViewModel) itemList.add(promotedStoryListViewModel) itemList.add(allTopicsViewModel) - topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList) +// topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList) +// topicListAdapter = createRecyclerViewAdapter() val spanCount = activity.resources.getInteger(R.integer.home_span_count) topicListAdapter.setSpanCount(spanCount) @@ -100,7 +105,7 @@ class HomeFragmentPresenter @Inject constructor( } binding.homeRecyclerView.apply { - adapter = topicListAdapter + adapter = createRecyclerViewAdapter() // https://stackoverflow.com/a/32763434/32763621 layoutManager = homeLayoutManager } @@ -108,38 +113,103 @@ class HomeFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment } - subscribeToProfileLiveData() - subscribeToOngoingStoryList() - subscribeToTopicList() +// subscribeToOngoingStoryList() +// subscribeToTopicList() return binding.root } - private val profileLiveData: LiveData by lazy { - getProfileData() + private fun createRecyclerViewAdapter(): BindableAdapter { + return BindableAdapter.MultiTypeBuilder + .newBuilder { viewModel -> + when (viewModel) { + is WelcomeViewModel -> ViewType.VIEW_TYPE_WELCOME_MESSAGE + is PromotedStoryListViewModel -> ViewType.VIEW_TYPE_PROMOTED_STORY_LIST + is AllTopicsViewModel -> ViewType.VIEW_TYPE_ALL_TOPICS + is TopicSummaryViewModel -> ViewType.VIEW_TYPE_TOPIC_LIST + else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") + } + } + .registerViewDataBinder( + viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, + inflateDataBinding = WelcomeBinding::inflate, + setViewModel = WelcomeBinding::setViewModel, + transformViewModel = { it as WelcomeViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.VIEW_TYPE_PROMOTED_STORY_LIST, + inflateDataBinding = PromotedStoryListBinding::inflate, + setViewModel = this::bindPromotedStoryListView, + transformViewModel = { it as PromotedStoryListViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.VIEW_TYPE_ALL_TOPICS, + inflateDataBinding = AllTopicsBinding::inflate, + setViewModel = AllTopicsBinding::setViewModel, + transformViewModel = { it as AllTopicsViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.VIEW_TYPE_TOPIC_LIST, + inflateDataBinding = TopicSummaryViewBinding::inflate, + setViewModel = TopicSummaryViewBinding::setViewModel, + transformViewModel = { it as TopicSummaryViewModel } + ) + .build() } - private fun getProfileData(): LiveData { - return Transformations.map( - profileManagementController.getProfile(profileId).toLiveData(), - ::processGetProfileResult - ) + private fun bindPromotedStoryListView( + binding: PromotedStoryListBinding, + model: PromotedStoryListViewModel + ) { + binding.viewModel = model + if (activity.resources.getBoolean(R.bool.isTablet)) { + binding.itemCount = model.promotedStoryList.size + } + val promotedStoryAdapter = PromotedStoryListAdapter(activity, model.promotedStoryList) + val horizontalLayoutManager = + LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) + binding.promotedStoryListRecyclerView.apply { + layoutManager = horizontalLayoutManager + adapter = promotedStoryAdapter + } + + /* + * The StartSnapHelper is used to snap between items rather than smooth scrolling, + * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. + */ + val snapHelper = StartSnapHelper() + binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager + binding.promotedStoryListRecyclerView.setOnFlingListener(null) + snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) + + val paddingEnd = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) + val paddingStart = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) + if (model.promotedStoryList.size > 1) { + binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) + } else { + binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) + } } - private fun subscribeToProfileLiveData() { - profileLiveData.observe( - activity, - Observer { result -> - profileName = result.name - setProfileName() - } - ) + private enum class ViewType { + VIEW_TYPE_WELCOME_MESSAGE, + VIEW_TYPE_PROMOTED_STORY_LIST, + VIEW_TYPE_ALL_TOPICS, + VIEW_TYPE_TOPIC_LIST } - private fun processGetProfileResult(profileResult: AsyncResult): Profile { - if (profileResult.isFailure()) { - logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) - } - return profileResult.getOrDefault(Profile.getDefaultInstance()) + private fun getWelcomeViewModel(): WelcomeViewModel { + return WelcomeViewModelProvider.getForFragment(fragment, WelcomeViewModel::class.java) + } + + private fun getPromotedStoryListViewModel(): PromotedStoryListViewModel { + return PromotedStoryListViewModelProvider + .getForFragment(fragment, PromotedStoryListViewModel::class.java) + } + + private fun getAllTopicsViewModel(): AllTopicsViewModel { + return AllTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) } private val topicListSummaryResultLiveData: LiveData> by lazy { @@ -171,24 +241,6 @@ class HomeFragmentPresenter @Inject constructor( } } - private fun setProfileName() { - if (::welcomeViewModel.isInitialized && ::profileName.isInitialized) { - welcomeViewModel.profileName.set(profileName) - welcomeViewModel.greeting.set( - DateTimeUtil( - fragment.requireContext(), - oppiaClock - ).getGreetingMessage() - ) - } - } - - private val ongoingStoryListSummaryResultLiveData: - LiveData> - by lazy { - topicListController.getOngoingStoryList(profileId).toLiveData() - } - private fun subscribeToOngoingStoryList() { val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) getAssumedSuccessfulOngoingStoryList().observe( @@ -224,15 +276,6 @@ class HomeFragmentPresenter @Inject constructor( ) } - private fun getAssumedSuccessfulOngoingStoryList(): LiveData { - // If there's an error loading the data, assume the default. - return Transformations.map(ongoingStoryListSummaryResultLiveData) { - it.getOrDefault( - OngoingStoryList.getDefaultInstance() - ) - } - } - fun onTopicSummaryClicked(topicSummary: TopicSummary) { routeToTopicListener.routeToTopic(internalProfileId, topicSummary.topicId) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index bf207c1931f..d9ca70554ed 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -1,10 +1,55 @@ package org.oppia.android.app.home -import androidx.databinding.ObservableField +import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel +import org.oppia.android.app.model.Profile +import org.oppia.android.app.model.ProfileId +import org.oppia.android.domain.profile.ProfileManagementController +import org.oppia.android.util.logging.ConsoleLogger +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.datetime.DateTimeUtil +import org.oppia.android.util.system.OppiaClock +import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ -class WelcomeViewModel : HomeItemViewModel() { - val profileName = ObservableField("") - val greeting = ObservableField("") +class WelcomeViewModel @Inject constructor( + private val logger: ConsoleLogger, + private val fragment: Fragment, + private val oppiaClock: OppiaClock, + private val profileManagementController: ProfileManagementController + ) : HomeItemViewModel() { + private lateinit var profileId: ProfileId + lateinit var greeting: String + + val profileNameLiveData: LiveData by lazy { + Transformations.map(profileLiveData, Profile::getName) + } + + private val profileResultLiveData: LiveData> by lazy { + profileManagementController.getProfile(profileId).toLiveData() + } + + private val profileLiveData: LiveData by lazy { + Transformations.map( + profileResultLiveData, + ::processGetProfileResult) + } + + private fun processGetProfileResult(profileResult: AsyncResult): Profile { + if (profileResult.isFailure()) { + logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) + } + greeting = DateTimeUtil( + fragment.requireContext(), + oppiaClock + ).getGreetingMessage() + return profileResult.getOrDefault(Profile.getDefaultInstance()) + } + + fun setInternalProfileId(internalProfileId: Int) { + this.profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 7ec5abd4850..6fd523d18bc 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,29 +1,100 @@ package org.oppia.android.app.home.topiclist import androidx.appcompat.app.AppCompatActivity +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel +import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener +import org.oppia.android.app.model.OngoingStoryList +import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.TopicList import org.oppia.android.app.shim.IntentFactoryShim +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.parser.StoryHtmlParserEntityType /** [ViewModel] promoted story list in [HomeFragment]. */ class PromotedStoryListViewModel( - private val activity: AppCompatActivity, - private val internalProfileId: Int, - private val IntentFactoryShim: IntentFactoryShim + private var activity: AppCompatActivity, + private var internalProfileId: Int, + private var intentFactoryShim: IntentFactoryShim, + private val topicListController: TopicListController, + @StoryHtmlParserEntityType private val storyEntityType: String ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { + val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + + var promotedStoryList: LiveData> by lazy { + promotedStoryList.clear() + if (assumedSuccessfulOngoingStoryListLiveData.recentStoryCount != 0) { + assumedSuccessfulOngoingStoryListLiveData.recentStoryList.take(limit) + .forEach { promotedStory -> + val recentStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + recentStory.setPromotedStory(promotedStory) + promotedStoryList.add(recentStory) + } + } else { + // TODO(#936): Optimise this as part of recommended stories. + assumedSuccessfulOngoingStoryListLiveData.olderStoryList.take(limit).forEach { promotedStory -> + val oldStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + oldStory.setPromotedStory(promotedStory) + promotedStoryList.add(oldStory) + } + } + } + + private val ongoingStoryListSummaryResultLiveData: + LiveData> by lazy { + topicListController.getOngoingStoryList( + ProfileId.newBuilder().setInternalId(internalProfileId).build() + ).toLiveData() + } + + private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(ongoingStoryListSummaryResultLiveData) { + it.getOrDefault( + OngoingStoryList.getDefaultInstance() + ) + } +// processPromotedStoryList() + } fun clickOnViewAll() { routeToRecentlyPlayed() } override fun routeToRecentlyPlayed() { - val intent = IntentFactoryShim.createRecentlyPlayedActivityIntent( + val intent = intentFactoryShim.createRecentlyPlayedActivityIntent( activity.applicationContext, internalProfileId ) activity.startActivity(intent) } + + fun setInternalProfileId(internalProfileId: Int) { + this.internalProfileId = internalProfileId + } + + fun setActivity(activity: AppCompatActivity) { + this.activity = activity; + } + + fun setIntentFactoryShim(intentFactoryShim: IntentFactoryShim) { + this.intentFactoryShim = intentFactoryShim + } } diff --git a/app/src/main/res/layout/all_topics.xml b/app/src/main/res/layout/all_topics.xml index ac5226506e9..b672a2e5365 100644 --- a/app/src/main/res/layout/all_topics.xml +++ b/app/src/main/res/layout/all_topics.xml @@ -1,5 +1,11 @@ + + + + Date: Tue, 8 Dec 2020 10:30:28 -0800 Subject: [PATCH 002/248] Refactor PromotedStoryListViewModel to update using BindableAdapter --- .../android/app/home/HomeFragmentPresenter.kt | 42 +------------- .../topiclist/PromotedStoryListViewModel.kt | 55 ++++++++++--------- 2 files changed, 33 insertions(+), 64 deletions(-) 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 3d27f2ddb67..aee21045611 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 @@ -113,7 +113,6 @@ class HomeFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment } -// subscribeToOngoingStoryList() // subscribeToTopicList() return binding.root } @@ -162,9 +161,9 @@ class HomeFragmentPresenter @Inject constructor( ) { binding.viewModel = model if (activity.resources.getBoolean(R.bool.isTablet)) { - binding.itemCount = model.promotedStoryList.size + binding.itemCount = model.promotedStoryListLiveData.value!!.size } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, model.promotedStoryList) + val promotedStoryAdapter = PromotedStoryListAdapter(activity, model.promotedStoryListLiveData.value!!) val horizontalLayoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) binding.promotedStoryListRecyclerView.apply { @@ -185,7 +184,7 @@ class HomeFragmentPresenter @Inject constructor( (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) val paddingStart = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) - if (model.promotedStoryList.size > 1) { + if (model.promotedStoryListLiveData.value!!.size > 1) { binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) } else { binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) @@ -241,41 +240,6 @@ class HomeFragmentPresenter @Inject constructor( } } - private fun subscribeToOngoingStoryList() { - val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) - getAssumedSuccessfulOngoingStoryList().observe( - fragment, - Observer { - promotedStoryList.clear() - if (it.recentStoryCount != 0) { - it.recentStoryList.take(limit).forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - recentStory.setPromotedStory(promotedStory) - promotedStoryList.add(recentStory) - } - } else { - // TODO(#936): Optimise this as part of recommended stories. - it.olderStoryList.take(limit).forEach { promotedStory -> - val oldStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - oldStory.setPromotedStory(promotedStory) - promotedStoryList.add(oldStory) - } - } - topicListAdapter.notifyItemChanged(1) - } - ) - } - fun onTopicSummaryClicked(topicSummary: TopicSummary) { routeToTopicListener.routeToTopic(internalProfileId, topicSummary.topicId) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 6fd523d18bc..94bab987064 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -28,37 +28,43 @@ class PromotedStoryListViewModel( RouteToRecentlyPlayedListener { val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) - var promotedStoryList: LiveData> by lazy { - promotedStoryList.clear() - if (assumedSuccessfulOngoingStoryListLiveData.recentStoryCount != 0) { - assumedSuccessfulOngoingStoryListLiveData.recentStoryList.take(limit) + val promotedStoryListLiveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processList) + } + + private fun processList(it: OngoingStoryList): MutableList { + var newPromotedStoryList: MutableList = ArrayList() + if (it.recentStoryCount != 0) { + it.recentStoryList.take(limit) .forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - recentStory.setPromotedStory(promotedStory) - promotedStoryList.add(recentStory) + val recentStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + recentStory.setPromotedStory(promotedStory) + newPromotedStoryList.add(recentStory) } } else { // TODO(#936): Optimise this as part of recommended stories. - assumedSuccessfulOngoingStoryListLiveData.olderStoryList.take(limit).forEach { promotedStory -> - val oldStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - oldStory.setPromotedStory(promotedStory) - promotedStoryList.add(oldStory) + it.olderStoryList.take(limit) + .forEach { promotedStory -> + val oldStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + oldStory.setPromotedStory(promotedStory) + newPromotedStoryList.add(oldStory) + } } - } + return newPromotedStoryList } - private val ongoingStoryListSummaryResultLiveData: - LiveData> by lazy { + private val ongoingStoryListSummaryResultLiveData: LiveData> + by lazy { topicListController.getOngoingStoryList( ProfileId.newBuilder().setInternalId(internalProfileId).build() ).toLiveData() @@ -71,7 +77,6 @@ class PromotedStoryListViewModel( OngoingStoryList.getDefaultInstance() ) } -// processPromotedStoryList() } fun clickOnViewAll() { From 4a1b0b47992d1944daa800d865ab1e5b20281b16 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Tue, 8 Dec 2020 12:49:24 -0800 Subject: [PATCH 003/248] Migrate TopicListViewHolder logic --- .../android/app/home/HomeFragmentPresenter.kt | 119 +++++++++++++++--- .../android/app/home/WelcomeViewModel.kt | 2 +- .../app/home/topiclist/AllTopicsViewModel.kt | 4 +- .../topiclist/PromotedStoryListViewModel.kt | 9 +- .../home/topiclist/TopicSummaryViewModel.kt | 5 + app/src/main/res/layout/welcome.xml | 2 +- 6 files changed, 116 insertions(+), 25 deletions(-) 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 aee21045611..bfecfe82f8a 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 @@ -11,6 +11,7 @@ import androidx.lifecycle.Observer 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.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope @@ -49,10 +50,9 @@ import javax.inject.Inject class HomeFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - private val WelcomeViewModelProvider: ViewModelProvider, - private val HomeItemViewModelProvider: ViewModelProvider, - private val PromotedStoryListViewModelProvider: ViewModelProvider, - private val AllTopicsViewModelProvider: ViewModelProvider, + private val welcomeViewModelProvider: ViewModelProvider, + private val promotedStoryListViewModelProvider: ViewModelProvider, + private val allTopicsViewModelProvider: ViewModelProvider, private val topicListController: TopicListController, private val oppiaClock: OppiaClock, private val oppiaLogger: OppiaLogger, @@ -62,12 +62,10 @@ class HomeFragmentPresenter @Inject constructor( ) { private val routeToTopicListener = activity as RouteToTopicListener private val itemList: MutableList = ArrayList() -// private val promotedStoryList: MutableList = ArrayList() private lateinit var binding: HomeFragmentBinding private var internalProfileId: Int = -1 - private lateinit var profileId: ProfileId - private lateinit var topicListAdapter: TopicListAdapter - +// private lateinit var topicListAdapter: TopicListAdapter + private var spanCount = 0 fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) @@ -87,11 +85,7 @@ class HomeFragmentPresenter @Inject constructor( itemList.add(welcomeViewModel) itemList.add(promotedStoryListViewModel) itemList.add(allTopicsViewModel) -// topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList) -// topicListAdapter = createRecyclerViewAdapter() - - val spanCount = activity.resources.getInteger(R.integer.home_span_count) - topicListAdapter.setSpanCount(spanCount) + spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { @@ -113,7 +107,7 @@ class HomeFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment } -// subscribeToTopicList() + subscribeToTopicList() return binding.root } @@ -155,6 +149,95 @@ class HomeFragmentPresenter @Inject constructor( .build() } + inner class TopicListViewHolder(val binding: TopicSummaryViewBinding) : + RecyclerView.ViewHolder(binding.root) { + + internal fun bind(topicSummaryViewModel: TopicSummaryViewModel, position: Int) { + binding.viewModel = topicSummaryViewModel + + val marginLayoutParams = binding.topicContainer.layoutParams as ViewGroup.MarginLayoutParams + + val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) + + val marginTopBottom = + (activity as Context).resources + .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) + + val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) + + when (spanCount) { + 2 -> { + when { + position % spanCount == 0 -> marginLayoutParams.setMargins( + marginMin, + marginTopBottom, + marginMax, + marginTopBottom + ) + else -> marginLayoutParams.setMargins( + marginMax, + marginTopBottom, + marginMin, + marginTopBottom + ) + } + } + 3 -> { + when { + position % spanCount == 0 -> marginLayoutParams.setMargins( + marginMax, + marginTopBottom, + /* right= */ 0, + marginTopBottom + ) + position % spanCount == 1 -> marginLayoutParams.setMargins( + marginMin, + marginTopBottom, + marginMin, + marginTopBottom + ) + position % spanCount == 2 -> marginLayoutParams.setMargins( + /* left= */ 0, + marginTopBottom, + marginMax, + marginTopBottom + ) + } + } + 4 -> { + when { + (position + 1) % spanCount == 0 -> marginLayoutParams.setMargins( + marginMax, + marginTopBottom, + /* right= */ 0, + marginTopBottom + ) + (position + 1) % spanCount == 1 -> marginLayoutParams.setMargins( + marginMin, + marginTopBottom, + marginMin / 2, + marginTopBottom + ) + (position + 1) % spanCount == 2 -> marginLayoutParams.setMargins( + marginMin / 2, + marginTopBottom, + marginMin, + marginTopBottom + ) + (position + 1) % spanCount == 3 -> marginLayoutParams.setMargins( + /* left= */ 0, + marginTopBottom, + marginMax, + marginTopBottom + ) + } + } + } + binding.topicContainer.layoutParams = marginLayoutParams + } + + } + private fun bindPromotedStoryListView( binding: PromotedStoryListBinding, model: PromotedStoryListViewModel @@ -199,16 +282,16 @@ class HomeFragmentPresenter @Inject constructor( } private fun getWelcomeViewModel(): WelcomeViewModel { - return WelcomeViewModelProvider.getForFragment(fragment, WelcomeViewModel::class.java) + return welcomeViewModelProvider.getForFragment(fragment, WelcomeViewModel::class.java) } private fun getPromotedStoryListViewModel(): PromotedStoryListViewModel { - return PromotedStoryListViewModelProvider + return promotedStoryListViewModelProvider .getForFragment(fragment, PromotedStoryListViewModel::class.java) } private fun getAllTopicsViewModel(): AllTopicsViewModel { - return AllTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) + return allTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) } private val topicListSummaryResultLiveData: LiveData> by lazy { @@ -228,7 +311,7 @@ class HomeFragmentPresenter @Inject constructor( ) itemList.add(topicSummaryViewModel) } - topicListAdapter.notifyDataSetChanged() +// topicListAdapter.notifyDataSetChanged() } ) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index d9ca70554ed..4e47ddf2bb0 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -24,7 +24,7 @@ class WelcomeViewModel @Inject constructor( private lateinit var profileId: ProfileId lateinit var greeting: String - val profileNameLiveData: LiveData by lazy { + val profileName: LiveData by lazy { Transformations.map(profileLiveData, Profile::getName) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index 7e8e9a3777e..ee21db72364 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -2,6 +2,8 @@ package org.oppia.android.app.home.topiclist import androidx.lifecycle.ViewModel import org.oppia.android.app.home.HomeItemViewModel +import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel : HomeItemViewModel() +class AllTopicsViewModel @Inject constructor () +: HomeItemViewModel() {} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 94bab987064..a91cade3ea0 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -9,24 +9,24 @@ import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.model.TopicList import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.parser.StoryHtmlParserEntityType +import javax.inject.Inject /** [ViewModel] promoted story list in [HomeFragment]. */ -class PromotedStoryListViewModel( +class PromotedStoryListViewModel @Inject constructor( private var activity: AppCompatActivity, - private var internalProfileId: Int, private var intentFactoryShim: IntentFactoryShim, private val topicListController: TopicListController, @StoryHtmlParserEntityType private val storyEntityType: String ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { - val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + + private var internalProfileId: Int = -1 val promotedStoryListLiveData: LiveData> by lazy { Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processList) @@ -34,6 +34,7 @@ class PromotedStoryListViewModel( private fun processList(it: OngoingStoryList): MutableList { var newPromotedStoryList: MutableList = ArrayList() + val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) if (it.recentStoryCount != 0) { it.recentStoryList.take(limit) .forEach { promotedStory -> diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index d9c98ad9b42..e6a6b8fb698 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -2,8 +2,13 @@ package org.oppia.android.app.home.topiclist import android.graphics.Color import androidx.annotation.ColorInt +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import org.oppia.android.app.home.HomeItemViewModel +import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.data.AsyncResult // TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. // These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the diff --git a/app/src/main/res/layout/welcome.xml b/app/src/main/res/layout/welcome.xml index 5f4f29b06cd..61db279657c 100644 --- a/app/src/main/res/layout/welcome.xml +++ b/app/src/main/res/layout/welcome.xml @@ -34,7 +34,7 @@ android:ellipsize="end" android:maxLines="1" android:fontFamily="sans-serif" - android:text="@{String.format(@string/welcome_profile_name, viewModel.profileNameLiveData)}" + android:text="@{String.format(@string/welcome_profile_name, viewModel.profileName)}" android:textColor="@color/oppiaPrimaryText" android:textSize="24sp" app:layout_constraintEnd_toEndOf="parent" From 1ddbe5a0eb0a5ea202bc28e43ea9ea089456ba2a Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Tue, 8 Dec 2020 18:08:35 -0800 Subject: [PATCH 004/248] Bind TopicSummary padding and HomeItemList --- .../android/app/home/HomeFragmentPresenter.kt | 149 +++--------------- .../oppia/android/app/home/HomeViewModel.kt | 57 +++++++ .../topiclist/PromotedStoryListViewModel.kt | 4 +- .../app/home/topiclist/TopicListAdapter.kt | 4 +- .../home/topiclist/TopicSummaryViewModel.kt | 93 ++++++++++- app/src/main/res/layout/home_fragment.xml | 9 +- .../main/res/layout/topic_summary_view.xml | 4 + 7 files changed, 187 insertions(+), 133 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt 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 bfecfe82f8a..40ef7bffd87 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 @@ -53,19 +53,16 @@ class HomeFragmentPresenter @Inject constructor( private val welcomeViewModelProvider: ViewModelProvider, private val promotedStoryListViewModelProvider: ViewModelProvider, private val allTopicsViewModelProvider: ViewModelProvider, - private val topicListController: TopicListController, + private val topicSummaryViewModelProvider: ViewModelProvider, + private val homeViewModelProvider: ViewModelProvider, private val oppiaClock: OppiaClock, private val oppiaLogger: OppiaLogger, - private val intentFactoryShim: IntentFactoryShim, - @TopicHtmlParserEntityType private val topicEntityType: String, - @StoryHtmlParserEntityType private val storyEntityType: String + private val intentFactoryShim: IntentFactoryShim ) { private val routeToTopicListener = activity as RouteToTopicListener - private val itemList: MutableList = ArrayList() private lateinit var binding: HomeFragmentBinding private var internalProfileId: Int = -1 -// private lateinit var topicListAdapter: TopicListAdapter - private var spanCount = 0 +// private var spanCount = 0 fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) @@ -82,11 +79,16 @@ class HomeFragmentPresenter @Inject constructor( promotedStoryListViewModel.setActivity(activity) promotedStoryListViewModel.setIntentFactoryShim(intentFactoryShim) val allTopicsViewModel = getAllTopicsViewModel() - itemList.add(welcomeViewModel) - itemList.add(promotedStoryListViewModel) - itemList.add(allTopicsViewModel) - spanCount = activity.resources.getInteger(R.integer.home_span_count) - + val topicSummaryViewModel = getTopicSummaryViewModel() + topicSummaryViewModel.setSpanCount(activity.resources.getInteger(R.integer.home_span_count)) + val homeViewModel = getHomeViewModel() + homeViewModel.addHomeItem(welcomeViewModel) + homeViewModel.addHomeItem(promotedStoryListViewModel) + homeViewModel.addHomeItem(allTopicsViewModel) + + // make item list a live data list + // live data is going to compute topic list (remove observe and turn it into transformation for list of viewmodels) + val spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { @@ -107,7 +109,6 @@ class HomeFragmentPresenter @Inject constructor( it.lifecycleOwner = fragment } - subscribeToTopicList() return binding.root } @@ -149,94 +150,11 @@ class HomeFragmentPresenter @Inject constructor( .build() } - inner class TopicListViewHolder(val binding: TopicSummaryViewBinding) : - RecyclerView.ViewHolder(binding.root) { - - internal fun bind(topicSummaryViewModel: TopicSummaryViewModel, position: Int) { - binding.viewModel = topicSummaryViewModel - - val marginLayoutParams = binding.topicContainer.layoutParams as ViewGroup.MarginLayoutParams - - val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) - - val marginTopBottom = - (activity as Context).resources - .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) - - val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) - - when (spanCount) { - 2 -> { - when { - position % spanCount == 0 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMax, - marginTopBottom - ) - else -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - marginMin, - marginTopBottom - ) - } - } - 3 -> { - when { - position % spanCount == 0 -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - /* right= */ 0, - marginTopBottom - ) - position % spanCount == 1 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMin, - marginTopBottom - ) - position % spanCount == 2 -> marginLayoutParams.setMargins( - /* left= */ 0, - marginTopBottom, - marginMax, - marginTopBottom - ) - } - } - 4 -> { - when { - (position + 1) % spanCount == 0 -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - /* right= */ 0, - marginTopBottom - ) - (position + 1) % spanCount == 1 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMin / 2, - marginTopBottom - ) - (position + 1) % spanCount == 2 -> marginLayoutParams.setMargins( - marginMin / 2, - marginTopBottom, - marginMin, - marginTopBottom - ) - (position + 1) % spanCount == 3 -> marginLayoutParams.setMargins( - /* left= */ 0, - marginTopBottom, - marginMax, - marginTopBottom - ) - } - } - } - binding.topicContainer.layoutParams = marginLayoutParams - } - - } + // two options + // 1. Could pipe a position to the BindableAdapter bindview and use different registering + // 2. better -- go all out with databinding + // -- put this logic in viewmodel as a function to calculate the padding + // -- could also do computation in layout itself but probably better to do it in kotlin private fun bindPromotedStoryListView( binding: PromotedStoryListBinding, @@ -294,33 +212,12 @@ class HomeFragmentPresenter @Inject constructor( return allTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) } - private val topicListSummaryResultLiveData: LiveData> by lazy { - topicListController.getTopicList() - } - - private fun subscribeToTopicList() { - getAssumedSuccessfulTopicList().observe( - fragment, - Observer { result -> - for (topicSummary in result.topicSummaryList) { - val topicSummaryViewModel = - TopicSummaryViewModel( - topicSummary, - topicEntityType, - fragment as TopicSummaryClickListener - ) - itemList.add(topicSummaryViewModel) - } -// topicListAdapter.notifyDataSetChanged() - } - ) + private fun getTopicSummaryViewModel(): TopicSummaryViewModel { + return topicSummaryViewModelProvider.getForFragment(fragment, TopicSummaryViewModel::class.java) } - private fun getAssumedSuccessfulTopicList(): LiveData { - // If there's an error loading the data, assume the default. - return Transformations.map(topicListSummaryResultLiveData) { - it.getOrDefault(TopicList.getDefaultInstance()) - } + private fun getHomeViewModel(): HomeViewModel { + return homeViewModelProvider.getForFragment(fragment, HomeViewModel::class.java) } fun onTopicSummaryClicked(topicSummary: TopicSummary) { diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt new file mode 100644 index 00000000000..084d701a2ca --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -0,0 +1,57 @@ +package org.oppia.android.app.home + +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations +import org.oppia.android.app.fragment.FragmentScope +import org.oppia.android.app.home.topiclist.TopicSummaryClickListener +import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.TopicList +import org.oppia.android.app.viewmodel.ObservableViewModel +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.parser.TopicHtmlParserEntityType +import javax.inject.Inject + +@FragmentScope +class HomeViewModel @Inject constructor( + private val activity: AppCompatActivity, + private val fragment: Fragment, + private val topicListController: TopicListController, + @TopicHtmlParserEntityType private val topicEntityType: String + ) : ObservableViewModel() { + private var itemList: MutableList = ArrayList() + private val topicListSummaryResultLiveData: LiveData> by lazy { + topicListController.getTopicList() + } + val itemListliveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) + } + + private fun processItemList(it: TopicList) : List { + for (topicSummary in it.topicSummaryList) { + val topicSummaryViewModel = + TopicSummaryViewModel( + activity, + topicSummary, + topicEntityType, + fragment as TopicSummaryClickListener + ) + topicSummaryViewModel.setPosition(it.topicSummaryList.indexOf(topicSummary)) + itemList.add(topicSummaryViewModel) + } + return itemList + } + + private val assumedSuccessfulTopicListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(topicListSummaryResultLiveData) { + it.getOrDefault(TopicList.getDefaultInstance()) + } + } + + fun addHomeItem(viewModel: HomeItemViewModel) { + itemList.add(viewModel) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index a91cade3ea0..fa0450227e2 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -29,10 +29,10 @@ class PromotedStoryListViewModel @Inject constructor( private var internalProfileId: Int = -1 val promotedStoryListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processList) + Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) } - private fun processList(it: OngoingStoryList): MutableList { + private fun processOngoingStoryList(it: OngoingStoryList) : MutableList { var newPromotedStoryList: MutableList = ArrayList() val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) if (it.recentStoryCount != 0) { diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index 4d4f5e2b2e6..db9cb755fd2 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -103,13 +103,13 @@ class TopicListAdapter( is WelcomeViewModel -> { VIEW_TYPE_WELCOME_MESSAGE } - is AllTopicsViewModel -> { + is AllTopicsViewModel -> { // VIEW_TYPE_ALL_TOPICS } is PromotedStoryListViewModel -> { VIEW_TYPE_PROMOTED_STORY_LIST } - is TopicSummaryViewModel -> { + is TopicSummaryViewModel -> { // topic tiles VIEW_TYPE_TOPIC_LIST } else -> throw IllegalArgumentException( diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index e6a6b8fb698..997dbf8a9d3 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -1,9 +1,13 @@ package org.oppia.android.app.home.topiclist +import android.content.Context import android.graphics.Color +import android.view.ViewGroup import androidx.annotation.ColorInt +import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations +import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary @@ -17,8 +21,9 @@ import org.oppia.android.util.data.AsyncResult const val DARKEN_VALUE_MULTIPLIER: Float = 0.9f const val DARKEN_SATURATION_MULTIPLIER: Float = 1.2f -/** The view model corresponding to topic summaries in the topic summary RecyclerView. */ +/** The view model corresponding to individual topic summaries in the topic summary RecyclerView. */ class TopicSummaryViewModel( + private val activity: AppCompatActivity, val topicSummary: TopicSummary, val entityType: String, private val topicSummaryClickListener: TopicSummaryClickListener @@ -29,12 +34,98 @@ class TopicSummaryViewModel( val backgroundColor: Int = retrieveBackgroundColor() @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() + private val marginTopBottom = (activity as Context).resources + .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) + private val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) + + private val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) + + private var position = -1 + private var spanCount = 0 /** Callback from data-binding for when the summary tile is clicked. */ fun clickOnSummaryTile() { topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } +// position is the order that it is displayed + // position is fixed based on itemList + // we know position of ViewModel + // new notion of position -- position of topic within topic list + // we know this when we make the ViewModels + // store position and span count and just recalculate the margins with four different function + // (start end, top bottom are four margins) + // compute each of thes eindividually and call for them in data binding + fun setSpanCount(newSpan: Int) { + this.spanCount = newSpan + } + + fun setPosition(newPosition: Int) { + this.position = newPosition + } + + fun computeTopMargin(): Int { + return marginTopBottom + } + + fun computeBottomMargin(): Int { + return marginTopBottom + } + + fun computeStartMargin(): Int { + when (spanCount) { + 2 -> { + when (position % spanCount) { + 0 -> return marginMin + else -> return marginMax + } + } + 3 -> { + when (position % spanCount) { + 0 -> return marginMax + 1 -> return marginMin + 2 -> return 0 + } + } + 4 -> { + when ((position + 1) % spanCount) { + 0 -> return marginMax + 1 -> return marginMin + 2 -> marginMin / 2 + 3 -> return 0 + } + } + } + return 0 // error here? + } + + fun computeEndMargin(): Int { + when (spanCount) { + 2 -> { + when (position % spanCount) { + 0 -> return marginMax + else -> return marginMin + } + } + 3 -> { + when (position % spanCount) { + 0 -> return 0 + 1 -> return marginMin + 2 -> return marginMax + } + } + 4 -> { + when ((position + 1) % spanCount) { + 0 -> return 0 + 1 -> return marginMin / 2 + 2 -> return marginMin + 3 ->return marginMax + } + } + } + return 0 // error here? + } + @ColorInt private fun retrieveBackgroundColor(): Int { return topicSummary.topicThumbnail.backgroundColorRgb diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 688e1372c4a..d36f149f41f 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -1,9 +1,13 @@ - + + @@ -22,7 +26,8 @@ android:overScrollMode="never" android:paddingTop="36dp" android:paddingBottom="148dp" - android:scrollbars="none" /> + android:scrollbars="none" + app:data="@{viewModel.itemListliveData}" /> Date: Wed, 9 Dec 2020 11:40:00 -0800 Subject: [PATCH 005/248] Compute margins and bind to layout in topic summary view --- .../home/topiclist/TopicSummaryViewModel.kt | 52 ++++++++++++++----- .../main/res/layout/topic_summary_view.xml | 8 +-- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 997dbf8a9d3..72be9bddf48 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -2,17 +2,17 @@ package org.oppia.android.app.home.topiclist import android.content.Context import android.graphics.Color +import android.view.View import android.view.ViewGroup +import android.view.ViewGroup.MarginLayoutParams import androidx.annotation.ColorInt +import androidx.annotation.Dimension import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations +import androidx.core.view.updateLayoutParams +import androidx.databinding.BindingAdapter import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel -import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary -import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult // TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. // These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the @@ -37,9 +37,7 @@ class TopicSummaryViewModel( private val marginTopBottom = (activity as Context).resources .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) private val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) - private val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) - private var position = -1 private var spanCount = 0 @@ -64,15 +62,43 @@ class TopicSummaryViewModel( this.position = newPosition } - fun computeTopMargin(): Int { + @BindingAdapter("layout_marginTop") + fun setLayoutMarginTop(view: View) { + view.updateLayoutParams { + this.topMargin = computeTopMargin() + } + } + + @BindingAdapter("layout_marginBottom") + fun setLayoutMarginBottom(view: View) { + view.updateLayoutParams { + this.bottomMargin = computeBottomMargin() + } + } + + @BindingAdapter("layout_marginStart") + fun setLayoutMarginStart(view: View) { + view.updateLayoutParams { + this.setMarginStart(computeStartMargin()) + } + } + + @BindingAdapter("layout_marginEnd") + fun setLayoutMarginEnd(view: View) { + view.updateLayoutParams { + this.setMarginEnd(computeEndMargin()) + } + } + + private fun computeTopMargin(): Int { return marginTopBottom } - fun computeBottomMargin(): Int { + private fun computeBottomMargin(): Int { return marginTopBottom } - fun computeStartMargin(): Int { + private fun computeStartMargin(): Int { when (spanCount) { 2 -> { when (position % spanCount) { @@ -91,7 +117,7 @@ class TopicSummaryViewModel( when ((position + 1) % spanCount) { 0 -> return marginMax 1 -> return marginMin - 2 -> marginMin / 2 + 2 -> return marginMin / 2 3 -> return 0 } } @@ -99,7 +125,7 @@ class TopicSummaryViewModel( return 0 // error here? } - fun computeEndMargin(): Int { + private fun computeEndMargin(): Int { when (spanCount) { 2 -> { when (position % spanCount) { @@ -119,7 +145,7 @@ class TopicSummaryViewModel( 0 -> return 0 1 -> return marginMin / 2 2 -> return marginMin - 3 ->return marginMax + 3 -> return marginMax } } } diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index 0ebb99f4052..5773c3d58d8 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -13,10 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@{viewModel.computeTopMargin()}" - android:layout_marginBottom="@{viewModel.computeBottomMargin()" - android:layout_marginStart="@{viewModel.computeStartMargin()" - android:layout_marginEnd="@{viewModel.computeEndMargin()" + android:layout_marginTop="@{viewModel.setLayoutMarginTop()}" + android:layout_marginBottom="@{viewModel.setLayoutMarginBottom()" + android:layout_marginStart="@{viewModel.setLayoutMarginStart()}" + android:layout_marginEnd="@{viewModel.setLayoutMarginEnd()" app:cardCornerRadius="4dp"> Date: Wed, 9 Dec 2020 13:10:00 -0800 Subject: [PATCH 006/248] Add databinding for topic summary margins --- .../android/app/home/HomeFragmentPresenter.kt | 26 ++---- .../oppia/android/app/home/HomeViewModel.kt | 2 + .../home/topiclist/TopicSummaryViewModel.kt | 84 +++++++++---------- .../main/res/layout/topic_summary_view.xml | 4 +- 4 files changed, 48 insertions(+), 68 deletions(-) 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 40ef7bffd87..3b047e279b2 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 @@ -6,26 +6,16 @@ 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 androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListAdapter import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryViewModel -import org.oppia.android.app.home.topiclist.TopicListAdapter -import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog -import org.oppia.android.app.model.OngoingStoryList -import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper @@ -37,11 +27,6 @@ import org.oppia.android.databinding.TopicSummaryViewBinding import org.oppia.android.databinding.WelcomeBinding import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger -import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult -import org.oppia.android.util.data.DataProviders.Companion.toLiveData -import org.oppia.android.util.parser.StoryHtmlParserEntityType -import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock import javax.inject.Inject @@ -53,7 +38,7 @@ class HomeFragmentPresenter @Inject constructor( private val welcomeViewModelProvider: ViewModelProvider, private val promotedStoryListViewModelProvider: ViewModelProvider, private val allTopicsViewModelProvider: ViewModelProvider, - private val topicSummaryViewModelProvider: ViewModelProvider, +// private val topicSummaryViewModelProvider: ViewModelProvider, private val homeViewModelProvider: ViewModelProvider, private val oppiaClock: OppiaClock, private val oppiaLogger: OppiaLogger, @@ -79,9 +64,8 @@ class HomeFragmentPresenter @Inject constructor( promotedStoryListViewModel.setActivity(activity) promotedStoryListViewModel.setIntentFactoryShim(intentFactoryShim) val allTopicsViewModel = getAllTopicsViewModel() - val topicSummaryViewModel = getTopicSummaryViewModel() - topicSummaryViewModel.setSpanCount(activity.resources.getInteger(R.integer.home_span_count)) val homeViewModel = getHomeViewModel() +// homeViewModel.setTopicSummarySpanCount(activity.resources.getInteger(R.integer.home_span_count)) homeViewModel.addHomeItem(welcomeViewModel) homeViewModel.addHomeItem(promotedStoryListViewModel) homeViewModel.addHomeItem(allTopicsViewModel) @@ -212,9 +196,9 @@ class HomeFragmentPresenter @Inject constructor( return allTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) } - private fun getTopicSummaryViewModel(): TopicSummaryViewModel { - return topicSummaryViewModelProvider.getForFragment(fragment, TopicSummaryViewModel::class.java) - } +// private fun getTopicSummaryViewModel(): TopicSummaryViewModel { +// return topicSummaryViewModelProvider.getForFragment(fragment, TopicSummaryViewModel::class.java) +// } private fun getHomeViewModel(): HomeViewModel { return homeViewModelProvider.getForFragment(fragment, HomeViewModel::class.java) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 084d701a2ca..4d56cbc23a4 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -9,6 +9,7 @@ import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.TopicList import org.oppia.android.app.viewmodel.ObservableViewModel +import org.oppia.android.app.viewmodel.ViewModelProvider import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.parser.TopicHtmlParserEntityType @@ -21,6 +22,7 @@ class HomeViewModel @Inject constructor( private val topicListController: TopicListController, @TopicHtmlParserEntityType private val topicEntityType: String ) : ObservableViewModel() { + private var itemList: MutableList = ArrayList() private val topicListSummaryResultLiveData: LiveData> by lazy { topicListController.getTopicList() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 72be9bddf48..43dc40c444f 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -4,15 +4,15 @@ import android.content.Context import android.graphics.Color import android.view.View import android.view.ViewGroup -import android.view.ViewGroup.MarginLayoutParams import androidx.annotation.ColorInt -import androidx.annotation.Dimension import androidx.appcompat.app.AppCompatActivity import androidx.core.view.updateLayoutParams import androidx.databinding.BindingAdapter +import dagger.Provides import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary +import javax.inject.Inject // TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. // These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the @@ -22,8 +22,8 @@ const val DARKEN_VALUE_MULTIPLIER: Float = 0.9f const val DARKEN_SATURATION_MULTIPLIER: Float = 1.2f /** The view model corresponding to individual topic summaries in the topic summary RecyclerView. */ -class TopicSummaryViewModel( - private val activity: AppCompatActivity, +class TopicSummaryViewModel ( + activity: AppCompatActivity, val topicSummary: TopicSummary, val entityType: String, private val topicSummaryClickListener: TopicSummaryClickListener @@ -39,21 +39,13 @@ class TopicSummaryViewModel( private val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) private val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) private var position = -1 - private var spanCount = 0 + private var spanCount = activity.resources.getInteger(R.integer.home_span_count) /** Callback from data-binding for when the summary tile is clicked. */ fun clickOnSummaryTile() { topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } -// position is the order that it is displayed - // position is fixed based on itemList - // we know position of ViewModel - // new notion of position -- position of topic within topic list - // we know this when we make the ViewModels - // store position and span count and just recalculate the margins with four different function - // (start end, top bottom are four margins) - // compute each of thes eindividually and call for them in data binding fun setSpanCount(newSpan: Int) { this.spanCount = newSpan } @@ -62,94 +54,96 @@ class TopicSummaryViewModel( this.position = newPosition } - @BindingAdapter("layout_marginTop") - fun setLayoutMarginTop(view: View) { + @BindingAdapter("bind:layout_marginTop") + fun setLayoutMarginTop(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.topMargin = computeTopMargin() } } - @BindingAdapter("layout_marginBottom") - fun setLayoutMarginBottom(view: View) { + @BindingAdapter("bind:layout_marginBottom") + fun setLayoutMarginBottom(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.bottomMargin = computeBottomMargin() } } - @BindingAdapter("layout_marginStart") - fun setLayoutMarginStart(view: View) { + @BindingAdapter("bind:layout_marginStart") + fun setLayoutMarginStart(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.setMarginStart(computeStartMargin()) } } - @BindingAdapter("layout_marginEnd") - fun setLayoutMarginEnd(view: View) { + @BindingAdapter("bind:layout_marginEnd") + fun setLayoutMarginEnd(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.setMarginEnd(computeEndMargin()) } } - private fun computeTopMargin(): Int { + fun computeTopMargin(): Int { return marginTopBottom } - private fun computeBottomMargin(): Int { + fun computeBottomMargin(): Int { return marginTopBottom } - private fun computeStartMargin(): Int { + fun computeStartMargin(): Int { + var margin = 0 when (spanCount) { 2 -> { when (position % spanCount) { - 0 -> return marginMin - else -> return marginMax + 0 -> margin = marginMin + else -> margin = marginMax } } 3 -> { when (position % spanCount) { - 0 -> return marginMax - 1 -> return marginMin - 2 -> return 0 + 0 -> margin = marginMax + 1 -> margin = marginMin + 2 -> margin = 0 } } 4 -> { when ((position + 1) % spanCount) { - 0 -> return marginMax - 1 -> return marginMin - 2 -> return marginMin / 2 - 3 -> return 0 + 0 -> margin = marginMax + 1 -> margin = marginMin + 2 -> margin = marginMin / 2 + 3 -> margin = 0 } } } - return 0 // error here? + return margin // error here? } - private fun computeEndMargin(): Int { + fun computeEndMargin(): Int { + var margin = 0 when (spanCount) { 2 -> { when (position % spanCount) { - 0 -> return marginMax - else -> return marginMin + 0 -> margin = marginMax + else -> margin = marginMin } } 3 -> { when (position % spanCount) { - 0 -> return 0 - 1 -> return marginMin - 2 -> return marginMax + 0 -> margin = 0 + 1 -> margin = marginMin + 2 -> margin = marginMax } } 4 -> { when ((position + 1) % spanCount) { - 0 -> return 0 - 1 -> return marginMin / 2 - 2 -> return marginMin - 3 -> return marginMax + 0 -> margin = 0 + 1 -> margin = marginMin / 2 + 2 -> margin = marginMin + 3 -> margin = marginMax } } } - return 0 // error here? + return margin // error here? } @ColorInt diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index 5773c3d58d8..8c053ed2284 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -14,9 +14,9 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@{viewModel.setLayoutMarginTop()}" - android:layout_marginBottom="@{viewModel.setLayoutMarginBottom()" + android:layout_marginBottom="@{viewModel.setLayoutMarginBottom()}" android:layout_marginStart="@{viewModel.setLayoutMarginStart()}" - android:layout_marginEnd="@{viewModel.setLayoutMarginEnd()" + android:layout_marginEnd="@{viewModel.setLayoutMarginEnd()}" app:cardCornerRadius="4dp"> Date: Wed, 9 Dec 2020 13:46:42 -0800 Subject: [PATCH 007/248] Pushing latest changes to compare --- .../android/app/home/topiclist/TopicSummaryViewModel.kt | 9 ++++----- app/src/main/res/layout/topic_summary_view.xml | 8 ++++---- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 43dc40c444f..844de0609e8 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -8,7 +8,6 @@ import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity import androidx.core.view.updateLayoutParams import androidx.databinding.BindingAdapter -import dagger.Provides import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary @@ -54,28 +53,28 @@ class TopicSummaryViewModel ( this.position = newPosition } - @BindingAdapter("bind:layout_marginTop") + @BindingAdapter("android:layout_marginTop") fun setLayoutMarginTop(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.topMargin = computeTopMargin() } } - @BindingAdapter("bind:layout_marginBottom") + @BindingAdapter("android:layout_marginBottom") fun setLayoutMarginBottom(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.bottomMargin = computeBottomMargin() } } - @BindingAdapter("bind:layout_marginStart") + @BindingAdapter("android:layout_marginStart") fun setLayoutMarginStart(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.setMarginStart(computeStartMargin()) } } - @BindingAdapter("bind:layout_marginEnd") + @BindingAdapter("android:layout_marginEnd") fun setLayoutMarginEnd(view: View, viewModel: TopicSummaryViewModel) { view.updateLayoutParams { this.setMarginEnd(computeEndMargin()) diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index 8c053ed2284..13bab76f8e3 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -13,10 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@{viewModel.setLayoutMarginTop()}" - android:layout_marginBottom="@{viewModel.setLayoutMarginBottom()}" - android:layout_marginStart="@{viewModel.setLayoutMarginStart()}" - android:layout_marginEnd="@{viewModel.setLayoutMarginEnd()}" + android:layout_marginTop="@{() -> viewModel.setLayoutMarginTop(viewModel)}" + android:layout_marginBottom="@{() -> viewModel.setLayoutMarginBottom()}" + android:layout_marginStart="@{() -> viewModel.setLayoutMarginStart()}" + android:layout_marginEnd="@{() -> viewModel.setLayoutMarginEnd()}" app:cardCornerRadius="4dp"> Date: Wed, 9 Dec 2020 14:27:50 -0800 Subject: [PATCH 008/248] Return int to layout margins --- .../oppia/android/app/home/HomeViewModel.kt | 2 +- .../home/topiclist/TopicSummaryViewModel.kt | 37 ------------------- .../main/res/layout/topic_summary_view.xml | 8 ++-- 3 files changed, 5 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 4d56cbc23a4..ad7204b6317 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -56,4 +56,4 @@ class HomeViewModel @Inject constructor( fun addHomeItem(viewModel: HomeItemViewModel) { itemList.add(viewModel) } -} \ No newline at end of file +} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 844de0609e8..e1be2b8225c 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -2,16 +2,11 @@ package org.oppia.android.app.home.topiclist import android.content.Context import android.graphics.Color -import android.view.View -import android.view.ViewGroup import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity -import androidx.core.view.updateLayoutParams -import androidx.databinding.BindingAdapter import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary -import javax.inject.Inject // TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. // These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the @@ -45,42 +40,10 @@ class TopicSummaryViewModel ( topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } - fun setSpanCount(newSpan: Int) { - this.spanCount = newSpan - } - fun setPosition(newPosition: Int) { this.position = newPosition } - @BindingAdapter("android:layout_marginTop") - fun setLayoutMarginTop(view: View, viewModel: TopicSummaryViewModel) { - view.updateLayoutParams { - this.topMargin = computeTopMargin() - } - } - - @BindingAdapter("android:layout_marginBottom") - fun setLayoutMarginBottom(view: View, viewModel: TopicSummaryViewModel) { - view.updateLayoutParams { - this.bottomMargin = computeBottomMargin() - } - } - - @BindingAdapter("android:layout_marginStart") - fun setLayoutMarginStart(view: View, viewModel: TopicSummaryViewModel) { - view.updateLayoutParams { - this.setMarginStart(computeStartMargin()) - } - } - - @BindingAdapter("android:layout_marginEnd") - fun setLayoutMarginEnd(view: View, viewModel: TopicSummaryViewModel) { - view.updateLayoutParams { - this.setMarginEnd(computeEndMargin()) - } - } - fun computeTopMargin(): Int { return marginTopBottom } diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index 13bab76f8e3..cbd4763bbd6 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -13,10 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@{() -> viewModel.setLayoutMarginTop(viewModel)}" - android:layout_marginBottom="@{() -> viewModel.setLayoutMarginBottom()}" - android:layout_marginStart="@{() -> viewModel.setLayoutMarginStart()}" - android:layout_marginEnd="@{() -> viewModel.setLayoutMarginEnd()}" + android:layout_marginTop="@{viewModel.computeTopMargin()}" + android:layout_marginBottom="@{viewModel.computeBottomMargin()}" + android:layout_marginStart="@{viewModel.computeStartMargin()}" + android:layout_marginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> Date: Wed, 9 Dec 2020 14:40:13 -0800 Subject: [PATCH 009/248] Clean up commented code --- .../org/oppia/android/app/home/HomeFragmentPresenter.kt | 7 ------- 1 file changed, 7 deletions(-) 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 3b047e279b2..96688f9b5cf 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 @@ -38,7 +38,6 @@ class HomeFragmentPresenter @Inject constructor( private val welcomeViewModelProvider: ViewModelProvider, private val promotedStoryListViewModelProvider: ViewModelProvider, private val allTopicsViewModelProvider: ViewModelProvider, -// private val topicSummaryViewModelProvider: ViewModelProvider, private val homeViewModelProvider: ViewModelProvider, private val oppiaClock: OppiaClock, private val oppiaLogger: OppiaLogger, @@ -47,7 +46,6 @@ class HomeFragmentPresenter @Inject constructor( private val routeToTopicListener = activity as RouteToTopicListener private lateinit var binding: HomeFragmentBinding private var internalProfileId: Int = -1 -// private var spanCount = 0 fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) @@ -65,7 +63,6 @@ class HomeFragmentPresenter @Inject constructor( promotedStoryListViewModel.setIntentFactoryShim(intentFactoryShim) val allTopicsViewModel = getAllTopicsViewModel() val homeViewModel = getHomeViewModel() -// homeViewModel.setTopicSummarySpanCount(activity.resources.getInteger(R.integer.home_span_count)) homeViewModel.addHomeItem(welcomeViewModel) homeViewModel.addHomeItem(promotedStoryListViewModel) homeViewModel.addHomeItem(allTopicsViewModel) @@ -196,10 +193,6 @@ class HomeFragmentPresenter @Inject constructor( return allTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) } -// private fun getTopicSummaryViewModel(): TopicSummaryViewModel { -// return topicSummaryViewModelProvider.getForFragment(fragment, TopicSummaryViewModel::class.java) -// } - private fun getHomeViewModel(): HomeViewModel { return homeViewModelProvider.getForFragment(fragment, HomeViewModel::class.java) } From 4c9d0bfbfb5b900eb720db6071d492ffe3d2eea5 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Wed, 9 Dec 2020 15:42:16 -0800 Subject: [PATCH 010/248] Use app-defined margin layouts for data binding --- .../android/app/home/HomeFragmentPresenter.kt | 2 + .../home/topiclist/TopicSummaryViewModel.kt | 74 +++++++++---------- .../main/res/layout/topic_summary_view.xml | 8 +- 3 files changed, 43 insertions(+), 41 deletions(-) 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 96688f9b5cf..2d53dd9df07 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 @@ -104,6 +104,7 @@ class HomeFragmentPresenter @Inject constructor( else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") } } +// . .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, inflateDataBinding = WelcomeBinding::inflate, @@ -174,6 +175,7 @@ class HomeFragmentPresenter @Inject constructor( } private enum class ViewType { + VIEW_TYPE_HOME, VIEW_TYPE_WELCOME_MESSAGE, VIEW_TYPE_PROMOTED_STORY_LIST, VIEW_TYPE_ALL_TOPICS, diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index e1be2b8225c..794ca9186c9 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -4,6 +4,7 @@ import android.content.Context import android.graphics.Color import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity +import androidx.databinding.BindingAdapter import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary @@ -17,7 +18,7 @@ const val DARKEN_SATURATION_MULTIPLIER: Float = 1.2f /** The view model corresponding to individual topic summaries in the topic summary RecyclerView. */ class TopicSummaryViewModel ( - activity: AppCompatActivity, + private val activity: AppCompatActivity, val topicSummary: TopicSummary, val entityType: String, private val topicSummaryClickListener: TopicSummaryClickListener @@ -30,10 +31,13 @@ class TopicSummaryViewModel ( val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() private val marginTopBottom = (activity as Context).resources .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) - private val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) - private val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) + private val marginMax by lazy { + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) } + private val marginMin by lazy { + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) } private var position = -1 - private var spanCount = activity.resources.getInteger(R.integer.home_span_count) + private val spanCount by lazy { + activity.resources.getInteger(R.integer.home_span_count) } /** Callback from data-binding for when the summary tile is clicked. */ fun clickOnSummaryTile() { @@ -53,59 +57,55 @@ class TopicSummaryViewModel ( } fun computeStartMargin(): Int { - var margin = 0 - when (spanCount) { + return when (spanCount) { 2 -> { when (position % spanCount) { - 0 -> margin = marginMin - else -> margin = marginMax + 0 -> marginMin + else -> marginMax } } 3 -> { when (position % spanCount) { - 0 -> margin = marginMax - 1 -> margin = marginMin - 2 -> margin = 0 + 0 -> marginMax + 1 -> marginMin + 2 -> 0 + else -> 0 } } 4 -> { when ((position + 1) % spanCount) { - 0 -> margin = marginMax - 1 -> margin = marginMin - 2 -> margin = marginMin / 2 - 3 -> margin = 0 + 0 -> marginMax + 1 -> marginMin + 2 -> marginMin / 2 + 3 -> 0 + else -> 0 } } + else -> 0 } - return margin // error here? } fun computeEndMargin(): Int { - var margin = 0 - when (spanCount) { - 2 -> { - when (position % spanCount) { - 0 -> margin = marginMax - else -> margin = marginMin - } + return when (spanCount) { + 2 -> when (position % spanCount) { + 0 -> marginMax + else -> marginMin } - 3 -> { - when (position % spanCount) { - 0 -> margin = 0 - 1 -> margin = marginMin - 2 -> margin = marginMax - } + 3 -> when (position % spanCount) { + 0 -> 0 + 1 -> marginMin + 2 -> marginMax + else -> 0 } - 4 -> { - when ((position + 1) % spanCount) { - 0 -> margin = 0 - 1 -> margin = marginMin / 2 - 2 -> margin = marginMin - 3 -> margin = marginMax - } + 4 -> when ((position + 1) % spanCount) { + 0 -> 0 + 1 -> marginMin / 2 + 2 -> marginMin + 3 -> marginMax + else -> 0 } + else -> 0 } - return margin // error here? } @ColorInt diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index cbd4763bbd6..7734a63329e 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -13,10 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_marginTop="@{viewModel.computeTopMargin()}" - android:layout_marginBottom="@{viewModel.computeBottomMargin()}" - android:layout_marginStart="@{viewModel.computeStartMargin()}" - android:layout_marginEnd="@{viewModel.computeEndMargin()}" + app:layoutMarginTop="@{viewModel.computeTopMargin()}" + app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginStart="@{viewModel.computeStartMargin()}" + app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> Date: Wed, 9 Dec 2020 16:28:05 -0800 Subject: [PATCH 011/248] Add binding to HomeViewModel --- .../android/app/home/HomeFragmentPresenter.kt | 22 +++------------- .../oppia/android/app/home/HomeViewModel.kt | 2 +- .../android/app/home/WelcomeViewModel.kt | 26 +++++++++---------- .../topiclist/PromotedStoryListViewModel.kt | 15 ++--------- app/src/main/res/layout/home_fragment.xml | 2 +- 5 files changed, 19 insertions(+), 48 deletions(-) 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 2d53dd9df07..43dafac0c19 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 @@ -9,17 +9,16 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import org.oppia.android.R -import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListAdapter import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel +import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper -import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ViewModelProvider import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.PromotedStoryListBinding @@ -40,8 +39,7 @@ class HomeFragmentPresenter @Inject constructor( private val allTopicsViewModelProvider: ViewModelProvider, private val homeViewModelProvider: ViewModelProvider, private val oppiaClock: OppiaClock, - private val oppiaLogger: OppiaLogger, - private val intentFactoryShim: IntentFactoryShim + private val oppiaLogger: OppiaLogger ) { private val routeToTopicListener = activity as RouteToTopicListener private lateinit var binding: HomeFragmentBinding @@ -53,22 +51,15 @@ class HomeFragmentPresenter @Inject constructor( // data-bound view models. val welcomeViewModel = getWelcomeViewModel() - internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) - welcomeViewModel.setInternalProfileId(internalProfileId) logHomeActivityEvent() val promotedStoryListViewModel = getPromotedStoryListViewModel() - promotedStoryListViewModel.setInternalProfileId(internalProfileId) - promotedStoryListViewModel.setActivity(activity) - promotedStoryListViewModel.setIntentFactoryShim(intentFactoryShim) val allTopicsViewModel = getAllTopicsViewModel() val homeViewModel = getHomeViewModel() homeViewModel.addHomeItem(welcomeViewModel) homeViewModel.addHomeItem(promotedStoryListViewModel) homeViewModel.addHomeItem(allTopicsViewModel) - // make item list a live data list - // live data is going to compute topic list (remove observe and turn it into transformation for list of viewmodels) val spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { @@ -88,6 +79,7 @@ class HomeFragmentPresenter @Inject constructor( } binding.let { it.lifecycleOwner = fragment + it.viewModel = homeViewModel } return binding.root @@ -104,7 +96,6 @@ class HomeFragmentPresenter @Inject constructor( else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") } } -// . .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, inflateDataBinding = WelcomeBinding::inflate, @@ -132,12 +123,6 @@ class HomeFragmentPresenter @Inject constructor( .build() } - // two options - // 1. Could pipe a position to the BindableAdapter bindview and use different registering - // 2. better -- go all out with databinding - // -- put this logic in viewmodel as a function to calculate the padding - // -- could also do computation in layout itself but probably better to do it in kotlin - private fun bindPromotedStoryListView( binding: PromotedStoryListBinding, model: PromotedStoryListViewModel @@ -175,7 +160,6 @@ class HomeFragmentPresenter @Inject constructor( } private enum class ViewType { - VIEW_TYPE_HOME, VIEW_TYPE_WELCOME_MESSAGE, VIEW_TYPE_PROMOTED_STORY_LIST, VIEW_TYPE_ALL_TOPICS, diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index ad7204b6317..34eb0160cb1 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -27,7 +27,7 @@ class HomeViewModel @Inject constructor( private val topicListSummaryResultLiveData: LiveData> by lazy { topicListController.getTopicList() } - val itemListliveData: LiveData> by lazy { + val itemListLiveData: LiveData> by lazy { Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 4e47ddf2bb0..f0da80d7f03 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -1,9 +1,12 @@ package org.oppia.android.app.home +import android.app.AppComponentFactory +import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel +import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.domain.profile.ProfileManagementController @@ -16,13 +19,18 @@ import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel @Inject constructor( + private val activity: AppCompatActivity, private val logger: ConsoleLogger, private val fragment: Fragment, private val oppiaClock: OppiaClock, private val profileManagementController: ProfileManagementController - ) : HomeItemViewModel() { - private lateinit var profileId: ProfileId - lateinit var greeting: String +) : HomeItemViewModel() { + private val internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) + private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + var greeting: String = DateTimeUtil( + fragment.requireContext(), + oppiaClock + ).getGreetingMessage() val profileName: LiveData by lazy { Transformations.map(profileLiveData, Profile::getName) @@ -33,23 +41,13 @@ class WelcomeViewModel @Inject constructor( } private val profileLiveData: LiveData by lazy { - Transformations.map( - profileResultLiveData, - ::processGetProfileResult) + Transformations.map(profileResultLiveData, ::processGetProfileResult) } private fun processGetProfileResult(profileResult: AsyncResult): Profile { if (profileResult.isFailure()) { logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) } - greeting = DateTimeUtil( - fragment.requireContext(), - oppiaClock - ).getGreetingMessage() return profileResult.getOrDefault(Profile.getDefaultInstance()) } - - fun setInternalProfileId(internalProfileId: Int) { - this.profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index fa0450227e2..1f93feccf78 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -5,6 +5,7 @@ import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import org.oppia.android.R +import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.model.OngoingStoryList @@ -26,7 +27,7 @@ class PromotedStoryListViewModel @Inject constructor( HomeItemViewModel(), RouteToRecentlyPlayedListener { - private var internalProfileId: Int = -1 + private val internalProfileId: Int = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) val promotedStoryListLiveData: LiveData> by lazy { Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) @@ -91,16 +92,4 @@ class PromotedStoryListViewModel @Inject constructor( ) activity.startActivity(intent) } - - fun setInternalProfileId(internalProfileId: Int) { - this.internalProfileId = internalProfileId - } - - fun setActivity(activity: AppCompatActivity) { - this.activity = activity; - } - - fun setIntentFactoryShim(intentFactoryShim: IntentFactoryShim) { - this.intentFactoryShim = intentFactoryShim - } } diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index d36f149f41f..1efab042e3e 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.itemListliveData}" /> + app:data="@{viewModel.itemListLiveData}" /> Date: Thu, 10 Dec 2020 11:22:04 -0800 Subject: [PATCH 012/248] Remove use of ViewModelProvider in HomeFragmentPresenter --- .../android/app/home/HomeFragmentPresenter.kt | 68 +++++++----- .../android/app/home/WelcomeViewModel.kt | 8 +- .../topiclist/PromotedStoryListAdapter.kt | 18 ++-- .../topiclist/PromotedStoryListViewModel.kt | 102 +++++++++++++----- .../home/topiclist/PromotedStoryViewModel.kt | 32 ++++++ .../app/home/topiclist/TopicListAdapter.kt | 2 +- .../main/res/layout/promoted_story_card.xml | 13 +-- .../main/res/layout/promoted_story_list.xml | 6 +- 8 files changed, 172 insertions(+), 77 deletions(-) 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 43dafac0c19..4f777137688 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 @@ -9,23 +9,29 @@ import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager import org.oppia.android.R +import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListAdapter import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog +import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper -import org.oppia.android.app.viewmodel.ViewModelProvider +import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.PromotedStoryListBinding import org.oppia.android.databinding.TopicSummaryViewBinding import org.oppia.android.databinding.WelcomeBinding import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger +import org.oppia.android.domain.profile.ProfileManagementController +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.logging.ConsoleLogger +import org.oppia.android.util.parser.StoryHtmlParserEntityType +import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock import javax.inject.Inject @@ -34,12 +40,14 @@ import javax.inject.Inject class HomeFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - private val welcomeViewModelProvider: ViewModelProvider, - private val promotedStoryListViewModelProvider: ViewModelProvider, - private val allTopicsViewModelProvider: ViewModelProvider, - private val homeViewModelProvider: ViewModelProvider, + private val profileManagementController: ProfileManagementController, + private val topicListController: TopicListController, private val oppiaClock: OppiaClock, - private val oppiaLogger: OppiaLogger + private val logger: ConsoleLogger, + private val oppiaLogger: OppiaLogger, + private val intentFactoryShim: IntentFactoryShim, + @TopicHtmlParserEntityType private val topicEntityType: String, + @StoryHtmlParserEntityType private val storyEntityType: String ) { private val routeToTopicListener = activity as RouteToTopicListener private lateinit var binding: HomeFragmentBinding @@ -50,12 +58,31 @@ class HomeFragmentPresenter @Inject constructor( // NB: Both the view model and lifecycle owner must be set in order to correctly bind LiveData elements to // data-bound view models. - val welcomeViewModel = getWelcomeViewModel() + internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) + val profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + val welcomeViewModel = WelcomeViewModel( + logger, + fragment, + oppiaClock, + profileManagementController, + profileId + ) logHomeActivityEvent() - val promotedStoryListViewModel = getPromotedStoryListViewModel() - val allTopicsViewModel = getAllTopicsViewModel() - val homeViewModel = getHomeViewModel() + val promotedStoryListViewModel = PromotedStoryListViewModel( + activity, + internalProfileId, + intentFactoryShim, + topicListController, + storyEntityType + ) + val allTopicsViewModel = AllTopicsViewModel() + val homeViewModel = HomeViewModel( + activity, + fragment, + topicListController, + topicEntityType + ) homeViewModel.addHomeItem(welcomeViewModel) homeViewModel.addHomeItem(promotedStoryListViewModel) homeViewModel.addHomeItem(allTopicsViewModel) @@ -105,7 +132,7 @@ class HomeFragmentPresenter @Inject constructor( .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_PROMOTED_STORY_LIST, inflateDataBinding = PromotedStoryListBinding::inflate, - setViewModel = this::bindPromotedStoryListView, + setViewModel = this::bindPromotedStoryListView, // PromotedStoryListBinding::setViewModel transformViewModel = { it as PromotedStoryListViewModel } ) .registerViewDataBinder( @@ -166,23 +193,6 @@ class HomeFragmentPresenter @Inject constructor( VIEW_TYPE_TOPIC_LIST } - private fun getWelcomeViewModel(): WelcomeViewModel { - return welcomeViewModelProvider.getForFragment(fragment, WelcomeViewModel::class.java) - } - - private fun getPromotedStoryListViewModel(): PromotedStoryListViewModel { - return promotedStoryListViewModelProvider - .getForFragment(fragment, PromotedStoryListViewModel::class.java) - } - - private fun getAllTopicsViewModel(): AllTopicsViewModel { - return allTopicsViewModelProvider.getForFragment(fragment, AllTopicsViewModel::class.java) - } - - private fun getHomeViewModel(): HomeViewModel { - return homeViewModelProvider.getForFragment(fragment, HomeViewModel::class.java) - } - fun onTopicSummaryClicked(topicSummary: TopicSummary) { routeToTopicListener.routeToTopic(internalProfileId, topicSummary.topicId) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index f0da80d7f03..5c06e252076 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -19,14 +19,12 @@ import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel @Inject constructor( - private val activity: AppCompatActivity, private val logger: ConsoleLogger, private val fragment: Fragment, private val oppiaClock: OppiaClock, - private val profileManagementController: ProfileManagementController -) : HomeItemViewModel() { - private val internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) - private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + private val profileManagementController: ProfileManagementController, + private val profileId: ProfileId + ) : HomeItemViewModel() { var greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt index aaf28ca84a2..5bb705010ce 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt @@ -13,7 +13,7 @@ import org.oppia.android.databinding.PromotedStoryCardBinding /** Adapter to bind promoted stories to [RecyclerView] inside [HomeFragment] to create carousel. */ class PromotedStoryListAdapter( private val activity: AppCompatActivity, - private val itemList: MutableList + private val itemList: List ) : RecyclerView.Adapter() { @@ -44,15 +44,17 @@ class PromotedStoryListAdapter( internal fun bind(promotedStoryViewModel: PromotedStoryViewModel) { binding.viewModel = promotedStoryViewModel val layoutParams = binding.promotedStoryCardContainer.layoutParams - layoutParams.width = if (itemCount > 1) { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - ViewGroup.LayoutParams.MATCH_PARENT + layoutParams.width = // set layout width based on number of stories + if (itemCount > 1) { // this checks for the number of promoted stories? + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + ViewGroup.LayoutParams.MATCH_PARENT + } else { + // set a different width only if it's landscape & there are multiple promoted stories + (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) + } } else { - (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) + ViewGroup.LayoutParams.MATCH_PARENT } - } else { - ViewGroup.LayoutParams.MATCH_PARENT - } binding.promotedStoryCardContainer.layoutParams = layoutParams } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 1f93feccf78..a54a8f0e8db 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,43 +1,69 @@ package org.oppia.android.app.home.topiclist +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener +import org.oppia.android.app.model.CompletedStoryList import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.IntentFactoryShim +import org.oppia.android.databinding.PromotedStoryListBinding import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.StoryHtmlParserEntityType import javax.inject.Inject /** [ViewModel] promoted story list in [HomeFragment]. */ class PromotedStoryListViewModel @Inject constructor( - private var activity: AppCompatActivity, - private var intentFactoryShim: IntentFactoryShim, - private val topicListController: TopicListController, + private val activity: AppCompatActivity, + private val internalProfileId: Int, + private val intentFactoryShim: IntentFactoryShim, + private val topicListController, @StoryHtmlParserEntityType private val storyEntityType: String ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { + private val orientation = Resources.getSystem().configuration.orientation + private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) - private val internalProfileId: Int = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) + private val ongoingStoryListSummaryResultLiveData: LiveData> + by lazy { + topicListController.getOngoingStoryList( + ProfileId.newBuilder().setInternalId(internalProfileId).build() + ).toLiveData() + } - val promotedStoryListLiveData: LiveData> by lazy { + private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(ongoingStoryListSummaryResultLiveData) { + it.getOrDefault( + OngoingStoryList.getDefaultInstance() + ) + } + } + + val promotedStoryListLiveData: LiveData> by lazy { Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) } - private fun processOngoingStoryList(it: OngoingStoryList) : MutableList { + private fun processOngoingStoryList(ongoingStoryList: OngoingStoryList) : List { var newPromotedStoryList: MutableList = ArrayList() - val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) - if (it.recentStoryCount != 0) { - it.recentStoryList.take(limit) + if (ongoingStoryList.recentStoryCount != 0) { + ongoingStoryList.recentStoryList.take(limit) .forEach { promotedStory -> val recentStory = PromotedStoryViewModel( activity, @@ -50,7 +76,7 @@ class PromotedStoryListViewModel @Inject constructor( } } else { // TODO(#936): Optimise this as part of recommended stories. - it.olderStoryList.take(limit) + ongoingStoryList.olderStoryList.take(limit) .forEach { promotedStory -> val oldStory = PromotedStoryViewModel( activity, @@ -65,22 +91,6 @@ class PromotedStoryListViewModel @Inject constructor( return newPromotedStoryList } - private val ongoingStoryListSummaryResultLiveData: LiveData> - by lazy { - topicListController.getOngoingStoryList( - ProfileId.newBuilder().setInternalId(internalProfileId).build() - ).toLiveData() - } - - private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(ongoingStoryListSummaryResultLiveData) { - it.getOrDefault( - OngoingStoryList.getDefaultInstance() - ) - } - } - fun clickOnViewAll() { routeToRecentlyPlayed() } @@ -92,4 +102,44 @@ class PromotedStoryListViewModel @Inject constructor( ) activity.startActivity(intent) } + + inner class PromotedStoryListViewHolder(val binding: PromotedStoryListBinding) : + RecyclerView.ViewHolder(binding.root) { + internal fun bind( + activity: AppCompatActivity, + promotedStoryListViewModel: PromotedStoryListViewModel, + promotedStoryList: MutableList + ) { + binding.viewModel = promotedStoryListViewModel + if (activity.resources.getBoolean(R.bool.isTablet)) { // Is this still needed? + binding.itemCount = promotedStoryList.size + } + val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) + val horizontalLayoutManager = + LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) + binding.promotedStoryListRecyclerView.apply { + layoutManager = horizontalLayoutManager + adapter = promotedStoryAdapter + } + + /* + * The StartSnapHelper is used to snap between items rather than smooth scrolling, + * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. + */ + val snapHelper = StartSnapHelper() + binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager + binding.promotedStoryListRecyclerView.setOnFlingListener(null) + snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) + + val paddingEnd = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) + val paddingStart = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) + if (promotedStoryList.size > 1) { + binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) + } else { + binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) + } + } + } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 749f0f8e513..d382a91c3df 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -1,13 +1,22 @@ package org.oppia.android.app.home.topiclist +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.view.ViewGroup +import android.view.animation.Transformation import androidx.appcompat.app.AppCompatActivity import androidx.databinding.ObservableField import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel +import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.R import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel +import org.oppia.android.databinding.PromotedStoryCardBinding // TODO(#283): Add download status information to promoted-story-card. @@ -27,11 +36,34 @@ class PromotedStoryViewModel( * always in sync. */ val promotedStoryObservable = ObservableField() + val promotedStoryLiveData: LiveData by lazy { + Transformations.map() + } + private val orientation = Resources.getSystem().configuration.orientation fun setPromotedStory(promotedStory: PromotedStory) { promotedStoryObservable.set(promotedStory) } +// inner class PromotedStoryViewHolder( +// val binding: PromotedStoryCardBinding +// ) : RecyclerView.ViewHolder(binding.root) { +// internal fun bind(promotedStoryViewModel: PromotedStoryViewModel) { +// binding.viewModel = promotedStoryViewModel +// val layoutParams = binding.promotedStoryCardContainer.layoutParams +// layoutParams.width = if (itemCount > 1) { +// if (orientation == Configuration.ORIENTATION_PORTRAIT) { +// ViewGroup.LayoutParams.MATCH_PARENT +// } else { +// (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) +// } +// } else { +// ViewGroup.LayoutParams.MATCH_PARENT +// } +// binding.promotedStoryCardContainer.layoutParams = layoutParams +// } +// } + fun clickOnStoryTile() { routeToTopicPlayStory( internalProfileId, diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index db9cb755fd2..4360f87482b 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -141,7 +141,7 @@ class TopicListAdapter( promotedStoryList: MutableList ) { binding.viewModel = promotedStoryListViewModel - if (activity.resources.getBoolean(R.bool.isTablet)) { + if (activity.resources.getBoolean(R.bool.isTablet)) { // reset dataList to match number of stories to display => why does tablet matter binding.itemCount = promotedStoryList.size } val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) diff --git a/app/src/main/res/layout/promoted_story_card.xml b/app/src/main/res/layout/promoted_story_card.xml index 41d1fdba21a..673b797b353 100755 --- a/app/src/main/res/layout/promoted_story_card.xml +++ b/app/src/main/res/layout/promoted_story_card.xml @@ -29,7 +29,8 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/recently_played_stories_text_view" - app:roundedRectDrawableWithColor="@{viewModel.promotedStoryObservable.lessonThumbnail.backgroundColorRgb}"> + app: + app:roundedRectDrawableWithColor="@{viewModel.promotedStoryLiveData.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStoryLiveData.lessonThumbnail}" /> @@ -79,7 +80,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryObservable.storyName}" + android:text="@{viewModel.promotedStoryLiveData.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -94,7 +95,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryObservable.topicName}" + android:text="@{viewModel.promotedStoryLiveData.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 011a24327e1..4b555dc8e5b 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -1,5 +1,6 @@ - + @@ -56,6 +57,7 @@ android:clipToPadding="false" android:layout_marginTop="4dp" android:overScrollMode="never" - android:scrollbars="none" /> + android:scrollbars="none" + app:data="@{viewModel.promotedStoryListLiveData}" /> From dd87309d0eb16de17912e3ee9aea79b5b53c238d Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 12:04:19 -0800 Subject: [PATCH 013/248] Bind PromotedStoryList layout values --- .../android/app/home/HomeFragmentPresenter.kt | 42 +-------------- .../topiclist/PromotedStoryListViewModel.kt | 54 +++++-------------- .../promoted_story_list.xml | 5 +- .../main/res/layout/promoted_story_list.xml | 7 +++ 4 files changed, 23 insertions(+), 85 deletions(-) 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 4f777137688..26624806d24 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 @@ -1,25 +1,21 @@ package org.oppia.android.app.home -import android.content.Context import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.LinearLayoutManager import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryListAdapter import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter -import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.PromotedStoryListBinding @@ -132,7 +128,7 @@ class HomeFragmentPresenter @Inject constructor( .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_PROMOTED_STORY_LIST, inflateDataBinding = PromotedStoryListBinding::inflate, - setViewModel = this::bindPromotedStoryListView, // PromotedStoryListBinding::setViewModel + setViewModel = PromotedStoryListBinding::setViewModel, transformViewModel = { it as PromotedStoryListViewModel } ) .registerViewDataBinder( @@ -150,42 +146,6 @@ class HomeFragmentPresenter @Inject constructor( .build() } - private fun bindPromotedStoryListView( - binding: PromotedStoryListBinding, - model: PromotedStoryListViewModel - ) { - binding.viewModel = model - if (activity.resources.getBoolean(R.bool.isTablet)) { - binding.itemCount = model.promotedStoryListLiveData.value!!.size - } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, model.promotedStoryListLiveData.value!!) - val horizontalLayoutManager = - LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = promotedStoryAdapter - } - - /* - * The StartSnapHelper is used to snap between items rather than smooth scrolling, - * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. - */ - val snapHelper = StartSnapHelper() - binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager - binding.promotedStoryListRecyclerView.setOnFlingListener(null) - snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) - - val paddingEnd = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) - val paddingStart = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) - if (model.promotedStoryListLiveData.value!!.size > 1) { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) - } else { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) - } - } - private enum class ViewType { VIEW_TYPE_WELCOME_MESSAGE, VIEW_TYPE_PROMOTED_STORY_LIST, diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index a54a8f0e8db..016baea84ed 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -32,13 +32,16 @@ class PromotedStoryListViewModel @Inject constructor( private val activity: AppCompatActivity, private val internalProfileId: Int, private val intentFactoryShim: IntentFactoryShim, - private val topicListController, + private val topicListController: TopicListController, @StoryHtmlParserEntityType private val storyEntityType: String ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { - private val orientation = Resources.getSystem().configuration.orientation private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + val paddingEnd = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) + val paddingStart = + (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) private val ongoingStoryListSummaryResultLiveData: LiveData> by lazy { @@ -103,43 +106,14 @@ class PromotedStoryListViewModel @Inject constructor( activity.startActivity(intent) } - inner class PromotedStoryListViewHolder(val binding: PromotedStoryListBinding) : - RecyclerView.ViewHolder(binding.root) { - internal fun bind( - activity: AppCompatActivity, - promotedStoryListViewModel: PromotedStoryListViewModel, - promotedStoryList: MutableList - ) { - binding.viewModel = promotedStoryListViewModel - if (activity.resources.getBoolean(R.bool.isTablet)) { // Is this still needed? - binding.itemCount = promotedStoryList.size - } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) - val horizontalLayoutManager = - LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = promotedStoryAdapter - } - - /* - * The StartSnapHelper is used to snap between items rather than smooth scrolling, - * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. - */ - val snapHelper = StartSnapHelper() - binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager - binding.promotedStoryListRecyclerView.setOnFlingListener(null) - snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) - val paddingEnd = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) - val paddingStart = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) - if (promotedStoryList.size > 1) { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) - } else { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) - } - } - } +// /* +// * The StartSnapHelper is used to snap between items rather than smooth scrolling, +// * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. +// */ +// val snapHelper = StartSnapHelper() +// binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager +// binding.promotedStoryListRecyclerView.setOnFlingListener(null) +// snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) +// } } diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index bc9c7908c3e..ec93b5d2e68 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -9,9 +9,6 @@ name="viewModel" type="org.oppia.android.app.home.topiclist.PromotedStoryListViewModel" /> - diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 4b555dc8e5b..0fc6fae7f6a 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -58,6 +58,13 @@ android:layout_marginTop="4dp" android:overScrollMode="never" android:scrollbars="none" + android:orientation="horizontal" + android:paddingStart="@{viewModel.paddingStart}" + android:paddingEnd="@{viewModel.promotedStoryListLiveData.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" + android:paddingTop="0dp" + android:paddingBottom="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:reverseLayout="false" app:data="@{viewModel.promotedStoryListLiveData}" /> From 95ad08c80e2d07044678533096982488463903e1 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 14:32:38 -0800 Subject: [PATCH 014/248] Add data binding for sotry & layout of PromotedStory card --- .../topiclist/PromotedStoryListViewModel.kt | 2 + .../home/topiclist/PromotedStoryViewModel.kt | 45 +++++++++---------- .../main/res/layout/promoted_story_card.xml | 15 +++---- 3 files changed, 29 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 016baea84ed..8fb0a9d6c06 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -75,6 +75,7 @@ class PromotedStoryListViewModel @Inject constructor( intentFactoryShim ) recentStory.setPromotedStory(promotedStory) + recentStory.setStoryCount(ongoingStoryList.recentStoryCount) newPromotedStoryList.add(recentStory) } } else { @@ -88,6 +89,7 @@ class PromotedStoryListViewModel @Inject constructor( intentFactoryShim ) oldStory.setPromotedStory(promotedStory) + oldStory.setStoryCount(ongoingStoryList.olderStoryCount) newPromotedStoryList.add(oldStory) } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index d382a91c3df..9196d5ba9a5 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -35,40 +35,35 @@ class PromotedStoryViewModel( * [LiveData] is used for all subsequent processed data to ensure the transformed [LiveData]s are * always in sync. */ - val promotedStoryObservable = ObservableField() - val promotedStoryLiveData: LiveData by lazy { - Transformations.map() - } + var story : PromotedStory = PromotedStory.getDefaultInstance() private val orientation = Resources.getSystem().configuration.orientation + var totalStoryCount = -1 fun setPromotedStory(promotedStory: PromotedStory) { - promotedStoryObservable.set(promotedStory) + this.story = promotedStory + } + + fun setStoryCount(newCount: Int) { + this.totalStoryCount = newCount } -// inner class PromotedStoryViewHolder( -// val binding: PromotedStoryCardBinding -// ) : RecyclerView.ViewHolder(binding.root) { -// internal fun bind(promotedStoryViewModel: PromotedStoryViewModel) { -// binding.viewModel = promotedStoryViewModel -// val layoutParams = binding.promotedStoryCardContainer.layoutParams -// layoutParams.width = if (itemCount > 1) { -// if (orientation == Configuration.ORIENTATION_PORTRAIT) { -// ViewGroup.LayoutParams.MATCH_PARENT -// } else { -// (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) -// } -// } else { -// ViewGroup.LayoutParams.MATCH_PARENT -// } -// binding.promotedStoryCardContainer.layoutParams = layoutParams -// } -// } + fun computeLayoutWidth(): Int { + if (totalStoryCount > 1) { + if (orientation == Configuration.ORIENTATION_PORTRAIT) { + return ViewGroup.LayoutParams.MATCH_PARENT + } else { + return (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) + } + } else { + return ViewGroup.LayoutParams.MATCH_PARENT + } + } fun clickOnStoryTile() { routeToTopicPlayStory( internalProfileId, - promotedStoryObservable.get()!!.topicId, - promotedStoryObservable.get()!!.storyId + story.topicId, + story.storyId ) } diff --git a/app/src/main/res/layout/promoted_story_card.xml b/app/src/main/res/layout/promoted_story_card.xml index 673b797b353..16b4b9c59d6 100755 --- a/app/src/main/res/layout/promoted_story_card.xml +++ b/app/src/main/res/layout/promoted_story_card.xml @@ -22,15 +22,14 @@ + app:roundedRectDrawableWithColor="@{viewModel.story.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.story.lessonThumbnail}" /> @@ -80,7 +79,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryLiveData.storyName}" + android:text="@{viewModel.story.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -95,7 +94,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryLiveData.topicName}" + android:text="@{viewModel.story.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> From 269204e996137141f19cbf33c961b930f082199e Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 15:24:47 -0800 Subject: [PATCH 015/248] Add BindingAdapter for layout height --- .../android/app/databinding/ViewBindingAdapters.java | 10 ++++++++++ .../java/org/oppia/android/app/home/HomeViewModel.kt | 6 +++--- .../app/home/topiclist/PromotedStoryViewModel.kt | 8 ++++---- app/src/main/res/layout/promoted_story_card.xml | 12 ++++++------ 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 6c3d99d4d07..9ae2bee2907 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -21,6 +21,16 @@ public static void setLayoutHeight(@NonNull View view, float height) { view.setLayoutParams(layoutParams); } + /** + * BindingAdapter to set the width of a View. + */ + @BindingAdapter("android:layout_width") + public static void setLayoutWidth(@NonNull View view, float width) { + ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); + layoutParams.width = (int) width; + view.setLayoutParams(layoutParams); + } + @BindingAdapter( value = { "app:isRotationAnimationClockwise", diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 34eb0160cb1..e8fb47f2b4d 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -31,8 +31,8 @@ class HomeViewModel @Inject constructor( Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) } - private fun processItemList(it: TopicList) : List { - for (topicSummary in it.topicSummaryList) { + private fun processItemList(itemListLiveData: TopicList) : List { + for (topicSummary in itemListLiveData.topicSummaryList) { val topicSummaryViewModel = TopicSummaryViewModel( activity, @@ -40,7 +40,7 @@ class HomeViewModel @Inject constructor( topicEntityType, fragment as TopicSummaryClickListener ) - topicSummaryViewModel.setPosition(it.topicSummaryList.indexOf(topicSummary)) + topicSummaryViewModel.setPosition(itemListLiveData.topicSummaryList.indexOf(topicSummary)) itemList.add(topicSummaryViewModel) } return itemList diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 9196d5ba9a5..aa43f670ff0 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -35,12 +35,12 @@ class PromotedStoryViewModel( * [LiveData] is used for all subsequent processed data to ensure the transformed [LiveData]s are * always in sync. */ - var story : PromotedStory = PromotedStory.getDefaultInstance() + var promotedStoryObservable : PromotedStory = PromotedStory.getDefaultInstance() private val orientation = Resources.getSystem().configuration.orientation var totalStoryCount = -1 fun setPromotedStory(promotedStory: PromotedStory) { - this.story = promotedStory + this.promotedStoryObservable = promotedStory } fun setStoryCount(newCount: Int) { @@ -62,8 +62,8 @@ class PromotedStoryViewModel( fun clickOnStoryTile() { routeToTopicPlayStory( internalProfileId, - story.topicId, - story.storyId + promotedStoryObservable.topicId, + promotedStoryObservable.storyId ) } diff --git a/app/src/main/res/layout/promoted_story_card.xml b/app/src/main/res/layout/promoted_story_card.xml index 16b4b9c59d6..d21e27477b4 100755 --- a/app/src/main/res/layout/promoted_story_card.xml +++ b/app/src/main/res/layout/promoted_story_card.xml @@ -29,7 +29,7 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/recently_played_stories_text_view" - app:roundedRectDrawableWithColor="@{viewModel.story.lessonThumbnail.backgroundColorRgb}"> + app:roundedRectDrawableWithColor="@{viewModel.promotedStoryObservable.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStoryObservable.lessonThumbnail}" /> @@ -79,7 +79,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.story.storyName}" + android:text="@{viewModel.promotedStoryObservable.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -94,7 +94,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.story.topicName}" + android:text="@{viewModel.promotedStoryObservable.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> From ace13545c5a0aba47277074f45d97c797a274b17 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 16:06:23 -0800 Subject: [PATCH 016/248] Create custom recycler view for PromotedStoryList --- .../home/topiclist/PromotedStoryListView.kt | 29 + .../topiclist/PromotedStoryListViewModel.kt | 14 - .../app/home/topiclist/TopicListAdapter.kt | 536 +++++++++--------- .../player/state/SelectionInteractionView.kt | 4 - .../main/res/layout/promoted_story_list.xml | 2 +- 5 files changed, 298 insertions(+), 287 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt new file mode 100644 index 00000000000..9b854fe4533 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -0,0 +1,29 @@ +package org.oppia.android.app.home.topiclist + +import android.content.Context +import android.util.AttributeSet +import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.app.recyclerview.StartSnapHelper + +/** + * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to + * a fixed position on the device. + */ +class PromotedStoryListView @JvmOverloads constructor ( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : RecyclerView(context, attrs, defStyleAttr) { + + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + /* + * The StartSnapHelper is used to snap between items rather than smooth scrolling, + * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. + */ + val snapHelper = StartSnapHelper() + this.setOnFlingListener(null) + snapHelper.attachToRecyclerView(this) + } +} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 8fb0a9d6c06..4fac44eb0bc 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,9 +1,6 @@ package org.oppia.android.app.home.topiclist import android.content.Context -import android.content.res.Configuration -import android.content.res.Resources -import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations @@ -107,15 +104,4 @@ class PromotedStoryListViewModel @Inject constructor( ) activity.startActivity(intent) } - - -// /* -// * The StartSnapHelper is used to snap between items rather than smooth scrolling, -// * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. -// */ -// val snapHelper = StartSnapHelper() -// binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager -// binding.promotedStoryListRecyclerView.setOnFlingListener(null) -// snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) -// } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index 4360f87482b..74c09dc2a24 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -1,268 +1,268 @@ -package org.oppia.android.app.home.topiclist - -import android.content.Context -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView -import org.oppia.android.R -import org.oppia.android.app.home.HomeItemViewModel -import org.oppia.android.app.home.WelcomeViewModel -import org.oppia.android.app.recyclerview.StartSnapHelper -import org.oppia.android.databinding.AllTopicsBinding -import org.oppia.android.databinding.PromotedStoryListBinding -import org.oppia.android.databinding.TopicSummaryViewBinding -import org.oppia.android.databinding.WelcomeBinding - -private const val VIEW_TYPE_WELCOME_MESSAGE = 1 -private const val VIEW_TYPE_PROMOTED_STORY_LIST = 2 -private const val VIEW_TYPE_ALL_TOPICS = 3 -private const val VIEW_TYPE_TOPIC_LIST = 4 - -/** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */ -class TopicListAdapter( - private val activity: AppCompatActivity, - private val itemList: MutableList, - private val promotedStoryList: MutableList -) : - RecyclerView.Adapter() { - - private var spanCount = 0 - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - return when (viewType) { - // TODO(#216): Generalize this binding to make adding future items easier. - VIEW_TYPE_WELCOME_MESSAGE -> { - val inflater = LayoutInflater.from(parent.context) - val binding = - WelcomeBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - WelcomeViewHolder(binding) - } - VIEW_TYPE_PROMOTED_STORY_LIST -> { - val inflater = LayoutInflater.from(parent.context) - val binding = - PromotedStoryListBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - PromotedStoryListViewHolder(binding) - } - VIEW_TYPE_ALL_TOPICS -> { - val inflater = LayoutInflater.from(parent.context) - val binding = - AllTopicsBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - AllTopicsViewHolder(binding) - } - VIEW_TYPE_TOPIC_LIST -> { - val inflater = LayoutInflater.from(parent.context) - val binding = - TopicSummaryViewBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - TopicListViewHolder(binding) - } - else -> throw IllegalArgumentException("Invalid view type: $viewType") - } - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - when (holder.itemViewType) { - VIEW_TYPE_WELCOME_MESSAGE -> { - (holder as WelcomeViewHolder).bind(itemList[position] as WelcomeViewModel) - } - VIEW_TYPE_PROMOTED_STORY_LIST -> { - (holder as PromotedStoryListViewHolder).bind( - activity, - itemList[position] as PromotedStoryListViewModel, - promotedStoryList - ) - } - VIEW_TYPE_ALL_TOPICS -> { - (holder as AllTopicsViewHolder).bind() - } - VIEW_TYPE_TOPIC_LIST -> { - (holder as TopicListViewHolder).bind(itemList[position] as TopicSummaryViewModel, position) - } - } - } - - override fun getItemViewType(position: Int): Int { - return when (itemList[position]) { - is WelcomeViewModel -> { - VIEW_TYPE_WELCOME_MESSAGE - } - is AllTopicsViewModel -> { // - VIEW_TYPE_ALL_TOPICS - } - is PromotedStoryListViewModel -> { - VIEW_TYPE_PROMOTED_STORY_LIST - } - is TopicSummaryViewModel -> { // topic tiles - VIEW_TYPE_TOPIC_LIST - } - else -> throw IllegalArgumentException( - "Invalid type of data $position with item ${itemList[position]}" - ) - } - } - - override fun getItemCount(): Int { - return itemList.size - } - - fun setSpanCount(spanCount: Int) { - this.spanCount = spanCount - } - - private class WelcomeViewHolder(val binding: WelcomeBinding) : - RecyclerView.ViewHolder(binding.root) { - internal fun bind(welcomeViewModel: WelcomeViewModel) { - binding.viewModel = welcomeViewModel - } - } - - inner class PromotedStoryListViewHolder(val binding: PromotedStoryListBinding) : - RecyclerView.ViewHolder(binding.root) { - internal fun bind( - activity: AppCompatActivity, - promotedStoryListViewModel: PromotedStoryListViewModel, - promotedStoryList: MutableList - ) { - binding.viewModel = promotedStoryListViewModel - if (activity.resources.getBoolean(R.bool.isTablet)) { // reset dataList to match number of stories to display => why does tablet matter - binding.itemCount = promotedStoryList.size - } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) - val horizontalLayoutManager = - LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = promotedStoryAdapter - } - - /* - * The StartSnapHelper is used to snap between items rather than smooth scrolling, - * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. - */ - val snapHelper = StartSnapHelper() - binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager - binding.promotedStoryListRecyclerView.setOnFlingListener(null) - snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) - - val paddingEnd = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) - val paddingStart = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) - if (promotedStoryList.size > 1) { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) - } else { - binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) - } - } - } - - private class AllTopicsViewHolder(binding: AllTopicsBinding) : - RecyclerView.ViewHolder(binding.root) { - internal fun bind() { - } - } - - inner class TopicListViewHolder(val binding: TopicSummaryViewBinding) : - RecyclerView.ViewHolder(binding.root) { - internal fun bind(topicSummaryViewModel: TopicSummaryViewModel, position: Int) { - binding.viewModel = topicSummaryViewModel - - val marginLayoutParams = binding.topicContainer.layoutParams as ViewGroup.MarginLayoutParams - - val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) - - val marginTopBottom = - (activity as Context).resources - .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) - - val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) - - when (spanCount) { - 2 -> { - when { - position % spanCount == 0 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMax, - marginTopBottom - ) - else -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - marginMin, - marginTopBottom - ) - } - } - 3 -> { - when { - position % spanCount == 0 -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - /* right= */ 0, - marginTopBottom - ) - position % spanCount == 1 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMin, - marginTopBottom - ) - position % spanCount == 2 -> marginLayoutParams.setMargins( - /* left= */ 0, - marginTopBottom, - marginMax, - marginTopBottom - ) - } - } - 4 -> { - when { - (position + 1) % spanCount == 0 -> marginLayoutParams.setMargins( - marginMax, - marginTopBottom, - /* right= */ 0, - marginTopBottom - ) - (position + 1) % spanCount == 1 -> marginLayoutParams.setMargins( - marginMin, - marginTopBottom, - marginMin / 2, - marginTopBottom - ) - (position + 1) % spanCount == 2 -> marginLayoutParams.setMargins( - marginMin / 2, - marginTopBottom, - marginMin, - marginTopBottom - ) - (position + 1) % spanCount == 3 -> marginLayoutParams.setMargins( - /* left= */ 0, - marginTopBottom, - marginMax, - marginTopBottom - ) - } - } - } - binding.topicContainer.layoutParams = marginLayoutParams - } - } -} +//package org.oppia.android.app.home.topiclist +// +//import android.content.Context +//import android.view.LayoutInflater +//import android.view.ViewGroup +//import androidx.appcompat.app.AppCompatActivity +//import androidx.recyclerview.widget.LinearLayoutManager +//import androidx.recyclerview.widget.RecyclerView +//import org.oppia.android.R +//import org.oppia.android.app.home.HomeItemViewModel +//import org.oppia.android.app.home.WelcomeViewModel +//import org.oppia.android.app.recyclerview.StartSnapHelper +//import org.oppia.android.databinding.AllTopicsBinding +//import org.oppia.android.databinding.PromotedStoryListBinding +//import org.oppia.android.databinding.TopicSummaryViewBinding +//import org.oppia.android.databinding.WelcomeBinding +// +//private const val VIEW_TYPE_WELCOME_MESSAGE = 1 +//private const val VIEW_TYPE_PROMOTED_STORY_LIST = 2 +//private const val VIEW_TYPE_ALL_TOPICS = 3 +//private const val VIEW_TYPE_TOPIC_LIST = 4 +// +///** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */ +//class TopicListAdapter( +// private val activity: AppCompatActivity, +// private val itemList: MutableList, +// private val promotedStoryList: MutableList +//) : +// RecyclerView.Adapter() { +// +// private var spanCount = 0 +// +// override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { +// return when (viewType) { +// // TODO(#216): Generalize this binding to make adding future items easier. +// VIEW_TYPE_WELCOME_MESSAGE -> { +// val inflater = LayoutInflater.from(parent.context) +// val binding = +// WelcomeBinding.inflate( +// inflater, +// parent, +// /* attachToParent= */ false +// ) +// WelcomeViewHolder(binding) +// } +// VIEW_TYPE_PROMOTED_STORY_LIST -> { +// val inflater = LayoutInflater.from(parent.context) +// val binding = +// PromotedStoryListBinding.inflate( +// inflater, +// parent, +// /* attachToParent= */ false +// ) +// PromotedStoryListViewHolder(binding) +// } +// VIEW_TYPE_ALL_TOPICS -> { +// val inflater = LayoutInflater.from(parent.context) +// val binding = +// AllTopicsBinding.inflate( +// inflater, +// parent, +// /* attachToParent= */ false +// ) +// AllTopicsViewHolder(binding) +// } +// VIEW_TYPE_TOPIC_LIST -> { +// val inflater = LayoutInflater.from(parent.context) +// val binding = +// TopicSummaryViewBinding.inflate( +// inflater, +// parent, +// /* attachToParent= */ false +// ) +// TopicListViewHolder(binding) +// } +// else -> throw IllegalArgumentException("Invalid view type: $viewType") +// } +// } +// +// override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { +// when (holder.itemViewType) { +// VIEW_TYPE_WELCOME_MESSAGE -> { +// (holder as WelcomeViewHolder).bind(itemList[position] as WelcomeViewModel) +// } +// VIEW_TYPE_PROMOTED_STORY_LIST -> { +// (holder as PromotedStoryListViewHolder).bind( +// activity, +// itemList[position] as PromotedStoryListViewModel, +// promotedStoryList +// ) +// } +// VIEW_TYPE_ALL_TOPICS -> { +// (holder as AllTopicsViewHolder).bind() +// } +// VIEW_TYPE_TOPIC_LIST -> { +// (holder as TopicListViewHolder).bind(itemList[position] as TopicSummaryViewModel, position) +// } +// } +// } +// +// override fun getItemViewType(position: Int): Int { +// return when (itemList[position]) { +// is WelcomeViewModel -> { +// VIEW_TYPE_WELCOME_MESSAGE +// } +// is AllTopicsViewModel -> { // +// VIEW_TYPE_ALL_TOPICS +// } +// is PromotedStoryListViewModel -> { +// VIEW_TYPE_PROMOTED_STORY_LIST +// } +// is TopicSummaryViewModel -> { // topic tiles +// VIEW_TYPE_TOPIC_LIST +// } +// else -> throw IllegalArgumentException( +// "Invalid type of data $position with item ${itemList[position]}" +// ) +// } +// } +// +// override fun getItemCount(): Int { +// return itemList.size +// } +// +// fun setSpanCount(spanCount: Int) { +// this.spanCount = spanCount +// } +// +// private class WelcomeViewHolder(val binding: WelcomeBinding) : +// RecyclerView.ViewHolder(binding.root) { +// internal fun bind(welcomeViewModel: WelcomeViewModel) { +// binding.viewModel = welcomeViewModel +// } +// } +// +// inner class PromotedStoryListViewHolder(val binding: PromotedStoryListBinding) : +// RecyclerView.ViewHolder(binding.root) { +// internal fun bind( +// activity: AppCompatActivity, +// promotedStoryListViewModel: PromotedStoryListViewModel, +// promotedStoryList: MutableList +// ) { +// binding.viewModel = promotedStoryListViewModel +// if (activity.resources.getBoolean(R.bool.isTablet)) { // reset dataList to match number of stories to display => why does tablet matter +// binding.itemCount = promotedStoryList.size +// } +// val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) +// val horizontalLayoutManager = +// LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) +// binding.promotedStoryListRecyclerView.apply { +// layoutManager = horizontalLayoutManager +// adapter = promotedStoryAdapter +// } +// +// /* +// * The StartSnapHelper is used to snap between items rather than smooth scrolling, +// * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. +// */ +// val snapHelper = StartSnapHelper() +// binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager +// binding.promotedStoryListRecyclerView.setOnFlingListener(null) +// snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) +// +// val paddingEnd = +// (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) +// val paddingStart = +// (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) +// if (promotedStoryList.size > 1) { +// binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) +// } else { +// binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) +// } +// } +// } +// +// private class AllTopicsViewHolder(binding: AllTopicsBinding) : +// RecyclerView.ViewHolder(binding.root) { +// internal fun bind() { +// } +// } +// +// inner class TopicListViewHolder(val binding: TopicSummaryViewBinding) : +// RecyclerView.ViewHolder(binding.root) { +// internal fun bind(topicSummaryViewModel: TopicSummaryViewModel, position: Int) { +// binding.viewModel = topicSummaryViewModel +// +// val marginLayoutParams = binding.topicContainer.layoutParams as ViewGroup.MarginLayoutParams +// +// val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) +// +// val marginTopBottom = +// (activity as Context).resources +// .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) +// +// val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) +// +// when (spanCount) { +// 2 -> { +// when { +// position % spanCount == 0 -> marginLayoutParams.setMargins( +// marginMin, +// marginTopBottom, +// marginMax, +// marginTopBottom +// ) +// else -> marginLayoutParams.setMargins( +// marginMax, +// marginTopBottom, +// marginMin, +// marginTopBottom +// ) +// } +// } +// 3 -> { +// when { +// position % spanCount == 0 -> marginLayoutParams.setMargins( +// marginMax, +// marginTopBottom, +// /* right= */ 0, +// marginTopBottom +// ) +// position % spanCount == 1 -> marginLayoutParams.setMargins( +// marginMin, +// marginTopBottom, +// marginMin, +// marginTopBottom +// ) +// position % spanCount == 2 -> marginLayoutParams.setMargins( +// /* left= */ 0, +// marginTopBottom, +// marginMax, +// marginTopBottom +// ) +// } +// } +// 4 -> { +// when { +// (position + 1) % spanCount == 0 -> marginLayoutParams.setMargins( +// marginMax, +// marginTopBottom, +// /* right= */ 0, +// marginTopBottom +// ) +// (position + 1) % spanCount == 1 -> marginLayoutParams.setMargins( +// marginMin, +// marginTopBottom, +// marginMin / 2, +// marginTopBottom +// ) +// (position + 1) % spanCount == 2 -> marginLayoutParams.setMargins( +// marginMin / 2, +// marginTopBottom, +// marginMin, +// marginTopBottom +// ) +// (position + 1) % spanCount == 3 -> marginLayoutParams.setMargins( +// /* left= */ 0, +// marginTopBottom, +// marginMax, +// marginTopBottom +// ) +// } +// } +// } +// binding.topicContainer.layoutParams = marginLayoutParams +// } +// } +//} diff --git a/app/src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt b/app/src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt index cdf0c87673b..a498b0a0a34 100644 --- a/app/src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt @@ -118,10 +118,6 @@ class SelectionInteractionView @JvmOverloads constructor( } } -fun setAllOptionsItemInputType(selectionItemInputType: SelectionItemInputType) { - setAllOptionsItemInputType(selectionItemInputType) -} - /** Sets the exploration ID for a specific [SelectionInteractionView] via data-binding. */ @BindingAdapter("entityId") fun setEntityId( diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 0fc6fae7f6a..95846e89f46 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -50,7 +50,7 @@ android:textSize="14sp" /> - Date: Thu, 10 Dec 2020 16:12:09 -0800 Subject: [PATCH 017/248] Remove unused imports & TopicListAdapter --- .../topiclist/PromotedStoryListViewModel.kt | 7 - .../app/home/topiclist/TopicListAdapter.kt | 268 ------------------ 2 files changed, 275 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 4fac44eb0bc..acf07517b2e 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -5,22 +5,15 @@ import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel -import androidx.recyclerview.widget.LinearLayoutManager -import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R -import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener -import org.oppia.android.app.model.CompletedStoryList import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.IntentFactoryShim -import org.oppia.android.databinding.PromotedStoryListBinding import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData -import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.StoryHtmlParserEntityType import javax.inject.Inject diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt deleted file mode 100644 index 74c09dc2a24..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ /dev/null @@ -1,268 +0,0 @@ -//package org.oppia.android.app.home.topiclist -// -//import android.content.Context -//import android.view.LayoutInflater -//import android.view.ViewGroup -//import androidx.appcompat.app.AppCompatActivity -//import androidx.recyclerview.widget.LinearLayoutManager -//import androidx.recyclerview.widget.RecyclerView -//import org.oppia.android.R -//import org.oppia.android.app.home.HomeItemViewModel -//import org.oppia.android.app.home.WelcomeViewModel -//import org.oppia.android.app.recyclerview.StartSnapHelper -//import org.oppia.android.databinding.AllTopicsBinding -//import org.oppia.android.databinding.PromotedStoryListBinding -//import org.oppia.android.databinding.TopicSummaryViewBinding -//import org.oppia.android.databinding.WelcomeBinding -// -//private const val VIEW_TYPE_WELCOME_MESSAGE = 1 -//private const val VIEW_TYPE_PROMOTED_STORY_LIST = 2 -//private const val VIEW_TYPE_ALL_TOPICS = 3 -//private const val VIEW_TYPE_TOPIC_LIST = 4 -// -///** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */ -//class TopicListAdapter( -// private val activity: AppCompatActivity, -// private val itemList: MutableList, -// private val promotedStoryList: MutableList -//) : -// RecyclerView.Adapter() { -// -// private var spanCount = 0 -// -// override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { -// return when (viewType) { -// // TODO(#216): Generalize this binding to make adding future items easier. -// VIEW_TYPE_WELCOME_MESSAGE -> { -// val inflater = LayoutInflater.from(parent.context) -// val binding = -// WelcomeBinding.inflate( -// inflater, -// parent, -// /* attachToParent= */ false -// ) -// WelcomeViewHolder(binding) -// } -// VIEW_TYPE_PROMOTED_STORY_LIST -> { -// val inflater = LayoutInflater.from(parent.context) -// val binding = -// PromotedStoryListBinding.inflate( -// inflater, -// parent, -// /* attachToParent= */ false -// ) -// PromotedStoryListViewHolder(binding) -// } -// VIEW_TYPE_ALL_TOPICS -> { -// val inflater = LayoutInflater.from(parent.context) -// val binding = -// AllTopicsBinding.inflate( -// inflater, -// parent, -// /* attachToParent= */ false -// ) -// AllTopicsViewHolder(binding) -// } -// VIEW_TYPE_TOPIC_LIST -> { -// val inflater = LayoutInflater.from(parent.context) -// val binding = -// TopicSummaryViewBinding.inflate( -// inflater, -// parent, -// /* attachToParent= */ false -// ) -// TopicListViewHolder(binding) -// } -// else -> throw IllegalArgumentException("Invalid view type: $viewType") -// } -// } -// -// override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { -// when (holder.itemViewType) { -// VIEW_TYPE_WELCOME_MESSAGE -> { -// (holder as WelcomeViewHolder).bind(itemList[position] as WelcomeViewModel) -// } -// VIEW_TYPE_PROMOTED_STORY_LIST -> { -// (holder as PromotedStoryListViewHolder).bind( -// activity, -// itemList[position] as PromotedStoryListViewModel, -// promotedStoryList -// ) -// } -// VIEW_TYPE_ALL_TOPICS -> { -// (holder as AllTopicsViewHolder).bind() -// } -// VIEW_TYPE_TOPIC_LIST -> { -// (holder as TopicListViewHolder).bind(itemList[position] as TopicSummaryViewModel, position) -// } -// } -// } -// -// override fun getItemViewType(position: Int): Int { -// return when (itemList[position]) { -// is WelcomeViewModel -> { -// VIEW_TYPE_WELCOME_MESSAGE -// } -// is AllTopicsViewModel -> { // -// VIEW_TYPE_ALL_TOPICS -// } -// is PromotedStoryListViewModel -> { -// VIEW_TYPE_PROMOTED_STORY_LIST -// } -// is TopicSummaryViewModel -> { // topic tiles -// VIEW_TYPE_TOPIC_LIST -// } -// else -> throw IllegalArgumentException( -// "Invalid type of data $position with item ${itemList[position]}" -// ) -// } -// } -// -// override fun getItemCount(): Int { -// return itemList.size -// } -// -// fun setSpanCount(spanCount: Int) { -// this.spanCount = spanCount -// } -// -// private class WelcomeViewHolder(val binding: WelcomeBinding) : -// RecyclerView.ViewHolder(binding.root) { -// internal fun bind(welcomeViewModel: WelcomeViewModel) { -// binding.viewModel = welcomeViewModel -// } -// } -// -// inner class PromotedStoryListViewHolder(val binding: PromotedStoryListBinding) : -// RecyclerView.ViewHolder(binding.root) { -// internal fun bind( -// activity: AppCompatActivity, -// promotedStoryListViewModel: PromotedStoryListViewModel, -// promotedStoryList: MutableList -// ) { -// binding.viewModel = promotedStoryListViewModel -// if (activity.resources.getBoolean(R.bool.isTablet)) { // reset dataList to match number of stories to display => why does tablet matter -// binding.itemCount = promotedStoryList.size -// } -// val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) -// val horizontalLayoutManager = -// LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) -// binding.promotedStoryListRecyclerView.apply { -// layoutManager = horizontalLayoutManager -// adapter = promotedStoryAdapter -// } -// -// /* -// * The StartSnapHelper is used to snap between items rather than smooth scrolling, -// * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. -// */ -// val snapHelper = StartSnapHelper() -// binding.promotedStoryListRecyclerView.layoutManager = horizontalLayoutManager -// binding.promotedStoryListRecyclerView.setOnFlingListener(null) -// snapHelper.attachToRecyclerView(binding.promotedStoryListRecyclerView) -// -// val paddingEnd = -// (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) -// val paddingStart = -// (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) -// if (promotedStoryList.size > 1) { -// binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingEnd, 0) -// } else { -// binding.promotedStoryListRecyclerView.setPadding(paddingStart, 0, paddingStart, 0) -// } -// } -// } -// -// private class AllTopicsViewHolder(binding: AllTopicsBinding) : -// RecyclerView.ViewHolder(binding.root) { -// internal fun bind() { -// } -// } -// -// inner class TopicListViewHolder(val binding: TopicSummaryViewBinding) : -// RecyclerView.ViewHolder(binding.root) { -// internal fun bind(topicSummaryViewModel: TopicSummaryViewModel, position: Int) { -// binding.viewModel = topicSummaryViewModel -// -// val marginLayoutParams = binding.topicContainer.layoutParams as ViewGroup.MarginLayoutParams -// -// val marginMax = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) -// -// val marginTopBottom = -// (activity as Context).resources -// .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) -// -// val marginMin = (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) -// -// when (spanCount) { -// 2 -> { -// when { -// position % spanCount == 0 -> marginLayoutParams.setMargins( -// marginMin, -// marginTopBottom, -// marginMax, -// marginTopBottom -// ) -// else -> marginLayoutParams.setMargins( -// marginMax, -// marginTopBottom, -// marginMin, -// marginTopBottom -// ) -// } -// } -// 3 -> { -// when { -// position % spanCount == 0 -> marginLayoutParams.setMargins( -// marginMax, -// marginTopBottom, -// /* right= */ 0, -// marginTopBottom -// ) -// position % spanCount == 1 -> marginLayoutParams.setMargins( -// marginMin, -// marginTopBottom, -// marginMin, -// marginTopBottom -// ) -// position % spanCount == 2 -> marginLayoutParams.setMargins( -// /* left= */ 0, -// marginTopBottom, -// marginMax, -// marginTopBottom -// ) -// } -// } -// 4 -> { -// when { -// (position + 1) % spanCount == 0 -> marginLayoutParams.setMargins( -// marginMax, -// marginTopBottom, -// /* right= */ 0, -// marginTopBottom -// ) -// (position + 1) % spanCount == 1 -> marginLayoutParams.setMargins( -// marginMin, -// marginTopBottom, -// marginMin / 2, -// marginTopBottom -// ) -// (position + 1) % spanCount == 2 -> marginLayoutParams.setMargins( -// marginMin / 2, -// marginTopBottom, -// marginMin, -// marginTopBottom -// ) -// (position + 1) % spanCount == 3 -> marginLayoutParams.setMargins( -// /* left= */ 0, -// marginTopBottom, -// marginMax, -// marginTopBottom -// ) -// } -// } -// } -// binding.topicContainer.layoutParams = marginLayoutParams -// } -// } -//} From c891f7aa1b8448c2d856aa809b6c806805198d2a Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 17:01:42 -0800 Subject: [PATCH 018/248] Construct adapter in custom view --- .../java/org/oppia/android/app/home/WelcomeViewModel.kt | 4 +++- .../android/app/home/topiclist/PromotedStoryListView.kt | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 5c06e252076..65d780f71b2 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -31,7 +31,9 @@ class WelcomeViewModel @Inject constructor( ).getGreetingMessage() val profileName: LiveData by lazy { - Transformations.map(profileLiveData, Profile::getName) + Transformations.map(profileLiveData) { + it.name + } } private val profileResultLiveData: LiveData> by lazy { diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index 9b854fe4533..9d646209caf 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -3,7 +3,9 @@ package org.oppia.android.app.home.topiclist import android.content.Context import android.util.AttributeSet import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper +import org.oppia.android.databinding.PromotedStoryCardBinding /** * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to @@ -17,6 +19,11 @@ class PromotedStoryListView @JvmOverloads constructor ( override fun onAttachedToWindow() { super.onAttachedToWindow() + adapter = BindableAdapter.SingleTypeBuilder.newBuilder() + .registerViewDataBinderWithSameModelType( + inflateDataBinding = PromotedStoryCardBinding::inflate, + setViewModel = PromotedStoryCardBinding::setViewModel + ).build() /* * The StartSnapHelper is used to snap between items rather than smooth scrolling, From 89a947b56fdba26359898ceee346258477d8de97 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 17:32:31 -0800 Subject: [PATCH 019/248] Debugging layout data binding --- .../org/oppia/android/app/home/HomeFragmentPresenter.kt | 4 ++-- .../java/org/oppia/android/app/home/WelcomeViewModel.kt | 8 ++++++-- .../android/app/home/topiclist/PromotedStoryListView.kt | 8 +++++--- .../android/app/home/topiclist/PromotedStoryViewModel.kt | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) 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 26624806d24..5e75ff0002c 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 @@ -60,9 +60,9 @@ class HomeFragmentPresenter @Inject constructor( logger, fragment, oppiaClock, - profileManagementController, - profileId + profileManagementController ) + welcomeViewModel.setInternalProfileId(profileId) logHomeActivityEvent() val promotedStoryListViewModel = PromotedStoryListViewModel( diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 65d780f71b2..64ae436ef4f 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -22,9 +22,9 @@ class WelcomeViewModel @Inject constructor( private val logger: ConsoleLogger, private val fragment: Fragment, private val oppiaClock: OppiaClock, - private val profileManagementController: ProfileManagementController, - private val profileId: ProfileId + private val profileManagementController: ProfileManagementController ) : HomeItemViewModel() { + private lateinit var profileId : ProfileId var greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock @@ -50,4 +50,8 @@ class WelcomeViewModel @Inject constructor( } return profileResult.getOrDefault(Profile.getDefaultInstance()) } + + fun setInternalProfileId(id: ProfileId) { + this.profileId = id + } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index 9d646209caf..17286f25116 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -6,6 +6,7 @@ import androidx.recyclerview.widget.RecyclerView import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.databinding.PromotedStoryCardBinding +import org.oppia.android.databinding.PromotedStoryListBinding /** * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to @@ -19,10 +20,11 @@ class PromotedStoryListView @JvmOverloads constructor ( override fun onAttachedToWindow() { super.onAttachedToWindow() - adapter = BindableAdapter.SingleTypeBuilder.newBuilder() + adapter = BindableAdapter.SingleTypeBuilder.newBuilder() + // should this be PromotedStoryCardBinding? .registerViewDataBinderWithSameModelType( - inflateDataBinding = PromotedStoryCardBinding::inflate, - setViewModel = PromotedStoryCardBinding::setViewModel + inflateDataBinding = PromotedStoryListBinding::inflate, + setViewModel = PromotedStoryListBinding::setViewModel ).build() /* diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index aa43f670ff0..52b81e78b94 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -35,8 +35,7 @@ class PromotedStoryViewModel( * [LiveData] is used for all subsequent processed data to ensure the transformed [LiveData]s are * always in sync. */ - var promotedStoryObservable : PromotedStory = PromotedStory.getDefaultInstance() - private val orientation = Resources.getSystem().configuration.orientation + lateinit var promotedStoryObservable : PromotedStory var totalStoryCount = -1 fun setPromotedStory(promotedStory: PromotedStory) { @@ -48,6 +47,7 @@ class PromotedStoryViewModel( } fun computeLayoutWidth(): Int { + val orientation = Resources.getSystem().configuration.orientation if (totalStoryCount > 1) { if (orientation == Configuration.ORIENTATION_PORTRAIT) { return ViewGroup.LayoutParams.MATCH_PARENT From efa6a2af0fff4d2fc77b3ec8c2066f7f40a5f501 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 17:55:37 -0800 Subject: [PATCH 020/248] Add PromotedStoryCard to custom promoted story list view --- .../android/app/home/topiclist/PromotedStoryListView.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index 17286f25116..86f60ecb573 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -20,11 +20,11 @@ class PromotedStoryListView @JvmOverloads constructor ( override fun onAttachedToWindow() { super.onAttachedToWindow() - adapter = BindableAdapter.SingleTypeBuilder.newBuilder() + adapter = BindableAdapter.SingleTypeBuilder.newBuilder() // should this be PromotedStoryCardBinding? .registerViewDataBinderWithSameModelType( - inflateDataBinding = PromotedStoryListBinding::inflate, - setViewModel = PromotedStoryListBinding::setViewModel + inflateDataBinding = PromotedStoryCardBinding::inflate, + setViewModel = PromotedStoryCardBinding::setViewModel ).build() /* From 4447d1b8c2bc2c3a6ee804e7ff3cff62c154079f Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 18:04:28 -0800 Subject: [PATCH 021/248] Remove unused imports --- .../main/java/org/oppia/android/app/home/WelcomeViewModel.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 64ae436ef4f..6226a8b1a1d 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -1,12 +1,9 @@ package org.oppia.android.app.home -import android.app.AppComponentFactory -import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel -import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.domain.profile.ProfileManagementController From 2f4f2e7b44256afb316a0bf6498edd47f2cc536c Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 19:00:39 -0800 Subject: [PATCH 022/248] Set topic summary position to start at 1 --- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 2 +- .../main/java/org/oppia/android/app/home/WelcomeViewModel.kt | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index e8fb47f2b4d..d183060ce5b 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -40,7 +40,7 @@ class HomeViewModel @Inject constructor( topicEntityType, fragment as TopicSummaryClickListener ) - topicSummaryViewModel.setPosition(itemListLiveData.topicSummaryList.indexOf(topicSummary)) + topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) itemList.add(topicSummaryViewModel) } return itemList diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 6226a8b1a1d..0dca3fa1414 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -17,8 +17,8 @@ import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel @Inject constructor( private val logger: ConsoleLogger, - private val fragment: Fragment, - private val oppiaClock: OppiaClock, + fragment: Fragment, + oppiaClock: OppiaClock, private val profileManagementController: ProfileManagementController ) : HomeItemViewModel() { private lateinit var profileId : ProfileId From 138435830b10435fc6738c8f95d462fd0b9d66b1 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Thu, 10 Dec 2020 20:09:40 -0800 Subject: [PATCH 023/248] Set adapter in initializer --- .../android/app/home/topiclist/PromotedStoryListView.kt | 4 +--- .../app/home/topiclist/PromotedStoryListViewModel.kt | 4 ++-- .../android/app/home/topiclist/PromotedStoryViewModel.kt | 2 +- .../android/app/home/topiclist/TopicSummaryViewModel.kt | 6 +++--- 4 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index 86f60ecb573..766c662ad11 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -6,7 +6,6 @@ import androidx.recyclerview.widget.RecyclerView import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.databinding.PromotedStoryCardBinding -import org.oppia.android.databinding.PromotedStoryListBinding /** * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to @@ -18,8 +17,7 @@ class PromotedStoryListView @JvmOverloads constructor ( defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr) { - override fun onAttachedToWindow() { - super.onAttachedToWindow() + init { adapter = BindableAdapter.SingleTypeBuilder.newBuilder() // should this be PromotedStoryCardBinding? .registerViewDataBinderWithSameModelType( diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index acf07517b2e..efc29e18ff1 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -29,9 +29,9 @@ class PromotedStoryListViewModel @Inject constructor( RouteToRecentlyPlayedListener { private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) val paddingEnd = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_end) + activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) val paddingStart = - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_padding_start) + activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) private val ongoingStoryListSummaryResultLiveData: LiveData> by lazy { diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 52b81e78b94..022762b5cf3 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -52,7 +52,7 @@ class PromotedStoryViewModel( if (orientation == Configuration.ORIENTATION_PORTRAIT) { return ViewGroup.LayoutParams.MATCH_PARENT } else { - return (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) + return activity.resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) } } else { return ViewGroup.LayoutParams.MATCH_PARENT diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 794ca9186c9..2310063c6ba 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -29,12 +29,12 @@ class TopicSummaryViewModel ( val backgroundColor: Int = retrieveBackgroundColor() @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() - private val marginTopBottom = (activity as Context).resources + private val marginTopBottom = activity.resources .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) private val marginMax by lazy { - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_max) } + activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) } private val marginMin by lazy { - (activity as Context).resources.getDimensionPixelSize(R.dimen.home_margin_min) } + activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) } private var position = -1 private val spanCount by lazy { activity.resources.getInteger(R.integer.home_span_count) } From 0d0e0d6129a9bb241176a815cc315ab7adaa258c Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 11 Dec 2020 13:39:51 +0530 Subject: [PATCH 024/248] implemented recommendation system --- .idea/gradle.xml | 3 +- .idea/misc.xml | 4 +- .../NavigationDrawerFragmentPresenter.kt | 10 +- .../android/app/home/HomeFragmentPresenter.kt | 93 +++++-- .../recentlyplayed/RecentlyPlayedActivity.kt | 3 +- .../topiclist/ComingSoonTopicListAdapter.kt | 55 ++++ .../ComingSoonTopicsListViewModel.kt | 45 ++++ .../home/topiclist/PromotedItemViewModel.kt | 6 + .../home/topiclist/PromotedStoryViewModel.kt | 4 +- .../app/home/topiclist/TopicListAdapter.kt | 70 ++++- .../player/exploration/ExplorationActivity.kt | 12 +- .../ExplorationActivityPresenter.kt | 8 +- .../player/exploration/ExplorationFragment.kt | 14 +- .../ExplorationFragmentPresenter.kt | 5 +- .../android/app/player/state/StateFragment.kt | 9 +- .../player/state/StateFragmentPresenter.kt | 60 ++++- .../StateFragmentTestActivityPresenter.kt | 8 +- .../oppia/android/app/story/StoryActivity.kt | 3 +- .../app/testing/ExplorationTestActivity.kt | 3 +- .../android/app/testing/TopicTestActivity.kt | 3 +- .../app/testing/TopicTestActivityForStory.kt | 4 +- .../oppia/android/app/topic/TopicActivity.kt | 3 +- .../app/walkthrough/WalkthroughActivity.kt | 29 ++- .../end/WalkthroughEndPageChanger.kt | 1 + .../end/WalkthroughFinalFragmentPresenter.kt | 51 +++- ...ft_rounded_rect_coming_soon_background.xml | 12 + .../layout-land/coming_soon_topic_view.xml | 106 ++++++++ .../walkthrough_final_fragment.xml | 1 + .../coming_soon_topic_view.xml | 106 ++++++++ .../res/layout/coming_soon_topic_view.xml | 106 ++++++++ .../main/res/layout/promoted_story_list.xml | 1 + .../res/layout/walkthrough_final_fragment.xml | 1 + app/src/main/res/values/strings.xml | 3 +- .../src/main/assets/coming_soon_topics.json | 8 + domain/src/main/assets/test_exp_id_4.json | 3 + .../domain/topic/StoryProgressController.kt | 45 +++- .../domain/topic/StoryProgressTestHelper.kt | 51 ++-- .../domain/topic/TopicListController.kt | 241 +++++++++++++++--- .../topic/StoryProgressControllerTest.kt | 21 +- .../domain/topic/TopicControllerTest.kt | 12 +- .../domain/topic/TopicListControllerTest.kt | 48 ++-- model/src/main/proto/topic.proto | 48 +++- 42 files changed, 1169 insertions(+), 150 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt create mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt create mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt create mode 100644 app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml create mode 100644 app/src/main/res/layout-land/coming_soon_topic_view.xml create mode 100644 app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml create mode 100644 app/src/main/res/layout/coming_soon_topic_view.xml create mode 100644 domain/src/main/assets/coming_soon_topics.json diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 6aa35f75034..6466b7bedb7 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -20,7 +20,8 @@ - + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index f06c82261e6..d5d35ec44f1 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,9 @@ - + - + \ No newline at end of file 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 5de1a3c745f..a59ef02aae4 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 @@ -28,6 +28,7 @@ import org.oppia.android.app.options.OptionsActivity import org.oppia.android.app.profileprogress.ProfileProgressActivity import org.oppia.android.app.topic.TopicActivity import org.oppia.android.app.viewmodel.ViewModelProvider +import org.oppia.android.app.walkthrough.WalkthroughActivity import org.oppia.android.databinding.DrawerFragmentBinding import org.oppia.android.databinding.NavHeaderNavigationDrawerBinding import org.oppia.android.domain.profile.ProfileManagementController @@ -214,9 +215,12 @@ class NavigationDrawerFragmentPresenter @Inject constructor( drawerLayout.closeDrawers() } NavigationDrawerItem.HELP -> { - val intent = HelpActivity.createHelpActivityIntent( - activity, internalProfileId, - /* isFromNavigationDrawer= */ true +// val intent = HelpActivity.createHelpActivityIntent( +// activity, internalProfileId, +// /* isFromNavigationDrawer= */ true +// ) + val intent = WalkthroughActivity.createWalkthroughActivityIntent( + activity, internalProfileId ) fragment.activity!!.startActivity(intent) if (checkIfPreviousActivityShouldGetFinished(menuItemId)) { 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 39a2d07e6d1..76cde6be4aa 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 @@ -1,5 +1,6 @@ package org.oppia.android.app.home +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -13,6 +14,7 @@ import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel +import org.oppia.android.app.home.topiclist.ComingSoonTopicsListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicListAdapter @@ -22,6 +24,7 @@ import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.shim.IntentFactoryShim @@ -55,6 +58,7 @@ class HomeFragmentPresenter @Inject constructor( private val routeToTopicListener = activity as RouteToTopicListener private val itemList: MutableList = ArrayList() private val promotedStoryList: MutableList = ArrayList() + private val comingSoonTopicList: MutableList = ArrayList() private lateinit var welcomeViewModel: WelcomeViewModel private lateinit var promotedStoryListViewModel: PromotedStoryListViewModel private lateinit var allTopicsViewModel: AllTopicsViewModel @@ -63,6 +67,7 @@ class HomeFragmentPresenter @Inject constructor( private var internalProfileId: Int = -1 private lateinit var profileId: ProfileId private lateinit var profileName: String + private var promotedStoriesType = PromotedStoriesType.PromotedStoriesTypeCase.PROMOTEDSTORIESTYPE_NOT_SET fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) @@ -83,7 +88,7 @@ class HomeFragmentPresenter @Inject constructor( itemList.add(welcomeViewModel) itemList.add(promotedStoryListViewModel) itemList.add(allTopicsViewModel) - topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList) + topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList,comingSoonTopicList) val spanCount = activity.resources.getInteger(R.integer.home_span_count) topicListAdapter.setSpanCount(spanCount) @@ -146,6 +151,10 @@ class HomeFragmentPresenter @Inject constructor( topicListController.getTopicList() } + private val comingSoontopicListSummaryResultLiveData: LiveData> by lazy { + topicListController.getComingSoonTopicList() + } + private fun subscribeToTopicList() { getAssumedSuccessfulTopicList().observe( fragment, @@ -164,6 +173,24 @@ class HomeFragmentPresenter @Inject constructor( ) } + private fun subscribeToComingSoonTopicList() { + getAssumedSuccessfulComingSoonTopicList().observe( + fragment, + Observer { result -> + for (topicSummary in result.topicSummaryList) { + val comingSoontopicViewModel = + ComingSoonTopicsListViewModel( + topicSummary, + topicEntityType, + fragment as TopicSummaryClickListener + ) + comingSoonTopicList.add(comingSoontopicViewModel) + } + topicListAdapter.notifyItemChanged(1) + } + ) + } + private fun getAssumedSuccessfulTopicList(): LiveData { // If there's an error loading the data, assume the default. return Transformations.map(topicListSummaryResultLiveData) { @@ -171,6 +198,13 @@ class HomeFragmentPresenter @Inject constructor( } } + private fun getAssumedSuccessfulComingSoonTopicList(): LiveData { + // If there's an error loading the data, assume the default. + return Transformations.map(comingSoontopicListSummaryResultLiveData) { + it.getOrDefault(TopicList.getDefaultInstance()) + } + } + private fun setProfileName() { if (::welcomeViewModel.isInitialized && ::profileName.isInitialized) { welcomeViewModel.profileName.set(profileName) @@ -195,31 +229,54 @@ class HomeFragmentPresenter @Inject constructor( fragment, Observer { promotedStoryList.clear() - if (it.recentStoryCount != 0) { - it.recentStoryList.take(limit).forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - recentStory.setPromotedStory(promotedStory) - promotedStoryList.add(recentStory) + promotedStoriesType = it.promotedStoriesType.promotedStoriesTypeCase + if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.RECENTLY_PLAYED){ + if (it.recentStoryCount != 0) { + it.recentStoryList.take(limit).forEach { promotedStory -> + val recentStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim, + promotedStoriesType + ) + recentStory.setPromotedStory(promotedStory) + promotedStoryList.add(recentStory) + } + }else { + it.olderStoryList.take(limit).forEach { promotedStory -> + val olderStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim, + promotedStoriesType + ) + olderStory.setPromotedStory(promotedStory) + promotedStoryList.add(olderStory) + } } - } else { + topicListAdapter.notifyItemChanged(1) + }else if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED){ + // TODO(#936): Optimise this as part of recommended stories. - it.olderStoryList.take(limit).forEach { promotedStory -> - val oldStory = PromotedStoryViewModel( + it.recommendedStoryList.take(limit).forEach { promotedStory -> + val recommendedStory = PromotedStoryViewModel( activity, internalProfileId, storyEntityType, - intentFactoryShim + intentFactoryShim, + promotedStoriesType ) - oldStory.setPromotedStory(promotedStory) - promotedStoryList.add(oldStory) + recommendedStory.setPromotedStory(promotedStory) + promotedStoryList.add(recommendedStory) + } + topicListAdapter.notifyItemChanged(1) + }else if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.COMING_SOON) { + subscribeToComingSoonTopicList() } - topicListAdapter.notifyItemChanged(1) + } ) } diff --git a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt index fcb09bc3876..78f19cd66c4 100644 --- a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt +++ b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt @@ -51,7 +51,8 @@ class RecentlyPlayedActivity : InjectableAppCompatActivity(), RouteToExploration topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt new file mode 100644 index 00000000000..9abcbb3f833 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt @@ -0,0 +1,55 @@ +package org.oppia.android.app.home.topiclist + +import android.content.Context +import android.content.res.Configuration +import android.content.res.Resources +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.R +import org.oppia.android.databinding.ComingSoonTopicViewBinding +import org.oppia.android.databinding.PromotedStoryCardBinding + +/** Adapter to bind promoted stories to [RecyclerView] inside [HomeFragment] to create carousel. */ +class ComingSoonTopicListAdapter( + private val activity: AppCompatActivity, + private val itemList: MutableList +) : + RecyclerView.Adapter() { + + private var spanCount = 0 + + private val orientation = Resources.getSystem().configuration.orientation + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { + val inflater = LayoutInflater.from(parent.context) + val binding = + ComingSoonTopicViewBinding.inflate( + inflater, + parent, + /* attachToParent= */ false + ) + return ComingSoonTopicsViewHolder(binding) + } + + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { + (holder as ComingSoonTopicsViewHolder).bind(itemList[position]) + } + + override fun getItemCount(): Int { + return itemList.size + } + + fun setSpanCount(spanCount: Int) { + this.spanCount = spanCount + } + + inner class ComingSoonTopicsViewHolder( + val binding: ComingSoonTopicViewBinding + ) : RecyclerView.ViewHolder(binding.root) { + internal fun bind(comingSoonTopicsListViewModel: ComingSoonTopicsListViewModel) { + binding.viewModel = comingSoonTopicsListViewModel + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt new file mode 100644 index 00000000000..dfbf7c79866 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt @@ -0,0 +1,45 @@ +package org.oppia.android.app.home.topiclist + +import android.graphics.Color +import androidx.annotation.ColorInt +import org.oppia.android.app.home.HomeItemViewModel +import org.oppia.android.app.model.TopicSummary +import java.util.* + +// TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. +// These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the +// mocks were not consistently darker. An alternative would be to specify both background colors together to ensure +// proper contrast with readable elements. + +/** The view model corresponding to coming soon topic summaries in the topic summary RecyclerView. */ +class ComingSoonTopicsListViewModel( + val topicSummary: TopicSummary, + val entityType: String, + private val topicSummaryClickListener: TopicSummaryClickListener +) : Observable() { + val name: String = topicSummary.name + val totalChapterCount: Int = topicSummary.totalChapterCount + @ColorInt + val backgroundColor: Int = retrieveBackgroundColor() + @ColorInt + val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() + + /** Callback from data-binding for when the summary tile is clicked. */ + fun clickOnSummaryTile() { + topicSummaryClickListener.onTopicSummaryClicked(topicSummary) + } + + @ColorInt + private fun retrieveBackgroundColor(): Int { + return topicSummary.topicThumbnail.backgroundColorRgb + } + + /** Returns a version of [backgroundColor] that is slightly darker. */ + private fun computeDarkerBackgroundColor(): Int { + val hsv = floatArrayOf(0f, 0f, 0f) + Color.colorToHSV(backgroundColor, hsv) + hsv[1] = (hsv[1] * DARKEN_SATURATION_MULTIPLIER).coerceIn(0f, 1f) + hsv[2] = (hsv[2] * DARKEN_VALUE_MULTIPLIER).coerceIn(0f, 1f) + return Color.HSVToColor(hsv) + } +} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt new file mode 100644 index 00000000000..10e3800728a --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt @@ -0,0 +1,6 @@ +package org.oppia.android.app.home.topiclist + +import org.oppia.android.app.viewmodel.ObservableViewModel + +/** The root [ViewModel] for all individual items that may be displayed in home fragment recycler view. */ +abstract class PromotedItemViewModel : ObservableViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 749f0f8e513..6153b25fb95 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -5,6 +5,7 @@ import androidx.databinding.ObservableField import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import org.oppia.android.app.home.RouteToTopicPlayStoryListener +import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel @@ -16,7 +17,8 @@ class PromotedStoryViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, val entityType: String, - private val IntentFactoryShim: IntentFactoryShim + private val IntentFactoryShim: IntentFactoryShim, + val promotedStoriesType: PromotedStoriesType.PromotedStoriesTypeCase ) : ObservableViewModel(), RouteToTopicPlayStoryListener { diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index e730c5f21a3..96c8911b15e 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -2,6 +2,7 @@ package org.oppia.android.app.home.topiclist import android.content.Context import android.view.LayoutInflater +import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager @@ -9,6 +10,7 @@ import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.WelcomeViewModel +import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.PromotedStoryListBinding @@ -19,17 +21,22 @@ private const val VIEW_TYPE_WELCOME_MESSAGE = 1 private const val VIEW_TYPE_PROMOTED_STORY_LIST = 2 private const val VIEW_TYPE_ALL_TOPICS = 3 private const val VIEW_TYPE_TOPIC_LIST = 4 +private const val VIEW_TYPE_COMING_SOON_TOPIC_LIST = 5 /** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */ class TopicListAdapter( private val activity: AppCompatActivity, private val itemList: MutableList, - private val promotedStoryList: MutableList + private val promotedStoryList: MutableList, + private val comingSoonTopicList: MutableList ) : RecyclerView.Adapter() { private var spanCount = 0 + private lateinit var promotedStoryViewModel: PromotedStoryViewModel + private lateinit var comingSoonTopicsListViewModel: ComingSoonTopicsListViewModel + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { // TODO(#216): Generalize this binding to make adding future items easier. @@ -86,7 +93,8 @@ class TopicListAdapter( (holder as PromotedStoryListViewHolder).bind( activity, itemList[position] as PromotedStoryListViewModel, - promotedStoryList + promotedStoryList, + comingSoonTopicList ) } VIEW_TYPE_ALL_TOPICS -> { @@ -138,18 +146,58 @@ class TopicListAdapter( internal fun bind( activity: AppCompatActivity, promotedStoryListViewModel: PromotedStoryListViewModel, - promotedStoryList: MutableList + promotedStoryList: MutableList, + comingSoonTopicList: MutableList ) { + binding.viewModel = promotedStoryListViewModel - if (activity.resources.getBoolean(R.bool.isTablet)) { - binding.itemCount = promotedStoryList.size - } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) - val horizontalLayoutManager = + + val horizontalLayoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = promotedStoryAdapter + + if (promotedStoryList.size!=0) { + if (activity.resources.getBoolean(R.bool.isTablet)) { + binding.itemCount = promotedStoryList.size + } + when (promotedStoryList[0].promotedStoriesType) { + PromotedStoriesType.PromotedStoriesTypeCase.RECENTLY_PLAYED -> { + binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) + binding.viewAllTextView.visibility = View.VISIBLE + } + PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED -> { + binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recommended_stories)) + binding.viewAllTextView.visibility = View.INVISIBLE + } + else -> { + binding.recentlyPlayedStoriesTextView.visibility = View.GONE + binding.viewAllTextView.visibility = View.GONE + } + } + val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) + + binding.promotedStoryListRecyclerView.apply { + layoutManager = horizontalLayoutManager + adapter = promotedStoryAdapter + } + }else if (comingSoonTopicList.size!=0){ + + if (activity.resources.getBoolean(R.bool.isTablet)) { + binding.itemCount = comingSoonTopicList.size + } + + binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.coming_soon)) + binding.viewAllTextView.visibility = View.INVISIBLE + + val comingSoonTopicListAdapter = ComingSoonTopicListAdapter(activity, comingSoonTopicList) + comingSoonTopicListAdapter.setSpanCount(spanCount) + + binding.promotedStoryListRecyclerView.apply { + layoutManager = horizontalLayoutManager + adapter = comingSoonTopicListAdapter + } + }else{ + binding.recentlyPlayedStoriesTextView.visibility = View.GONE + binding.viewAllTextView.visibility = View.GONE } /* diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt index 1a3aa618ec1..bd7a701f9d6 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt @@ -46,6 +46,7 @@ class ExplorationActivity : private lateinit var explorationId: String private lateinit var state: State private var backflowScreen: Int? = null + private var isFromWalkthrough: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -54,14 +55,17 @@ class ExplorationActivity : topicId = intent.getStringExtra(EXPLORATION_ACTIVITY_TOPIC_ID_ARGUMENT_KEY) storyId = intent.getStringExtra(EXPLORATION_ACTIVITY_STORY_ID_ARGUMENT_KEY) explorationId = intent.getStringExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY) + explorationId = intent.getStringExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY) backflowScreen = intent.getIntExtra(EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY, -1) + isFromWalkthrough = intent.getBooleanExtra(EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY, false) explorationActivityPresenter.handleOnCreate( this, internalProfileId, topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough ) } @@ -77,6 +81,8 @@ class ExplorationActivity : "ExplorationActivity.exploration_id" const val EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY = "ExplorationActivity.backflow_screen" + const val EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY = + "ExplorationActivity.is_from_walkthrough_screen" fun createExplorationActivityIntent( context: Context, @@ -84,7 +90,8 @@ class ExplorationActivity : topicId: String, storyId: String, explorationId: String, - backflowScreen: Int? + backflowScreen: Int?, + isFromWalkthrough: Boolean ): Intent { val intent = Intent(context, ExplorationActivity::class.java) intent.putExtra(EXPLORATION_ACTIVITY_PROFILE_ID_ARGUMENT_KEY, profileId) @@ -92,6 +99,7 @@ class ExplorationActivity : intent.putExtra(EXPLORATION_ACTIVITY_STORY_ID_ARGUMENT_KEY, storyId) intent.putExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY, explorationId) intent.putExtra(EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY, backflowScreen) + intent.putExtra(EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY, isFromWalkthrough) return intent } } diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt index 5421e4705d0..fa821292e07 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt @@ -48,6 +48,7 @@ class ExplorationActivityPresenter @Inject constructor( private lateinit var explorationId: String private lateinit var context: Context private var backflowScreen: Int? = null + private var isFromWalkthrough: Boolean = false enum class ParentActivityForExploration(val value: Int) { BACKFLOW_SCREEN_LESSONS(0), @@ -64,7 +65,8 @@ class ExplorationActivityPresenter @Inject constructor( topicId: String, storyId: String, explorationId: String, - backflowScreen: Int? + backflowScreen: Int?, + isFromWalkthrough: Boolean ) { val binding = DataBindingUtil.setContentView( activity, @@ -98,6 +100,7 @@ class ExplorationActivityPresenter @Inject constructor( this.explorationId = explorationId this.context = context this.backflowScreen = backflowScreen + this.isFromWalkthrough = isFromWalkthrough if (getExplorationManagerFragment() == null) { val explorationManagerFragment = ExplorationManagerFragment() val args = Bundle() @@ -123,7 +126,8 @@ class ExplorationActivityPresenter @Inject constructor( internalProfileId = internalProfileId, storyId = storyId, readingTextSize = readingTextSize.name, - explorationId = explorationId + explorationId = explorationId, + isFromWalkthrough = isFromWalkthrough ), TAG_EXPLORATION_FRAGMENT ).commitNow() diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt index b8ac46fac0c..853ea364484 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt @@ -26,6 +26,8 @@ class ExplorationFragment : InjectableFragment() { "ExplorationFragment.story_default_font_size" internal const val EXPLORATION_ID_ARGUMENT_KEY = "ExplorationFragment.exploration_id" + internal const val EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY = + "ExplorationFragment.is_from_walkthrough" /** Returns a new [ExplorationFragment] to pass the profileId, topicId, storyId, readingTextSize and explorationId. */ fun newInstance( @@ -33,7 +35,8 @@ class ExplorationFragment : InjectableFragment() { topicId: String, storyId: String, readingTextSize: String, - explorationId: String + explorationId: String, + isFromWalkthrough: Boolean ): ExplorationFragment { val explorationFragment = ExplorationFragment() val args = Bundle() @@ -51,6 +54,10 @@ class ExplorationFragment : InjectableFragment() { EXPLORATION_ID_ARGUMENT_KEY, explorationId ) + args.putBoolean( + EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY, + isFromWalkthrough + ) explorationFragment.arguments = args return explorationFragment } @@ -81,13 +88,16 @@ class ExplorationFragment : InjectableFragment() { val explorationId = arguments!!.getString(EXPLORATION_ID_ARGUMENT_KEY) checkNotNull(explorationId) { "StateFragment must be created with an exploration ID" } + val isFromWalkthrough = + arguments!!.getBoolean(EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY) return explorationFragmentPresenter.handleCreateView( inflater, container, profileId, topicId, storyId, - explorationId + explorationId, + isFromWalkthrough ) } diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt index be57cf17643..24196feb6a6 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt @@ -26,11 +26,12 @@ class ExplorationFragmentPresenter @Inject constructor( profileId: Int, topicId: String, storyId: String, - explorationId: String + explorationId: String, + isFromWalkthrough: Boolean ): View? { val binding = ExplorationFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false).root - val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId) + val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId, isFromWalkthrough) logPracticeFragmentEvent(topicId, storyId, explorationId) if (getStateFragment() == null) { fragment.childFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt index 1eff9e90ff0..cfcc94fef87 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt @@ -46,7 +46,8 @@ class StateFragment : internalProfileId: Int, topicId: String, storyId: String, - explorationId: String + explorationId: String, + isFromWalkthrough: Boolean ): StateFragment { val stateFragment = StateFragment() val args = Bundle() @@ -54,6 +55,7 @@ class StateFragment : args.putString(STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY, topicId) args.putString(STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY, storyId) args.putString(STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY, explorationId) + args.putBoolean(STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY, isFromWalkthrough) stateFragment.arguments = args return stateFragment } @@ -76,13 +78,16 @@ class StateFragment : val topicId = arguments!!.getString(STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY)!! val storyId = arguments!!.getString(STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY)!! val explorationId = arguments!!.getString(STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY)!! + val isFromWalkthrough = arguments!!.getBoolean( + STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY) return stateFragmentPresenter.handleCreateView( inflater, container, internalProfileId, topicId, storyId, - explorationId + explorationId, + isFromWalkthrough ) } diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt index 43737cab4be..f196fc365eb 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt @@ -1,6 +1,7 @@ package org.oppia.android.app.player.state import android.content.Context +import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -23,6 +24,7 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.Solution import org.oppia.android.app.model.State import org.oppia.android.app.model.UserAnswer +import org.oppia.android.app.model.Walkthrough import org.oppia.android.app.player.audio.AudioButtonListener import org.oppia.android.app.player.audio.AudioFragment import org.oppia.android.app.player.audio.AudioUiManager @@ -33,6 +35,7 @@ import org.oppia.android.app.viewmodel.ViewModelProvider import org.oppia.android.databinding.StateFragmentBinding import org.oppia.android.domain.exploration.ExplorationProgressController import org.oppia.android.domain.topic.StoryProgressController +import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.gcsresource.DefaultResourceBucketName @@ -45,6 +48,7 @@ const val STATE_FRAGMENT_PROFILE_ID_ARGUMENT_KEY = "STATE_FRAGMENT_PROFILE_ID_AR const val STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY = "STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY" const val STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY = "STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY" const val STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY = "STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY" +const val STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY = "STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUH_ARGUMENT_KEY" private const val TAG_AUDIO_FRAGMENT = "AUDIO_FRAGMENT" /** The presenter for [StateFragment]. */ @@ -56,6 +60,7 @@ class StateFragmentPresenter @Inject constructor( private val viewModelProvider: ViewModelProvider, private val explorationProgressController: ExplorationProgressController, private val storyProgressController: StoryProgressController, + private val topicListController: TopicListController, private val logger: ConsoleLogger, @DefaultResourceBucketName private val resourceBucketName: String, private val assemblerBuilderFactory: StatePlayerRecyclerViewAssembler.Builder.Factory, @@ -70,6 +75,7 @@ class StateFragmentPresenter @Inject constructor( private lateinit var topicId: String private lateinit var storyId: String private lateinit var explorationId: String + private var isFromWalkthrough: Boolean = false private lateinit var currentStateName: String private lateinit var binding: StateFragmentBinding private lateinit var recyclerViewAdapter: RecyclerView.Adapter<*> @@ -88,12 +94,14 @@ class StateFragmentPresenter @Inject constructor( internalProfileId: Int, topicId: String, storyId: String, - explorationId: String + explorationId: String, + isFromWalkthrough: Boolean ): View? { profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() this.topicId = topicId this.storyId = storyId this.explorationId = explorationId + this.isFromWalkthrough = isFromWalkthrough binding = StateFragmentBinding.inflate( inflater, @@ -141,7 +149,7 @@ class StateFragmentPresenter @Inject constructor( } subscribeToCurrentState() - markExplorationAsRecentlyPlayed() + subscribeToWalkthroughData() return binding.root } @@ -502,23 +510,55 @@ class StateFragmentPresenter @Inject constructor( } } - private fun markExplorationAsRecentlyPlayed() { - storyProgressController.recordRecentlyPlayedChapter( - profileId, - topicId, - storyId, - explorationId, - Date().time + private val walkthroughResultLiveData: + LiveData> + by lazy { + topicListController.getWalkthroughData(profileId).toLiveData() + } + private fun getAssumedSuccessfulWalkthroughData(): LiveData { + // If there's an error loading the data, assume the default. + return Transformations.map(walkthroughResultLiveData) { + it.getOrDefault( + Walkthrough.getDefaultInstance() + ) + } + } + + private fun subscribeToWalkthroughData() { + getAssumedSuccessfulWalkthroughData().observe( + fragment, + Observer { + if(it.topicId == topicId){ + isFromWalkthrough = true + + Log.d("topic state T=", "==" +it.topicId +" == " + topicId ) + }else{ + Log.d("topic state F=", "==" +it.topicId +" == " + topicId ) + isFromWalkthrough = false + } + markExplorationAsRecentlyPlayed() + } ) } + private fun markExplorationAsRecentlyPlayed() { + storyProgressController.recordRecentlyPlayedChapter( + profileId, + topicId, + storyId, + explorationId, + Date().time, + isFromWalkthrough) + } + private fun markExplorationCompleted() { storyProgressController.recordCompletedChapter( profileId, topicId, storyId, explorationId, - Date().time + Date().time, + isFromWalkthrough ) } } diff --git a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt index d25d68d172c..177347f97e3 100644 --- a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt @@ -103,7 +103,13 @@ class StateFragmentTestActivityPresenter @Inject constructor( ) { getStateFragmentTestViewModel().hasExplorationStarted.set(true) - val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId) + val stateFragment = StateFragment.newInstance( + profileId, + topicId, + storyId, + explorationId, + isFromWalkthrough = false + ) activity.supportFragmentManager.beginTransaction().add( R.id.state_fragment_placeholder, stateFragment diff --git a/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt b/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt index a3e57491dc7..967b492c1d0 100644 --- a/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt +++ b/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt @@ -43,7 +43,8 @@ class StoryActivity : InjectableAppCompatActivity(), RouteToExplorationListener topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt index 5281e777a50..4ba6ae957a9 100644 --- a/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt @@ -32,7 +32,8 @@ class ExplorationTestActivity : InjectableAppCompatActivity(), RouteToExploratio topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt index 3111170ebde..c679da5b8e7 100644 --- a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt @@ -69,7 +69,8 @@ class TopicTestActivity : topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt index ad9879f1943..8f4be3b1751 100644 --- a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt +++ b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt @@ -70,7 +70,8 @@ class TopicTestActivityForStory : topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } @@ -83,3 +84,4 @@ class TopicTestActivityForStory : ) } } + diff --git a/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt b/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt index a158d2fa7e3..14c453151c0 100755 --- a/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt +++ b/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt @@ -86,7 +86,8 @@ class TopicActivity : topicId, storyId, explorationId, - backflowScreen + backflowScreen, + isFromWalkthrough = false ) ) } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt index 8e62c6f3974..5c6c5f8c7b0 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt @@ -4,10 +4,15 @@ import android.content.Context import android.content.Intent import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity +import org.oppia.android.app.home.RouteToExplorationListener +import org.oppia.android.app.home.RouteToTopicListener +import org.oppia.android.app.player.exploration.ExplorationActivity +import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject /** Activity that contains the walkthrough flow for users. */ -class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentChangeListener { +class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentChangeListener, + RouteToExplorationListener { @Inject lateinit var walkthroughActivityPresenter: WalkthroughActivityPresenter @@ -26,6 +31,28 @@ class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentCh walkthroughActivityPresenter.changePage(walkthroughPage) } + override fun routeToExploration( + internalProfileId: Int, + topicId: String, + storyId: String, + explorationId: String, + backflowScreen: Int? + ) { + startActivity( + ExplorationActivity.createExplorationActivityIntent( + this, + internalProfileId, + topicId, + storyId, + explorationId, + backflowScreen, + isFromWalkthrough = true + ) + ) + finish() + } + + override fun onBackPressed() { walkthroughActivityPresenter.handleSystemBack() } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt index c21ea4e030f..15880161d4f 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt @@ -4,4 +4,5 @@ package org.oppia.android.app.walkthrough.end interface WalkthroughEndPageChanger { fun goBack() + fun goToTopicsPage() } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt index 2a0189200c4..12392ae2bfc 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt @@ -10,14 +10,21 @@ import androidx.lifecycle.Observer import androidx.lifecycle.Transformations import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope +import org.oppia.android.app.home.RouteToExplorationListener import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.Topic +import org.oppia.android.app.model.Walkthrough import org.oppia.android.app.walkthrough.WalkthroughActivity +import org.oppia.android.app.walkthrough.WalkthroughFragmentChangeListener +import org.oppia.android.app.walkthrough.WalkthroughPages import org.oppia.android.databinding.WalkthroughFinalFragmentBinding +import org.oppia.android.domain.exploration.ExplorationDataController +import org.oppia.android.domain.topic.StoryProgressController import org.oppia.android.domain.topic.TopicController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.logging.ConsoleLogger +import java.util.* import javax.inject.Inject /** The presenter for [WalkthroughFinalFragment]. */ @@ -26,13 +33,19 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val logger: ConsoleLogger, - private val topicController: TopicController + private val explorationDataController: ExplorationDataController, + private val topicController: TopicController, + private val storyProgressController: StoryProgressController ) : WalkthroughEndPageChanger { private lateinit var binding: WalkthroughFinalFragmentBinding private lateinit var walkthroughFinalViewModel: WalkthroughFinalViewModel + private val routeToExploration = activity as RouteToExplorationListener + private var internalProfileId: Int = -1 private lateinit var topicId: String private lateinit var profileId: ProfileId private lateinit var topicName: String + private lateinit var storyId: String + private lateinit var explorationId: String fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?, topicId: String): View? { binding = @@ -42,7 +55,7 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( /* attachToRoot= */ false ) this.topicId = topicId - val internalProfileId = activity.intent.getIntExtra( + internalProfileId = activity.intent.getIntExtra( WalkthroughActivity.WALKTHROUGH_ACTIVITY_INTERNAL_PROFILE_ID_KEY, -1 ) @@ -66,6 +79,8 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( activity, Observer { result -> topicName = result.name + storyId = result.storyList[0].storyId + explorationId = result.storyList[0].chapterList[0].explorationId setTopicName() } ) @@ -104,4 +119,36 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( override fun goBack() { activity.onBackPressed() } + + override fun goToTopicsPage() { + explorationDataController.startPlayingExploration( + explorationId + ).observe( + fragment, + Observer> { result -> + when { + result.isPending() -> logger.d("WalkthroughFinalFragment", "Loading exploration") + result.isFailure() -> logger.e( + "WalkthroughFinalFragment", + "Failed to load exploration", + result.getErrorOrNull()!! + ) + else -> { + logger.d("WalkthroughFinalFragment", "Successfully loaded exploration") + getTopic() + storyProgressController.recordRecentlyPlayedChapter(profileId,topicId,storyId,explorationId, + Date().time, + isFromWalkthrough = true) + routeToExploration.routeToExploration( + internalProfileId, + topicId, + storyId, + explorationId, + 1 + ) + } + } + } + ) + } } diff --git a/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml b/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml new file mode 100644 index 00000000000..9de21a84bd1 --- /dev/null +++ b/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/layout-land/coming_soon_topic_view.xml b/app/src/main/res/layout-land/coming_soon_topic_view.xml new file mode 100644 index 00000000000..e3be77ddd88 --- /dev/null +++ b/app/src/main/res/layout-land/coming_soon_topic_view.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout-land/walkthrough_final_fragment.xml b/app/src/main/res/layout-land/walkthrough_final_fragment.xml index 2cd78708a18..b7dba40a08e 100644 --- a/app/src/main/res/layout-land/walkthrough_final_fragment.xml +++ b/app/src/main/res/layout-land/walkthrough_final_fragment.xml @@ -79,6 +79,7 @@ android:layout_weight="1" android:background="?attr/selectableItemBackground" android:clickable="true" + android:onClick="@{(v) -> presenter.goToTopicsPage()}" android:focusable="true" app:cardCornerRadius="4dp" app:contentPadding="@dimen/space_24dp"> diff --git a/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml b/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml new file mode 100644 index 00000000000..e3be77ddd88 --- /dev/null +++ b/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/coming_soon_topic_view.xml b/app/src/main/res/layout/coming_soon_topic_view.xml new file mode 100644 index 00000000000..e3be77ddd88 --- /dev/null +++ b/app/src/main/res/layout/coming_soon_topic_view.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 011a24327e1..136d10d29ee 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -11,6 +11,7 @@ diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 654401baeb0..c70d526dee5 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -415,5 +415,6 @@ Enter a ratio in the form x:y. - + Coming Soon + Recommended Stories diff --git a/domain/src/main/assets/coming_soon_topics.json b/domain/src/main/assets/coming_soon_topics.json new file mode 100644 index 00000000000..70aa6bfd57a --- /dev/null +++ b/domain/src/main/assets/coming_soon_topics.json @@ -0,0 +1,8 @@ +{ + "topic_id_list": [ + "test_topic_id_0", + "test_topic_id_1", + "GJ2rLXRKD5hw", + "omzF4oqgeTXd" + ] +} diff --git a/domain/src/main/assets/test_exp_id_4.json b/domain/src/main/assets/test_exp_id_4.json index a56e2482d6e..3f719c88d80 100644 --- a/domain/src/main/assets/test_exp_id_4.json +++ b/domain/src/main/assets/test_exp_id_4.json @@ -56,6 +56,9 @@ ], [ "

a camera at the store

" + ], + [ + "

to photograph the parade.

" ] ] } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index abda9c898a2..c706869e6d8 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -1,5 +1,6 @@ package org.oppia.android.domain.topic +import android.util.Log import kotlinx.coroutines.Deferred import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.ChapterProgress @@ -7,6 +8,7 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicProgressDatabase +import org.oppia.android.app.model.Walkthrough import org.oppia.android.data.persistence.PersistentCacheStore import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider @@ -39,11 +41,14 @@ const val RATIOS_EXPLORATION_ID_3 = "tIoSb3HZFN6e" private const val CACHE_NAME = "topic_progress_database" private const val RETRIEVE_TOPIC_PROGRESS_LIST_DATA_PROVIDER_ID = "retrieve_topic_progress_list_data_provider_id" +private const val RETRIEVE_WALKTHROUGH_DATA_PROVIDER_ID = + "retrieve_walkthroug_data_provider_id" private const val RETRIEVE_TOPIC_PROGRESS_DATA_PROVIDER_ID = "retrieve_topic_progress_data_provider_id" private const val RETRIEVE_STORY_PROGRESS_DATA_PROVIDER_ID = "retrieve_story_progress_data_provider_id" private const val RECORD_COMPLETED_CHAPTER_PROVIDER_ID = "record_completed_chapter_provider_id" +private const val RECORD_WALKTROUGH_TOPIC_PROVIDER_ID = "record_walkthrough_topic_provider_id" private const val RECORD_RECENTLY_PLAYED_CHAPTER_PROVIDER_ID = "record_recently_played_chapter_provider_id" @@ -78,6 +83,7 @@ class StoryProgressController @Inject constructor( * @param storyId the ID corresponding to the story for which progress needs to be stored. * @param explorationId the chapter id which will marked as [ChapterPlayState.COMPLETED] * @param completionTimestamp the timestamp at the exploration was finished. + * @param isFromWalkthrough the boolean to be set false once exploration was finished. * @return a [DataProvider] that indicates the success/failure of this record progress operation. */ fun recordCompletedChapter( @@ -85,7 +91,8 @@ class StoryProgressController @Inject constructor( topicId: String, storyId: String, explorationId: String, - completionTimestamp: Long + completionTimestamp: Long, + isFromWalkthrough: Boolean ): DataProvider { val deferred = retrieveCacheStore(profileId).storeDataWithCustomChannelAsync( @@ -110,7 +117,7 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setIsFromWalkthrough(isFromWalkthrough) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -141,6 +148,7 @@ class StoryProgressController @Inject constructor( * @param explorationId the chapter id which will marked as [ChapterPlayState.NOT_STARTED] if it * has not been [ChapterPlayState.COMPLETED] already. * @param lastPlayedTimestamp the timestamp at which the exploration was last played. + * @param isFromWalkthrough the boolean to be set true if exploration was played from [WalkthroughActivity]. * @return a [DataProvider] that indicates the success/failure of this record progress operation. */ fun recordRecentlyPlayedChapter( @@ -148,12 +156,14 @@ class StoryProgressController @Inject constructor( topicId: String, storyId: String, explorationId: String, - lastPlayedTimestamp: Long + lastPlayedTimestamp: Long, + isFromWalkthrough: Boolean ): DataProvider { val deferred = retrieveCacheStore(profileId).storeDataWithCustomChannelAsync( updateInMemoryCache = true ) { topicProgressDatabase -> + val previousChapterProgress = topicProgressDatabase .topicProgressMap[topicId]?.storyProgressMap?.get(storyId)?.chapterProgressMap?.get( @@ -190,17 +200,26 @@ class StoryProgressController @Inject constructor( } storyProgressBuilder.putChapterProgress(explorationId, chapterProgressBuilder.build()) val storyProgress = storyProgressBuilder.build() - - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setIsFromWalkthrough(isFromWalkthrough) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() - - val topicDatabaseBuilder = - topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) + val topicDatabaseBuilder = topicProgressDatabase.toBuilder() + Log.d("topic WW =","=="+topicProgress.getIsFromWalkthrough()) + if (isFromWalkthrough) { + val walkthrough = Walkthrough.newBuilder() + .setExplorationId(explorationId) + .setTopicId(topicId) + .setProfileId(profileId) + .build() + topicDatabaseBuilder.putTopicProgress(topicId, topicProgress) + .setWalkthrough(walkthrough) + }else{ + topicDatabaseBuilder.putTopicProgress(topicId, topicProgress) + } Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) } @@ -223,6 +242,16 @@ class StoryProgressController @Inject constructor( } } + /** Returns topic selected in [WalkthroughActivity] [DataProvider] for a particular profile. */ + internal fun retrieveWalkthroughDataProvider( + profileId: ProfileId + ): DataProvider { + return retrieveCacheStore(profileId) + .transformAsync(RETRIEVE_WALKTHROUGH_DATA_PROVIDER_ID) { topicProgressDatabase -> + AsyncResult.success(topicProgressDatabase.walkthrough) + } + } + /** Returns a [TopicProgress] [DataProvider] for a specific topicId, per-profile basis. */ internal fun retrieveTopicProgressDataProvider( profileId: ProfileId, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index bae93039f53..c05f98c926f 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -32,7 +32,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -48,7 +49,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -64,7 +66,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordCompletedChapter( @@ -72,7 +75,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -88,7 +92,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordCompletedChapter( @@ -96,7 +101,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -115,7 +121,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordCompletedChapter( @@ -123,7 +130,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_1, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -139,7 +147,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordCompletedChapter( @@ -147,7 +156,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -166,7 +176,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -185,7 +196,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -205,7 +217,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordRecentlyPlayedChapter( @@ -213,7 +226,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp + timestamp, + isFromWalkthrough = false ) } @@ -233,7 +247,8 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordRecentlyPlayedChapter( @@ -241,7 +256,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false ) storyProgressController.recordRecentlyPlayedChapter( @@ -249,7 +265,8 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp + timestamp, + isFromWalkthrough = false ) } } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index f8e4246d647..4cb179eb2a5 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -1,6 +1,7 @@ package org.oppia.android.domain.topic import android.graphics.Color +import android.util.Log import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import org.json.JSONObject @@ -11,11 +12,13 @@ import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.model.Walkthrough import org.oppia.android.domain.util.JsonAssetRetriever import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider @@ -69,6 +72,8 @@ val EXPLORATION_THUMBNAILS = mapOf( private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" +private const val WALKTHROUGH_PROVIDER_ID = + "walkthrough_provider_id" private val EVICTION_TIME_MILLIS = TimeUnit.DAYS.toMillis(1) @@ -87,6 +92,14 @@ class TopicListController @Inject constructor( return MutableLiveData(AsyncResult.success(createTopicList())) } + /** + * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to + * [EVICTION_TIME_MILLIS] old. + */ + fun getComingSoonTopicList(): LiveData> { + return MutableLiveData(AsyncResult.success(createComingSoonTopicList())) + } + /** * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. * The total number of promoted stories should correspond to the ongoing story count within the @@ -99,11 +112,18 @@ class TopicListController @Inject constructor( fun getOngoingStoryList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { - val ongoingStoryList = createOngoingStoryListFromProgress(it) + val ongoingStoryList = createOngoingStoryListFromProgress(it, profileId) AsyncResult.success(ongoingStoryList) } } + fun getWalkthroughData(profileId: ProfileId): DataProvider { + return storyProgressController.retrieveWalkthroughDataProvider(profileId) + .transformAsync(WALKTHROUGH_PROVIDER_ID) { + AsyncResult.success(it) + } + } + private fun createTopicList(): TopicList { val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! @@ -115,6 +135,17 @@ class TopicListController @Inject constructor( return topicListBuilder.build() } + private fun createComingSoonTopicList(): TopicList { + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") + val topicListBuilder = TopicList.newBuilder() + for (i in 0 until topicIdJsonArray.length()) { + topicListBuilder.addTopicSummary(createTopicSummary(topicIdJsonArray.optString(i)!!)) + } + return topicListBuilder.build() + } + private fun createTopicSummary(topicId: String): TopicSummary { val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!! @@ -140,14 +171,145 @@ class TopicListController @Inject constructor( } private fun createOngoingStoryListFromProgress( - topicProgressList: List + topicProgressList: List, + profileId: ProfileId ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() + + if (topicProgressList.size!=0) { + topicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + Log.d("topic Walkthrough=", "==" + topicProgress.isFromWalkthrough) + + if (topicProgress.isFromWalkthrough && topicProgressList.size == 1) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setRecommended(true) + ) + ongoingStoryListBuilder.addAllRecommendedStory( + createRecommendedStoryList( + topicProgressList + ) + ) + } else { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setRecentlyPlayed(true) + ) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + var story = topicController.retrieveStory(topic.topicId, storyId) + Log.d("topic progress =", "" + topicProgress.topicId) + + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() + + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } + } + } + } + + if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setRecommended(true) + ) + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") + for (j in 0 until topicIdJsonArray.length()) { + val found = topicProgressList.any { it.topicId == topicIdJsonArray[j] } + if (!found) { + Log.d("topic =", " not" + " " + topicIdJsonArray[j]) + ongoingStoryListBuilder.addRecommendedStory( + createRecommendedStoryFromAssets( + topicIdJsonArray[j].toString() + ) + ) + } + } + if (ongoingStoryListBuilder.recommendedStoryCount == 0) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setComingSoon(true) + ) + Log.d("topic =", " coming" + " " + "soon") + } + } + } + return ongoingStoryListBuilder.build() + } + + private fun createRecommendedStoryList( + topicProgressList: List + ): List { + val recommendedStories = ArrayList() topicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) + var story = topicController.retrieveStory(topic.topicId, storyId) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -156,10 +318,6 @@ class TopicListController @Inject constructor( ChapterPlayState.COMPLETED } .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() - val startedChapterProgressList = storyProgress.chapterProgressMap.values .filter { chapterProgress -> @@ -168,6 +326,9 @@ class TopicListController @Inject constructor( } .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() + val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() if (recentlyPlayerChapterProgress != null) { @@ -176,8 +337,6 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -186,11 +345,7 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } + recommendedStories.add(promotedStory) } } else if (lastCompletedChapterProgress != null && lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId @@ -201,8 +356,6 @@ class TopicListController @Inject constructor( val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = - (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -211,29 +364,49 @@ class TopicListController @Inject constructor( nextChapterSummary.name, nextChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) + recommendedStories.add(promotedStory) + } else { + val nextStoryIndex = topic.storyList.indexOf(story) + 1 + if (nextStoryIndex < topic.storyList.size) { + story = topicController.retrieveStory( + topic.topicId, + topic.storyList[nextStoryIndex].storyId + ) + val nextChapterSummary: ChapterSummary? = story.chapterList[0] + if (nextChapterSummary != null) { + val promotedStory = createPromotedStory( + story.storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + recommendedStories.add(promotedStory) + } } } } +// storyProgressController.recordRecentlyPlayedChapter( +// profileId, +// topicProgress.topicId, +// storyId, +// lastCompletedChapterProgress.explorationId, +// Date().time, +// isFromWalkthrough = false) +// } +// + + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") + for (i in 0 until topicIdJsonArray.length()) { + if (topicProgress.topicId != topicIdJsonArray[i]) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())) + } + } } } - if ((ongoingStoryListBuilder.olderStoryCount + ongoingStoryListBuilder.recentStoryCount) == 0) { - ongoingStoryListBuilder.addAllRecentStory(createRecommendedStoryList()) - } - return ongoingStoryListBuilder.build() - } - - private fun createRecommendedStoryList(): List { - val recommendedStories = ArrayList() - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") - for (i in 0 until topicIdJsonArray.length()) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())) - } return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt index c5fe05ad722..34de3227f6c 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt @@ -91,7 +91,8 @@ class StoryProgressControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + false ).toLiveData().observeForever(mockRecordProgressObserver) testCoroutineDispatchers.runCurrent() @@ -105,7 +106,23 @@ class StoryProgressControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp + timestamp, + isFromWalkthrough = false + ).toLiveData().observeForever(mockRecordProgressObserver) + testCoroutineDispatchers.runCurrent() + + verifyRecordProgressSucceeded() + } + + @Test + fun testStoryProgressController_recordRecentlyPlayedChapterFromWalkthrough_isSuccessful() { + storyProgressController.recordRecentlyPlayedChapter( + profileId, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + timestamp, + isFromWalkthrough = true ).toLiveData().observeForever(mockRecordProgressObserver) testCoroutineDispatchers.runCurrent() diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt index ff319aa5406..f5cb58782ed 100755 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt @@ -1148,7 +1148,8 @@ class TopicControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - currentTimestamp + currentTimestamp, + false ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1158,7 +1159,8 @@ class TopicControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - currentTimestamp + currentTimestamp, + false ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1168,7 +1170,8 @@ class TopicControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - currentTimestamp + currentTimestamp, + false ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1178,7 +1181,8 @@ class TopicControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_1, - currentTimestamp + currentTimestamp, + false ).toLiveData().observeForever(mockRecordProgressObserver) } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 84aaa8da12b..bb9d895d592 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -245,7 +245,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + isFromWalkthrough = false ) testCoroutineDispatchers.runCurrent() @@ -267,7 +268,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -289,7 +291,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -298,7 +301,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() + getCurrentTimestamp(), + isFromWalkthrough = false ) testCoroutineDispatchers.runCurrent() @@ -321,7 +325,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -330,7 +335,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -352,7 +358,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + isFromWalkthrough = false ) testCoroutineDispatchers.runCurrent() @@ -361,7 +368,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() + getCurrentTimestamp(), + isFromWalkthrough = false ) testCoroutineDispatchers.runCurrent() @@ -384,7 +392,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -393,7 +402,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() + getCurrentTimestamp(), + isFromWalkthrough = false ) testCoroutineDispatchers.runCurrent() @@ -416,7 +426,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -425,7 +436,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -434,7 +446,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -458,7 +471,8 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getOldTimestamp() + getOldTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -467,7 +481,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getOldTimestamp() + getOldTimestamp(), + false ) testCoroutineDispatchers.runCurrent() @@ -476,7 +491,8 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() + getCurrentTimestamp(), + false ) testCoroutineDispatchers.runCurrent() diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 8e68f41dad5..b5eea46d5ea 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -6,6 +6,7 @@ import "subtitled_html.proto"; import "thumbnail.proto"; import "translation.proto"; import "voiceover.proto"; +import "profile.proto"; option java_package = "org.oppia.android.app.model"; option java_multiple_files = true; @@ -147,11 +148,30 @@ message CompletedStory { // Corresponds to the list of stories the player is currently playing across all topics. message OngoingStoryList { + // Ongoing stories from within the last 7 days. repeated PromotedStory recent_story = 1; + // Recommended stories based on user's interest. + repeated PromotedStory recommended_story = 2; + // Other ongoing stories from longer than 7 days ago. - repeated PromotedStory older_story = 2; + repeated PromotedStory older_story = 3; + + // Indicates type of story promoted + PromotedStoriesType promoted_stories_type = 5; +} + +// Corresponds to the Walkthrough. When a user explores a topic through a walkthrough page. +message Walkthrough { + // The ID of the profile. + ProfileId profile_id = 1; + + // The ID of the exploration being played. + string exploration_id = 2; + + // The ID of the topic being played. + string topic_id = 3; } // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, @@ -226,6 +246,9 @@ enum ChapterPlayState { message TopicProgressDatabase { // Map from topic ID to TopicProgress. map topic_progress = 1; + + // The topic that was selected through walkthrough + Walkthrough walkthrough = 2; } // Represents the topic progress. @@ -233,10 +256,31 @@ message TopicProgress { // The ID corresponding to the topic. string topic_id = 1; + // Preference on whether user launched topic from walkthrough + bool isFromWalkthrough = 2; + // Map from story ID to StoryProgress. - map story_progress = 2; + map story_progress = 3; + + // Indicates type of story promoted + PromotedStoriesType promoted_stories_type = 4; } +// A structure corresponding to the Promoted Stories. This structure is set up +// to properly account for recently_played stories, for recommended stories +// and for coming soon topics. +message PromotedStoriesType { + oneof promoted_stories_type { + // Indicates recently played topics from the topic list. + bool recently_played = 1; + + // Indicates recommended from the topic list. + bool recommended = 2; + + // Indicates coming soon topics. + bool coming_soon = 3; + } +} // Represents the story progress. message StoryProgress { // The ID corresponding to the story. From 3b374c6f9cda9d40ce1f3e818efad5e03c680617 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 11 Dec 2020 23:16:40 +0530 Subject: [PATCH 025/248] writing testcases --- .../app/home/topiclist/TopicListAdapter.kt | 2 + .../player/state/StateFragmentPresenter.kt | 3 + .../domain/topic/TopicListController.kt | 6 +- .../domain/topic/TopicListControllerTest.kt | 287 +++++++++++++++++- 4 files changed, 292 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index b7d28bbe95b..fc547d7216e 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -161,10 +161,12 @@ class TopicListAdapter( } when (promotedStoryList[0].promotedStoriesType) { PromotedStoriesType.PromotedStoriesTypeCase.RECENTLY_PLAYED -> { + binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) binding.viewAllTextView.visibility = View.VISIBLE } PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED -> { + binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recommended_stories)) binding.viewAllTextView.visibility = View.INVISIBLE } diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt index f196fc365eb..0402768c570 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt @@ -542,6 +542,7 @@ class StateFragmentPresenter @Inject constructor( } private fun markExplorationAsRecentlyPlayed() { + Log.d("topicplay=", "==" +topicId+" "+ storyId+" "+explorationId) storyProgressController.recordRecentlyPlayedChapter( profileId, topicId, @@ -552,6 +553,8 @@ class StateFragmentPresenter @Inject constructor( } private fun markExplorationCompleted() { + + Log.d("topicplaycom=", "==" +topicId+" "+ storyId+" "+explorationId) storyProgressController.recordCompletedChapter( profileId, topicId, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 4cb179eb2a5..e38e7caa9cf 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -197,7 +197,7 @@ class TopicListController @Inject constructor( topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId var story = topicController.retrieveStory(topic.topicId, storyId) - Log.d("topic progress =", "" + topicProgress.topicId) + Log.d("topic progress =", "" + topicProgress.topicId + storyId) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -281,7 +281,7 @@ class TopicListController @Inject constructor( .getJSONArray("topic_id_list") for (j in 0 until topicIdJsonArray.length()) { val found = topicProgressList.any { it.topicId == topicIdJsonArray[j] } - if (!found) { + if (!found && ongoingStoryListBuilder.recommendedStoryList.size<3) { Log.d("topic =", " not" + " " + topicIdJsonArray[j]) ongoingStoryListBuilder.addRecommendedStory( createRecommendedStoryFromAssets( @@ -401,7 +401,7 @@ class TopicListController @Inject constructor( .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") for (i in 0 until topicIdJsonArray.length()) { - if (topicProgress.topicId != topicIdJsonArray[i]) { + if (topicProgress.topicId != topicIdJsonArray[i] && recommendedStories.size<3) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())) } } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index bb9d895d592..69c57736388 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -239,7 +239,7 @@ class TopicListControllerTest { @Test @Ignore("Failing on Circle CI.") - fun testRetrieveOngoingStoryList_markRecentlyPlayedFracStory0Exp0_ongoingStoryListIsCorrect() { + fun testRetrieveRecentStoryList_markRecentlyPlayedFracStory0Exp0_recentStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -262,7 +262,164 @@ class TopicListControllerTest { } @Test - fun testRetrieveOngoingStoryList_markChapterCompletedFracStory0Exp0_ongoingStoryListIsCorrect() { + fun testRetrieveRecommendedStoryList_markChapterCompletedFracStory0Exp0_fromWalkthrough_recommendedStoryListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) + } + + @Test + @Ignore("Failing on Circle CI.") + fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_isFromWalkthrough_recommendedStoryListIsCorrect() { + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + isFromWalkthrough = true + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) + } + + @Test + fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_fromWalkthrough_recommendedListCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp(), + isFromWalkthrough = true + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) + } + + @Test + fun testRetrieveRecommendedStoryList_markAllChaptersCompletedInFractions_recommendedListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + verifyDefaultRecommendedStoryListSucceeded() + } + + @Test + fun testRetrieveRecentStoryList_markAllChaptersCompletedInFractions_fromRecommendedList_playedFirstTopicStory0Exploration0_recentStoryListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp(), + true + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp(), + isFromWalkthrough = false + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) + + verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recentStoryList[0]) + } + + @Test + fun testRetrieveRecentList_markChapterCompletedFracStory0Exp0_recentStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -285,7 +442,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_ongoingListCorrect() { + fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_RecentStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -464,6 +621,122 @@ class TopicListControllerTest { verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[2]) } + @Test + fun testRetrieveRecommendedStoryList_markFirstStoryOfFractDone_noMoreOngoingList_recommendedListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + } + + @Test + fun testRetrieveComingSoonTopicList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_comingSoonListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + +// storyProgressController.recordCompletedChapter( +// profileId0, +// RATIOS_TOPIC_ID, +// RATIOS_STORY_ID_1, +// RATIOS_EXPLORATION_ID_2, +// getCurrentTimestamp(), +// false +// ) +// testCoroutineDispatchers.runCurrent() +// +// storyProgressController.recordCompletedChapter( +// profileId0, +// RATIOS_TOPIC_ID, +// RATIOS_STORY_ID_1, +// RATIOS_EXPLORATION_ID_3, +// getCurrentTimestamp(), +// false +// ) +// testCoroutineDispatchers.runCurrent() + + topicListController.getOngoingStoryList(profileId0).toLiveData() + .observeForever(mockOngoingStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingStoryListSucceeded() + + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) +// assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + } + @Test fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastMonth_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -527,6 +800,14 @@ class TopicListControllerTest { verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[3]) } + private fun verifyDefaultRecommendedStoryListSucceeded() { + val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) + verifyOngoingStoryAsSecondTopicStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) + verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[2]) + } + private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) From fd9e418b3933a765595dfb2fe76d68081fc378f6 Mon Sep 17 00:00:00 2001 From: Jacque Li Date: Fri, 11 Dec 2020 10:00:22 -0800 Subject: [PATCH 026/248] Refactor to process TopicList later --- .../android/app/home/HomeFragmentPresenter.kt | 26 +++++++-- .../oppia/android/app/home/HomeViewModel.kt | 49 +---------------- .../android/app/home/WelcomeViewModel.kt | 2 +- .../topiclist/PromotedStoryListViewModel.kt | 1 - .../topiclist/TopicSummaryListViewModel.kt | 53 +++++++++++++++++++ app/src/main/res/layout/home_fragment.xml | 2 +- 6 files changed, 78 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt 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 5e75ff0002c..a2ef37ef81f 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 @@ -11,6 +11,7 @@ import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel +import org.oppia.android.app.home.topiclist.TopicSummaryListViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.ProfileId @@ -62,7 +63,7 @@ class HomeFragmentPresenter @Inject constructor( oppiaClock, profileManagementController ) - welcomeViewModel.setInternalProfileId(profileId) + welcomeViewModel.setProfileId(profileId) logHomeActivityEvent() val promotedStoryListViewModel = PromotedStoryListViewModel( @@ -73,15 +74,23 @@ class HomeFragmentPresenter @Inject constructor( storyEntityType ) val allTopicsViewModel = AllTopicsViewModel() - val homeViewModel = HomeViewModel( + val topicSummaryListViewModel = TopicSummaryListViewModel( activity, fragment, topicListController, topicEntityType ) - homeViewModel.addHomeItem(welcomeViewModel) - homeViewModel.addHomeItem(promotedStoryListViewModel) - homeViewModel.addHomeItem(allTopicsViewModel) + val itemList : MutableList = ArrayList() + itemList.add(welcomeViewModel) + itemList.add(promotedStoryListViewModel) + itemList.add(allTopicsViewModel) + itemList.add(topicSummaryListViewModel) + + val homeViewModel = HomeViewModel( + activity, + fragment, + itemList + ) val spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) @@ -119,6 +128,12 @@ class HomeFragmentPresenter @Inject constructor( else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") } } + .registerViewDataBinder( + viewType = ViewType.VIEW_TYPE_HOME_FRAGMENT, + inflateDataBinding = HomeFragmentBinding::inflate, + setViewModel = HomeFragmentBinding::setViewModel, + transformViewModel = { it as HomeViewModel } + ) .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, inflateDataBinding = WelcomeBinding::inflate, @@ -147,6 +162,7 @@ class HomeFragmentPresenter @Inject constructor( } private enum class ViewType { + VIEW_TYPE_HOME_FRAGMENT, VIEW_TYPE_WELCOME_MESSAGE, VIEW_TYPE_PROMOTED_STORY_LIST, VIEW_TYPE_ALL_TOPICS, diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index d183060ce5b..f23f2e20cf0 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -2,58 +2,13 @@ package org.oppia.android.app.home import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.topiclist.TopicSummaryClickListener -import org.oppia.android.app.home.topiclist.TopicSummaryViewModel -import org.oppia.android.app.model.TopicList -import org.oppia.android.app.viewmodel.ObservableViewModel -import org.oppia.android.app.viewmodel.ViewModelProvider -import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult -import org.oppia.android.util.parser.TopicHtmlParserEntityType import javax.inject.Inject @FragmentScope class HomeViewModel @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - private val topicListController: TopicListController, - @TopicHtmlParserEntityType private val topicEntityType: String - ) : ObservableViewModel() { - - private var itemList: MutableList = ArrayList() - private val topicListSummaryResultLiveData: LiveData> by lazy { - topicListController.getTopicList() - } - val itemListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) - } - - private fun processItemList(itemListLiveData: TopicList) : List { - for (topicSummary in itemListLiveData.topicSummaryList) { - val topicSummaryViewModel = - TopicSummaryViewModel( - activity, - topicSummary, - topicEntityType, - fragment as TopicSummaryClickListener - ) - topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) - itemList.add(topicSummaryViewModel) - } - return itemList - } - - private val assumedSuccessfulTopicListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(topicListSummaryResultLiveData) { - it.getOrDefault(TopicList.getDefaultInstance()) - } - } - - fun addHomeItem(viewModel: HomeItemViewModel) { - itemList.add(viewModel) - } + val itemList: List +) : HomeItemViewModel() { } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 0dca3fa1414..7367b4bc4b2 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -48,7 +48,7 @@ class WelcomeViewModel @Inject constructor( return profileResult.getOrDefault(Profile.getDefaultInstance()) } - fun setInternalProfileId(id: ProfileId) { + fun setProfileId(id: ProfileId) { this.profileId = id } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index efc29e18ff1..8bad704cf66 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,6 +1,5 @@ package org.oppia.android.app.home.topiclist -import android.content.Context import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt new file mode 100644 index 00000000000..a16b8b3b4f6 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt @@ -0,0 +1,53 @@ +package org.oppia.android.app.home.topiclist + +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations +import org.oppia.android.app.fragment.FragmentScope +import org.oppia.android.app.home.HomeItemViewModel +import org.oppia.android.app.model.TopicList +import org.oppia.android.app.viewmodel.ObservableViewModel +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.parser.TopicHtmlParserEntityType +import javax.inject.Inject + +@FragmentScope +class TopicSummaryListViewModel @Inject constructor( + private val activity: AppCompatActivity, + private val fragment: Fragment, + private val topicListController: TopicListController, + @TopicHtmlParserEntityType private val topicEntityType: String + ) : HomeItemViewModel() { + + private var topicList: MutableList = ArrayList() + private val topicListSummaryResultLiveData: LiveData> by lazy { + topicListController.getTopicList() + } + val itemListLiveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) + } + + private fun processItemList(itemListLiveData: TopicList) : List { + for (topicSummary in itemListLiveData.topicSummaryList) { + val topicSummaryViewModel = + TopicSummaryViewModel( + activity, + topicSummary, + topicEntityType, + fragment as TopicSummaryClickListener + ) + topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) + topicList.add(topicSummaryViewModel) + } + return topicList + } + + private val assumedSuccessfulTopicListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(topicListSummaryResultLiveData) { + it.getOrDefault(TopicList.getDefaultInstance()) + } + } +} diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 1efab042e3e..37ff7d19ca8 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.itemListLiveData}" /> + app:data="@{viewModel.itemList}" /> Date: Fri, 11 Dec 2020 10:43:54 -0800 Subject: [PATCH 027/248] Revert "Refactor to process TopicList later" This reverts commit fd9e418b3933a765595dfb2fe76d68081fc378f6. --- .../android/app/home/HomeFragmentPresenter.kt | 26 ++------- .../oppia/android/app/home/HomeViewModel.kt | 49 ++++++++++++++++- .../android/app/home/WelcomeViewModel.kt | 2 +- .../topiclist/PromotedStoryListViewModel.kt | 1 + .../topiclist/TopicSummaryListViewModel.kt | 53 ------------------- app/src/main/res/layout/home_fragment.xml | 2 +- 6 files changed, 55 insertions(+), 78 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt 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 a2ef37ef81f..5e75ff0002c 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 @@ -11,7 +11,6 @@ import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel -import org.oppia.android.app.home.topiclist.TopicSummaryListViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.ProfileId @@ -63,7 +62,7 @@ class HomeFragmentPresenter @Inject constructor( oppiaClock, profileManagementController ) - welcomeViewModel.setProfileId(profileId) + welcomeViewModel.setInternalProfileId(profileId) logHomeActivityEvent() val promotedStoryListViewModel = PromotedStoryListViewModel( @@ -74,23 +73,15 @@ class HomeFragmentPresenter @Inject constructor( storyEntityType ) val allTopicsViewModel = AllTopicsViewModel() - val topicSummaryListViewModel = TopicSummaryListViewModel( + val homeViewModel = HomeViewModel( activity, fragment, topicListController, topicEntityType ) - val itemList : MutableList = ArrayList() - itemList.add(welcomeViewModel) - itemList.add(promotedStoryListViewModel) - itemList.add(allTopicsViewModel) - itemList.add(topicSummaryListViewModel) - - val homeViewModel = HomeViewModel( - activity, - fragment, - itemList - ) + homeViewModel.addHomeItem(welcomeViewModel) + homeViewModel.addHomeItem(promotedStoryListViewModel) + homeViewModel.addHomeItem(allTopicsViewModel) val spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) @@ -128,12 +119,6 @@ class HomeFragmentPresenter @Inject constructor( else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") } } - .registerViewDataBinder( - viewType = ViewType.VIEW_TYPE_HOME_FRAGMENT, - inflateDataBinding = HomeFragmentBinding::inflate, - setViewModel = HomeFragmentBinding::setViewModel, - transformViewModel = { it as HomeViewModel } - ) .registerViewDataBinder( viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, inflateDataBinding = WelcomeBinding::inflate, @@ -162,7 +147,6 @@ class HomeFragmentPresenter @Inject constructor( } private enum class ViewType { - VIEW_TYPE_HOME_FRAGMENT, VIEW_TYPE_WELCOME_MESSAGE, VIEW_TYPE_PROMOTED_STORY_LIST, VIEW_TYPE_ALL_TOPICS, diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index f23f2e20cf0..d183060ce5b 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -2,13 +2,58 @@ package org.oppia.android.app.home import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import org.oppia.android.app.fragment.FragmentScope +import org.oppia.android.app.home.topiclist.TopicSummaryClickListener +import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.TopicList +import org.oppia.android.app.viewmodel.ObservableViewModel +import org.oppia.android.app.viewmodel.ViewModelProvider +import org.oppia.android.domain.topic.TopicListController +import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.parser.TopicHtmlParserEntityType import javax.inject.Inject @FragmentScope class HomeViewModel @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, - val itemList: List -) : HomeItemViewModel() { + private val topicListController: TopicListController, + @TopicHtmlParserEntityType private val topicEntityType: String + ) : ObservableViewModel() { + + private var itemList: MutableList = ArrayList() + private val topicListSummaryResultLiveData: LiveData> by lazy { + topicListController.getTopicList() + } + val itemListLiveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) + } + + private fun processItemList(itemListLiveData: TopicList) : List { + for (topicSummary in itemListLiveData.topicSummaryList) { + val topicSummaryViewModel = + TopicSummaryViewModel( + activity, + topicSummary, + topicEntityType, + fragment as TopicSummaryClickListener + ) + topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) + itemList.add(topicSummaryViewModel) + } + return itemList + } + + private val assumedSuccessfulTopicListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(topicListSummaryResultLiveData) { + it.getOrDefault(TopicList.getDefaultInstance()) + } + } + + fun addHomeItem(viewModel: HomeItemViewModel) { + itemList.add(viewModel) + } } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 7367b4bc4b2..0dca3fa1414 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -48,7 +48,7 @@ class WelcomeViewModel @Inject constructor( return profileResult.getOrDefault(Profile.getDefaultInstance()) } - fun setProfileId(id: ProfileId) { + fun setInternalProfileId(id: ProfileId) { this.profileId = id } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 8bad704cf66..efc29e18ff1 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,5 +1,6 @@ package org.oppia.android.app.home.topiclist +import android.content.Context import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt deleted file mode 100644 index a16b8b3b4f6..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryListViewModel.kt +++ /dev/null @@ -1,53 +0,0 @@ -package org.oppia.android.app.home.topiclist - -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations -import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.HomeItemViewModel -import org.oppia.android.app.model.TopicList -import org.oppia.android.app.viewmodel.ObservableViewModel -import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult -import org.oppia.android.util.parser.TopicHtmlParserEntityType -import javax.inject.Inject - -@FragmentScope -class TopicSummaryListViewModel @Inject constructor( - private val activity: AppCompatActivity, - private val fragment: Fragment, - private val topicListController: TopicListController, - @TopicHtmlParserEntityType private val topicEntityType: String - ) : HomeItemViewModel() { - - private var topicList: MutableList = ArrayList() - private val topicListSummaryResultLiveData: LiveData> by lazy { - topicListController.getTopicList() - } - val itemListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) - } - - private fun processItemList(itemListLiveData: TopicList) : List { - for (topicSummary in itemListLiveData.topicSummaryList) { - val topicSummaryViewModel = - TopicSummaryViewModel( - activity, - topicSummary, - topicEntityType, - fragment as TopicSummaryClickListener - ) - topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) - topicList.add(topicSummaryViewModel) - } - return topicList - } - - private val assumedSuccessfulTopicListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(topicListSummaryResultLiveData) { - it.getOrDefault(TopicList.getDefaultInstance()) - } - } -} diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 37ff7d19ca8..1efab042e3e 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.itemList}" /> + app:data="@{viewModel.itemListLiveData}" /> Date: Fri, 11 Dec 2020 16:09:05 -0800 Subject: [PATCH 028/248] Process welcome in home view model --- .../android/app/home/HomeFragmentPresenter.kt | 14 ++--- .../oppia/android/app/home/HomeViewModel.kt | 58 +++++++++++++++---- .../android/app/home/WelcomeViewModel.kt | 41 ++----------- .../main/res/layout-sw600dp-land/welcome.xml | 2 +- 4 files changed, 57 insertions(+), 58 deletions(-) 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 5e75ff0002c..7d1c02c2f34 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 @@ -56,13 +56,6 @@ class HomeFragmentPresenter @Inject constructor( internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) val profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - val welcomeViewModel = WelcomeViewModel( - logger, - fragment, - oppiaClock, - profileManagementController - ) - welcomeViewModel.setInternalProfileId(profileId) logHomeActivityEvent() val promotedStoryListViewModel = PromotedStoryListViewModel( @@ -76,12 +69,13 @@ class HomeFragmentPresenter @Inject constructor( val homeViewModel = HomeViewModel( activity, fragment, + oppiaClock, + logger, + profileId, + profileManagementController, topicListController, topicEntityType ) - homeViewModel.addHomeItem(welcomeViewModel) - homeViewModel.addHomeItem(promotedStoryListViewModel) - homeViewModel.addHomeItem(allTopicsViewModel) val spanCount = activity.resources.getInteger(R.integer.home_span_count) val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index d183060ce5b..7ad1ff697eb 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -3,36 +3,74 @@ package org.oppia.android.app.home import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.Profile +import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList import org.oppia.android.app.viewmodel.ObservableViewModel import org.oppia.android.app.viewmodel.ViewModelProvider +import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProviders.Companion.toLiveData +import org.oppia.android.util.datetime.DateTimeUtil +import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.TopicHtmlParserEntityType +import org.oppia.android.util.system.OppiaClock import javax.inject.Inject @FragmentScope class HomeViewModel @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, + private val oppiaClock: OppiaClock, + private val logger: ConsoleLogger, + private val profileId: ProfileId, + private val profileManagementController: ProfileManagementController, private val topicListController: TopicListController, @TopicHtmlParserEntityType private val topicEntityType: String ) : ObservableViewModel() { - private var itemList: MutableList = ArrayList() + val itemListLiveData by lazy { + + } + + private val profileResultLiveData: LiveData> by lazy { + profileManagementController.getProfile(profileId).toLiveData() + } + + private val welcomeLiveData: LiveData> by lazy { + Transformations.map(profileResultLiveData, ::processGetProfileResult) + } + + private fun processGetProfileResult(profileResult: AsyncResult) + : MutableList { + if (profileResult.isFailure()) { + logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) + } + val profile = profileResult.getOrDefault(Profile.getDefaultInstance()) + val welcome = WelcomeViewModel( + fragment, + oppiaClock + ) + welcome.profileName.set(profile.name) + return mutableListOf(welcome) + } + private val topicListSummaryResultLiveData: LiveData> by lazy { topicListController.getTopicList() } - val itemListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulTopicListLiveData, ::processItemList) + private val topicListLiveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulTopicListLiveData, ::processTopicList) } - private fun processItemList(itemListLiveData: TopicList) : List { - for (topicSummary in itemListLiveData.topicSummaryList) { + private fun processTopicList(itemsList: TopicList) : MutableList { + var list : MutableList = ArrayList() + for (topicSummary in itemsList.topicSummaryList) { val topicSummaryViewModel = TopicSummaryViewModel( activity, @@ -40,10 +78,10 @@ class HomeViewModel @Inject constructor( topicEntityType, fragment as TopicSummaryClickListener ) - topicSummaryViewModel.setPosition(1 + itemListLiveData.topicSummaryList.indexOf(topicSummary)) - itemList.add(topicSummaryViewModel) + topicSummaryViewModel.setPosition(1 + itemsList.topicSummaryList.indexOf(topicSummary)) + list.add(topicSummaryViewModel) } - return itemList + return list } private val assumedSuccessfulTopicListLiveData: LiveData by lazy { @@ -52,8 +90,4 @@ class HomeViewModel @Inject constructor( it.getOrDefault(TopicList.getDefaultInstance()) } } - - fun addHomeItem(viewModel: HomeItemViewModel) { - itemList.add(viewModel) - } } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 0dca3fa1414..f5b54c7267f 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -1,54 +1,25 @@ package org.oppia.android.app.home +import androidx.databinding.ObservableField import androidx.fragment.app.Fragment -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel -import org.oppia.android.app.model.Profile -import org.oppia.android.app.model.ProfileId -import org.oppia.android.domain.profile.ProfileManagementController -import org.oppia.android.util.logging.ConsoleLogger -import org.oppia.android.util.data.AsyncResult -import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.datetime.DateTimeUtil import org.oppia.android.util.system.OppiaClock import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel @Inject constructor( - private val logger: ConsoleLogger, fragment: Fragment, - oppiaClock: OppiaClock, - private val profileManagementController: ProfileManagementController + oppiaClock: OppiaClock ) : HomeItemViewModel() { - private lateinit var profileId : ProfileId - var greeting: String = DateTimeUtil( + private val greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock ).getGreetingMessage() - val profileName: LiveData by lazy { - Transformations.map(profileLiveData) { - it.name - } - } - - private val profileResultLiveData: LiveData> by lazy { - profileManagementController.getProfile(profileId).toLiveData() - } - - private val profileLiveData: LiveData by lazy { - Transformations.map(profileResultLiveData, ::processGetProfileResult) - } - - private fun processGetProfileResult(profileResult: AsyncResult): Profile { - if (profileResult.isFailure()) { - logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) - } - return profileResult.getOrDefault(Profile.getDefaultInstance()) - } + val profileName = ObservableField("") - fun setInternalProfileId(id: ProfileId) { - this.profileId = id + fun getGreeting() : String { + return greeting } } diff --git a/app/src/main/res/layout-sw600dp-land/welcome.xml b/app/src/main/res/layout-sw600dp-land/welcome.xml index 71505ed5332..b9e92ee88a2 100644 --- a/app/src/main/res/layout-sw600dp-land/welcome.xml +++ b/app/src/main/res/layout-sw600dp-land/welcome.xml @@ -21,7 +21,7 @@ android:fontFamily="sans-serif" android:textColor="@color/oppiaPrimaryText" android:textSize="24sp" - android:text="@{viewModel.greeting}" + android:text="@{viewModel.getGreeting()}" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> From fd0d43198753f4964892e0f6ea6e00b7b8e6d834 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 11 Dec 2020 17:39:47 -0800 Subject: [PATCH 029/248] Move processing logic for all view models to home --- .../android/app/home/HomeFragmentPresenter.kt | 15 +-- .../android/app/home/HomeItemViewModel.kt | 4 +- .../oppia/android/app/home/HomeViewModel.kt | 116 +++++++++++++++--- .../topiclist/PromotedStoryListViewModel.kt | 68 +--------- .../promoted_story_list.xml | 2 +- app/src/main/res/layout/home_fragment.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 4 +- 7 files changed, 117 insertions(+), 94 deletions(-) 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 7d1c02c2f34..d1630f73762 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 @@ -55,26 +55,19 @@ class HomeFragmentPresenter @Inject constructor( // data-bound view models. internalProfileId = activity.intent.getIntExtra(KEY_NAVIGATION_PROFILE_ID, -1) - val profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() logHomeActivityEvent() - val promotedStoryListViewModel = PromotedStoryListViewModel( - activity, - internalProfileId, - intentFactoryShim, - topicListController, - storyEntityType - ) - val allTopicsViewModel = AllTopicsViewModel() val homeViewModel = HomeViewModel( activity, fragment, oppiaClock, logger, - profileId, + internalProfileId, + intentFactoryShim, profileManagementController, topicListController, - topicEntityType + topicEntityType, + storyEntityType ) val spanCount = activity.resources.getInteger(R.integer.home_span_count) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt index 4cd6675658d..31b06c5bd41 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt @@ -3,4 +3,6 @@ package org.oppia.android.app.home import org.oppia.android.app.viewmodel.ObservableViewModel /** The root [ViewModel] for all individual items that may be displayed in home fragment recycler view. */ -abstract class HomeItemViewModel : ObservableViewModel() +abstract class HomeItemViewModel : ObservableViewModel() { + +} diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 7ad1ff697eb..b91d4c88429 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -3,22 +3,28 @@ package org.oppia.android.app.home import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.Transformations +import androidx.work.impl.utils.LiveDataUtils +import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope +import org.oppia.android.app.home.HomeItemViewModel +import org.oppia.android.app.home.topiclist.AllTopicsViewModel +import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel +import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList +import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel -import org.oppia.android.app.viewmodel.ViewModelProvider import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData -import org.oppia.android.util.datetime.DateTimeUtil import org.oppia.android.util.logging.ConsoleLogger +import org.oppia.android.util.parser.StoryHtmlParserEntityType import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock import javax.inject.Inject @@ -29,28 +35,41 @@ class HomeViewModel @Inject constructor( private val fragment: Fragment, private val oppiaClock: OppiaClock, private val logger: ConsoleLogger, - private val profileId: ProfileId, + private val internalProfileId: Int, + private val intentFactoryShim: IntentFactoryShim, private val profileManagementController: ProfileManagementController, private val topicListController: TopicListController, - @TopicHtmlParserEntityType private val topicEntityType: String + @TopicHtmlParserEntityType private val topicEntityType: String, + @StoryHtmlParserEntityType private val storyEntityType: String ) : ObservableViewModel() { - val itemListLiveData by lazy { + private val profileId : ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + private lateinit var welcomeViewModel : WelcomeViewModel + private lateinit var promotedStoryListViewModel : PromotedStoryListViewModel + private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + private val allTopicsViewModel = AllTopicsViewModel() + private lateinit var topicSummaryViewModelList : List - } + val itemsList = listOf( + welcomeViewModel, + promotedStoryListViewModel, + allTopicsViewModel, + topicSummaryViewModelList + ) private val profileResultLiveData: LiveData> by lazy { profileManagementController.getProfile(profileId).toLiveData() } - private val welcomeLiveData: LiveData> by lazy { + private val welcomeViewModelLiveData: LiveData by lazy { Transformations.map(profileResultLiveData, ::processGetProfileResult) } - private fun processGetProfileResult(profileResult: AsyncResult) - : MutableList { + private fun processGetProfileResult(profileResult: AsyncResult) : WelcomeViewModel { if (profileResult.isFailure()) { - logger.e("HomeFragment", "Failed to retrieve profile", profileResult.getErrorOrNull()!!) + logger.e("HomeFragment", + "Failed to retrieve profile", + profileResult.getErrorOrNull()!!) } val profile = profileResult.getOrDefault(Profile.getDefaultInstance()) val welcome = WelcomeViewModel( @@ -58,18 +77,84 @@ class HomeViewModel @Inject constructor( oppiaClock ) welcome.profileName.set(profile.name) - return mutableListOf(welcome) + welcomeViewModel = welcome + return welcome + } + + private val ongoingStoryListSummaryResultLiveData: LiveData> + by lazy { + topicListController.getOngoingStoryList(profileId).toLiveData() + } + + private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { + // If there's an error loading the data, assume the default. + Transformations.map(ongoingStoryListSummaryResultLiveData) { + it.getOrDefault( + OngoingStoryList.getDefaultInstance() + ) + } + } + + private val promotedStoryListViewModelLiveData: LiveData by lazy { + Transformations.map(promotedStoryListLiveData, ::processPromotedStories) + } + + private fun processPromotedStories(list: List) : PromotedStoryListViewModel{ + promotedStoryListViewModel = PromotedStoryListViewModel( + activity, + internalProfileId, + intentFactoryShim + ) + promotedStoryListViewModel.setList(list) + return promotedStoryListViewModel + } + + val promotedStoryListLiveData: LiveData> by lazy { + Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) + } + + private fun processOngoingStoryList(ongoingStoryList: OngoingStoryList) : List { + var newPromotedStoryList: MutableList = ArrayList() + if (ongoingStoryList.recentStoryCount != 0) { + ongoingStoryList.recentStoryList.take(limit) + .forEach { promotedStory -> + val recentStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + recentStory.setPromotedStory(promotedStory) + recentStory.setStoryCount(ongoingStoryList.recentStoryCount) + newPromotedStoryList.add(recentStory) + } + } else { + // TODO(#936): Optimise this as part of recommended stories. + ongoingStoryList.olderStoryList.take(limit) + .forEach { promotedStory -> + val oldStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + oldStory.setPromotedStory(promotedStory) + oldStory.setStoryCount(ongoingStoryList.olderStoryCount) + newPromotedStoryList.add(oldStory) + } + } + return newPromotedStoryList } private val topicListSummaryResultLiveData: LiveData> by lazy { topicListController.getTopicList() } - private val topicListLiveData: LiveData> by lazy { + private val topicListLiveData: LiveData> by lazy { Transformations.map(assumedSuccessfulTopicListLiveData, ::processTopicList) } - private fun processTopicList(itemsList: TopicList) : MutableList { - var list : MutableList = ArrayList() + private fun processTopicList(itemsList: TopicList) : MutableList { + var list : MutableList = ArrayList() for (topicSummary in itemsList.topicSummaryList) { val topicSummaryViewModel = TopicSummaryViewModel( @@ -81,6 +166,7 @@ class HomeViewModel @Inject constructor( topicSummaryViewModel.setPosition(1 + itemsList.topicSummaryList.indexOf(topicSummary)) list.add(topicSummaryViewModel) } + topicSummaryViewModelList = list return list } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index efc29e18ff1..2088d62ffb8 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -1,89 +1,31 @@ package org.oppia.android.app.home.topiclist -import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener -import org.oppia.android.app.model.OngoingStoryList -import org.oppia.android.app.model.ProfileId import org.oppia.android.app.shim.IntentFactoryShim -import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult -import org.oppia.android.util.data.DataProviders.Companion.toLiveData -import org.oppia.android.util.parser.StoryHtmlParserEntityType import javax.inject.Inject /** [ViewModel] promoted story list in [HomeFragment]. */ class PromotedStoryListViewModel @Inject constructor( private val activity: AppCompatActivity, private val internalProfileId: Int, - private val intentFactoryShim: IntentFactoryShim, - private val topicListController: TopicListController, - @StoryHtmlParserEntityType private val storyEntityType: String + private val intentFactoryShim: IntentFactoryShim ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { - private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) +// private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) val paddingEnd = activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) val paddingStart = activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - private val ongoingStoryListSummaryResultLiveData: LiveData> - by lazy { - topicListController.getOngoingStoryList( - ProfileId.newBuilder().setInternalId(internalProfileId).build() - ).toLiveData() - } + var promotedStoryList : List = ArrayList() - private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(ongoingStoryListSummaryResultLiveData) { - it.getOrDefault( - OngoingStoryList.getDefaultInstance() - ) - } - } - - val promotedStoryListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) - } - - private fun processOngoingStoryList(ongoingStoryList: OngoingStoryList) : List { - var newPromotedStoryList: MutableList = ArrayList() - if (ongoingStoryList.recentStoryCount != 0) { - ongoingStoryList.recentStoryList.take(limit) - .forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - recentStory.setPromotedStory(promotedStory) - recentStory.setStoryCount(ongoingStoryList.recentStoryCount) - newPromotedStoryList.add(recentStory) - } - } else { - // TODO(#936): Optimise this as part of recommended stories. - ongoingStoryList.olderStoryList.take(limit) - .forEach { promotedStory -> - val oldStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim - ) - oldStory.setPromotedStory(promotedStory) - oldStory.setStoryCount(ongoingStoryList.olderStoryCount) - newPromotedStoryList.add(oldStory) - } - } - return newPromotedStoryList + fun setList(storyList: List) { + this.promotedStoryList = storyList } fun clickOnViewAll() { diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index ec93b5d2e68..f1431cb5190 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -46,7 +46,7 @@ android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" - android:visibility="@{viewModel.promotedStoryListLiveData.size() > 3 ? View.VISIBLE : View.INVISIBLE}" + android:visibility="@{viewModel.promotedStoryList.size() > 3 ? View.VISIBLE : View.INVISIBLE}" android:textColor="@color/oppiaPrimaryDark" android:textSize="14sp" />
diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 1efab042e3e..b454d3109df 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.itemListLiveData}" /> + app:data="@{viewModel.itemsList}" /> + app:data="@{viewModel.promotedStoryList}" />
From 9d2d9e49ba9a1d8aee4c733e5d76c5b83515b8cb Mon Sep 17 00:00:00 2001 From: Veena Date: Sat, 12 Dec 2020 14:54:27 +0530 Subject: [PATCH 030/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 46 +++++++++++-------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 69c57736388..70e063fbb69 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -706,25 +706,25 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() -// storyProgressController.recordCompletedChapter( -// profileId0, -// RATIOS_TOPIC_ID, -// RATIOS_STORY_ID_1, -// RATIOS_EXPLORATION_ID_2, -// getCurrentTimestamp(), -// false -// ) -// testCoroutineDispatchers.runCurrent() -// -// storyProgressController.recordCompletedChapter( -// profileId0, -// RATIOS_TOPIC_ID, -// RATIOS_STORY_ID_1, -// RATIOS_EXPLORATION_ID_3, -// getCurrentTimestamp(), -// false -// ) -// testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + getCurrentTimestamp(), + false + ) + testCoroutineDispatchers.runCurrent() topicListController.getOngoingStoryList(profileId0).toLiveData() .observeForever(mockOngoingStoryListObserver) @@ -734,7 +734,13 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) -// assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(0) + + val comingSoontopicListLiveData = topicListController.getComingSoonTopicList() + + val topicListResult = comingSoontopicListLiveData.value + assertThat(topicListResult).isNotNull() + assertThat(topicListResult!!.isSuccess()).isTrue() } @Test From 5309299d473a37b1fb2f6cec1bce38ac437b7136 Mon Sep 17 00:00:00 2001 From: Veena Date: Sat, 12 Dec 2020 14:59:30 +0530 Subject: [PATCH 031/248] reverted changes --- .idea/misc.xml | 4 ++-- .../app/drawer/NavigationDrawerFragmentPresenter.kt | 10 +++------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index d5d35ec44f1..f06c82261e6 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,9 +1,9 @@ - + - \ No newline at end of file + 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 a59ef02aae4..5de1a3c745f 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 @@ -28,7 +28,6 @@ import org.oppia.android.app.options.OptionsActivity import org.oppia.android.app.profileprogress.ProfileProgressActivity import org.oppia.android.app.topic.TopicActivity import org.oppia.android.app.viewmodel.ViewModelProvider -import org.oppia.android.app.walkthrough.WalkthroughActivity import org.oppia.android.databinding.DrawerFragmentBinding import org.oppia.android.databinding.NavHeaderNavigationDrawerBinding import org.oppia.android.domain.profile.ProfileManagementController @@ -215,12 +214,9 @@ class NavigationDrawerFragmentPresenter @Inject constructor( drawerLayout.closeDrawers() } NavigationDrawerItem.HELP -> { -// val intent = HelpActivity.createHelpActivityIntent( -// activity, internalProfileId, -// /* isFromNavigationDrawer= */ true -// ) - val intent = WalkthroughActivity.createWalkthroughActivityIntent( - activity, internalProfileId + val intent = HelpActivity.createHelpActivityIntent( + activity, internalProfileId, + /* isFromNavigationDrawer= */ true ) fragment.activity!!.startActivity(intent) if (checkIfPreviousActivityShouldGetFinished(menuItemId)) { From 7bf14b3d53afb32548579e483e3432598c962e2b Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 14 Dec 2020 14:17:15 -0800 Subject: [PATCH 032/248] Add model for home fragment data to combine data providers --- .../oppia/android/app/home/HomeViewModel.kt | 169 ++++++++++-------- .../home/topiclist/PromotedStoryListView.kt | 5 +- .../topiclist/PromotedStoryListViewModel.kt | 5 +- app/src/main/res/layout/home_fragment.xml | 2 +- 4 files changed, 102 insertions(+), 79 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index b91d4c88429..f1aeb15ec9e 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -4,10 +4,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment import androidx.lifecycle.LiveData import androidx.lifecycle.Transformations -import androidx.work.impl.utils.LiveDataUtils +import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryViewModel @@ -21,7 +20,8 @@ import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController -import org.oppia.android.util.data.AsyncResult +import org.oppia.android.util.data.DataProvider +import org.oppia.android.util.data.DataProviders.Companion.combineWith import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.StoryHtmlParserEntityType @@ -29,6 +29,10 @@ import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock import javax.inject.Inject +private const val PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID = "profile+ongoingStoryList" +private const val HOME_FRAGMENT_COMBINED_PROVIDER_ID = "profile+ongoingStoryList+topicListProvider" + +/** [ViewModel] for layouts in home fragment . */ @FragmentScope class HomeViewModel @Inject constructor( private val activity: AppCompatActivity, @@ -44,77 +48,91 @@ class HomeViewModel @Inject constructor( ) : ObservableViewModel() { private val profileId : ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - private lateinit var welcomeViewModel : WelcomeViewModel - private lateinit var promotedStoryListViewModel : PromotedStoryListViewModel private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) - private val allTopicsViewModel = AllTopicsViewModel() - private lateinit var topicSummaryViewModelList : List - - val itemsList = listOf( - welcomeViewModel, - promotedStoryListViewModel, - allTopicsViewModel, - topicSummaryViewModelList - ) - private val profileResultLiveData: LiveData> by lazy { - profileManagementController.getProfile(profileId).toLiveData() + private val profileDataProvider: DataProvider by lazy { + profileManagementController.getProfile(profileId) } - private val welcomeViewModelLiveData: LiveData by lazy { - Transformations.map(profileResultLiveData, ::processGetProfileResult) - } - - private fun processGetProfileResult(profileResult: AsyncResult) : WelcomeViewModel { - if (profileResult.isFailure()) { - logger.e("HomeFragment", - "Failed to retrieve profile", - profileResult.getErrorOrNull()!!) + private val ongoingStoryListSummaryDataProvider: DataProvider + by lazy { + topicListController.getOngoingStoryList(profileId) } - val profile = profileResult.getOrDefault(Profile.getDefaultInstance()) - val welcome = WelcomeViewModel( - fragment, - oppiaClock - ) - welcome.profileName.set(profile.name) - welcomeViewModel = welcome - return welcome + + private val topicListSummaryDataProvider: DataProvider by lazy { + topicListController.getTopicList() } - private val ongoingStoryListSummaryResultLiveData: LiveData> - by lazy { - topicListController.getOngoingStoryList(profileId).toLiveData() + private val combinedHomeFragmentModelDataProvider: DataProvider by lazy { + // This will block until all data providers return initial results (which may be default + // instances). If any of the data providers are pending or failed, the combined result will also + // be pending or failed. + profileDataProvider.combineWith( + ongoingStoryListSummaryDataProvider, + PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID) { profile, ongoingStoryList -> + HomeFragmentModel(profile, ongoingStoryList) + }.combineWith( + topicListSummaryDataProvider, + HOME_FRAGMENT_COMBINED_PROVIDER_ID) { combinedModel, topicList -> + HomeFragmentModel(combinedModel.profile, combinedModel.ongoingStoryList, topicList) } + } - private val assumedSuccessfulOngoingStoryListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(ongoingStoryListSummaryResultLiveData) { - it.getOrDefault( - OngoingStoryList.getDefaultInstance() + // Resulting LiveData to bind to the outer RecyclerView & that contains all ViewModels. + val combinedHomeViewModelListLiveData: LiveData> by lazy { + Transformations.map(combinedHomeFragmentModelDataProvider.toLiveData()) { combinedModelResult -> + if (combinedModelResult.isFailure()) { + logger.e("HomeFragment", + "Failed to retrieve fragment", + combinedModelResult.getErrorOrNull() + ) + } + val combinedModel = combinedModelResult.getOrDefault(HomeFragmentModel()) + // Convert combinedModel into a list of view models for the home screen (proto defaults + // should result in no view models for corresponding sections so that they don't appear). + // This can usually be done by checking that a constituent list is empty. + var itemList : List = listOf( + getProfileData(combinedModel.profile) as HomeItemViewModel, + getPromotedStoryListData(combinedModel.ongoingStoryList) as HomeItemViewModel, + AllTopicsViewModel() as HomeItemViewModel, + getTopicListData(combinedModel.topicList) as HomeItemViewModel ) + return@map itemList } } - private val promotedStoryListViewModelLiveData: LiveData by lazy { - Transformations.map(promotedStoryListLiveData, ::processPromotedStories) + private fun getProfileData(profile: Profile) : WelcomeViewModel { + val welcomeViewModel = WelcomeViewModel(fragment, oppiaClock) + if (profile.isInitialized) { + welcomeViewModel.profileName.set(profile.name) + } else { + logger.i("HomeFragment", + "Failed to retrieve profile" + ) + welcomeViewModel.profileName.set(Profile.getDefaultInstance().name) + } + return welcomeViewModel } - private fun processPromotedStories(list: List) : PromotedStoryListViewModel{ - promotedStoryListViewModel = PromotedStoryListViewModel( + private fun getPromotedStoryListData(ongoingStoryList: OngoingStoryList) : PromotedStoryListViewModel { + val promotedStoryListViewModel = PromotedStoryListViewModel( activity, internalProfileId, - intentFactoryShim - ) - promotedStoryListViewModel.setList(list) + intentFactoryShim) + if (ongoingStoryList.isInitialized) { + promotedStoryListViewModel.setPromotedStories(processPromotedStories(ongoingStoryList)) + } else { + logger.i("HomeFragment", + "Failed to retrieve promoted stories" + ) + promotedStoryListViewModel.setPromotedStories( + processPromotedStories(OngoingStoryList.getDefaultInstance())) + } return promotedStoryListViewModel } - val promotedStoryListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulOngoingStoryListLiveData, ::processOngoingStoryList) - } - - private fun processOngoingStoryList(ongoingStoryList: OngoingStoryList) : List { - var newPromotedStoryList: MutableList = ArrayList() + private fun processPromotedStories(ongoingStoryList: OngoingStoryList) : List { + var promotedStoryList: MutableList = ArrayList() if (ongoingStoryList.recentStoryCount != 0) { ongoingStoryList.recentStoryList.take(limit) .forEach { promotedStory -> @@ -126,7 +144,7 @@ class HomeViewModel @Inject constructor( ) recentStory.setPromotedStory(promotedStory) recentStory.setStoryCount(ongoingStoryList.recentStoryCount) - newPromotedStoryList.add(recentStory) + promotedStoryList.add(recentStory) } } else { // TODO(#936): Optimise this as part of recommended stories. @@ -140,22 +158,26 @@ class HomeViewModel @Inject constructor( ) oldStory.setPromotedStory(promotedStory) oldStory.setStoryCount(ongoingStoryList.olderStoryCount) - newPromotedStoryList.add(oldStory) + promotedStoryList.add(oldStory) } } - return newPromotedStoryList + return promotedStoryList } - private val topicListSummaryResultLiveData: LiveData> by lazy { - topicListController.getTopicList() - } - private val topicListLiveData: LiveData> by lazy { - Transformations.map(assumedSuccessfulTopicListLiveData, ::processTopicList) + private fun getTopicListData(topicsList: TopicList) : List { + if (topicsList.isInitialized) { + return processTopicsList(topicsList) + } else { + logger.i("HomeFragment", + "Failed to retrieve topics list" + ) + return processTopicsList(TopicList.getDefaultInstance()) + } } - private fun processTopicList(itemsList: TopicList) : MutableList { - var list : MutableList = ArrayList() - for (topicSummary in itemsList.topicSummaryList) { + private fun processTopicsList(topicsList: TopicList) : List { + var list: MutableList = ArrayList() + for (topicSummary in topicsList.topicSummaryList) { val topicSummaryViewModel = TopicSummaryViewModel( activity, @@ -163,17 +185,18 @@ class HomeViewModel @Inject constructor( topicEntityType, fragment as TopicSummaryClickListener ) - topicSummaryViewModel.setPosition(1 + itemsList.topicSummaryList.indexOf(topicSummary)) + topicSummaryViewModel.setPosition(1 + topicsList.topicSummaryList.indexOf(topicSummary)) list.add(topicSummaryViewModel) } - topicSummaryViewModelList = list return list } - private val assumedSuccessfulTopicListLiveData: LiveData by lazy { - // If there's an error loading the data, assume the default. - Transformations.map(topicListSummaryResultLiveData) { - it.getOrDefault(TopicList.getDefaultInstance()) - } - } + // Model to display combined fragment data from all view models. Initialize to the default values + // so that fragment can display on initial load until data-fetching from each Data Provider + // finishes. + private data class HomeFragmentModel( + val profile: Profile = Profile.getDefaultInstance(), + val ongoingStoryList: OngoingStoryList = OngoingStoryList.getDefaultInstance(), + val topicList: TopicList = TopicList.getDefaultInstance() + ) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index 766c662ad11..acb1f57015f 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -26,8 +26,9 @@ class PromotedStoryListView @JvmOverloads constructor ( ).build() /* - * The StartSnapHelper is used to snap between items rather than smooth scrolling, - * so that the item is completely visible in [HomeFragment] as soon as learner lifts the finger after scrolling. + * The StartSnapHelper is used to snap between items rather than smooth scrolling, so that + * the item is completely visible in [HomeFragment] as soon as learner lifts the finger + * after scrolling. */ val snapHelper = StartSnapHelper() this.setOnFlingListener(null) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 2088d62ffb8..59f63e9d5fb 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -16,15 +16,14 @@ class PromotedStoryListViewModel @Inject constructor( ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { -// private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) val paddingEnd = activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) val paddingStart = activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - var promotedStoryList : List = ArrayList() + var promotedStoryList : List = listOf() - fun setList(storyList: List) { + fun setPromotedStories(storyList: List) { this.promotedStoryList = storyList } diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index b454d3109df..69a437b41c6 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.itemsList}" /> + app:data="@{viewModel.combinedHomeViewModelListLiveData}" /> Date: Mon, 14 Dec 2020 17:36:21 -0800 Subject: [PATCH 033/248] Apply patch for combining home view model data and adjust topic list margins --- .../oppia/android/app/home/HomeViewModel.kt | 141 ++++++------------ .../android/app/home/WelcomeViewModel.kt | 15 +- .../topiclist/PromotedStoryListViewModel.kt | 11 +- .../home/topiclist/PromotedStoryViewModel.kt | 36 +---- .../home/topiclist/TopicSummaryViewModel.kt | 20 +-- app/src/main/res/layout-land/all_topics.xml | 6 + .../main/res/layout-land/home_fragment.xml | 9 +- .../res/layout-land/promoted_story_card.xml | 14 +- .../res/layout-land/promoted_story_list.xml | 15 +- .../res/layout-land/topic_summary_view.xml | 4 + .../res/layout-sw600dp-land/all_topics.xml | 6 + .../res/layout-sw600dp-land/home_fragment.xml | 9 +- .../promoted_story_card.xml | 14 +- .../promoted_story_list.xml | 15 +- .../topic_summary_view.xml | 4 + .../res/layout-sw600dp-port/all_topics.xml | 6 + .../res/layout-sw600dp-port/home_fragment.xml | 9 +- .../promoted_story_card.xml | 14 +- .../promoted_story_list.xml | 13 +- app/src/main/res/layout/home_fragment.xml | 2 +- .../main/res/layout/promoted_story_card.xml | 14 +- .../main/res/layout/promoted_story_list.xml | 2 +- .../domain/topic/TopicListController.kt | 12 +- 23 files changed, 192 insertions(+), 199 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index f1aeb15ec9e..cce3e0101ee 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -60,143 +60,96 @@ class HomeViewModel @Inject constructor( } private val topicListSummaryDataProvider: DataProvider by lazy { - topicListController.getTopicList() + // TODO: once #2253 is merged change this function call + topicListController.getTopicList2() } - private val combinedHomeFragmentModelDataProvider: DataProvider by lazy { + private val homeItemViewModelListDataProvider: DataProvider> by lazy { // This will block until all data providers return initial results (which may be default // instances). If any of the data providers are pending or failed, the combined result will also // be pending or failed. profileDataProvider.combineWith( ongoingStoryListSummaryDataProvider, PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID) { profile, ongoingStoryList -> - HomeFragmentModel(profile, ongoingStoryList) + listOfNotNull(computeWelcomeViewModel(profile), computePromotedStoryListViewModel(ongoingStoryList)) }.combineWith( topicListSummaryDataProvider, - HOME_FRAGMENT_COMBINED_PROVIDER_ID) { combinedModel, topicList -> - HomeFragmentModel(combinedModel.profile, combinedModel.ongoingStoryList, topicList) + HOME_FRAGMENT_COMBINED_PROVIDER_ID) { homeItemViewModelList, topicList -> + homeItemViewModelList + listOf(AllTopicsViewModel()) + computeTopicSummaryItemViewModelList(topicList) } } // Resulting LiveData to bind to the outer RecyclerView & that contains all ViewModels. - val combinedHomeViewModelListLiveData: LiveData> by lazy { - Transformations.map(combinedHomeFragmentModelDataProvider.toLiveData()) { combinedModelResult -> - if (combinedModelResult.isFailure()) { + val homeItemViewModelListLiveData: LiveData> by lazy { + Transformations.map(homeItemViewModelListDataProvider.toLiveData()) { itemListResult -> + if (itemListResult.isFailure()) { logger.e("HomeFragment", "Failed to retrieve fragment", - combinedModelResult.getErrorOrNull() + itemListResult.getErrorOrNull() ) } - val combinedModel = combinedModelResult.getOrDefault(HomeFragmentModel()) - // Convert combinedModel into a list of view models for the home screen (proto defaults - // should result in no view models for corresponding sections so that they don't appear). - // This can usually be done by checking that a constituent list is empty. - var itemList : List = listOf( - getProfileData(combinedModel.profile) as HomeItemViewModel, - getPromotedStoryListData(combinedModel.ongoingStoryList) as HomeItemViewModel, - AllTopicsViewModel() as HomeItemViewModel, - getTopicListData(combinedModel.topicList) as HomeItemViewModel - ) - return@map itemList + return@map itemListResult.getOrDefault(listOf()) } } - private fun getProfileData(profile: Profile) : WelcomeViewModel { - val welcomeViewModel = WelcomeViewModel(fragment, oppiaClock) - if (profile.isInitialized) { - welcomeViewModel.profileName.set(profile.name) - } else { - logger.i("HomeFragment", - "Failed to retrieve profile" - ) - welcomeViewModel.profileName.set(Profile.getDefaultInstance().name) - } - return welcomeViewModel + private fun computeWelcomeViewModel(profile: Profile) : HomeItemViewModel? { + return if (profile.name.isNotEmpty()) { + WelcomeViewModel(fragment, oppiaClock, profile.name) + } else null } - private fun getPromotedStoryListData(ongoingStoryList: OngoingStoryList) : PromotedStoryListViewModel { - val promotedStoryListViewModel = PromotedStoryListViewModel( - activity, - internalProfileId, - intentFactoryShim) - if (ongoingStoryList.isInitialized) { - promotedStoryListViewModel.setPromotedStories(processPromotedStories(ongoingStoryList)) - } else { - logger.i("HomeFragment", - "Failed to retrieve promoted stories" + private fun computePromotedStoryListViewModel(ongoingStoryList: OngoingStoryList): HomeItemViewModel? { + val storyViewModelList = computePromotedStoryViewModelList(ongoingStoryList) + return if (storyViewModelList.isNotEmpty()) { + return PromotedStoryListViewModel( + activity, + internalProfileId, + intentFactoryShim, + storyViewModelList ) - promotedStoryListViewModel.setPromotedStories( - processPromotedStories(OngoingStoryList.getDefaultInstance())) - } - return promotedStoryListViewModel + } else null } - private fun processPromotedStories(ongoingStoryList: OngoingStoryList) : List { - var promotedStoryList: MutableList = ArrayList() + private fun computePromotedStoryViewModelList( + ongoingStoryList: OngoingStoryList + ): List { if (ongoingStoryList.recentStoryCount != 0) { - ongoingStoryList.recentStoryList.take(limit) - .forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( + return ongoingStoryList.recentStoryList.take(limit) + .map { promotedStory -> + PromotedStoryViewModel( activity, internalProfileId, + intentFactoryShim, + ongoingStoryList.recentStoryCount, storyEntityType, - intentFactoryShim + promotedStory ) - recentStory.setPromotedStory(promotedStory) - recentStory.setStoryCount(ongoingStoryList.recentStoryCount) - promotedStoryList.add(recentStory) } } else { // TODO(#936): Optimise this as part of recommended stories. - ongoingStoryList.olderStoryList.take(limit) - .forEach { promotedStory -> - val oldStory = PromotedStoryViewModel( + return ongoingStoryList.olderStoryList.take(limit) + .map { promotedStory -> + PromotedStoryViewModel( activity, internalProfileId, + intentFactoryShim, + ongoingStoryList.olderStoryCount, storyEntityType, - intentFactoryShim + promotedStory ) - oldStory.setPromotedStory(promotedStory) - oldStory.setStoryCount(ongoingStoryList.olderStoryCount) - promotedStoryList.add(oldStory) } } - return promotedStoryList } - private fun getTopicListData(topicsList: TopicList) : List { - if (topicsList.isInitialized) { - return processTopicsList(topicsList) - } else { - logger.i("HomeFragment", - "Failed to retrieve topics list" + private fun computeTopicSummaryItemViewModelList(topicList: TopicList) : List { + return topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> + TopicSummaryViewModel( + activity, + topicSummary, + topicEntityType, + fragment as TopicSummaryClickListener, + position = topicIndex ) - return processTopicsList(TopicList.getDefaultInstance()) - } - } - - private fun processTopicsList(topicsList: TopicList) : List { - var list: MutableList = ArrayList() - for (topicSummary in topicsList.topicSummaryList) { - val topicSummaryViewModel = - TopicSummaryViewModel( - activity, - topicSummary, - topicEntityType, - fragment as TopicSummaryClickListener - ) - topicSummaryViewModel.setPosition(1 + topicsList.topicSummaryList.indexOf(topicSummary)) - list.add(topicSummaryViewModel) } - return list } - - // Model to display combined fragment data from all view models. Initialize to the default values - // so that fragment can display on initial load until data-fetching from each Data Provider - // finishes. - private data class HomeFragmentModel( - val profile: Profile = Profile.getDefaultInstance(), - val ongoingStoryList: OngoingStoryList = OngoingStoryList.getDefaultInstance(), - val topicList: TopicList = TopicList.getDefaultInstance() - ) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index f5b54c7267f..888b845169b 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -8,18 +8,13 @@ import org.oppia.android.util.system.OppiaClock import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ -class WelcomeViewModel @Inject constructor( +class WelcomeViewModel( fragment: Fragment, - oppiaClock: OppiaClock - ) : HomeItemViewModel() { - private val greeting: String = DateTimeUtil( + oppiaClock: OppiaClock, + val profileName: String +): HomeItemViewModel() { + val greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock ).getGreetingMessage() - - val profileName = ObservableField("") - - fun getGreeting() : String { - return greeting - } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 59f63e9d5fb..0580838be38 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -9,10 +9,11 @@ import org.oppia.android.app.shim.IntentFactoryShim import javax.inject.Inject /** [ViewModel] promoted story list in [HomeFragment]. */ -class PromotedStoryListViewModel @Inject constructor( +class PromotedStoryListViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, - private val intentFactoryShim: IntentFactoryShim + private val intentFactoryShim: IntentFactoryShim, + val promotedStoryList: List ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { @@ -21,12 +22,6 @@ class PromotedStoryListViewModel @Inject constructor( val paddingStart = activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - var promotedStoryList : List = listOf() - - fun setPromotedStories(storyList: List) { - this.promotedStoryList = storyList - } - fun clickOnViewAll() { routeToRecentlyPlayed() } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 022762b5cf3..7a15403db55 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -24,47 +24,25 @@ import org.oppia.android.databinding.PromotedStoryCardBinding class PromotedStoryViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, + private val IntentFactoryShim: IntentFactoryShim, + private val totalStoryCount: Int, val entityType: String, - private val IntentFactoryShim: IntentFactoryShim + val promotedStory: PromotedStory ) : ObservableViewModel(), RouteToTopicPlayStoryListener { - /** - * The retrieved [LiveData] for retrieving topic summaries. This model should ensure only one - * [LiveData] is used for all subsequent processed data to ensure the transformed [LiveData]s are - * always in sync. - */ - lateinit var promotedStoryObservable : PromotedStory - var totalStoryCount = -1 - - fun setPromotedStory(promotedStory: PromotedStory) { - this.promotedStoryObservable = promotedStory - } - - fun setStoryCount(newCount: Int) { - this.totalStoryCount = newCount - } - fun computeLayoutWidth(): Int { val orientation = Resources.getSystem().configuration.orientation - if (totalStoryCount > 1) { - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - return ViewGroup.LayoutParams.MATCH_PARENT - } else { - return activity.resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) - } + return if (orientation != Configuration.ORIENTATION_PORTRAIT && totalStoryCount > 1) { + activity.resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) } else { - return ViewGroup.LayoutParams.MATCH_PARENT + ViewGroup.LayoutParams.MATCH_PARENT } } fun clickOnStoryTile() { - routeToTopicPlayStory( - internalProfileId, - promotedStoryObservable.topicId, - promotedStoryObservable.storyId - ) + routeToTopicPlayStory(internalProfileId, promotedStory.topicId, promotedStory.storyId) } override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 2310063c6ba..5cd73fdfaba 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -21,7 +21,8 @@ class TopicSummaryViewModel ( private val activity: AppCompatActivity, val topicSummary: TopicSummary, val entityType: String, - private val topicSummaryClickListener: TopicSummaryClickListener + private val topicSummaryClickListener: TopicSummaryClickListener, + private val position: Int ) : HomeItemViewModel() { val name: String = topicSummary.name val totalChapterCount: Int = topicSummary.totalChapterCount @@ -35,7 +36,6 @@ class TopicSummaryViewModel ( activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) } private val marginMin by lazy { activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) } - private var position = -1 private val spanCount by lazy { activity.resources.getInteger(R.integer.home_span_count) } @@ -44,10 +44,6 @@ class TopicSummaryViewModel ( topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } - fun setPosition(newPosition: Int) { - this.position = newPosition - } - fun computeTopMargin(): Int { return marginTopBottom } @@ -60,8 +56,8 @@ class TopicSummaryViewModel ( return when (spanCount) { 2 -> { when (position % spanCount) { - 0 -> marginMin - else -> marginMax + 0 -> marginMax + else -> marginMin } } 3 -> { @@ -73,7 +69,7 @@ class TopicSummaryViewModel ( } } 4 -> { - when ((position + 1) % spanCount) { + when (position % spanCount) { 0 -> marginMax 1 -> marginMin 2 -> marginMin / 2 @@ -88,8 +84,8 @@ class TopicSummaryViewModel ( fun computeEndMargin(): Int { return when (spanCount) { 2 -> when (position % spanCount) { - 0 -> marginMax - else -> marginMin + 0 -> marginMin + else -> marginMax } 3 -> when (position % spanCount) { 0 -> 0 @@ -97,7 +93,7 @@ class TopicSummaryViewModel ( 2 -> marginMax else -> 0 } - 4 -> when ((position + 1) % spanCount) { + 4 -> when (position % spanCount) { 0 -> 0 1 -> marginMin / 2 2 -> marginMin diff --git a/app/src/main/res/layout-land/all_topics.xml b/app/src/main/res/layout-land/all_topics.xml index d997dc9127c..d62d0343565 100644 --- a/app/src/main/res/layout-land/all_topics.xml +++ b/app/src/main/res/layout-land/all_topics.xml @@ -1,5 +1,11 @@ + + + + - + + @@ -22,7 +26,8 @@ android:overScrollMode="never" android:paddingTop="40dp" android:paddingBottom="96dp" - android:scrollbars="none" /> + android:scrollbars="none" + app:data="@{viewModel.homeItemViewModelListLiveData}" /> + app:roundedRectDrawableWithColor="@{viewModel.promotedStory.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStory.lessonThumbnail}" /> @@ -79,7 +79,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryObservable.storyName}" + android:text="@{viewModel.promotedStory.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> @@ -94,7 +94,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryObservable.topicName}" + android:text="@{viewModel.promotedStory.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 910e6e5abff..a55688475ec 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -1,5 +1,6 @@ - + @@ -49,13 +50,21 @@ android:textSize="14sp" /> - + android:scrollbars="none" + android:orientation="horizontal" + android:paddingStart="@{viewModel.paddingStart}" + android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" + android:paddingTop="0dp" + android:paddingBottom="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:reverseLayout="false" + app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-land/topic_summary_view.xml b/app/src/main/res/layout-land/topic_summary_view.xml index b52fd9baac7..7734a63329e 100755 --- a/app/src/main/res/layout-land/topic_summary_view.xml +++ b/app/src/main/res/layout-land/topic_summary_view.xml @@ -13,6 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" + app:layoutMarginTop="@{viewModel.computeTopMargin()}" + app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginStart="@{viewModel.computeStartMargin()}" + app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> + + + + - + + @@ -22,7 +26,8 @@ android:overScrollMode="never" android:paddingTop="48dp" android:paddingBottom="100dp" - android:scrollbars="none" /> + android:scrollbars="none" + app:data="@{viewModel.homeItemViewModelListLiveData}" /> + app:roundedRectDrawableWithColor="@{viewModel.promotedStory.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStory.lessonThumbnail}" /> @@ -78,7 +78,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryObservable.storyName}" + android:text="@{viewModel.promotedStory.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -93,7 +93,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryObservable.topicName}" + android:text="@{viewModel.promotedStory.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index f1431cb5190..86aabd57c39 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -1,5 +1,6 @@ - + @@ -8,7 +9,6 @@ - - + android:scrollbars="none" + android:paddingStart="@{viewModel.paddingStart}" + android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" + android:paddingTop="0dp" + android:paddingBottom="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:reverseLayout="false" + app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml b/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml index 72f608eaf17..96ff2872254 100644 --- a/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml +++ b/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml @@ -13,6 +13,10 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" + app:layoutMarginTop="@{viewModel.computeTopMargin()}" + app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginStart="@{viewModel.computeStartMargin()}" + app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> + + + + - + + @@ -22,7 +26,8 @@ android:overScrollMode="never" android:paddingTop="48dp" android:paddingBottom="100dp" - android:scrollbars="none" /> + android:scrollbars="none" + app:data="@{viewModel.homeItemViewModelListLiveData}" /> + app:roundedRectDrawableWithColor="@{viewModel.promotedStory.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStory.lessonThumbnail}" /> @@ -78,7 +78,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryObservable.storyName}" + android:text="@{viewModel.promotedStory.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -93,7 +93,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryObservable.topicName}" + android:text="@{viewModel.promotedStory.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 8b431a7ebb4..57163f5ef60 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -1,5 +1,6 @@ - + @@ -54,7 +55,7 @@ android:textSize="14sp" /> - + android:orientation="horizontal" + android:paddingStart="@{viewModel.paddingStart}" + android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" + android:paddingTop="0dp" + android:paddingBottom="0dp" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:reverseLayout="false" + app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/home_fragment.xml b/app/src/main/res/layout/home_fragment.xml index 69a437b41c6..fbe0e8a6257 100644 --- a/app/src/main/res/layout/home_fragment.xml +++ b/app/src/main/res/layout/home_fragment.xml @@ -27,7 +27,7 @@ android:paddingTop="36dp" android:paddingBottom="148dp" android:scrollbars="none" - app:data="@{viewModel.combinedHomeViewModelListLiveData}" /> + app:data="@{viewModel.homeItemViewModelListLiveData}" /> + app:roundedRectDrawableWithColor="@{viewModel.promotedStory.lessonThumbnail.backgroundColorRgb}"> + app:lessonThumbnail="@{viewModel.promotedStory.lessonThumbnail}" /> @@ -79,7 +79,7 @@ android:ellipsize="end" android:fontFamily="sans-serif" android:maxLines="1" - android:text="@{viewModel.promotedStoryObservable.storyName}" + android:text="@{viewModel.promotedStory.storyName}" android:textColor="@color/oppiaPrimaryText" android:textSize="16sp" /> @@ -94,7 +94,7 @@ android:fontFamily="sans-serif-light" android:maxLines="1" android:paddingBottom="8dp" - android:text="@{viewModel.promotedStoryObservable.topicName}" + android:text="@{viewModel.promotedStory.topicName}" android:textAllCaps="true" android:textColor="@color/oppiaPrimaryText" android:textSize="14sp" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 0871d4e0963..5b50ab0d97d 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -65,6 +65,6 @@ android:paddingBottom="0dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:reverseLayout="false" - app:data="@{viewModel.promotedStoryList}" /> + app:list="@{viewModel.promotedStoryList}" /> diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index f8e4246d647..7fd40219f88 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -19,6 +19,7 @@ import org.oppia.android.app.model.TopicSummary import org.oppia.android.domain.util.JsonAssetRetriever import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider +import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import java.util.Date import java.util.concurrent.TimeUnit @@ -67,6 +68,7 @@ val EXPLORATION_THUMBNAILS = mapOf( TEST_EXPLORATION_ID_6 to createChapterThumbnail0() ) +private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" @@ -77,7 +79,8 @@ private val EVICTION_TIME_MILLIS = TimeUnit.DAYS.toMillis(1) class TopicListController @Inject constructor( private val jsonAssetRetriever: JsonAssetRetriever, private val topicController: TopicController, - private val storyProgressController: StoryProgressController + private val storyProgressController: StoryProgressController, + private val dataProviders: DataProviders ) { /** * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to @@ -87,6 +90,13 @@ class TopicListController @Inject constructor( return MutableLiveData(AsyncResult.success(createTopicList())) } + fun getTopicList2(): DataProvider { + return dataProviders.createInMemoryDataProvider( + GET_TOPIC_LIST_PROVIDER_ID, + this::createTopicList + ) + } + /** * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. * The total number of promoted stories should correspond to the ongoing story count within the From b9c2d4dfe192a9a5e00d759890b9173db46ef0d0 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 14 Dec 2020 17:50:59 -0800 Subject: [PATCH 034/248] Add orientation to tablet layouts --- app/src/main/res/layout-sw600dp-land/promoted_story_list.xml | 1 + app/src/main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 86aabd57c39..bd01bb881f7 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -59,6 +59,7 @@ android:layout_marginTop="4dp" android:overScrollMode="never" android:scrollbars="none" + android:orientation="horizontal" android:paddingStart="@{viewModel.paddingStart}" android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" android:paddingTop="0dp" diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 57163f5ef60..540321da8b1 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -62,7 +62,7 @@ android:clipToPadding="false" android:layout_marginTop="4dp" android:overScrollMode="never" - android:scrollbars="none" /> + android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@{viewModel.paddingStart}" android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" From 728265059111cb6ce238c1d59a1afc60ab51612c Mon Sep 17 00:00:00 2001 From: Veena Date: Tue, 15 Dec 2020 17:59:04 +0530 Subject: [PATCH 035/248] optimized list --- .../app/home/topiclist/TopicListAdapter.kt | 8 +- .../android/app/player/state/StateFragment.kt | 6 +- .../player/state/StateFragmentPresenter.kt | 63 ++-------- .../app/walkthrough/WalkthroughActivity.kt | 29 +---- .../end/WalkthroughEndPageChanger.kt | 1 - .../end/WalkthroughFinalFragmentPresenter.kt | 51 +------- .../walkthrough_final_fragment.xml | 1 - .../res/layout/fraction_interaction_item.xml | 4 +- .../res/layout/walkthrough_final_fragment.xml | 1 - app/src/main/res/values/strings.xml | 1 + .../domain/topic/StoryProgressController.kt | 45 ++------ .../domain/topic/StoryProgressTestHelper.kt | 51 +++----- .../domain/topic/TopicListController.kt | 109 +++++++++--------- .../topic/StoryProgressControllerTest.kt | 21 +--- .../domain/topic/TopicListControllerTest.kt | 108 ++++++----------- model/src/main/proto/topic.proto | 25 +--- 16 files changed, 145 insertions(+), 379 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index fc547d7216e..870ee6698ca 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -34,9 +34,6 @@ class TopicListAdapter( private var spanCount = 0 - private lateinit var promotedStoryViewModel: PromotedStoryViewModel - private lateinit var comingSoonTopicsListViewModel: ComingSoonTopicsListViewModel - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { // TODO(#216): Generalize this binding to make adding future items easier. @@ -165,6 +162,11 @@ class TopicListAdapter( binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) binding.viewAllTextView.visibility = View.VISIBLE } + PromotedStoriesType.PromotedStoriesTypeCase.LAST_PLAYED -> { + binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE + binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) + binding.viewAllTextView.visibility = View.VISIBLE + } PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED -> { binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recommended_stories)) diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt index cfcc94fef87..1ec5536b293 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt @@ -55,7 +55,6 @@ class StateFragment : args.putString(STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY, topicId) args.putString(STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY, storyId) args.putString(STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY, explorationId) - args.putBoolean(STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY, isFromWalkthrough) stateFragment.arguments = args return stateFragment } @@ -78,16 +77,13 @@ class StateFragment : val topicId = arguments!!.getString(STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY)!! val storyId = arguments!!.getString(STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY)!! val explorationId = arguments!!.getString(STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY)!! - val isFromWalkthrough = arguments!!.getBoolean( - STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY) return stateFragmentPresenter.handleCreateView( inflater, container, internalProfileId, topicId, storyId, - explorationId, - isFromWalkthrough + explorationId ) } diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt index 0402768c570..43737cab4be 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragmentPresenter.kt @@ -1,7 +1,6 @@ package org.oppia.android.app.player.state import android.content.Context -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -24,7 +23,6 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.Solution import org.oppia.android.app.model.State import org.oppia.android.app.model.UserAnswer -import org.oppia.android.app.model.Walkthrough import org.oppia.android.app.player.audio.AudioButtonListener import org.oppia.android.app.player.audio.AudioFragment import org.oppia.android.app.player.audio.AudioUiManager @@ -35,7 +33,6 @@ import org.oppia.android.app.viewmodel.ViewModelProvider import org.oppia.android.databinding.StateFragmentBinding import org.oppia.android.domain.exploration.ExplorationProgressController import org.oppia.android.domain.topic.StoryProgressController -import org.oppia.android.domain.topic.TopicListController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.gcsresource.DefaultResourceBucketName @@ -48,7 +45,6 @@ const val STATE_FRAGMENT_PROFILE_ID_ARGUMENT_KEY = "STATE_FRAGMENT_PROFILE_ID_AR const val STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY = "STATE_FRAGMENT_TOPIC_ID_ARGUMENT_KEY" const val STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY = "STATE_FRAGMENT_STORY_ID_ARGUMENT_KEY" const val STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY = "STATE_FRAGMENT_EXPLORATION_ID_ARGUMENT_KEY" -const val STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY = "STATE_FRAGMENT_EXPLORATION_IS_FROM_WALKTHROUH_ARGUMENT_KEY" private const val TAG_AUDIO_FRAGMENT = "AUDIO_FRAGMENT" /** The presenter for [StateFragment]. */ @@ -60,7 +56,6 @@ class StateFragmentPresenter @Inject constructor( private val viewModelProvider: ViewModelProvider, private val explorationProgressController: ExplorationProgressController, private val storyProgressController: StoryProgressController, - private val topicListController: TopicListController, private val logger: ConsoleLogger, @DefaultResourceBucketName private val resourceBucketName: String, private val assemblerBuilderFactory: StatePlayerRecyclerViewAssembler.Builder.Factory, @@ -75,7 +70,6 @@ class StateFragmentPresenter @Inject constructor( private lateinit var topicId: String private lateinit var storyId: String private lateinit var explorationId: String - private var isFromWalkthrough: Boolean = false private lateinit var currentStateName: String private lateinit var binding: StateFragmentBinding private lateinit var recyclerViewAdapter: RecyclerView.Adapter<*> @@ -94,14 +88,12 @@ class StateFragmentPresenter @Inject constructor( internalProfileId: Int, topicId: String, storyId: String, - explorationId: String, - isFromWalkthrough: Boolean + explorationId: String ): View? { profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() this.topicId = topicId this.storyId = storyId this.explorationId = explorationId - this.isFromWalkthrough = isFromWalkthrough binding = StateFragmentBinding.inflate( inflater, @@ -149,7 +141,7 @@ class StateFragmentPresenter @Inject constructor( } subscribeToCurrentState() - subscribeToWalkthroughData() + markExplorationAsRecentlyPlayed() return binding.root } @@ -510,58 +502,23 @@ class StateFragmentPresenter @Inject constructor( } } - private val walkthroughResultLiveData: - LiveData> - by lazy { - topicListController.getWalkthroughData(profileId).toLiveData() - } - private fun getAssumedSuccessfulWalkthroughData(): LiveData { - // If there's an error loading the data, assume the default. - return Transformations.map(walkthroughResultLiveData) { - it.getOrDefault( - Walkthrough.getDefaultInstance() - ) - } - } - - private fun subscribeToWalkthroughData() { - getAssumedSuccessfulWalkthroughData().observe( - fragment, - Observer { - if(it.topicId == topicId){ - isFromWalkthrough = true - - Log.d("topic state T=", "==" +it.topicId +" == " + topicId ) - }else{ - Log.d("topic state F=", "==" +it.topicId +" == " + topicId ) - isFromWalkthrough = false - } - markExplorationAsRecentlyPlayed() - } - ) - } - private fun markExplorationAsRecentlyPlayed() { - Log.d("topicplay=", "==" +topicId+" "+ storyId+" "+explorationId) - storyProgressController.recordRecentlyPlayedChapter( - profileId, - topicId, - storyId, - explorationId, - Date().time, - isFromWalkthrough) + storyProgressController.recordRecentlyPlayedChapter( + profileId, + topicId, + storyId, + explorationId, + Date().time + ) } private fun markExplorationCompleted() { - - Log.d("topicplaycom=", "==" +topicId+" "+ storyId+" "+explorationId) storyProgressController.recordCompletedChapter( profileId, topicId, storyId, explorationId, - Date().time, - isFromWalkthrough + Date().time ) } } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt index 5c6c5f8c7b0..8e62c6f3974 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/WalkthroughActivity.kt @@ -4,15 +4,10 @@ import android.content.Context import android.content.Intent import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity -import org.oppia.android.app.home.RouteToExplorationListener -import org.oppia.android.app.home.RouteToTopicListener -import org.oppia.android.app.player.exploration.ExplorationActivity -import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject /** Activity that contains the walkthrough flow for users. */ -class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentChangeListener, - RouteToExplorationListener { +class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentChangeListener { @Inject lateinit var walkthroughActivityPresenter: WalkthroughActivityPresenter @@ -31,28 +26,6 @@ class WalkthroughActivity : InjectableAppCompatActivity(), WalkthroughFragmentCh walkthroughActivityPresenter.changePage(walkthroughPage) } - override fun routeToExploration( - internalProfileId: Int, - topicId: String, - storyId: String, - explorationId: String, - backflowScreen: Int? - ) { - startActivity( - ExplorationActivity.createExplorationActivityIntent( - this, - internalProfileId, - topicId, - storyId, - explorationId, - backflowScreen, - isFromWalkthrough = true - ) - ) - finish() - } - - override fun onBackPressed() { walkthroughActivityPresenter.handleSystemBack() } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt index 15880161d4f..c21ea4e030f 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughEndPageChanger.kt @@ -4,5 +4,4 @@ package org.oppia.android.app.walkthrough.end interface WalkthroughEndPageChanger { fun goBack() - fun goToTopicsPage() } diff --git a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt index 12392ae2bfc..2a0189200c4 100644 --- a/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/walkthrough/end/WalkthroughFinalFragmentPresenter.kt @@ -10,21 +10,14 @@ import androidx.lifecycle.Observer import androidx.lifecycle.Transformations import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.RouteToExplorationListener import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.Topic -import org.oppia.android.app.model.Walkthrough import org.oppia.android.app.walkthrough.WalkthroughActivity -import org.oppia.android.app.walkthrough.WalkthroughFragmentChangeListener -import org.oppia.android.app.walkthrough.WalkthroughPages import org.oppia.android.databinding.WalkthroughFinalFragmentBinding -import org.oppia.android.domain.exploration.ExplorationDataController -import org.oppia.android.domain.topic.StoryProgressController import org.oppia.android.domain.topic.TopicController import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProviders.Companion.toLiveData import org.oppia.android.util.logging.ConsoleLogger -import java.util.* import javax.inject.Inject /** The presenter for [WalkthroughFinalFragment]. */ @@ -33,19 +26,13 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( private val activity: AppCompatActivity, private val fragment: Fragment, private val logger: ConsoleLogger, - private val explorationDataController: ExplorationDataController, - private val topicController: TopicController, - private val storyProgressController: StoryProgressController + private val topicController: TopicController ) : WalkthroughEndPageChanger { private lateinit var binding: WalkthroughFinalFragmentBinding private lateinit var walkthroughFinalViewModel: WalkthroughFinalViewModel - private val routeToExploration = activity as RouteToExplorationListener - private var internalProfileId: Int = -1 private lateinit var topicId: String private lateinit var profileId: ProfileId private lateinit var topicName: String - private lateinit var storyId: String - private lateinit var explorationId: String fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?, topicId: String): View? { binding = @@ -55,7 +42,7 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( /* attachToRoot= */ false ) this.topicId = topicId - internalProfileId = activity.intent.getIntExtra( + val internalProfileId = activity.intent.getIntExtra( WalkthroughActivity.WALKTHROUGH_ACTIVITY_INTERNAL_PROFILE_ID_KEY, -1 ) @@ -79,8 +66,6 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( activity, Observer { result -> topicName = result.name - storyId = result.storyList[0].storyId - explorationId = result.storyList[0].chapterList[0].explorationId setTopicName() } ) @@ -119,36 +104,4 @@ class WalkthroughFinalFragmentPresenter @Inject constructor( override fun goBack() { activity.onBackPressed() } - - override fun goToTopicsPage() { - explorationDataController.startPlayingExploration( - explorationId - ).observe( - fragment, - Observer> { result -> - when { - result.isPending() -> logger.d("WalkthroughFinalFragment", "Loading exploration") - result.isFailure() -> logger.e( - "WalkthroughFinalFragment", - "Failed to load exploration", - result.getErrorOrNull()!! - ) - else -> { - logger.d("WalkthroughFinalFragment", "Successfully loaded exploration") - getTopic() - storyProgressController.recordRecentlyPlayedChapter(profileId,topicId,storyId,explorationId, - Date().time, - isFromWalkthrough = true) - routeToExploration.routeToExploration( - internalProfileId, - topicId, - storyId, - explorationId, - 1 - ) - } - } - } - ) - } } diff --git a/app/src/main/res/layout-land/walkthrough_final_fragment.xml b/app/src/main/res/layout-land/walkthrough_final_fragment.xml index d9a9c4affcc..c23c0c09f82 100644 --- a/app/src/main/res/layout-land/walkthrough_final_fragment.xml +++ b/app/src/main/res/layout-land/walkthrough_final_fragment.xml @@ -79,7 +79,6 @@ android:layout_weight="1" android:background="?attr/selectableItemBackground" android:clickable="true" - android:onClick="@{(v) -> presenter.goToTopicsPage()}" android:focusable="true" app:cardCornerRadius="4dp" app:contentPadding="@dimen/walkthrough_final_fragment_card_content_padding"> diff --git a/app/src/main/res/layout/fraction_interaction_item.xml b/app/src/main/res/layout/fraction_interaction_item.xml index 5eeb801f244..e215fd8cfe1 100644 --- a/app/src/main/res/layout/fraction_interaction_item.xml +++ b/app/src/main/res/layout/fraction_interaction_item.xml @@ -28,11 +28,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/edit_text_background" - android:digits="0123456789/- " + android:digits="0123456789/-" android:fontFamily="sans-serif" android:hint="@{viewModel.hintText}" android:imeOptions="actionDone" - android:inputType="date" + android:inputType="text" android:longClickable="false" android:maxLength="200" android:minHeight="48dp" diff --git a/app/src/main/res/layout/walkthrough_final_fragment.xml b/app/src/main/res/layout/walkthrough_final_fragment.xml index 333fc3f4d1d..75d1ef649a9 100644 --- a/app/src/main/res/layout/walkthrough_final_fragment.xml +++ b/app/src/main/res/layout/walkthrough_final_fragment.xml @@ -84,7 +84,6 @@ android:layout_weight="1" android:background="?attr/selectableItemBackground" android:clickable="true" - android:onClick="@{(v) -> presenter.goToTopicsPage()}" android:focusable="true" app:cardCornerRadius="4dp" app:contentPadding="@dimen/walkthrough_final_fragment_card_content_padding"> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 6133a4b1243..afcaee0bac7 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -70,6 +70,7 @@ Write numbers with units here. Enable audio voiceover for this lesson. Recently-Played Stories + Last-Played Stories View All Played within the Last Week Played within the Last Month diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index c706869e6d8..abda9c898a2 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -1,6 +1,5 @@ package org.oppia.android.domain.topic -import android.util.Log import kotlinx.coroutines.Deferred import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.ChapterProgress @@ -8,7 +7,6 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicProgressDatabase -import org.oppia.android.app.model.Walkthrough import org.oppia.android.data.persistence.PersistentCacheStore import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider @@ -41,14 +39,11 @@ const val RATIOS_EXPLORATION_ID_3 = "tIoSb3HZFN6e" private const val CACHE_NAME = "topic_progress_database" private const val RETRIEVE_TOPIC_PROGRESS_LIST_DATA_PROVIDER_ID = "retrieve_topic_progress_list_data_provider_id" -private const val RETRIEVE_WALKTHROUGH_DATA_PROVIDER_ID = - "retrieve_walkthroug_data_provider_id" private const val RETRIEVE_TOPIC_PROGRESS_DATA_PROVIDER_ID = "retrieve_topic_progress_data_provider_id" private const val RETRIEVE_STORY_PROGRESS_DATA_PROVIDER_ID = "retrieve_story_progress_data_provider_id" private const val RECORD_COMPLETED_CHAPTER_PROVIDER_ID = "record_completed_chapter_provider_id" -private const val RECORD_WALKTROUGH_TOPIC_PROVIDER_ID = "record_walkthrough_topic_provider_id" private const val RECORD_RECENTLY_PLAYED_CHAPTER_PROVIDER_ID = "record_recently_played_chapter_provider_id" @@ -83,7 +78,6 @@ class StoryProgressController @Inject constructor( * @param storyId the ID corresponding to the story for which progress needs to be stored. * @param explorationId the chapter id which will marked as [ChapterPlayState.COMPLETED] * @param completionTimestamp the timestamp at the exploration was finished. - * @param isFromWalkthrough the boolean to be set false once exploration was finished. * @return a [DataProvider] that indicates the success/failure of this record progress operation. */ fun recordCompletedChapter( @@ -91,8 +85,7 @@ class StoryProgressController @Inject constructor( topicId: String, storyId: String, explorationId: String, - completionTimestamp: Long, - isFromWalkthrough: Boolean + completionTimestamp: Long ): DataProvider { val deferred = retrieveCacheStore(profileId).storeDataWithCustomChannelAsync( @@ -117,7 +110,7 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setIsFromWalkthrough(isFromWalkthrough) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -148,7 +141,6 @@ class StoryProgressController @Inject constructor( * @param explorationId the chapter id which will marked as [ChapterPlayState.NOT_STARTED] if it * has not been [ChapterPlayState.COMPLETED] already. * @param lastPlayedTimestamp the timestamp at which the exploration was last played. - * @param isFromWalkthrough the boolean to be set true if exploration was played from [WalkthroughActivity]. * @return a [DataProvider] that indicates the success/failure of this record progress operation. */ fun recordRecentlyPlayedChapter( @@ -156,14 +148,12 @@ class StoryProgressController @Inject constructor( topicId: String, storyId: String, explorationId: String, - lastPlayedTimestamp: Long, - isFromWalkthrough: Boolean + lastPlayedTimestamp: Long ): DataProvider { val deferred = retrieveCacheStore(profileId).storeDataWithCustomChannelAsync( updateInMemoryCache = true ) { topicProgressDatabase -> - val previousChapterProgress = topicProgressDatabase .topicProgressMap[topicId]?.storyProgressMap?.get(storyId)?.chapterProgressMap?.get( @@ -200,26 +190,17 @@ class StoryProgressController @Inject constructor( } storyProgressBuilder.putChapterProgress(explorationId, chapterProgressBuilder.build()) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setIsFromWalkthrough(isFromWalkthrough) + + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() - val topicDatabaseBuilder = topicProgressDatabase.toBuilder() - Log.d("topic WW =","=="+topicProgress.getIsFromWalkthrough()) - if (isFromWalkthrough) { - val walkthrough = Walkthrough.newBuilder() - .setExplorationId(explorationId) - .setTopicId(topicId) - .setProfileId(profileId) - .build() - topicDatabaseBuilder.putTopicProgress(topicId, topicProgress) - .setWalkthrough(walkthrough) - }else{ - topicDatabaseBuilder.putTopicProgress(topicId, topicProgress) - } + + val topicDatabaseBuilder = + topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) } @@ -242,16 +223,6 @@ class StoryProgressController @Inject constructor( } } - /** Returns topic selected in [WalkthroughActivity] [DataProvider] for a particular profile. */ - internal fun retrieveWalkthroughDataProvider( - profileId: ProfileId - ): DataProvider { - return retrieveCacheStore(profileId) - .transformAsync(RETRIEVE_WALKTHROUGH_DATA_PROVIDER_ID) { topicProgressDatabase -> - AsyncResult.success(topicProgressDatabase.walkthrough) - } - } - /** Returns a [TopicProgress] [DataProvider] for a specific topicId, per-profile basis. */ internal fun retrieveTopicProgressDataProvider( profileId: ProfileId, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index c05f98c926f..bae93039f53 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -32,8 +32,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -49,8 +48,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -66,8 +64,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordCompletedChapter( @@ -75,8 +72,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -92,8 +88,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordCompletedChapter( @@ -101,8 +96,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -121,8 +115,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordCompletedChapter( @@ -130,8 +123,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_1, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -147,8 +139,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordCompletedChapter( @@ -156,8 +147,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -176,8 +166,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -196,8 +185,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -217,8 +205,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordRecentlyPlayedChapter( @@ -226,8 +213,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp, - isFromWalkthrough = false + timestamp ) } @@ -247,8 +233,7 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordRecentlyPlayedChapter( @@ -256,8 +241,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false + timestamp ) storyProgressController.recordRecentlyPlayedChapter( @@ -265,8 +249,7 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - timestamp, - isFromWalkthrough = false + timestamp ) } } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index e38e7caa9cf..7d09934829d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -18,7 +18,6 @@ import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicSummary -import org.oppia.android.app.model.Walkthrough import org.oppia.android.domain.util.JsonAssetRetriever import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider @@ -72,8 +71,6 @@ val EXPLORATION_THUMBNAILS = mapOf( private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" -private const val WALKTHROUGH_PROVIDER_ID = - "walkthrough_provider_id" private val EVICTION_TIME_MILLIS = TimeUnit.DAYS.toMillis(1) @@ -117,13 +114,6 @@ class TopicListController @Inject constructor( } } - fun getWalkthroughData(profileId: ProfileId): DataProvider { - return storyProgressController.retrieveWalkthroughDataProvider(profileId) - .transformAsync(WALKTHROUGH_PROVIDER_ID) { - AsyncResult.success(it) - } - } - private fun createTopicList(): TopicList { val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! @@ -177,20 +167,19 @@ class TopicListController @Inject constructor( val ongoingStoryListBuilder = OngoingStoryList.newBuilder() if (topicProgressList.size!=0) { + if (topicProgressList.size==1) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setRecommended(true) + ) + ongoingStoryListBuilder.addAllRecommendedStory( + createRecommendedStoryList( + topicProgressList + )) + + } else { topicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - Log.d("topic Walkthrough=", "==" + topicProgress.isFromWalkthrough) - if (topicProgress.isFromWalkthrough && topicProgressList.size == 1) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setRecommended(true) - ) - ongoingStoryListBuilder.addAllRecommendedStory( - createRecommendedStoryList( - topicProgressList - ) - ) - } else { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecentlyPlayed(true) ) @@ -269,34 +258,49 @@ class TopicListController @Inject constructor( } } } - } - } - - if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setRecommended(true) - ) - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") - for (j in 0 until topicIdJsonArray.length()) { - val found = topicProgressList.any { it.topicId == topicIdJsonArray[j] } - if (!found && ongoingStoryListBuilder.recommendedStoryList.size<3) { - Log.d("topic =", " not" + " " + topicIdJsonArray[j]) - ongoingStoryListBuilder.addRecommendedStory( - createRecommendedStoryFromAssets( - topicIdJsonArray[j].toString() - ) + if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0 || topicProgressList.size==1) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setRecommended(true) + ) + ongoingStoryListBuilder.addAllRecommendedStory( + createRecommendedStoryList( + topicProgressList + )) +// val topicIdJsonArray = jsonAssetRetriever +// .loadJsonFromAsset("topics.json")!! +// .getJSONArray("topic_id_list") +// for (j in 0 until topicIdJsonArray.length()) { +// val found = topicProgressList.any { it.topicId == topicIdJsonArray[j] } +// if (!found && ongoingStoryListBuilder.recommendedStoryList.size<3) { +// Log.d("topic =", " not" + " " + topicIdJsonArray[j]) +// ongoingStoryListBuilder.addRecommendedStory( +// createRecommendedStoryFromAssets( +// topicIdJsonArray[j].toString() +// ) +// ) +// } +// } + if (ongoingStoryListBuilder.recommendedStoryCount == 0) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setComingSoon(true) ) + Log.d("topic =", " coming" + " " + "soon") } +// if ( topicProgressList.size == 1) { +// ongoingStoryListBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setRecommended(true) +// ) +// ongoingStoryListBuilder.addAllRecommendedStory( +// createRecommendedStoryList( +// topicProgressList +// ) +// ) } - if (ongoingStoryListBuilder.recommendedStoryCount == 0) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setComingSoon(true) - ) - Log.d("topic =", " coming" + " " + "soon") } } + + +// } } return ongoingStoryListBuilder.build() } @@ -387,23 +391,18 @@ class TopicListController @Inject constructor( } } } -// storyProgressController.recordRecentlyPlayedChapter( -// profileId, -// topicProgress.topicId, -// storyId, -// lastCompletedChapterProgress.explorationId, -// Date().time, -// isFromWalkthrough = false) -// } -// + val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") for (i in 0 until topicIdJsonArray.length()) { - if (topicProgress.topicId != topicIdJsonArray[i] && recommendedStories.size<3) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())) + if (topicProgress.topicId == topicIdJsonArray[i] && topicIdJsonArray[i + 1] != null) { + Log.d("topicpos "," "+topicProgress.topicId +" = "+topicIdJsonArray[i] + " "+topicIdJsonArray[i + 1] ) + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i + 1].toString())) + return recommendedStories } + } } } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt index 34de3227f6c..c5fe05ad722 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressControllerTest.kt @@ -91,8 +91,7 @@ class StoryProgressControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - false + timestamp ).toLiveData().observeForever(mockRecordProgressObserver) testCoroutineDispatchers.runCurrent() @@ -106,23 +105,7 @@ class StoryProgressControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = false - ).toLiveData().observeForever(mockRecordProgressObserver) - testCoroutineDispatchers.runCurrent() - - verifyRecordProgressSucceeded() - } - - @Test - fun testStoryProgressController_recordRecentlyPlayedChapterFromWalkthrough_isSuccessful() { - storyProgressController.recordRecentlyPlayedChapter( - profileId, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - timestamp, - isFromWalkthrough = true + timestamp ).toLiveData().observeForever(mockRecordProgressObserver) testCoroutineDispatchers.runCurrent() diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 70e063fbb69..84a8701e549 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -245,8 +245,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -262,14 +261,13 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecommendedStoryList_markChapterCompletedFracStory0Exp0_fromWalkthrough_recommendedStoryListIsCorrect() { + fun testRetrieveRecommendedStoryList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -286,14 +284,13 @@ class TopicListControllerTest { @Test @Ignore("Failing on Circle CI.") - fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_isFromWalkthrough_recommendedStoryListIsCorrect() { + fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - isFromWalkthrough = true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -309,14 +306,13 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_fromWalkthrough_recommendedListCorrect() { + fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recommendedListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -325,8 +321,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - isFromWalkthrough = true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -348,8 +343,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -358,8 +352,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -381,8 +374,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -391,8 +383,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - true + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -401,8 +392,7 @@ class TopicListControllerTest { TEST_TOPIC_ID_0, TEST_STORY_ID_0, TEST_EXPLORATION_ID_2, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -425,8 +415,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -448,8 +437,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -458,8 +446,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -482,8 +469,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -492,8 +478,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -515,8 +500,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -525,8 +509,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -549,8 +532,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -559,8 +541,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp(), - isFromWalkthrough = false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -583,8 +564,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -593,8 +573,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -603,8 +582,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -628,8 +606,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -638,8 +615,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -661,8 +637,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -671,8 +646,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -681,8 +655,7 @@ class TopicListControllerTest { TEST_TOPIC_ID_0, TEST_STORY_ID_0, TEST_EXPLORATION_ID_2, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() storyProgressController.recordCompletedChapter( @@ -690,8 +663,7 @@ class TopicListControllerTest { TEST_TOPIC_ID_0, TEST_STORY_ID_0, TEST_EXPLORATION_ID_5, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -700,8 +672,7 @@ class TopicListControllerTest { TEST_TOPIC_ID_1, TEST_STORY_ID_2, TEST_EXPLORATION_ID_4, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -711,8 +682,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -721,8 +691,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_1, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -750,8 +719,7 @@ class TopicListControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - getOldTimestamp(), - false + getOldTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -760,8 +728,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - getOldTimestamp(), - false + getOldTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -770,8 +737,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp(), - false + getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index b5eea46d5ea..6e72ce7e586 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -162,18 +162,6 @@ message OngoingStoryList { PromotedStoriesType promoted_stories_type = 5; } -// Corresponds to the Walkthrough. When a user explores a topic through a walkthrough page. -message Walkthrough { - // The ID of the profile. - ProfileId profile_id = 1; - - // The ID of the exploration being played. - string exploration_id = 2; - - // The ID of the topic being played. - string topic_id = 3; -} - // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, // or because they have completed all other lessons and may find this one interesting. message PromotedStory { @@ -246,9 +234,6 @@ enum ChapterPlayState { message TopicProgressDatabase { // Map from topic ID to TopicProgress. map topic_progress = 1; - - // The topic that was selected through walkthrough - Walkthrough walkthrough = 2; } // Represents the topic progress. @@ -256,9 +241,6 @@ message TopicProgress { // The ID corresponding to the topic. string topic_id = 1; - // Preference on whether user launched topic from walkthrough - bool isFromWalkthrough = 2; - // Map from story ID to StoryProgress. map story_progress = 3; @@ -274,11 +256,14 @@ message PromotedStoriesType { // Indicates recently played topics from the topic list. bool recently_played = 1; + // Indicates last played topics more than a week ago from the topic list. + bool last_played = 2; + // Indicates recommended from the topic list. - bool recommended = 2; + bool recommended = 3; // Indicates coming soon topics. - bool coming_soon = 3; + bool coming_soon = 4; } } // Represents the story progress. From 45b946240d7b4fbff529b02c613fd9b3b381d0af Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 08:25:30 -0800 Subject: [PATCH 036/248] Use promoted story list for itemCount --- .../main/res/layout-sw600dp-port/promoted_story_list.xml | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 540321da8b1..d3956619a5c 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -9,10 +9,6 @@ - - From 41d3af477b6d1e375061ab4628096eb5e7bd20f6 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 09:32:46 -0800 Subject: [PATCH 037/248] Bind list of ChapterSummaryViewModel instead of ChapterSummary to fix lesson crash --- app/src/main/res/layout-land/topic_lessons_story_summary.xml | 2 +- .../res/layout-sw600dp-land/topic_lessons_story_summary.xml | 2 +- .../res/layout-sw600dp-port/topic_lessons_story_summary.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/res/layout-land/topic_lessons_story_summary.xml b/app/src/main/res/layout-land/topic_lessons_story_summary.xml index bd2c48d08bc..386e7927d94 100644 --- a/app/src/main/res/layout-land/topic_lessons_story_summary.xml +++ b/app/src/main/res/layout-land/topic_lessons_story_summary.xml @@ -164,7 +164,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="8dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:list="@{viewModel.storySummary.chapterList}" /> + app:list="@{viewModel.chapterSummaryItemList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/topic_lessons_story_summary.xml b/app/src/main/res/layout-sw600dp-land/topic_lessons_story_summary.xml index af1043ccf3d..5b0ca3727c4 100644 --- a/app/src/main/res/layout-sw600dp-land/topic_lessons_story_summary.xml +++ b/app/src/main/res/layout-sw600dp-land/topic_lessons_story_summary.xml @@ -167,7 +167,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="8dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:list="@{viewModel.storySummary.chapterList}" /> + app:list="@{viewModel.chapterSummaryItemList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/topic_lessons_story_summary.xml b/app/src/main/res/layout-sw600dp-port/topic_lessons_story_summary.xml index 68d9cd46fae..33978ea6380 100644 --- a/app/src/main/res/layout-sw600dp-port/topic_lessons_story_summary.xml +++ b/app/src/main/res/layout-sw600dp-port/topic_lessons_story_summary.xml @@ -167,7 +167,7 @@ android:layout_marginTop="8dp" android:layout_marginBottom="8dp" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:list="@{viewModel.storySummary.chapterList}" /> + app:list="@{viewModel.chapterSummaryItemList}" /> From 14fb58cbd6e218fdf17b2b10847680e6f7b37ed1 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 09:40:49 -0800 Subject: [PATCH 038/248] Fix linter errors & remove PromotedStoryListAdapter --- .../android/app/home/HomeFragmentPresenter.kt | 3 +- .../android/app/home/HomeItemViewModel.kt | 4 +- .../oppia/android/app/home/HomeViewModel.kt | 28 ++++++--- .../android/app/home/WelcomeViewModel.kt | 4 +- .../app/home/topiclist/AllTopicsViewModel.kt | 3 +- .../topiclist/PromotedStoryListAdapter.kt | 61 ------------------- .../home/topiclist/PromotedStoryListView.kt | 2 +- .../topiclist/PromotedStoryListViewModel.kt | 1 - .../home/topiclist/TopicSummaryViewModel.kt | 21 ++++--- .../main/res/layout/promoted_story_list.xml | 14 ++--- 10 files changed, 42 insertions(+), 99 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt 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 d1630f73762..0ff1d174646 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 @@ -13,15 +13,14 @@ import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog -import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.databinding.AllTopicsBinding +import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.databinding.PromotedStoryListBinding import org.oppia.android.databinding.TopicSummaryViewBinding import org.oppia.android.databinding.WelcomeBinding -import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.domain.oppialogger.OppiaLogger import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController diff --git a/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt index 31b06c5bd41..4cd6675658d 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt @@ -3,6 +3,4 @@ package org.oppia.android.app.home import org.oppia.android.app.viewmodel.ObservableViewModel /** The root [ViewModel] for all individual items that may be displayed in home fragment recycler view. */ -abstract class HomeItemViewModel : ObservableViewModel() { - -} +abstract class HomeItemViewModel : ObservableViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index cce3e0101ee..60c6ca2364a 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -45,9 +45,9 @@ class HomeViewModel @Inject constructor( private val topicListController: TopicListController, @TopicHtmlParserEntityType private val topicEntityType: String, @StoryHtmlParserEntityType private val storyEntityType: String - ) : ObservableViewModel() { +) : ObservableViewModel() { - private val profileId : ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) private val profileDataProvider: DataProvider by lazy { @@ -70,12 +70,19 @@ class HomeViewModel @Inject constructor( // be pending or failed. profileDataProvider.combineWith( ongoingStoryListSummaryDataProvider, - PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID) { profile, ongoingStoryList -> - listOfNotNull(computeWelcomeViewModel(profile), computePromotedStoryListViewModel(ongoingStoryList)) + PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID + ) { profile, ongoingStoryList -> + listOfNotNull( + computeWelcomeViewModel(profile), + computePromotedStoryListViewModel(ongoingStoryList) + ) }.combineWith( topicListSummaryDataProvider, - HOME_FRAGMENT_COMBINED_PROVIDER_ID) { homeItemViewModelList, topicList -> - homeItemViewModelList + listOf(AllTopicsViewModel()) + computeTopicSummaryItemViewModelList(topicList) + HOME_FRAGMENT_COMBINED_PROVIDER_ID + ) { homeItemViewModelList, topicList -> + homeItemViewModelList + listOf(AllTopicsViewModel()) + computeTopicSummaryItemViewModelList( + topicList + ) } } @@ -83,8 +90,9 @@ class HomeViewModel @Inject constructor( val homeItemViewModelListLiveData: LiveData> by lazy { Transformations.map(homeItemViewModelListDataProvider.toLiveData()) { itemListResult -> if (itemListResult.isFailure()) { - logger.e("HomeFragment", - "Failed to retrieve fragment", + logger.e( + "HomeFragment", + "Failed to retrieve fragment", itemListResult.getErrorOrNull() ) } @@ -92,7 +100,7 @@ class HomeViewModel @Inject constructor( } } - private fun computeWelcomeViewModel(profile: Profile) : HomeItemViewModel? { + private fun computeWelcomeViewModel(profile: Profile): HomeItemViewModel? { return if (profile.name.isNotEmpty()) { WelcomeViewModel(fragment, oppiaClock, profile.name) } else null @@ -141,7 +149,7 @@ class HomeViewModel @Inject constructor( } } - private fun computeTopicSummaryItemViewModelList(topicList: TopicList) : List { + private fun computeTopicSummaryItemViewModelList(topicList: TopicList): List { return topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 888b845169b..56c5f01d92c 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -1,18 +1,16 @@ package org.oppia.android.app.home -import androidx.databinding.ObservableField import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel import org.oppia.android.util.datetime.DateTimeUtil import org.oppia.android.util.system.OppiaClock -import javax.inject.Inject /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel( fragment: Fragment, oppiaClock: OppiaClock, val profileName: String -): HomeItemViewModel() { +) : HomeItemViewModel() { val greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index ee21db72364..9f72123e392 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -5,5 +5,4 @@ import org.oppia.android.app.home.HomeItemViewModel import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel @Inject constructor () -: HomeItemViewModel() {} +class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() {} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt deleted file mode 100644 index 5bb705010ce..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListAdapter.kt +++ /dev/null @@ -1,61 +0,0 @@ -package org.oppia.android.app.home.topiclist - -import android.content.Context -import android.content.res.Configuration -import android.content.res.Resources -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.RecyclerView -import org.oppia.android.R -import org.oppia.android.databinding.PromotedStoryCardBinding - -/** Adapter to bind promoted stories to [RecyclerView] inside [HomeFragment] to create carousel. */ -class PromotedStoryListAdapter( - private val activity: AppCompatActivity, - private val itemList: List -) : - RecyclerView.Adapter() { - - private val orientation = Resources.getSystem().configuration.orientation - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val inflater = LayoutInflater.from(parent.context) - val binding = - PromotedStoryCardBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - return PromotedStoryViewHolder(binding) - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - (holder as PromotedStoryViewHolder).bind(itemList[position]) - } - - override fun getItemCount(): Int { - return itemList.size - } - - inner class PromotedStoryViewHolder( - val binding: PromotedStoryCardBinding - ) : RecyclerView.ViewHolder(binding.root) { - internal fun bind(promotedStoryViewModel: PromotedStoryViewModel) { - binding.viewModel = promotedStoryViewModel - val layoutParams = binding.promotedStoryCardContainer.layoutParams - layoutParams.width = // set layout width based on number of stories - if (itemCount > 1) { // this checks for the number of promoted stories? - if (orientation == Configuration.ORIENTATION_PORTRAIT) { - ViewGroup.LayoutParams.MATCH_PARENT - } else { - // set a different width only if it's landscape & there are multiple promoted stories - (activity as Context).resources.getDimensionPixelSize(R.dimen.promoted_story_card_width) - } - } else { - ViewGroup.LayoutParams.MATCH_PARENT - } - binding.promotedStoryCardContainer.layoutParams = layoutParams - } - } -} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt index acb1f57015f..d8645220599 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt @@ -11,7 +11,7 @@ import org.oppia.android.databinding.PromotedStoryCardBinding * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to * a fixed position on the device. */ -class PromotedStoryListView @JvmOverloads constructor ( +class PromotedStoryListView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt index 0580838be38..ae64a5f8ff2 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt @@ -6,7 +6,6 @@ import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.shim.IntentFactoryShim -import javax.inject.Inject /** [ViewModel] promoted story list in [HomeFragment]. */ class PromotedStoryListViewModel( diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 5cd73fdfaba..faafd8ec614 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -1,10 +1,8 @@ package org.oppia.android.app.home.topiclist -import android.content.Context import android.graphics.Color import androidx.annotation.ColorInt import androidx.appcompat.app.AppCompatActivity -import androidx.databinding.BindingAdapter import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary @@ -17,7 +15,7 @@ const val DARKEN_VALUE_MULTIPLIER: Float = 0.9f const val DARKEN_SATURATION_MULTIPLIER: Float = 1.2f /** The view model corresponding to individual topic summaries in the topic summary RecyclerView. */ -class TopicSummaryViewModel ( +class TopicSummaryViewModel( private val activity: AppCompatActivity, val topicSummary: TopicSummary, val entityType: String, @@ -26,18 +24,23 @@ class TopicSummaryViewModel ( ) : HomeItemViewModel() { val name: String = topicSummary.name val totalChapterCount: Int = topicSummary.totalChapterCount + @ColorInt val backgroundColor: Int = retrieveBackgroundColor() + @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() private val marginTopBottom = activity.resources - .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) + .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) private val marginMax by lazy { - activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) } + activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) + } private val marginMin by lazy { - activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) } + activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) + } private val spanCount by lazy { - activity.resources.getInteger(R.integer.home_span_count) } + activity.resources.getInteger(R.integer.home_span_count) + } /** Callback from data-binding for when the summary tile is clicked. */ fun clickOnSummaryTile() { @@ -48,7 +51,7 @@ class TopicSummaryViewModel ( return marginTopBottom } - fun computeBottomMargin(): Int { + fun computeBottomMargin(): Int { return marginTopBottom } @@ -64,7 +67,7 @@ class TopicSummaryViewModel ( when (position % spanCount) { 0 -> marginMax 1 -> marginMin - 2 -> 0 + 2 -> 0 else -> 0 } } diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 5b50ab0d97d..d7fde81f71a 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -38,11 +38,11 @@ android:id="@+id/view_all_text_view" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:minHeight="48dp" android:layout_marginStart="8dp" android:layout_marginEnd="28dp" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" + android:minHeight="48dp" android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" @@ -54,17 +54,17 @@ android:id="@+id/promoted_story_list_recycler_view" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clipToPadding="false" android:layout_marginTop="4dp" - android:overScrollMode="never" - android:scrollbars="none" + android:clipToPadding="false" android:orientation="horizontal" + android:overScrollMode="never" android:paddingStart="@{viewModel.paddingStart}" - android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" android:paddingTop="0dp" + android:paddingEnd="@{viewModel.promotedStoryList.size() > 1 ? viewModel.paddingEnd : viewModel.paddingStart}" android:paddingBottom="0dp" + android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:reverseLayout="false" - app:list="@{viewModel.promotedStoryList}" /> + app:list="@{viewModel.promotedStoryList}" + app:reverseLayout="false" /> From f090330b164688b23c5e26dfc8996a1cc895deb2 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 10:00:12 -0800 Subject: [PATCH 039/248] Add viewmodels to bazel build --- app/BUILD.bazel | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 294d200cad4..b248e94d657 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -122,6 +122,9 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/help/HelpItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpListViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt", + "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt", + "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt", + "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt", "src/main/java/org/oppia/android/app/parser/StringToFractionParser.kt", From 798bc4c8fd8319ee79e7e3862463625bc2fef4d2 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 10:04:06 -0800 Subject: [PATCH 040/248] Fix more linter errors --- .../main/java/org/oppia/android/app/home/HomeViewModel.kt | 6 +++--- .../oppia/android/app/home/topiclist/AllTopicsViewModel.kt | 2 +- .../android/app/home/topiclist/PromotedStoryViewModel.kt | 7 ------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 60c6ca2364a..cc831945716 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -54,8 +54,7 @@ class HomeViewModel @Inject constructor( profileManagementController.getProfile(profileId) } - private val ongoingStoryListSummaryDataProvider: DataProvider - by lazy { + private val ongoingStoryListSummaryDataProvider: DataProvider by lazy { topicListController.getOngoingStoryList(profileId) } @@ -106,7 +105,8 @@ class HomeViewModel @Inject constructor( } else null } - private fun computePromotedStoryListViewModel(ongoingStoryList: OngoingStoryList): HomeItemViewModel? { + private fun computePromotedStoryListViewModel(ongoingStoryList: OngoingStoryList) + : HomeItemViewModel? { val storyViewModelList = computePromotedStoryViewModelList(ongoingStoryList) return if (storyViewModelList.isNotEmpty()) { return PromotedStoryListViewModel( diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index 9f72123e392..d0a6488fc44 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -5,4 +5,4 @@ import org.oppia.android.app.home.HomeItemViewModel import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() {} +class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 7a15403db55..2253de4efe6 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -1,22 +1,15 @@ package org.oppia.android.app.home.topiclist -import android.content.Context import android.content.res.Configuration import android.content.res.Resources import android.view.ViewGroup -import android.view.animation.Transformation import androidx.appcompat.app.AppCompatActivity -import androidx.databinding.ObservableField -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel -import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel -import org.oppia.android.databinding.PromotedStoryCardBinding // TODO(#283): Add download status information to promoted-story-card. From 801d4e14a7759cc09f43411a189f7e91d8d780d8 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 10:04:06 -0800 Subject: [PATCH 041/248] Fix more linter errors --- .../java/org/oppia/android/app/home/HomeViewModel.kt | 11 ++++++----- .../android/app/home/topiclist/AllTopicsViewModel.kt | 2 +- .../app/home/topiclist/PromotedStoryViewModel.kt | 7 ------- 3 files changed, 7 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 60c6ca2364a..1357878cd9c 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -54,10 +54,9 @@ class HomeViewModel @Inject constructor( profileManagementController.getProfile(profileId) } - private val ongoingStoryListSummaryDataProvider: DataProvider - by lazy { - topicListController.getOngoingStoryList(profileId) - } + private val ongoingStoryListSummaryDataProvider: DataProvider by lazy { + topicListController.getOngoingStoryList(profileId) + } private val topicListSummaryDataProvider: DataProvider by lazy { // TODO: once #2253 is merged change this function call @@ -106,7 +105,9 @@ class HomeViewModel @Inject constructor( } else null } - private fun computePromotedStoryListViewModel(ongoingStoryList: OngoingStoryList): HomeItemViewModel? { + private fun computePromotedStoryListViewModel( + ongoingStoryList: OngoingStoryList + ): HomeItemViewModel? { val storyViewModelList = computePromotedStoryViewModelList(ongoingStoryList) return if (storyViewModelList.isNotEmpty()) { return PromotedStoryListViewModel( diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index 9f72123e392..d0a6488fc44 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -5,4 +5,4 @@ import org.oppia.android.app.home.HomeItemViewModel import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() {} +class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 7a15403db55..2253de4efe6 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -1,22 +1,15 @@ package org.oppia.android.app.home.topiclist -import android.content.Context import android.content.res.Configuration import android.content.res.Resources import android.view.ViewGroup -import android.view.animation.Transformation import androidx.appcompat.app.AppCompatActivity -import androidx.databinding.ObservableField -import androidx.lifecycle.LiveData -import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel -import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel -import org.oppia.android.databinding.PromotedStoryCardBinding // TODO(#283): Add download status information to promoted-story-card. From 7dd9fb0c5eee86fcf98cf777d8441e1b46721b20 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 10:17:42 -0800 Subject: [PATCH 042/248] Revert "Add viewmodels to bazel build" This reverts commit f090330b164688b23c5e26dfc8996a1cc895deb2. --- app/BUILD.bazel | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index b248e94d657..294d200cad4 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -122,9 +122,6 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/help/HelpItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpListViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt", "src/main/java/org/oppia/android/app/parser/StringToFractionParser.kt", From 02bba56e1041109408db252a8e7c4ce17835a919 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 16 Dec 2020 01:30:09 +0530 Subject: [PATCH 043/248] fixed recommended list --- .../domain/topic/TopicListController.kt | 72 +++++++------------ .../domain/topic/TopicControllerTest.kt | 12 ++-- .../domain/topic/TopicListControllerTest.kt | 2 +- 3 files changed, 32 insertions(+), 54 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 7d09934829d..a36e20681d5 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -109,7 +109,7 @@ class TopicListController @Inject constructor( fun getOngoingStoryList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { - val ongoingStoryList = createOngoingStoryListFromProgress(it, profileId) + val ongoingStoryList = createOngoingStoryListFromProgress(it) AsyncResult.success(ongoingStoryList) } } @@ -161,21 +161,21 @@ class TopicListController @Inject constructor( } private fun createOngoingStoryListFromProgress( - topicProgressList: List, - profileId: ProfileId + topicProgressList: List ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() - if (topicProgressList.size!=0) { + if (topicProgressList.isNotEmpty()) { + Log.d("topic size",""+topicProgressList.size) if (topicProgressList.size==1) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecommended(true) ) + Log.d("topic size = 1",""+topicProgressList.size) ongoingStoryListBuilder.addAllRecommendedStory( createRecommendedStoryList( topicProgressList )) - } else { topicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) @@ -185,7 +185,7 @@ class TopicListController @Inject constructor( ) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId - var story = topicController.retrieveStory(topic.topicId, storyId) + val story = topicController.retrieveStory(topic.topicId, storyId) Log.d("topic progress =", "" + topicProgress.topicId + storyId) val completedChapterProgressList = @@ -258,7 +258,10 @@ class TopicListController @Inject constructor( } } } - if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0 || topicProgressList.size==1) { + + } + + if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecommended(true) ) @@ -266,41 +269,14 @@ class TopicListController @Inject constructor( createRecommendedStoryList( topicProgressList )) -// val topicIdJsonArray = jsonAssetRetriever -// .loadJsonFromAsset("topics.json")!! -// .getJSONArray("topic_id_list") -// for (j in 0 until topicIdJsonArray.length()) { -// val found = topicProgressList.any { it.topicId == topicIdJsonArray[j] } -// if (!found && ongoingStoryListBuilder.recommendedStoryList.size<3) { -// Log.d("topic =", " not" + " " + topicIdJsonArray[j]) -// ongoingStoryListBuilder.addRecommendedStory( -// createRecommendedStoryFromAssets( -// topicIdJsonArray[j].toString() -// ) -// ) -// } -// } if (ongoingStoryListBuilder.recommendedStoryCount == 0) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setComingSoon(true) ) Log.d("topic =", " coming" + " " + "soon") } -// if ( topicProgressList.size == 1) { -// ongoingStoryListBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setRecommended(true) -// ) -// ongoingStoryListBuilder.addAllRecommendedStory( -// createRecommendedStoryList( -// topicProgressList -// ) -// ) - } } } - - -// } } return ongoingStoryListBuilder.build() } @@ -391,21 +367,27 @@ class TopicListController @Inject constructor( } } } + } + + } + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") - for (i in 0 until topicIdJsonArray.length()) { - if (topicProgress.topicId == topicIdJsonArray[i] && topicIdJsonArray[i + 1] != null) { - Log.d("topicpos "," "+topicProgress.topicId +" = "+topicIdJsonArray[i] + " "+topicIdJsonArray[i + 1] ) - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i + 1].toString())) - return recommendedStories - } + val topicList = ArrayList() + for (i in 0 until topicIdJsonArray.length()) { + topicList.add(topicIdJsonArray[i].toString()) + } - } - } + val index = topicList.indexOf(topicProgressList[topicProgressList.size-1].topicId) + Log.d("topic index", " = " + " " + index +" "+topicProgressList[topicProgressList.size-1].topicId) + Log.d("topic index", " = " + " " + topicIdJsonArray.length()) + if ( topicIdJsonArray[index + 1] != null && topicIdJsonArray.length() > (index+1) ) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) + return recommendedStories } + return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt index f5cb58782ed..ff319aa5406 100755 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt @@ -1148,8 +1148,7 @@ class TopicControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_0, - currentTimestamp, - false + currentTimestamp ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1159,8 +1158,7 @@ class TopicControllerTest { FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, FRACTIONS_EXPLORATION_ID_1, - currentTimestamp, - false + currentTimestamp ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1170,8 +1168,7 @@ class TopicControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_0, - currentTimestamp, - false + currentTimestamp ).toLiveData().observeForever(mockRecordProgressObserver) } @@ -1181,8 +1178,7 @@ class TopicControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, RATIOS_EXPLORATION_ID_1, - currentTimestamp, - false + currentTimestamp ).toLiveData().observeForever(mockRecordProgressObserver) } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 84a8701e549..59aed82822f 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -431,7 +431,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_RecentStoryListCorrect() { + fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recentStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, From b9b226b1a3b12d35e0181b5b5e149d807b299f37 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 12:23:51 -0800 Subject: [PATCH 044/248] Apply test changes from #2253 --- .../oppia/android/app/home/HomeActivityTest.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) 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 d8093e8b87f..81c3aea9dff 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 @@ -240,6 +240,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysRecentlyPlayedStoriesText() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(1) ) @@ -260,6 +261,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysViewAllText() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(1) ) @@ -274,6 +276,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_clickViewAll_opensRecentlyPlayedActivity() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(1) ) @@ -372,6 +375,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex3_topicSummary_topicNameIsCorrect() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(3) ) @@ -386,6 +390,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex3_topicSummary_lessonCountIsCorrect() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(3) ) @@ -405,6 +410,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex4_topicSummary_topicNameIsCorrect() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(4) ) @@ -419,6 +425,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex4_topicSummary_lessonCountIsCorrect() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(4) ) @@ -438,6 +445,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex4_topicSummary_configurationChange_lessonCountIsCorrect() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(4) @@ -458,6 +466,7 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex3_clickTopicSummary_opensTopicActivity() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( scrollToPosition(3) ) @@ -470,6 +479,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_showsExitToProfileChooserDialog() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() pressBack() onView(withText(R.string.home_activity_back_dialog_message)) .inRoot(isDialog()) @@ -480,6 +490,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_orientationChange_showsExitToProfileChooserDialog() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() pressBack() onView(isRoot()).perform(orientationLandscape()) onView(withText(R.string.home_activity_back_dialog_message)) @@ -491,6 +502,7 @@ class HomeActivityTest { @Test fun testHomeActivity_onBackPressed_clickExit_checkOpensProfileActivity() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() pressBack() onView(withText(R.string.home_activity_back_dialog_exit)) .inRoot(isDialog()) @@ -502,6 +514,7 @@ class HomeActivityTest { @Test fun testHomeActivity_checkSpanForItem0_spanSizeIsTwoOrThree() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() if (context.resources.getBoolean(R.bool.isTablet)) { onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(3, 0)) } else { @@ -513,6 +526,7 @@ class HomeActivityTest { @Test fun testHomeActivity_checkSpanForItem4_spanSizeIsOne() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(1, 4)) } } @@ -520,6 +534,7 @@ class HomeActivityTest { @Test fun testHomeActivity_configurationChange_checkSpanForItem4_spanSizeIsOne() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(isRoot()).perform(orientationLandscape()) onView(withId(R.id.home_recycler_view)).check(hasGridItemCount(1, 4)) } From 0097bfa93cc9a313b25435affd566d316d596874 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 16:29:41 -0800 Subject: [PATCH 045/248] Address review comments --- .../app/databinding/ViewBindingAdapters.java | 8 +- .../android/app/home/HomeFragmentPresenter.kt | 26 +++--- .../oppia/android/app/home/HomeViewModel.kt | 89 +++++++++++-------- .../android/app/home/WelcomeViewModel.kt | 2 + .../PromotedStoryListView.kt | 5 +- .../PromotedStoryListViewModel.kt | 26 ++++-- .../PromotedStoryViewModel.kt | 11 ++- .../app/home/topiclist/AllTopicsViewModel.kt | 2 +- .../res/layout-land/promoted_story_card.xml | 2 +- .../res/layout-land/promoted_story_list.xml | 11 +-- .../promoted_story_card.xml | 2 +- .../promoted_story_list.xml | 11 +-- .../promoted_story_card.xml | 2 +- .../promoted_story_list.xml | 17 ++-- .../main/res/layout/promoted_story_card.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 13 ++- 16 files changed, 131 insertions(+), 98 deletions(-) rename app/src/main/java/org/oppia/android/app/home/{topiclist => promotedlist}/PromotedStoryListView.kt (90%) rename app/src/main/java/org/oppia/android/app/home/{topiclist => promotedlist}/PromotedStoryListViewModel.kt (56%) rename app/src/main/java/org/oppia/android/app/home/{topiclist => promotedlist}/PromotedStoryViewModel.kt (79%) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 9ae2bee2907..6f9e967e919 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -12,7 +12,9 @@ public final class ViewBindingAdapters { /** - * BindingAdapter to set the height of a View. + * BindingAdapter to set the height of a View. If this value is calculated in data fetching, the + * layout will require a default value since data fetching is not immediately evaluated with + * view layouts and measurements. */ @BindingAdapter("android:layout_height") public static void setLayoutHeight(@NonNull View view, float height) { @@ -22,7 +24,9 @@ public static void setLayoutHeight(@NonNull View view, float height) { } /** - * BindingAdapter to set the width of a View. + * BindingAdapter to set the width of a View. If this value is calculated in data fetching, the + * layout will require a default value since data fetching is not immediately evaluated with + * view layouts and measurements. */ @BindingAdapter("android:layout_width") public static void setLayoutWidth(@NonNull View view, float width) { 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 0ff1d174646..fdc72e4c3d2 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 @@ -10,7 +10,7 @@ import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel +import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.TopicSummary @@ -98,33 +98,33 @@ class HomeFragmentPresenter @Inject constructor( return BindableAdapter.MultiTypeBuilder .newBuilder { viewModel -> when (viewModel) { - is WelcomeViewModel -> ViewType.VIEW_TYPE_WELCOME_MESSAGE - is PromotedStoryListViewModel -> ViewType.VIEW_TYPE_PROMOTED_STORY_LIST - is AllTopicsViewModel -> ViewType.VIEW_TYPE_ALL_TOPICS - is TopicSummaryViewModel -> ViewType.VIEW_TYPE_TOPIC_LIST + is WelcomeViewModel -> ViewType.WELCOME_MESSAGE + is PromotedStoryListViewModel -> ViewType.PROMOTED_STORY_LIST + is AllTopicsViewModel -> ViewType.ALL_TOPICS + is TopicSummaryViewModel -> ViewType.TOPIC_LIST else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") } } .registerViewDataBinder( - viewType = ViewType.VIEW_TYPE_WELCOME_MESSAGE, + viewType = ViewType.WELCOME_MESSAGE, inflateDataBinding = WelcomeBinding::inflate, setViewModel = WelcomeBinding::setViewModel, transformViewModel = { it as WelcomeViewModel } ) .registerViewDataBinder( - viewType = ViewType.VIEW_TYPE_PROMOTED_STORY_LIST, + viewType = ViewType.PROMOTED_STORY_LIST, inflateDataBinding = PromotedStoryListBinding::inflate, setViewModel = PromotedStoryListBinding::setViewModel, transformViewModel = { it as PromotedStoryListViewModel } ) .registerViewDataBinder( - viewType = ViewType.VIEW_TYPE_ALL_TOPICS, + viewType = ViewType.ALL_TOPICS, inflateDataBinding = AllTopicsBinding::inflate, setViewModel = AllTopicsBinding::setViewModel, transformViewModel = { it as AllTopicsViewModel } ) .registerViewDataBinder( - viewType = ViewType.VIEW_TYPE_TOPIC_LIST, + viewType = ViewType.TOPIC_LIST, inflateDataBinding = TopicSummaryViewBinding::inflate, setViewModel = TopicSummaryViewBinding::setViewModel, transformViewModel = { it as TopicSummaryViewModel } @@ -133,10 +133,10 @@ class HomeFragmentPresenter @Inject constructor( } private enum class ViewType { - VIEW_TYPE_WELCOME_MESSAGE, - VIEW_TYPE_PROMOTED_STORY_LIST, - VIEW_TYPE_ALL_TOPICS, - VIEW_TYPE_TOPIC_LIST + WELCOME_MESSAGE, + PROMOTED_STORY_LIST, + ALL_TOPICS, + TOPIC_LIST } fun onTopicSummaryClicked(topicSummary: TopicSummary) { diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 1357878cd9c..c5f60647014 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -8,8 +8,8 @@ import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel -import org.oppia.android.app.home.topiclist.PromotedStoryViewModel +import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel +import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.OngoingStoryList @@ -27,14 +27,13 @@ import org.oppia.android.util.logging.ConsoleLogger import org.oppia.android.util.parser.StoryHtmlParserEntityType import org.oppia.android.util.parser.TopicHtmlParserEntityType import org.oppia.android.util.system.OppiaClock -import javax.inject.Inject private const val PROFILE_AND_ONGOING_STORY_COMBINED_PROVIDER_ID = "profile+ongoingStoryList" private const val HOME_FRAGMENT_COMBINED_PROVIDER_ID = "profile+ongoingStoryList+topicListProvider" /** [ViewModel] for layouts in home fragment . */ @FragmentScope -class HomeViewModel @Inject constructor( +class HomeViewModel( private val activity: AppCompatActivity, private val fragment: Fragment, private val oppiaClock: OppiaClock, @@ -48,7 +47,7 @@ class HomeViewModel @Inject constructor( ) : ObservableViewModel() { private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - private val limit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + private val promotedStoryListLimit = activity.resources.getInteger(R.integer.promoted_story_list_limit) private val profileDataProvider: DataProvider by lazy { profileManagementController.getProfile(profileId) @@ -79,19 +78,26 @@ class HomeViewModel @Inject constructor( topicListSummaryDataProvider, HOME_FRAGMENT_COMBINED_PROVIDER_ID ) { homeItemViewModelList, topicList -> - homeItemViewModelList + listOf(AllTopicsViewModel()) + computeTopicSummaryItemViewModelList( - topicList - ) + computeAllTopicsItemsViewModelList(topicList).let { + if (it != null) { + homeItemViewModelList + it + } else { + homeItemViewModelList + } + } } } - // Resulting LiveData to bind to the outer RecyclerView & that contains all ViewModels. + /** + * [LiveData] of the list of items displayed in the HomeFragment RecyclerView. The list backing this live data will + * automatically update if constituent parts of the UI change (e.g. if the promoted story list changes). + * */ val homeItemViewModelListLiveData: LiveData> by lazy { Transformations.map(homeItemViewModelListDataProvider.toLiveData()) { itemListResult -> if (itemListResult.isFailure()) { logger.e( "HomeFragment", - "Failed to retrieve fragment", + "Failed to retrieve items for home fragment", itemListResult.getErrorOrNull() ) } @@ -99,12 +105,21 @@ class HomeViewModel @Inject constructor( } } + /** + * Returns a [HomeItemViewModel] corresponding to the welcome message (see [WelcomeViewModel]), or null if + * the specified profile has insufficient information to show the welcome message. + * */ private fun computeWelcomeViewModel(profile: Profile): HomeItemViewModel? { return if (profile.name.isNotEmpty()) { WelcomeViewModel(fragment, oppiaClock, profile.name) } else null } + /** + * Returns a [HomeItemViewModel] corresponding to the promoted stories to be displayed for this learner + * (see [PromotedStoryListViewModel]), or null if this profile does not have any promoted stories. + * Promoted stories are determined by any recent stories started by this profile. + * */ private fun computePromotedStoryListViewModel( ongoingStoryList: OngoingStoryList ): HomeItemViewModel? { @@ -119,39 +134,40 @@ class HomeViewModel @Inject constructor( } else null } + /** + * Returns a list of [HomeItemViewModel]s corresponding to the the [PromotedStoryListViewModel] displayed + * for this profile (see [PromotedStoryViewModel]), or an empty list if the profile does not have any + * ongoing stories at all. + */ private fun computePromotedStoryViewModelList( ongoingStoryList: OngoingStoryList ): List { - if (ongoingStoryList.recentStoryCount != 0) { - return ongoingStoryList.recentStoryList.take(limit) - .map { promotedStory -> - PromotedStoryViewModel( - activity, - internalProfileId, - intentFactoryShim, - ongoingStoryList.recentStoryCount, - storyEntityType, - promotedStory - ) - } + val storyList = if (ongoingStoryList.recentStoryCount != 0) { + ongoingStoryList.recentStoryList } else { // TODO(#936): Optimise this as part of recommended stories. - return ongoingStoryList.olderStoryList.take(limit) - .map { promotedStory -> - PromotedStoryViewModel( - activity, - internalProfileId, - intentFactoryShim, - ongoingStoryList.olderStoryCount, - storyEntityType, - promotedStory - ) - } + ongoingStoryList.olderStoryList } + return storyList.take(promotedStoryListLimit) + .map { promotedStory -> + PromotedStoryViewModel( + activity, + internalProfileId, + intentFactoryShim, + storyList.size, + storyEntityType, + promotedStory + ) + } } - private fun computeTopicSummaryItemViewModelList(topicList: TopicList): List { - return topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> + /** + * Returns a list of [HomeItemViewModel]s corresponding to all the lesson topics available and to be + * displayed on the home activity (see [TopicSummaryViewModel]) along with associated topics list header (see + * [AllTopicsViewModel]). Returns null if there are no lesson topics to display in the home fragment. + */ + private fun computeAllTopicsItemsViewModelList(topicList: TopicList): Iterable? { + val allTopicsList = topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, topicSummary, @@ -160,5 +176,8 @@ class HomeViewModel @Inject constructor( position = topicIndex ) } + return if (!allTopicsList.isEmpty()) { + listOf(AllTopicsViewModel()) + allTopicsList + } else null } } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 56c5f01d92c..edc25ef8aef 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -11,6 +11,8 @@ class WelcomeViewModel( oppiaClock: OppiaClock, val profileName: String ) : HomeItemViewModel() { + + /** Text [String] to greet the learner and display on-screen when launching the home activity. */ val greeting: String = DateTimeUtil( fragment.requireContext(), oppiaClock diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt similarity index 90% rename from app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt rename to app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index d8645220599..6067df4688e 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -1,4 +1,4 @@ -package org.oppia.android.app.home.topiclist +package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet @@ -9,7 +9,7 @@ import org.oppia.android.databinding.PromotedStoryCardBinding /** * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to - * a fixed position on the device. + * a fixed position when being scrolled. */ class PromotedStoryListView @JvmOverloads constructor( context: Context, @@ -19,7 +19,6 @@ class PromotedStoryListView @JvmOverloads constructor( init { adapter = BindableAdapter.SingleTypeBuilder.newBuilder() - // should this be PromotedStoryCardBinding? .registerViewDataBinderWithSameModelType( inflateDataBinding = PromotedStoryCardBinding::inflate, setViewModel = PromotedStoryCardBinding::setViewModel diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt similarity index 56% rename from app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt rename to app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index ae64a5f8ff2..e62f61ae0a5 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -1,4 +1,4 @@ -package org.oppia.android.app.home.topiclist +package org.oppia.android.app.home.promotedlist import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel @@ -16,10 +16,26 @@ class PromotedStoryListViewModel( ) : HomeItemViewModel(), RouteToRecentlyPlayedListener { - val paddingEnd = - activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) - val paddingStart = - activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) + + /** + * Returns an [Int] for the padding placed at the start of the promoted stories list layout displayed on the + * home activity. + */ + fun getStartPadding(): Int { + return activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) + } + + /** + * Returns an [Int] for the padding placed at the end of the promoted stories list layout displayed on the + * home activity, centering the story if there is only one promoted story. + */ + fun getEndPadding(): Int { + return if (promotedStoryList.size > 1) { + activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) + } else { + getStartPadding() + } + } fun clickOnViewAll() { routeToRecentlyPlayed() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt similarity index 79% rename from app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt rename to app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 2253de4efe6..61a721a6f29 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -1,4 +1,4 @@ -package org.oppia.android.app.home.topiclist +package org.oppia.android.app.home.promotedlist import android.content.res.Configuration import android.content.res.Resources @@ -17,7 +17,7 @@ import org.oppia.android.app.viewmodel.ObservableViewModel class PromotedStoryViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, - private val IntentFactoryShim: IntentFactoryShim, + private val intentFactoryShim: IntentFactoryShim, private val totalStoryCount: Int, val entityType: String, val promotedStory: PromotedStory @@ -25,6 +25,10 @@ class PromotedStoryViewModel( ObservableViewModel(), RouteToTopicPlayStoryListener { + /** + * Returns an [Int] for the width of the card layout of this promoted story, based on the device's orientation + * and the number of promoted stories displayed the home activity. + */ fun computeLayoutWidth(): Int { val orientation = Resources.getSystem().configuration.orientation return if (orientation != Configuration.ORIENTATION_PORTRAIT && totalStoryCount > 1) { @@ -38,8 +42,9 @@ class PromotedStoryViewModel( routeToTopicPlayStory(internalProfileId, promotedStory.topicId, promotedStory.storyId) } + /** Launches the lesson for this story. */ override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { - val intent = IntentFactoryShim.createTopicPlayStoryActivityIntent( + val intent = intentFactoryShim.createTopicPlayStoryActivityIntent( activity.applicationContext, internalProfileId, topicId, diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index d0a6488fc44..97e0740ce1c 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -5,4 +5,4 @@ import org.oppia.android.app.home.HomeItemViewModel import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel @Inject constructor() : HomeItemViewModel() +class AllTopicsViewModel() : HomeItemViewModel() diff --git a/app/src/main/res/layout-land/promoted_story_card.xml b/app/src/main/res/layout-land/promoted_story_card.xml index 7fd0f2aa276..559177451ec 100755 --- a/app/src/main/res/layout-land/promoted_story_card.xml +++ b/app/src/main/res/layout-land/promoted_story_card.xml @@ -8,7 +8,7 @@ + type="org.oppia.android.app.home.promotedlist.PromotedStoryViewModel" /> + type="org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel" /> - diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_card.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_card.xml index b3ff345b492..c4959219fe1 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_card.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_card.xml @@ -8,7 +8,7 @@ + type="org.oppia.android.app.home.promotedlist.PromotedStoryViewModel" /> + type="org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel" /> - diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_card.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_card.xml index 45c9bbd36c5..8dd03dc1667 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_card.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_card.xml @@ -8,7 +8,7 @@ + type="org.oppia.android.app.home.promotedlist.PromotedStoryViewModel" /> + type="org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel" /> - + android:orientation="horizontal" + android:paddingStart="@{viewModel.getStartPadding}" + android:paddingEnd="@{viewModel.getEndPadding}" + app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_card.xml b/app/src/main/res/layout/promoted_story_card.xml index ffa35a9aa31..7701243edaf 100755 --- a/app/src/main/res/layout/promoted_story_card.xml +++ b/app/src/main/res/layout/promoted_story_card.xml @@ -8,7 +8,7 @@ + type="org.oppia.android.app.home.promotedlist.PromotedStoryViewModel" /> + type="org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel" /> - + app:list="@{viewModel.promotedStoryList}" /> From 9c6ea9f9f5a649f53c0cd603aff65db3c7e7ee02 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 17:54:06 -0800 Subject: [PATCH 046/248] Fix linter errors --- .../java/org/oppia/android/app/home/HomeViewModel.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index db4b9a67723..41d9d6c496d 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -7,9 +7,9 @@ import androidx.lifecycle.Transformations import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel +import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.OngoingStoryList @@ -47,7 +47,8 @@ class HomeViewModel( ) : ObservableViewModel() { private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - private val promotedStoryListLimit = activity.resources.getInteger(R.integer.promoted_story_list_limit) + private val promotedStoryListLimit = + activity.resources.getInteger(R.integer.promoted_story_list_limit) private val profileDataProvider: DataProvider by lazy { profileManagementController.getProfile(profileId) @@ -165,7 +166,9 @@ class HomeViewModel( * displayed on the home activity (see [TopicSummaryViewModel]) along with associated topics list header (see * [AllTopicsViewModel]). Returns null if there are no lesson topics to display in the home fragment. */ - private fun computeAllTopicsItemsViewModelList(topicList: TopicList): Iterable? { + private fun computeAllTopicsItemsViewModelList( + topicList: TopicList + ): Iterable?{ val allTopicsList = topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, From 27f878f2774e415704ecb6207b564c78fa244c92 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 15 Dec 2020 17:56:01 -0800 Subject: [PATCH 047/248] Fix linter errors --- .../java/org/oppia/android/app/home/HomeFragmentPresenter.kt | 2 +- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 2 +- .../org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) 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 fdc72e4c3d2..01361b1f04b 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 @@ -9,8 +9,8 @@ import androidx.recyclerview.widget.GridLayoutManager import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope -import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel +import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.TopicSummary diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 41d9d6c496d..620aec9acbe 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -168,7 +168,7 @@ class HomeViewModel( */ private fun computeAllTopicsItemsViewModelList( topicList: TopicList - ): Iterable?{ + ): Iterable? { val allTopicsList = topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index 97e0740ce1c..154d5104091 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -2,7 +2,6 @@ package org.oppia.android.app.home.topiclist import androidx.lifecycle.ViewModel import org.oppia.android.app.home.HomeItemViewModel -import javax.inject.Inject /** [ViewModel] all topics text in [HomeFragment]. */ class AllTopicsViewModel() : HomeItemViewModel() From 27112a377306936d101306c353b06b9cc8e87fb7 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 16 Dec 2020 14:31:33 +0530 Subject: [PATCH 048/248] fixed index error --- .../domain/topic/TopicListController.kt | 2 +- .../domain/topic/TopicListControllerTest.kt | 30 ++++++++++++------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index a36e20681d5..1ae1c7d165c 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -383,7 +383,7 @@ class TopicListController @Inject constructor( val index = topicList.indexOf(topicProgressList[topicProgressList.size-1].topicId) Log.d("topic index", " = " + " " + index +" "+topicProgressList[topicProgressList.size-1].topicId) Log.d("topic index", " = " + " " + topicIdJsonArray.length()) - if ( topicIdJsonArray[index + 1] != null && topicIdJsonArray.length() > (index+1) ) { + if (topicIdJsonArray.length() > (index+1) ) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 59aed82822f..2049fee2634 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -278,12 +278,12 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) } @Test - @Ignore("Failing on Circle CI.") +// @Ignore("Failing on Circle CI.") fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, @@ -301,7 +301,7 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) } @@ -332,7 +332,7 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) } @@ -363,7 +363,7 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) verifyDefaultRecommendedStoryListSucceeded() } @@ -431,7 +431,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recentStoryListCorrect() { + fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_fromRecommendedStories_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -450,6 +450,16 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + testCoroutineDispatchers.runCurrent() topicListController.getOngoingStoryList(profileId0).toLiveData() .observeForever(mockOngoingStoryListObserver) testCoroutineDispatchers.runCurrent() @@ -457,7 +467,7 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) + assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) } @@ -774,10 +784,8 @@ class TopicListControllerTest { private fun verifyDefaultRecommendedStoryListSucceeded() { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) - verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[2]) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { From 1a9fdc4066ddc6a3585e64298f3fc50553cefafc Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 16 Dec 2020 19:35:01 +0530 Subject: [PATCH 049/248] added timestamp for recently played --- .../domain/topic/StoryProgressController.kt | 6 +- .../domain/topic/TopicListController.kt | 189 +++++++++--------- model/src/main/proto/topic.proto | 3 + 3 files changed, 103 insertions(+), 95 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index abda9c898a2..31bf6584d80 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -13,6 +13,7 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.logging.ConsoleLogger +import java.util.* import javax.inject.Inject import javax.inject.Singleton @@ -110,7 +111,8 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp( + Date().time) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -191,7 +193,7 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgressBuilder.build()) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(lastPlayedTimestamp) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index e77ffc3db98..a4c33d82a6a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -167,17 +167,18 @@ class TopicListController @Inject constructor( } private fun createOngoingStoryListFromProgress( - topicProgressList: List + sortedTopicProgressList: List ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() + + val topicProgressList = sortedTopicProgressList.sortedByDescending { it.lastPlayedTimestamp } if (topicProgressList.isNotEmpty()) { Log.d("topic size",""+topicProgressList.size) if (topicProgressList.size==1) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecommended(true) ) - Log.d("topic size = 1",""+topicProgressList.size) ongoingStoryListBuilder.addAllRecommendedStory( createRecommendedStoryList( topicProgressList @@ -192,7 +193,7 @@ class TopicListController @Inject constructor( topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) - Log.d("topic progress =", "" + topicProgress.topicId + storyId) + Log.d("topic progress =", "" + topicProgress.topicId +" "+ topicProgress.lastPlayedTimestamp) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -291,109 +292,111 @@ class TopicListController @Inject constructor( topicProgressList: List ): List { val recommendedStories = ArrayList() - topicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - var story = topicController.retrieveStory(topic.topicId, storyId) - - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + topicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + var story = topicController.retrieveStory(topic.topicId, storyId) + + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + recommendedStories.add(promotedStory) } - if (recentlyPlayerChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } else { - val nextStoryIndex = topic.storyList.indexOf(story) + 1 - if (nextStoryIndex < topic.storyList.size) { - story = topicController.retrieveStory( - topic.topicId, - topic.storyList[nextStoryIndex].storyId + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId ) - val nextChapterSummary: ChapterSummary? = story.chapterList[0] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - story.storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId + recommendedStories.add(promotedStory) + } else { + val nextStoryIndex = topic.storyList.indexOf(story) + 1 + if (nextStoryIndex < topic.storyList.size) { + story = topicController.retrieveStory( + topic.topicId, + topic.storyList[nextStoryIndex].storyId ) - recommendedStories.add(promotedStory) + val nextChapterSummary: ChapterSummary? = story.chapterList[0] + if (nextChapterSummary != null) { + val promotedStory = createPromotedStory( + story.storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + recommendedStories.add(promotedStory) + } } } } } - } - - } - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") + } - val topicList = ArrayList() - for (i in 0 until topicIdJsonArray.length()) { - topicList.add(topicIdJsonArray[i].toString()) - } + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") - val index = topicList.indexOf(topicProgressList[topicProgressList.size-1].topicId) - Log.d("topic index", " = " + " " + index +" "+topicProgressList[topicProgressList.size-1].topicId) - Log.d("topic index", " = " + " " + topicIdJsonArray.length()) - if (topicIdJsonArray.length() > (index+1) ) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) - return recommendedStories - } + val topicList = ArrayList() + for (i in 0 until topicIdJsonArray.length()) { + topicList.add(topicIdJsonArray[i].toString()) + } + val index = topicList.indexOf(topicProgressList[topicProgressList.size - 1].topicId) + Log.d( + "topic index", + " = " + " " + index + " " + topicProgressList[topicProgressList.size - 1].topicId + ) + Log.d("topic index", " = " + " " + topicIdJsonArray.length()) + if (topicIdJsonArray.length() > (index + 1)) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) + return recommendedStories + } return recommendedStories } diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 6e72ce7e586..b718805a71f 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -246,6 +246,9 @@ message TopicProgress { // Indicates type of story promoted PromotedStoriesType promoted_stories_type = 4; + + // Timestamp to record last time the exploration was played in ms. + int64 last_played_timestamp = 5; } // A structure corresponding to the Promoted Stories. This structure is set up From 435270a316d3eccafe5665fcb45ce2c711aa1f8d Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 16 Dec 2020 16:27:09 -0800 Subject: [PATCH 050/248] Add view models to bazel build file --- app/BUILD.bazel | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index ad0269475b5..abf5e122376 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -122,6 +122,9 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/help/HelpItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpListViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt", + "src/main/java/org/oppia/android/app/home/HomeViewModel.kt", + "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt", "src/main/java/org/oppia/android/app/parser/StringToFractionParser.kt", @@ -159,6 +162,8 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQHeaderViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpItems.kt", + "src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt", + "src/main/java/org/oppia/android/app/topiclist/AllTopicsViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionItemViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsDividerViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsViewModel.kt", From 5f93d32d26eeeb5ebf0772d03459de088ad510f6 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 16 Dec 2020 17:52:43 -0800 Subject: [PATCH 051/248] Refactor all topics list to return empty list if no topics --- .../java/org/oppia/android/app/home/HomeViewModel.kt | 12 +++--------- .../org/oppia/android/app/home/HomeActivityTest.kt | 3 +++ .../android/testing/home/HomeFragmentTestHelper.kt | 4 ++++ 3 files changed, 10 insertions(+), 9 deletions(-) create mode 100644 testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 620aec9acbe..2bfd9e5546f 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -78,13 +78,7 @@ class HomeViewModel( topicListSummaryDataProvider, HOME_FRAGMENT_COMBINED_PROVIDER_ID ) { homeItemViewModelList, topicList -> - computeAllTopicsItemsViewModelList(topicList).let { - if (it != null) { - homeItemViewModelList + it - } else { - homeItemViewModelList - } - } + homeItemViewModelList + computeAllTopicsItemsViewModelList(topicList) } } @@ -168,7 +162,7 @@ class HomeViewModel( */ private fun computeAllTopicsItemsViewModelList( topicList: TopicList - ): Iterable? { + ): Iterable { val allTopicsList = topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, @@ -180,6 +174,6 @@ class HomeViewModel( } return if (!allTopicsList.isEmpty()) { listOf(AllTopicsViewModel()) + allTopicsList - } else null + } else emptyList() } } 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 81c3aea9dff..ee4c8fe1540 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 @@ -540,6 +540,9 @@ class HomeActivityTest { } } + // HomeActivity does not display promoted stories when the list is empty + // HomeActivity does not display topics list when there are no topics + private fun createHomeActivityIntent(profileId: Int): Intent { return HomeActivity.createHomeActivity(ApplicationProvider.getApplicationContext(), profileId) } diff --git a/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt new file mode 100644 index 00000000000..757c0363016 --- /dev/null +++ b/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt @@ -0,0 +1,4 @@ +package org.oppia.android.testing.home + +class HomeFragmentTestHelper { +} \ No newline at end of file From b184d1e5e382614d00c47a00ce2144c79b588633 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 16 Dec 2020 18:14:52 -0800 Subject: [PATCH 052/248] Remove duplicated HomeViewModel in bazel build --- app/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index abf5e122376..877c12774b9 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -162,7 +162,6 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQHeaderViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpItems.kt", - "src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt", "src/main/java/org/oppia/android/app/topiclist/AllTopicsViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionItemViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsDividerViewModel.kt", From cec345def3f3d36b80bccdeba2348d048471e332 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 16 Dec 2020 18:31:02 -0800 Subject: [PATCH 053/248] Fix linter error & filepath for AllTopicsViewModel in bazel build --- app/BUILD.bazel | 1 - .../org/oppia/android/testing/home/HomeFragmentTestHelper.kt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 877c12774b9..3e1d874ec93 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -162,7 +162,6 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQHeaderViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/faqItemViewModel/FAQItemViewModel.kt", "src/main/java/org/oppia/android/app/help/HelpItems.kt", - "src/main/java/org/oppia/android/app/topiclist/AllTopicsViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsAndSolutionItemViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsDividerViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/HintsViewModel.kt", diff --git a/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt index 757c0363016..5b301f63709 100644 --- a/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt +++ b/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt @@ -1,4 +1,5 @@ package org.oppia.android.testing.home +/** This helper allows tests to easily set various HomeFragment states. */ class HomeFragmentTestHelper { -} \ No newline at end of file +} From f2b62710909a09fc85164bc593977385780eb66a Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 14:45:11 +0530 Subject: [PATCH 054/248] removed walkthrough field --- .../recentlyplayed/RecentlyPlayedActivity.kt | 3 +- .../player/exploration/ExplorationActivity.kt | 12 +- .../ExplorationActivityPresenter.kt | 8 +- .../player/exploration/ExplorationFragment.kt | 14 +- .../ExplorationFragmentPresenter.kt | 5 +- .../android/app/player/state/StateFragment.kt | 3 +- .../StateFragmentTestActivityPresenter.kt | 3 +- .../oppia/android/app/story/StoryActivity.kt | 3 +- .../app/testing/ExplorationTestActivity.kt | 3 +- .../android/app/testing/TopicTestActivity.kt | 3 +- .../app/testing/TopicTestActivityForStory.kt | 3 +- .../oppia/android/app/topic/TopicActivity.kt | 3 +- .../domain/topic/TopicListController.kt | 216 +++++++------- .../domain/topic/TopicListControllerTest.kt | 280 +++++------------- 14 files changed, 192 insertions(+), 367 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt index 78f19cd66c4..fcb09bc3876 100644 --- a/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt +++ b/app/src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedActivity.kt @@ -51,8 +51,7 @@ class RecentlyPlayedActivity : InjectableAppCompatActivity(), RouteToExploration topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt index bd7a701f9d6..1a3aa618ec1 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivity.kt @@ -46,7 +46,6 @@ class ExplorationActivity : private lateinit var explorationId: String private lateinit var state: State private var backflowScreen: Int? = null - private var isFromWalkthrough: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -55,17 +54,14 @@ class ExplorationActivity : topicId = intent.getStringExtra(EXPLORATION_ACTIVITY_TOPIC_ID_ARGUMENT_KEY) storyId = intent.getStringExtra(EXPLORATION_ACTIVITY_STORY_ID_ARGUMENT_KEY) explorationId = intent.getStringExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY) - explorationId = intent.getStringExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY) backflowScreen = intent.getIntExtra(EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY, -1) - isFromWalkthrough = intent.getBooleanExtra(EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY, false) explorationActivityPresenter.handleOnCreate( this, internalProfileId, topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough + backflowScreen ) } @@ -81,8 +77,6 @@ class ExplorationActivity : "ExplorationActivity.exploration_id" const val EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY = "ExplorationActivity.backflow_screen" - const val EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY = - "ExplorationActivity.is_from_walkthrough_screen" fun createExplorationActivityIntent( context: Context, @@ -90,8 +84,7 @@ class ExplorationActivity : topicId: String, storyId: String, explorationId: String, - backflowScreen: Int?, - isFromWalkthrough: Boolean + backflowScreen: Int? ): Intent { val intent = Intent(context, ExplorationActivity::class.java) intent.putExtra(EXPLORATION_ACTIVITY_PROFILE_ID_ARGUMENT_KEY, profileId) @@ -99,7 +92,6 @@ class ExplorationActivity : intent.putExtra(EXPLORATION_ACTIVITY_STORY_ID_ARGUMENT_KEY, storyId) intent.putExtra(EXPLORATION_ACTIVITY_EXPLORATION_ID_ARGUMENT_KEY, explorationId) intent.putExtra(EXPLORATION_ACTIVITY_BACKFLOW_SCREEN_KEY, backflowScreen) - intent.putExtra(EXPLORATION_ACTIVITY_IS_FROM_WALKTHROUGH_KEY, isFromWalkthrough) return intent } } diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt index fa821292e07..5421e4705d0 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationActivityPresenter.kt @@ -48,7 +48,6 @@ class ExplorationActivityPresenter @Inject constructor( private lateinit var explorationId: String private lateinit var context: Context private var backflowScreen: Int? = null - private var isFromWalkthrough: Boolean = false enum class ParentActivityForExploration(val value: Int) { BACKFLOW_SCREEN_LESSONS(0), @@ -65,8 +64,7 @@ class ExplorationActivityPresenter @Inject constructor( topicId: String, storyId: String, explorationId: String, - backflowScreen: Int?, - isFromWalkthrough: Boolean + backflowScreen: Int? ) { val binding = DataBindingUtil.setContentView( activity, @@ -100,7 +98,6 @@ class ExplorationActivityPresenter @Inject constructor( this.explorationId = explorationId this.context = context this.backflowScreen = backflowScreen - this.isFromWalkthrough = isFromWalkthrough if (getExplorationManagerFragment() == null) { val explorationManagerFragment = ExplorationManagerFragment() val args = Bundle() @@ -126,8 +123,7 @@ class ExplorationActivityPresenter @Inject constructor( internalProfileId = internalProfileId, storyId = storyId, readingTextSize = readingTextSize.name, - explorationId = explorationId, - isFromWalkthrough = isFromWalkthrough + explorationId = explorationId ), TAG_EXPLORATION_FRAGMENT ).commitNow() diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt index 853ea364484..b8ac46fac0c 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragment.kt @@ -26,8 +26,6 @@ class ExplorationFragment : InjectableFragment() { "ExplorationFragment.story_default_font_size" internal const val EXPLORATION_ID_ARGUMENT_KEY = "ExplorationFragment.exploration_id" - internal const val EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY = - "ExplorationFragment.is_from_walkthrough" /** Returns a new [ExplorationFragment] to pass the profileId, topicId, storyId, readingTextSize and explorationId. */ fun newInstance( @@ -35,8 +33,7 @@ class ExplorationFragment : InjectableFragment() { topicId: String, storyId: String, readingTextSize: String, - explorationId: String, - isFromWalkthrough: Boolean + explorationId: String ): ExplorationFragment { val explorationFragment = ExplorationFragment() val args = Bundle() @@ -54,10 +51,6 @@ class ExplorationFragment : InjectableFragment() { EXPLORATION_ID_ARGUMENT_KEY, explorationId ) - args.putBoolean( - EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY, - isFromWalkthrough - ) explorationFragment.arguments = args return explorationFragment } @@ -88,16 +81,13 @@ class ExplorationFragment : InjectableFragment() { val explorationId = arguments!!.getString(EXPLORATION_ID_ARGUMENT_KEY) checkNotNull(explorationId) { "StateFragment must be created with an exploration ID" } - val isFromWalkthrough = - arguments!!.getBoolean(EXPLORATION_IS_FROM_WALKTHROUGH_ARGUMENT_KEY) return explorationFragmentPresenter.handleCreateView( inflater, container, profileId, topicId, storyId, - explorationId, - isFromWalkthrough + explorationId ) } diff --git a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt index 24196feb6a6..be57cf17643 100755 --- a/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/exploration/ExplorationFragmentPresenter.kt @@ -26,12 +26,11 @@ class ExplorationFragmentPresenter @Inject constructor( profileId: Int, topicId: String, storyId: String, - explorationId: String, - isFromWalkthrough: Boolean + explorationId: String ): View? { val binding = ExplorationFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false).root - val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId, isFromWalkthrough) + val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId) logPracticeFragmentEvent(topicId, storyId, explorationId) if (getStateFragment() == null) { fragment.childFragmentManager.beginTransaction().add( diff --git a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt index 1ec5536b293..1eff9e90ff0 100755 --- a/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/StateFragment.kt @@ -46,8 +46,7 @@ class StateFragment : internalProfileId: Int, topicId: String, storyId: String, - explorationId: String, - isFromWalkthrough: Boolean + explorationId: String ): StateFragment { val stateFragment = StateFragment() val args = Bundle() diff --git a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt index 852c5ac005a..e94cda7bdf1 100644 --- a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt @@ -110,8 +110,7 @@ class StateFragmentTestActivityPresenter @Inject constructor( profileId, topicId, storyId, - explorationId, - isFromWalkthrough = false + explorationId ) activity.supportFragmentManager.beginTransaction().add( R.id.state_fragment_placeholder, diff --git a/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt b/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt index 967b492c1d0..a3e57491dc7 100644 --- a/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt +++ b/app/src/main/java/org/oppia/android/app/story/StoryActivity.kt @@ -43,8 +43,7 @@ class StoryActivity : InjectableAppCompatActivity(), RouteToExplorationListener topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt index 4ba6ae957a9..5281e777a50 100644 --- a/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/ExplorationTestActivity.kt @@ -32,8 +32,7 @@ class ExplorationTestActivity : InjectableAppCompatActivity(), RouteToExploratio topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt index c679da5b8e7..3111170ebde 100644 --- a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivity.kt @@ -69,8 +69,7 @@ class TopicTestActivity : topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt index 8f4be3b1751..5f3b5e96f30 100644 --- a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt +++ b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt @@ -70,8 +70,7 @@ class TopicTestActivityForStory : topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt b/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt index 14c453151c0..a158d2fa7e3 100755 --- a/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt +++ b/app/src/main/java/org/oppia/android/app/topic/TopicActivity.kt @@ -86,8 +86,7 @@ class TopicActivity : topicId, storyId, explorationId, - backflowScreen, - isFromWalkthrough = false + backflowScreen ) ) } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index a4c33d82a6a..47455650786 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -167,33 +167,38 @@ class TopicListController @Inject constructor( } private fun createOngoingStoryListFromProgress( - sortedTopicProgressList: List + topicProgressList: List ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() - - val topicProgressList = sortedTopicProgressList.sortedByDescending { it.lastPlayedTimestamp } if (topicProgressList.isNotEmpty()) { - Log.d("topic size",""+topicProgressList.size) - if (topicProgressList.size==1) { + Log.d("topic size", "" + topicProgressList.size) + if (topicProgressList.size == 1) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecommended(true) ) ongoingStoryListBuilder.addAllRecommendedStory( createRecommendedStoryList( topicProgressList - )) + ) + ) } else { - topicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) + val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + + sortedTopicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecentlyPlayed(true) ) + topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) - Log.d("topic progress =", "" + topicProgress.topicId +" "+ topicProgress.lastPlayedTimestamp) + Log.d( + "topic progress =", + "" + topicProgress.topicId + " " + topicProgress.lastPlayedTimestamp + ) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -265,9 +270,14 @@ class TopicListController @Inject constructor( } } } - - } - + } + if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount > 0 + && ongoingStoryListBuilder.recommendedStoryCount == 0 + ) { + ongoingStoryListBuilder.setPromotedStoriesType( + PromotedStoriesType.newBuilder().setLastPlayed(true) + ) + } if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setRecommended(true) @@ -275,7 +285,8 @@ class TopicListController @Inject constructor( ongoingStoryListBuilder.addAllRecommendedStory( createRecommendedStoryList( topicProgressList - )) + ) + ) if (ongoingStoryListBuilder.recommendedStoryCount == 0) { ongoingStoryListBuilder.setPromotedStoriesType( PromotedStoriesType.newBuilder().setComingSoon(true) @@ -292,111 +303,104 @@ class TopicListController @Inject constructor( topicProgressList: List ): List { val recommendedStories = ArrayList() - topicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - var story = topicController.retrieveStory(topic.topicId, storyId) - - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + topicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + var story = topicController.retrieveStory(topic.topicId, storyId) + + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId + if (recentlyPlayerChapterSummary != null) { + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + recommendedStories.add(promotedStory) + } + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + recommendedStories.add(promotedStory) + } else { + val nextStoryIndex = topic.storyList.indexOf(story) + 1 + if (nextStoryIndex < topic.storyList.size) { + story = topicController.retrieveStory( + topic.topicId, + topic.storyList[nextStoryIndex].storyId ) - recommendedStories.add(promotedStory) - } else { - val nextStoryIndex = topic.storyList.indexOf(story) + 1 - if (nextStoryIndex < topic.storyList.size) { - story = topicController.retrieveStory( - topic.topicId, - topic.storyList[nextStoryIndex].storyId + val nextChapterSummary: ChapterSummary? = story.chapterList[0] + if (nextChapterSummary != null) { + val promotedStory = createPromotedStory( + story.storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId ) - val nextChapterSummary: ChapterSummary? = story.chapterList[0] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - story.storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } + recommendedStories.add(promotedStory) } } } } - } + } - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") - - val topicList = ArrayList() - for (i in 0 until topicIdJsonArray.length()) { - topicList.add(topicIdJsonArray[i].toString()) - } + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") - val index = topicList.indexOf(topicProgressList[topicProgressList.size - 1].topicId) - Log.d( - "topic index", - " = " + " " + index + " " + topicProgressList[topicProgressList.size - 1].topicId - ) - Log.d("topic index", " = " + " " + topicIdJsonArray.length()) - if (topicIdJsonArray.length() > (index + 1)) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) - return recommendedStories - } + val topicList = ArrayList() + for (i in 0 until topicIdJsonArray.length()) { + topicList.add(topicIdJsonArray[i].toString()) + } + val index = topicList.indexOf(topicProgressList[topicProgressList.size - 1].topicId) + if (topicIdJsonArray.length() > (index + 1)) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) + return recommendedStories + } return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 8c7fd8b564d..b2c4754f474 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -289,39 +289,6 @@ class TopicListControllerTest { assertThat(ratiosTopic.totalChapterCount).isEqualTo(4) } - @Test - fun testRetrieveOngoingStoryList_defaultLesson_hasCorrectInfo() { - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - verifyDefaultOngoingStoryListSucceeded() - } - - @Test - @Ignore("Failing on Circle CI.") - fun testRetrieveRecentStoryList_markRecentlyPlayedFracStory0Exp0_recentStoryListIsCorrect() { - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recentStoryList[0]) - } - @Test fun testRetrieveRecommendedStoryList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -342,6 +309,7 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) } @Test @@ -365,38 +333,39 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) - } - - @Test - fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recommendedListCorrect() { - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) - } + verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) + } + +// @Test +// fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recommendedListCorrect() { +// storyProgressController.recordCompletedChapter( +// profileId0, +// FRACTIONS_TOPIC_ID, +// FRACTIONS_STORY_ID_0, +// FRACTIONS_EXPLORATION_ID_0, +// getCurrentTimestamp() +// ) +// testCoroutineDispatchers.runCurrent() +// +// storyProgressController.recordRecentlyPlayedChapter( +// profileId0, +// FRACTIONS_TOPIC_ID, +// FRACTIONS_STORY_ID_0, +// FRACTIONS_EXPLORATION_ID_1, +// getCurrentTimestamp() +// ) +// testCoroutineDispatchers.runCurrent() +// +// topicListController.getOngoingStoryList(profileId0).toLiveData() +// .observeForever(mockOngoingStoryListObserver) +// testCoroutineDispatchers.runCurrent() +// +// verifyGetOngoingStoryListSucceeded() +// +// val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() +// assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) +// verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) +// } @Test fun testRetrieveRecommendedStoryList_markAllChaptersCompletedInFractions_recommendedListIsCorrect() { @@ -470,28 +439,6 @@ class TopicListControllerTest { verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recentStoryList[0]) } - @Test - fun testRetrieveRecentList_markChapterCompletedFracStory0Exp0_recentStoryListIsCorrect() { - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) - } - @Test fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_fromRecommendedStories_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { storyProgressController.recordCompletedChapter( @@ -528,105 +475,10 @@ class TopicListControllerTest { verifyGetOngoingStoryListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) - } - - @Test - @Ignore("Failing on Circle CI.") - fun testRetrieveOngoingStoryList_markAllChaptersCompletedInFractions_ongoingStoryListIsCorrect() { - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyDefaultOngoingStoryListSucceeded() - } - - @Test - fun testRetrieveStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_ongoingListIsCorrect() { - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_1, - RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) - } - - @Test - fun testRetrieveStoryList_markExp0DoneAndExp2AsPlayedInRatios_ongoingStoryListIsCorrect() { - storyProgressController.recordCompletedChapter( - profileId0, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_1, - RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetOngoingStoryListSucceeded() - - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[1]) } @Test @@ -666,9 +518,9 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(3) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[2]) + verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[2]) } @Test @@ -699,7 +551,7 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(3) + assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) } @Test @@ -722,31 +574,31 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - storyProgressController.recordCompletedChapter( - profileId0, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_2, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - storyProgressController.recordCompletedChapter( - profileId0, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_5, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - TEST_TOPIC_ID_1, - TEST_STORY_ID_2, - TEST_EXPLORATION_ID_4, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() +// storyProgressController.recordCompletedChapter( +// profileId0, +// TEST_TOPIC_ID_0, +// TEST_STORY_ID_0, +// TEST_EXPLORATION_ID_2, +// getCurrentTimestamp() +// ) +// testCoroutineDispatchers.runCurrent() +// storyProgressController.recordCompletedChapter( +// profileId0, +// TEST_TOPIC_ID_0, +// TEST_STORY_ID_0, +// TEST_EXPLORATION_ID_5, +// getCurrentTimestamp() +// ) +// testCoroutineDispatchers.runCurrent() +// +// storyProgressController.recordCompletedChapter( +// profileId0, +// TEST_TOPIC_ID_1, +// TEST_STORY_ID_2, +// TEST_EXPLORATION_ID_4, +// getCurrentTimestamp() +// ) +// testCoroutineDispatchers.runCurrent() storyProgressController.recordCompletedChapter( @@ -822,8 +674,8 @@ class TopicListControllerTest { val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) assertThat(ongoingTopicList.olderStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.olderStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.olderStoryList[1]) + verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.olderStoryList[0]) + verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.olderStoryList[1]) verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[0]) } From 4e6926c5ce844e9857c6c9759257f52f9e09a8c5 Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 16:47:11 +0530 Subject: [PATCH 055/248] writting testcases --- .../android/app/home/HomeActivityTest.kt | 158 +++++++++++++++++- .../app/home/RecentlyPlayedFragmentTest.kt | 2 +- .../app/testing/RecentlyPlayedSpanTest.kt | 2 +- .../domain/topic/StoryProgressTestHelper.kt | 2 +- .../topic/StoryProgressTestHelperTest.kt | 2 +- 5 files changed, 156 insertions(+), 10 deletions(-) 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 81c3aea9dff..232803f5288 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 @@ -10,6 +10,7 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.pressBack import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition import androidx.test.espresso.intent.Intents @@ -17,9 +18,11 @@ 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.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isRoot +import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withParent import androidx.test.espresso.matcher.ViewMatchers.withText @@ -42,6 +45,7 @@ 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.home.recentlyplayed.RecentlyPlayedActivity +import org.oppia.android.app.model.ProfileId import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.profile.ProfileChooserActivity import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPosition @@ -67,7 +71,10 @@ import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.FRACTIONS_STORY_ID_0 +import org.oppia.android.domain.topic.FRACTIONS_TOPIC_ID import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.domain.topic.StoryProgressTestHelper import org.oppia.android.domain.topic.TEST_STORY_ID_0 import org.oppia.android.domain.topic.TEST_TOPIC_ID_0 import org.oppia.android.testing.TestAccessibilityModule @@ -109,6 +116,8 @@ class HomeActivityTest { @Inject lateinit var profileTestHelper: ProfileTestHelper + @Inject + lateinit var storyProgressTestHelper: StoryProgressTestHelper @Inject lateinit var context: Context @@ -117,6 +126,7 @@ class HomeActivityTest { private val internalProfileId: Int = 1 private lateinit var oppiaClock: OppiaClock + private lateinit var profileId: ProfileId @Before fun setUp() { @@ -124,6 +134,7 @@ class HomeActivityTest { setUpTestApplicationComponent() testCoroutineDispatchers.registerIdlingResource() profileTestHelper.initializeProfiles() + profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() FirebaseApp.initializeApp(context) } @@ -239,6 +250,14 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysRecentlyPlayedStoriesText() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -260,6 +279,14 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysViewAllText() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -273,8 +300,87 @@ class HomeActivityTest { } } + @Test + fun testHomeActivity_recyclerViewIndex1_displaysRecommendedStoriesText() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(1) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 1, + R.id.recently_played_stories_text_view + ) + ).check( + matches( + withText(R.string.recommended_stories) + ) + ) + } + } + + @Test + fun testHomeActivity_recyclerViewIndex1_forRecommendedStories_hideViewAll() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(1) + ) + + onView(allOf(withId(R.id.view_all_text_view), + withEffectiveVisibility(ViewMatchers.Visibility.GONE))) + } + } + + @Test + fun testHomeActivity_recyclerViewIndex1_displaysComingSoonTopicsText() { + storyProgressTestHelper.markFullStoryProgressForFractions( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( + profileId, + timestampOlderThanAWeek = false + ) + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(1) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 1, + R.id.recently_played_stories_text_view + ) + ).check( + matches( + withText(R.string.coming_soon) + ) + ) + } + } + @Test fun testHomeActivity_recyclerViewIndex1_clickViewAll_opensRecentlyPlayedActivity() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -291,6 +397,14 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_chapterNameIsCorrect() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView( @@ -300,12 +414,20 @@ class HomeActivityTest { atPosition(R.id.home_recycler_view, 1) ) ) - ).check(matches(hasDescendant(withText(containsString("Prototype Exploration"))))) + ).check(matches(hasDescendant(withText(containsString("What is a Fraction"))))) } } @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_storyNameIsCorrect() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -313,7 +435,7 @@ class HomeActivityTest { ) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( matches( - withText(containsString("First Story")) + withText(containsString("Matthew Goes to the Bakery")) ) ) } @@ -321,6 +443,14 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_configurationChange_promotedCard_storyNameIsCorrect() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -329,7 +459,7 @@ class HomeActivityTest { onView(isRoot()).perform(orientationLandscape()) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( matches( - withText(containsString("First Story")) + withText(containsString("Matthew Goes to the Bakery")) ) ) } @@ -337,6 +467,14 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_clickPromotedStory_opensTopicActivity() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -352,13 +490,21 @@ class HomeActivityTest { ).perform(click()) intended(hasComponent(TopicActivity::class.java.name)) intended(hasExtra(TopicActivity.getProfileIdKey(), internalProfileId)) - intended(hasExtra(TopicActivity.getTopicIdKey(), TEST_TOPIC_ID_0)) - intended(hasExtra(TopicActivity.getStoryIdKey(), TEST_STORY_ID_0)) + intended(hasExtra(TopicActivity.getTopicIdKey(), FRACTIONS_TOPIC_ID)) + intended(hasExtra(TopicActivity.getStoryIdKey(), FRACTIONS_STORY_ID_0)) } } @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_topicNameIsCorrect() { + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + profileId, + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( + profileId, + timestampOlderThanAWeek = true + ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -366,7 +512,7 @@ class HomeActivityTest { ) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.topic_name_text_view)).check( matches( - withText(containsString("FIRST TEST TOPIC")) + withText(containsString("Fractions")) ) ) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt index 04abf39977b..25813417752 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt @@ -119,7 +119,7 @@ class RecentlyPlayedFragmentTest { profileTestHelper.initializeProfiles() testCoroutineDispatchers.registerIdlingResource() profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( profileId, timestampOlderThanAWeek = false ) diff --git a/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt b/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt index 614a235415a..4c4356e83fc 100644 --- a/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt +++ b/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt @@ -84,7 +84,7 @@ class RecentlyPlayedSpanTest { setUpTestApplicationComponent() testCoroutineDispatchers.registerIdlingResource() profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( profileId, timestampOlderThanAWeek = false ) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index bae93039f53..c98737e53a2 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -152,7 +152,7 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. */ - fun markRecentlyPlayedForFractionsStory0Exploration0( + fun markTopicPlayedForFractionsStory0Exploration0( profileId: ProfileId, timestampOlderThanAWeek: Boolean ) { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index a698b5112be..428b6ce2d83 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -620,7 +620,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getOngoingStoryListIsCorrect() { - storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( profileId, /* timestampOlderThanAWeek= */ false ) From 872ccc3827ffd94205be30107a96592e1ec9a719 Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 17:01:32 +0530 Subject: [PATCH 056/248] fixing testcase --- .../android/app/home/HomeActivityTest.kt | 29 ------------------- .../domain/topic/TopicListControllerTest.kt | 27 ----------------- 2 files changed, 56 deletions(-) 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 232803f5288..389eab6ee5f 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 @@ -342,35 +342,6 @@ class HomeActivityTest { } } - @Test - fun testHomeActivity_recyclerViewIndex1_displaysComingSoonTopicsText() { - storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, - timestampOlderThanAWeek = false - ) - launch(createHomeActivityIntent(internalProfileId)).use { - testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 1, - R.id.recently_played_stories_text_view - ) - ).check( - matches( - withText(R.string.coming_soon) - ) - ) - } - } - @Test fun testHomeActivity_recyclerViewIndex1_clickViewAll_opensRecentlyPlayedActivity() { storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index b2c4754f474..4ff168d5592 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -574,33 +574,6 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() -// storyProgressController.recordCompletedChapter( -// profileId0, -// TEST_TOPIC_ID_0, -// TEST_STORY_ID_0, -// TEST_EXPLORATION_ID_2, -// getCurrentTimestamp() -// ) -// testCoroutineDispatchers.runCurrent() -// storyProgressController.recordCompletedChapter( -// profileId0, -// TEST_TOPIC_ID_0, -// TEST_STORY_ID_0, -// TEST_EXPLORATION_ID_5, -// getCurrentTimestamp() -// ) -// testCoroutineDispatchers.runCurrent() -// -// storyProgressController.recordCompletedChapter( -// profileId0, -// TEST_TOPIC_ID_1, -// TEST_STORY_ID_2, -// TEST_EXPLORATION_ID_4, -// getCurrentTimestamp() -// ) -// testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, From e07c7e6f0f08f00c4b5b6cf38ebd86188b5238a3 Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 17:14:00 +0530 Subject: [PATCH 057/248] Seperated UI part from this PR --- .../android/app/home/HomeFragmentPresenter.kt | 93 +++---------- .../topiclist/ComingSoonTopicListAdapter.kt | 55 -------- .../ComingSoonTopicsListViewModel.kt | 45 ------ .../home/topiclist/PromotedItemViewModel.kt | 6 - .../app/home/topiclist/TopicListAdapter.kt | 74 ++-------- .../layout-land/coming_soon_topic_view.xml | 106 -------------- .../coming_soon_topic_view.xml | 106 -------------- .../res/layout/coming_soon_topic_view.xml | 106 -------------- .../android/app/home/HomeActivityTest.kt | 129 +----------------- .../app/home/RecentlyPlayedFragmentTest.kt | 2 +- .../domain/topic/StoryProgressTestHelper.kt | 2 +- .../topic/StoryProgressTestHelperTest.kt | 2 +- 12 files changed, 38 insertions(+), 688 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt delete mode 100644 app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt delete mode 100644 app/src/main/res/layout-land/coming_soon_topic_view.xml delete mode 100644 app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml delete mode 100644 app/src/main/res/layout/coming_soon_topic_view.xml 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 2ac6d0a9a63..192436cd655 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 @@ -1,6 +1,5 @@ package org.oppia.android.app.home -import android.util.Log import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -14,7 +13,6 @@ import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID import org.oppia.android.app.fragment.FragmentScope import org.oppia.android.app.home.topiclist.AllTopicsViewModel -import org.oppia.android.app.home.topiclist.ComingSoonTopicsListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryListViewModel import org.oppia.android.app.home.topiclist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.TopicListAdapter @@ -24,7 +22,6 @@ import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.shim.IntentFactoryShim @@ -58,7 +55,6 @@ class HomeFragmentPresenter @Inject constructor( private val routeToTopicListener = activity as RouteToTopicListener private val itemList: MutableList = ArrayList() private val promotedStoryList: MutableList = ArrayList() - private val comingSoonTopicList: MutableList = ArrayList() private lateinit var welcomeViewModel: WelcomeViewModel private lateinit var promotedStoryListViewModel: PromotedStoryListViewModel private lateinit var allTopicsViewModel: AllTopicsViewModel @@ -67,7 +63,6 @@ class HomeFragmentPresenter @Inject constructor( private var internalProfileId: Int = -1 private lateinit var profileId: ProfileId private lateinit var profileName: String - private var promotedStoriesType = PromotedStoriesType.PromotedStoriesTypeCase.PROMOTEDSTORIESTYPE_NOT_SET fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { binding = HomeFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) @@ -88,7 +83,7 @@ class HomeFragmentPresenter @Inject constructor( itemList.add(welcomeViewModel) itemList.add(promotedStoryListViewModel) itemList.add(allTopicsViewModel) - topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList,comingSoonTopicList) + topicListAdapter = TopicListAdapter(activity, itemList, promotedStoryList) val spanCount = activity.resources.getInteger(R.integer.home_span_count) topicListAdapter.setSpanCount(spanCount) @@ -151,10 +146,6 @@ class HomeFragmentPresenter @Inject constructor( topicListController.getTopicList().toLiveData() } - private val comingSoontopicListSummaryResultLiveData: LiveData> by lazy { - topicListController.getComingSoonTopicList() - } - private fun subscribeToTopicList() { getAssumedSuccessfulTopicList().observe( fragment, @@ -173,24 +164,6 @@ class HomeFragmentPresenter @Inject constructor( ) } - private fun subscribeToComingSoonTopicList() { - getAssumedSuccessfulComingSoonTopicList().observe( - fragment, - Observer { result -> - for (topicSummary in result.topicSummaryList) { - val comingSoontopicViewModel = - ComingSoonTopicsListViewModel( - topicSummary, - topicEntityType, - fragment as TopicSummaryClickListener - ) - comingSoonTopicList.add(comingSoontopicViewModel) - } - topicListAdapter.notifyItemChanged(1) - } - ) - } - private fun getAssumedSuccessfulTopicList(): LiveData { // If there's an error loading the data, assume the default. return Transformations.map(topicListSummaryResultLiveData) { @@ -198,13 +171,6 @@ class HomeFragmentPresenter @Inject constructor( } } - private fun getAssumedSuccessfulComingSoonTopicList(): LiveData { - // If there's an error loading the data, assume the default. - return Transformations.map(comingSoontopicListSummaryResultLiveData) { - it.getOrDefault(TopicList.getDefaultInstance()) - } - } - private fun setProfileName() { if (::welcomeViewModel.isInitialized && ::profileName.isInitialized) { welcomeViewModel.profileName.set(profileName) @@ -229,54 +195,31 @@ class HomeFragmentPresenter @Inject constructor( fragment, Observer { promotedStoryList.clear() - promotedStoriesType = it.promotedStoriesType.promotedStoriesTypeCase - if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.RECENTLY_PLAYED){ - if (it.recentStoryCount != 0) { - it.recentStoryList.take(limit).forEach { promotedStory -> - val recentStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim, - promotedStoriesType - ) - recentStory.setPromotedStory(promotedStory) - promotedStoryList.add(recentStory) - } - }else { - it.olderStoryList.take(limit).forEach { promotedStory -> - val olderStory = PromotedStoryViewModel( - activity, - internalProfileId, - storyEntityType, - intentFactoryShim, - promotedStoriesType - ) - olderStory.setPromotedStory(promotedStory) - promotedStoryList.add(olderStory) - } + if (it.recentStoryCount != 0) { + it.recentStoryList.take(limit).forEach { promotedStory -> + val recentStory = PromotedStoryViewModel( + activity, + internalProfileId, + storyEntityType, + intentFactoryShim + ) + recentStory.setPromotedStory(promotedStory) + promotedStoryList.add(recentStory) } - topicListAdapter.notifyItemChanged(1) - }else if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED){ - + } else { // TODO(#936): Optimise this as part of recommended stories. - it.recommendedStoryList.take(limit).forEach { promotedStory -> - val recommendedStory = PromotedStoryViewModel( + it.olderStoryList.take(limit).forEach { promotedStory -> + val oldStory = PromotedStoryViewModel( activity, internalProfileId, storyEntityType, - intentFactoryShim, - promotedStoriesType + intentFactoryShim ) - recommendedStory.setPromotedStory(promotedStory) - promotedStoryList.add(recommendedStory) - + oldStory.setPromotedStory(promotedStory) + promotedStoryList.add(oldStory) } - topicListAdapter.notifyItemChanged(1) - }else if(it.promotedStoriesType.promotedStoriesTypeCase == PromotedStoriesType.PromotedStoriesTypeCase.COMING_SOON) { - subscribeToComingSoonTopicList() } - + topicListAdapter.notifyItemChanged(1) } ) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt deleted file mode 100644 index 9abcbb3f833..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicListAdapter.kt +++ /dev/null @@ -1,55 +0,0 @@ -package org.oppia.android.app.home.topiclist - -import android.content.Context -import android.content.res.Configuration -import android.content.res.Resources -import android.view.LayoutInflater -import android.view.ViewGroup -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.RecyclerView -import org.oppia.android.R -import org.oppia.android.databinding.ComingSoonTopicViewBinding -import org.oppia.android.databinding.PromotedStoryCardBinding - -/** Adapter to bind promoted stories to [RecyclerView] inside [HomeFragment] to create carousel. */ -class ComingSoonTopicListAdapter( - private val activity: AppCompatActivity, - private val itemList: MutableList -) : - RecyclerView.Adapter() { - - private var spanCount = 0 - - private val orientation = Resources.getSystem().configuration.orientation - - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { - val inflater = LayoutInflater.from(parent.context) - val binding = - ComingSoonTopicViewBinding.inflate( - inflater, - parent, - /* attachToParent= */ false - ) - return ComingSoonTopicsViewHolder(binding) - } - - override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { - (holder as ComingSoonTopicsViewHolder).bind(itemList[position]) - } - - override fun getItemCount(): Int { - return itemList.size - } - - fun setSpanCount(spanCount: Int) { - this.spanCount = spanCount - } - - inner class ComingSoonTopicsViewHolder( - val binding: ComingSoonTopicViewBinding - ) : RecyclerView.ViewHolder(binding.root) { - internal fun bind(comingSoonTopicsListViewModel: ComingSoonTopicsListViewModel) { - binding.viewModel = comingSoonTopicsListViewModel - } - } -} \ No newline at end of file diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt deleted file mode 100644 index dfbf7c79866..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/ComingSoonTopicsListViewModel.kt +++ /dev/null @@ -1,45 +0,0 @@ -package org.oppia.android.app.home.topiclist - -import android.graphics.Color -import androidx.annotation.ColorInt -import org.oppia.android.app.home.HomeItemViewModel -import org.oppia.android.app.model.TopicSummary -import java.util.* - -// TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. -// These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the -// mocks were not consistently darker. An alternative would be to specify both background colors together to ensure -// proper contrast with readable elements. - -/** The view model corresponding to coming soon topic summaries in the topic summary RecyclerView. */ -class ComingSoonTopicsListViewModel( - val topicSummary: TopicSummary, - val entityType: String, - private val topicSummaryClickListener: TopicSummaryClickListener -) : Observable() { - val name: String = topicSummary.name - val totalChapterCount: Int = topicSummary.totalChapterCount - @ColorInt - val backgroundColor: Int = retrieveBackgroundColor() - @ColorInt - val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() - - /** Callback from data-binding for when the summary tile is clicked. */ - fun clickOnSummaryTile() { - topicSummaryClickListener.onTopicSummaryClicked(topicSummary) - } - - @ColorInt - private fun retrieveBackgroundColor(): Int { - return topicSummary.topicThumbnail.backgroundColorRgb - } - - /** Returns a version of [backgroundColor] that is slightly darker. */ - private fun computeDarkerBackgroundColor(): Int { - val hsv = floatArrayOf(0f, 0f, 0f) - Color.colorToHSV(backgroundColor, hsv) - hsv[1] = (hsv[1] * DARKEN_SATURATION_MULTIPLIER).coerceIn(0f, 1f) - hsv[2] = (hsv[2] * DARKEN_VALUE_MULTIPLIER).coerceIn(0f, 1f) - return Color.HSVToColor(hsv) - } -} diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt deleted file mode 100644 index 10e3800728a..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedItemViewModel.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.oppia.android.app.home.topiclist - -import org.oppia.android.app.viewmodel.ObservableViewModel - -/** The root [ViewModel] for all individual items that may be displayed in home fragment recycler view. */ -abstract class PromotedItemViewModel : ObservableViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt index 870ee6698ca..4d4f5e2b2e6 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicListAdapter.kt @@ -2,7 +2,6 @@ package org.oppia.android.app.home.topiclist import android.content.Context import android.view.LayoutInflater -import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.recyclerview.widget.LinearLayoutManager @@ -10,7 +9,6 @@ import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.WelcomeViewModel -import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.PromotedStoryListBinding @@ -21,14 +19,12 @@ private const val VIEW_TYPE_WELCOME_MESSAGE = 1 private const val VIEW_TYPE_PROMOTED_STORY_LIST = 2 private const val VIEW_TYPE_ALL_TOPICS = 3 private const val VIEW_TYPE_TOPIC_LIST = 4 -private const val VIEW_TYPE_COMING_SOON_TOPIC_LIST = 5 /** Adapter to inflate different items/views inside [RecyclerView]. The itemList consists of various ViewModels. */ class TopicListAdapter( private val activity: AppCompatActivity, private val itemList: MutableList, - private val promotedStoryList: MutableList, - private val comingSoonTopicList: MutableList + private val promotedStoryList: MutableList ) : RecyclerView.Adapter() { @@ -90,8 +86,7 @@ class TopicListAdapter( (holder as PromotedStoryListViewHolder).bind( activity, itemList[position] as PromotedStoryListViewModel, - promotedStoryList, - comingSoonTopicList + promotedStoryList ) } VIEW_TYPE_ALL_TOPICS -> { @@ -143,65 +138,18 @@ class TopicListAdapter( internal fun bind( activity: AppCompatActivity, promotedStoryListViewModel: PromotedStoryListViewModel, - promotedStoryList: MutableList, - comingSoonTopicList: MutableList + promotedStoryList: MutableList ) { - binding.viewModel = promotedStoryListViewModel - - val horizontalLayoutManager = + if (activity.resources.getBoolean(R.bool.isTablet)) { + binding.itemCount = promotedStoryList.size + } + val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) + val horizontalLayoutManager = LinearLayoutManager(activity, LinearLayoutManager.HORIZONTAL, /* reverseLayout= */ false) - - if (promotedStoryList.size!=0) { - if (activity.resources.getBoolean(R.bool.isTablet)) { - binding.itemCount = promotedStoryList.size - } - when (promotedStoryList[0].promotedStoriesType) { - PromotedStoriesType.PromotedStoriesTypeCase.RECENTLY_PLAYED -> { - binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE - binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) - binding.viewAllTextView.visibility = View.VISIBLE - } - PromotedStoriesType.PromotedStoriesTypeCase.LAST_PLAYED -> { - binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE - binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recently_played_stories)) - binding.viewAllTextView.visibility = View.VISIBLE - } - PromotedStoriesType.PromotedStoriesTypeCase.RECOMMENDED -> { - binding.recentlyPlayedStoriesTextView.visibility = View.VISIBLE - binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.recommended_stories)) - binding.viewAllTextView.visibility = View.INVISIBLE - } - else -> { - binding.recentlyPlayedStoriesTextView.visibility = View.GONE - binding.viewAllTextView.visibility = View.GONE - } - } - val promotedStoryAdapter = PromotedStoryListAdapter(activity, promotedStoryList) - - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = promotedStoryAdapter - } - }else if (comingSoonTopicList.size!=0){ - - if (activity.resources.getBoolean(R.bool.isTablet)) { - binding.itemCount = comingSoonTopicList.size - } - - binding.recentlyPlayedStoriesTextView.setText(activity.getString(R.string.coming_soon)) - binding.viewAllTextView.visibility = View.INVISIBLE - - val comingSoonTopicListAdapter = ComingSoonTopicListAdapter(activity, comingSoonTopicList) - comingSoonTopicListAdapter.setSpanCount(spanCount) - - binding.promotedStoryListRecyclerView.apply { - layoutManager = horizontalLayoutManager - adapter = comingSoonTopicListAdapter - } - }else{ - binding.recentlyPlayedStoriesTextView.visibility = View.GONE - binding.viewAllTextView.visibility = View.GONE + binding.promotedStoryListRecyclerView.apply { + layoutManager = horizontalLayoutManager + adapter = promotedStoryAdapter } /* diff --git a/app/src/main/res/layout-land/coming_soon_topic_view.xml b/app/src/main/res/layout-land/coming_soon_topic_view.xml deleted file mode 100644 index e3be77ddd88..00000000000 --- a/app/src/main/res/layout-land/coming_soon_topic_view.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml b/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml deleted file mode 100644 index e3be77ddd88..00000000000 --- a/app/src/main/res/layout-sw600dp-land/coming_soon_topic_view.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/layout/coming_soon_topic_view.xml b/app/src/main/res/layout/coming_soon_topic_view.xml deleted file mode 100644 index e3be77ddd88..00000000000 --- a/app/src/main/res/layout/coming_soon_topic_view.xml +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - 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 389eab6ee5f..81c3aea9dff 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 @@ -10,7 +10,6 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.pressBack import androidx.test.espresso.action.ViewActions.click -import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition import androidx.test.espresso.intent.Intents @@ -18,11 +17,9 @@ 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.hasDescendant import androidx.test.espresso.matcher.ViewMatchers.isDisplayed import androidx.test.espresso.matcher.ViewMatchers.isRoot -import androidx.test.espresso.matcher.ViewMatchers.withEffectiveVisibility import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.espresso.matcher.ViewMatchers.withParent import androidx.test.espresso.matcher.ViewMatchers.withText @@ -45,7 +42,6 @@ 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.home.recentlyplayed.RecentlyPlayedActivity -import org.oppia.android.app.model.ProfileId import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.profile.ProfileChooserActivity import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPosition @@ -71,10 +67,7 @@ import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule import org.oppia.android.domain.question.QuestionModule -import org.oppia.android.domain.topic.FRACTIONS_STORY_ID_0 -import org.oppia.android.domain.topic.FRACTIONS_TOPIC_ID import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule -import org.oppia.android.domain.topic.StoryProgressTestHelper import org.oppia.android.domain.topic.TEST_STORY_ID_0 import org.oppia.android.domain.topic.TEST_TOPIC_ID_0 import org.oppia.android.testing.TestAccessibilityModule @@ -116,8 +109,6 @@ class HomeActivityTest { @Inject lateinit var profileTestHelper: ProfileTestHelper - @Inject - lateinit var storyProgressTestHelper: StoryProgressTestHelper @Inject lateinit var context: Context @@ -126,7 +117,6 @@ class HomeActivityTest { private val internalProfileId: Int = 1 private lateinit var oppiaClock: OppiaClock - private lateinit var profileId: ProfileId @Before fun setUp() { @@ -134,7 +124,6 @@ class HomeActivityTest { setUpTestApplicationComponent() testCoroutineDispatchers.registerIdlingResource() profileTestHelper.initializeProfiles() - profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() FirebaseApp.initializeApp(context) } @@ -250,14 +239,6 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysRecentlyPlayedStoriesText() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -279,14 +260,6 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_displaysViewAllText() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -300,58 +273,8 @@ class HomeActivityTest { } } - @Test - fun testHomeActivity_recyclerViewIndex1_displaysRecommendedStoriesText() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - launch(createHomeActivityIntent(internalProfileId)).use { - testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 1, - R.id.recently_played_stories_text_view - ) - ).check( - matches( - withText(R.string.recommended_stories) - ) - ) - } - } - - @Test - fun testHomeActivity_recyclerViewIndex1_forRecommendedStories_hideViewAll() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - launch(createHomeActivityIntent(internalProfileId)).use { - testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - - onView(allOf(withId(R.id.view_all_text_view), - withEffectiveVisibility(ViewMatchers.Visibility.GONE))) - } - } - @Test fun testHomeActivity_recyclerViewIndex1_clickViewAll_opensRecentlyPlayedActivity() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -368,14 +291,6 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_chapterNameIsCorrect() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView( @@ -385,20 +300,12 @@ class HomeActivityTest { atPosition(R.id.home_recycler_view, 1) ) ) - ).check(matches(hasDescendant(withText(containsString("What is a Fraction"))))) + ).check(matches(hasDescendant(withText(containsString("Prototype Exploration"))))) } } @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_storyNameIsCorrect() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -406,7 +313,7 @@ class HomeActivityTest { ) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( matches( - withText(containsString("Matthew Goes to the Bakery")) + withText(containsString("First Story")) ) ) } @@ -414,14 +321,6 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_configurationChange_promotedCard_storyNameIsCorrect() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -430,7 +329,7 @@ class HomeActivityTest { onView(isRoot()).perform(orientationLandscape()) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.story_name_text_view)).check( matches( - withText(containsString("Matthew Goes to the Bakery")) + withText(containsString("First Story")) ) ) } @@ -438,14 +337,6 @@ class HomeActivityTest { @Test fun testHomeActivity_recyclerViewIndex1_clickPromotedStory_opensTopicActivity() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -461,21 +352,13 @@ class HomeActivityTest { ).perform(click()) intended(hasComponent(TopicActivity::class.java.name)) intended(hasExtra(TopicActivity.getProfileIdKey(), internalProfileId)) - intended(hasExtra(TopicActivity.getTopicIdKey(), FRACTIONS_TOPIC_ID)) - intended(hasExtra(TopicActivity.getStoryIdKey(), FRACTIONS_STORY_ID_0)) + intended(hasExtra(TopicActivity.getTopicIdKey(), TEST_TOPIC_ID_0)) + intended(hasExtra(TopicActivity.getStoryIdKey(), TEST_STORY_ID_0)) } } @Test fun testHomeActivity_recyclerViewIndex1_promotedCard_topicNameIsCorrect() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( - profileId, - timestampOlderThanAWeek = false - ) - storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - timestampOlderThanAWeek = true - ) launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)).perform( @@ -483,7 +366,7 @@ class HomeActivityTest { ) onView(atPositionOnView(R.id.home_recycler_view, 1, R.id.topic_name_text_view)).check( matches( - withText(containsString("Fractions")) + withText(containsString("FIRST TEST TOPIC")) ) ) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt index 25813417752..04abf39977b 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/RecentlyPlayedFragmentTest.kt @@ -119,7 +119,7 @@ class RecentlyPlayedFragmentTest { profileTestHelper.initializeProfiles() testCoroutineDispatchers.registerIdlingResource() profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId, timestampOlderThanAWeek = false ) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index c98737e53a2..bae93039f53 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -152,7 +152,7 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. */ - fun markTopicPlayedForFractionsStory0Exploration0( + fun markRecentlyPlayedForFractionsStory0Exploration0( profileId: ProfileId, timestampOlderThanAWeek: Boolean ) { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 428b6ce2d83..a698b5112be 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -620,7 +620,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getOngoingStoryListIsCorrect() { - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId, /* timestampOlderThanAWeek= */ false ) From e9a1ed140ed22e5767029ce4a7997ae5d5d375ff Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 17:22:47 +0530 Subject: [PATCH 058/248] Removed UI implementation from this PR --- .../app/home/topiclist/PromotedStoryViewModel.kt | 4 +--- .../testing/StateFragmentTestActivityPresenter.kt | 7 +------ .../android/app/testing/TopicTestActivityForStory.kt | 1 - ...ttom_left_rounded_rect_coming_soon_background.xml | 12 ------------ .../main/res/layout/fraction_interaction_item.xml | 4 ++-- app/src/main/res/layout/promoted_story_list.xml | 1 - app/src/main/res/values/strings.xml | 1 - .../android/app/testing/RecentlyPlayedSpanTest.kt | 2 +- 8 files changed, 5 insertions(+), 27 deletions(-) delete mode 100644 app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt index 6153b25fb95..749f0f8e513 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt @@ -5,7 +5,6 @@ import androidx.databinding.ObservableField import androidx.lifecycle.LiveData import androidx.lifecycle.ViewModel import org.oppia.android.app.home.RouteToTopicPlayStoryListener -import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel @@ -17,8 +16,7 @@ class PromotedStoryViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, val entityType: String, - private val IntentFactoryShim: IntentFactoryShim, - val promotedStoriesType: PromotedStoriesType.PromotedStoriesTypeCase + private val IntentFactoryShim: IntentFactoryShim ) : ObservableViewModel(), RouteToTopicPlayStoryListener { diff --git a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt index e94cda7bdf1..6a366fda7f4 100644 --- a/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt +++ b/app/src/main/java/org/oppia/android/app/player/state/testing/StateFragmentTestActivityPresenter.kt @@ -106,12 +106,7 @@ class StateFragmentTestActivityPresenter @Inject constructor( ) { getStateFragmentTestViewModel().hasExplorationStarted.set(true) - val stateFragment = StateFragment.newInstance( - profileId, - topicId, - storyId, - explorationId - ) + val stateFragment = StateFragment.newInstance(profileId, topicId, storyId, explorationId) activity.supportFragmentManager.beginTransaction().add( R.id.state_fragment_placeholder, stateFragment diff --git a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt index 5f3b5e96f30..ad9879f1943 100644 --- a/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt +++ b/app/src/main/java/org/oppia/android/app/testing/TopicTestActivityForStory.kt @@ -83,4 +83,3 @@ class TopicTestActivityForStory : ) } } - diff --git a/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml b/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml deleted file mode 100644 index 9de21a84bd1..00000000000 --- a/app/src/main/res/drawable/bottom_left_rounded_rect_coming_soon_background.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/app/src/main/res/layout/fraction_interaction_item.xml b/app/src/main/res/layout/fraction_interaction_item.xml index e215fd8cfe1..5eeb801f244 100644 --- a/app/src/main/res/layout/fraction_interaction_item.xml +++ b/app/src/main/res/layout/fraction_interaction_item.xml @@ -28,11 +28,11 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/edit_text_background" - android:digits="0123456789/-" + android:digits="0123456789/- " android:fontFamily="sans-serif" android:hint="@{viewModel.hintText}" android:imeOptions="actionDone" - android:inputType="text" + android:inputType="date" android:longClickable="false" android:maxLength="200" android:minHeight="48dp" diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 136d10d29ee..011a24327e1 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -11,7 +11,6 @@ Write numbers with units here. Enable audio voiceover for this lesson. Recently-Played Stories - Last-Played Stories View All Played within the Last Week Played within the Last Month diff --git a/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt b/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt index 4c4356e83fc..614a235415a 100644 --- a/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt +++ b/app/src/test/java/org/oppia/android/app/testing/RecentlyPlayedSpanTest.kt @@ -84,7 +84,7 @@ class RecentlyPlayedSpanTest { setUpTestApplicationComponent() testCoroutineDispatchers.registerIdlingResource() profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - storyProgressTestHelper.markTopicPlayedForFractionsStory0Exploration0( + storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId, timestampOlderThanAWeek = false ) From f164aa98a72f7cc18b0647acf2bd92c154559750 Mon Sep 17 00:00:00 2001 From: Veena Date: Thu, 17 Dec 2020 17:24:43 +0530 Subject: [PATCH 059/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 31 ------------------- 1 file changed, 31 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 4ff168d5592..da19136e299 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -336,37 +336,6 @@ class TopicListControllerTest { verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) } -// @Test -// fun testRetrieveRecommendedStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_recommendedListCorrect() { -// storyProgressController.recordCompletedChapter( -// profileId0, -// FRACTIONS_TOPIC_ID, -// FRACTIONS_STORY_ID_0, -// FRACTIONS_EXPLORATION_ID_0, -// getCurrentTimestamp() -// ) -// testCoroutineDispatchers.runCurrent() -// -// storyProgressController.recordRecentlyPlayedChapter( -// profileId0, -// FRACTIONS_TOPIC_ID, -// FRACTIONS_STORY_ID_0, -// FRACTIONS_EXPLORATION_ID_1, -// getCurrentTimestamp() -// ) -// testCoroutineDispatchers.runCurrent() -// -// topicListController.getOngoingStoryList(profileId0).toLiveData() -// .observeForever(mockOngoingStoryListObserver) -// testCoroutineDispatchers.runCurrent() -// -// verifyGetOngoingStoryListSucceeded() -// -// val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() -// assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) -// verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) -// } - @Test fun testRetrieveRecommendedStoryList_markAllChaptersCompletedInFractions_recommendedListIsCorrect() { storyProgressController.recordCompletedChapter( From 0026e36a7454cbf0e0c9a374c52118290d59718b Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 13:25:04 -0800 Subject: [PATCH 060/248] Remove test helper for home fragment --- .../org/oppia/android/testing/home/HomeFragmentTestHelper.kt | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt diff --git a/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt deleted file mode 100644 index 5b301f63709..00000000000 --- a/testing/src/main/java/org/oppia/android/testing/home/HomeFragmentTestHelper.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.oppia.android.testing.home - -/** This helper allows tests to easily set various HomeFragment states. */ -class HomeFragmentTestHelper { -} From a2644420df7117b636228d9bfdca6c45c17b9615 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 16:52:44 -0800 Subject: [PATCH 061/248] Add completing all topics to story progress test helper --- .../domain/topic/StoryProgressTestHelper.kt | 81 ++++++++++++++++++- .../topic/StoryProgressTestHelperTest.kt | 37 +++++++++ 2 files changed, 117 insertions(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index bae93039f53..c0aef83f2a8 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -90,7 +90,6 @@ class StoryProgressTestHelper @Inject constructor( FRACTIONS_EXPLORATION_ID_0, timestamp ) - storyProgressController.recordCompletedChapter( profileId, FRACTIONS_TOPIC_ID, @@ -100,6 +99,86 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** Marks full story progress for a particular profile. */ + fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + markFullTopicProgressForFractions(profileId, timestampOlderThanAWeek) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_3, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_4, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_5, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_1, + RATIOS_EXPLORATION_ID_2, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_1, + RATIOS_EXPLORATION_ID_3, + timestamp + ) + } + /** Marks one story progress full in ratios exploration for a particular profile. */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index a698b5112be..e3ff49082ab 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -491,6 +491,43 @@ class StoryProgressTestHelperTest { assertThat(storySummary.chapterList[1].chapterPlayState).isEqualTo(ChapterPlayState.COMPLETED) } + @Test + fun testProgressTestHelper_markProgressForAllTopics_getOngoingTopicListIsEmpty() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanAWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicController.getOngoingTopicList( + profileId + ).toLiveData().observeForever(mockOngoingTopicListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingTopicListSucceeded() + + val ongoingTopicList = ongoingTopicListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.topicList.size).isEqualTo(0) + } + + @Test + fun testProgressTestHelper_markProgressForAllTopics_getCompletedStoryListIsCorrect() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanAWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicController.getCompletedStoryList(profileId).toLiveData() + .observeForever(mockCompletedStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetCompletedStoryListSucceeded() + + val completedStoryList = completedStoryListResultCaptor.value.getOrThrow() + assertThat(completedStoryList.completedStoryList.size).isEqualTo(6) + } + @Test fun testProgressTestHelper_markPartialTopicProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( From 95d0af98c17ce5ac69f8821d0befa09e603db4ae Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 18:21:08 -0800 Subject: [PATCH 062/248] Add tests for no promtoed stories on home fragment and all topics completed --- .../android/app/home/HomeActivityTest.kt | 72 ++++++++++++++++++- .../topic/StoryProgressTestHelperTest.kt | 37 +++++++++- 2 files changed, 105 insertions(+), 4 deletions(-) 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 ee4c8fe1540..02ea6e4b128 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 @@ -10,6 +10,7 @@ import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView import androidx.test.espresso.Espresso.pressBack import androidx.test.espresso.action.ViewActions.click +import androidx.test.espresso.assertion.ViewAssertions.doesNotExist import androidx.test.espresso.assertion.ViewAssertions.matches import androidx.test.espresso.contrib.RecyclerViewActions.scrollToPosition import androidx.test.espresso.intent.Intents @@ -42,11 +43,13 @@ 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.home.recentlyplayed.RecentlyPlayedActivity +import org.oppia.android.app.model.ProfileId import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.profile.ProfileChooserActivity import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPosition import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPositionOnView import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasGridItemCount +import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasGridColumnCount import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.testing.HomeInjectionActivity import org.oppia.android.app.topic.TopicActivity @@ -68,6 +71,7 @@ import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.domain.topic.StoryProgressTestHelper import org.oppia.android.domain.topic.TEST_STORY_ID_0 import org.oppia.android.domain.topic.TEST_TOPIC_ID_0 import org.oppia.android.testing.TestAccessibilityModule @@ -109,6 +113,9 @@ class HomeActivityTest { @Inject lateinit var profileTestHelper: ProfileTestHelper + @Inject + lateinit var storyProgressTestHelper: StoryProgressTestHelper + @Inject lateinit var context: Context @@ -540,8 +547,69 @@ class HomeActivityTest { } } - // HomeActivity does not display promoted stories when the list is empty - // HomeActivity does not display topics list when there are no topics + @Test + fun testHomeActivity_allTopicsCompleted_hidesPromotedStories() { + storyProgressTestHelper.markFullProgressForAllTopics( + ProfileId.newBuilder().setInternalId(internalProfileId).build(), + timestampOlderThanAWeek = false + ) + testCoroutineDispatchers.runCurrent() + + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(1) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 2, + R.id.promoted_story_list_recycler_view + ) + ).check(doesNotExist()) + } + } + + @Test + fun testHomeActivity_allTopicsCompleted_displaysAllTopicsHeader() { + storyProgressTestHelper.markFullProgressForAllTopics( + ProfileId.newBuilder().setInternalId(internalProfileId).build(), + timestampOlderThanAWeek = false + ) + testCoroutineDispatchers.runCurrent() + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(2) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 2, + R.id.all_topics_text_view + ) + ).check( + matches(withText(R.string.all_topics)) + ) + } + } + + @Test + fun testHomeActivity_allTopicsCompleted_displaysTopicCards() { + storyProgressTestHelper.markFullProgressForAllTopics( + ProfileId.newBuilder().setInternalId(internalProfileId).build(), + timestampOlderThanAWeek = false + ) + testCoroutineDispatchers.runCurrent() + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(3) + ) + onView(withId(R.id.home_recycler_view)).check( + hasGridColumnCount(2)) + } + } private fun createHomeActivityIntent(profileId: Int): Intent { return HomeActivity.createHomeActivity(ApplicationProvider.getApplicationContext(), profileId) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index e3ff49082ab..d1e3cadebd3 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -28,6 +28,7 @@ import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic +import org.oppia.android.app.model.TopicList import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule @@ -88,6 +89,12 @@ class StoryProgressTestHelperTest { @Captor lateinit var ongoingTopicListResultCaptor: ArgumentCaptor> + @Mock + lateinit var mockTopicListObserver: Observer> + + @Captor + lateinit var topicListResultCaptor: ArgumentCaptor> + @Mock lateinit var mockStorySummaryObserver: Observer> @@ -492,7 +499,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markProgressForAllTopics_getOngoingTopicListIsEmpty() { + fun testProgressTestHelper_markFullProgressForAllTopics_getOngoingTopicListIsEmpty() { storyProgressTestHelper.markFullProgressForAllTopics( profileId, /* timestampOlderThanAWeek= */ false @@ -511,7 +518,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markProgressForAllTopics_getCompletedStoryListIsCorrect() { + fun testProgressTestHelper_markFullProgressForAllTopics_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullProgressForAllTopics( profileId, /* timestampOlderThanAWeek= */ false @@ -528,6 +535,24 @@ class StoryProgressTestHelperTest { assertThat(completedStoryList.completedStoryList.size).isEqualTo(6) } + @Test + fun testProgressTestHelper_markFullProgressForAllTopics_getTopicListIsCorrect() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanAWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getTopicList().toLiveData() + .observeForever(mockTopicListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetTopicListSucceeded() + + val topicList = topicListResultCaptor.value.getOrThrow() + assertThat(topicList.topicSummaryCount).isEqualTo(4) + } + @Test fun testProgressTestHelper_markPartialTopicProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( @@ -798,6 +823,14 @@ class StoryProgressTestHelperTest { assertThat(ongoingStoryListResultCaptor.value.isSuccess()).isTrue() } + private fun verifyGetTopicListSucceeded() { + verify( + mockTopicListObserver, + atLeastOnce() + ).onChanged(topicListResultCaptor.capture()) + assertThat(topicListResultCaptor.value.isSuccess()).isTrue() + } + // TODO(#89): Move this to a common test application component. @Module class TestModule { From 2570dde0c1fe603a2c5f56c7abb0feeefd5707d8 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 18:55:15 -0800 Subject: [PATCH 063/248] Address review comments --- .../app/databinding/ViewBindingAdapters.java | 10 +++++----- .../org/oppia/android/app/home/HomeViewModel.kt | 12 +++++++----- .../promotedlist/PromotedStoryListViewModel.kt | 15 +++++---------- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 6f9e967e919..f3f2813ab50 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -13,8 +13,8 @@ public final class ViewBindingAdapters { /** * BindingAdapter to set the height of a View. If this value is calculated in data fetching, the - * layout will require a default value since data fetching is not immediately evaluated with - * view layouts and measurements. + * layout will require a default value since binding adapters aren't called until after initial + * view measurements and layouts are formatted. */ @BindingAdapter("android:layout_height") public static void setLayoutHeight(@NonNull View view, float height) { @@ -24,9 +24,9 @@ public static void setLayoutHeight(@NonNull View view, float height) { } /** - * BindingAdapter to set the width of a View. If this value is calculated in data fetching, the - * layout will require a default value since data fetching is not immediately evaluated with - * view layouts and measurements. + * BindingAdapter to set the height of a Width. If this value is calculated in data fetching, the + * layout will require a default value since binding adapters aren't called until after initial + * view measurements and layouts are formatted. */ @BindingAdapter("android:layout_width") public static void setLayoutWidth(@NonNull View view, float width) { diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 2bfd9e5546f..3e7f24aff38 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -84,8 +84,9 @@ class HomeViewModel( /** * [LiveData] of the list of items displayed in the HomeFragment RecyclerView. The list backing this live data will - * automatically update if constituent parts of the UI change (e.g. if the promoted story list changes). - * */ + * automatically update if constituent parts of the UI change (e.g. if the promoted story list changes). If an error + * occurs or data providers are still pending, the list is empty and so the view shown will be empty. + */ val homeItemViewModelListLiveData: LiveData> by lazy { Transformations.map(homeItemViewModelListDataProvider.toLiveData()) { itemListResult -> if (itemListResult.isFailure()) { @@ -102,7 +103,7 @@ class HomeViewModel( /** * Returns a [HomeItemViewModel] corresponding to the welcome message (see [WelcomeViewModel]), or null if * the specified profile has insufficient information to show the welcome message. - * */ + */ private fun computeWelcomeViewModel(profile: Profile): HomeItemViewModel? { return if (profile.name.isNotEmpty()) { WelcomeViewModel(fragment, oppiaClock, profile.name) @@ -113,7 +114,7 @@ class HomeViewModel( * Returns a [HomeItemViewModel] corresponding to the promoted stories to be displayed for this learner * (see [PromotedStoryListViewModel]), or null if this profile does not have any promoted stories. * Promoted stories are determined by any recent stories started by this profile. - * */ + */ private fun computePromotedStoryListViewModel( ongoingStoryList: OngoingStoryList ): HomeItemViewModel? { @@ -158,7 +159,8 @@ class HomeViewModel( /** * Returns a list of [HomeItemViewModel]s corresponding to all the lesson topics available and to be * displayed on the home activity (see [TopicSummaryViewModel]) along with associated topics list header (see - * [AllTopicsViewModel]). Returns null if there are no lesson topics to display in the home fragment. + * [AllTopicsViewModel]). Returns an empty list if there are no topics to display to the learner (caused by + * either error or pending data providers). */ private fun computeAllTopicsItemsViewModelList( topicList: TopicList diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index e62f61ae0a5..d4140f12ad4 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -7,27 +7,22 @@ import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.shim.IntentFactoryShim -/** [ViewModel] promoted story list in [HomeFragment]. */ +/** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, private val intentFactoryShim: IntentFactoryShim, val promotedStoryList: List -) : - HomeItemViewModel(), +) : HomeItemViewModel(), RouteToRecentlyPlayedListener { /** - * Returns an [Int] for the padding placed at the start of the promoted stories list layout displayed on the - * home activity. + * Returns the padding placed at the start of the promoted stories list. */ - fun getStartPadding(): Int { - return activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - } + fun getStartPadding(): Int = activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) /** - * Returns an [Int] for the padding placed at the end of the promoted stories list layout displayed on the - * home activity, centering the story if there is only one promoted story. + * Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. */ fun getEndPadding(): Int { return if (promotedStoryList.size > 1) { From 5633194f20f99131e643e0fdfebb49fb6a7be3b4 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 19:17:37 -0800 Subject: [PATCH 064/248] Set View All button visiblity in view model --- .../PromotedStoryListViewModel.kt | 21 +++++++++++++++++++ .../res/layout-land/promoted_story_list.xml | 1 + .../promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 1 + 5 files changed, 25 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index d4140f12ad4..81c6c23ee1b 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -1,5 +1,8 @@ package org.oppia.android.app.home.promotedlist +import android.content.res.Configuration +import android.content.res.Resources +import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel import org.oppia.android.R @@ -32,6 +35,24 @@ class PromotedStoryListViewModel( } } + /** + * Determines and returns the visibility for the "View All" button. + */ + fun getButtonVisibility(): Int { + if (activity.resources.getBoolean(R.bool.isTablet)) { + when (Resources.getSystem().configuration.orientation) { + Configuration.ORIENTATION_PORTRAIT -> { + return if (promotedStoryList.size > 2) View.VISIBLE else View.INVISIBLE + } + Configuration.ORIENTATION_LANDSCAPE -> { + return if (promotedStoryList.size > 3) View.VISIBLE else View.INVISIBLE + } + else -> View.VISIBLE + } + } + return View.VISIBLE + } + fun clickOnViewAll() { routeToRecentlyPlayed() } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 38465a9344e..de53f98d6d5 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -46,6 +46,7 @@ android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" + android:visibility="@{viewModel.getButtonVisibility()}" android:textColor="@color/oppiaPrimaryDark" android:textSize="14sp" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 068c674d0e7..6ebd9c23e78 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -46,7 +46,7 @@ android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" - android:visibility="@{viewModel.promotedStoryList.size() > 3 ? View.VISIBLE : View.INVISIBLE}" + android:visibility="@{viewModel.getButtonVisibility()}" android:textColor="@color/oppiaPrimaryDark" android:textSize="14sp" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index b5d470c4672..6014da0fbf2 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -46,7 +46,7 @@ android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" - android:visibility="@{viewModel.promotedStoryList.size() > 2 ? View.VISIBLE : View.INVISIBLE}" + android:visibility="@{viewModel.getButtonVisibility()}" android:textColor="@color/oppiaPrimaryDark" android:textSize="14sp" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 1bed2a73de6..129adcf4fa0 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -46,6 +46,7 @@ android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" + android:visibility="@{viewModel.getButtonVisibility()}" android:textColor="@color/oppiaPrimaryDark" android:textSize="14sp" /> From f906d0daa003c06e7fd06f739db9498aed2dd8c5 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 19:26:57 -0800 Subject: [PATCH 065/248] Fix linter issues --- .../java/org/oppia/android/app/home/HomeActivityTest.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 02ea6e4b128..5023c3e66e4 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 @@ -48,8 +48,8 @@ import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfi import org.oppia.android.app.profile.ProfileChooserActivity import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPosition import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.atPositionOnView -import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasGridItemCount import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasGridColumnCount +import org.oppia.android.app.recyclerview.RecyclerViewMatcher.Companion.hasGridItemCount import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.testing.HomeInjectionActivity import org.oppia.android.app.topic.TopicActivity @@ -607,7 +607,8 @@ class HomeActivityTest { scrollToPosition(3) ) onView(withId(R.id.home_recycler_view)).check( - hasGridColumnCount(2)) + hasGridColumnCount(2) + ) } } From d971e13d640c22f373a756c15427d6c11ceadb33 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 17 Dec 2020 19:37:33 -0800 Subject: [PATCH 066/248] Add comment to explain test topic exploration progress in test helper --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index c0aef83f2a8..6b7e2b3d954 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -107,6 +107,8 @@ class StoryProgressTestHelper @Inject constructor( getOldTimestamp() } markFullTopicProgressForFractions(profileId, timestampOlderThanAWeek) + // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure + // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. storyProgressController.recordCompletedChapter( profileId, TEST_TOPIC_ID_0, From 440113727b2704e014247675cbb0e19b17b7a3c7 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 18 Dec 2020 12:20:00 +0530 Subject: [PATCH 067/248] renamed functions --- .../domain/topic/StoryProgressController.kt | 11 +- .../domain/topic/TopicListController.kt | 162 +++++++++++++++--- model/src/main/proto/topic.proto | 30 +++- 3 files changed, 167 insertions(+), 36 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 31bf6584d80..798d624cdff 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -13,7 +13,7 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.logging.ConsoleLogger -import java.util.* +import java.util.Date import javax.inject.Inject import javax.inject.Singleton @@ -111,8 +111,10 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp( - Date().time) + val topicProgressBuilder = + TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp( + Date().time + ) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -193,7 +195,8 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgressBuilder.build()) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(lastPlayedTimestamp) + val topicProgressBuilder = + TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(lastPlayedTimestamp) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 47455650786..7070bd55801 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -14,6 +14,7 @@ import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.model.RecommendedStoryList import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicProgress @@ -120,6 +121,23 @@ class TopicListController @Inject constructor( } } + /** + * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. + * The total number of promoted stories should correspond to the ongoing story count within the + * [TopicList] returned by [getTopicList]. + * + * @param profileId the ID corresponding to the profile for which [PromotedStory] needs to be + * fetched. + * @return a [DataProvider] for an [OngoingStoryList]. + */ + fun getRecommendedActivityList(profileId: ProfileId): DataProvider { + return storyProgressController.retrieveTopicProgressListDataProvider(profileId) + .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { + val ongoingStoryList = createRecommendedActivityList(it) + AsyncResult.success(ongoingStoryList) + } + } + private fun createTopicList(): TopicList { val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! @@ -171,13 +189,105 @@ class TopicListController @Inject constructor( ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() + if (topicProgressList.isNotEmpty()) { + + val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + + sortedTopicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) + + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() + + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } + } + } + } + + return ongoingStoryListBuilder.build() + } + + private fun createRecommendedActivityList( + topicProgressList: List + ): RecommendedStoryList { + val recommendedStoryBuilder = RecommendedStoryList.newBuilder() + if (topicProgressList.isNotEmpty()) { Log.d("topic size", "" + topicProgressList.size) if (topicProgressList.size == 1) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setRecommended(true) - ) - ongoingStoryListBuilder.addAllRecommendedStory( +// recommendedStoryBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setRecommended(true) +// ) + recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList ) @@ -188,9 +298,9 @@ class TopicListController @Inject constructor( sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setRecentlyPlayed(true) - ) +// recommendedStoryBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setRecentlyPlayed(true) +// ) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId @@ -238,9 +348,9 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.explorationId ) if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) + recommendedStoryBuilder.addRecentlyPlayed(promotedStory) } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) + recommendedStoryBuilder.addOlderStory(promotedStory) } } } else if (lastCompletedChapterProgress != null && @@ -263,40 +373,40 @@ class TopicListController @Inject constructor( nextChapterSummary.explorationId ) if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) + recommendedStoryBuilder.addRecentlyPlayed(promotedStory) } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) + recommendedStoryBuilder.addOlderStory(promotedStory) } } } } } - if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount > 0 - && ongoingStoryListBuilder.recommendedStoryCount == 0 + if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount > 0 + && recommendedStoryBuilder.suggestStoryCount == 0 ) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setLastPlayed(true) - ) +// recommendedStoryBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setLastPlayed(true) +// ) } - if (ongoingStoryListBuilder.recentStoryCount == 0 && ongoingStoryListBuilder.olderStoryCount == 0) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setRecommended(true) - ) - ongoingStoryListBuilder.addAllRecommendedStory( + if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount == 0) { +// recommendedStoryBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setRecommended(true) +// ) + recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList ) ) - if (ongoingStoryListBuilder.recommendedStoryCount == 0) { - ongoingStoryListBuilder.setPromotedStoriesType( - PromotedStoriesType.newBuilder().setComingSoon(true) - ) + if (recommendedStoryBuilder.suggestStoryCount == 0) { +// recommendedStoryBuilder.setPromotedStoriesType( +// PromotedStoriesType.newBuilder().setComingSoon(true) +// ) Log.d("topic =", " coming" + " " + "soon") } } } } - return ongoingStoryListBuilder.build() + return recommendedStoryBuilder.build() } private fun createRecommendedStoryList( diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 7a88b3cf82a..4800b58fda1 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -156,14 +156,8 @@ message OngoingStoryList { // Ongoing stories from within the last 7 days. repeated PromotedStory recent_story = 1; - // Recommended stories based on user's interest. - repeated PromotedStory recommended_story = 2; - // Other ongoing stories from longer than 7 days ago. repeated PromotedStory older_story = 3; - - // Indicates type of story promoted - PromotedStoriesType promoted_stories_type = 5; } // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, @@ -255,6 +249,30 @@ message TopicProgress { int64 last_played_timestamp = 5; } +message RecommendedActivityList { + oneof recommendation_type { + RecommendedStoryList recommended_story_list = 1; + ComingSoonTopicList coming_soon_topic_list = 2; + } +} + +message RecommendedStoryList { + repeated PromotedStory recently_played = 1; + repeated PromotedStory older_story = 2; + repeated PromotedStory suggest_story = 3; +} + +message ComingSoonTopicList { + repeated UpcomingTopic upcoming_topic = 1; +} + +message UpcomingTopic { + string topic_id = 1; + string name = 2; + int32 version = 3; + int64 estimated_release_unix_timestamp = 4; + LessonThumbnail lesson_thumbnail = 5; +} // A structure corresponding to the Promoted Stories. This structure is set up // to properly account for recently_played stories, for recommended stories // and for coming soon topics. From 948cfb1fe70f525809245306e41f93cbd0142692 Mon Sep 17 00:00:00 2001 From: Veena Date: Mon, 21 Dec 2020 15:44:13 +0530 Subject: [PATCH 068/248] updated testcases --- .../domain/topic/TopicListController.kt | 79 +++++--- .../domain/topic/TopicListControllerTest.kt | 183 ++++++++++-------- 2 files changed, 151 insertions(+), 111 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 7070bd55801..16fd177fe0f 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -8,17 +8,20 @@ import org.json.JSONObject import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.ChapterProgress import org.oppia.android.app.model.ChapterSummary +import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.RecommendedStoryList import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.model.UpcomingTopic import org.oppia.android.domain.util.JsonAssetRetriever import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider @@ -72,6 +75,7 @@ val EXPLORATION_THUMBNAILS = mapOf( ) private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" +private const val GET_COMING_SOON_TOPIC_LIST_PROVIDER_ID = "get_coming_soon_topic_list_provider_id" private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" @@ -100,8 +104,11 @@ class TopicListController @Inject constructor( * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to * [EVICTION_TIME_MILLIS] old. */ - fun getComingSoonTopicList(): LiveData> { - return MutableLiveData(AsyncResult.success(createComingSoonTopicList())) + fun getComingSoonTopicList(): DataProvider { + return dataProviders.createInMemoryDataProvider( + GET_COMING_SOON_TOPIC_LIST_PROVIDER_ID, + this::createComingSoonTopicList + ) } /** @@ -130,11 +137,11 @@ class TopicListController @Inject constructor( * fetched. * @return a [DataProvider] for an [OngoingStoryList]. */ - fun getRecommendedActivityList(profileId: ProfileId): DataProvider { + fun getRecommendedActivityList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { - val ongoingStoryList = createRecommendedActivityList(it) - AsyncResult.success(ongoingStoryList) + val recommendedActivityList = createRecommendedActivityList(it) + AsyncResult.success(recommendedActivityList) } } @@ -149,15 +156,16 @@ class TopicListController @Inject constructor( return topicListBuilder.build() } - private fun createComingSoonTopicList(): TopicList { + private fun createComingSoonTopicList(): ComingSoonTopicList { val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") - val topicListBuilder = TopicList.newBuilder() + val comingSoonTopicListBuilder = ComingSoonTopicList.newBuilder() for (i in 0 until topicIdJsonArray.length()) { - topicListBuilder.addTopicSummary(createTopicSummary(topicIdJsonArray.optString(i)!!)) + comingSoonTopicListBuilder.addUpcomingTopic(createUpcomingTopicSummary(topicIdJsonArray.optString(i)!!)) } - return topicListBuilder.build() + RecommendedActivityList.newBuilder().setComingSoonTopicList(comingSoonTopicListBuilder) + return comingSoonTopicListBuilder.build() } private fun createTopicSummary(topicId: String): TopicSummary { @@ -166,6 +174,12 @@ class TopicListController @Inject constructor( return createTopicSummaryFromJson(topicId, topicJson) } + private fun createUpcomingTopicSummary(topicId: String): UpcomingTopic { + val topicJson = + jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!! + return createUpcomingTopicSummaryFromJson(topicId, topicJson) + } + private fun createTopicSummaryFromJson(topicId: String, jsonObject: JSONObject): TopicSummary { var totalChapterCount = 0 val storyData = jsonObject.getJSONArray("canonical_story_dicts") @@ -184,6 +198,24 @@ class TopicListController @Inject constructor( .build() } + private fun createUpcomingTopicSummaryFromJson(topicId: String, jsonObject: JSONObject): UpcomingTopic { + var totalChapterCount = 0 + val storyData = jsonObject.getJSONArray("canonical_story_dicts") + for (i in 0 until storyData.length()) { + totalChapterCount += storyData + .getJSONObject(i) + .getJSONArray("node_titles") + .length() + } + return UpcomingTopic.newBuilder() + .setTopicId(topicId) + .setName(jsonObject.getString("topic_name")) + .setVersion(jsonObject.optInt("version")) + .setEstimatedReleaseUnixTimestamp(Date().time) + .setLessonThumbnail(createTopicThumbnail(jsonObject)) + .build() + } + private fun createOngoingStoryListFromProgress( topicProgressList: List ): OngoingStoryList { @@ -278,20 +310,21 @@ class TopicListController @Inject constructor( private fun createRecommendedActivityList( topicProgressList: List - ): RecommendedStoryList { - val recommendedStoryBuilder = RecommendedStoryList.newBuilder() + ): RecommendedActivityList { + val recommendedActivityListBuilder = RecommendedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { + val recommendedStoryBuilder = RecommendedStoryList.newBuilder() + Log.d("topic size", "" + topicProgressList.size) if (topicProgressList.size == 1) { -// recommendedStoryBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setRecommended(true) -// ) + recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList ) ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } else { val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } @@ -380,33 +413,29 @@ class TopicListController @Inject constructor( } } } + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount > 0 && recommendedStoryBuilder.suggestStoryCount == 0 ) { -// recommendedStoryBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setLastPlayed(true) -// ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount == 0) { -// recommendedStoryBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setRecommended(true) -// ) - recommendedStoryBuilder.addAllSuggestStory( + recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList ) ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + if (recommendedStoryBuilder.suggestStoryCount == 0) { -// recommendedStoryBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setComingSoon(true) -// ) + recommendedActivityListBuilder.setComingSoonTopicList(createComingSoonTopicList()) Log.d("topic =", " coming" + " " + "soon") } } } } - return recommendedStoryBuilder.build() + return recommendedActivityListBuilder.build() } private fun createRecommendedStoryList( diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index da19136e299..9d014f24188 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -22,11 +22,13 @@ import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule +import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnailGraphic -import org.oppia.android.app.model.OngoingStoryList +import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.TopicList +import org.oppia.android.app.model.UpcomingTopic import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule @@ -77,13 +79,19 @@ class TopicListControllerTest { lateinit var mockTopicListObserver: Observer> @Mock - lateinit var mockOngoingStoryListObserver: Observer> + lateinit var mockComingSoonTopicListObserver: Observer> + + @Mock + lateinit var mockRecommendedActivityListObserver: Observer> @Captor lateinit var topicListResultCaptor: ArgumentCaptor> @Captor - lateinit var ongoingStoryListResultCaptor: ArgumentCaptor> + lateinit var comingSoonTopicListResultCaptor: ArgumentCaptor> + + @Captor + lateinit var recommendedActivityListResultCaptor: ArgumentCaptor> private lateinit var profileId0: ProfileId @@ -99,7 +107,7 @@ class TopicListControllerTest { // TODO(#15): Add tests for recommended lessons rather than promoted, and tests for the 'continue playing' LiveData // not providing any data for cases when there are no ongoing lessons. Also, add tests for other uncovered cases - // (such as having and not having lessons in either of the OngoingStoryList section, or AsyncResult errors). + // (such as having and not having lessons in either of the RecommendedActivityList section, or AsyncResult errors). @Test fun testRetrieveTopicList_isSuccessful() { @@ -290,7 +298,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecommendedStoryList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { + fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -300,16 +308,16 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recommendedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[1]) } @Test @@ -324,20 +332,20 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[1]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[1]) } @Test - fun testRetrieveRecommendedStoryList_markAllChaptersCompletedInFractions_recommendedListIsCorrect() { + fun testRetrieveSuggestedStoryList_markAllChaptersCompletedInFractions_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -356,14 +364,14 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) verifyDefaultRecommendedStoryListSucceeded() } @@ -396,16 +404,16 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(1) - verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recentStoryList[0]) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) } @Test @@ -438,20 +446,20 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[1]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) } @Test - fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { + fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -479,17 +487,17 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[2]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[2]) } @Test @@ -512,15 +520,15 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) } @Test @@ -561,21 +569,24 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(0) - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(0) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(0) - val comingSoontopicListLiveData = topicListController.getComingSoonTopicList() + val comingSoonTopicListLiveData = topicListController.getComingSoonTopicList().toLiveData() - val topicListResult = comingSoontopicListLiveData.value - assertThat(topicListResult).isNotNull() - assertThat(topicListResult!!.isSuccess()).isTrue() + comingSoonTopicListLiveData.observeForever(mockComingSoonTopicListObserver) + testCoroutineDispatchers.runCurrent() + + verify(mockComingSoonTopicListObserver).onChanged(comingSoonTopicListResultCaptor.capture()) + val comingSoonTopicListResult = comingSoonTopicListResultCaptor.value + assertThat(comingSoonTopicListResult!!.isSuccess()).isTrue() } @Test @@ -607,41 +618,41 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId0).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - assertThat(ongoingTopicList.olderStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.olderStoryList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.olderStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[0]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.olderStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.olderStoryList[0]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.olderStoryList[1]) + verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) } - private fun verifyGetOngoingStoryListSucceeded() { + private fun verifyGetRecommendedActivityListSucceeded() { verify( - mockOngoingStoryListObserver, + mockRecommendedActivityListObserver, atLeastOnce() - ).onChanged(ongoingStoryListResultCaptor.capture()) - assertThat(ongoingStoryListResultCaptor.value.isSuccess()).isTrue() + ).onChanged(recommendedActivityListResultCaptor.capture()) + assertThat(recommendedActivityListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyDefaultOngoingStoryListSucceeded() { - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(ongoingTopicList.recentStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recentStoryList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[3]) + private fun verifyDefaultRecommendedActivityListSucceeded() { + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(4) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) + verifyOngoingStoryAsSecondTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) + verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[2]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[3]) } private fun verifyDefaultRecommendedStoryListSucceeded() { - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recommendedStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recommendedStoryList[0]) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { From 05d0057fbb8102a7aa94207fa56cc14e93962a16 Mon Sep 17 00:00:00 2001 From: Veena Date: Mon, 21 Dec 2020 16:09:36 +0530 Subject: [PATCH 069/248] Update topic.proto --- model/src/main/proto/topic.proto | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 4800b58fda1..7bae40b2155 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -249,6 +249,7 @@ message TopicProgress { int64 last_played_timestamp = 5; } +// Represents the recommended stories and coming soon topics. message RecommendedActivityList { oneof recommendation_type { RecommendedStoryList recommended_story_list = 1; @@ -256,16 +257,26 @@ message RecommendedActivityList { } } +// Corresponds to the list of stories the player is currently playing across all topics and Recommended stories. message RecommendedStoryList { + // Ongoing stories from within the last 7 days. repeated PromotedStory recently_played = 1; + + // Other ongoing stories from longer than 7 days ago. repeated PromotedStory older_story = 2; + + // Stories recommended to the user. repeated PromotedStory suggest_story = 3; } + +// Corresponds to the list of Coming soon topics that can be shown on the homescreen. message ComingSoonTopicList { +// Upcoming topics for the user. repeated UpcomingTopic upcoming_topic = 1; } +// Represents upcoming topics message UpcomingTopic { string topic_id = 1; string name = 2; From 5327b7435e0dde9eb7bac806f4094549fc87e170 Mon Sep 17 00:00:00 2001 From: Veena Date: Mon, 21 Dec 2020 16:44:30 +0530 Subject: [PATCH 070/248] updated proto. --- .../domain/topic/TopicListController.kt | 13 +++--- .../domain/topic/TopicListControllerTest.kt | 42 ++++++++--------- model/src/main/proto/topic.proto | 46 +++++++------------ 3 files changed, 44 insertions(+), 57 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 16fd177fe0f..d49ccbf8d52 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -13,7 +13,6 @@ import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.model.PromotedStoriesType import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.RecommendedStoryList @@ -381,9 +380,9 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.explorationId ) if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayed(promotedStory) + recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { - recommendedStoryBuilder.addOlderStory(promotedStory) + recommendedStoryBuilder.addOlderPlayedStory(promotedStory) } } } else if (lastCompletedChapterProgress != null && @@ -406,21 +405,21 @@ class TopicListController @Inject constructor( nextChapterSummary.explorationId ) if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayed(promotedStory) + recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { - recommendedStoryBuilder.addOlderStory(promotedStory) + recommendedStoryBuilder.addOlderPlayedStory(promotedStory) } } } } recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } - if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount > 0 + if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount > 0 && recommendedStoryBuilder.suggestStoryCount == 0 ) { recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } - if (recommendedStoryBuilder.recentlyPlayedCount == 0 && recommendedStoryBuilder.olderStoryCount == 0) { + if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0) { recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 9d014f24188..e0151108158 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -411,9 +411,9 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(1) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) } @Test @@ -453,9 +453,9 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) } @Test @@ -494,10 +494,10 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedList[2]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[2]) } @Test @@ -527,7 +527,7 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) } @@ -576,7 +576,7 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(0) val comingSoonTopicListLiveData = topicListController.getComingSoonTopicList().toLiveData() @@ -625,11 +625,11 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(1) - assertThat(recommendedActivityList.recommendedStoryList.olderStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.olderStoryList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.olderStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.olderPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.olderPlayedStoryList[0]) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.olderPlayedStoryList[1]) + verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) } private fun verifyGetRecommendedActivityListSucceeded() { @@ -642,11 +642,11 @@ class TopicListControllerTest { private fun verifyDefaultRecommendedActivityListSucceeded() { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[1]) - verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedList[3]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(4) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsSecondTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[2]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[3]) } private fun verifyDefaultRecommendedStoryListSucceeded() { diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 7bae40b2155..33e2e6b5a87 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -6,7 +6,6 @@ import "subtitled_html.proto"; import "thumbnail.proto"; import "translation.proto"; import "voiceover.proto"; -import "profile.proto"; option java_package = "org.oppia.android.app.model"; option java_multiple_files = true; @@ -152,12 +151,11 @@ message CompletedStory { // Corresponds to the list of stories the player is currently playing across all topics. message OngoingStoryList { - // Ongoing stories from within the last 7 days. repeated PromotedStory recent_story = 1; // Other ongoing stories from longer than 7 days ago. - repeated PromotedStory older_story = 3; + repeated PromotedStory older_story = 2; } // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, @@ -240,16 +238,15 @@ message TopicProgress { string topic_id = 1; // Map from story ID to StoryProgress. - map story_progress = 3; - - // Indicates type of story promoted - PromotedStoriesType promoted_stories_type = 4; + map story_progress = 2; // Timestamp to record last time the exploration was played in ms. - int64 last_played_timestamp = 5; + int64 last_played_timestamp = 4; } -// Represents the recommended stories and coming soon topics. +// A structure corresponding to the Promoted Stories. This structure is set up +// to properly account for recently_played stories, for recommended stories +// and for coming soon topics. message RecommendedActivityList { oneof recommendation_type { RecommendedStoryList recommended_story_list = 1; @@ -260,16 +257,15 @@ message RecommendedActivityList { // Corresponds to the list of stories the player is currently playing across all topics and Recommended stories. message RecommendedStoryList { // Ongoing stories from within the last 7 days. - repeated PromotedStory recently_played = 1; + repeated PromotedStory recently_played_story = 1; // Other ongoing stories from longer than 7 days ago. - repeated PromotedStory older_story = 2; + repeated PromotedStory older_played_story = 2; // Stories recommended to the user. repeated PromotedStory suggest_story = 3; } - // Corresponds to the list of Coming soon topics that can be shown on the homescreen. message ComingSoonTopicList { // Upcoming topics for the user. @@ -278,30 +274,22 @@ message ComingSoonTopicList { // Represents upcoming topics message UpcomingTopic { + // The ID of the topic. string topic_id = 1; + + // The name of the topic. string name = 2; + + // The structural version of the topic. int32 version = 3; + + // The estimated release date/timestamp of topic. int64 estimated_release_unix_timestamp = 4; + + // The associated thumbnail that should be displayed with this topic. LessonThumbnail lesson_thumbnail = 5; } -// A structure corresponding to the Promoted Stories. This structure is set up -// to properly account for recently_played stories, for recommended stories -// and for coming soon topics. -message PromotedStoriesType { - oneof promoted_stories_type { - // Indicates recently played topics from the topic list. - bool recently_played = 1; - - // Indicates last played topics more than a week ago from the topic list. - bool last_played = 2; - - // Indicates recommended from the topic list. - bool recommended = 3; - // Indicates coming soon topics. - bool coming_soon = 4; - } -} // Represents the story progress. message StoryProgress { // The ID corresponding to the story. From 01c3653fc55f9ccd0fec6fcec428ca46bcb9ce19 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 16:36:38 -0800 Subject: [PATCH 071/248] Address review comments --- .../oppia/android/app/home/HomeViewModel.kt | 8 ++--- .../PromotedStoryListViewModel.kt | 34 +++++++------------ .../app/home/topiclist/AllTopicsViewModel.kt | 2 +- .../home/topiclist/TopicSummaryViewModel.kt | 22 ++---------- .../res/layout-land/promoted_story_list.xml | 4 +-- .../res/layout-land/topic_summary_view.xml | 4 +-- .../promoted_story_list.xml | 4 +-- .../topic_summary_view.xml | 4 +-- .../promoted_story_list.xml | 4 +-- .../main/res/layout/promoted_story_list.xml | 4 +-- .../main/res/layout/topic_summary_view.xml | 4 +-- 11 files changed, 34 insertions(+), 60 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 3e7f24aff38..e266c6cd07f 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -47,8 +47,6 @@ class HomeViewModel( ) : ObservableViewModel() { private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() - private val promotedStoryListLimit = - activity.resources.getInteger(R.integer.promoted_story_list_limit) private val profileDataProvider: DataProvider by lazy { profileManagementController.getProfile(profileId) @@ -143,7 +141,7 @@ class HomeViewModel( // TODO(#936): Optimise this as part of recommended stories. ongoingStoryList.olderStoryList } - return storyList.take(promotedStoryListLimit) + return storyList.take(R.integer.promoted_story_list_limit) .map { promotedStory -> PromotedStoryViewModel( activity, @@ -164,7 +162,7 @@ class HomeViewModel( */ private fun computeAllTopicsItemsViewModelList( topicList: TopicList - ): Iterable { + ): List { val allTopicsList = topicList.topicSummaryList.mapIndexed { topicIndex, topicSummary -> TopicSummaryViewModel( activity, @@ -175,7 +173,7 @@ class HomeViewModel( ) } return if (!allTopicsList.isEmpty()) { - listOf(AllTopicsViewModel()) + allTopicsList + listOf(AllTopicsViewModel) + allTopicsList } else emptyList() } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 81c6c23ee1b..d9bb044766c 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -16,36 +16,32 @@ class PromotedStoryListViewModel( private val internalProfileId: Int, private val intentFactoryShim: IntentFactoryShim, val promotedStoryList: List -) : HomeItemViewModel(), - RouteToRecentlyPlayedListener { +) : HomeItemViewModel() { + // TODO(#2297): Update this span count and move to values/integers.xml once behavior is clarified + private val promotedStoriesTabletSpanCount: Int = + if (Resources.getSystem().configuration.orientation == Configuration.ORIENTATION_PORTRAIT) 2 + else 3 - /** - * Returns the padding placed at the start of the promoted stories list. - */ - fun getStartPadding(): Int = activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - - /** - * Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. - */ + /** Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. */ fun getEndPadding(): Int { return if (promotedStoryList.size > 1) { activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) } else { - getStartPadding() + activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) } } - /** - * Determines and returns the visibility for the "View All" button. - */ + /** Determines and returns the visibility for the "View All" button. */ fun getButtonVisibility(): Int { if (activity.resources.getBoolean(R.bool.isTablet)) { when (Resources.getSystem().configuration.orientation) { Configuration.ORIENTATION_PORTRAIT -> { - return if (promotedStoryList.size > 2) View.VISIBLE else View.INVISIBLE + return if (promotedStoryList.size > promotedStoriesTabletSpanCount)View.VISIBLE + else View.INVISIBLE } Configuration.ORIENTATION_LANDSCAPE -> { - return if (promotedStoryList.size > 3) View.VISIBLE else View.INVISIBLE + return if (promotedStoryList.size > promotedStoriesTabletSpanCount) View.VISIBLE + else View.INVISIBLE } else -> View.VISIBLE } @@ -53,11 +49,7 @@ class PromotedStoryListViewModel( return View.VISIBLE } - fun clickOnViewAll() { - routeToRecentlyPlayed() - } - - override fun routeToRecentlyPlayed() { + fun routeToRecentlyPlayed() { val intent = intentFactoryShim.createRecentlyPlayedActivityIntent( activity.applicationContext, internalProfileId diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt index 154d5104091..55077cbb220 100644 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt @@ -4,4 +4,4 @@ import androidx.lifecycle.ViewModel import org.oppia.android.app.home.HomeItemViewModel /** [ViewModel] all topics text in [HomeFragment]. */ -class AllTopicsViewModel() : HomeItemViewModel() +object AllTopicsViewModel : HomeItemViewModel() diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index faafd8ec614..910b9723e95 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -30,8 +30,6 @@ class TopicSummaryViewModel( @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() - private val marginTopBottom = activity.resources - .getDimensionPixelSize(R.dimen.topic_list_item_margin_top_bottom) private val marginMax by lazy { activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) } @@ -47,39 +45,25 @@ class TopicSummaryViewModel( topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } - fun computeTopMargin(): Int { - return marginTopBottom - } - - fun computeBottomMargin(): Int { - return marginTopBottom - } - fun computeStartMargin(): Int { return when (spanCount) { - 2 -> { - when (position % spanCount) { + 2 -> when (position % spanCount) { 0 -> marginMax else -> marginMin } - } - 3 -> { - when (position % spanCount) { + 3 -> when (position % spanCount) { 0 -> marginMax 1 -> marginMin 2 -> 0 else -> 0 } - } - 4 -> { - when (position % spanCount) { + 4 -> when (position % spanCount) { 0 -> marginMax 1 -> marginMin 2 -> marginMin / 2 3 -> 0 else -> 0 } - } else -> 0 } } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index de53f98d6d5..7ebc7e8f086 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="72dp" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.clickOnViewAll()}" + android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{viewModel.getStartPadding}" + android:paddingStart="@{@dimen/home_padding_start}" android:paddingEnd="@{viewModel.getEndPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-land/topic_summary_view.xml b/app/src/main/res/layout-land/topic_summary_view.xml index 7734a63329e..b41b7d3e76f 100755 --- a/app/src/main/res/layout-land/topic_summary_view.xml +++ b/app/src/main/res/layout-land/topic_summary_view.xml @@ -13,8 +13,8 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layoutMarginTop="@{viewModel.computeTopMargin()}" - app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginTop="@{@dimen/topic_list_item_margin_top_bottom}" + app:layoutMarginBottom="@{@dimen/topic_list_item_margin_top_bottom}" app:layoutMarginStart="@{viewModel.computeStartMargin()}" app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 6ebd9c23e78..0ad14bfba1b 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="@dimen/home_tablet_land_outer_margin" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.clickOnViewAll()}" + android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{viewModel.getStartPadding}" + android:paddingStart="@{@dimen/home_padding_start}" android:paddingEnd="@{viewModel.getEndPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml b/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml index 96ff2872254..9af2a3d0c3e 100644 --- a/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml +++ b/app/src/main/res/layout-sw600dp-land/topic_summary_view.xml @@ -13,8 +13,8 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layoutMarginTop="@{viewModel.computeTopMargin()}" - app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginTop="@{@dimen/topic_list_item_margin_top_bottom}" + app:layoutMarginBottom="@{@dimen/topic_list_item_margin_top_bottom}" app:layoutMarginStart="@{viewModel.computeStartMargin()}" app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 6014da0fbf2..a20d2ce188b 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="@dimen/home_tablet_port_outer_margin" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.clickOnViewAll()}" + android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{viewModel.getStartPadding}" + android:paddingStart="@{@dimen/home_padding_start}" android:paddingEnd="@{viewModel.getEndPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 129adcf4fa0..e33b3e89089 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -43,7 +43,7 @@ android:fontFamily="sans-serif-medium" android:gravity="center_vertical" android:minHeight="48dp" - android:onClick="@{() -> viewModel.clickOnViewAll()}" + android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" @@ -59,7 +59,7 @@ android:clipToPadding="false" android:orientation="horizontal" android:overScrollMode="never" - android:paddingStart="@{viewModel.getStartPadding}" + android:paddingStart="@{@dimen/home_padding_start}" android:paddingEnd="@{viewModel.getEndPadding}" android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" diff --git a/app/src/main/res/layout/topic_summary_view.xml b/app/src/main/res/layout/topic_summary_view.xml index 7734a63329e..b41b7d3e76f 100755 --- a/app/src/main/res/layout/topic_summary_view.xml +++ b/app/src/main/res/layout/topic_summary_view.xml @@ -13,8 +13,8 @@ android:id="@+id/topic_container" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layoutMarginTop="@{viewModel.computeTopMargin()}" - app:layoutMarginBottom="@{viewModel.computeBottomMargin()}" + app:layoutMarginTop="@{@dimen/topic_list_item_margin_top_bottom}" + app:layoutMarginBottom="@{@dimen/topic_list_item_margin_top_bottom}" app:layoutMarginStart="@{viewModel.computeStartMargin()}" app:layoutMarginEnd="@{viewModel.computeEndMargin()}" app:cardCornerRadius="4dp"> From f347994e5f4a30aec6779604a22d524dcc86d123 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 17:09:39 -0800 Subject: [PATCH 072/248] Set routing / listeners in home activity --- .../oppia/android/app/home/HomeActivity.kt | 27 +++++++++++++++- .../oppia/android/app/home/HomeFragment.kt | 1 + .../oppia/android/app/home/HomeViewModel.kt | 3 -- .../PromotedStoryListViewModel.kt | 17 +++++----- .../promotedlist/PromotedStoryViewModel.kt | 32 +++++++++++-------- .../res/layout-land/promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 2 +- 9 files changed, 58 insertions(+), 30 deletions(-) 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 18cd11517f0..f0558ca6948 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 @@ -8,11 +8,16 @@ import org.oppia.android.app.activity.InjectableAppCompatActivity 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.topic.TopicActivity import javax.inject.Inject /** The central activity for all users entering the app. */ -class HomeActivity : InjectableAppCompatActivity(), RouteToTopicListener { +class HomeActivity : InjectableAppCompatActivity(), + RouteToTopicListener, + RouteToTopicPlayStoryListener, + RouteToRecentlyPlayedListener +{ @Inject lateinit var homeActivityPresenter: HomeActivityPresenter private var internalProfileId: Int = -1 @@ -47,4 +52,24 @@ class HomeActivity : InjectableAppCompatActivity(), RouteToTopicListener { .newInstance(isFromNavigationDrawer = false) dialogFragment.showNow(supportFragmentManager, TAG_SWITCH_PROFILE_DIALOG) } + + override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { + startActivity( + TopicActivity.createTopicPlayStoryActivityIntent( + this, + internalProfileId, + topicId, + storyId + ) + ) + } + + override fun routeToRecentlyPlayed() { + startActivity( + RecentlyPlayedActivity.createRecentlyPlayedActivityIntent( + this, + internalProfileId + ) + ) + } } diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt index 1dd8bd40439..ca10c3ea761 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt @@ -8,6 +8,7 @@ import android.view.ViewGroup import org.oppia.android.app.fragment.InjectableFragment import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject /** Fragment that contains an introduction to the app. */ diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index e266c6cd07f..46abf9b7419 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -120,8 +120,6 @@ class HomeViewModel( return if (storyViewModelList.isNotEmpty()) { return PromotedStoryListViewModel( activity, - internalProfileId, - intentFactoryShim, storyViewModelList ) } else null @@ -146,7 +144,6 @@ class HomeViewModel( PromotedStoryViewModel( activity, internalProfileId, - intentFactoryShim, storyList.size, storyEntityType, promotedStory diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index d9bb044766c..9fa5d1acf0f 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -13,10 +13,10 @@ import org.oppia.android.app.shim.IntentFactoryShim /** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( private val activity: AppCompatActivity, - private val internalProfileId: Int, - private val intentFactoryShim: IntentFactoryShim, val promotedStoryList: List ) : HomeItemViewModel() { + private val routeToRecentlyPlayedListener = activity as RouteToRecentlyPlayedListener + // TODO(#2297): Update this span count and move to values/integers.xml once behavior is clarified private val promotedStoriesTabletSpanCount: Int = if (Resources.getSystem().configuration.orientation == Configuration.ORIENTATION_PORTRAIT) 2 @@ -49,11 +49,12 @@ class PromotedStoryListViewModel( return View.VISIBLE } - fun routeToRecentlyPlayed() { - val intent = intentFactoryShim.createRecentlyPlayedActivityIntent( - activity.applicationContext, - internalProfileId - ) - activity.startActivity(intent) + fun clickOnViewAll() { + routeToRecentlyPlayedListener.routeToRecentlyPlayed() +// val intent = intentFactoryShim.createRecentlyPlayedActivityIntent( +// activity.applicationContext, +// internalProfileId +// ) +// activity.startActivity(intent) } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 61a721a6f29..80045408be5 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -6,6 +6,7 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel import org.oppia.android.R +import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.shim.IntentFactoryShim @@ -17,13 +18,11 @@ import org.oppia.android.app.viewmodel.ObservableViewModel class PromotedStoryViewModel( private val activity: AppCompatActivity, private val internalProfileId: Int, - private val intentFactoryShim: IntentFactoryShim, private val totalStoryCount: Int, val entityType: String, val promotedStory: PromotedStory -) : - ObservableViewModel(), - RouteToTopicPlayStoryListener { +) : ObservableViewModel() { + private val routeToTopicPlayStoryListener = activity as RouteToTopicPlayStoryListener /** * Returns an [Int] for the width of the card layout of this promoted story, based on the device's orientation @@ -39,17 +38,22 @@ class PromotedStoryViewModel( } fun clickOnStoryTile() { - routeToTopicPlayStory(internalProfileId, promotedStory.topicId, promotedStory.storyId) - } - - /** Launches the lesson for this story. */ - override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { - val intent = intentFactoryShim.createTopicPlayStoryActivityIntent( - activity.applicationContext, + routeToTopicPlayStoryListener.routeToTopicPlayStory( internalProfileId, - topicId, - storyId + promotedStory.topicId, + promotedStory.storyId ) - activity.startActivity(intent) } + + /** Launches the lesson for this story. */ + +// override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { +// val intent = intentFactoryShim.createTopicPlayStoryActivityIntent( +// activity.applicationContext, +// internalProfileId, +// topicId, +// storyId +// ) +// activity.startActivity(intent) +// } } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 7ebc7e8f086..30c3c00cc3f 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="72dp" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" + android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 0ad14bfba1b..0aa594dbb23 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="@dimen/home_tablet_land_outer_margin" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" + android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index a20d2ce188b..dd2b7cf854c 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -43,7 +43,7 @@ android:layout_marginEnd="@dimen/home_tablet_port_outer_margin" android:fontFamily="sans-serif-medium" android:gravity="center_vertical" - android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" + android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index e33b3e89089..fb3e0881a23 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -43,7 +43,7 @@ android:fontFamily="sans-serif-medium" android:gravity="center_vertical" android:minHeight="48dp" - android:onClick="@{() -> viewModel.routeToRecentlyPlayed()}" + android:onClick="@{() -> viewModel.clickOnViewAll()}" android:text="@string/view_all" android:textAllCaps="true" android:visibility="@{viewModel.getButtonVisibility()}" From 26b082c76be797ae1a56f9909f2713bd41ab32ca Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 17:28:21 -0800 Subject: [PATCH 073/248] More review comments --- .../oppia/android/app/home/HomeFragmentPresenter.kt | 1 - .../java/org/oppia/android/app/home/HomeViewModel.kt | 1 - .../home/promotedlist/PromotedStoryListViewModel.kt | 11 ++++------- app/src/main/res/layout-land/promoted_story_list.xml | 2 +- .../res/layout-sw600dp-land/promoted_story_list.xml | 2 +- .../res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 2 +- .../org/oppia/android/app/home/HomeActivityTest.kt | 1 + 8 files changed, 9 insertions(+), 13 deletions(-) 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 01361b1f04b..0adf0b538f5 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 @@ -62,7 +62,6 @@ class HomeFragmentPresenter @Inject constructor( oppiaClock, logger, internalProfileId, - intentFactoryShim, profileManagementController, topicListController, topicEntityType, diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 46abf9b7419..fe145312af1 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -39,7 +39,6 @@ class HomeViewModel( private val oppiaClock: OppiaClock, private val logger: ConsoleLogger, private val internalProfileId: Int, - private val intentFactoryShim: IntentFactoryShim, private val profileManagementController: ProfileManagementController, private val topicListController: TopicListController, @TopicHtmlParserEntityType private val topicEntityType: String, diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 9fa5d1acf0f..c6cb0161683 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -22,14 +22,11 @@ class PromotedStoryListViewModel( if (Resources.getSystem().configuration.orientation == Configuration.ORIENTATION_PORTRAIT) 2 else 3 - /** Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. */ - fun getEndPadding(): Int { - return if (promotedStoryList.size > 1) { + /** Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. */ + val endPadding: Int = + if (promotedStoryList.size > 1) activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) - } else { - activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - } - } + else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) /** Determines and returns the visibility for the "View All" button. */ fun getButtonVisibility(): Int { diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 30c3c00cc3f..9a6fe4c6d2e 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@{@dimen/home_padding_start}" - android:paddingEnd="@{viewModel.getEndPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 0aa594dbb23..05ffd06785f 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@{@dimen/home_padding_start}" - android:paddingEnd="@{viewModel.getEndPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index dd2b7cf854c..82cdbf451f8 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@{@dimen/home_padding_start}" - android:paddingEnd="@{viewModel.getEndPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index fb3e0881a23..d635ce73c66 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -60,7 +60,7 @@ android:orientation="horizontal" android:overScrollMode="never" android:paddingStart="@{@dimen/home_padding_start}" - android:paddingEnd="@{viewModel.getEndPadding}" + android:paddingEnd="@{viewModel.endPadding}" android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> 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 5023c3e66e4..aade2477c62 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 @@ -607,6 +607,7 @@ class HomeActivityTest { scrollToPosition(3) ) onView(withId(R.id.home_recycler_view)).check( + // The "All Topics" section currently should display the four test topics in two rows. hasGridColumnCount(2) ) } From 92b6beda8ba78f7ab35a735d0a261afff3c60585 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 18:18:56 -0800 Subject: [PATCH 074/248] Address review comments --- .../oppia/android/app/home/HomeViewModel.kt | 1 - .../PromotedStoryListViewModel.kt | 10 +-- .../promotedlist/PromotedStoryViewModel.kt | 14 --- .../android/app/home/HomeActivityTest.kt | 37 +++++++- .../domain/topic/StoryProgressTestHelper.kt | 90 +++++++++++++++---- .../topic/StoryProgressTestHelperTest.kt | 71 +++++++++++++-- 6 files changed, 174 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index fe145312af1..4876f47f12e 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -16,7 +16,6 @@ import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList -import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel import org.oppia.android.domain.profile.ProfileManagementController import org.oppia.android.domain.topic.TopicListController diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index c6cb0161683..9273c9d90f9 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -8,7 +8,6 @@ import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener -import org.oppia.android.app.shim.IntentFactoryShim /** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( @@ -26,14 +25,14 @@ class PromotedStoryListViewModel( val endPadding: Int = if (promotedStoryList.size > 1) activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) - else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) + else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) /** Determines and returns the visibility for the "View All" button. */ fun getButtonVisibility(): Int { if (activity.resources.getBoolean(R.bool.isTablet)) { when (Resources.getSystem().configuration.orientation) { Configuration.ORIENTATION_PORTRAIT -> { - return if (promotedStoryList.size > promotedStoriesTabletSpanCount)View.VISIBLE + return if (promotedStoryList.size > promotedStoriesTabletSpanCount) View.VISIBLE else View.INVISIBLE } Configuration.ORIENTATION_LANDSCAPE -> { @@ -48,10 +47,5 @@ class PromotedStoryListViewModel( fun clickOnViewAll() { routeToRecentlyPlayedListener.routeToRecentlyPlayed() -// val intent = intentFactoryShim.createRecentlyPlayedActivityIntent( -// activity.applicationContext, -// internalProfileId -// ) -// activity.startActivity(intent) } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 80045408be5..51fdce1763f 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -6,10 +6,8 @@ import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.lifecycle.ViewModel import org.oppia.android.R -import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory -import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.app.viewmodel.ObservableViewModel // TODO(#283): Add download status information to promoted-story-card. @@ -44,16 +42,4 @@ class PromotedStoryViewModel( promotedStory.storyId ) } - - /** Launches the lesson for this story. */ - -// override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) { -// val intent = intentFactoryShim.createTopicPlayStoryActivityIntent( -// activity.applicationContext, -// internalProfileId, -// topicId, -// storyId -// ) -// activity.startActivity(intent) -// } } 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 aade2477c62..5a1f736b640 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 @@ -551,7 +551,7 @@ class HomeActivityTest { fun testHomeActivity_allTopicsCompleted_hidesPromotedStories() { storyProgressTestHelper.markFullProgressForAllTopics( ProfileId.newBuilder().setInternalId(internalProfileId).build(), - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -570,11 +570,42 @@ class HomeActivityTest { } } + @Test + fun testHomeActivity_partialProgressForFractionsAndRatios_showsRecentlyPlayedStories() { + storyProgressTestHelper.markPartialTopicProgressForFractions( + ProfileId.newBuilder().setInternalId(internalProfileId).build(), + timestampOlderThanAWeek = false + ) + storyProgressTestHelper.markTwoPartialStoryProgressForRatios( + ProfileId.newBuilder().setInternalId(internalProfileId).build(), + timestampOlderThanAWeek = false + ) + testCoroutineDispatchers.runCurrent() + + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(1) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 1, + R.id.recently_played_stories_text_view + ) + ).check( + matches( + withText(R.string.recently_played_stories) + ) + ) + } + } + @Test fun testHomeActivity_allTopicsCompleted_displaysAllTopicsHeader() { storyProgressTestHelper.markFullProgressForAllTopics( ProfileId.newBuilder().setInternalId(internalProfileId).build(), - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() launch(createHomeActivityIntent(internalProfileId)).use { @@ -598,7 +629,7 @@ class HomeActivityTest { fun testHomeActivity_allTopicsCompleted_displaysTopicCards() { storyProgressTestHelper.markFullProgressForAllTopics( ProfileId.newBuilder().setInternalId(internalProfileId).build(), - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() launch(createHomeActivityIntent(internalProfileId)).use { diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 6b7e2b3d954..cc0c3ecf10e 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -1,7 +1,7 @@ package org.oppia.android.domain.topic import org.oppia.android.app.model.ProfileId -import java.util.Date +import java.util.* import javax.inject.Inject private const val EIGHT_DAYS_IN_MS = 8 * 24 * 60 * 60 * 1000 @@ -20,7 +20,10 @@ class StoryProgressTestHelper @Inject constructor( return Date().time - EIGHT_DAYS_IN_MS } - /** Creates a partial story progress for a particular profile. */ + /** Creates a partial story progress for a particular profile. + * @param profileId The profile we are setting partial progress of the fraction story for. + * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. + */ fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() @@ -36,7 +39,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Creates a partial topic progress for a particular profile. */ + /** Creates a partial topic progress for a particular profile. + * @param profileId The profile we are setting partial progress of the fraction topic for. + * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. + */ fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() @@ -52,7 +58,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks full story progress for a particular profile. */ + /** Marks full story progress for a particular profile. + * @param profileId The profile we are setting full on the fraction story progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the story is more than one week ago. + */ fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() @@ -76,7 +85,11 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks full topic progress for a particular profile. */ + /** + * Marks full topic progress for a particular profile. + * @param profileId The profile we are setting fraction topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is more than one week ago. + */ fun markFullTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() @@ -99,14 +112,28 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks full story progress for a particular profile. */ - fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + /** + * Marks full topic progress on all topics for a particular profile. + * @param profileId The profile we are setting topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + */ + fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + markFullTopicProgressForFractions(profileId, timestampOlderThanOneWeek) + markFullTopicProgressForTestTopics(profileId, timestampOlderThanOneWeek) + markFullTopicProgressForRatios(profileId, timestampOlderThanOneWeek) + } + + /** + * Marks full topic progress on Test Topics for a particular profile. + * @param profileId The profile we are setting topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + */ + fun markFullTopicProgressForTestTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() } - markFullTopicProgressForFractions(profileId, timestampOlderThanAWeek) // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. storyProgressController.recordCompletedChapter( @@ -151,6 +178,19 @@ class StoryProgressTestHelper @Inject constructor( TEST_EXPLORATION_ID_5, timestamp ) + } + + /** + * Marks full topic progress on Ratios for a particular profile. + * @param profileId The profile we are setting topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + */ + fun markFullTopicProgressForRatios(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } storyProgressController.recordCompletedChapter( profileId, RATIOS_TOPIC_ID, @@ -181,7 +221,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks one story progress full in ratios exploration for a particular profile. */ + /** Marks one story progress full in ratios exploration for a particular profile. + * @param profileId The profile we are setting topic progress on ratios for. + * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. + */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, timestampOlderThanAWeek: Boolean @@ -208,7 +251,11 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks two partial story progress in ratios exploration for a particular profile. */ + /** Marks two partial story progress in ratios exploration for a particular profile. + * @param profileId The profile we are setting topic progress on ratios for. + * @param timestampOlderThanOneWeek If the timestamp for the progress on the two stories is from more than one week + * ago. + */ fun markTwoPartialStoryProgressForRatios(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() @@ -232,7 +279,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. */ + /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. + * @param profileId The profile we are setting recently played for. + * @param timestampOlderThanOneWeek If the timestamp for the recently played stor is more than a week ago. + */ fun markRecentlyPlayedForFractionsStory0Exploration0( profileId: ProfileId, timestampOlderThanAWeek: Boolean @@ -251,7 +301,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. */ + /** Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. + * @param profileId The profile we are setting recently played for. + * @param timestampOlderThanOneWeek If the timestamp for the recently played story is more than a week ago. + */ fun markRecentlyPlayedForRatiosStory0Exploration0( profileId: ProfileId, timestampOlderThanAWeek: Boolean @@ -270,7 +323,11 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks first exploration in both stories of Ratios as recently played for a particular profile. */ + /** Marks first exploration in both stories of Ratios as recently played for a particular profile. + * @param profileId The profile we are setting recently played for. + * @param timestampOlderThanOneWeek If the timestamp for the recently played story and explorations is more than + * a week ago. + */ fun markRecentlyPlayedForRatiosStory0Exploration0AndStory1Exploration2( profileId: ProfileId, timestampOlderThanAWeek: Boolean @@ -298,7 +355,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. */ + /** Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. + * @param profileId The profile we are setting recently played for. + * @param timestampOlderThanOneWeek If the timestamp for the recently played explorations is more than a week ago. + */ fun markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId: ProfileId, timestampOlderThanAWeek: Boolean diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index d1e3cadebd3..a414b0de05e 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -499,10 +499,10 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markFullProgressForAllTopics_getOngoingTopicListIsEmpty() { + fun testProgressTestHelper_markFullProgressForAllTopicsMoreThanOneWeek_ongoingTopicListEmpty() { storyProgressTestHelper.markFullProgressForAllTopics( profileId, - /* timestampOlderThanAWeek= */ false + /* timestampOlderThanOneWeek= */ true ) testCoroutineDispatchers.runCurrent() @@ -514,14 +514,33 @@ class StoryProgressTestHelperTest { verifyGetOngoingTopicListSucceeded() val ongoingTopicList = ongoingTopicListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.topicList.size).isEqualTo(0) + assertThat(ongoingTopicList.topicList).isEmpty() } @Test - fun testProgressTestHelper_markFullProgressForAllTopics_getCompletedStoryListIsCorrect() { + fun testProgressTestHelper_markFullProgressForAllTopicsLessThanOneWeek_ongoingTopicListEmpty() { storyProgressTestHelper.markFullProgressForAllTopics( profileId, - /* timestampOlderThanAWeek= */ false + /* timestampOlderThanOneWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicController.getOngoingTopicList( + profileId + ).toLiveData().observeForever(mockOngoingTopicListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetOngoingTopicListSucceeded() + + val ongoingTopicList = ongoingTopicListResultCaptor.value.getOrThrow() + assertThat(ongoingTopicList.topicList).isEmpty() + } + + @Test + fun testProgressTestHelper_fullProgressAllTopicsMoreThanOneWk_completedStoryListHasSixStories() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanOneWeek= */ true ) testCoroutineDispatchers.runCurrent() @@ -532,14 +551,50 @@ class StoryProgressTestHelperTest { verifyGetCompletedStoryListSucceeded() val completedStoryList = completedStoryListResultCaptor.value.getOrThrow() - assertThat(completedStoryList.completedStoryList.size).isEqualTo(6) + assertThat(completedStoryList.completedStoryList).hasSize(6) } @Test - fun testProgressTestHelper_markFullProgressForAllTopics_getTopicListIsCorrect() { + fun testProgressTestHelper_fullProgressAllTopicsLessThanOneWk_completedStoryListHasSixStories() { storyProgressTestHelper.markFullProgressForAllTopics( profileId, - /* timestampOlderThanAWeek= */ false + /* timestampOlderThanOneWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicController.getCompletedStoryList(profileId).toLiveData() + .observeForever(mockCompletedStoryListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetCompletedStoryListSucceeded() + + val completedStoryList = completedStoryListResultCaptor.value.getOrThrow() + assertThat(completedStoryList.completedStoryList).hasSize(6) + } + + @Test + fun testProgressTestHelper_markFullProgressForAllTopicsMoreThanOneWeek_topicListHasFourStories() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanOneWeek= */ true + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getTopicList().toLiveData() + .observeForever(mockTopicListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetTopicListSucceeded() + + val topicList = topicListResultCaptor.value.getOrThrow() + assertThat(topicList.topicSummaryCount).isEqualTo(4) + } + + @Test + fun testProgressTestHelper_markFullProgressForAllTopicsLessThanOneWeek_topicListHasFourStories() { + storyProgressTestHelper.markFullProgressForAllTopics( + profileId, + /* timestampOlderThanOneWeek= */ false ) testCoroutineDispatchers.runCurrent() From e304b6333c9f74f49c95a0127feb13ea2a015c9e Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 18:20:29 -0800 Subject: [PATCH 075/248] Fix linter issues --- .../oppia/android/app/home/HomeActivity.kt | 3 +- .../oppia/android/app/home/HomeFragment.kt | 4 +-- .../home/topiclist/TopicSummaryViewModel.kt | 28 +++++++++---------- 3 files changed, 17 insertions(+), 18 deletions(-) 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 f0558ca6948..ce1f684f357 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 @@ -16,8 +16,7 @@ import javax.inject.Inject class HomeActivity : InjectableAppCompatActivity(), RouteToTopicListener, RouteToTopicPlayStoryListener, - RouteToRecentlyPlayedListener -{ + RouteToRecentlyPlayedListener { @Inject lateinit var homeActivityPresenter: HomeActivityPresenter private var internalProfileId: Int = -1 diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt index ca10c3ea761..7e506d5e19c 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt @@ -8,12 +8,12 @@ import android.view.ViewGroup import org.oppia.android.app.fragment.InjectableFragment import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.model.TopicSummary -import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject /** Fragment that contains an introduction to the app. */ class HomeFragment : InjectableFragment(), TopicSummaryClickListener { - @Inject lateinit var homeFragmentPresenter: HomeFragmentPresenter + @Inject + lateinit var homeFragmentPresenter: HomeFragmentPresenter override fun onAttach(context: Context) { super.onAttach(context) diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 910b9723e95..6fa45aba526 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -48,22 +48,22 @@ class TopicSummaryViewModel( fun computeStartMargin(): Int { return when (spanCount) { 2 -> when (position % spanCount) { - 0 -> marginMax - else -> marginMin - } + 0 -> marginMax + else -> marginMin + } 3 -> when (position % spanCount) { - 0 -> marginMax - 1 -> marginMin - 2 -> 0 - else -> 0 - } + 0 -> marginMax + 1 -> marginMin + 2 -> 0 + else -> 0 + } 4 -> when (position % spanCount) { - 0 -> marginMax - 1 -> marginMin - 2 -> marginMin / 2 - 3 -> 0 - else -> 0 - } + 0 -> marginMax + 1 -> marginMin + 2 -> marginMin / 2 + 3 -> 0 + else -> 0 + } else -> 0 } } From ac7a029d7e10761a3699416964d4aea160a07ab0 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 21 Dec 2020 18:24:07 -0800 Subject: [PATCH 076/248] Fix linter errors --- app/src/main/java/org/oppia/android/app/home/HomeFragment.kt | 3 +-- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt index 7e506d5e19c..1dd8bd40439 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragment.kt @@ -12,8 +12,7 @@ import javax.inject.Inject /** Fragment that contains an introduction to the app. */ class HomeFragment : InjectableFragment(), TopicSummaryClickListener { - @Inject - lateinit var homeFragmentPresenter: HomeFragmentPresenter + @Inject lateinit var homeFragmentPresenter: HomeFragmentPresenter override fun onAttach(context: Context) { super.onAttach(context) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index cc0c3ecf10e..8ad19118c70 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -1,7 +1,7 @@ package org.oppia.android.domain.topic import org.oppia.android.app.model.ProfileId -import java.util.* +import java.util.Date import javax.inject.Inject private const val EIGHT_DAYS_IN_MS = 8 * 24 * 60 * 60 * 1000 From 8e5d5afd467ecf6fc9bf15726e2ed8dbe563bd79 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 10:50:31 -0800 Subject: [PATCH 077/248] Fix test errors (linter & bazel) --- app/BUILD.bazel | 1 - app/src/main/java/org/oppia/android/app/home/HomeActivity.kt | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 3e1d874ec93..cff38fcea8d 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -171,7 +171,6 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedItemViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/SectionTitleViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryListViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/home/UserAppHistoryViewModel.kt", 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 ce1f684f357..164af1622e7 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 @@ -13,7 +13,8 @@ import org.oppia.android.app.topic.TopicActivity import javax.inject.Inject /** The central activity for all users entering the app. */ -class HomeActivity : InjectableAppCompatActivity(), +class HomeActivity : + InjectableAppCompatActivity(), RouteToTopicListener, RouteToTopicPlayStoryListener, RouteToRecentlyPlayedListener { From 795718b2663c876a4a91646a32582e03005c8277 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 23 Dec 2020 00:45:33 +0530 Subject: [PATCH 078/248] Update TopicListController.kt --- .../domain/topic/TopicListController.kt | 190 ++++++++---------- 1 file changed, 85 insertions(+), 105 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index d49ccbf8d52..615d1dbb76b 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -161,7 +161,13 @@ class TopicListController @Inject constructor( .getJSONArray("topic_id_list") val comingSoonTopicListBuilder = ComingSoonTopicList.newBuilder() for (i in 0 until topicIdJsonArray.length()) { - comingSoonTopicListBuilder.addUpcomingTopic(createUpcomingTopicSummary(topicIdJsonArray.optString(i)!!)) + comingSoonTopicListBuilder.addUpcomingTopic( + createUpcomingTopicSummary( + topicIdJsonArray.optString( + i + )!! + ) + ) } RecommendedActivityList.newBuilder().setComingSoonTopicList(comingSoonTopicListBuilder) return comingSoonTopicListBuilder.build() @@ -197,7 +203,10 @@ class TopicListController @Inject constructor( .build() } - private fun createUpcomingTopicSummaryFromJson(topicId: String, jsonObject: JSONObject): UpcomingTopic { + private fun createUpcomingTopicSummaryFromJson( + topicId: String, + jsonObject: JSONObject + ): UpcomingTopic { var totalChapterCount = 0 val storyData = jsonObject.getJSONArray("canonical_story_dicts") for (i in 0 until storyData.length()) { @@ -222,87 +231,87 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { - val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - sortedTopicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) + sortedTopicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) } } } } } + } return ongoingStoryListBuilder.build() } @@ -314,10 +323,7 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() - - Log.d("topic size", "" + topicProgressList.size) if (topicProgressList.size == 1) { - recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList @@ -325,22 +331,14 @@ class TopicListController @Inject constructor( ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } else { - val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + val sortedTopicProgressList = + topicProgressList.sortedByDescending { it.lastPlayedTimestamp } sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - -// recommendedStoryBuilder.setPromotedStoriesType( -// PromotedStoriesType.newBuilder().setRecentlyPlayed(true) -// ) - topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) - Log.d( - "topic progress =", - "" + topicProgress.topicId + " " + topicProgress.lastPlayedTimestamp - ) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -420,7 +418,7 @@ class TopicListController @Inject constructor( recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0) { - recommendedStoryBuilder.addAllSuggestStory( + recommendedStoryBuilder.addAllSuggestStory( createRecommendedStoryList( topicProgressList ) @@ -501,26 +499,6 @@ class TopicListController @Inject constructor( nextChapterSummary.explorationId ) recommendedStories.add(promotedStory) - } else { - val nextStoryIndex = topic.storyList.indexOf(story) + 1 - if (nextStoryIndex < topic.storyList.size) { - story = topicController.retrieveStory( - topic.topicId, - topic.storyList[nextStoryIndex].storyId - ) - val nextChapterSummary: ChapterSummary? = story.chapterList[0] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - story.storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } - } } } } @@ -534,7 +512,9 @@ class TopicListController @Inject constructor( for (i in 0 until topicIdJsonArray.length()) { topicList.add(topicIdJsonArray[i].toString()) } + val index = topicList.indexOf(topicProgressList[topicProgressList.size - 1].topicId) + if (topicIdJsonArray.length() > (index + 1)) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) return recommendedStories From 03f688784cb2c5fe445a7f5461c2b0e9cdca3385 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 13:35:21 -0800 Subject: [PATCH 079/248] Fix bazel errors and add tests for no user progress case --- app/BUILD.bazel | 2 +- .../android/app/home/HomeActivityTest.kt | 39 ++++++++++++++++++- .../testing/profile/ProfileTestHelper.kt | 3 ++ .../testing/profile/ProfileTestHelperTest.kt | 12 ++++++ 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index cff38fcea8d..140bfc0ac40 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -167,11 +167,11 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/hintsandsolution/HintsViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/SolutionViewModel.kt", "src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/OngoingStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedItemViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/SectionTitleViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/PromotedStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/home/UserAppHistoryViewModel.kt", "src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt", 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 5a1f736b640..58c35b110a4 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 @@ -626,7 +626,7 @@ class HomeActivityTest { } @Test - fun testHomeActivity_allTopicsCompleted_displaysTopicCards() { + fun testHomeActivity_allTopicsCompleted_displaysAllTopicCards() { storyProgressTestHelper.markFullProgressForAllTopics( ProfileId.newBuilder().setInternalId(internalProfileId).build(), timestampOlderThanOneWeek = false @@ -644,6 +644,43 @@ class HomeActivityTest { } } + @Test + fun testHomeActivity_noTopicsCompleted_displaysAllTopicsHeader() { + // Only new users will have no progress for any topics. + profileTestHelper.loginToNewUser() + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(2) + ) + onView( + atPositionOnView( + R.id.home_recycler_view, + 2, + R.id.all_topics_text_view + ) + ).check( + matches(withText(R.string.all_topics)) + ) + } + } + + @Test + fun testHomeActivity_noTopicsStarted_displaysAllTopicCards() { + // Only new users will have no progress for any topics. + profileTestHelper.loginToNewUser() + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(withId(R.id.home_recycler_view)).perform( + scrollToPosition(3) + ) + onView(withId(R.id.home_recycler_view)).check( + // The "All Topics" section currently should display the four test topics in two rows. + hasGridColumnCount(2) + ) + } + } + private fun createHomeActivityIntent(profileId: Int): Intent { return HomeActivity.createHomeActivity(ApplicationProvider.getApplicationContext(), profileId) } diff --git a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt index b42a709afc5..ba87e7b1263 100644 --- a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt +++ b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt @@ -99,6 +99,9 @@ class ProfileTestHelper @Inject constructor( /** Login to user profile. */ fun loginToUser() = logIntoProfile(internalProfileId = 1) + /** Login to a new user profile, since profile #2 is not used as a default user anywhere in this helper. */ + fun loginToNewUser() = logIntoProfile(internalProfileId = 2) + private fun logIntoProfile(internalProfileId: Int): LiveData> { val result = profileManagementController.loginToProfile( ProfileId.newBuilder().setInternalId(internalProfileId).build() diff --git a/testing/src/test/java/org/oppia/android/testing/profile/ProfileTestHelperTest.kt b/testing/src/test/java/org/oppia/android/testing/profile/ProfileTestHelperTest.kt index 79bb3ad1f91..ebe678a48bd 100644 --- a/testing/src/test/java/org/oppia/android/testing/profile/ProfileTestHelperTest.kt +++ b/testing/src/test/java/org/oppia/android/testing/profile/ProfileTestHelperTest.kt @@ -153,6 +153,18 @@ class ProfileTestHelperTest { assertThat(profileManagementController.getCurrentProfileId().internalId).isEqualTo(1) } + @Test + fun testLogingToNewUser_initializeProfiles_loginToUser_checkIsSuccessful() { + profileTestHelper.initializeProfiles() + + profileTestHelper.loginToNewUser().observeForever(mockUpdateResultObserver) + testCoroutineDispatchers.runCurrent() + + verify(mockUpdateResultObserver, atLeastOnce()).onChanged(updateResultCaptor.capture()) + assertThat(updateResultCaptor.value.isSuccess()).isTrue() + assertThat(profileManagementController.getCurrentProfileId().internalId).isEqualTo(2) + } + // TODO(#89): Move this to a common test application component. @Module class TestModule { From 2e87b690751b88f91b508c460cf044fa7befdec3 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 13:56:37 -0800 Subject: [PATCH 080/248] Remove double declaration of TopicSummaryViewModel --- app/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 140bfc0ac40..0f53768f48e 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -172,7 +172,6 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedItemViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/SectionTitleViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/AllTopicsViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/home/UserAppHistoryViewModel.kt", "src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingSlideFinalViewModel.kt", From c8451133f4b5b369227ed15ec5148a1130a99559 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 14:39:43 -0800 Subject: [PATCH 081/248] Move PromotedStoryViewModel to be declared with resources --- app/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 0f53768f48e..b2d637e3fc4 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -125,6 +125,7 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/home/HomeViewModel.kt", "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt", "src/main/java/org/oppia/android/app/parser/StringToFractionParser.kt", @@ -167,7 +168,6 @@ VIEW_MODELS = [ "src/main/java/org/oppia/android/app/hintsandsolution/HintsViewModel.kt", "src/main/java/org/oppia/android/app/hintsandsolution/SolutionViewModel.kt", "src/main/java/org/oppia/android/app/home/HomeItemViewModel.kt", - "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/OngoingStoryViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/RecentlyPlayedItemViewModel.kt", "src/main/java/org/oppia/android/app/home/recentlyplayed/SectionTitleViewModel.kt", From ca30f39b792c6ad89fa8440ab8277cd6d8582993 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 15:17:36 -0800 Subject: [PATCH 082/248] Remove curly brace on padding dimensions in promotedstorylistview --- app/src/main/res/layout-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 9a6fe4c6d2e..8d789dffe00 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{@dimen/home_padding_start}" + android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 05ffd06785f..63d902bc1f8 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{@dimen/home_padding_start}" + android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 82cdbf451f8..184044bb647 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -60,7 +60,7 @@ android:overScrollMode="never" android:scrollbars="none" android:orientation="horizontal" - android:paddingStart="@{@dimen/home_padding_start}" + android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index d635ce73c66..92023722847 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -59,7 +59,7 @@ android:clipToPadding="false" android:orientation="horizontal" android:overScrollMode="never" - android:paddingStart="@{@dimen/home_padding_start}" + android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" From 9a4c82cdd20123b347982dabf526f928c54a5bd4 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 22 Dec 2020 17:26:47 -0800 Subject: [PATCH 083/248] Remove Int type from padding value --- .../android/app/home/promotedlist/PromotedStoryListViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 9273c9d90f9..d05eca1dc6c 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -22,7 +22,7 @@ class PromotedStoryListViewModel( else 3 /** Returns the padding placed at the end of the promoted stories list based on the number of promoted stories. */ - val endPadding: Int = + val endPadding = if (promotedStoryList.size > 1) activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) From 130803f3b3011e3ab20e8ccd37e2ee25e1719bb6 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 23 Dec 2020 14:22:53 +0530 Subject: [PATCH 084/248] updated nit changes. --- .../domain/topic/StoryProgressController.kt | 4 +--- .../domain/topic/TopicListControllerTest.kt | 22 ------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 798d624cdff..9227369890a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -112,9 +112,7 @@ class StoryProgressController @Inject constructor( val storyProgress = storyProgressBuilder.build() val topicProgressBuilder = - TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp( - Date().time - ) + TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(Date().time) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index e0151108158..b9082cc5cf4 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -321,7 +321,6 @@ class TopicListControllerTest { } @Test -// @Ignore("Failing on Circle CI.") fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, @@ -640,15 +639,6 @@ class TopicListControllerTest { assertThat(recommendedActivityListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyDefaultRecommendedActivityListSucceeded() { - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[3]) - } - private fun verifyDefaultRecommendedStoryListSucceeded() { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) @@ -727,18 +717,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - private fun verifyOngoingStoryAsRatioStory1Exploration2(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_2) - assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_1) - assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) - assertThat(promotedStory.nextChapterName).isEqualTo("Equivalent Ratios") - assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(2) - } - private fun verifyOngoingStoryAsRatioStory1Exploration3(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_3) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_1) From 6d31714afba19d10cf86d206c3942d63ab51f85c Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 23 Dec 2020 16:43:16 +0530 Subject: [PATCH 085/248] fixed nit changes --- .../domain/topic/TopicListController.kt | 36 +++++++++---------- .../domain/topic/TopicListControllerTest.kt | 22 ++++++------ model/src/main/proto/topic.proto | 16 ++++----- 3 files changed, 35 insertions(+), 39 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 615d1dbb76b..db50579243d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -16,6 +16,7 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.RecommendedStoryList +import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicProgress @@ -26,6 +27,7 @@ import org.oppia.android.util.data.AsyncResult import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync +import org.oppia.android.util.system.OppiaClock import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject @@ -86,7 +88,8 @@ class TopicListController @Inject constructor( private val jsonAssetRetriever: JsonAssetRetriever, private val topicController: TopicController, private val storyProgressController: StoryProgressController, - private val dataProviders: DataProviders + private val dataProviders: DataProviders, + private val oppiaClock: OppiaClock ) { /** * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to @@ -219,7 +222,7 @@ class TopicListController @Inject constructor( .setTopicId(topicId) .setName(jsonObject.getString("topic_name")) .setVersion(jsonObject.optInt("version")) - .setEstimatedReleaseUnixTimestamp(Date().time) + .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) .setLessonThumbnail(createTopicThumbnail(jsonObject)) .build() } @@ -228,11 +231,8 @@ class TopicListController @Inject constructor( topicProgressList: List ): OngoingStoryList { val ongoingStoryListBuilder = OngoingStoryList.newBuilder() - if (topicProgressList.isNotEmpty()) { - val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) @@ -268,7 +268,7 @@ class TopicListController @Inject constructor( } if (recentlyPlayerChapterSummary != null) { val numberOfDaysPassed = - (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -293,7 +293,7 @@ class TopicListController @Inject constructor( val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { val numberOfDaysPassed = - (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -312,7 +312,6 @@ class TopicListController @Inject constructor( } } } - return ongoingStoryListBuilder.build() } @@ -324,7 +323,7 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() if (topicProgressList.size == 1) { - recommendedStoryBuilder.addAllSuggestStory( + recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList ) @@ -333,7 +332,6 @@ class TopicListController @Inject constructor( } else { val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) topicProgress.storyProgressMap.values.forEach { storyProgress -> @@ -368,7 +366,7 @@ class TopicListController @Inject constructor( } if (recentlyPlayerChapterSummary != null) { val numberOfDaysPassed = - (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -393,7 +391,7 @@ class TopicListController @Inject constructor( val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { val numberOfDaysPassed = - (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -413,21 +411,20 @@ class TopicListController @Inject constructor( recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount > 0 - && recommendedStoryBuilder.suggestStoryCount == 0 + && recommendedStoryBuilder.suggestedStoryCount == 0 ) { recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0) { - recommendedStoryBuilder.addAllSuggestStory( + recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList ) ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - if (recommendedStoryBuilder.suggestStoryCount == 0) { + if (recommendedStoryBuilder.suggestedStoryCount == 0) { recommendedActivityListBuilder.setComingSoonTopicList(createComingSoonTopicList()) - Log.d("topic =", " coming" + " " + "soon") } } } @@ -443,7 +440,7 @@ class TopicListController @Inject constructor( val topic = topicController.retrieveTopic(topicProgress.topicId) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId - var story = topicController.retrieveStory(topic.topicId, storyId) + val story = topicController.retrieveStory(topic.topicId, storyId) val completedChapterProgressList = storyProgress.chapterProgressMap.values @@ -508,13 +505,12 @@ class TopicListController @Inject constructor( .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") - val topicList = ArrayList() + val topicList = mutableListOf() for (i in 0 until topicIdJsonArray.length()) { topicList.add(topicIdJsonArray[i].toString()) } - val index = topicList.indexOf(topicProgressList[topicProgressList.size - 1].topicId) - + val index = topicList.indexOf(topicProgressList.last().topicId) if (topicIdJsonArray.length() > (index + 1)) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index b9082cc5cf4..8d3f35c3da2 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -315,9 +315,9 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[1]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[1]) } @Test @@ -338,9 +338,9 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[1]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[1]) } @Test @@ -370,7 +370,7 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) verifyDefaultRecommendedStoryListSucceeded() } @@ -527,7 +527,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) } @Test @@ -576,7 +576,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(0) val comingSoonTopicListLiveData = topicListController.getComingSoonTopicList().toLiveData() @@ -641,8 +641,8 @@ class TopicListControllerTest { private fun verifyDefaultRecommendedStoryListSucceeded() { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestStoryList[0]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 33e2e6b5a87..932332f0ba0 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -241,12 +241,12 @@ message TopicProgress { map story_progress = 2; // Timestamp to record last time the exploration was played in ms. - int64 last_played_timestamp = 4; + int64 last_played_timestamp = 3; } // A structure corresponding to the Promoted Stories. This structure is set up -// to properly account for recently_played stories, for recommended stories -// and for coming soon topics. +// to properly account for recently played stories, recommended stories +// and coming soon topics. message RecommendedActivityList { oneof recommendation_type { RecommendedStoryList recommended_story_list = 1; @@ -256,19 +256,19 @@ message RecommendedActivityList { // Corresponds to the list of stories the player is currently playing across all topics and Recommended stories. message RecommendedStoryList { - // Ongoing stories from within the last 7 days. + // Ongoing stories from within the last 7 days. repeated PromotedStory recently_played_story = 1; // Other ongoing stories from longer than 7 days ago. repeated PromotedStory older_played_story = 2; - // Stories recommended to the user. - repeated PromotedStory suggest_story = 3; + // Stories specifically recommended for the learner to complete next. + repeated PromotedStory suggested_story = 3; } -// Corresponds to the list of Coming soon topics that can be shown on the homescreen. +// Corresponds to the list of coming soon topics that can be shown on the home screen. message ComingSoonTopicList { -// Upcoming topics for the user. + // Upcoming topics for the user. repeated UpcomingTopic upcoming_topic = 1; } From f449b5ca73e0822b91a34eeb6c39f55bf9bb87f3 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 23 Dec 2020 19:17:41 +0530 Subject: [PATCH 086/248] Update TopicListController.kt --- .../domain/topic/TopicListController.kt | 126 ++++++++---------- 1 file changed, 54 insertions(+), 72 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index db50579243d..3996637d6cf 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -102,17 +102,6 @@ class TopicListController @Inject constructor( ) } - /** - * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to - * [EVICTION_TIME_MILLIS] old. - */ - fun getComingSoonTopicList(): DataProvider { - return dataProviders.createInMemoryDataProvider( - GET_COMING_SOON_TOPIC_LIST_PROVIDER_ID, - this::createComingSoonTopicList - ) - } - /** * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. * The total number of promoted stories should correspond to the ongoing story count within the @@ -240,27 +229,14 @@ class TopicListController @Inject constructor( val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - + val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) val lastCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - + val startedChapterProgressList = getStartedChapterProgressList(storyProgress) val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> @@ -315,6 +291,25 @@ class TopicListController @Inject constructor( return ongoingStoryListBuilder.build() } + private fun getStartedChapterProgressList(storyProgress: StoryProgress): List { + return storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + } + + private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List { + return storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + } + private fun createRecommendedActivityList( topicProgressList: List ): RecommendedActivityList { @@ -338,27 +333,15 @@ class TopicListController @Inject constructor( val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - + val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) val lastCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + val startedChapterProgressList = getStartedChapterProgressList(storyProgress) val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> @@ -381,46 +364,45 @@ class TopicListController @Inject constructor( recommendedStoryBuilder.addOlderPlayedStory(promotedStory) } } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) - } else { - recommendedStoryBuilder.addOlderPlayedStory(promotedStory) + } else if (lastCompletedChapterProgress != null) { + if (lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) + } else { + recommendedStoryBuilder.addOlderPlayedStory(promotedStory) + } } } } } recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } - if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount > 0 + if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount > 0 && recommendedStoryBuilder.suggestedStoryCount == 0 ) { recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } - if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0) { - recommendedStoryBuilder.addAllSuggestedStory( - createRecommendedStoryList( - topicProgressList - ) - ) + if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 + && recommendedStoryBuilder.olderPlayedStoryCount == 0 + ) { + recommendedStoryBuilder.addAllSuggestedStory(createRecommendedStoryList(topicProgressList)) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) if (recommendedStoryBuilder.suggestedStoryCount == 0) { From 42456b90b9bc71e4c4c1eba15db254c2a15168bc Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 23 Dec 2020 20:12:38 +0530 Subject: [PATCH 087/248] Delete gradle.xml --- .idea/gradle.xml | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 .idea/gradle.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 6466b7bedb7..00000000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - \ No newline at end of file From 4beaf320f472c33327b6b228167f6ab117d7f849 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 23 Dec 2020 20:20:01 +0530 Subject: [PATCH 088/248] Update strings.xml --- app/src/main/res/values/strings.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8e3e515b6e5..465ff3ed0f4 100755 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -416,6 +416,5 @@ Enter a ratio in the form x:y. - Coming Soon - Recommended Stories + From f2e47100106bb6908ebfe916a92025b6b75f9384 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 23 Dec 2020 21:58:15 +0530 Subject: [PATCH 089/248] Update TopicListControllerTest.kt --- .../android/domain/topic/TopicListControllerTest.kt | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 8d3f35c3da2..a2d5489a502 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -531,7 +531,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveComingSoonTopicList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_comingSoonListIsCorrect() { + fun testRetrieveComingSoonTopicList_markFirstStoryOfEveryTopicDoneWithinLastSevenDays_comingSoonListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -577,15 +577,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(0) - - val comingSoonTopicListLiveData = topicListController.getComingSoonTopicList().toLiveData() - - comingSoonTopicListLiveData.observeForever(mockComingSoonTopicListObserver) - testCoroutineDispatchers.runCurrent() - - verify(mockComingSoonTopicListObserver).onChanged(comingSoonTopicListResultCaptor.capture()) - val comingSoonTopicListResult = comingSoonTopicListResultCaptor.value - assertThat(comingSoonTopicListResult!!.isSuccess()).isTrue() + assertThat(recommendedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(4) } @Test From b13c629318fe2cec5a3539efe4d3b0bdbd61f405 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 23 Dec 2020 22:00:54 +0530 Subject: [PATCH 090/248] Update TopicListControllerTest.kt --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index a2d5489a502..a1c14105f15 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -457,6 +457,7 @@ class TopicListControllerTest { verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) } + // TODO(#2303): Rewrite this testcase for coming soon topics. @Test fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { storyProgressController.recordCompletedChapter( From 28b60a2c972f97793b893a190da24403c5398db2 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 09:48:53 -0800 Subject: [PATCH 091/248] Address review comments --- .../android/app/home/HomeFragmentPresenter.kt | 15 ++++-- .../home/topiclist/TopicSummaryViewModel.kt | 54 +++++++++++++------ .../domain/topic/StoryProgressTestHelper.kt | 26 +++++++++ 3 files changed, 75 insertions(+), 20 deletions(-) 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 0adf0b538f5..0a8b3fa44d7 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 @@ -5,6 +5,7 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment +import androidx.lifecycle.Transformations import androidx.recyclerview.widget.GridLayoutManager import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID @@ -72,10 +73,16 @@ class HomeFragmentPresenter @Inject constructor( val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { - return if (position == 0 || position == 1 || position == 2) { - /* number of spaces this item should occupy = */ spanCount - } else { - /* number of spaces this item should occupy = */ 1 + val homeItemList = homeViewModel.homeItemViewModelListLiveData.value + if (homeItemList.isNullOrEmpty() || homeItemList.size < position) { + // If there is any error with the data or it is still pending, set each view to cover the entire + // span of the HomeFragment. Any TopicSummaries displayed this way will be off-centered, but this + // ensures that most other views properly display. + return spanCount + } + return when (homeItemList!!.get(position)) { + is TopicSummaryViewModel -> /* number of spaces this item should occupy = */ 1 + else -> /* number of spaces this item should occupy = */ spanCount } } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 6fa45aba526..fe0ad1e97d6 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -30,10 +30,10 @@ class TopicSummaryViewModel( @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() - private val marginMax by lazy { + private val outerMargin by lazy { activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) } - private val marginMin by lazy { + private val innerMargin by lazy { activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) } private val spanCount by lazy { @@ -45,22 +45,39 @@ class TopicSummaryViewModel( topicSummaryClickListener.onTopicSummaryClicked(topicSummary) } + /** + * Determines the start margin for an individual TopicSummary relative to the grid columns laid out on the + * HomeActivity. GridLayout columns are evenly spread out across the entire activity screen but the + * Topic Summaries are positioned towards the center, so start margins are calculated to stagger inside each + * fixed column but centered on the activity's layout, as shown below. + * + * | _____| _____ | _____ |_____ | + * | | | | | | | | | | | + * | | | | | | | | | | | + * | |_____| |_____| | |_____| |_____| | + * | | | | | + * | _____ _____ _____ _____ | + * | | | | | | | | | | + * | | | | | | | | | | + * | |_____| |_____| |_____| |_____| | + * | | + */ fun computeStartMargin(): Int { return when (spanCount) { 2 -> when (position % spanCount) { - 0 -> marginMax - else -> marginMin + 0 -> outerMargin + else -> innerMargin } 3 -> when (position % spanCount) { - 0 -> marginMax - 1 -> marginMin + 0 -> outerMargin + 1 -> innerMargin 2 -> 0 else -> 0 } 4 -> when (position % spanCount) { - 0 -> marginMax - 1 -> marginMin - 2 -> marginMin / 2 + 0 -> outerMargin + 1 -> innerMargin + 2 -> innerMargin / 2 3 -> 0 else -> 0 } @@ -68,23 +85,28 @@ class TopicSummaryViewModel( } } + /** + * Determines the end margin for an individual TopicSummary relative to the grid columns laid out on the + * HomeActivity. The end margins are calculated to stagger inside each fixed column but centered on the + * activity's layout (see [computeStartMargin])/ + */ fun computeEndMargin(): Int { return when (spanCount) { 2 -> when (position % spanCount) { - 0 -> marginMin - else -> marginMax + 0 -> innerMargin + else -> outerMargin } 3 -> when (position % spanCount) { 0 -> 0 - 1 -> marginMin - 2 -> marginMax + 1 -> innerMargin + 2 -> outerMargin else -> 0 } 4 -> when (position % spanCount) { 0 -> 0 - 1 -> marginMin / 2 - 2 -> marginMin - 3 -> marginMax + 1 -> innerMargin / 2 + 2 -> innerMargin + 3 -> outerMargin else -> 0 } else -> 0 diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 8ad19118c70..861c90bfe57 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -21,7 +21,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Creates a partial story progress for a particular profile. + * * @param profileId The profile we are setting partial progress of the fraction story for. + * * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. */ fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -40,7 +42,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Creates a partial topic progress for a particular profile. + * * @param profileId The profile we are setting partial progress of the fraction topic for. + * * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. */ fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -59,7 +63,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks full story progress for a particular profile. + * * @param profileId The profile we are setting full on the fraction story progress for. + * * @param timestampOlderThanOneWeek If the timestamp for completing the story is more than one week ago. */ fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -87,7 +93,9 @@ class StoryProgressTestHelper @Inject constructor( /** * Marks full topic progress for a particular profile. + * * @param profileId The profile we are setting fraction topic progress for. + * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is more than one week ago. */ fun markFullTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -114,7 +122,9 @@ class StoryProgressTestHelper @Inject constructor( /** * Marks full topic progress on all topics for a particular profile. + * * @param profileId The profile we are setting topic progress for. + * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { @@ -125,7 +135,9 @@ class StoryProgressTestHelper @Inject constructor( /** * Marks full topic progress on Test Topics for a particular profile. + * * @param profileId The profile we are setting topic progress for. + * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullTopicProgressForTestTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { @@ -182,7 +194,9 @@ class StoryProgressTestHelper @Inject constructor( /** * Marks full topic progress on Ratios for a particular profile. + * * @param profileId The profile we are setting topic progress for. + * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullTopicProgressForRatios(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { @@ -222,7 +236,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks one story progress full in ratios exploration for a particular profile. + * * @param profileId The profile we are setting topic progress on ratios for. + * * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. */ fun markFullStoryPartialTopicProgressForRatios( @@ -252,7 +268,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks two partial story progress in ratios exploration for a particular profile. + * * @param profileId The profile we are setting topic progress on ratios for. + * * @param timestampOlderThanOneWeek If the timestamp for the progress on the two stories is from more than one week * ago. */ @@ -280,7 +298,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. + * * @param profileId The profile we are setting recently played for. + * * @param timestampOlderThanOneWeek If the timestamp for the recently played stor is more than a week ago. */ fun markRecentlyPlayedForFractionsStory0Exploration0( @@ -302,7 +322,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. + * * @param profileId The profile we are setting recently played for. + * * @param timestampOlderThanOneWeek If the timestamp for the recently played story is more than a week ago. */ fun markRecentlyPlayedForRatiosStory0Exploration0( @@ -324,7 +346,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks first exploration in both stories of Ratios as recently played for a particular profile. + * * @param profileId The profile we are setting recently played for. + * * @param timestampOlderThanOneWeek If the timestamp for the recently played story and explorations is more than * a week ago. */ @@ -356,7 +380,9 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. + * * @param profileId The profile we are setting recently played for. + * * @param timestampOlderThanOneWeek If the timestamp for the recently played explorations is more than a week ago. */ fun markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( From 3f23dbb58a3a3f2a87b7f3fa051da4766ad97afe Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 10:07:30 -0800 Subject: [PATCH 092/248] Add BindingAdapter for padding end --- .../android/app/databinding/ViewBindingAdapters.java | 9 +++++++++ app/src/main/res/layout-land/promoted_story_list.xml | 2 +- .../main/res/layout-sw600dp-land/promoted_story_list.xml | 2 +- .../main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 2 +- 5 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index f3f2813ab50..6848fa36fe5 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -34,6 +34,15 @@ public static void setLayoutWidth(@NonNull View view, float width) { layoutParams.width = (int) width; view.setLayoutParams(layoutParams); } + /** Used to set a padding-start for views. */ + @BindingAdapter("android:padding_end") + public static void setPaddingEnd(@NonNull View view, float paddingEnd) { + view.setPaddingRelative( + view.getPaddingStart(), + view.getPaddingTop(), + (int) paddingEnd, + view.getPaddingBottom()); + } @BindingAdapter( value = { diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 8d789dffe00..2120fd7b05c 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + android:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 63d902bc1f8..249eb98b512 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + android:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 184044bb647..42c96bd3bc4 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + android:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 92023722847..e442d7f087b 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -60,7 +60,7 @@ android:orientation="horizontal" android:overScrollMode="never" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + android:padding_end="@{viewModel.endPadding}" android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> From 9566c629d4381714cf4eb44a93313e8ac6cffb54 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 10:08:47 -0800 Subject: [PATCH 093/248] Remove unused import --- .../java/org/oppia/android/app/home/HomeFragmentPresenter.kt | 1 - 1 file changed, 1 deletion(-) 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 0a8b3fa44d7..e73bccd7457 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 @@ -5,7 +5,6 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.app.AppCompatActivity import androidx.fragment.app.Fragment -import androidx.lifecycle.Transformations import androidx.recyclerview.widget.GridLayoutManager import org.oppia.android.R import org.oppia.android.app.drawer.KEY_NAVIGATION_PROFILE_ID From b37f62416100e403cf4e63c52e56b9eb0f8d3d1c Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 10:20:54 -0800 Subject: [PATCH 094/248] Fix comments --- .../android/app/databinding/ViewBindingAdapters.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 6848fa36fe5..1e9dfd2a81f 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -24,7 +24,7 @@ public static void setLayoutHeight(@NonNull View view, float height) { } /** - * BindingAdapter to set the height of a Width. If this value is calculated in data fetching, the + * BindingAdapter to set the width of a View. If this value is calculated in data fetching, the * layout will require a default value since binding adapters aren't called until after initial * view measurements and layouts are formatted. */ @@ -34,7 +34,12 @@ public static void setLayoutWidth(@NonNull View view, float width) { layoutParams.width = (int) width; view.setLayoutParams(layoutParams); } - /** Used to set a padding-start for views. */ + + /** + * BindingAdapter to set the end padding of a View. If this value is calculated in data fetching, the + * layout will require a default value since binding adapters aren't called until after initial + * view measurements and layouts are formatted. + */ @BindingAdapter("android:padding_end") public static void setPaddingEnd(@NonNull View view, float paddingEnd) { view.setPaddingRelative( From 5cc9b283ffe6b7161c469529a7ac95d32b6d2d82 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 10:45:09 -0800 Subject: [PATCH 095/248] Use int in BindingAdapter --- .../oppia/android/app/databinding/ViewBindingAdapters.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 1e9dfd2a81f..37736ef15e4 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -41,11 +41,11 @@ public static void setLayoutWidth(@NonNull View view, float width) { * view measurements and layouts are formatted. */ @BindingAdapter("android:padding_end") - public static void setPaddingEnd(@NonNull View view, float paddingEnd) { + public static void setPaddingEnd(@NonNull View view, int paddingEnd) { view.setPaddingRelative( view.getPaddingStart(), view.getPaddingTop(), - (int) paddingEnd, + paddingEnd, view.getPaddingBottom()); } From b527e166589b1f7f699abcfeecf23461dd206697 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 10:47:06 -0800 Subject: [PATCH 096/248] Rename BindingAdapter? --- .../org/oppia/android/app/databinding/ViewBindingAdapters.java | 2 +- app/src/main/res/layout-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 37736ef15e4..c6ed45985d5 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -40,7 +40,7 @@ public static void setLayoutWidth(@NonNull View view, float width) { * layout will require a default value since binding adapters aren't called until after initial * view measurements and layouts are formatted. */ - @BindingAdapter("android:padding_end") + @BindingAdapter("android:paddingEnd") public static void setPaddingEnd(@NonNull View view, int paddingEnd) { view.setPaddingRelative( view.getPaddingStart(), diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 2120fd7b05c..8d789dffe00 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 249eb98b512..63d902bc1f8 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 42c96bd3bc4..184044bb647 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index e442d7f087b..92023722847 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -60,7 +60,7 @@ android:orientation="horizontal" android:overScrollMode="never" android:paddingStart="@dimen/home_padding_start" - android:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" android:scrollbars="none" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> From f67afed1d067e86c944f7481d33b51e30b3e0dc2 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 11:10:26 -0800 Subject: [PATCH 097/248] Refactor BindingAdapter naming --- .../oppia/android/app/databinding/ViewBindingAdapters.java | 6 +++--- app/src/main/res/layout-land/promoted_story_list.xml | 2 +- .../main/res/layout-sw600dp-land/promoted_story_list.xml | 2 +- .../main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 4 ++-- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index c6ed45985d5..c77cd23e85d 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -40,12 +40,12 @@ public static void setLayoutWidth(@NonNull View view, float width) { * layout will require a default value since binding adapters aren't called until after initial * view measurements and layouts are formatted. */ - @BindingAdapter("android:paddingEnd") - public static void setPaddingEnd(@NonNull View view, int paddingEnd) { + @BindingAdapter("app:padding_End") + public static void setPaddingEnd(@NonNull View view, float paddingEnd) { view.setPaddingRelative( view.getPaddingStart(), view.getPaddingTop(), - paddingEnd, + (int) paddingEnd, view.getPaddingBottom()); } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 8d789dffe00..4142b6a51ce 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + app:padding_End="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 63d902bc1f8..73ddad86108 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + app:padding_End="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 184044bb647..8d2ce94844d 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" + app:padding_End="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 92023722847..10f9f1f12e4 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -59,9 +59,9 @@ android:clipToPadding="false" android:orientation="horizontal" android:overScrollMode="never" - android:paddingStart="@dimen/home_padding_start" - android:paddingEnd="@{viewModel.endPadding}" android:scrollbars="none" + android:paddingStart="@dimen/home_padding_start" + app:padding_End="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> From c7fc75b737622f3ba9eb149809f92090479bd652 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 12:45:29 -0800 Subject: [PATCH 098/248] Add view to bazel build --- app/BUILD.bazel | 1 + .../org/oppia/android/app/databinding/ViewBindingAdapters.java | 2 +- app/src/main/res/layout-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-land/promoted_story_list.xml | 2 +- app/src/main/res/layout-sw600dp-port/promoted_story_list.xml | 2 +- app/src/main/res/layout/promoted_story_list.xml | 2 +- 6 files changed, 6 insertions(+), 5 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index b2d637e3fc4..3eb31e45fbd 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -314,6 +314,7 @@ VIEWS = [ "src/main/java/org/oppia/android/app/customview/interaction/NumericInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/TextInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/RatioInputInteractionView.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt", "src/main/java/org/oppia/android/app/player/state/DragDropSortInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/ImageRegionSelectionInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt", diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index c77cd23e85d..614f2786dd3 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -40,7 +40,7 @@ public static void setLayoutWidth(@NonNull View view, float width) { * layout will require a default value since binding adapters aren't called until after initial * view measurements and layouts are formatted. */ - @BindingAdapter("app:padding_End") + @BindingAdapter("app:padding_end") public static void setPaddingEnd(@NonNull View view, float paddingEnd) { view.setPaddingRelative( view.getPaddingStart(), diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 4142b6a51ce..b14f70fa2a7 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_End="@{viewModel.endPadding}" + app:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 73ddad86108..315c490e103 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_End="@{viewModel.endPadding}" + app:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 8d2ce94844d..70fa04534c6 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_End="@{viewModel.endPadding}" + app:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 10f9f1f12e4..6eafecd0cbb 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -61,7 +61,7 @@ android:overScrollMode="never" android:scrollbars="none" android:paddingStart="@dimen/home_padding_start" - app:padding_End="@{viewModel.endPadding}" + app:padding_end="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> From 4f48b76ae5ed6834390e4cd8bb043ac658143fa7 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 14:07:23 -0800 Subject: [PATCH 099/248] Add SnapHelper to build --- app/BUILD.bazel | 13 ++++++++++++- .../org/oppia/android/app/home/HomeFragmentView.kt | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 3eb31e45fbd..0dcf124328e 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -406,6 +406,10 @@ in order to keep Gradle building. """, ) for file in BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS] +# Snap Helper + +SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] + """ Files to be excluded from the source list for the app library. This list includes all the files built by the following libraries: @@ -416,7 +420,7 @@ built by the following libraries: - binding_adapters """ -EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS +EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS + SNAP_HELPER """ Files to be built by the app library. All of these files are assumed to have resource imports and @@ -531,6 +535,7 @@ kt_android_library( ":listeners", ":resources", ":view_models", + ":snap_helper", "//model", "@circularimageview//circularimageview:circular_image_view", artifact("androidx.appcompat:appcompat"), @@ -573,6 +578,12 @@ kt_android_library( ], ) +# Library for scope annotations required to build views and view_model libraries. +kt_android_library( + name = "snap_helper", + srcs = SNAP_HELPER, +) + # TODO(#1639): Translate binding adapters back to Kotlin post-Bazel modularization. # Library for all custom data-binding adapters under org/oppia/android/app/databinding. android_library( diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt new file mode 100644 index 00000000000..c5ed2bb6e9e --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt @@ -0,0 +1,4 @@ +package org.oppia.android.app.home.topiclist + +class HomeFragmentView { +} \ No newline at end of file From 51311b20c3a67009d498c39ef66bdb88ff721a0d Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 15:20:45 -0800 Subject: [PATCH 100/248] Create HomeFragmentView to handle layout --- .../android/app/home/HomeFragmentPresenter.kt | 24 ----- .../android/app/home/HomeFragmentView.kt | 89 ++++++++++++++++++- .../main/res/layout-land/home_fragment.xml | 2 +- .../res/layout-sw600dp-land/home_fragment.xml | 2 +- .../res/layout-sw600dp-port/home_fragment.xml | 2 +- app/src/main/res/layout/home_fragment.xml | 2 +- 6 files changed, 91 insertions(+), 30 deletions(-) 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 e73bccd7457..dadc3c0e78a 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 @@ -40,7 +40,6 @@ class HomeFragmentPresenter @Inject constructor( private val oppiaClock: OppiaClock, private val logger: ConsoleLogger, private val oppiaLogger: OppiaLogger, - private val intentFactoryShim: IntentFactoryShim, @TopicHtmlParserEntityType private val topicEntityType: String, @StoryHtmlParserEntityType private val storyEntityType: String ) { @@ -68,29 +67,6 @@ class HomeFragmentPresenter @Inject constructor( storyEntityType ) - val spanCount = activity.resources.getInteger(R.integer.home_span_count) - val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) - homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { - override fun getSpanSize(position: Int): Int { - val homeItemList = homeViewModel.homeItemViewModelListLiveData.value - if (homeItemList.isNullOrEmpty() || homeItemList.size < position) { - // If there is any error with the data or it is still pending, set each view to cover the entire - // span of the HomeFragment. Any TopicSummaries displayed this way will be off-centered, but this - // ensures that most other views properly display. - return spanCount - } - return when (homeItemList!!.get(position)) { - is TopicSummaryViewModel -> /* number of spaces this item should occupy = */ 1 - else -> /* number of spaces this item should occupy = */ spanCount - } - } - } - - binding.homeRecyclerView.apply { - adapter = createRecyclerViewAdapter() - // https://stackoverflow.com/a/32763434/32763621 - layoutManager = homeLayoutManager - } binding.let { it.lifecycleOwner = fragment it.viewModel = homeViewModel diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt index c5ed2bb6e9e..ca87f1bf1bc 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt @@ -1,4 +1,89 @@ -package org.oppia.android.app.home.topiclist +package org.oppia.android.app.home -class HomeFragmentView { +import android.content.Context +import android.util.AttributeSet +import androidx.appcompat.app.AppCompatActivity +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.RecyclerView +import dagger.Provides +import org.oppia.android.R +import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel +import org.oppia.android.app.home.topiclist.AllTopicsViewModel +import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.recyclerview.BindableAdapter +import org.oppia.android.databinding.AllTopicsBinding +import org.oppia.android.databinding.PromotedStoryListBinding +import org.oppia.android.databinding.TopicSummaryViewBinding +import org.oppia.android.databinding.WelcomeBinding +import javax.inject.Inject + +/** A custom [RecyclerView] for the HomeActivity that uses a GridLayoutManager. */ +class HomeFragmentView @JvmOverloads constructor ( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +): RecyclerView(context, attrs, defStyleAttr) { + + @Inject + private lateinit var activity: AppCompatActivity + + init { + adapter = createAdapter() + + val spanCount = activity.resources.getInteger(R.integer.home_span_count) + val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) + homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (this@HomeFragmentView.adapter?.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) { + 1 + } else spanCount + } + } + layoutManager = homeLayoutManager + } + + private fun createAdapter(): BindableAdapter { + return BindableAdapter.MultiTypeBuilder + .newBuilder { viewModel -> + when (viewModel) { + is WelcomeViewModel -> ViewType.WELCOME_MESSAGE + is PromotedStoryListViewModel -> ViewType.PROMOTED_STORY_LIST + is AllTopicsViewModel -> ViewType.ALL_TOPICS + is TopicSummaryViewModel -> ViewType.TOPIC_LIST + else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") + } + } + .registerViewDataBinder( + viewType = ViewType.WELCOME_MESSAGE, + inflateDataBinding = WelcomeBinding::inflate, + setViewModel = WelcomeBinding::setViewModel, + transformViewModel = { it as WelcomeViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.PROMOTED_STORY_LIST, + inflateDataBinding = PromotedStoryListBinding::inflate, + setViewModel = PromotedStoryListBinding::setViewModel, + transformViewModel = { it as PromotedStoryListViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.ALL_TOPICS, + inflateDataBinding = AllTopicsBinding::inflate, + setViewModel = AllTopicsBinding::setViewModel, + transformViewModel = { it as AllTopicsViewModel } + ) + .registerViewDataBinder( + viewType = ViewType.TOPIC_LIST, + inflateDataBinding = TopicSummaryViewBinding::inflate, + setViewModel = TopicSummaryViewBinding::setViewModel, + transformViewModel = { it as TopicSummaryViewModel } + ) + .build() + } + + private enum class ViewType { + WELCOME_MESSAGE, + PROMOTED_STORY_LIST, + ALL_TOPICS, + TOPIC_LIST + } } \ No newline at end of file diff --git a/app/src/main/res/layout-land/home_fragment.xml b/app/src/main/res/layout-land/home_fragment.xml index 09c8a2670c0..7bbe51ea5c2 100644 --- a/app/src/main/res/layout-land/home_fragment.xml +++ b/app/src/main/res/layout-land/home_fragment.xml @@ -17,7 +17,7 @@ android:background="@color/white" android:gravity="center"> - - - - Date: Wed, 23 Dec 2020 16:00:35 -0800 Subject: [PATCH 101/248] Handle layout in presenter again --- .../android/app/home/HomeFragmentPresenter.kt | 14 +++ .../android/app/home/HomeFragmentView.kt | 89 ------------------- .../main/res/layout-land/home_fragment.xml | 2 +- .../res/layout-sw600dp-land/home_fragment.xml | 2 +- .../res/layout-sw600dp-port/home_fragment.xml | 2 +- app/src/main/res/layout/home_fragment.xml | 2 +- 6 files changed, 18 insertions(+), 93 deletions(-) delete mode 100644 app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt 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 dadc3c0e78a..6e87b72f527 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 @@ -67,6 +67,20 @@ class HomeFragmentPresenter @Inject constructor( storyEntityType ) + val homeAdapter = createRecyclerViewAdapter() + val spanCount = activity.resources.getInteger(R.integer.home_span_count) + val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) + homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { + override fun getSpanSize(position: Int): Int { + return if (homeAdapter.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) 1 + else spanCount + } + } + binding.homeRecyclerView.apply{ + adapter = homeAdapter + layoutManager = homeLayoutManager + } + binding.let { it.lifecycleOwner = fragment it.viewModel = homeViewModel diff --git a/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt b/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt deleted file mode 100644 index ca87f1bf1bc..00000000000 --- a/app/src/main/java/org/oppia/android/app/home/HomeFragmentView.kt +++ /dev/null @@ -1,89 +0,0 @@ -package org.oppia.android.app.home - -import android.content.Context -import android.util.AttributeSet -import androidx.appcompat.app.AppCompatActivity -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import dagger.Provides -import org.oppia.android.R -import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel -import org.oppia.android.app.home.topiclist.AllTopicsViewModel -import org.oppia.android.app.home.topiclist.TopicSummaryViewModel -import org.oppia.android.app.recyclerview.BindableAdapter -import org.oppia.android.databinding.AllTopicsBinding -import org.oppia.android.databinding.PromotedStoryListBinding -import org.oppia.android.databinding.TopicSummaryViewBinding -import org.oppia.android.databinding.WelcomeBinding -import javax.inject.Inject - -/** A custom [RecyclerView] for the HomeActivity that uses a GridLayoutManager. */ -class HomeFragmentView @JvmOverloads constructor ( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0 -): RecyclerView(context, attrs, defStyleAttr) { - - @Inject - private lateinit var activity: AppCompatActivity - - init { - adapter = createAdapter() - - val spanCount = activity.resources.getInteger(R.integer.home_span_count) - val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) - homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { - override fun getSpanSize(position: Int): Int { - return if (this@HomeFragmentView.adapter?.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) { - 1 - } else spanCount - } - } - layoutManager = homeLayoutManager - } - - private fun createAdapter(): BindableAdapter { - return BindableAdapter.MultiTypeBuilder - .newBuilder { viewModel -> - when (viewModel) { - is WelcomeViewModel -> ViewType.WELCOME_MESSAGE - is PromotedStoryListViewModel -> ViewType.PROMOTED_STORY_LIST - is AllTopicsViewModel -> ViewType.ALL_TOPICS - is TopicSummaryViewModel -> ViewType.TOPIC_LIST - else -> throw IllegalArgumentException("Encountered unexpected view model: $viewModel") - } - } - .registerViewDataBinder( - viewType = ViewType.WELCOME_MESSAGE, - inflateDataBinding = WelcomeBinding::inflate, - setViewModel = WelcomeBinding::setViewModel, - transformViewModel = { it as WelcomeViewModel } - ) - .registerViewDataBinder( - viewType = ViewType.PROMOTED_STORY_LIST, - inflateDataBinding = PromotedStoryListBinding::inflate, - setViewModel = PromotedStoryListBinding::setViewModel, - transformViewModel = { it as PromotedStoryListViewModel } - ) - .registerViewDataBinder( - viewType = ViewType.ALL_TOPICS, - inflateDataBinding = AllTopicsBinding::inflate, - setViewModel = AllTopicsBinding::setViewModel, - transformViewModel = { it as AllTopicsViewModel } - ) - .registerViewDataBinder( - viewType = ViewType.TOPIC_LIST, - inflateDataBinding = TopicSummaryViewBinding::inflate, - setViewModel = TopicSummaryViewBinding::setViewModel, - transformViewModel = { it as TopicSummaryViewModel } - ) - .build() - } - - private enum class ViewType { - WELCOME_MESSAGE, - PROMOTED_STORY_LIST, - ALL_TOPICS, - TOPIC_LIST - } -} \ No newline at end of file diff --git a/app/src/main/res/layout-land/home_fragment.xml b/app/src/main/res/layout-land/home_fragment.xml index 7bbe51ea5c2..09c8a2670c0 100644 --- a/app/src/main/res/layout-land/home_fragment.xml +++ b/app/src/main/res/layout-land/home_fragment.xml @@ -17,7 +17,7 @@ android:background="@color/white" android:gravity="center"> - - - - Date: Wed, 23 Dec 2020 16:02:32 -0800 Subject: [PATCH 102/248] Fix linter errors --- .../java/org/oppia/android/app/home/HomeFragmentPresenter.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 6e87b72f527..024cf5f62ed 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 @@ -15,7 +15,6 @@ import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.EventLog import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.recyclerview.BindableAdapter -import org.oppia.android.app.shim.IntentFactoryShim import org.oppia.android.databinding.AllTopicsBinding import org.oppia.android.databinding.HomeFragmentBinding import org.oppia.android.databinding.PromotedStoryListBinding @@ -76,7 +75,7 @@ class HomeFragmentPresenter @Inject constructor( else spanCount } } - binding.homeRecyclerView.apply{ + binding.homeRecyclerView.apply { adapter = homeAdapter layoutManager = homeLayoutManager } From 0df343ee76c9867eb5a9c6312bb532f0971a28f0 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 16:08:09 -0800 Subject: [PATCH 103/248] Add recyclerview to snap helper in build --- app/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 0dcf124328e..7c555ed8148 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -582,6 +582,7 @@ kt_android_library( kt_android_library( name = "snap_helper", srcs = SNAP_HELPER, + deps = [artifact("androidx.recyclerview:recyclerview:1.0.0")], ) # TODO(#1639): Translate binding adapters back to Kotlin post-Bazel modularization. From f9e94942c17fd594019e24abd11b567d7f7e20d5 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:04:06 -0800 Subject: [PATCH 104/248] Add databidning dependency --- app/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 7c555ed8148..f70c3d556ac 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -534,6 +534,7 @@ kt_android_library( ":annotations", ":listeners", ":resources", + ":databinding_resources", ":view_models", ":snap_helper", "//model", From 7d94895564781691407c854e2674414d632ba2f7 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:10:27 -0800 Subject: [PATCH 105/248] WOrk on bazel errors --- app/BUILD.bazel | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index f70c3d556ac..7fdfad1021c 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -294,6 +294,7 @@ Place your file here if: VIEWS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/customview/LessonThumbnailImageView.kt", "src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt", "src/main/java/org/oppia/android/app/profile/ProfileInputView.kt", "src/main/java/org/oppia/android/app/utility/ClickableAreasImage.kt", ] @@ -314,7 +315,6 @@ VIEWS = [ "src/main/java/org/oppia/android/app/customview/interaction/NumericInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/TextInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/RatioInputInteractionView.kt", - "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt", "src/main/java/org/oppia/android/app/player/state/DragDropSortInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/ImageRegionSelectionInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt", @@ -534,7 +534,6 @@ kt_android_library( ":annotations", ":listeners", ":resources", - ":databinding_resources", ":view_models", ":snap_helper", "//model", From 8a0bc4aa81f526299f4bbf8553e7418dee64705e Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:26:38 -0800 Subject: [PATCH 106/248] WOrk on bazel errors --- app/BUILD.bazel | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 7fdfad1021c..ee769b8b31b 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -294,7 +294,6 @@ Place your file here if: VIEWS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/customview/LessonThumbnailImageView.kt", "src/main/java/org/oppia/android/app/customview/SegmentedCircularProgressView.kt", - "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt", "src/main/java/org/oppia/android/app/profile/ProfileInputView.kt", "src/main/java/org/oppia/android/app/utility/ClickableAreasImage.kt", ] @@ -315,6 +314,7 @@ VIEWS = [ "src/main/java/org/oppia/android/app/customview/interaction/NumericInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/TextInputInteractionView.kt", "src/main/java/org/oppia/android/app/customview/interaction/RatioInputInteractionView.kt", + "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt", "src/main/java/org/oppia/android/app/player/state/DragDropSortInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/ImageRegionSelectionInteractionView.kt", "src/main/java/org/oppia/android/app/player/state/SelectionInteractionView.kt", @@ -582,7 +582,8 @@ kt_android_library( kt_android_library( name = "snap_helper", srcs = SNAP_HELPER, - deps = [artifact("androidx.recyclerview:recyclerview:1.0.0")], + deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"), + ":databinding_resources",], ) # TODO(#1639): Translate binding adapters back to Kotlin post-Bazel modularization. From 6de46c32432b776a0ad8100ec58d5871821ec16a Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:37:49 -0800 Subject: [PATCH 107/248] WOrk on bazel errors --- app/BUILD.bazel | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index ee769b8b31b..2ee4f7c1f03 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -408,7 +408,7 @@ in order to keep Gradle building. # Snap Helper -SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] +#SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] """ Files to be excluded from the source list for the app library. This list includes all the files @@ -420,7 +420,7 @@ built by the following libraries: - binding_adapters """ -EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS + SNAP_HELPER +EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS """ Files to be built by the app library. All of these files are assumed to have resource imports and @@ -535,13 +535,14 @@ kt_android_library( ":listeners", ":resources", ":view_models", - ":snap_helper", + "src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt", "//model", "@circularimageview//circularimageview:circular_image_view", artifact("androidx.appcompat:appcompat"), artifact("androidx.core:core-ktx"), artifact("androidx.databinding:databinding-common"), artifact("androidx.databinding:databinding-runtime"), + artifact("androidx.recyclerview:recyclerview:1.0.0"), ], ) @@ -579,12 +580,12 @@ kt_android_library( ) # Library for scope annotations required to build views and view_model libraries. -kt_android_library( - name = "snap_helper", - srcs = SNAP_HELPER, - deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"), - ":databinding_resources",], -) +#kt_android_library( +# name = "snap_helper", +# enable_data_binding = True, +# srcs = SNAP_HELPER, +# deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"),], +#) # TODO(#1639): Translate binding adapters back to Kotlin post-Bazel modularization. # Library for all custom data-binding adapters under org/oppia/android/app/databinding. From 55a45970a68e6b785bab48b17825f0eb37beeed4 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:47:34 -0800 Subject: [PATCH 108/248] Enable data-binding in build? --- app/BUILD.bazel | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 2ee4f7c1f03..f5801dc4c12 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -408,7 +408,7 @@ in order to keep Gradle building. # Snap Helper -#SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] +SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] """ Files to be excluded from the source list for the app library. This list includes all the files @@ -420,7 +420,7 @@ built by the following libraries: - binding_adapters """ -EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS +EXCLUDED_APP_LIB_FILES = VIEW_MODELS + VIEW_MODELS_WITH_RESOURCE_IMPORTS + VIEWS + VIEWS_WITH_RESOURCE_IMPORTS + BINDING_ADAPTERS + BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS + LISTENERS + ANNOTATIONS + SNAP_HELPER """ Files to be built by the app library. All of these files are assumed to have resource imports and @@ -535,14 +535,13 @@ kt_android_library( ":listeners", ":resources", ":view_models", - "src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt", + ":snap_helper", "//model", "@circularimageview//circularimageview:circular_image_view", artifact("androidx.appcompat:appcompat"), artifact("androidx.core:core-ktx"), artifact("androidx.databinding:databinding-common"), artifact("androidx.databinding:databinding-runtime"), - artifact("androidx.recyclerview:recyclerview:1.0.0"), ], ) @@ -580,12 +579,12 @@ kt_android_library( ) # Library for scope annotations required to build views and view_model libraries. -#kt_android_library( -# name = "snap_helper", -# enable_data_binding = True, -# srcs = SNAP_HELPER, -# deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"),], -#) +kt_android_library( + name = "snap_helper", + enable_data_binding = True, + srcs = SNAP_HELPER, + deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"),], +) # TODO(#1639): Translate binding adapters back to Kotlin post-Bazel modularization. # Library for all custom data-binding adapters under org/oppia/android/app/databinding. From a308621ef66c30ecea9e5f8a8d117c1e0262e88b Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:55:17 -0800 Subject: [PATCH 109/248] Remove enable data binding for snap helper --- app/BUILD.bazel | 1 - 1 file changed, 1 deletion(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index f5801dc4c12..04b3e1a7031 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -581,7 +581,6 @@ kt_android_library( # Library for scope annotations required to build views and view_model libraries. kt_android_library( name = "snap_helper", - enable_data_binding = True, srcs = SNAP_HELPER, deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"),], ) From 94e9f3be5ca58eaa8c85b260c352b7ea847abcb1 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 17:56:23 -0800 Subject: [PATCH 110/248] Add custom package? --- app/BUILD.bazel | 1 + 1 file changed, 1 insertion(+) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 04b3e1a7031..8f36f8a1a1d 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -582,6 +582,7 @@ kt_android_library( kt_android_library( name = "snap_helper", srcs = SNAP_HELPER, + custom_package = "org.oppia.android.app.recyclerview", deps = [artifact("androidx.recyclerview:recyclerview:1.0.0"),], ) From aa5656a577788a71e62aa454245e8fb26fba748f Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 19:07:01 -0800 Subject: [PATCH 111/248] Use shim for bindings in PromotedStoryListView --- .../app/application/ApplicationInjector.kt | 3 +++ .../promotedlist/PromotedStoryListView.kt | 27 ++++++++++++++++--- .../oppia/android/app/shim/ViewBindingShim.kt | 15 +++++++++++ .../android/app/shim/ViewBindingShimImpl.kt | 23 ++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt b/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt index 97d28db1361..3663fffb9d8 100644 --- a/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt +++ b/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt @@ -1,5 +1,6 @@ package org.oppia.android.app.application +import org.oppia.android.app.home.promotedlist.PromotedStoryListView import org.oppia.android.app.profile.ProfileInputView import org.oppia.android.util.data.DataProvidersInjector @@ -8,4 +9,6 @@ interface ApplicationInjector : DataProvidersInjector { // TODO(#1619): Remove post-modularization. fun inject(profileInputView: ProfileInputView) + + fun injectPromotedStoryListView(promotedStoryListView: PromotedStoryListView) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 6067df4688e..9d8e86d9f73 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -2,10 +2,13 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet +import android.view.LayoutInflater import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.app.application.ApplicationInjectorProvider import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper -import org.oppia.android.databinding.PromotedStoryCardBinding +import org.oppia.android.app.shim.ViewBindingShim +import javax.inject.Inject /** * A custom [RecyclerView] for displaying a variable list of promoted lesson stories that snaps to @@ -17,11 +20,27 @@ class PromotedStoryListView @JvmOverloads constructor( defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr) { + @Inject + lateinit var bindingInterface: ViewBindingShim + init { + (context.applicationContext as ApplicationInjectorProvider).getApplicationInjector() + .injectPromotedStoryListView(this) adapter = BindableAdapter.SingleTypeBuilder.newBuilder() - .registerViewDataBinderWithSameModelType( - inflateDataBinding = PromotedStoryCardBinding::inflate, - setViewModel = PromotedStoryCardBinding::setViewModel + .registerViewBinder( + inflateView = { parent -> + bindingInterface.inflatePromotedStoryCardBinding( + inflater = LayoutInflater.from(context), + parent = parent, + attachToParent = false + ) + }, + bindView = { view, viewModel -> + bindingInterface.providePromotedStoryViewModel( + view = view, + viewModel = viewModel + ) + } ).build() /* 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 846dc200fed..f4e946bd288 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 @@ -9,6 +9,8 @@ import android.widget.ImageButton import android.widget.LinearLayout import android.widget.TextView import androidx.recyclerview.widget.RecyclerView +import org.oppia.android.app.home.promotedlist.PromotedStoryListView +import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.player.state.itemviewmodel.DragDropInteractionContentViewModel import org.oppia.android.app.player.state.itemviewmodel.SelectionInteractionContentViewModel import org.oppia.android.util.parser.HtmlParser @@ -46,6 +48,19 @@ interface ViewBindingShim { profileInputView: View ): TextView + /** Handles binding inflation for [PromotedStoryListView] */ + fun inflatePromotedStoryCardBinding( + inflater: LayoutInflater, + parent: ViewGroup, + attachToParent: Boolean + ): View + + /** Handles binding inflation for [PromotedStoryListView] and returns the view model.*/ + fun providePromotedStoryViewModel( + view: View, + viewModel: PromotedStoryViewModel + ) + /** * Handles binding inflation for [SelectionInteractionView]'s ItemSelectionInteraction and * returns the binding's root. 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 3b0bbeb6825..747486353fb 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 @@ -11,6 +11,7 @@ import android.widget.TextView import androidx.databinding.DataBindingUtil import androidx.recyclerview.widget.RecyclerView import org.oppia.android.R +import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.player.state.itemviewmodel.DragDropInteractionContentViewModel import org.oppia.android.app.player.state.itemviewmodel.SelectionInteractionContentViewModel import org.oppia.android.databinding.DragDropInteractionItemsBinding @@ -18,6 +19,7 @@ import org.oppia.android.databinding.DragDropSingleItemBinding import org.oppia.android.databinding.ItemSelectionInteractionItemsBinding import org.oppia.android.databinding.MultipleChoiceInteractionItemsBinding import org.oppia.android.databinding.ProfileInputViewBinding +import org.oppia.android.databinding.PromotedStoryCardBinding import org.oppia.android.util.parser.HtmlParser import javax.inject.Inject @@ -63,6 +65,27 @@ class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { return DataBindingUtil.findBinding(profileInputView)!!.errorText } + override fun inflatePromotedStoryCardBinding( + inflater: LayoutInflater, + parent: ViewGroup, + attachToParent: Boolean + ): View { + return PromotedStoryCardBinding.inflate( + LayoutInflater.from(parent.context), + parent, + /* attachToParent= */ false + ).root + } + + override fun providePromotedStoryViewModel( + view: View, + viewModel: PromotedStoryViewModel + ) { + val binding = + DataBindingUtil.findBinding(view)!! + binding.viewModel = viewModel + } + override fun provideSelectionInteractionViewInflatedView( inflater: LayoutInflater, parent: ViewGroup, From 666de4d089f6b22a0a4eb5806cfe08fc427aab73 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 20:54:15 -0800 Subject: [PATCH 112/248] Address review comments --- app/BUILD.bazel | 4 +- .../app/databinding/ViewBindingAdapters.java | 14 ------- .../oppia/android/app/home/HomeViewModel.kt | 2 +- .../promotedlist/PromotedStoryListView.kt | 7 +++- .../home/topiclist/TopicSummaryViewModel.kt | 6 +-- .../android/app/shim/ViewBindingShimImpl.kt | 2 +- .../oppia/android/app/view/ViewComponent.kt | 2 + .../res/layout-land/promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 2 +- app/src/main/res/values-land/dimens.xml | 4 +- .../main/res/values-sw600dp-land/dimens.xml | 4 +- .../main/res/values-sw600dp-port/dimens.xml | 4 +- app/src/main/res/values/dimens.xml | 4 +- .../domain/topic/StoryProgressTestHelper.kt | 41 +++++++++---------- 16 files changed, 44 insertions(+), 58 deletions(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index 8f36f8a1a1d..175df863fa3 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -406,8 +406,6 @@ in order to keep Gradle building. """, ) for file in BINDING_ADAPTERS_WITH_RESOURCE_IMPORTS] -# Snap Helper - SNAP_HELPER = ["src/main/java/org/oppia/android/app/recyclerview/StartSnapHelper.kt"] """ @@ -578,7 +576,7 @@ kt_android_library( ], ) -# Library for scope annotations required to build views and view_model libraries. +# Library for snap helper used to build views. kt_android_library( name = "snap_helper", srcs = SNAP_HELPER, diff --git a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java index 614f2786dd3..0d1ecb30200 100644 --- a/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java +++ b/app/src/main/java/org/oppia/android/app/databinding/ViewBindingAdapters.java @@ -35,20 +35,6 @@ public static void setLayoutWidth(@NonNull View view, float width) { view.setLayoutParams(layoutParams); } - /** - * BindingAdapter to set the end padding of a View. If this value is calculated in data fetching, the - * layout will require a default value since binding adapters aren't called until after initial - * view measurements and layouts are formatted. - */ - @BindingAdapter("app:padding_end") - public static void setPaddingEnd(@NonNull View view, float paddingEnd) { - view.setPaddingRelative( - view.getPaddingStart(), - view.getPaddingTop(), - (int) paddingEnd, - view.getPaddingBottom()); - } - @BindingAdapter( value = { "app:isRotationAnimationClockwise", diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 4876f47f12e..e1bc4d20505 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -88,7 +88,7 @@ class HomeViewModel( if (itemListResult.isFailure()) { logger.e( "HomeFragment", - "Failed to retrieve items for home fragment", + "No home fragment available -- failed to retrieve home fragment information.", itemListResult.getErrorOrNull() ) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 9d8e86d9f73..63f1d6f01ab 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,11 +3,14 @@ package org.oppia.android.app.home.promotedlist 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.application.ApplicationInjectorProvider import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.ViewBindingShim +import org.oppia.android.app.shim.ViewComponentFactory import javax.inject.Inject /** @@ -24,8 +27,8 @@ class PromotedStoryListView @JvmOverloads constructor( lateinit var bindingInterface: ViewBindingShim init { - (context.applicationContext as ApplicationInjectorProvider).getApplicationInjector() - .injectPromotedStoryListView(this) + (FragmentManager.findFragment(this) as ViewComponentFactory) + .createViewComponent(this).inject(this) adapter = BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( inflateView = { parent -> diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index fe0ad1e97d6..0b4d6abffaf 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -31,10 +31,10 @@ class TopicSummaryViewModel( @ColorInt val darkerBackgroundOverlayColor: Int = computeDarkerBackgroundColor() private val outerMargin by lazy { - activity.resources.getDimensionPixelSize(R.dimen.home_margin_max) + activity.resources.getDimensionPixelSize(R.dimen.home_outer_margin) } private val innerMargin by lazy { - activity.resources.getDimensionPixelSize(R.dimen.home_margin_min) + activity.resources.getDimensionPixelSize(R.dimen.home_inner_margin) } private val spanCount by lazy { activity.resources.getInteger(R.integer.home_span_count) @@ -88,7 +88,7 @@ class TopicSummaryViewModel( /** * Determines the end margin for an individual TopicSummary relative to the grid columns laid out on the * HomeActivity. The end margins are calculated to stagger inside each fixed column but centered on the - * activity's layout (see [computeStartMargin])/ + * activity's layout (see [computeStartMargin]). */ fun computeEndMargin(): Int { return when (spanCount) { 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 747486353fb..8524004ef1c 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 @@ -73,7 +73,7 @@ class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { return PromotedStoryCardBinding.inflate( LayoutInflater.from(parent.context), parent, - /* attachToParent= */ false + /* attachToParent= */ attachToParent ).root } diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt index 468a8531f3f..b2028020044 100644 --- a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt +++ b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt @@ -4,6 +4,7 @@ import android.view.View import dagger.BindsInstance import dagger.Subcomponent import org.oppia.android.app.customview.LessonThumbnailImageView +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 @@ -24,4 +25,5 @@ interface ViewComponent { fun inject(dragDropSortInteractionView: DragDropSortInteractionView) fun inject(imageRegionSelectionInteractionView: ImageRegionSelectionInteractionView) fun inject(lessonThumbnailImageView: LessonThumbnailImageView) + fun inject(promotedStoryListView: PromotedStoryListView) } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index b14f70fa2a7..8d789dffe00 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 315c490e103..63d902bc1f8 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 70fa04534c6..184044bb647 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -61,7 +61,7 @@ android:scrollbars="none" android:orientation="horizontal" android:paddingStart="@dimen/home_padding_start" - app:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 6eafecd0cbb..638eb0bcc44 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -61,7 +61,7 @@ android:overScrollMode="never" android:scrollbars="none" android:paddingStart="@dimen/home_padding_start" - app:padding_end="@{viewModel.endPadding}" + android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/values-land/dimens.xml b/app/src/main/res/values-land/dimens.xml index ae3478d3c53..4667273520c 100644 --- a/app/src/main/res/values-land/dimens.xml +++ b/app/src/main/res/values-land/dimens.xml @@ -2,8 +2,8 @@ 72dp 72dp - 72dp - 36dp + 72dp + 36dp 72dp 36dp diff --git a/app/src/main/res/values-sw600dp-land/dimens.xml b/app/src/main/res/values-sw600dp-land/dimens.xml index 5098bd0f7df..c45aa3393d5 100644 --- a/app/src/main/res/values-sw600dp-land/dimens.xml +++ b/app/src/main/res/values-sw600dp-land/dimens.xml @@ -2,8 +2,8 @@ 96dp 96dp - 96dp - 64dp + 96dp + 64dp 96dp 64dp 32dp diff --git a/app/src/main/res/values-sw600dp-port/dimens.xml b/app/src/main/res/values-sw600dp-port/dimens.xml index 3949ea215f9..4f03876ac38 100644 --- a/app/src/main/res/values-sw600dp-port/dimens.xml +++ b/app/src/main/res/values-sw600dp-port/dimens.xml @@ -2,8 +2,8 @@ 120dp 120dp - 120dp - 60dp + 120dp + 60dp 120dp 60dp diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a49f7838442..72c63359fa0 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -101,8 +101,8 @@ 280dp 44dp 20dp - 28dp - 8dp + 28dp + 8dp 96dp 120dp 28dp diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 861c90bfe57..c66976f3332 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -20,10 +20,10 @@ class StoryProgressTestHelper @Inject constructor( return Date().time - EIGHT_DAYS_IN_MS } - /** Creates a partial story progress for a particular profile. + /** + * Creates a partial story progress for a particular profile. * * @param profileId The profile we are setting partial progress of the fraction story for. - * * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. */ fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -41,10 +41,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Creates a partial topic progress for a particular profile. + /** + * Creates a partial topic progress for a particular profile. * * @param profileId The profile we are setting partial progress of the fraction topic for. - * * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. */ fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -62,10 +62,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks full story progress for a particular profile. + /** + * Marks full story progress for a particular profile. * * @param profileId The profile we are setting full on the fraction story progress for. - * * @param timestampOlderThanOneWeek If the timestamp for completing the story is more than one week ago. */ fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -95,7 +95,6 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress for a particular profile. * * @param profileId The profile we are setting fraction topic progress for. - * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is more than one week ago. */ fun markFullTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { @@ -124,7 +123,6 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on all topics for a particular profile. * * @param profileId The profile we are setting topic progress for. - * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { @@ -137,7 +135,6 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on Test Topics for a particular profile. * * @param profileId The profile we are setting topic progress for. - * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullTopicProgressForTestTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { @@ -196,8 +193,8 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on Ratios for a particular profile. * * @param profileId The profile we are setting topic progress for. - * * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + * */ fun markFullTopicProgressForRatios(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { val timestamp = if (!timestampOlderThanOneWeek) { @@ -235,10 +232,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks one story progress full in ratios exploration for a particular profile. + /** + * Marks one story progress full in ratios exploration for a particular profile. * * @param profileId The profile we are setting topic progress on ratios for. - * * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. */ fun markFullStoryPartialTopicProgressForRatios( @@ -267,10 +264,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks two partial story progress in ratios exploration for a particular profile. + /** + * Marks two partial story progress in ratios exploration for a particular profile. * * @param profileId The profile we are setting topic progress on ratios for. - * * @param timestampOlderThanOneWeek If the timestamp for the progress on the two stories is from more than one week * ago. */ @@ -297,10 +294,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. + /** + * Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. * * @param profileId The profile we are setting recently played for. - * * @param timestampOlderThanOneWeek If the timestamp for the recently played stor is more than a week ago. */ fun markRecentlyPlayedForFractionsStory0Exploration0( @@ -321,10 +318,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. + /** + * Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. * * @param profileId The profile we are setting recently played for. - * * @param timestampOlderThanOneWeek If the timestamp for the recently played story is more than a week ago. */ fun markRecentlyPlayedForRatiosStory0Exploration0( @@ -345,10 +342,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks first exploration in both stories of Ratios as recently played for a particular profile. + /** + * Marks first exploration in both stories of Ratios as recently played for a particular profile. * * @param profileId The profile we are setting recently played for. - * * @param timestampOlderThanOneWeek If the timestamp for the recently played story and explorations is more than * a week ago. */ @@ -379,10 +376,10 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. + /** + * Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. * * @param profileId The profile we are setting recently played for. - * * @param timestampOlderThanOneWeek If the timestamp for the recently played explorations is more than a week ago. */ fun markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( From 6fc5312008b8c1a7f9be60c1564a64c3d28fa103 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 21:14:04 -0800 Subject: [PATCH 113/248] Attach to window and use view component --- .../android/app/home/promotedlist/PromotedStoryListView.kt | 5 ++++- .../test/java/org/oppia/android/app/testing/HomeSpanTest.kt | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 63f1d6f01ab..be3d09bf804 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -26,9 +26,12 @@ class PromotedStoryListView @JvmOverloads constructor( @Inject lateinit var bindingInterface: ViewBindingShim - init { + override fun onAttachedToWindow() { + super.onAttachedToWindow() + (FragmentManager.findFragment(this) as ViewComponentFactory) .createViewComponent(this).inject(this) + adapter = BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( inflateView = { parent -> diff --git a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt index 9a5833c634d..e50f65b7a17 100644 --- a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt +++ b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt @@ -44,6 +44,7 @@ import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfiguration import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule import org.oppia.android.testing.TestLogReportingModule import org.oppia.android.util.caching.testing.CachingTestModule @@ -68,6 +69,9 @@ class HomeSpanTest { private val internalProfileId: Int = 1 + @Inject + lateinit var testCoroutineDispatchers: TestCoroutineDispatchers + @Before fun setUp() { setUpTestApplicationComponent() @@ -81,6 +85,7 @@ class HomeSpanTest { @Test fun testHomeSpanTest_checkSpanForItem0_port_hasCorrectSpanCount() { launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)) .check( hasGridItemCount( From 19c98a2ecb7bb7f1bcac52e41820491323619e3a Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 22:02:07 -0800 Subject: [PATCH 114/248] Use application injection in PromotedStoryListView, add bounds check for getSpanSize --- .../org/oppia/android/app/home/HomeFragmentPresenter.kt | 3 ++- .../app/home/promotedlist/PromotedStoryListView.kt | 9 ++++----- .../java/org/oppia/android/app/view/ViewComponent.kt | 1 - .../java/org/oppia/android/app/testing/HomeSpanTest.kt | 6 ++---- 4 files changed, 8 insertions(+), 11 deletions(-) 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 024cf5f62ed..995e94fe269 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 @@ -71,7 +71,8 @@ class HomeFragmentPresenter @Inject constructor( val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { - return if (homeAdapter.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) 1 + return if (position < homeAdapter.itemCount + && homeAdapter.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) 1 else spanCount } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index be3d09bf804..cf5d7d96d55 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,6 +3,7 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import androidx.databinding.Bindable import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView @@ -26,11 +27,9 @@ class PromotedStoryListView @JvmOverloads constructor( @Inject lateinit var bindingInterface: ViewBindingShim - override fun onAttachedToWindow() { - super.onAttachedToWindow() - - (FragmentManager.findFragment(this) as ViewComponentFactory) - .createViewComponent(this).inject(this) + init { + (context.applicationContext as ApplicationInjectorProvider).getApplicationInjector() + .injectPromotedStoryListView(this) adapter = BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt index b2028020044..cc9b07caebd 100644 --- a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt +++ b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt @@ -25,5 +25,4 @@ interface ViewComponent { fun inject(dragDropSortInteractionView: DragDropSortInteractionView) fun inject(imageRegionSelectionInteractionView: ImageRegionSelectionInteractionView) fun inject(lessonThumbnailImageView: LessonThumbnailImageView) - fun inject(promotedStoryListView: PromotedStoryListView) } diff --git a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt index e50f65b7a17..00367dfd832 100644 --- a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt +++ b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt @@ -7,9 +7,11 @@ import androidx.appcompat.app.AppCompatActivity import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView +import androidx.test.espresso.intent.Intents import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.Component +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -69,9 +71,6 @@ class HomeSpanTest { private val internalProfileId: Int = 1 - @Inject - lateinit var testCoroutineDispatchers: TestCoroutineDispatchers - @Before fun setUp() { setUpTestApplicationComponent() @@ -85,7 +84,6 @@ class HomeSpanTest { @Test fun testHomeSpanTest_checkSpanForItem0_port_hasCorrectSpanCount() { launch(createHomeActivityIntent(internalProfileId)).use { - testCoroutineDispatchers.runCurrent() onView(withId(R.id.home_recycler_view)) .check( hasGridItemCount( From 057f9376829f44ffe33342c227bef06e741340b8 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 23 Dec 2020 22:04:18 -0800 Subject: [PATCH 115/248] Fix linter errors --- .../java/org/oppia/android/app/home/HomeFragmentPresenter.kt | 5 +++-- .../android/app/home/promotedlist/PromotedStoryListView.kt | 4 ---- .../main/java/org/oppia/android/app/view/ViewComponent.kt | 1 - .../test/java/org/oppia/android/app/testing/HomeSpanTest.kt | 3 --- 4 files changed, 3 insertions(+), 10 deletions(-) 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 995e94fe269..d1c0898080d 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 @@ -71,8 +71,9 @@ class HomeFragmentPresenter @Inject constructor( val homeLayoutManager = GridLayoutManager(activity.applicationContext, spanCount) homeLayoutManager.spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { - return if (position < homeAdapter.itemCount - && homeAdapter.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal) 1 + return if (position < homeAdapter.itemCount && + homeAdapter.getItemViewType(position) === ViewType.TOPIC_LIST.ordinal + ) 1 else spanCount } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index cf5d7d96d55..ac4d03ec583 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,15 +3,11 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import androidx.databinding.Bindable -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView import org.oppia.android.app.application.ApplicationInjectorProvider import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.ViewBindingShim -import org.oppia.android.app.shim.ViewComponentFactory import javax.inject.Inject /** diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt index cc9b07caebd..468a8531f3f 100644 --- a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt +++ b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt @@ -4,7 +4,6 @@ import android.view.View import dagger.BindsInstance import dagger.Subcomponent import org.oppia.android.app.customview.LessonThumbnailImageView -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 diff --git a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt index 00367dfd832..9a5833c634d 100644 --- a/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt +++ b/app/src/test/java/org/oppia/android/app/testing/HomeSpanTest.kt @@ -7,11 +7,9 @@ import androidx.appcompat.app.AppCompatActivity import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.espresso.Espresso.onView -import androidx.test.espresso.intent.Intents import androidx.test.espresso.matcher.ViewMatchers.withId import androidx.test.ext.junit.runners.AndroidJUnit4 import dagger.Component -import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -46,7 +44,6 @@ import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfiguration import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule import org.oppia.android.testing.TestAccessibilityModule -import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule import org.oppia.android.testing.TestLogReportingModule import org.oppia.android.util.caching.testing.CachingTestModule From a2113b22633d71626af63e6eaba24e21c865b02b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 25 Dec 2020 16:51:51 +0530 Subject: [PATCH 116/248] updated implementaion with stories for you --- .../domain/topic/StoryProgressTestHelper.kt | 50 ++- .../android/domain/topic/TopicController.kt | 7 + .../domain/topic/TopicListController.kt | 397 +++++++++--------- .../domain/topic/TopicControllerTest.kt | 27 +- .../domain/topic/TopicListControllerTest.kt | 19 +- model/src/main/proto/topic.proto | 21 + 6 files changed, 312 insertions(+), 209 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 6b7e2b3d954..347faace38d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -181,6 +181,49 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** Marks full story progress for a particular profile. */ + fun markFullProgressForFirstTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure + // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + timestamp + ) + } + + /** Marks full story progress for a particular profile. */ + fun markFullProgressForSecondTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure + // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + timestamp + ) + } + /** Marks one story progress full in ratios exploration for a particular profile. */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, @@ -191,13 +234,6 @@ class StoryProgressTestHelper @Inject constructor( } else { getOldTimestamp() } - storyProgressController.recordCompletedChapter( - profileId, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_0, - timestamp - ) storyProgressController.recordCompletedChapter( profileId, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt index c8c1d7414a0..5cff912eb01 100755 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt @@ -21,6 +21,7 @@ import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Subtopic import org.oppia.android.app.model.Topic +import org.oppia.android.app.model.TopicPlayAvailability import org.oppia.android.app.model.TopicProgress import org.oppia.android.domain.oppialogger.exceptions.ExceptionsController import org.oppia.android.domain.question.QuestionRetriever @@ -406,6 +407,11 @@ class TopicController @Inject constructor( createSubtopicListFromJsonArray(topicData.optJSONArray("subtopics")) val storySummaryList: List = createStorySummaryListFromJsonArray(topicId, topicData.optJSONArray("canonical_story_dicts")) + val topicPlayAvailability = if (topicData.getBoolean("published")) { + TopicPlayAvailability.newBuilder().setAvailableToPlayNow(true).build() + } else { + TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build() + } return Topic.newBuilder() .setTopicId(topicId) .setName(topicData.getString("topic_name")) @@ -414,6 +420,7 @@ class TopicController @Inject constructor( .setTopicThumbnail(createTopicThumbnail(topicData)) .setDiskSizeBytes(computeTopicSizeBytes(getAssetFileNameList(topicId))) .addAllSubtopic(subtopicList) + .setTopicPlayAvailability(topicPlayAvailability) .build() } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 3996637d6cf..d04cbd3da81 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -19,6 +19,9 @@ import org.oppia.android.app.model.RecommendedStoryList import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList +import org.oppia.android.app.model.TopicPlayAvailability +import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_IN_FUTURE +import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_NOW import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.model.UpcomingTopic @@ -41,6 +44,7 @@ private const val TOPIC_BG_COLOR = "#C6DCDA" const val TEST_TOPIC_ID_0 = "test_topic_id_0" const val TEST_TOPIC_ID_1 = "test_topic_id_1" +const val TEST_TOPIC_ID_2 = "test_topic_id_2" const val FRACTIONS_TOPIC_ID = "GJ2rLXRKD5hw" const val SUBTOPIC_TOPIC_ID = 1 const val SUBTOPIC_TOPIC_ID_2 = 2 @@ -142,7 +146,11 @@ class TopicListController @Inject constructor( .getJSONArray("topic_id_list") val topicListBuilder = TopicList.newBuilder() for (i in 0 until topicIdJsonArray.length()) { - topicListBuilder.addTopicSummary(createTopicSummary(topicIdJsonArray.optString(i)!!)) + val topicSummary = createTopicSummary(topicIdJsonArray.optString(i)!!) + // Only include topics currently playable in the topic list. + if (topicSummary.topicPlayAvailability.availabilityCase == AVAILABLE_TO_PLAY_NOW) { + topicListBuilder.addTopicSummary(topicSummary) + } } return topicListBuilder.build() } @@ -153,15 +161,12 @@ class TopicListController @Inject constructor( .getJSONArray("topic_id_list") val comingSoonTopicListBuilder = ComingSoonTopicList.newBuilder() for (i in 0 until topicIdJsonArray.length()) { - comingSoonTopicListBuilder.addUpcomingTopic( - createUpcomingTopicSummary( - topicIdJsonArray.optString( - i - )!! - ) - ) + val upcomingTopicSummary = createUpcomingTopicSummary(topicIdJsonArray.optString(i)!!) + // Only include topics currently not playable in the upcoming topic list. + if (upcomingTopicSummary.topicPlayAvailability.availabilityCase == AVAILABLE_TO_PLAY_IN_FUTURE) { + comingSoonTopicListBuilder.addUpcomingTopic(upcomingTopicSummary) + } } - RecommendedActivityList.newBuilder().setComingSoonTopicList(comingSoonTopicListBuilder) return comingSoonTopicListBuilder.build() } @@ -186,12 +191,18 @@ class TopicListController @Inject constructor( .getJSONArray("node_titles") .length() } + val topicPlayAvailability = if (jsonObject.getBoolean("published")) { + TopicPlayAvailability.newBuilder().setAvailableToPlayNow(true).build() + } else { + TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build() + } return TopicSummary.newBuilder() .setTopicId(topicId) .setName(jsonObject.getString("topic_name")) .setVersion(jsonObject.optInt("version")) .setTotalChapterCount(totalChapterCount) .setTopicThumbnail(createTopicThumbnail(jsonObject)) + .setTopicPlayAvailability(topicPlayAvailability) .build() } @@ -199,6 +210,7 @@ class TopicListController @Inject constructor( topicId: String, jsonObject: JSONObject ): UpcomingTopic { + val upcomingTopic = UpcomingTopic.newBuilder() var totalChapterCount = 0 val storyData = jsonObject.getJSONArray("canonical_story_dicts") for (i in 0 until storyData.length()) { @@ -207,13 +219,21 @@ class TopicListController @Inject constructor( .getJSONArray("node_titles") .length() } - return UpcomingTopic.newBuilder() - .setTopicId(topicId) - .setName(jsonObject.getString("topic_name")) - .setVersion(jsonObject.optInt("version")) - .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) - .setLessonThumbnail(createTopicThumbnail(jsonObject)) - .build() + val topicPlayAvailability = if (jsonObject.getBoolean("published")) { + TopicPlayAvailability.newBuilder().setAvailableToPlayNow(true).build() + } else { + TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build() + } + + return upcomingTopic.setTopicId(topicId) + .setName(jsonObject.getString("topic_name")) + .setVersion(jsonObject.optInt("version")) + .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) + .setTopicPlayAvailability(topicPlayAvailability) + .setLessonThumbnail(createTopicThumbnail(jsonObject)) + .build() + + } private fun createOngoingStoryListFromProgress( @@ -237,51 +257,53 @@ class TopicListController @Inject constructor( val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) + when { + recentlyPlayerChapterProgress != null -> { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } } } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) + lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } } } } @@ -315,48 +337,119 @@ class TopicListController @Inject constructor( ): RecommendedActivityList { val recommendedActivityListBuilder = RecommendedActivityList.newBuilder() + Log.d("topic prog","size - "+ topicProgressList.size) if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() if (topicProgressList.size == 1) { recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( - topicProgressList + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder ) ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + if (recommendedStoryBuilder.suggestedStoryCount == 0 && recommendedStoryBuilder.recentlyPlayedStoryCount == 0 + && recommendedStoryBuilder.olderPlayedStoryCount == 0) { + recommendedActivityListBuilder.setComingSoonTopicList( createComingSoonTopicList()) + } } else { - val sortedTopicProgressList = - topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - sortedTopicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) + // Add recently played stories or last played stories in RecommendedActivityList. + createRecentPlayedStories( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) + + // If no recently played stories or last played stories then set suggested stories stories in RecommendedActivityList. + when { + recommendedStoryBuilder.recentlyPlayedStoryCount == 0 + && recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { + recommendedStoryBuilder.addAllSuggestedStory( + createRecommendedStoryList( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) + ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + + // If user has completed all the topcs then add upcoming topics in RecommendedActivityList. + if (recommendedStoryBuilder.suggestedStoryCount == 0) { + recommendedActivityListBuilder.setComingSoonTopicList( createComingSoonTopicList()) + } + + } + } + } + } + return recommendedActivityListBuilder.build() + } + + private fun createRecentPlayedStories( + topicProgressList: List, + recommendedActivityListBuilder: RecommendedActivityList.Builder, + recommendedStoryBuilder: RecommendedStoryList.Builder + ) { + val sortedTopicProgressList = + topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + + sortedTopicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) - val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() + val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() - val startedChapterProgressList = getStartedChapterProgressList(storyProgress) + val startedChapterProgressList = getStartedChapterProgressList(storyProgress) - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { + when { + recentlyPlayerChapterProgress != null -> { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) + } else { + recommendedStoryBuilder.addOlderPlayedStory(promotedStory) + } + } + } + lastCompletedChapterProgress != null -> { + if (lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, completedChapterProgressList.size, story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId + nextChapterSummary.name, + nextChapterSummary.explorationId ) if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) @@ -364,144 +457,50 @@ class TopicListController @Inject constructor( recommendedStoryBuilder.addOlderPlayedStory(promotedStory) } } - } else if (lastCompletedChapterProgress != null) { - if (lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) - } else { - recommendedStoryBuilder.addOlderPlayedStory(promotedStory) - } - } - } } } - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - } - if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount > 0 - && recommendedStoryBuilder.suggestedStoryCount == 0 - ) { - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - } - if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 - && recommendedStoryBuilder.olderPlayedStoryCount == 0 - ) { - recommendedStoryBuilder.addAllSuggestedStory(createRecommendedStoryList(topicProgressList)) - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - - if (recommendedStoryBuilder.suggestedStoryCount == 0) { - recommendedActivityListBuilder.setComingSoonTopicList(createComingSoonTopicList()) - } } } + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } - return recommendedActivityListBuilder.build() } private fun createRecommendedStoryList( - topicProgressList: List + topicProgressList: List, + recommendedActivityListBuilder: RecommendedActivityList.Builder, + recommendedStoryBuilder: RecommendedStoryList.Builder ): List { - val recommendedStories = ArrayList() - topicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) + val recommendedStories = mutableListOf() - val completedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - val startedChapterProgressList = - storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - - val lastCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() - - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() - if (recentlyPlayerChapterProgress != null) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } - } else if (lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - recommendedStories.add(promotedStory) - } - } - } - } + createRecentPlayedStories( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") - val topicList = mutableListOf() - for (i in 0 until topicIdJsonArray.length()) { - topicList.add(topicIdJsonArray[i].toString()) - } + val topicIdList = (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } + + val index = topicIdList.indexOf(topicProgressList.last().topicId) - val index = topicList.indexOf(topicProgressList.last().topicId) - if (topicIdJsonArray.length() > (index + 1)) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[index + 1].toString())) - return recommendedStories + for (i in (index+1) until topicIdJsonArray.length()) { + if (topicIdJsonArray.length() > i && createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) + return recommendedStories + } } return recommendedStories } - private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory { + private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!! + if (!topicJson.getBoolean("published")) { + // Do not recommend unpublished topics. + return null + } val storyData = topicJson.getJSONArray("canonical_story_dicts") if (storyData.length() == 0) { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt index 3094d5cdd86..508e6971ed5 100755 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicControllerTest.kt @@ -31,6 +31,8 @@ import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.Question import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic +import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_IN_FUTURE +import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_NOW import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.FakeExceptionLogger import org.oppia.android.testing.TestCoroutineDispatchers @@ -216,7 +218,30 @@ class TopicControllerTest { testCoroutineDispatchers.runCurrent() verifyGetTopicFailed() - assertThat(topicResultCaptor.value!!.isFailure()).isTrue() + } + + @Test + fun testRetrieveTopic_testTopic_published_returnsAsAvailable() { + topicController.getTopic( + profileId1, TEST_TOPIC_ID_0 + ).toLiveData().observeForever(mockTopicObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetTopicSucceeded() + val topic = topicResultCaptor.value.getOrThrow() + assertThat(topic.topicPlayAvailability.availabilityCase).isEqualTo(AVAILABLE_TO_PLAY_NOW) + } + + @Test + fun testRetrieveTopic_testTopic_unpublished_returnsAsAvailableInFuture() { + topicController.getTopic( + profileId1, TEST_TOPIC_ID_2 + ).toLiveData().observeForever(mockTopicObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetTopicSucceeded() + val topic = topicResultCaptor.value.getOrThrow() + assertThat(topic.topicPlayAvailability.availabilityCase).isEqualTo(AVAILABLE_TO_PLAY_IN_FUTURE) } @Test diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index a1c14105f15..7429c548c8e 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -28,6 +28,7 @@ import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.TopicList +import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.model.UpcomingTopic import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.TestCoroutineDispatchers @@ -297,6 +298,21 @@ class TopicListControllerTest { assertThat(ratiosTopic.totalChapterCount).isEqualTo(4) } + @Test + fun testRetrieveTopicList_doesNotContainUnavailableTopic() { + val topicListLiveData = topicListController.getTopicList().toLiveData() + + topicListLiveData.observeForever(mockTopicListObserver) + testCoroutineDispatchers.runCurrent() + + // Verify that the topic list does not contain a not-yet published topic (since it can't be + // played by the user). + verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) + val topicList = topicListResultCaptor.value.getOrThrow() + val topicIds = topicList.topicSummaryList.map(TopicSummary::getTopicId) + assertThat(topicIds).doesNotContain(TEST_TOPIC_ID_2) + } + @Test fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -457,7 +473,6 @@ class TopicListControllerTest { verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) } - // TODO(#2303): Rewrite this testcase for coming soon topics. @Test fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -578,7 +593,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(4) + assertThat(recommendedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) } @Test diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 932332f0ba0..795b7e8b5d5 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -32,6 +32,21 @@ message Topic { // The number of on-disk bytes this topic consumes. int64 disk_size_bytes = 7; + + // Specifics about whether this topic is playable. + TopicPlayAvailability topic_play_availability = 8; +} + +// Corresponds to details around whether a particular topic is playable. +message TopicPlayAvailability { + // Corresponds to the availability of this topic (e.g. whether it can be played now). + oneof availability { + // Indicates this topic is available to be played. + bool available_to_play_now = 1; + + // Indicates this topic is not yet available to be played but is expected to be in the future. + bool available_to_play_in_future = 2; + } } // Corresponds to a concept card that can be displayed for a specific skill. @@ -206,6 +221,9 @@ message TopicSummary { // The associated thumbnail that should be displayed with this topic summary. LessonThumbnail topic_thumbnail = 5; + + // Specifics about whether this topic is playable. + TopicPlayAvailability topic_play_availability = 6; } // Represents the play state of a single chapter. @@ -288,6 +306,9 @@ message UpcomingTopic { // The associated thumbnail that should be displayed with this topic. LessonThumbnail lesson_thumbnail = 5; + + // Specifics about whether this topic is playable. + TopicPlayAvailability topic_play_availability = 6; } // Represents the story progress. From 1714d1551c86ed750c4c4a2f1de58b25b381dfeb Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 25 Dec 2020 17:08:35 +0530 Subject: [PATCH 117/248] updated code. --- .../android/domain/topic/TopicListController.kt | 2 +- .../domain/topic/TopicListControllerTest.kt | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 6a524283e98..c05dae1b889 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -20,6 +20,7 @@ import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicPlayAvailability +import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_IN_FUTURE import org.oppia.android.app.model.TopicPlayAvailability.AvailabilityCase.AVAILABLE_TO_PLAY_NOW import org.oppia.android.app.model.TopicProgress import org.oppia.android.app.model.TopicSummary @@ -377,7 +378,6 @@ class TopicListController @Inject constructor( if (recommendedStoryBuilder.suggestedStoryCount == 0) { recommendedActivityListBuilder.setComingSoonTopicList( createComingSoonTopicList()) } - } } } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index fdfa4ebfed1..7429c548c8e 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -313,21 +313,6 @@ class TopicListControllerTest { assertThat(topicIds).doesNotContain(TEST_TOPIC_ID_2) } - @Test - fun testRetrieveTopicList_doesNotContainUnavailableTopic() { - val topicListLiveData = topicListController.getTopicList().toLiveData() - - topicListLiveData.observeForever(mockTopicListObserver) - testCoroutineDispatchers.runCurrent() - - // Verify that the topic list does not contain a not-yet published topic (since it can't be - // played by the user). - verify(mockTopicListObserver).onChanged(topicListResultCaptor.capture()) - val topicList = topicListResultCaptor.value.getOrThrow() - val topicIds = topicList.topicSummaryList.map(TopicSummary::getTopicId) - assertThat(topicIds).doesNotContain(TEST_TOPIC_ID_2) - } - @Test fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( From c43a1876208dae3545fe904e4e8a330774b1364c Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 25 Dec 2020 17:24:41 +0530 Subject: [PATCH 118/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 30 ++----------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 7429c548c8e..c2ecfc48b37 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -319,30 +319,7 @@ class TopicListControllerTest { profileId0, FRACTIONS_TOPIC_ID, FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - topicListController.getRecommendedActivityList(profileId0).toLiveData() - .observeForever(mockRecommendedActivityListObserver) - testCoroutineDispatchers.runCurrent() - - verifyGetRecommendedActivityListSucceeded() - - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[1]) - } - - @Test - fun testRetrieveRecommendedStoryList_markRecentlyPlayedFracStory0Exp0_recommendedStoryListIsCorrect() { - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, + FRACTIONS_EXPLORATION_ID_1, getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() @@ -354,9 +331,8 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[1]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) } @Test From e43a9fd5200893a831e5ee6efd8ac104b1b1e0e7 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 26 Dec 2020 17:57:21 +0530 Subject: [PATCH 119/248] Update topic.proto --- model/src/main/proto/topic.proto | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 795b7e8b5d5..c0a7c48c2a0 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -262,7 +262,7 @@ message TopicProgress { int64 last_played_timestamp = 3; } -// A structure corresponding to the Promoted Stories. This structure is set up +// A structure corresponding to the promoted stories. This structure is set up // to properly account for recently played stories, recommended stories // and coming soon topics. message RecommendedActivityList { @@ -272,7 +272,7 @@ message RecommendedActivityList { } } -// Corresponds to the list of stories the player is currently playing across all topics and Recommended stories. +// Corresponds to the list of stories the player is currently playing across all topics and recommended stories. message RecommendedStoryList { // Ongoing stories from within the last 7 days. repeated PromotedStory recently_played_story = 1; From 002420c35312cb434e2556d9d1d32c2d3c48bfaf Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 30 Dec 2020 17:00:35 +0530 Subject: [PATCH 120/248] fixed nit changes and lint error --- .idea/gradle.xml | 26 ++++ .../domain/topic/StoryProgressTestHelper.kt | 39 +---- .../domain/topic/TopicListController.kt | 98 +++++++------ .../topic/StoryProgressTestHelperTest.kt | 41 ++++++ .../domain/topic/TopicListControllerTest.kt | 137 +++++++++--------- model/src/main/proto/topic.proto | 2 +- 6 files changed, 200 insertions(+), 143 deletions(-) create mode 100644 .idea/gradle.xml diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 00000000000..6aa35f75034 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + + diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 372e31f3874..9fa1c472792 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -24,7 +24,8 @@ class StoryProgressTestHelper @Inject constructor( * Creates a partial story progress for a particular profile. * * @param profileId The profile we are setting partial progress of the fraction story for. - * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. + * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more + * than one week ago. */ fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { @@ -45,7 +46,8 @@ class StoryProgressTestHelper @Inject constructor( * Creates a partial topic progress for a particular profile. * * @param profileId The profile we are setting partial progress of the fraction topic for. - * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than one week ago. + * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than + * one week ago. */ fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { @@ -127,7 +129,7 @@ class StoryProgressTestHelper @Inject constructor( */ fun markFullProgressForAllTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { markFullTopicProgressForFractions(profileId, timestampOlderThanOneWeek) - markFullTopicProgressForTestTopics(profileId, timestampOlderThanOneWeek) + markFullTopicProgressForTestTopic(profileId, timestampOlderThanOneWeek) markFullTopicProgressForRatios(profileId, timestampOlderThanOneWeek) } @@ -137,13 +139,12 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId The profile we are setting topic progress for. * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ - fun markFullTopicProgressForTestTopics(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + fun markFullTopicProgressForTestTopic(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() } - markFullTopicProgressForFractions(profileId, timestampOlderThanOneWeek) // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. storyProgressController.recordCompletedChapter( @@ -234,32 +235,7 @@ class StoryProgressTestHelper @Inject constructor( } /** Marks full story progress for a particular profile. */ - fun markFullProgressForFirstTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { - getCurrentTimestamp() - } else { - getOldTimestamp() - } - // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure - // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. - storyProgressController.recordCompletedChapter( - profileId, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_2, - timestamp - ) - storyProgressController.recordCompletedChapter( - profileId, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_5, - timestamp - ) - } - - /** Marks full story progress for a particular profile. */ - fun markFullProgressForSecondTopics(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + fun markFullProgressForSecondTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { @@ -276,7 +252,6 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** * Marks one story progress full in ratios exploration for a particular profile. * diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index c05dae1b889..ec105166d0b 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -2,8 +2,6 @@ package org.oppia.android.domain.topic import android.graphics.Color import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import org.json.JSONObject import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.ChapterProgress @@ -31,11 +29,9 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.system.OppiaClock -import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton -import kotlin.collections.ArrayList private const val ONE_WEEK_IN_DAYS = 7 private const val ONE_DAY_IN_MS = 24 * 60 * 60 * 1000 @@ -80,7 +76,6 @@ val EXPLORATION_THUMBNAILS = mapOf( ) private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" -private const val GET_COMING_SOON_TOPIC_LIST_PROVIDER_ID = "get_coming_soon_topic_list_provider_id" private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" @@ -163,7 +158,9 @@ class TopicListController @Inject constructor( for (i in 0 until topicIdJsonArray.length()) { val upcomingTopicSummary = createUpcomingTopicSummary(topicIdJsonArray.optString(i)!!) // Only include topics currently not playable in the upcoming topic list. - if (upcomingTopicSummary.topicPlayAvailability.availabilityCase == AVAILABLE_TO_PLAY_IN_FUTURE) { + if (upcomingTopicSummary.topicPlayAvailability.availabilityCase + == AVAILABLE_TO_PLAY_IN_FUTURE + ) { comingSoonTopicListBuilder.addUpcomingTopic(upcomingTopicSummary) } } @@ -225,15 +222,13 @@ class TopicListController @Inject constructor( TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build() } - return upcomingTopic.setTopicId(topicId) - .setName(jsonObject.getString("topic_name")) - .setVersion(jsonObject.optInt("version")) - .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) - .setTopicPlayAvailability(topicPlayAvailability) - .setLessonThumbnail(createTopicThumbnail(jsonObject)) - .build() - - + return upcomingTopic.setTopicId(topicId) + .setName(jsonObject.getString("topic_name")) + .setVersion(jsonObject.optInt("version")) + .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) + .setTopicPlayAvailability(topicPlayAvailability) + .setLessonThumbnail(createTopicThumbnail(jsonObject)) + .build() } private fun createOngoingStoryListFromProgress( @@ -264,8 +259,10 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + recentlyPlayerChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -282,15 +279,19 @@ class TopicListController @Inject constructor( } } lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } + lastCompletedChapterProgress.explorationId != + story.chapterList.last().explorationId -> { + val lastChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + lastCompletedChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -320,7 +321,6 @@ class TopicListController @Inject constructor( ChapterPlayState.STARTED_NOT_COMPLETED } .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - } private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List { @@ -337,7 +337,7 @@ class TopicListController @Inject constructor( ): RecommendedActivityList { val recommendedActivityListBuilder = RecommendedActivityList.newBuilder() - Log.d("topic prog","size - "+ topicProgressList.size) + Log.d("topic prog", "size - " + topicProgressList.size) if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() if (topicProgressList.size == 1) { @@ -349,9 +349,11 @@ class TopicListController @Inject constructor( ) ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - if (recommendedStoryBuilder.suggestedStoryCount == 0 && recommendedStoryBuilder.recentlyPlayedStoryCount == 0 - && recommendedStoryBuilder.olderPlayedStoryCount == 0) { - recommendedActivityListBuilder.setComingSoonTopicList( createComingSoonTopicList()) + if (recommendedStoryBuilder.suggestedStoryCount == 0 && + recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount == 0 + ) { + recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } } else { // Add recently played stories or last played stories in RecommendedActivityList. @@ -361,10 +363,11 @@ class TopicListController @Inject constructor( recommendedStoryBuilder ) - // If no recently played stories or last played stories then set suggested stories stories in RecommendedActivityList. + // If no recently played stories or last played stories then set suggested stories + // in RecommendedActivityList. when { - recommendedStoryBuilder.recentlyPlayedStoryCount == 0 - && recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { + recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList, @@ -374,9 +377,10 @@ class TopicListController @Inject constructor( ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - // If user has completed all the topcs then add upcoming topics in RecommendedActivityList. + // If user has completed all the topcs then add upcoming topics in + // RecommendedActivityList. if (recommendedStoryBuilder.suggestedStoryCount == 0) { - recommendedActivityListBuilder.setComingSoonTopicList( createComingSoonTopicList()) + recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } } } @@ -415,8 +419,10 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + recentlyPlayerChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -433,15 +439,19 @@ class TopicListController @Inject constructor( } } lastCompletedChapterProgress != null -> { - if (lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId) { + if (lastCompletedChapterProgress.explorationId + != story.chapterList.last().explorationId + ) { val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> lastCompletedChapterProgress.explorationId == chapterSummary.explorationId } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = - (oppiaClock.getCurrentCalendar().timeInMillis - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + lastCompletedChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -485,11 +495,13 @@ class TopicListController @Inject constructor( val index = topicIdList.indexOf(topicProgressList.last().topicId) - for (i in (index+1) until topicIdJsonArray.length()) { - if (topicIdJsonArray.length() > i && createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) - return recommendedStories - } + for (i in (index + 1) until topicIdJsonArray.length()) { + if (topicIdJsonArray.length() > i && + createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null + ) { + recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) + return recommendedStories + } } return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index a414b0de05e..af0fc40aca2 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -26,6 +26,7 @@ import org.oppia.android.app.model.CompletedStoryList import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList @@ -80,6 +81,13 @@ class StoryProgressTestHelperTest { @Mock lateinit var mockOngoingStoryListObserver: Observer> + @Mock + lateinit var mockRecommendedActivityListObserver: Observer> + + @Captor + lateinit var recommendedActivityListResultCaptor: + ArgumentCaptor> + @Captor lateinit var ongoingStoryListResultCaptor: ArgumentCaptor> @@ -809,6 +817,31 @@ class StoryProgressTestHelperTest { assertThat(ongoingStoryList.recentStoryList[1].completedChapterCount).isEqualTo(0) } + @Test + fun testProgressTestHelper_markFullProgressForSecondTopic_showRecommendedStories_storyListIsCorrect() { // ktlint-disable max-line-length + storyProgressTestHelper.markFullProgressForSecondTopic( + profileId, + /* timestampOlderThanAWeek= */ false + ) + testCoroutineDispatchers.runCurrent() + + topicListController.getRecommendedActivityList(profileId).toLiveData() + .observeForever(mockRecommendedActivityListObserver) + testCoroutineDispatchers.runCurrent() + + verifyGetRecommendedActivityListSucceeded() + + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryList[0].explorationId) + .isEqualTo( + FRACTIONS_EXPLORATION_ID_0 + ) + } + @Test fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_ongoingStoryListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( @@ -878,6 +911,14 @@ class StoryProgressTestHelperTest { assertThat(ongoingStoryListResultCaptor.value.isSuccess()).isTrue() } + private fun verifyGetRecommendedActivityListSucceeded() { + verify( + mockRecommendedActivityListObserver, + atLeastOnce() + ).onChanged(recommendedActivityListResultCaptor.capture()) + assertThat(recommendedActivityListResultCaptor.value.isSuccess()).isTrue() + } + private fun verifyGetTopicListSucceeded() { verify( mockTopicListObserver, diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index c2ecfc48b37..864864a9272 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -11,7 +11,6 @@ import dagger.Component import dagger.Module import dagger.Provides import org.junit.Before -import org.junit.Ignore import org.junit.Rule import org.junit.Test import org.junit.runner.RunWith @@ -22,14 +21,12 @@ import org.mockito.Mockito.atLeastOnce import org.mockito.Mockito.verify import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule -import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnailGraphic -import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary -import org.oppia.android.app.model.UpcomingTopic import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule @@ -79,9 +76,6 @@ class TopicListControllerTest { @Mock lateinit var mockTopicListObserver: Observer> - @Mock - lateinit var mockComingSoonTopicListObserver: Observer> - @Mock lateinit var mockRecommendedActivityListObserver: Observer> @@ -89,10 +83,8 @@ class TopicListControllerTest { lateinit var topicListResultCaptor: ArgumentCaptor> @Captor - lateinit var comingSoonTopicListResultCaptor: ArgumentCaptor> - - @Captor - lateinit var recommendedActivityListResultCaptor: ArgumentCaptor> + lateinit var recommendedActivityListResultCaptor: + ArgumentCaptor> private lateinit var profileId0: ProfileId @@ -314,7 +306,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { + fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -331,12 +323,15 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0( + recommendedActivityList.recommendedStoryList.suggestedStoryList[0] + ) } @Test - fun testRetrieveSuggestedStoryList_markAllChaptersCompletedInFractions_suggestedStoryListIsCorrect() { + fun testRetrieveSuggestedStoryList_markAllChaptersCompletedInFractions_suggestedStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -362,12 +357,13 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount) + .isEqualTo(1) verifyDefaultRecommendedStoryListSucceeded() } @Test - fun testRetrieveRecentStoryList_markAllChaptersCompletedInFractions_fromRecommendedList_playedFirstTopicStory0Exploration0_recentStoryListIsCorrect() { + fun testRetrieveRecentStoryList_markAllChaptersCompletedInFractions_fromRecommendedList_playedFirstTopicStory0Exploration0_recentStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -402,13 +398,16 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsFirstTopicStory0Exploration0( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] + ) } @Test - fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_fromRecommendedStories_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { + fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_fromRecommendedStories_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -444,13 +443,18 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration0( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1] + ) } - @Test - fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { + @Test + fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -485,14 +489,21 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[2]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration3( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[1] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[2] + ) } @Test - fun testRetrieveRecommendedStoryList_markFirstStoryOfFractDone_noMoreOngoingList_recommendedListIsCorrect() { + fun testRetrieveRecommendedStoryList_markFirstStoryOfFractDone_noMoreOngoingList_recommendedListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -518,12 +529,14 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount) + .isEqualTo(1) } @Test - fun testRetrieveComingSoonTopicList_markFirstStoryOfEveryTopicDoneWithinLastSevenDays_comingSoonListIsCorrect() { + fun testRetrieveComingSoonTopicList_markFirstStoryOfEveryTopicDoneWithinLastSevenDays_comingSoonListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -567,9 +580,12 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(0) - assertThat(recommendedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount) + .isEqualTo(0) + assertThat(recommendedActivityList.comingSoonTopicList.upcomingTopicCount) + .isEqualTo(1) } @Test @@ -608,11 +624,19 @@ class TopicListControllerTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount).isEqualTo(1) - assertThat(recommendedActivityList.recommendedStoryList.olderPlayedStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(recommendedActivityList.recommendedStoryList.olderPlayedStoryList[0]) - verifyOngoingStoryAsFractionStory0Exploration1(recommendedActivityList.recommendedStoryList.olderPlayedStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0]) + assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + assertThat(recommendedActivityList.recommendedStoryList.olderPlayedStoryCount) + .isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1( + recommendedActivityList.recommendedStoryList.olderPlayedStoryList[0] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + recommendedActivityList.recommendedStoryList.olderPlayedStoryList[1] + ) + verifyOngoingStoryAsRatioStory1Exploration3( + recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] + ) } private fun verifyGetRecommendedActivityListSucceeded() { @@ -625,8 +649,11 @@ class TopicListControllerTest { private fun verifyDefaultRecommendedStoryListSucceeded() { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(recommendedActivityList.recommendedStoryList.suggestedStoryList[0]) + assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0( + recommendedActivityList.recommendedStoryList.suggestedStoryList[0] + ) } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { @@ -641,30 +668,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - private fun verifyOngoingStoryAsSecondTopicStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) - assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) - assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) - assertThat(promotedStory.topicName).isEqualTo("Second Test Topic") - assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(1) - } - - private fun verifyOngoingStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) - assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) - assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) - assertThat(promotedStory.topicName).isEqualTo("Fractions") - assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(2) - } - private fun verifyOngoingStoryAsFractionStory0Exploration1(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_1) assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index c0a7c48c2a0..1dc7201c3db 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -286,7 +286,7 @@ message RecommendedStoryList { // Corresponds to the list of coming soon topics that can be shown on the home screen. message ComingSoonTopicList { - // Upcoming topics for the user. + // Upcoming topics for the learner. repeated UpcomingTopic upcoming_topic = 1; } From 9330df166ae5ce37b3a7f32b6268dcef422d1ac5 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 30 Dec 2020 17:04:52 +0530 Subject: [PATCH 121/248] Update topic.proto --- model/src/main/proto/topic.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 1dc7201c3db..db7c03674b0 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -290,7 +290,7 @@ message ComingSoonTopicList { repeated UpcomingTopic upcoming_topic = 1; } -// Represents upcoming topics +// Represents topics not yet ready to be played by the learner. message UpcomingTopic { // The ID of the topic. string topic_id = 1; From 136abc810a84b0d4d9c6235ecd1e65738cba4010 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 30 Dec 2020 17:05:22 +0530 Subject: [PATCH 122/248] Delete coming_soon_topics.json --- domain/src/main/assets/coming_soon_topics.json | 8 -------- 1 file changed, 8 deletions(-) delete mode 100644 domain/src/main/assets/coming_soon_topics.json diff --git a/domain/src/main/assets/coming_soon_topics.json b/domain/src/main/assets/coming_soon_topics.json deleted file mode 100644 index 70aa6bfd57a..00000000000 --- a/domain/src/main/assets/coming_soon_topics.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "topic_id_list": [ - "test_topic_id_0", - "test_topic_id_1", - "GJ2rLXRKD5hw", - "omzF4oqgeTXd" - ] -} From 586bd3fb171ef5056743c9e5cbb6e3aa3388d1cb Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 30 Dec 2020 18:01:39 +0530 Subject: [PATCH 123/248] Update TopicListControllerTest.kt --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 864864a9272..369acc54c59 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -453,7 +453,7 @@ class TopicListControllerTest { ) } - @Test + @Test fun testRetrieveRecentlyStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_recentStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, From 9b23ee7046320e128e1165a6372ee83c49374a49 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 5 Jan 2021 12:22:05 -0800 Subject: [PATCH 124/248] Use fragment injection in custom recycler view, override equals in view models --- .../android/app/application/ApplicationInjector.kt | 3 --- .../org/oppia/android/app/home/WelcomeViewModel.kt | 11 +++++++++++ .../app/home/promotedlist/PromotedStoryListView.kt | 12 ++++++++---- .../home/promotedlist/PromotedStoryListViewModel.kt | 11 +++++++++++ .../app/home/promotedlist/PromotedStoryViewModel.kt | 12 ++++++++++++ .../app/home/topiclist/TopicSummaryViewModel.kt | 12 ++++++++++++ .../app/recyclerview/RecyclerViewBindingAdapter.java | 2 ++ .../java/org/oppia/android/app/view/ViewComponent.kt | 2 ++ 8 files changed, 58 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt b/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt index 3663fffb9d8..97d28db1361 100644 --- a/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt +++ b/app/src/main/java/org/oppia/android/app/application/ApplicationInjector.kt @@ -1,6 +1,5 @@ package org.oppia.android.app.application -import org.oppia.android.app.home.promotedlist.PromotedStoryListView import org.oppia.android.app.profile.ProfileInputView import org.oppia.android.util.data.DataProvidersInjector @@ -9,6 +8,4 @@ interface ApplicationInjector : DataProvidersInjector { // TODO(#1619): Remove post-modularization. fun inject(profileInputView: ProfileInputView) - - fun injectPromotedStoryListView(promotedStoryListView: PromotedStoryListView) } diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index edc25ef8aef..c69c004a8f4 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -17,4 +17,15 @@ class WelcomeViewModel( fragment.requireContext(), oppiaClock ).getGreetingMessage() + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || other.javaClass != javaClass) { + return false + } + val otherResult = other as WelcomeViewModel + return otherResult.profileName == this.profileName + } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index ac4d03ec583..71110e46703 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,11 +3,13 @@ package org.oppia.android.app.home.promotedlist 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.application.ApplicationInjectorProvider import org.oppia.android.app.recyclerview.BindableAdapter import org.oppia.android.app.recyclerview.StartSnapHelper import org.oppia.android.app.shim.ViewBindingShim +import org.oppia.android.app.shim.ViewComponentFactory import javax.inject.Inject /** @@ -23,9 +25,11 @@ class PromotedStoryListView @JvmOverloads constructor( @Inject lateinit var bindingInterface: ViewBindingShim - init { - (context.applicationContext as ApplicationInjectorProvider).getApplicationInjector() - .injectPromotedStoryListView(this) + override fun onAttachedToWindow() { + super.onAttachedToWindow() + + (FragmentManager.findFragment(this) as ViewComponentFactory) + .createViewComponent(this).inject(this) adapter = BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index d05eca1dc6c..266828a9619 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -48,4 +48,15 @@ class PromotedStoryListViewModel( fun clickOnViewAll() { routeToRecentlyPlayedListener.routeToRecentlyPlayed() } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || other.javaClass != javaClass) { + return false + } + val otherResult = other as PromotedStoryListViewModel + return otherResult.promotedStoryList == this.promotedStoryList + } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 51fdce1763f..7e8880961c0 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -42,4 +42,16 @@ class PromotedStoryViewModel( promotedStory.storyId ) } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || other.javaClass != javaClass) { + return false + } + val otherResult = other as PromotedStoryViewModel + return otherResult.internalProfileId == this.internalProfileId && + otherResult.promotedStory == this.promotedStory + } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 0b4d6abffaf..3367f5bf2a9 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -126,4 +126,16 @@ class TopicSummaryViewModel( hsv[2] = (hsv[2] * DARKEN_VALUE_MULTIPLIER).coerceIn(0f, 1f) return Color.HSVToColor(hsv) } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other == null || other.javaClass != javaClass) { + return false + } + val otherResult = other as TopicSummaryViewModel + return otherResult.topicSummary == this.topicSummary && + otherResult.position == this.position + } } diff --git a/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java b/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java index b3173bbc45f..9b0620722f4 100644 --- a/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java +++ b/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java @@ -1,6 +1,8 @@ package org.oppia.android.app.recyclerview; import android.graphics.drawable.Drawable; +import android.util.Log; + import androidx.annotation.NonNull; import androidx.databinding.BindingAdapter; import androidx.databinding.ObservableList; diff --git a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt index 468a8531f3f..b2028020044 100644 --- a/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt +++ b/app/src/main/java/org/oppia/android/app/view/ViewComponent.kt @@ -4,6 +4,7 @@ import android.view.View import dagger.BindsInstance import dagger.Subcomponent import org.oppia.android.app.customview.LessonThumbnailImageView +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 @@ -24,4 +25,5 @@ interface ViewComponent { fun inject(dragDropSortInteractionView: DragDropSortInteractionView) fun inject(imageRegionSelectionInteractionView: ImageRegionSelectionInteractionView) fun inject(lessonThumbnailImageView: LessonThumbnailImageView) + fun inject(promotedStoryListView: PromotedStoryListView) } From 206bc41183b9d7891b7e8d398b214102f95e02aa Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 5 Jan 2021 13:38:35 -0800 Subject: [PATCH 125/248] Shorten error message --- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index e1bc4d20505..7313e394b84 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -88,7 +88,7 @@ class HomeViewModel( if (itemListResult.isFailure()) { logger.e( "HomeFragment", - "No home fragment available -- failed to retrieve home fragment information.", + "No home fragment available -- failed to retrieve fragment information.", itemListResult.getErrorOrNull() ) } From 7c23c9fc852abfe268c16b9ebef83dcf552f32d5 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 5 Jan 2021 13:38:35 -0800 Subject: [PATCH 126/248] Shorten error message --- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index e1bc4d20505..0ae6fd9f527 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -88,7 +88,7 @@ class HomeViewModel( if (itemListResult.isFailure()) { logger.e( "HomeFragment", - "No home fragment available -- failed to retrieve home fragment information.", + "No home fragment available -- failed to retrieve fragment data.", itemListResult.getErrorOrNull() ) } From 6701b059af5f76f8071d846d435e8eb413cf4baa Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 6 Jan 2021 17:29:07 +0530 Subject: [PATCH 127/248] fixed nit changes --- .../domain/topic/StoryProgressController.kt | 7 +- .../domain/topic/StoryProgressTestHelper.kt | 38 ++++- .../domain/topic/TopicListController.kt | 138 +++++++++++------- .../topic/StoryProgressTestHelperTest.kt | 2 +- 4 files changed, 130 insertions(+), 55 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 9227369890a..091740c684d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -13,7 +13,7 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.logging.ConsoleLogger -import java.util.Date +import org.oppia.android.util.system.OppiaClock import javax.inject.Inject import javax.inject.Singleton @@ -56,6 +56,7 @@ private const val RECORD_RECENTLY_PLAYED_CHAPTER_PROVIDER_ID = class StoryProgressController @Inject constructor( private val cacheStoreFactory: PersistentCacheStore.Factory, private val dataProviders: DataProviders, + private val oppiaClock: OppiaClock, private val logger: ConsoleLogger ) { // TODO(#21): Determine whether chapters can have missing prerequisites in the initial prototype, @@ -112,7 +113,9 @@ class StoryProgressController @Inject constructor( val storyProgress = storyProgressBuilder.build() val topicProgressBuilder = - TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(Date().time) + TopicProgress.newBuilder() + .setTopicId(topicId) + .setLastPlayedTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 9fa1c472792..a1ef5fcbefb 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -267,7 +267,37 @@ class StoryProgressTestHelper @Inject constructor( } else { getOldTimestamp() } + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + timestamp + ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + timestamp + ) + } + /** + * Marks one story progress full in ratios exploration for a particular profile. + * + * @param profileId The profile we are setting topic progress on ratios for. + * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. + */ + fun markLastChapterDoneOfFirstStoryTopicProgressForRatios( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } storyProgressController.recordCompletedChapter( profileId, RATIOS_TOPIC_ID, @@ -275,6 +305,13 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_EXPLORATION_ID_1, timestamp ) + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + timestamp + ) } /** @@ -297,7 +334,6 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_EXPLORATION_ID_0, timestamp ) - storyProgressController.recordCompletedChapter( profileId, RATIOS_TOPIC_ID, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index ec105166d0b..dad5525be09 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -1,7 +1,6 @@ package org.oppia.android.domain.topic import android.graphics.Color -import android.util.Log import org.json.JSONObject import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.ChapterProgress @@ -15,6 +14,7 @@ import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.RecommendedStoryList import org.oppia.android.app.model.StoryProgress +import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicPlayAvailability @@ -125,7 +125,7 @@ class TopicListController @Inject constructor( * * @param profileId the ID corresponding to the profile for which [PromotedStory] needs to be * fetched. - * @return a [DataProvider] for an [OngoingStoryList]. + * @return a [DataProvider] for an [RecommendedActivityList]. */ fun getRecommendedActivityList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) @@ -254,58 +254,26 @@ class TopicListController @Inject constructor( when { recentlyPlayerChapterProgress != null -> { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } - } + createOngoingStoryListBasedOnRecentlyPlayed( + storyId, + story, + recentlyPlayerChapterProgress, + completedChapterProgressList, + topic, + ongoingStoryListBuilder + ) } lastCompletedChapterProgress != null && lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { - val lastChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - lastCompletedChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } - } + createOngoingStoryListBasedOnLastCompleted( + storyId, + story, + lastCompletedChapterProgress, + completedChapterProgressList, + topic, + ongoingStoryListBuilder + ) } } } @@ -314,6 +282,74 @@ class TopicListController @Inject constructor( return ongoingStoryListBuilder.build() } + private fun createOngoingStoryListBasedOnLastCompleted( + storyId: String, + story: StorySummary, + lastCompletedChapterProgress: ChapterProgress, + completedChapterProgressList: List, + topic: Topic, + ongoingStoryListBuilder: OngoingStoryList.Builder + ) { + val lastChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + lastCompletedChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } + + private fun createOngoingStoryListBasedOnRecentlyPlayed( + storyId: String, + story: StorySummary, + recentlyPlayerChapterProgress: ChapterProgress, + completedChapterProgressList: List, + topic: Topic, + ongoingStoryListBuilder: OngoingStoryList.Builder + ) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = ( + oppiaClock.getCurrentCalendar().timeInMillis - + recentlyPlayerChapterProgress.lastPlayedTimestamp + ) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } + private fun getStartedChapterProgressList(storyProgress: StoryProgress): List { return storyProgress.chapterProgressMap.values .filter { chapterProgress -> @@ -337,7 +373,6 @@ class TopicListController @Inject constructor( ): RecommendedActivityList { val recommendedActivityListBuilder = RecommendedActivityList.newBuilder() - Log.d("topic prog", "size - " + topicProgressList.size) if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() if (topicProgressList.size == 1) { @@ -349,6 +384,7 @@ class TopicListController @Inject constructor( ) ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + if (recommendedStoryBuilder.suggestedStoryCount == 0 && recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0 diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index af0fc40aca2..fc5391dc91b 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -818,7 +818,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markFullProgressForSecondTopic_showRecommendedStories_storyListIsCorrect() { // ktlint-disable max-line-length + fun testProgressTestHelper_markFullProgressForSecondTopic_showRecommendedStories_listIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTopic( profileId, /* timestampOlderThanAWeek= */ false From 7e71d54e94d662fc61c07b6ac07c8d6c1123662d Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 6 Jan 2021 13:31:44 -0800 Subject: [PATCH 128/248] Add hashcode to view models and address review comments --- .../android/app/home/WelcomeViewModel.kt | 16 ++++++------ .../PromotedStoryListViewModel.kt | 16 ++++++------ .../promotedlist/PromotedStoryViewModel.kt | 25 ++++++++++++------- .../home/topiclist/TopicSummaryViewModel.kt | 23 ++++++++++------- .../RecyclerViewBindingAdapter.java | 1 - .../android/app/shim/ViewBindingShimImpl.kt | 2 +- .../domain/topic/StoryProgressTestHelper.kt | 1 - 7 files changed, 47 insertions(+), 37 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index c69c004a8f4..3992e24a4c0 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -4,6 +4,7 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel import org.oppia.android.util.datetime.DateTimeUtil import org.oppia.android.util.system.OppiaClock +import java.util.Objects /** [ViewModel] for welcome text in home screen. */ class WelcomeViewModel( @@ -18,14 +19,13 @@ class WelcomeViewModel( oppiaClock ).getGreetingMessage() + // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel + // only rebinds data when the actual data values in the HomeViewModel data list changes rather than + // the ViewModel object. override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other == null || other.javaClass != javaClass) { - return false - } - val otherResult = other as WelcomeViewModel - return otherResult.profileName == this.profileName + return other is WelcomeViewModel && this.profileName == other.profileName && + this.greeting == other.greeting } + + override fun hashCode() = Objects.hash(this.profileName) + Objects.hash(this.greeting) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 266828a9619..8b362ec4e43 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -8,6 +8,7 @@ import androidx.lifecycle.ViewModel import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener +import java.util.Objects /** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( @@ -49,14 +50,13 @@ class PromotedStoryListViewModel( routeToRecentlyPlayedListener.routeToRecentlyPlayed() } + // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel + // only rebinds data when the actual data values in the HomeViewModel data list changes rather than + // the ViewModel object. override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other == null || other.javaClass != javaClass) { - return false - } - val otherResult = other as PromotedStoryListViewModel - return otherResult.promotedStoryList == this.promotedStoryList + return other is PromotedStoryListViewModel && + other.promotedStoryList == this.promotedStoryList } + + override fun hashCode() = Objects.hash(this.promotedStoryList) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 7e8880961c0..2e9eb8ca0dd 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -9,6 +9,7 @@ import org.oppia.android.R import org.oppia.android.app.home.RouteToTopicPlayStoryListener import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.viewmodel.ObservableViewModel +import java.util.Objects // TODO(#283): Add download status information to promoted-story-card. @@ -43,15 +44,21 @@ class PromotedStoryViewModel( ) } + // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel + // only rebinds data when the actual data values in the HomeViewModel data list changes rather than + // the ViewModel object. override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other == null || other.javaClass != javaClass) { - return false - } - val otherResult = other as PromotedStoryViewModel - return otherResult.internalProfileId == this.internalProfileId && - otherResult.promotedStory == this.promotedStory + return other is PromotedStoryViewModel && + other.internalProfileId == this.internalProfileId && + other.totalStoryCount == this.totalStoryCount && + other.entityType == this.entityType && + other.promotedStory == this.promotedStory + } + + override fun hashCode(): Int { + return Objects.hash(this.internalProfileId) + + Objects.hash(this.totalStoryCount) + + Objects.hash(this.entityType) + + Objects.hash(this.promotedStory) } } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 3367f5bf2a9..093a89cc164 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity import org.oppia.android.R import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.model.TopicSummary +import java.util.Objects // TODO(#206): Remove the color darkening computation and properly set up the topic thumbnails. // These values were roughly computed based on the mocks. They won't produce the same colors since darker colors in the @@ -127,15 +128,19 @@ class TopicSummaryViewModel( return Color.HSVToColor(hsv) } + // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel + // only rebinds data when the actual data values in the HomeViewModel data list changes rather than + // the ViewModel object. override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - if (other == null || other.javaClass != javaClass) { - return false - } - val otherResult = other as TopicSummaryViewModel - return otherResult.topicSummary == this.topicSummary && - otherResult.position == this.position + return other is TopicSummaryViewModel && + other.topicSummary == this.topicSummary && + other.entityType == this.entityType && + other.position == this.position + } + + override fun hashCode(): Int { + return Objects.hash(this.topicSummary) + + Objects.hash(this.entityType) + + Objects.hash(this.position) } } diff --git a/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java b/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java index 9b0620722f4..8d98e5c1bf0 100644 --- a/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java +++ b/app/src/main/java/org/oppia/android/app/recyclerview/RecyclerViewBindingAdapter.java @@ -1,7 +1,6 @@ package org.oppia.android.app.recyclerview; import android.graphics.drawable.Drawable; -import android.util.Log; import androidx.annotation.NonNull; import androidx.databinding.BindingAdapter; 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 8524004ef1c..51ad95b0c93 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 @@ -73,7 +73,7 @@ class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { return PromotedStoryCardBinding.inflate( LayoutInflater.from(parent.context), parent, - /* attachToParent= */ attachToParent + attachToParent ).root } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index c66976f3332..a66cc19dc95 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -194,7 +194,6 @@ class StoryProgressTestHelper @Inject constructor( * * @param profileId The profile we are setting topic progress for. * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. - * */ fun markFullTopicProgressForRatios(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { val timestamp = if (!timestampOlderThanOneWeek) { From cfa1d491cad815eb90c49a9e7fe027ece1bc3365 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 6 Jan 2021 15:51:57 -0800 Subject: [PATCH 129/248] Start tests for view model equals --- .../android/app/home/HomeViewModelsTest.kt | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt new file mode 100644 index 00000000000..fe19854261f --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt @@ -0,0 +1,150 @@ +package org.oppia.android.app.home + +import android.app.Application +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.intent.Intents +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.oppia.android.util.system.OppiaClock +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +// Time: Wed Apr 24 2019 08:22:00 +private const val MORNING_TIMESTAMP = 1556094120000 + +// Time: Tue Apr 23 2019 23:22:00 +private const val EVENING_TIMESTAMP = 1556061720000 + +/** Tests for [HomeViewModel]s data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config(manifest = Config.NONE) +class HomeViewModelsTest { + @Inject + lateinit var fragment: Fragment + @Inject + lateinit var morningClock: OppiaClock + @Inject + lateinit var eveningClock: OppiaClock + private lateinit var welcomeViewModelUser1Morning: WelcomeViewModel + private lateinit var welcomeViewModelUser2Morning: WelcomeViewModel + private lateinit var welcomeViewModelUser2Evening: WelcomeViewModel + + @Before + fun setUp() { + Intents.init() + ApplicationProvider.getApplicationContext().inject(this) + morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) + eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) + setUpWelcomeViewModels() + } + + private fun setUpWelcomeViewModels() { + welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") + welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") + } + + @Test + fun testWelcomeViewModel_differentProfileName_isNotEqual() { + val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) + assertThat(isEqual).isFalse() + } + + @After + fun tearDown() { + Intents.release() + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(homeViewModelsTest: HomeViewModelsTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerHomeViewModelsTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(homeViewModelsTest: HomeViewModelsTest) { + component.inject(homeViewModelsTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} From def4ae370574667d2a8ba3103e5e7097ea48a8ea Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 7 Jan 2021 15:10:00 -0800 Subject: [PATCH 130/248] Add view model tests --- .../android/app/home/HomeViewModelTest.kt | 150 ++++++++++++++++++ 1 file changed, 150 insertions(+) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt new file mode 100644 index 00000000000..e2acccc35ce --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt @@ -0,0 +1,150 @@ +package org.oppia.android.app.home + +import android.app.Application +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment +import androidx.test.core.app.ApplicationProvider +import androidx.test.espresso.intent.Intents +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.After +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.oppia.android.util.system.OppiaClock +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +// Time: Wed Apr 24 2019 08:22:00 +private const val MORNING_TIMESTAMP = 1556094120000 + +// Time: Tue Apr 23 2019 23:22:00 +private const val EVENING_TIMESTAMP = 1556061720000 + +/** Tests for [HomeViewModel]s data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config(manifest = Config.NONE) +class HomeViewModelTest { + @Inject + lateinit var fragment: Fragment + @Inject + lateinit var morningClock: OppiaClock + @Inject + lateinit var eveningClock: OppiaClock + private lateinit var welcomeViewModelUser1Morning: WelcomeViewModel + private lateinit var welcomeViewModelUser2Morning: WelcomeViewModel + private lateinit var welcomeViewModelUser2Evening: WelcomeViewModel + + @Before + fun setUp() { + Intents.init() + ApplicationProvider.getApplicationContext().inject(this) + morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) + eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) + setUpWelcomeViewModels() + } + + private fun setUpWelcomeViewModels() { + welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") + welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") + } + + @Test + fun testWelcomeViewModel_differentProfileName_isNotEqual() { + val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) + assertThat(isEqual).isFalse() + } + + @After + fun tearDown() { + Intents.release() + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(homeViewModelsTest: HomeViewModelsTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerHomeViewModelsTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(homeViewModelsTest: HomeViewModelsTest) { + component.inject(homeViewModelsTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} From 86224fa90171e505efc6cbca5769aee33666e785 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 7 Jan 2021 17:25:24 -0800 Subject: [PATCH 131/248] Use test activity to get fragment --- .../android/app/activity/ActivityComponent.kt | 2 + .../app/testing/HomeFragmentTestActivity.kt | 27 ++++ ...lTest.kt => HomeFragmentViewModelsTest.kt} | 63 ++++++-- .../android/app/home/HomeViewModelsTest.kt | 150 ------------------ 4 files changed, 75 insertions(+), 167 deletions(-) create mode 100644 app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt rename app/src/sharedTest/java/org/oppia/android/app/home/{HomeViewModelTest.kt => HomeFragmentViewModelsTest.kt} (76%) delete mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt diff --git a/app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt b/app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt index 431370c5980..0677b01727f 100644 --- a/app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt +++ b/app/src/main/java/org/oppia/android/app/activity/ActivityComponent.kt @@ -40,6 +40,7 @@ import org.oppia.android.app.testing.ConceptCardFragmentTestActivity import org.oppia.android.app.testing.DragDropTestActivity import org.oppia.android.app.testing.ExplorationInjectionActivity import org.oppia.android.app.testing.ExplorationTestActivity +import org.oppia.android.app.testing.HomeFragmentTestActivity import org.oppia.android.app.testing.HomeInjectionActivity import org.oppia.android.app.testing.HomeTestActivity import org.oppia.android.app.testing.HtmlParserTestActivity @@ -90,6 +91,7 @@ interface ActivityComponent { fun inject(testFontScaleConfigurationUtilActivity: TestFontScaleConfigurationUtilActivity) fun inject(helpActivity: HelpActivity) fun inject(homeActivity: HomeActivity) + fun inject(homeFragmentTestActivity: HomeFragmentTestActivity) fun inject(homeInjectionActivity: HomeInjectionActivity) fun inject(homeTestActivity: HomeTestActivity) fun inject(htmlParserTestActivity: HtmlParserTestActivity) diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt new file mode 100644 index 00000000000..46a2a4b0ef3 --- /dev/null +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -0,0 +1,27 @@ +package org.oppia.android.app.testing + +import android.os.Bundle +import org.oppia.android.app.activity.InjectableAppCompatActivity +import org.oppia.android.app.home.HomeFragment + +/** Test Activity for testing view models on the HomeFragment */ +class HomeFragmentTestActivity : InjectableAppCompatActivity() { + + private val homeFragment = HomeFragment() + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + activityComponent.inject(this) + supportFragmentManager.beginTransaction().add( + HomeFragment(), + "home_fragment_test_activity" + ).commitNow() + } + +// companion object { +// fun createHomeFragmentTestActivity(context: Context): Intent { +// val intent = Intent(context, HomeFragmentTestActivity::class.java) +// return intent +// } +// } +} diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt similarity index 76% rename from app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt rename to app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index e2acccc35ce..c97df67ff1d 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -1,10 +1,10 @@ package org.oppia.android.app.home import android.app.Application +import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment +import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider -import androidx.test.espresso.intent.Intents import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat import dagger.Component @@ -22,6 +22,7 @@ import org.oppia.android.app.application.ApplicationStartupListenerModule import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.shim.IntentFactoryShimModule import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.app.testing.HomeFragmentTestActivity import org.oppia.android.domain.classify.InteractionsModule import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule @@ -41,6 +42,7 @@ import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule import org.oppia.android.testing.RobolectricModule import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule import org.oppia.android.testing.TestLogReportingModule import org.oppia.android.util.caching.testing.CachingTestModule @@ -65,42 +67,69 @@ private const val EVENING_TIMESTAMP = 1556061720000 /** Tests for [HomeViewModel]s data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) -@Config(manifest = Config.NONE) -class HomeViewModelTest { +@Config( + application = HomeFragmentViewModelsTest.TestApplication::class, + manifest = Config.NONE +) +class HomeFragmentViewModelsTest { @Inject - lateinit var fragment: Fragment + lateinit var context: Context + + @Inject + lateinit var testCoroutineDispatchers: TestCoroutineDispatchers + @Inject lateinit var morningClock: OppiaClock + @Inject lateinit var eveningClock: OppiaClock + + // private val fragment = Fragment() private lateinit var welcomeViewModelUser1Morning: WelcomeViewModel private lateinit var welcomeViewModelUser2Morning: WelcomeViewModel private lateinit var welcomeViewModelUser2Evening: WelcomeViewModel @Before fun setUp() { - Intents.init() ApplicationProvider.getApplicationContext().inject(this) + setUpClocks() +// setUpWelcomeViewModels() + testCoroutineDispatchers.registerIdlingResource() + } + + private fun setUpClocks() { morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) - setUpWelcomeViewModels() } private fun setUpWelcomeViewModels() { - welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") - welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") +// welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") +// welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") +// welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") + } + + private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { + return activity.supportFragmentManager.findFragmentByTag( + "home_fragment_test_activity" + ) as HomeFragment } @Test fun testWelcomeViewModel_differentProfileName_isNotEqual() { - val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) - assertThat(isEqual).isFalse() + launch(HomeFragmentTestActivity::class.java).use { + it.onActivity { + val fragment = getTestFragment(it) + welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") + val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) + assertThat(isEqual).isFalse() + } + } } @After fun tearDown() { - Intents.release() + testCoroutineDispatchers.unregisterIdlingResource() } // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. @@ -127,18 +156,18 @@ class HomeViewModelTest { @Component.Builder interface Builder : ApplicationComponent.Builder - fun inject(homeViewModelsTest: HomeViewModelsTest) + fun inject(homeFragmentViewModelsTest: HomeFragmentViewModelsTest) } class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { private val component: TestApplicationComponent by lazy { - DaggerHomeViewModelsTest_TestApplicationComponent.builder() + DaggerHomeFragmentViewModelsTest_TestApplicationComponent.builder() .setApplication(this) .build() as TestApplicationComponent } - fun inject(homeViewModelsTest: HomeViewModelsTest) { - component.inject(homeViewModelsTest) + fun inject(homeViewModelTest: HomeFragmentViewModelsTest) { + component.inject(homeViewModelTest) } override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt deleted file mode 100644 index fe19854261f..00000000000 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeViewModelsTest.kt +++ /dev/null @@ -1,150 +0,0 @@ -package org.oppia.android.app.home - -import android.app.Application -import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment -import androidx.test.core.app.ApplicationProvider -import androidx.test.espresso.intent.Intents -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.common.truth.Truth.assertThat -import dagger.Component -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.oppia.android.app.activity.ActivityComponent -import org.oppia.android.app.application.ActivityComponentFactory -import org.oppia.android.app.application.ApplicationComponent -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.player.state.hintsandsolution.HintsAndSolutionConfigModule -import org.oppia.android.app.shim.IntentFactoryShimModule -import org.oppia.android.app.shim.ViewBindingShimModule -import org.oppia.android.domain.classify.InteractionsModule -import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule -import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule -import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule -import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule -import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule -import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule -import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule -import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule -import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule -import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule -import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule -import org.oppia.android.domain.oppialogger.LogStorageModule -import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule -import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule -import org.oppia.android.domain.question.QuestionModule -import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule -import org.oppia.android.testing.RobolectricModule -import org.oppia.android.testing.TestAccessibilityModule -import org.oppia.android.testing.TestDispatcherModule -import org.oppia.android.testing.TestLogReportingModule -import org.oppia.android.util.caching.testing.CachingTestModule -import org.oppia.android.util.gcsresource.GcsResourceModule -import org.oppia.android.util.logging.LoggerModule -import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule -import org.oppia.android.util.parser.GlideImageLoaderModule -import org.oppia.android.util.parser.HtmlParserEntityTypeModule -import org.oppia.android.util.parser.ImageParsingModule -import org.oppia.android.util.system.OppiaClock -import org.robolectric.annotation.Config -import org.robolectric.annotation.LooperMode -import javax.inject.Inject -import javax.inject.Singleton - -// Time: Wed Apr 24 2019 08:22:00 -private const val MORNING_TIMESTAMP = 1556094120000 - -// Time: Tue Apr 23 2019 23:22:00 -private const val EVENING_TIMESTAMP = 1556061720000 - -/** Tests for [HomeViewModel]s data. */ -@RunWith(AndroidJUnit4::class) -@LooperMode(LooperMode.Mode.PAUSED) -@Config(manifest = Config.NONE) -class HomeViewModelsTest { - @Inject - lateinit var fragment: Fragment - @Inject - lateinit var morningClock: OppiaClock - @Inject - lateinit var eveningClock: OppiaClock - private lateinit var welcomeViewModelUser1Morning: WelcomeViewModel - private lateinit var welcomeViewModelUser2Morning: WelcomeViewModel - private lateinit var welcomeViewModelUser2Evening: WelcomeViewModel - - @Before - fun setUp() { - Intents.init() - ApplicationProvider.getApplicationContext().inject(this) - morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) - eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) - setUpWelcomeViewModels() - } - - private fun setUpWelcomeViewModels() { - welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") - welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") - } - - @Test - fun testWelcomeViewModel_differentProfileName_isNotEqual() { - val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) - assertThat(isEqual).isFalse() - } - - @After - fun tearDown() { - Intents.release() - } - - // 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 - @Component( - modules = [ - TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, - LoggerModule::class, ContinueModule::class, FractionInputModule::class, - ItemSelectionInputModule::class, MultipleChoiceInputModule::class, - NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, - DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, - GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, - QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, - ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, - ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, - PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, - ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, - WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, - FirebaseLogUploaderModule::class - ] - ) - interface TestApplicationComponent : ApplicationComponent { - @Component.Builder - interface Builder : ApplicationComponent.Builder - - fun inject(homeViewModelsTest: HomeViewModelsTest) - } - - class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { - private val component: TestApplicationComponent by lazy { - DaggerHomeViewModelsTest_TestApplicationComponent.builder() - .setApplication(this) - .build() as TestApplicationComponent - } - - fun inject(homeViewModelsTest: HomeViewModelsTest) { - component.inject(homeViewModelsTest) - } - - override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { - return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() - } - - override fun getApplicationInjector(): ApplicationInjector = component - } -} From 4faf7e7d8fbde2b74de245ed2c0f3523e0e81e69 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 7 Jan 2021 17:35:18 -0800 Subject: [PATCH 132/248] Create intent in test activity --- .../app/testing/HomeFragmentTestActivity.kt | 16 +++++++++------- .../app/home/HomeFragmentViewModelsTest.kt | 5 ++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 46a2a4b0ef3..2396af621b5 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -1,5 +1,7 @@ package org.oppia.android.app.testing +import android.content.Context +import android.content.Intent import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity import org.oppia.android.app.home.HomeFragment @@ -13,15 +15,15 @@ class HomeFragmentTestActivity : InjectableAppCompatActivity() { super.onCreate(savedInstanceState) activityComponent.inject(this) supportFragmentManager.beginTransaction().add( - HomeFragment(), + homeFragment, "home_fragment_test_activity" ).commitNow() } -// companion object { -// fun createHomeFragmentTestActivity(context: Context): Intent { -// val intent = Intent(context, HomeFragmentTestActivity::class.java) -// return intent -// } -// } + companion object { + fun createHomeFragmentTestActivity(context: Context): Intent { + val intent = Intent(context, HomeFragmentTestActivity::class.java) + return intent + } + } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index c97df67ff1d..5a0ca562a04 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -23,6 +23,7 @@ import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfi import org.oppia.android.app.shim.IntentFactoryShimModule import org.oppia.android.app.shim.ViewBindingShimModule import org.oppia.android.app.testing.HomeFragmentTestActivity +import org.oppia.android.app.testing.HomeFragmentTestActivity.Companion.createHomeFragmentTestActivity import org.oppia.android.domain.classify.InteractionsModule import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule @@ -116,7 +117,9 @@ class HomeFragmentViewModelsTest { @Test fun testWelcomeViewModel_differentProfileName_isNotEqual() { - launch(HomeFragmentTestActivity::class.java).use { + launch( + createHomeFragmentTestActivity(context) + ).use { it.onActivity { val fragment = getTestFragment(it) welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") From 92b23890b0acadf99736124fdadfe19e2c77ec5e Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 7 Jan 2021 18:33:40 -0800 Subject: [PATCH 133/248] Add test for WelcomeViewModel --- app/src/main/AndroidManifest.xml | 1 + .../android/app/home/WelcomeViewModel.kt | 3 +- .../app/testing/HomeFragmentTestActivity.kt | 14 +++-- .../app/home/HomeFragmentViewModelsTest.kt | 55 ++++++++++++------- 4 files changed, 47 insertions(+), 26 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6ff7126bb03..2d1b96368c1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -126,6 +126,7 @@ + diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 3992e24a4c0..ca68dccaf23 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -23,7 +23,8 @@ class WelcomeViewModel( // only rebinds data when the actual data values in the HomeViewModel data list changes rather than // the ViewModel object. override fun equals(other: Any?): Boolean { - return other is WelcomeViewModel && this.profileName == other.profileName && + return other is WelcomeViewModel && + this.profileName == other.profileName && this.greeting == other.greeting } diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 2396af621b5..91378869146 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -5,17 +5,19 @@ import android.content.Intent import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity import org.oppia.android.app.home.HomeFragment +import org.oppia.android.app.home.RouteToTopicListener -/** Test Activity for testing view models on the HomeFragment */ -class HomeFragmentTestActivity : InjectableAppCompatActivity() { - - private val homeFragment = HomeFragment() +/** + * Test Activity for testing view models on the [HomeFragment] + * Must implement [RouteToTopicListener] so the test can access a [HomeFragmnet] + */ +class HomeFragmentTestActivity : RouteToTopicListener, InjectableAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activityComponent.inject(this) supportFragmentManager.beginTransaction().add( - homeFragment, + HomeFragment(), "home_fragment_test_activity" ).commitNow() } @@ -26,4 +28,6 @@ class HomeFragmentTestActivity : InjectableAppCompatActivity() { return intent } } + + override fun routeToTopic(internalProfileId: Int, topicId: String) {} } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 5a0ca562a04..13f144925f0 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -79,22 +79,13 @@ class HomeFragmentViewModelsTest { @Inject lateinit var testCoroutineDispatchers: TestCoroutineDispatchers - @Inject - lateinit var morningClock: OppiaClock - - @Inject - lateinit var eveningClock: OppiaClock - - // private val fragment = Fragment() - private lateinit var welcomeViewModelUser1Morning: WelcomeViewModel - private lateinit var welcomeViewModelUser2Morning: WelcomeViewModel - private lateinit var welcomeViewModelUser2Evening: WelcomeViewModel + private var morningClock = OppiaClock() + private var eveningClock = OppiaClock() @Before fun setUp() { ApplicationProvider.getApplicationContext().inject(this) setUpClocks() -// setUpWelcomeViewModels() testCoroutineDispatchers.registerIdlingResource() } @@ -103,12 +94,6 @@ class HomeFragmentViewModelsTest { eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) } - private fun setUpWelcomeViewModels() { -// welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") -// welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") -// welcomeViewModelUser2Evening = WelcomeViewModel(fragment, eveningClock, "User 2") - } - private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { return activity.supportFragmentManager.findFragmentByTag( "home_fragment_test_activity" @@ -116,20 +101,50 @@ class HomeFragmentViewModelsTest { } @Test - fun testWelcomeViewModel_differentProfileName_isNotEqual() { + fun testWelcomeViewModel_sameProfileNameSameTime_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { val fragment = getTestFragment(it) - welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") + val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + val copyWelcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + val isEqual = welcomeViewModelUser1Morning.equals(copyWelcomeViewModelUser1Morning) + assertThat(isEqual).isTrue() + } + } + } + + @Test + fun testWelcomeViewModel_differentProfileNameSameTime_isNotEqual() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + val welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) assertThat(isEqual).isFalse() } } } + @Test + fun testWelcomeViewModel_sameNameDifferentTimes_isNotEqual() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") + val welcomeViewModelUser1Evening = WelcomeViewModel(fragment, eveningClock, "User 1") + val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser1Evening) + assertThat(isEqual).isFalse() + } + } + } + @After fun tearDown() { testCoroutineDispatchers.unregisterIdlingResource() From d1bcc2d6aa4648e1bb3230f28ee9645efa72fbe7 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 7 Jan 2021 18:51:35 -0800 Subject: [PATCH 134/248] Clarify test names and start PromotedStoryListViewModel --- .../app/home/HomeFragmentViewModelsTest.kt | 36 ++++++++++++++----- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 13f144925f0..83664a48fbb 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -101,7 +101,7 @@ class HomeFragmentViewModelsTest { } @Test - fun testWelcomeViewModel_sameProfileNameSameTime_isEqual() { + fun testWelcomeViewModelEquals_sameProfileNameSameTime_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { @@ -109,14 +109,14 @@ class HomeFragmentViewModelsTest { val fragment = getTestFragment(it) val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") val copyWelcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - val isEqual = welcomeViewModelUser1Morning.equals(copyWelcomeViewModelUser1Morning) - assertThat(isEqual).isTrue() + val equal = welcomeViewModelUser1Morning.equals(copyWelcomeViewModelUser1Morning) + assertThat(equal).isTrue() } } } @Test - fun testWelcomeViewModel_differentProfileNameSameTime_isNotEqual() { + fun testWelcomeViewModelEquals_differentProfileNameSameTime_isFalse() { launch( createHomeFragmentTestActivity(context) ).use { @@ -124,14 +124,14 @@ class HomeFragmentViewModelsTest { val fragment = getTestFragment(it) val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") val welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") - val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) - assertThat(isEqual).isFalse() + val equal = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) + assertThat(equal).isFalse() } } } @Test - fun testWelcomeViewModel_sameNameDifferentTimes_isNotEqual() { + fun testWelcomeViewModelEquals_sameNameDifferentTimes_isFalse() { launch( createHomeFragmentTestActivity(context) ).use { @@ -139,12 +139,30 @@ class HomeFragmentViewModelsTest { val fragment = getTestFragment(it) val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") val welcomeViewModelUser1Evening = WelcomeViewModel(fragment, eveningClock, "User 1") - val isEqual = welcomeViewModelUser1Morning.equals(welcomeViewModelUser1Evening) - assertThat(isEqual).isFalse() + val equal = welcomeViewModelUser1Morning.equals(welcomeViewModelUser1Evening) + assertThat(equal).isFalse() } } } +// @Test +// fun testPromotedStoryViewModelEquals_sameProfileSameStoryCountSameEntitySameStory_isTrue() { +// launch( +// createHomeFragmentTestActivity(context) +// ).use { +// it.onActivity { +// val promotedStoryViewModel = PromotedStoryViewModel( +// it, 1, 3, "", PromotedStory() +// ) +// val copyPromotedStoryViewModel = PromotedStoryViewModel( +// it, 1, 3, "", PromotedStory() +// ) +// val equal = promotedStoryViewModel.equals(copyPromotedStoryViewModel) +// assertThat(equal).isFalse() +// } +// } +// } + @After fun tearDown() { testCoroutineDispatchers.unregisterIdlingResource() From f15d1055a0118314242aac2c5da6e30dca6cc17f Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 8 Jan 2021 11:57:25 +0530 Subject: [PATCH 135/248] Update test_exp_id_4.json --- domain/src/main/assets/test_exp_id_4.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/domain/src/main/assets/test_exp_id_4.json b/domain/src/main/assets/test_exp_id_4.json index 3f719c88d80..a56e2482d6e 100644 --- a/domain/src/main/assets/test_exp_id_4.json +++ b/domain/src/main/assets/test_exp_id_4.json @@ -56,9 +56,6 @@ ], [ "

a camera at the store

" - ], - [ - "

to photograph the parade.

" ] ] } From f11e530d6c950fc26c85c605f1baee4c5737abe9 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 08:47:01 -0800 Subject: [PATCH 136/248] Add tests for equals definition and hashcode of WelcomeViewModel and PromotedStoryViewModel --- .../app/testing/HomeFragmentTestActivity.kt | 12 +- .../app/home/HomeFragmentViewModelsTest.kt | 553 +++++++++++++++++- 2 files changed, 531 insertions(+), 34 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 91378869146..417ce9325d3 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -6,12 +6,16 @@ import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity import org.oppia.android.app.home.HomeFragment import org.oppia.android.app.home.RouteToTopicListener +import org.oppia.android.app.home.RouteToTopicPlayStoryListener /** - * Test Activity for testing view models on the [HomeFragment] - * Must implement [RouteToTopicListener] so the test can access a [HomeFragmnet] + * Test Activity for testing view models on the [HomeFragment]. + * This activity must implement listeners so the test can use it as a [HomeFragmnet]. */ -class HomeFragmentTestActivity : RouteToTopicListener, InjectableAppCompatActivity() { +class HomeFragmentTestActivity : + RouteToTopicListener, + RouteToTopicPlayStoryListener, + InjectableAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -29,5 +33,7 @@ class HomeFragmentTestActivity : RouteToTopicListener, InjectableAppCompatActivi } } + // Override functions are needed to fulfill listener definitions. override fun routeToTopic(internalProfileId: Int, topicId: String) {} + override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) {} } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 83664a48fbb..e68a5e4b981 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -19,6 +19,8 @@ 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.home.promotedlist.PromotedStoryViewModel +import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.shim.IntentFactoryShimModule import org.oppia.android.app.shim.ViewBindingShimModule @@ -101,67 +103,556 @@ class HomeFragmentViewModelsTest { } @Test - fun testWelcomeViewModelEquals_sameProfileNameSameTime_isTrue() { + fun testWelcomeViewModelEquals_reflexiveProfile1MorningAndProfile1Morning_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { val fragment = getTestFragment(it) - val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - val copyWelcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - val equal = welcomeViewModelUser1Morning.equals(copyWelcomeViewModelUser1Morning) - assertThat(equal).isTrue() + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning)).isTrue() } } } @Test - fun testWelcomeViewModelEquals_differentProfileNameSameTime_isFalse() { + fun testWelcomeViewModelEquals_symmetricProfile1MorningAndDifferentProfile1Morning_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { val fragment = getTestFragment(it) - val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - val welcomeViewModelUser2Morning = WelcomeViewModel(fragment, morningClock, "User 2") - val equal = welcomeViewModelUser1Morning.equals(welcomeViewModelUser2Morning) - assertThat(equal).isFalse() + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isSymmetric = + welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning) && + copyWelcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_transitiveProfile1MorningAndTwoDifferentProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy2WelcomeVieModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isTransitive = + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && + copy1WelcomeViewModelProfile1Morning.equals(copy2WelcomeVieModelProfile1Morning) && + copy2WelcomeVieModelProfile1Morning.equals(welcomeViewModelProfile1Morning) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_consistentProfile1MorningAndDifferentProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isConsistent = + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_profile1MorningAndNull_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(null)).isFalse() + } + } + } + + @Test + fun testWelcomeViewModelEquals_profile1MorningAndProfile2Morning_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val welcomeViewModelProfile2Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 2" + ) + assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile2Morning)) + .isFalse() } } } @Test - fun testWelcomeViewModelEquals_sameNameDifferentTimes_isFalse() { + fun testWelcomeViewModelEquals_profile1MorningAndProfile1Evening_isFalse() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { val fragment = getTestFragment(it) - val welcomeViewModelUser1Morning = WelcomeViewModel(fragment, morningClock, "User 1") - val welcomeViewModelUser1Evening = WelcomeViewModel(fragment, eveningClock, "User 1") - val equal = welcomeViewModelUser1Morning.equals(welcomeViewModelUser1Evening) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val welcomeViewModelProfile1Evening = WelcomeViewModel( + fragment, + eveningClock, + "Profile 1" + ) + val equal = welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Evening) assertThat(equal).isFalse() } } } -// @Test -// fun testPromotedStoryViewModelEquals_sameProfileSameStoryCountSameEntitySameStory_isTrue() { -// launch( -// createHomeFragmentTestActivity(context) -// ).use { -// it.onActivity { -// val promotedStoryViewModel = PromotedStoryViewModel( -// it, 1, 3, "", PromotedStory() -// ) -// val copyPromotedStoryViewModel = PromotedStoryViewModel( -// it, 1, 3, "", PromotedStory() -// ) -// val equal = promotedStoryViewModel.equals(copyPromotedStoryViewModel) -// assertThat(equal).isFalse() -// } -// } -// } + @Test + fun testWelcomeViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning)) + .isTrue() + + assertThat( + welcomeViewModelProfile1Morning.hashCode() == + copyWelcomeViewModelProfile1Morning.hashCode() + ).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_reflexiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + val isReflexive = promotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isReflexive).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_symmetricProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + val isSymmetric = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && + copyPromotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_transitiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val copy1PromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val copy2PromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + val isTransitive = promotedStoryViewModel.equals(copy1PromotedStoryViewModel) && + copy1PromotedStoryViewModel.equals(copy2PromotedStoryViewModel) && + copy2PromotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_consistentProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + val isConsistent = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && + promotedStoryViewModel.equals(copyPromotedStoryViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_profile1StoryCount3EntityTypeEmptyStory1AndNull_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + assertThat(promotedStoryViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelProfile1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val promotedStoryViewModelProfile2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */2, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + assertThat(promotedStoryViewModelProfile1.equals(promotedStoryViewModelProfile2)).isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelStoryCount2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */2, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + assertThat(promotedStoryViewModelStoryCount2.equals(promotedStoryViewModelStoryCount3)) + .isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_entity1AndEntity2_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelEntity1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 1", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val promotedStoryViewModelEntity2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 2", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + assertThat(promotedStoryViewModelEntity1.equals(promotedStoryViewModelEntity2)).isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_story1AndStory2_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val story1 = PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + val story2 = PromotedStory.newBuilder() + .setStoryId("id_2") + .setStoryName("Story 2") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + assertThat(story1.equals(story2)).isFalse() + + val promotedStoryViewModelStory1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 1", + story1 + ) + val promotedStoryViewModelStory2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 2", + story2 + ) + + assertThat(promotedStoryViewModelStory1.equals(promotedStoryViewModelStory2)).isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() + + assertThat(promotedStoryViewModel.hashCode() == copyPromotedStoryViewModel.hashCode()) + .isTrue() + } + } + } @After fun tearDown() { From 23c816b0fdc9eb82c1d3c0b5ae8e17e1b2be9727 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 09:09:36 -0800 Subject: [PATCH 137/248] Add tests for PromotedStoryListViewModel --- .../app/testing/HomeFragmentTestActivity.kt | 3 + .../app/home/HomeFragmentViewModelsTest.kt | 468 +++++++++++++----- 2 files changed, 360 insertions(+), 111 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 417ce9325d3..9b2bf245b6a 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -5,6 +5,7 @@ import android.content.Intent import android.os.Bundle import org.oppia.android.app.activity.InjectableAppCompatActivity import org.oppia.android.app.home.HomeFragment +import org.oppia.android.app.home.RouteToRecentlyPlayedListener import org.oppia.android.app.home.RouteToTopicListener import org.oppia.android.app.home.RouteToTopicPlayStoryListener @@ -15,6 +16,7 @@ import org.oppia.android.app.home.RouteToTopicPlayStoryListener class HomeFragmentTestActivity : RouteToTopicListener, RouteToTopicPlayStoryListener, + RouteToRecentlyPlayedListener, InjectableAppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { @@ -36,4 +38,5 @@ class HomeFragmentTestActivity : // Override functions are needed to fulfill listener definitions. override fun routeToTopic(internalProfileId: Int, topicId: String) {} override fun routeToTopicPlayStory(internalProfileId: Int, topicId: String, storyId: String) {} + override fun routeToRecentlyPlayed() {} } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index e68a5e4b981..2562b4196de 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -19,6 +19,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.home.promotedlist.PromotedStoryListViewModel import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule @@ -83,6 +84,33 @@ class HomeFragmentViewModelsTest { private var morningClock = OppiaClock() private var eveningClock = OppiaClock() + private val promotedStory1 = PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory2 = PromotedStory.newBuilder() + .setStoryId("id_2") + .setStoryName("Story 2") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory3 = PromotedStory.newBuilder() + .setStoryId("id_3") + .setStoryName("Story 3") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() +// private val promotedStoryList2Stories = listOf( +// promotedStoryId1Story1, +// promotedStoryId2Story2 +// ) +// private val promotedStoryList3Stories = listOf( +// promotedStoryId1Story1, +// promotedStoryId2Story2, +// promotedStoryId3Story3 +// ) @Before fun setUp() { @@ -302,12 +330,7 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val isReflexive = promotedStoryViewModel.equals(promotedStoryViewModel) @@ -327,12 +350,7 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val copyPromotedStoryViewModel = PromotedStoryViewModel( /* activity = */ it, @@ -365,36 +383,21 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val copy1PromotedStoryViewModel = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val copy2PromotedStoryViewModel = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val isTransitive = promotedStoryViewModel.equals(copy1PromotedStoryViewModel) && @@ -416,24 +419,14 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val copyPromotedStoryViewModel = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val isConsistent = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && @@ -454,12 +447,7 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) assertThat(promotedStoryViewModel.equals(null)).isFalse() @@ -478,24 +466,14 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val promotedStoryViewModelProfile2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */2, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) assertThat(promotedStoryViewModelProfile1.equals(promotedStoryViewModelProfile2)).isFalse() @@ -514,24 +492,14 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */2, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) assertThat(promotedStoryViewModelStoryCount2.equals(promotedStoryViewModelStoryCount3)) @@ -551,24 +519,14 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"Entity 1", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val promotedStoryViewModelEntity2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"Entity 2", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) assertThat(promotedStoryViewModelEntity1.equals(promotedStoryViewModelEntity2)).isFalse() @@ -582,33 +540,21 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val story1 = PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - val story2 = PromotedStory.newBuilder() - .setStoryId("id_2") - .setStoryName("Story 2") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - assertThat(story1.equals(story2)).isFalse() + assertThat(promotedStory1.equals(promotedStory2)).isFalse() val promotedStoryViewModelStory1 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"Entity 1", - story1 + promotedStory1 ) val promotedStoryViewModelStory2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"Entity 2", - story2 + promotedStory2 ) assertThat(promotedStoryViewModelStory1.equals(promotedStoryViewModelStory2)).isFalse() @@ -627,24 +573,14 @@ class HomeFragmentViewModelsTest { /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) val copyPromotedStoryViewModel = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() + promotedStory1 ) assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() @@ -654,6 +590,316 @@ class HomeFragmentViewModelsTest { } } + @Test + fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + + val isReflexive = promotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isReflexive).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + + val isSymmetric = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && + copyPromotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val copy1PromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val copy2PromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + + val isTransitive = promotedStoryListViewModel.equals(copy1PromotedStoryListViewModel) && + copy1PromotedStoryListViewModel.equals(copy2PromotedStoryListViewModel) && + copy2PromotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + + val isConsistent = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && + promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + + assertThat(promotedStoryListViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModelOf2 = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val promotedStoryListViewModelOf3 = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory3 + ) + )) + + assertThat(promotedStoryListViewModelOf2.equals(promotedStoryListViewModelOf3)).isFalse() + } + } + } + + @Test + fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + )) + assertThat(promotedStoryListViewModel.equals(copyPromotedStoryListViewModel)).isTrue() + + assertThat( + promotedStoryListViewModel.hashCode() == copyPromotedStoryListViewModel.hashCode() + ).isTrue() + } + } + } + @After fun tearDown() { testCoroutineDispatchers.unregisterIdlingResource() From 93e64770687cfa8249736b470c17713a489f2966 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 8 Jan 2021 22:58:50 +0530 Subject: [PATCH 138/248] Update TopicListController.kt --- .../java/org/oppia/android/domain/topic/TopicListController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index d54eb2c5526..b9d46d23311 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -418,7 +418,7 @@ class TopicListController @Inject constructor( ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - // If user has completed all the topcs then add upcoming topics in + // If user has completed all the topics then add upcoming topics in // RecommendedActivityList. if (recommendedStoryBuilder.suggestedStoryCount == 0) { recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() From e9e0d5252dc37cdeb784e88c872c98ae538343c2 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 09:32:43 -0800 Subject: [PATCH 139/248] Add tests for TopicSummaryViewModel --- .../app/home/HomeFragmentViewModelsTest.kt | 735 ++++++++++++------ 1 file changed, 508 insertions(+), 227 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 2562b4196de..84b1bfc8ad9 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -21,7 +21,9 @@ import org.oppia.android.app.application.ApplicationModule import org.oppia.android.app.application.ApplicationStartupListenerModule import org.oppia.android.app.home.promotedlist.PromotedStoryListViewModel import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel +import org.oppia.android.app.home.topiclist.TopicSummaryViewModel import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.model.TopicSummary import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.shim.IntentFactoryShimModule import org.oppia.android.app.shim.ViewBindingShimModule @@ -46,7 +48,6 @@ import org.oppia.android.domain.question.QuestionModule import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule import org.oppia.android.testing.RobolectricModule import org.oppia.android.testing.TestAccessibilityModule -import org.oppia.android.testing.TestCoroutineDispatchers import org.oppia.android.testing.TestDispatcherModule import org.oppia.android.testing.TestLogReportingModule import org.oppia.android.util.caching.testing.CachingTestModule @@ -79,9 +80,6 @@ class HomeFragmentViewModelsTest { @Inject lateinit var context: Context - @Inject - lateinit var testCoroutineDispatchers: TestCoroutineDispatchers - private var morningClock = OppiaClock() private var eveningClock = OppiaClock() private val promotedStory1 = PromotedStory.newBuilder() @@ -102,21 +100,25 @@ class HomeFragmentViewModelsTest { .setTopicName("topic_name") .setTotalChapterCount(1) .build() -// private val promotedStoryList2Stories = listOf( -// promotedStoryId1Story1, -// promotedStoryId2Story2 -// ) -// private val promotedStoryList3Stories = listOf( -// promotedStoryId1Story1, -// promotedStoryId2Story2, -// promotedStoryId3Story3 -// ) + private val topicSummary1 = TopicSummary.newBuilder() + .setTopicId("id_1") + .setName("topic_name") + .setTotalChapterCount(2) + .build() + private val topicSummary2 = TopicSummary.newBuilder() + .setTopicId("id_2") + .setName("topic_name") + .setTotalChapterCount(2) + .build() @Before fun setUp() { - ApplicationProvider.getApplicationContext().inject(this) + setUpTestApplicationComponent() setUpClocks() - testCoroutineDispatchers.registerIdlingResource() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) } private fun setUpClocks() { @@ -311,10 +313,8 @@ class HomeFragmentViewModelsTest { assertThat(welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning)) .isTrue() - assertThat( - welcomeViewModelProfile1Morning.hashCode() == - copyWelcomeViewModelProfile1Morning.hashCode() - ).isTrue() + assertThat(welcomeViewModelProfile1Morning.hashCode()) + .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) } } } @@ -584,8 +584,8 @@ class HomeFragmentViewModelsTest { ) assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() - assertThat(promotedStoryViewModel.hashCode() == copyPromotedStoryViewModel.hashCode()) - .isTrue() + assertThat(promotedStoryViewModel.hashCode()) + .isEqualTo(copyPromotedStoryViewModel.hashCode()) } } } @@ -596,22 +596,25 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) val isReflexive = promotedStoryListViewModel.equals(promotedStoryListViewModel) assertThat(isReflexive).isTrue() @@ -625,38 +628,44 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) val isSymmetric = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && copyPromotedStoryListViewModel.equals(promotedStoryListViewModel) @@ -671,54 +680,63 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val copy1PromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + ) + val copy1PromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val copy2PromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + ) + val copy2PromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) val isTransitive = promotedStoryListViewModel.equals(copy1PromotedStoryListViewModel) && copy1PromotedStoryListViewModel.equals(copy2PromotedStoryListViewModel) && @@ -734,38 +752,44 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) val isConsistent = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) @@ -780,22 +804,25 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) assertThat(promotedStoryListViewModel.equals(null)).isFalse() } @@ -808,45 +835,51 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModelOf2 = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModelOf2 = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val promotedStoryListViewModelOf3 = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory3 + ) + val promotedStoryListViewModelOf3 = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory3 + ) ) - )) + ) assertThat(promotedStoryListViewModelOf2.equals(promotedStoryListViewModelOf3)).isFalse() } @@ -859,50 +892,298 @@ class HomeFragmentViewModelsTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel(it, listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) ) - )) + ) assertThat(promotedStoryListViewModel.equals(copyPromotedStoryListViewModel)).isTrue() - assertThat( - promotedStoryListViewModel.hashCode() == copyPromotedStoryListViewModel.hashCode() - ).isTrue() + assertThat(promotedStoryListViewModel.hashCode()) + .isEqualTo(copyPromotedStoryListViewModel.hashCode()) + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_reflexiveTopicSummary1Entity1Position5_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + assertThat(topicSummaryViewModel.equals(topicSummaryViewModel)).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_symmetricTopicSummary1Entity1Position5_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isSymmetric = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && + copyTopicSummaryViewModel.equals(topicSummaryViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_transitiveTopicSummary1Entity1Position5_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copy1TopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copy2TopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isTransitive = topicSummaryViewModel.equals(copy1TopicSummaryViewModel) && + copy1TopicSummaryViewModel.equals(copy2TopicSummaryViewModel) && + copy2TopicSummaryViewModel.equals(topicSummaryViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_consistentTopicSummary1Entity1Position5_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isConsistent = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && + topicSummaryViewModel.equals(copyTopicSummaryViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_topicSummary1Entity1Position5AndNull_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary2, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_entity1AndEntity2_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_2", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_position4AndPosition5_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 4 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + assertThat(topicSummaryViewModel.equals(copyTopicSummaryViewModel)).isTrue() + + assertThat(topicSummaryViewModel.hashCode()) + .isEqualTo(copyTopicSummaryViewModel.hashCode()) } } } @After fun tearDown() { - testCoroutineDispatchers.unregisterIdlingResource() } // TODO(#59): Figure out a way to reuse modules instead of needing to re-declare them. From 57abbea38372d300ca9897d5ea20ca1a9e4e6b0d Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 09:43:25 -0800 Subject: [PATCH 140/248] Shorten comment --- .../main/java/org/oppia/android/app/home/WelcomeViewModel.kt | 4 ++-- .../app/home/promotedlist/PromotedStoryListViewModel.kt | 4 ++-- .../android/app/home/promotedlist/PromotedStoryViewModel.kt | 4 ++-- .../oppia/android/app/home/topiclist/TopicSummaryViewModel.kt | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index ca68dccaf23..8623a06a9d9 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -20,8 +20,8 @@ class WelcomeViewModel( ).getGreetingMessage() // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel - // only rebinds data when the actual data values in the HomeViewModel data list changes rather than - // the ViewModel object. + // will only rebind when the actual data in the data list changes, rather than when the ViewModel + // object changes. override fun equals(other: Any?): Boolean { return other is WelcomeViewModel && this.profileName == other.profileName && diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 8b362ec4e43..32fad70087d 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -51,8 +51,8 @@ class PromotedStoryListViewModel( } // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel - // only rebinds data when the actual data values in the HomeViewModel data list changes rather than - // the ViewModel object. + // will only rebind when the actual data in the data list changes, rather than when the ViewModel + // object changes. override fun equals(other: Any?): Boolean { return other is PromotedStoryListViewModel && other.promotedStoryList == this.promotedStoryList diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 2e9eb8ca0dd..5eb7be4cf0e 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -45,8 +45,8 @@ class PromotedStoryViewModel( } // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel - // only rebinds data when the actual data values in the HomeViewModel data list changes rather than - // the ViewModel object. + // will only rebind when the actual data in the data list changes, rather than when the ViewModel + // object changes. override fun equals(other: Any?): Boolean { return other is PromotedStoryViewModel && other.internalProfileId == this.internalProfileId && diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index 093a89cc164..d68bf026c2b 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -129,8 +129,8 @@ class TopicSummaryViewModel( } // Overriding equals is needed so that DataProvider combine functions used in the HomeViewModel - // only rebinds data when the actual data values in the HomeViewModel data list changes rather than - // the ViewModel object. + // will only rebind when the actual data in the data list changes, rather than when the ViewModel + // object changes. override fun equals(other: Any?): Boolean { return other is TopicSummaryViewModel && other.topicSummary == this.topicSummary && From 502a6f7274a58025fcbcdc08fb5dc8b65c03e4e8 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 12:17:06 -0800 Subject: [PATCH 141/248] Address review comments --- .../oppia/android/app/home/WelcomeViewModel.kt | 2 +- .../promotedlist/PromotedStoryListViewModel.kt | 5 ++--- .../home/promotedlist/PromotedStoryViewModel.kt | 12 ++++++------ .../app/home/topiclist/TopicSummaryViewModel.kt | 6 +----- .../app/testing/HomeFragmentTestActivity.kt | 3 +-- .../app/home/HomeFragmentViewModelsTest.kt | 15 +++++++++++---- 6 files changed, 22 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt index 8623a06a9d9..3fafd5f0320 100644 --- a/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/WelcomeViewModel.kt @@ -28,5 +28,5 @@ class WelcomeViewModel( this.greeting == other.greeting } - override fun hashCode() = Objects.hash(this.profileName) + Objects.hash(this.greeting) + override fun hashCode() = Objects.hash(profileName, greeting) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 32fad70087d..afe052b5ed9 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -54,9 +54,8 @@ class PromotedStoryListViewModel( // will only rebind when the actual data in the data list changes, rather than when the ViewModel // object changes. override fun equals(other: Any?): Boolean { - return other is PromotedStoryListViewModel && - other.promotedStoryList == this.promotedStoryList + return other is PromotedStoryListViewModel && other.promotedStoryList == this.promotedStoryList } - override fun hashCode() = Objects.hash(this.promotedStoryList) + override fun hashCode() = Objects.hash(promotedStoryList) } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt index 5eb7be4cf0e..bd586a8cf28 100755 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt @@ -55,10 +55,10 @@ class PromotedStoryViewModel( other.promotedStory == this.promotedStory } - override fun hashCode(): Int { - return Objects.hash(this.internalProfileId) + - Objects.hash(this.totalStoryCount) + - Objects.hash(this.entityType) + - Objects.hash(this.promotedStory) - } + override fun hashCode() = Objects.hash( + internalProfileId, + totalStoryCount, + entityType, + promotedStory + ) } diff --git a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt index d68bf026c2b..a4704e5c89e 100755 --- a/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt @@ -138,9 +138,5 @@ class TopicSummaryViewModel( other.position == this.position } - override fun hashCode(): Int { - return Objects.hash(this.topicSummary) + - Objects.hash(this.entityType) + - Objects.hash(this.position) - } + override fun hashCode() = Objects.hash(topicSummary, entityType, position) } diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 9b2bf245b6a..6ce8fe58204 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -30,8 +30,7 @@ class HomeFragmentTestActivity : companion object { fun createHomeFragmentTestActivity(context: Context): Intent { - val intent = Intent(context, HomeFragmentTestActivity::class.java) - return intent + return Intent(context, HomeFragmentTestActivity::class.java) } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 84b1bfc8ad9..d4ef47cd3fd 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -80,8 +80,12 @@ class HomeFragmentViewModelsTest { @Inject lateinit var context: Context - private var morningClock = OppiaClock() - private var eveningClock = OppiaClock() + @Inject + lateinit var morningClock: OppiaClock + + @Inject + lateinit var eveningClock: OppiaClock + private val promotedStory1 = PromotedStory.newBuilder() .setStoryId("id_1") .setStoryName("Story 1") @@ -114,15 +118,16 @@ class HomeFragmentViewModelsTest { @Before fun setUp() { setUpTestApplicationComponent() - setUpClocks() } private fun setUpTestApplicationComponent() { ApplicationProvider.getApplicationContext().inject(this) } - private fun setUpClocks() { + private fun setUpDifferentClockTimes() { + morningClock = OppiaClock() morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) + eveningClock = OppiaClock() eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) } @@ -275,7 +280,9 @@ class HomeFragmentViewModelsTest { launch( createHomeFragmentTestActivity(context) ).use { + it.onActivity { + setUpDifferentClockTimes() val fragment = getTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( fragment, From e05ba31e5822e6a74d5e810694231a2c0ad2bd7a Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 12:37:21 -0800 Subject: [PATCH 142/248] Separate WelcomeViewModel into own test --- .../app/home/HomeFragmentViewModelsTest.kt | 202 ---------- .../android/app/home/WelcomeViewModelTest.kt | 358 ++++++++++++++++++ 2 files changed, 358 insertions(+), 202 deletions(-) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index d4ef47cd3fd..55454e21087 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -80,12 +80,6 @@ class HomeFragmentViewModelsTest { @Inject lateinit var context: Context - @Inject - lateinit var morningClock: OppiaClock - - @Inject - lateinit var eveningClock: OppiaClock - private val promotedStory1 = PromotedStory.newBuilder() .setStoryId("id_1") .setStoryName("Story 1") @@ -124,208 +118,12 @@ class HomeFragmentViewModelsTest { ApplicationProvider.getApplicationContext().inject(this) } - private fun setUpDifferentClockTimes() { - morningClock = OppiaClock() - morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) - eveningClock = OppiaClock() - eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) - } - private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { return activity.supportFragmentManager.findFragmentByTag( "home_fragment_test_activity" ) as HomeFragment } - @Test - fun testWelcomeViewModelEquals_reflexiveProfile1MorningAndProfile1Morning_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning)).isTrue() - } - } - } - - @Test - fun testWelcomeViewModelEquals_symmetricProfile1MorningAndDifferentProfile1Morning_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val isSymmetric = - welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning) && - copyWelcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning) - assertThat(isSymmetric).isTrue() - } - } - } - - @Test - fun testWelcomeViewModelEquals_transitiveProfile1MorningAndTwoDifferentProfile1Morning_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val copy2WelcomeVieModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val isTransitive = - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && - copy1WelcomeViewModelProfile1Morning.equals(copy2WelcomeVieModelProfile1Morning) && - copy2WelcomeVieModelProfile1Morning.equals(welcomeViewModelProfile1Morning) - assertThat(isTransitive).isTrue() - } - } - } - - @Test - fun testWelcomeViewModelEquals_consistentProfile1MorningAndDifferentProfile1Morning_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val isConsistent = - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) - assertThat(isConsistent).isTrue() - } - } - } - - @Test - fun testWelcomeViewModelEquals_profile1MorningAndNull_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - assertThat(welcomeViewModelProfile1Morning.equals(null)).isFalse() - } - } - } - - @Test - fun testWelcomeViewModelEquals_profile1MorningAndProfile2Morning_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val welcomeViewModelProfile2Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 2" - ) - assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile2Morning)) - .isFalse() - } - } - } - - @Test - fun testWelcomeViewModelEquals_profile1MorningAndProfile1Evening_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - - it.onActivity { - setUpDifferentClockTimes() - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val welcomeViewModelProfile1Evening = WelcomeViewModel( - fragment, - eveningClock, - "Profile 1" - ) - val equal = welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Evening) - assertThat(equal).isFalse() - } - } - } - - @Test - fun testWelcomeViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - assertThat(welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning)) - .isTrue() - - assertThat(welcomeViewModelProfile1Morning.hashCode()) - .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) - } - } - } - @Test fun testPromotedStoryViewModelEquals_reflexiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { launch( diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt new file mode 100644 index 00000000000..a7130ee2e71 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -0,0 +1,358 @@ +package org.oppia.android.app.home + +import android.app.Application +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ActivityScenario.launch +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.app.testing.HomeFragmentTestActivity +import org.oppia.android.app.testing.HomeFragmentTestActivity.Companion.createHomeFragmentTestActivity +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.oppia.android.util.system.OppiaClock +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +// Time: Wed Apr 24 2019 08:22:00 +private const val MORNING_TIMESTAMP = 1556094120000 + +// Time: Tue Apr 23 2019 23:22:00 +private const val EVENING_TIMESTAMP = 1556061720000 + +/** Tests for [HomeViewModel]s data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = WelcomeViewModelTest.TestApplication::class, + manifest = Config.NONE +) +class WelcomeViewModelTest { + @Inject + lateinit var context: Context + + @Inject + lateinit var morningClock: OppiaClock + + @Inject + lateinit var eveningClock: OppiaClock + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun setUpDifferentClockTimes() { + morningClock = OppiaClock() + morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) + eveningClock = OppiaClock() + eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) + } + + private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { + return activity.supportFragmentManager.findFragmentByTag( + "home_fragment_test_activity" + ) as HomeFragment + } + + @Test + fun testWelcomeViewModelEquals_reflexiveProfile1MorningAndProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning)).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_symmetricProfile1MorningAndDifferentProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isSymmetric = + welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning) && + copyWelcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_transitiveProfile1MorningAndTwoDifferentProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy2WelcomeVieModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isTransitive = + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && + copy1WelcomeViewModelProfile1Morning.equals(copy2WelcomeVieModelProfile1Morning) && + copy2WelcomeVieModelProfile1Morning.equals(welcomeViewModelProfile1Morning) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_consistentProfile1MorningAndDifferentProfile1Morning_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val isConsistent = + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && + welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testWelcomeViewModelEquals_profile1MorningAndNull_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(null)).isFalse() + } + } + } + + @Test + fun testWelcomeViewModelEquals_profile1MorningAndProfile2Morning_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val welcomeViewModelProfile2Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 2" + ) + assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile2Morning)) + .isFalse() + } + } + } + + @Test + fun testWelcomeViewModelEquals_profile1MorningAndProfile1Evening_isFalse() { + launch( + createHomeFragmentTestActivity(context) + ).use { + + it.onActivity { + setUpDifferentClockTimes() + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val welcomeViewModelProfile1Evening = WelcomeViewModel( + fragment, + eveningClock, + "Profile 1" + ) + val equal = welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Evening) + assertThat(equal).isFalse() + } + } + } + + @Test + fun testWelcomeViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + assertThat(welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning)) + .isTrue() + + assertThat(welcomeViewModelProfile1Morning.hashCode()) + .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) + } + } + } + + @Test + fun testWelcomeViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + launch( + createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val welcomeViewModelProfile1Morning = WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + val firstHash = welcomeViewModelProfile1Morning.hashCode() + val secondHash = welcomeViewModelProfile1Morning.hashCode() + + assertThat(firstHash).isEqualTo(secondHash) + } + } + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(welcomeViewModelTest: WelcomeViewModelTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerWelcomeViewModelTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(welcomeViewModelTest: WelcomeViewModelTest) { + component.inject(welcomeViewModelTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} From dc1c8af763caa54e33b6b26a4edcac767a984dad Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 12:48:13 -0800 Subject: [PATCH 143/248] Separate PromotedStoryViewModel test --- .../app/home/HomeFragmentViewModelsTest.kt | 281 ----------- .../home/PromotedStoryListViewModelTest.kt | 2 + .../app/home/PromotedStoryViewModelTest.kt | 438 ++++++++++++++++++ 3 files changed, 440 insertions(+), 281 deletions(-) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 55454e21087..03e8b296aed 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -63,12 +63,6 @@ import org.robolectric.annotation.LooperMode import javax.inject.Inject import javax.inject.Singleton -// Time: Wed Apr 24 2019 08:22:00 -private const val MORNING_TIMESTAMP = 1556094120000 - -// Time: Tue Apr 23 2019 23:22:00 -private const val EVENING_TIMESTAMP = 1556061720000 - /** Tests for [HomeViewModel]s data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) @@ -124,277 +118,6 @@ class HomeFragmentViewModelsTest { ) as HomeFragment } - @Test - fun testPromotedStoryViewModelEquals_reflexiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - val isReflexive = promotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isReflexive).isTrue() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_symmetricProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - ) - - val isSymmetric = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && - copyPromotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isSymmetric).isTrue() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_transitiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copy1PromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copy2PromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - val isTransitive = promotedStoryViewModel.equals(copy1PromotedStoryViewModel) && - copy1PromotedStoryViewModel.equals(copy2PromotedStoryViewModel) && - copy2PromotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isTransitive).isTrue() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_consistentProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - val isConsistent = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && - promotedStoryViewModel.equals(copyPromotedStoryViewModel) - assertThat(isConsistent).isTrue() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_profile1StoryCount3EntityTypeEmptyStory1AndNull_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - assertThat(promotedStoryViewModel.equals(null)).isFalse() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModelProfile1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val promotedStoryViewModelProfile2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */2, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - assertThat(promotedStoryViewModelProfile1.equals(promotedStoryViewModelProfile2)).isFalse() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModelStoryCount2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */2, - /* entytType = */"", - promotedStory1 - ) - val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - assertThat(promotedStoryViewModelStoryCount2.equals(promotedStoryViewModelStoryCount3)) - .isFalse() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_entity1AndEntity2_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModelEntity1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"Entity 1", - promotedStory1 - ) - val promotedStoryViewModelEntity2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"Entity 2", - promotedStory1 - ) - - assertThat(promotedStoryViewModelEntity1.equals(promotedStoryViewModelEntity2)).isFalse() - } - } - } - - @Test - fun testPromotedStoryViewModelEquals_story1AndStory2_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - assertThat(promotedStory1.equals(promotedStory2)).isFalse() - - val promotedStoryViewModelStory1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"Entity 1", - promotedStory1 - ) - val promotedStoryViewModelStory2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"Entity 2", - promotedStory2 - ) - - assertThat(promotedStoryViewModelStory1.equals(promotedStoryViewModelStory2)).isFalse() - } - } - } - - @Test - fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() - - assertThat(promotedStoryViewModel.hashCode()) - .isEqualTo(copyPromotedStoryViewModel.hashCode()) - } - } - } - @Test fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { launch( @@ -987,10 +710,6 @@ class HomeFragmentViewModelsTest { } } - @After - fun tearDown() { - } - // 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/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt new file mode 100644 index 00000000000..f732e47cc52 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt @@ -0,0 +1,2 @@ +package org.oppia.android.app.home + diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt new file mode 100644 index 00000000000..4e77292300d --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt @@ -0,0 +1,438 @@ +package org.oppia.android.app.home + +import android.app.Application +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.home.promotedlist.PromotedStoryViewModel +import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.app.testing.HomeFragmentTestActivity +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +/** Tests for [HomeViewModel]s data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = PromotedStoryViewModelTest.TestApplication::class, + manifest = Config.NONE +) +class PromotedStoryViewModelTest { + @Inject + lateinit var context: Context + + private val promotedStory1 = PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory2 = PromotedStory.newBuilder() + .setStoryId("id_2") + .setStoryName("Story 2") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory3 = PromotedStory.newBuilder() + .setStoryId("id_3") + .setStoryName("Story 3") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + @Test + fun testPromotedStoryViewModelEquals_reflexiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + val isReflexive = promotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isReflexive).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_symmetricProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + ) + + val isSymmetric = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && + copyPromotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_transitiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val copy1PromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val copy2PromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + val isTransitive = promotedStoryViewModel.equals(copy1PromotedStoryViewModel) && + copy1PromotedStoryViewModel.equals(copy2PromotedStoryViewModel) && + copy2PromotedStoryViewModel.equals(promotedStoryViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_consistentProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + val isConsistent = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && + promotedStoryViewModel.equals(copyPromotedStoryViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_profile1StoryCount3EntityTypeEmptyStory1AndNull_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + assertThat(promotedStoryViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelProfile1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val promotedStoryViewModelProfile2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */2, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + assertThat(promotedStoryViewModelProfile1.equals(promotedStoryViewModelProfile2)) + .isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelStoryCount2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */2, + /* entytType = */"", + promotedStory1 + ) + val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + + assertThat(promotedStoryViewModelStoryCount2.equals(promotedStoryViewModelStoryCount3)) + .isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_entity1AndEntity2_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModelEntity1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 1", + promotedStory1 + ) + val promotedStoryViewModelEntity2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 2", + promotedStory1 + ) + + assertThat(promotedStoryViewModelEntity1.equals(promotedStoryViewModelEntity2)) + .isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelEquals_story1AndStory2_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + assertThat(promotedStory1.equals(promotedStory2)).isFalse() + + val promotedStoryViewModelStory1 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 1", + promotedStory1 + ) + val promotedStoryViewModelStory2 = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"Entity 2", + promotedStory2 + ) + + assertThat(promotedStoryViewModelStory1.equals(promotedStoryViewModelStory2)) + .isFalse() + } + } + } + + @Test + fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val copyPromotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() + + assertThat(promotedStoryViewModel.hashCode()) + .isEqualTo(copyPromotedStoryViewModel.hashCode()) + } + } + } + + @Test + fun testPromotedStoryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryViewModel = PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ) + val firstHash = promotedStoryViewModel.hashCode() + val secondHash = promotedStoryViewModel.hashCode() + + assertThat(firstHash).isEqualTo(secondHash) + } + } + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(promotedStoryViewModelTest: PromotedStoryViewModelTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerPromotedStoryViewModelTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(promotedStoryViewModelTest: PromotedStoryViewModelTest) { + component.inject(promotedStoryViewModelTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} \ No newline at end of file From 8dae24430249c43505e260857f915a250e5e12e5 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:02:17 -0800 Subject: [PATCH 144/248] Separate PromotedStoryListViewModel tests --- .../app/home/HomeFragmentViewModelsTest.kt | 348 ------------ .../home/PromotedStoryListViewModelTest.kt | 523 ++++++++++++++++++ .../app/home/PromotedStoryViewModelTest.kt | 2 +- .../android/app/home/WelcomeViewModelTest.kt | 2 +- 4 files changed, 525 insertions(+), 350 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt index 03e8b296aed..d71d867c616 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt @@ -118,354 +118,6 @@ class HomeFragmentViewModelsTest { ) as HomeFragment } - @Test - fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - - val isReflexive = promotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isReflexive).isTrue() - } - } - } - - @Test - fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - - val isSymmetric = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && - copyPromotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isSymmetric).isTrue() - } - } - } - - @Test - fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val copy1PromotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val copy2PromotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - - val isTransitive = promotedStoryListViewModel.equals(copy1PromotedStoryListViewModel) && - copy1PromotedStoryListViewModel.equals(copy2PromotedStoryListViewModel) && - copy2PromotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isTransitive).isTrue() - } - } - } - - @Test - fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - - val isConsistent = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && - promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) - assertThat(isConsistent).isTrue() - } - } - } - - @Test - fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - - assertThat(promotedStoryListViewModel.equals(null)).isFalse() - } - } - } - - @Test - fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModelOf2 = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val promotedStoryListViewModelOf3 = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory3 - ) - ) - ) - - assertThat(promotedStoryListViewModelOf2.equals(promotedStoryListViewModelOf3)).isFalse() - } - } - } - - @Test - fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) - ) - assertThat(promotedStoryListViewModel.equals(copyPromotedStoryListViewModel)).isTrue() - - assertThat(promotedStoryListViewModel.hashCode()) - .isEqualTo(copyPromotedStoryListViewModel.hashCode()) - } - } - } - @Test fun testTopicSummaryViewModelEquals_reflexiveTopicSummary1Entity1Position5_isTrue() { launch( diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt index f732e47cc52..88a0f8d7045 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt @@ -1,2 +1,525 @@ package org.oppia.android.app.home +import android.app.Application +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.home.promotedlist.PromotedStoryListViewModel +import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel +import org.oppia.android.app.model.PromotedStory +import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.app.testing.HomeFragmentTestActivity +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +/** Tests for [PromotedStoryListViewModel] data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = PromotedStoryListViewModelTest.TestApplication::class, + manifest = Config.NONE +) +class PromotedStoryListViewModelTest { + @Inject + lateinit var context: Context + + private val promotedStory1 = PromotedStory.newBuilder() + .setStoryId("id_1") + .setStoryName("Story 1") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory2 = PromotedStory.newBuilder() + .setStoryId("id_2") + .setStoryName("Story 2") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + private val promotedStory3 = PromotedStory.newBuilder() + .setStoryId("id_3") + .setStoryName("Story 3") + .setTopicName("topic_name") + .setTotalChapterCount(1) + .build() + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + @Test + fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + val isReflexive = promotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isReflexive).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + val isSymmetric = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && + copyPromotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val copy1PromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val copy2PromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + val isTransitive = promotedStoryListViewModel.equals(copy1PromotedStoryListViewModel) && + copy1PromotedStoryListViewModel.equals(copy2PromotedStoryListViewModel) && + copy2PromotedStoryListViewModel.equals(promotedStoryListViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + val isConsistent = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && + promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + assertThat(promotedStoryListViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModelOf2 = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val promotedStoryListViewModelOf3 = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory3 + ) + ) + ) + + assertThat(promotedStoryListViewModelOf2.equals(promotedStoryListViewModelOf3)).isFalse() + } + } + } + + @Test + fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + assertThat(promotedStoryListViewModel.equals(copyPromotedStoryListViewModel)).isTrue() + + assertThat(promotedStoryListViewModel.hashCode()) + .isEqualTo(copyPromotedStoryListViewModel.hashCode()) + } + } + } + + @Test + fun testPromotedStoryListViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val promotedStoryListViewModel = PromotedStoryListViewModel( + it, + listOf( + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory1 + ), + PromotedStoryViewModel( + /* activity = */ it, + /* internalProfileId = */1, + /* totalStoryCount = */3, + /* entytType = */"", + promotedStory2 + ) + ) + ) + + val firstHash = promotedStoryListViewModel.hashCode() + val secondHash = promotedStoryListViewModel.hashCode() + assertThat(firstHash).isEqualTo(secondHash) + } + } + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(promotedStoryListViewModelTest: PromotedStoryListViewModelTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerPromotedStoryListViewModelTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(promotedStoryListViewModelTest: PromotedStoryListViewModelTest) { + component.inject(promotedStoryListViewModelTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} \ No newline at end of file diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt index 4e77292300d..c6a9bfcd2fe 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt @@ -57,7 +57,7 @@ import org.robolectric.annotation.LooperMode import javax.inject.Inject import javax.inject.Singleton -/** Tests for [HomeViewModel]s data. */ +/** Tests for [PromotedStoryViewModel] data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) @Config( diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index a7130ee2e71..6c8e6c6ada4 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -63,7 +63,7 @@ private const val MORNING_TIMESTAMP = 1556094120000 // Time: Tue Apr 23 2019 23:22:00 private const val EVENING_TIMESTAMP = 1556061720000 -/** Tests for [HomeViewModel]s data. */ +/** Tests for [WelcomeViewModel] data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) @Config( From e7576c95bcbe08635e467ce3d1d254f19810134b Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:16:27 -0800 Subject: [PATCH 145/248] Separate TopicSummaryViewModel tests --- .../app/home/TopicSummaryViewModelTest.kt | 407 ++++++++++++++++++ 1 file changed, 407 insertions(+) create mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt new file mode 100644 index 00000000000..e201cc2d1f5 --- /dev/null +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -0,0 +1,407 @@ +package org.oppia.android.app.home + +import android.app.Application +import android.content.Context +import androidx.appcompat.app.AppCompatActivity +import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.google.common.truth.Truth.assertThat +import dagger.Component +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.oppia.android.app.activity.ActivityComponent +import org.oppia.android.app.application.ActivityComponentFactory +import org.oppia.android.app.application.ApplicationComponent +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.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule +import org.oppia.android.app.shim.IntentFactoryShimModule +import org.oppia.android.app.shim.ViewBindingShimModule +import org.oppia.android.app.testing.HomeFragmentTestActivity +import org.oppia.android.domain.classify.InteractionsModule +import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule +import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule +import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule +import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule +import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule +import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule +import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule +import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule +import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule +import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule +import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule +import org.oppia.android.domain.oppialogger.LogStorageModule +import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule +import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule +import org.oppia.android.domain.question.QuestionModule +import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule +import org.oppia.android.testing.RobolectricModule +import org.oppia.android.testing.TestAccessibilityModule +import org.oppia.android.testing.TestDispatcherModule +import org.oppia.android.testing.TestLogReportingModule +import org.oppia.android.util.caching.testing.CachingTestModule +import org.oppia.android.util.gcsresource.GcsResourceModule +import org.oppia.android.util.logging.LoggerModule +import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule +import org.oppia.android.util.parser.GlideImageLoaderModule +import org.oppia.android.util.parser.HtmlParserEntityTypeModule +import org.oppia.android.util.parser.ImageParsingModule +import org.robolectric.annotation.Config +import org.robolectric.annotation.LooperMode +import javax.inject.Inject +import javax.inject.Singleton + +/** Tests for [HomeViewModel]s data. */ +@RunWith(AndroidJUnit4::class) +@LooperMode(LooperMode.Mode.PAUSED) +@Config( + application = TopicSummaryViewModelTest.TestApplication::class, + manifest = Config.NONE +) +class TopicSummaryViewModelTest { + @Inject + lateinit var context: Context + + private val topicSummary1 = TopicSummary.newBuilder() + .setTopicId("id_1") + .setName("topic_name") + .setTotalChapterCount(2) + .build() + private val topicSummary2 = TopicSummary.newBuilder() + .setTopicId("id_2") + .setName("topic_name") + .setTotalChapterCount(2) + .build() + + @Before + fun setUp() { + setUpTestApplicationComponent() + } + + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { + return activity.supportFragmentManager.findFragmentByTag( + "home_fragment_test_activity" + ) as HomeFragment + } + + @Test + fun testTopicSummaryViewModelEquals_reflexiveTopicSummary1Entity1Position5_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + assertThat(topicSummaryViewModel.equals(topicSummaryViewModel)).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_symmetricTopicSummary1Entity1Position5_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isSymmetric = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && + copyTopicSummaryViewModel.equals(topicSummaryViewModel) + assertThat(isSymmetric).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_transitiveTopicSummary1Entity1Position5_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copy1TopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copy2TopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isTransitive = topicSummaryViewModel.equals(copy1TopicSummaryViewModel) && + copy1TopicSummaryViewModel.equals(copy2TopicSummaryViewModel) && + copy2TopicSummaryViewModel.equals(topicSummaryViewModel) + assertThat(isTransitive).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_consistentTopicSummary1Entity1Position5_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + val isConsistent = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && + topicSummaryViewModel.equals(copyTopicSummaryViewModel) + assertThat(isConsistent).isTrue() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_topicSummary1Entity1Position5AndNull_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel.equals(null)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary2, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_entity1AndEntity2_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_2", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelEquals_position4AndPosition5_isFalse() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel1 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 4 + ) + val topicSummaryViewModel2 = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + + assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + } + } + } + + @Test + fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val copyTopicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + assertThat(topicSummaryViewModel.equals(copyTopicSummaryViewModel)).isTrue() + + assertThat(topicSummaryViewModel.hashCode()) + .isEqualTo(copyTopicSummaryViewModel.hashCode()) + } + } + } + + @Test + fun testTopicSummaryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + ActivityScenario.launch( + HomeFragmentTestActivity.createHomeFragmentTestActivity(context) + ).use { + it.onActivity { + val fragment = getTestFragment(it) + val topicSummaryViewModel = TopicSummaryViewModel( + /* activity = */ it, + topicSummary1, + /* entityType = */ "entity_1", + /* topicSummaryCLickListener = */ fragment, + /* position = */ 5 + ) + val firstHash = topicSummaryViewModel.hashCode() + val secondHash = topicSummaryViewModel.hashCode() + + assertThat(firstHash).isEqualTo(secondHash) + } + } + } + + // 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 + @Component( + modules = [ + TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, + LoggerModule::class, ContinueModule::class, FractionInputModule::class, + ItemSelectionInputModule::class, MultipleChoiceInputModule::class, + NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, + DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, + GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, + QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, + ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, + ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, + PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, + ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, + WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, + FirebaseLogUploaderModule::class + ] + ) + interface TestApplicationComponent : ApplicationComponent { + @Component.Builder + interface Builder : ApplicationComponent.Builder + + fun inject(topicSummaryViewModelTest: TopicSummaryViewModelTest) + } + + class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { + private val component: TestApplicationComponent by lazy { + DaggerTopicSummaryViewModelTest_TestApplicationComponent.builder() + .setApplication(this) + .build() as TestApplicationComponent + } + + fun inject(topicSummaryViewModelTest: TopicSummaryViewModelTest) { + component.inject(topicSummaryViewModelTest) + } + + override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { + return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() + } + + override fun getApplicationInjector(): ApplicationInjector = component + } +} From 401ddb04b5c75abab430b9932fcfbf0598d0ac87 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:24:09 -0800 Subject: [PATCH 146/248] Remove combined ViewModel tests --- .../app/home/HomeFragmentViewModelsTest.kt | 409 ------------------ 1 file changed, 409 deletions(-) delete mode 100644 app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt deleted file mode 100644 index d71d867c616..00000000000 --- a/app/src/sharedTest/java/org/oppia/android/app/home/HomeFragmentViewModelsTest.kt +++ /dev/null @@ -1,409 +0,0 @@ -package org.oppia.android.app.home - -import android.app.Application -import android.content.Context -import androidx.appcompat.app.AppCompatActivity -import androidx.test.core.app.ActivityScenario.launch -import androidx.test.core.app.ApplicationProvider -import androidx.test.ext.junit.runners.AndroidJUnit4 -import com.google.common.truth.Truth.assertThat -import dagger.Component -import org.junit.After -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.oppia.android.app.activity.ActivityComponent -import org.oppia.android.app.application.ActivityComponentFactory -import org.oppia.android.app.application.ApplicationComponent -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.home.promotedlist.PromotedStoryListViewModel -import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel -import org.oppia.android.app.home.topiclist.TopicSummaryViewModel -import org.oppia.android.app.model.PromotedStory -import org.oppia.android.app.model.TopicSummary -import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule -import org.oppia.android.app.shim.IntentFactoryShimModule -import org.oppia.android.app.shim.ViewBindingShimModule -import org.oppia.android.app.testing.HomeFragmentTestActivity -import org.oppia.android.app.testing.HomeFragmentTestActivity.Companion.createHomeFragmentTestActivity -import org.oppia.android.domain.classify.InteractionsModule -import org.oppia.android.domain.classify.rules.continueinteraction.ContinueModule -import org.oppia.android.domain.classify.rules.dragAndDropSortInput.DragDropSortInputModule -import org.oppia.android.domain.classify.rules.fractioninput.FractionInputModule -import org.oppia.android.domain.classify.rules.imageClickInput.ImageClickInputModule -import org.oppia.android.domain.classify.rules.itemselectioninput.ItemSelectionInputModule -import org.oppia.android.domain.classify.rules.multiplechoiceinput.MultipleChoiceInputModule -import org.oppia.android.domain.classify.rules.numberwithunits.NumberWithUnitsRuleModule -import org.oppia.android.domain.classify.rules.numericinput.NumericInputRuleModule -import org.oppia.android.domain.classify.rules.ratioinput.RatioInputModule -import org.oppia.android.domain.classify.rules.textinput.TextInputRuleModule -import org.oppia.android.domain.onboarding.ExpirationMetaDataRetrieverModule -import org.oppia.android.domain.oppialogger.LogStorageModule -import org.oppia.android.domain.oppialogger.loguploader.LogUploadWorkerModule -import org.oppia.android.domain.oppialogger.loguploader.WorkManagerConfigurationModule -import org.oppia.android.domain.question.QuestionModule -import org.oppia.android.domain.topic.PrimeTopicAssetsControllerModule -import org.oppia.android.testing.RobolectricModule -import org.oppia.android.testing.TestAccessibilityModule -import org.oppia.android.testing.TestDispatcherModule -import org.oppia.android.testing.TestLogReportingModule -import org.oppia.android.util.caching.testing.CachingTestModule -import org.oppia.android.util.gcsresource.GcsResourceModule -import org.oppia.android.util.logging.LoggerModule -import org.oppia.android.util.logging.firebase.FirebaseLogUploaderModule -import org.oppia.android.util.parser.GlideImageLoaderModule -import org.oppia.android.util.parser.HtmlParserEntityTypeModule -import org.oppia.android.util.parser.ImageParsingModule -import org.oppia.android.util.system.OppiaClock -import org.robolectric.annotation.Config -import org.robolectric.annotation.LooperMode -import javax.inject.Inject -import javax.inject.Singleton - -/** Tests for [HomeViewModel]s data. */ -@RunWith(AndroidJUnit4::class) -@LooperMode(LooperMode.Mode.PAUSED) -@Config( - application = HomeFragmentViewModelsTest.TestApplication::class, - manifest = Config.NONE -) -class HomeFragmentViewModelsTest { - @Inject - lateinit var context: Context - - private val promotedStory1 = PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - private val promotedStory2 = PromotedStory.newBuilder() - .setStoryId("id_2") - .setStoryName("Story 2") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - private val promotedStory3 = PromotedStory.newBuilder() - .setStoryId("id_3") - .setStoryName("Story 3") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - private val topicSummary1 = TopicSummary.newBuilder() - .setTopicId("id_1") - .setName("topic_name") - .setTotalChapterCount(2) - .build() - private val topicSummary2 = TopicSummary.newBuilder() - .setTopicId("id_2") - .setName("topic_name") - .setTotalChapterCount(2) - .build() - - @Before - fun setUp() { - setUpTestApplicationComponent() - } - - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - - private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { - return activity.supportFragmentManager.findFragmentByTag( - "home_fragment_test_activity" - ) as HomeFragment - } - - @Test - fun testTopicSummaryViewModelEquals_reflexiveTopicSummary1Entity1Position5_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - assertThat(topicSummaryViewModel.equals(topicSummaryViewModel)).isTrue() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_symmetricTopicSummary1Entity1Position5_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - val isSymmetric = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && - copyTopicSummaryViewModel.equals(topicSummaryViewModel) - assertThat(isSymmetric).isTrue() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_transitiveTopicSummary1Entity1Position5_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val copy1TopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val copy2TopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - val isTransitive = topicSummaryViewModel.equals(copy1TopicSummaryViewModel) && - copy1TopicSummaryViewModel.equals(copy2TopicSummaryViewModel) && - copy2TopicSummaryViewModel.equals(topicSummaryViewModel) - assertThat(isTransitive).isTrue() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_consistentTopicSummary1Entity1Position5_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - val isConsistent = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && - topicSummaryViewModel.equals(copyTopicSummaryViewModel) - assertThat(isConsistent).isTrue() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_topicSummary1Entity1Position5AndNull_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - assertThat(topicSummaryViewModel.equals(null)).isFalse() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val topicSummaryViewModel2 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary2, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_entity1AndEntity2_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val topicSummaryViewModel2 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_2", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() - } - } - } - - @Test - fun testTopicSummaryViewModelEquals_position4AndPosition5_isFalse() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 4 - ) - val topicSummaryViewModel2 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() - } - } - } - - @Test - fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { - launch( - createHomeFragmentTestActivity(context) - ).use { - it.onActivity { - val fragment = getTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, - /* position = */ 5 - ) - assertThat(topicSummaryViewModel.equals(copyTopicSummaryViewModel)).isTrue() - - assertThat(topicSummaryViewModel.hashCode()) - .isEqualTo(copyTopicSummaryViewModel.hashCode()) - } - } - } - - // 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 - @Component( - modules = [ - TestDispatcherModule::class, ApplicationModule::class, RobolectricModule::class, - LoggerModule::class, ContinueModule::class, FractionInputModule::class, - ItemSelectionInputModule::class, MultipleChoiceInputModule::class, - NumberWithUnitsRuleModule::class, NumericInputRuleModule::class, TextInputRuleModule::class, - DragDropSortInputModule::class, InteractionsModule::class, GcsResourceModule::class, - GlideImageLoaderModule::class, ImageParsingModule::class, HtmlParserEntityTypeModule::class, - QuestionModule::class, TestLogReportingModule::class, TestAccessibilityModule::class, - ImageClickInputModule::class, LogStorageModule::class, IntentFactoryShimModule::class, - ViewBindingShimModule::class, CachingTestModule::class, RatioInputModule::class, - PrimeTopicAssetsControllerModule::class, ExpirationMetaDataRetrieverModule::class, - ApplicationStartupListenerModule::class, LogUploadWorkerModule::class, - WorkManagerConfigurationModule::class, HintsAndSolutionConfigModule::class, - FirebaseLogUploaderModule::class - ] - ) - interface TestApplicationComponent : ApplicationComponent { - @Component.Builder - interface Builder : ApplicationComponent.Builder - - fun inject(homeFragmentViewModelsTest: HomeFragmentViewModelsTest) - } - - class TestApplication : Application(), ActivityComponentFactory, ApplicationInjectorProvider { - private val component: TestApplicationComponent by lazy { - DaggerHomeFragmentViewModelsTest_TestApplicationComponent.builder() - .setApplication(this) - .build() as TestApplicationComponent - } - - fun inject(homeViewModelTest: HomeFragmentViewModelsTest) { - component.inject(homeViewModelTest) - } - - override fun createActivityComponent(activity: AppCompatActivity): ActivityComponent { - return component.getActivityComponentBuilderProvider().get().setActivity(activity).build() - } - - override fun getApplicationInjector(): ApplicationInjector = component - } -} From a8818ba65ed0d707269114ed1ab9e6ed74a7d44a Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:24:50 -0800 Subject: [PATCH 147/248] Fix lint errors --- .../oppia/android/app/home/PromotedStoryListViewModelTest.kt | 2 +- .../org/oppia/android/app/home/PromotedStoryViewModelTest.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt index 88a0f8d7045..451d8ee0df9 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt @@ -522,4 +522,4 @@ class PromotedStoryListViewModelTest { override fun getApplicationInjector(): ApplicationInjector = component } -} \ No newline at end of file +} diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt index c6a9bfcd2fe..0d69d67c7ab 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt @@ -435,4 +435,4 @@ class PromotedStoryViewModelTest { override fun getApplicationInjector(): ApplicationInjector = component } -} \ No newline at end of file +} From fc8d16f25c075aec2d4f663b3d46bd5cefe571ac Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:32:23 -0800 Subject: [PATCH 148/248] Create fragment in view model test --- .../app/home/TopicSummaryViewModelTest.kt | 67 ++++++++++--------- .../android/app/home/WelcomeViewModelTest.kt | 65 +++++++++--------- 2 files changed, 69 insertions(+), 63 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index e201cc2d1f5..4cb528e2a09 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -3,6 +3,7 @@ package org.oppia.android.app.home import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -57,6 +58,8 @@ import org.robolectric.annotation.LooperMode import javax.inject.Inject import javax.inject.Singleton +private const val TEST_FRAGMENT_TAG = "topic_summary_view_model_test_fragment" + /** Tests for [HomeViewModel]s data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) @@ -68,6 +71,8 @@ class TopicSummaryViewModelTest { @Inject lateinit var context: Context + private val testFragment by lazy { HomeFragment() } + private val topicSummary1 = TopicSummary.newBuilder() .setTopicId("id_1") .setName("topic_name") @@ -88,10 +93,8 @@ class TopicSummaryViewModelTest { ApplicationProvider.getApplicationContext().inject(this) } - private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { - return activity.supportFragmentManager.findFragmentByTag( - "home_fragment_test_activity" - ) as HomeFragment + private fun setUpTestFragment(activity: HomeFragmentTestActivity) { + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG).commitNow() } @Test @@ -100,12 +103,12 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) assertThat(topicSummaryViewModel.equals(topicSummaryViewModel)).isTrue() @@ -119,19 +122,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val copyTopicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -148,26 +151,26 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val copy1TopicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val copy2TopicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -185,19 +188,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val copyTopicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -214,12 +217,12 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -234,19 +237,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel1 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val topicSummaryViewModel2 = TopicSummaryViewModel( /* activity = */ it, topicSummary2, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -261,19 +264,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel1 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val topicSummaryViewModel2 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_2", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -288,19 +291,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel1 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 4 ) val topicSummaryViewModel2 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) @@ -315,19 +318,19 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val copyTopicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) assertThat(topicSummaryViewModel.equals(copyTopicSummaryViewModel)).isTrue() @@ -344,12 +347,12 @@ class TopicSummaryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val topicSummaryViewModel = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ fragment, + /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) val firstHash = topicSummaryViewModel.hashCode() diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 6c8e6c6ada4..8cc05cfe093 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -3,6 +3,7 @@ package org.oppia.android.app.home import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.Fragment import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -63,6 +64,8 @@ private const val MORNING_TIMESTAMP = 1556094120000 // Time: Tue Apr 23 2019 23:22:00 private const val EVENING_TIMESTAMP = 1556061720000 +private const val TEST_FRAGMENT_TAG = "welcome_view_model_test_fragment" + /** Tests for [WelcomeViewModel] data. */ @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) @@ -80,6 +83,8 @@ class WelcomeViewModelTest { @Inject lateinit var eveningClock: OppiaClock + private val testFragment by lazy { Fragment() } + @Before fun setUp() { setUpTestApplicationComponent() @@ -89,6 +94,10 @@ class WelcomeViewModelTest { ApplicationProvider.getApplicationContext().inject(this) } + private fun setUpTestFragment(activity: HomeFragmentTestActivity) { + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG).commitNow() + } + private fun setUpDifferentClockTimes() { morningClock = OppiaClock() morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) @@ -96,21 +105,15 @@ class WelcomeViewModelTest { eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) } - private fun getTestFragment(activity: HomeFragmentTestActivity): HomeFragment { - return activity.supportFragmentManager.findFragmentByTag( - "home_fragment_test_activity" - ) as HomeFragment - } - @Test fun testWelcomeViewModelEquals_reflexiveProfile1MorningAndProfile1Morning_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -125,14 +128,14 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -150,19 +153,19 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val copy2WelcomeVieModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -181,14 +184,14 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -206,9 +209,9 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -223,14 +226,14 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val welcomeViewModelProfile2Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 2" ) @@ -248,14 +251,14 @@ class WelcomeViewModelTest { it.onActivity { setUpDifferentClockTimes() - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val welcomeViewModelProfile1Evening = WelcomeViewModel( - fragment, + testFragment, eveningClock, "Profile 1" ) @@ -271,14 +274,14 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) @@ -297,9 +300,9 @@ class WelcomeViewModelTest { createHomeFragmentTestActivity(context) ).use { it.onActivity { - val fragment = getTestFragment(it) + setUpTestFragment(it) val welcomeViewModelProfile1Morning = WelcomeViewModel( - fragment, + testFragment, morningClock, "Profile 1" ) From c00411136f44e75c096b010280c21301131aadc6 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:39:27 -0800 Subject: [PATCH 149/248] Remove fragment transaction from test activity --- .../org/oppia/android/app/testing/HomeFragmentTestActivity.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 6ce8fe58204..00a6a6cf45c 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -22,10 +22,6 @@ class HomeFragmentTestActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) activityComponent.inject(this) - supportFragmentManager.beginTransaction().add( - HomeFragment(), - "home_fragment_test_activity" - ).commitNow() } companion object { From 01d96cbead8383fb8d83f77f84577493a0c7a22c Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 13:42:11 -0800 Subject: [PATCH 150/248] Fix linter errors --- .../org/oppia/android/app/home/TopicSummaryViewModelTest.kt | 4 ++-- .../java/org/oppia/android/app/home/WelcomeViewModelTest.kt | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index 4cb528e2a09..5c1084fd85f 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -3,7 +3,6 @@ package org.oppia.android.app.home import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.fragment.app.Fragment import androidx.test.core.app.ActivityScenario import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -94,7 +93,8 @@ class TopicSummaryViewModelTest { } private fun setUpTestFragment(activity: HomeFragmentTestActivity) { - activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG).commitNow() + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) + .commitNow() } @Test diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 8cc05cfe093..1b6cb7ce4ea 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -95,7 +95,8 @@ class WelcomeViewModelTest { } private fun setUpTestFragment(activity: HomeFragmentTestActivity) { - activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG).commitNow() + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) + .commitNow() } private fun setUpDifferentClockTimes() { From a8e47a82cbd14af596f551d18a97b07d222f7c05 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 17:14:01 -0800 Subject: [PATCH 151/248] Use helpers and improve readability of promoted story list view model test --- .../PromotedStoryListViewModelTest.kt | 338 ++++-------------- .../PromotedStoryViewModelTest.kt | 2 +- 2 files changed, 76 insertions(+), 264 deletions(-) rename app/src/sharedTest/java/org/oppia/android/app/home/{ => promotedlist}/PromotedStoryListViewModelTest.kt (50%) rename app/src/sharedTest/java/org/oppia/android/app/home/{ => promotedlist}/PromotedStoryViewModelTest.kt (99%) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt similarity index 50% rename from app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt rename to app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 451d8ee0df9..bcef1d3198c 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -1,5 +1,6 @@ -package org.oppia.android.app.home +package org.oppia.android.app.home.promotedlist +import android.app.Activity import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity @@ -97,34 +98,42 @@ class PromotedStoryListViewModelTest { ApplicationProvider.getApplicationContext().inject(this) } + private fun createPromotedStoryViewModelList( + activity: AppCompatActivity, + promotedStoryList: List + ): List { + return promotedStoryList.map { + PromotedStoryViewModel( + activity, + internalProfileId = 1, + totalStoryCount = promotedStoryList.size, + entityType = "entity", + promotedStory = it) + } + } + + private fun createPromotedStoryListViewModel( + activity: AppCompatActivity, + promotedStoryList: List + ): PromotedStoryListViewModel { + return PromotedStoryListViewModel( + activity, + createPromotedStoryViewModelList(activity, promotedStoryList) + ) + } + @Test fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( - it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + val promotedStoryListViewModel = createPromotedStoryListViewModel( + it, listOf(promotedStory1, promotedStory2) ) - val isReflexive = promotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isReflexive).isTrue() + // Verify the reflexive property of equals(): a == a. + assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListViewModel) } } } @@ -135,48 +144,20 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModel = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModelCopy = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) + val originalEqualsCopy = promotedStoryListViewModel == promotedStoryListViewModelCopy + val copyEqualsOriginal = promotedStoryListViewModelCopy == promotedStoryListViewModel - val isSymmetric = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && - copyPromotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isSymmetric).isTrue() + // Verify the symmetric property of equals(): a == b iff b == a. + assertThat(originalEqualsCopy).isTrue() + assertThat(copyEqualsOriginal).isTrue() } } } @@ -187,68 +168,23 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModelCopy1 = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val copy1PromotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModelCopy2 = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val copy2PromotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModelCopy3 = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) + assertThat(promotedStoryListViewModelCopy1).isEqualTo(promotedStoryListViewModelCopy2) + assertThat(promotedStoryListViewModelCopy2).isEqualTo(promotedStoryListViewModelCopy3) - val isTransitive = promotedStoryListViewModel.equals(copy1PromotedStoryListViewModel) && - copy1PromotedStoryListViewModel.equals(copy2PromotedStoryListViewModel) && - copy2PromotedStoryListViewModel.equals(promotedStoryListViewModel) - assertThat(isTransitive).isTrue() + // Verify the transitive property of equals(): if a == b & b == c, then a == c + assertThat(promotedStoryListViewModelCopy1).isEqualTo(promotedStoryListViewModelCopy3) } } } @@ -259,48 +195,19 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModel = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModelCopy = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) + assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListViewModelCopy) - val isConsistent = promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) && - promotedStoryListViewModel.equals(copyPromotedStoryListViewModel) - assertThat(isConsistent).isTrue() + // Verify the consistent property of equals(): if neither object is modified, then a == b + // for multiple invocations + assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListViewModelCopy) } } } @@ -311,27 +218,13 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModel = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - assertThat(promotedStoryListViewModel.equals(null)).isFalse() + // Verify the non-null property of equals(): for any non-null reference a, a != null + assertThat(promotedStoryListViewModel).isNotEqualTo(null) } } } @@ -342,53 +235,16 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModelOf2 = PromotedStoryListViewModel( + val promotedStoryListViewModelOf2 = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val promotedStoryListViewModelOf3 = PromotedStoryListViewModel( + val promotedStoryListViewModelOf3 = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory3 - ) - ) + listOf(promotedStory1, promotedStory2, promotedStory3) ) - assertThat(promotedStoryListViewModelOf2.equals(promotedStoryListViewModelOf3)).isFalse() + assertThat(promotedStoryListViewModelOf2).isNotEqualTo(promotedStoryListViewModelOf3) } } } @@ -399,48 +255,19 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModel = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - val copyPromotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListCopy = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) - assertThat(promotedStoryListViewModel.equals(copyPromotedStoryListViewModel)).isTrue() + assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListCopy) + // If a == b, then a.hashCode == b.hashCode assertThat(promotedStoryListViewModel.hashCode()) - .isEqualTo(copyPromotedStoryListViewModel.hashCode()) + .isEqualTo(promotedStoryListCopy.hashCode()) } } } @@ -451,24 +278,9 @@ class PromotedStoryListViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryListViewModel = PromotedStoryListViewModel( + val promotedStoryListViewModel = createPromotedStoryListViewModel( it, - listOf( - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ), - PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory2 - ) - ) + listOf(promotedStory1, promotedStory2) ) val firstHash = promotedStoryListViewModel.hashCode() diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt similarity index 99% rename from app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt rename to app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 0d69d67c7ab..66c0c3f5735 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -1,4 +1,4 @@ -package org.oppia.android.app.home +package org.oppia.android.app.home.promotedlist import android.app.Application import android.content.Context From c89b077c95361ced91a93d0dfcc060c90dcd30bc Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 17:32:17 -0800 Subject: [PATCH 152/248] Improve readability for WelcomeViewModel tests --- .../android/app/home/WelcomeViewModelTest.kt | 60 ++++++++++--------- .../PromotedStoryListViewModelTest.kt | 9 ++- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 1b6cb7ce4ea..7aa4745994d 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -1,5 +1,6 @@ package org.oppia.android.app.home +import android.app.Activity import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity @@ -118,7 +119,9 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning)).isTrue() + + // Verify the reflexive property of equals(): a == a. + assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1Morning) } } } @@ -140,10 +143,10 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - val isSymmetric = - welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning) && - copyWelcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Morning) - assertThat(isSymmetric).isTrue() + + // Verify the symmetric property of equals(): a == b iff b == a. + assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + assertThat(copyWelcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1Morning) } } } @@ -155,26 +158,26 @@ class WelcomeViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( + val welcomeViewModelProfile1MorningCopy1 = WelcomeViewModel( testFragment, morningClock, "Profile 1" ) - val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + val welcomeViewModelProfile1MorningCopy2 = WelcomeViewModel( testFragment, morningClock, "Profile 1" ) - val copy2WelcomeVieModelProfile1Morning = WelcomeViewModel( + val welcomeViewModelProfile1MorningCopy3 = WelcomeViewModel( testFragment, morningClock, "Profile 1" ) - val isTransitive = - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && - copy1WelcomeViewModelProfile1Morning.equals(copy2WelcomeVieModelProfile1Morning) && - copy2WelcomeVieModelProfile1Morning.equals(welcomeViewModelProfile1Morning) - assertThat(isTransitive).isTrue() + assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo(welcomeViewModelProfile1MorningCopy2) + assertThat(welcomeViewModelProfile1MorningCopy2).isEqualTo(welcomeViewModelProfile1MorningCopy3) + + // Verify the transitive property of equals(): if a == b & b == c, then a == c + assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo(welcomeViewModelProfile1MorningCopy3) } } } @@ -191,15 +194,16 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - val copy1WelcomeViewModelProfile1Morning = WelcomeViewModel( + val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( testFragment, morningClock, "Profile 1" ) - val isConsistent = - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) && - welcomeViewModelProfile1Morning.equals(copy1WelcomeViewModelProfile1Morning) - assertThat(isConsistent).isTrue() + assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + + // Verify the consistent property of equals(): if neither object is modified, then a == b + // for multiple invocations + assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) } } } @@ -216,7 +220,9 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - assertThat(welcomeViewModelProfile1Morning.equals(null)).isFalse() + + // Verify the non-null property of equals(): for any non-null reference a, a != null + assertThat(welcomeViewModelProfile1Morning).isNotEqualTo(null) } } } @@ -238,8 +244,8 @@ class WelcomeViewModelTest { morningClock, "Profile 2" ) - assertThat(welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile2Morning)) - .isFalse() + + assertThat(welcomeViewModelProfile1Morning).isNotEqualTo(welcomeViewModelProfile2Morning) } } } @@ -249,7 +255,6 @@ class WelcomeViewModelTest { launch( createHomeFragmentTestActivity(context) ).use { - it.onActivity { setUpDifferentClockTimes() setUpTestFragment(it) @@ -263,8 +268,8 @@ class WelcomeViewModelTest { eveningClock, "Profile 1" ) - val equal = welcomeViewModelProfile1Morning.equals(welcomeViewModelProfile1Evening) - assertThat(equal).isFalse() + + assertThat(welcomeViewModelProfile1Morning).isNotEqualTo(welcomeViewModelProfile1Evening) } } } @@ -286,9 +291,9 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - assertThat(welcomeViewModelProfile1Morning.equals(copyWelcomeViewModelProfile1Morning)) - .isTrue() + assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + // If a == b, then a.hashCode == b.hashCode assertThat(welcomeViewModelProfile1Morning.hashCode()) .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) } @@ -307,9 +312,10 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) + + // Verify that hashCode consistently returns the same value. val firstHash = welcomeViewModelProfile1Morning.hashCode() val secondHash = welcomeViewModelProfile1Morning.hashCode() - assertThat(firstHash).isEqualTo(secondHash) } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index bcef1d3198c..6373f6904eb 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -148,16 +148,14 @@ class PromotedStoryListViewModelTest { it, listOf(promotedStory1, promotedStory2) ) - val promotedStoryListViewModelCopy = createPromotedStoryListViewModel( + val copyPromotedStoryListViewModel = createPromotedStoryListViewModel( it, listOf(promotedStory1, promotedStory2) ) - val originalEqualsCopy = promotedStoryListViewModel == promotedStoryListViewModelCopy - val copyEqualsOriginal = promotedStoryListViewModelCopy == promotedStoryListViewModel // Verify the symmetric property of equals(): a == b iff b == a. - assertThat(originalEqualsCopy).isTrue() - assertThat(copyEqualsOriginal).isTrue() + assertThat(promotedStoryListViewModel).isEqualTo(copyPromotedStoryListViewModel) + assertThat(copyPromotedStoryListViewModel).isEqualTo(promotedStoryListViewModel) } } } @@ -283,6 +281,7 @@ class PromotedStoryListViewModelTest { listOf(promotedStory1, promotedStory2) ) + // Verify that hashCode consistently returns the same value. val firstHash = promotedStoryListViewModel.hashCode() val secondHash = promotedStoryListViewModel.hashCode() assertThat(firstHash).isEqualTo(secondHash) From b2c6bcf77a441653bc8c6d8a506bc42701386553 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 17:56:01 -0800 Subject: [PATCH 153/248] Simplilfy promtoed story view model and welcome view model tests --- .../android/app/home/WelcomeViewModelTest.kt | 74 +++---- .../PromotedStoryListViewModelTest.kt | 2 +- .../PromotedStoryViewModelTest.kt | 190 ++++++------------ 3 files changed, 83 insertions(+), 183 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 7aa4745994d..8bb7707887d 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -107,18 +107,22 @@ class WelcomeViewModelTest { eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) } + private fun createBasicWelcomeViewModel(fragment: Fragment): WelcomeViewModel { + return WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + } + @Test - fun testWelcomeViewModelEquals_reflexiveProfile1MorningAndProfile1Morning_isTrue() { + fun testWelcomeViewModelEquals_reflexiveBasicWelcomeViewModel_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) + val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) // Verify the reflexive property of equals(): a == a. assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1Morning) @@ -127,22 +131,14 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_symmetricProfile1MorningAndDifferentProfile1Morning_isTrue() { + fun testWelcomeViewModelEquals_symmetricBasicWelcomeViewModels_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) - val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) + val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) + val copyWelcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) // Verify the symmetric property of equals(): a == b iff b == a. assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) @@ -152,27 +148,15 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_transitiveProfile1MorningAndTwoDifferentProfile1Morning_isTrue() { + fun testWelcomeViewModelEquals_transitiveBasicWelcomeViewModels_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1MorningCopy1 = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) - val welcomeViewModelProfile1MorningCopy2 = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) - val welcomeViewModelProfile1MorningCopy3 = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) + val welcomeViewModelProfile1MorningCopy1 = createBasicWelcomeViewModel(testFragment) + val welcomeViewModelProfile1MorningCopy2 = createBasicWelcomeViewModel(testFragment) + val welcomeViewModelProfile1MorningCopy3 = createBasicWelcomeViewModel(testFragment) assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo(welcomeViewModelProfile1MorningCopy2) assertThat(welcomeViewModelProfile1MorningCopy2).isEqualTo(welcomeViewModelProfile1MorningCopy3) @@ -183,22 +167,14 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_consistentProfile1MorningAndDifferentProfile1Morning_isTrue() { + fun testWelcomeViewModelEquals_consistentBasicWelcomeViewModels_isTrue() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) - val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) + val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) + val copyWelcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) // Verify the consistent property of equals(): if neither object is modified, then a == b @@ -209,17 +185,13 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_profile1MorningAndNull_isFalse() { + fun testWelcomeViewModelEquals_basicWelcomeViewModelAndNull_isFalse() { launch( createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val welcomeViewModelProfile1Morning = WelcomeViewModel( - testFragment, - morningClock, - "Profile 1" - ) + val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) // Verify the non-null property of equals(): for any non-null reference a, a != null assertThat(welcomeViewModelProfile1Morning).isNotEqualTo(null) @@ -293,7 +265,7 @@ class WelcomeViewModelTest { ) assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) - // If a == b, then a.hashCode == b.hashCode + // Verify that if a == b, then a.hashCode == b.hashCode assertThat(welcomeViewModelProfile1Morning.hashCode()) .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 6373f6904eb..9696b4978de 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -263,7 +263,7 @@ class PromotedStoryListViewModelTest { ) assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListCopy) - // If a == b, then a.hashCode == b.hashCode + // Verify that if a == b, then a.hashCode == b.hashCode assertThat(promotedStoryListViewModel.hashCode()) .isEqualTo(promotedStoryListCopy.hashCode()) } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 66c0c3f5735..1aca394a8de 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -80,12 +80,6 @@ class PromotedStoryViewModelTest { .setTopicName("topic_name") .setTotalChapterCount(1) .build() - private val promotedStory3 = PromotedStory.newBuilder() - .setStoryId("id_3") - .setStoryName("Story 3") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() @Before fun setUp() { @@ -96,138 +90,92 @@ class PromotedStoryViewModelTest { ApplicationProvider.getApplicationContext().inject(this) } + private fun createBasicPromotedStoryViewModel( + activity: AppCompatActivity + ): PromotedStoryViewModel { + return PromotedStoryViewModel( + activity = activity, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 + ) + } + @Test - fun testPromotedStoryViewModelEquals_reflexiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + fun testPromotedStoryViewModelEquals_reflexiveBasicPromotedStoryViewModel_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) - val isReflexive = promotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isReflexive).isTrue() + // Verify the reflexive property of equals(): a == a. + assertThat(promotedStoryViewModel).isEqualTo(promotedStoryViewModel) } } } @Test - fun testPromotedStoryViewModelEquals_symmetricProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + fun testPromotedStoryViewModelEquals_symmetricBasicPromotedStoryViewModels_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - PromotedStory.newBuilder() - .setStoryId("id_1") - .setStoryName("Story 1") - .setTopicName("topic_name") - .setTotalChapterCount(1) - .build() - ) + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) + val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) - val isSymmetric = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && - copyPromotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isSymmetric).isTrue() + // Verify the symmetric property of equals(): a == b iff b == a. + assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) + assertThat(copyPromotedStoryViewModel).isEqualTo(promotedStoryViewModel) } } } @Test - fun testPromotedStoryViewModelEquals_transitiveProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + fun testPromotedStoryViewModelEquals_transitiveBasicPromotedStoryViewModels_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copy1PromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copy2PromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - - val isTransitive = promotedStoryViewModel.equals(copy1PromotedStoryViewModel) && - copy1PromotedStoryViewModel.equals(copy2PromotedStoryViewModel) && - copy2PromotedStoryViewModel.equals(promotedStoryViewModel) - assertThat(isTransitive).isTrue() + val promotedStoryViewModelCopy1 = createBasicPromotedStoryViewModel(it) + val promotedStoryViewModelCopy2 = createBasicPromotedStoryViewModel(it) + val promotedStoryViewModelCopy3 = createBasicPromotedStoryViewModel(it) + assertThat(promotedStoryViewModelCopy1).isEqualTo(promotedStoryViewModelCopy2) + assertThat(promotedStoryViewModelCopy2).isEqualTo(promotedStoryViewModelCopy3) + + // Verify the transitive property of equals(): if a == b & b == c, then a == c + assertThat(promotedStoryViewModelCopy1).isEqualTo(promotedStoryViewModelCopy3) } } } @Test - fun testPromotedStoryViewModelEquals_consistentProfile1StoryCount3EntityTypeEmptyStory1_isTrue() { + fun testPromotedStoryViewModelEquals_consistentBasicPromotedStoryViewModels_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) + val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) + assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) - val isConsistent = promotedStoryViewModel.equals(copyPromotedStoryViewModel) && - promotedStoryViewModel.equals(copyPromotedStoryViewModel) - assertThat(isConsistent).isTrue() + // Verify the consistent property of equals(): if neither object is modified, then a == b + // for multiple invocations + assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) } } } @Test - fun testPromotedStoryViewModelEquals_profile1StoryCount3EntityTypeEmptyStory1AndNull_isFalse() { + fun testPromotedStoryViewModelEquals_basicPromotedStoryViewModelAndNull_isFalse() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) - assertThat(promotedStoryViewModel.equals(null)).isFalse() + assertThat(promotedStoryViewModel).isNotEqualTo(null) } } } @@ -242,19 +190,18 @@ class PromotedStoryViewModelTest { /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"", + /* entytType = */"entity", promotedStory1 ) val promotedStoryViewModelProfile2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */2, /* totalStoryCount = */3, - /* entytType = */"", + /* entytType = */"entity", promotedStory1 ) - assertThat(promotedStoryViewModelProfile1.equals(promotedStoryViewModelProfile2)) - .isFalse() + assertThat(promotedStoryViewModelProfile1).isNotEqualTo(promotedStoryViewModelProfile2) } } } @@ -269,19 +216,18 @@ class PromotedStoryViewModelTest { /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */2, - /* entytType = */"", + /* entytType = */"entity", promotedStory1 ) val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"", + /* entytType = */"entity", promotedStory1 ) - assertThat(promotedStoryViewModelStoryCount2.equals(promotedStoryViewModelStoryCount3)) - .isFalse() + assertThat(promotedStoryViewModelStoryCount2).isNotEqualTo(promotedStoryViewModelStoryCount3) } } } @@ -296,19 +242,18 @@ class PromotedStoryViewModelTest { /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"Entity 1", + /* entytType = */"entity_1", promotedStory1 ) val promotedStoryViewModelEntity2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"Entity 2", + /* entytType = */"entity_2", promotedStory1 ) - assertThat(promotedStoryViewModelEntity1.equals(promotedStoryViewModelEntity2)) - .isFalse() + assertThat(promotedStoryViewModelEntity1).isNotEqualTo(promotedStoryViewModelEntity2) } } } @@ -325,19 +270,18 @@ class PromotedStoryViewModelTest { /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"Entity 1", + /* entytType = */"entity_1", promotedStory1 ) val promotedStoryViewModelStory2 = PromotedStoryViewModel( /* activity = */ it, /* internalProfileId = */1, /* totalStoryCount = */3, - /* entytType = */"Entity 2", + /* entytType = */"entity_2", promotedStory2 ) - assertThat(promotedStoryViewModelStory1.equals(promotedStoryViewModelStory2)) - .isFalse() + assertThat(promotedStoryViewModelStory1).isNotEqualTo(promotedStoryViewModelStory2) } } } @@ -348,22 +292,11 @@ class PromotedStoryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - val copyPromotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) - assertThat(promotedStoryViewModel.equals(copyPromotedStoryViewModel)).isTrue() + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) + val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) + assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) + // Verify that if a == b, then a.hashCode == b.hashCode assertThat(promotedStoryViewModel.hashCode()) .isEqualTo(copyPromotedStoryViewModel.hashCode()) } @@ -376,16 +309,11 @@ class PromotedStoryViewModelTest { HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { - val promotedStoryViewModel = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"", - promotedStory1 - ) + val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) val firstHash = promotedStoryViewModel.hashCode() val secondHash = promotedStoryViewModel.hashCode() + // Verify that hashCode consistently returns the same value. assertThat(firstHash).isEqualTo(secondHash) } } From 3bc2364e4e84514c040c87340e0db4f53e4ea5ec Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 18:05:39 -0800 Subject: [PATCH 154/248] Simplify topic summary and promtoed story view models --- .../app/home/TopicSummaryViewModelTest.kt | 169 ++++++------------ .../android/app/home/WelcomeViewModelTest.kt | 13 +- .../PromotedStoryListViewModelTest.kt | 6 +- .../PromotedStoryViewModelTest.kt | 11 +- 4 files changed, 72 insertions(+), 127 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index 5c1084fd85f..898127bf062 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -97,136 +97,96 @@ class TopicSummaryViewModelTest { .commitNow() } + private fun createBasicTopicSummaryViewModel(activity: AppCompatActivity): TopicSummaryViewModel { + return TopicSummaryViewModel( + activity = activity, + topicSummary = topicSummary1, + entityType = "entity", + topicSummaryClickListener = testFragment, + position = 5 + ) + } + @Test - fun testTopicSummaryViewModelEquals_reflexiveTopicSummary1Entity1Position5_isTrue() { + fun testTopicSummaryViewModelEquals_reflexiveBasicTopicSummaryViewModel_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - assertThat(topicSummaryViewModel.equals(topicSummaryViewModel)).isTrue() + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) + + // Verify the reflexive property of equals(): a == a. + assertThat(topicSummaryViewModel).isEqualTo(topicSummaryViewModel) } } } @Test - fun testTopicSummaryViewModelEquals_symmetricTopicSummary1Entity1Position5_isTrue() { + fun testTopicSummaryViewModelEquals_symmetricBasicTopicSummaryViewModel_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) + val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) - val isSymmetric = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && - copyTopicSummaryViewModel.equals(topicSummaryViewModel) - assertThat(isSymmetric).isTrue() + // Verify the symmetric property of equals(): a == b iff b == a. + assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) + assertThat(copyTopicSummaryViewModel).isEqualTo(topicSummaryViewModel) } } } @Test - fun testTopicSummaryViewModelEquals_transitiveTopicSummary1Entity1Position5_isTrue() { + fun testTopicSummaryViewModelEquals_transitiveBasicSummaryViewModel_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - val copy1TopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - val copy2TopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - - val isTransitive = topicSummaryViewModel.equals(copy1TopicSummaryViewModel) && - copy1TopicSummaryViewModel.equals(copy2TopicSummaryViewModel) && - copy2TopicSummaryViewModel.equals(topicSummaryViewModel) - assertThat(isTransitive).isTrue() + val topicSummaryViewModelCopy1 = createBasicTopicSummaryViewModel(it) + val topicSummaryViewModelCopy2 = createBasicTopicSummaryViewModel(it) + val topicSummaryViewModelCopy3 = createBasicTopicSummaryViewModel(it) + assertThat(topicSummaryViewModelCopy1).isEqualTo(topicSummaryViewModelCopy2) + assertThat(topicSummaryViewModelCopy2).isEqualTo(topicSummaryViewModelCopy3) + + // Verify the transitive property of equals(): if a == b & b == c, then a == c + assertThat(topicSummaryViewModelCopy1).isEqualTo(topicSummaryViewModelCopy3) } } } @Test - fun testTopicSummaryViewModelEquals_consistentTopicSummary1Entity1Position5_isTrue() { + fun testTopicSummaryViewModelEquals_consistentBasicTopicSummaryViewModel_isTrue() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) + val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) + assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) - val isConsistent = topicSummaryViewModel.equals(copyTopicSummaryViewModel) && - topicSummaryViewModel.equals(copyTopicSummaryViewModel) - assertThat(isConsistent).isTrue() + // Verify the consistent property of equals(): if neither object is modified, then a == b + // for multiple invocations + assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) } } } @Test - fun testTopicSummaryViewModelEquals_topicSummary1Entity1Position5AndNull_isFalse() { + fun testTopicSummaryViewModelEquals_basicTopicSummaryViewModelAndNull_isFalse() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) - assertThat(topicSummaryViewModel.equals(null)).isFalse() + // Verify the non-null property of equals(): for any non-null reference a, a != null + assertThat(topicSummaryViewModel).isNotEqualTo(null) } } } @@ -253,7 +213,7 @@ class TopicSummaryViewModelTest { /* position = */ 5 ) - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + assertThat(topicSummaryViewModel1).isNotEqualTo(topicSummaryViewModel2) } } } @@ -265,14 +225,14 @@ class TopicSummaryViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( + val topicSummaryViewModelEntity1 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", /* topicSummaryCLickListener = */ testFragment, /* position = */ 5 ) - val topicSummaryViewModel2 = TopicSummaryViewModel( + val topicSummaryViewModelEntity2 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_2", @@ -280,7 +240,7 @@ class TopicSummaryViewModelTest { /* position = */ 5 ) - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + assertThat(topicSummaryViewModelEntity1).isNotEqualTo(topicSummaryViewModelEntity2) } } } @@ -292,14 +252,14 @@ class TopicSummaryViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( + val topicSummaryViewModelPosition4 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", /* topicSummaryCLickListener = */ testFragment, /* position = */ 4 ) - val topicSummaryViewModel2 = TopicSummaryViewModel( + val topicSummaryViewModelPosition5 = TopicSummaryViewModel( /* activity = */ it, topicSummary1, /* entityType = */ "entity_1", @@ -307,7 +267,7 @@ class TopicSummaryViewModelTest { /* position = */ 5 ) - assertThat(topicSummaryViewModel1.equals(topicSummaryViewModel2)).isFalse() + assertThat(topicSummaryViewModelPosition4).isNotEqualTo(topicSummaryViewModelPosition5) } } } @@ -319,24 +279,12 @@ class TopicSummaryViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - val copyTopicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) - assertThat(topicSummaryViewModel.equals(copyTopicSummaryViewModel)).isTrue() + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) + val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) + assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) - assertThat(topicSummaryViewModel.hashCode()) - .isEqualTo(copyTopicSummaryViewModel.hashCode()) + // Verify that if a == b, then a.hashCode == b.hashCode + assertThat(topicSummaryViewModel.hashCode()).isEqualTo(copyTopicSummaryViewModel.hashCode()) } } } @@ -348,16 +296,11 @@ class TopicSummaryViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 - ) + val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) + + // Verify that hashCode consistently returns the same value. val firstHash = topicSummaryViewModel.hashCode() val secondHash = topicSummaryViewModel.hashCode() - assertThat(firstHash).isEqualTo(secondHash) } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 8bb7707887d..b900654eb09 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -1,6 +1,5 @@ package org.oppia.android.app.home -import android.app.Activity import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity @@ -157,11 +156,17 @@ class WelcomeViewModelTest { val welcomeViewModelProfile1MorningCopy1 = createBasicWelcomeViewModel(testFragment) val welcomeViewModelProfile1MorningCopy2 = createBasicWelcomeViewModel(testFragment) val welcomeViewModelProfile1MorningCopy3 = createBasicWelcomeViewModel(testFragment) - assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo(welcomeViewModelProfile1MorningCopy2) - assertThat(welcomeViewModelProfile1MorningCopy2).isEqualTo(welcomeViewModelProfile1MorningCopy3) + assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo( + welcomeViewModelProfile1MorningCopy2 + ) + assertThat(welcomeViewModelProfile1MorningCopy2).isEqualTo( + welcomeViewModelProfile1MorningCopy3 + ) // Verify the transitive property of equals(): if a == b & b == c, then a == c - assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo(welcomeViewModelProfile1MorningCopy3) + assertThat(welcomeViewModelProfile1MorningCopy1).isEqualTo( + welcomeViewModelProfile1MorningCopy3 + ) } } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 9696b4978de..75a7205a122 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -1,6 +1,5 @@ package org.oppia.android.app.home.promotedlist -import android.app.Activity import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity @@ -19,8 +18,6 @@ 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.home.promotedlist.PromotedStoryListViewModel -import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.shim.IntentFactoryShimModule @@ -108,7 +105,8 @@ class PromotedStoryListViewModelTest { internalProfileId = 1, totalStoryCount = promotedStoryList.size, entityType = "entity", - promotedStory = it) + promotedStory = it + ) } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 1aca394a8de..f9f0ef34d85 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -18,7 +18,6 @@ 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.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.player.state.hintsandsolution.HintsAndSolutionConfigModule import org.oppia.android.app.shim.IntentFactoryShimModule @@ -93,11 +92,11 @@ class PromotedStoryViewModelTest { private fun createBasicPromotedStoryViewModel( activity: AppCompatActivity ): PromotedStoryViewModel { - return PromotedStoryViewModel( - activity = activity, - internalProfileId = 1, - totalStoryCount = 3, - entityType = "entity", + return PromotedStoryViewModel( + activity = activity, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", promotedStory = promotedStory1 ) } From a15141c570c486dd7ed2570c37ea0d6f57d65446 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Fri, 8 Jan 2021 18:10:17 -0800 Subject: [PATCH 155/248] Clarify test names --- .../app/home/TopicSummaryViewModelTest.kt | 20 +++++++-------- .../android/app/home/WelcomeViewModelTest.kt | 18 ++++++------- .../PromotedStoryListViewModelTest.kt | 16 ++++++------ .../PromotedStoryViewModelTest.kt | 25 ++++++++++--------- 4 files changed, 40 insertions(+), 39 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index 898127bf062..277ae854e6a 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -108,7 +108,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_reflexiveBasicTopicSummaryViewModel_isTrue() { + fun testTopicSummaryViewModelEquals_reflexiveBasicTopicSummaryViewModel_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -123,7 +123,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_symmetricBasicTopicSummaryViewModel_isTrue() { + fun testTopicSummaryViewModelEquals_symmetricBasicTopicSummaryViewModel_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -140,7 +140,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_transitiveBasicSummaryViewModel_isTrue() { + fun testTopicSummaryViewModelEquals_transitiveBasicSummaryViewModel_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -159,7 +159,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_consistentBasicTopicSummaryViewModel_isTrue() { + fun testTopicSummaryViewModelEquals_consistentBasicTopicSummaryViewModel_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -177,7 +177,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_basicTopicSummaryViewModelAndNull_isFalse() { + fun testTopicSummaryViewModelEquals_basicTopicSummaryViewModelAndNull_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -192,7 +192,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isFalse() { + fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -219,7 +219,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_entity1AndEntity2_isFalse() { + fun testTopicSummaryViewModelEquals_entity1AndEntity2_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -246,7 +246,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelEquals_position4AndPosition5_isFalse() { + fun testTopicSummaryViewModelEquals_position4AndPosition5_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -273,7 +273,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -290,7 +290,7 @@ class TopicSummaryViewModelTest { } @Test - fun testTopicSummaryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + fun testTopicSummaryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index b900654eb09..73f30daf729 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -115,7 +115,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_reflexiveBasicWelcomeViewModel_isTrue() { + fun testWelcomeViewModelEquals_reflexiveBasicWelcomeViewModel_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -130,7 +130,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_symmetricBasicWelcomeViewModels_isTrue() { + fun testWelcomeViewModelEquals_symmetricBasicWelcomeViewModels_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -147,7 +147,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_transitiveBasicWelcomeViewModels_isTrue() { + fun testWelcomeViewModelEquals_transitiveBasicWelcomeViewModels_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -172,7 +172,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_consistentBasicWelcomeViewModels_isTrue() { + fun testWelcomeViewModelEquals_consistentBasicWelcomeViewModels_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -190,7 +190,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_basicWelcomeViewModelAndNull_isFalse() { + fun testWelcomeViewModelEquals_basicWelcomeViewModelAndNull_isNotEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -205,7 +205,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_profile1MorningAndProfile2Morning_isFalse() { + fun testWelcomeViewModelEquals_profile1MorningAndProfile2Morning_isNotEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -228,7 +228,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelEquals_profile1MorningAndProfile1Evening_isFalse() { + fun testWelcomeViewModelEquals_profile1MorningAndProfile1Evening_isNotEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -252,7 +252,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + fun testWelcomeViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { @@ -278,7 +278,7 @@ class WelcomeViewModelTest { } @Test - fun testWelcomeViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + fun testWelcomeViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { launch( createHomeFragmentTestActivity(context) ).use { diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 75a7205a122..9fd833b7f05 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -121,7 +121,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isTrue() { + fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -137,7 +137,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isTrue() { + fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -159,7 +159,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isTrue() { + fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -186,7 +186,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isTrue() { + fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -209,7 +209,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isFalse() { + fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -226,7 +226,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isFalse() { + fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -246,7 +246,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -269,7 +269,7 @@ class PromotedStoryListViewModelTest { } @Test - fun testPromotedStoryListViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + fun testPromotedStoryListViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index f9f0ef34d85..6f6486d732f 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -102,7 +102,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_reflexiveBasicPromotedStoryViewModel_isTrue() { + fun testPromotedStoryViewModelEquals_reflexiveBasicPromotedStoryViewModel_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -116,7 +116,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_symmetricBasicPromotedStoryViewModels_isTrue() { + fun testPromotedStoryViewModelEquals_symmetricBasicPromotedStoryViewModels_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -132,7 +132,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_transitiveBasicPromotedStoryViewModels_isTrue() { + fun testPromotedStoryViewModelEquals_transitiveBasicPromotedStoryViewModels_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -150,7 +150,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_consistentBasicPromotedStoryViewModels_isTrue() { + fun testPromotedStoryViewModelEquals_consistentBasicPromotedStoryViewModels_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -167,7 +167,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_basicPromotedStoryViewModelAndNull_isFalse() { + fun testPromotedStoryViewModelEquals_basicPromotedStoryViewModelAndNull_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -180,7 +180,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isFalse() { + fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -206,7 +206,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isFalse() { + fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -226,13 +226,14 @@ class PromotedStoryViewModelTest { promotedStory1 ) - assertThat(promotedStoryViewModelStoryCount2).isNotEqualTo(promotedStoryViewModelStoryCount3) + assertThat(promotedStoryViewModelStoryCount2) + .isNotEqualTo(promotedStoryViewModelStoryCount3) } } } @Test - fun testPromotedStoryViewModelEquals_entity1AndEntity2_isFalse() { + fun testPromotedStoryViewModelEquals_entity1AndEntity2_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -258,7 +259,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelEquals_story1AndStory2_isFalse() { + fun testPromotedStoryViewModelEquals_story1AndStory2_isNotEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -286,7 +287,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isTrue() { + fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { @@ -303,7 +304,7 @@ class PromotedStoryViewModelTest { } @Test - fun testPromotedStoryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isTrue() { + fun testPromotedStoryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { ActivityScenario.launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { From ef1bc504466ef5f21d6c1a91633f77d37e7c5901 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 9 Jan 2021 14:26:53 +0530 Subject: [PATCH 156/248] Update TopicController.kt --- .../org/oppia/android/domain/topic/TopicController.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt index 5cff912eb01..9161578a77d 100755 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt @@ -248,11 +248,6 @@ class TopicController @Inject constructor( ) } - // If there is no completed chapter, it cannot be an ongoing-topic. - if (completedChapterProgressList.isEmpty()) { - return false - } - // If there is at least 1 completed chapter and 1 not-completed chapter, it is definitely an // ongoing-topic. if (startedChapterProgressList.isNotEmpty()) { @@ -274,6 +269,11 @@ class TopicController @Inject constructor( } } } + + // If there is no completed chapter, it cannot be an ongoing-topic. + if (completedChapterProgressList.isEmpty()) { + return false + } return false } From 5034a625a63ecc7ccda138cc40aee445336c3a66 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 9 Jan 2021 17:01:47 +0530 Subject: [PATCH 157/248] Fixed nit. --- .../domain/topic/StoryProgressController.kt | 20 +++- .../domain/topic/StoryProgressTestHelper.kt | 68 ++++------- .../domain/topic/TopicListController.kt | 111 +++++++++--------- .../topic/StoryProgressTestHelperTest.kt | 2 +- .../domain/topic/TopicListControllerTest.kt | 10 +- 5 files changed, 103 insertions(+), 108 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 091740c684d..d93c3b89e19 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -112,10 +112,10 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() + val topicProgressBuilder = TopicProgress.newBuilder() .setTopicId(topicId) - .setLastPlayedTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -123,6 +123,15 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() + val topicProgressStories = topicProgressBuilder.storyProgressMap.values + val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } + val topicProgressLastPlayedTimes = + topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) + val lastPlayedTimestamp = + topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. + if (lastPlayedTimestamp != null) { + topicProgressBuilder.lastPlayedTimestamp = lastPlayedTimestamp + } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) @@ -205,6 +214,15 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() + val topicProgressStories = topicProgressBuilder.storyProgressMap.values + val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } + val topicProgressLastPlayedTimes = + topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) + val computedLastPlayedTimestamp = + topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. + if (computedLastPlayedTimestamp != null) { + topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp + } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 154a7c2e238..46d6ee0be6d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -25,7 +25,7 @@ class StoryProgressTestHelper @Inject constructor( * * @param profileId The profile we are setting partial progress of the fraction story for. * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more - * than one week ago. + * than one week ago. */ fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { @@ -47,7 +47,7 @@ class StoryProgressTestHelper @Inject constructor( * * @param profileId The profile we are setting partial progress of the fraction topic for. * @param timestampOlderThanOneWeek If the timestamp for this topic progress is more than - * one week ago. + * one week ago. */ fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { @@ -137,7 +137,8 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on Test Topics for a particular profile. * * @param profileId The profile we are setting topic progress for. - * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than + * one week ago. */ fun markFullTopicProgressForTestTopic(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { val timestamp = if (!timestampOlderThanOneWeek) { @@ -145,8 +146,9 @@ class StoryProgressTestHelper @Inject constructor( } else { getOldTimestamp() } - // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure - // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. + // Stories and Explorations for "Test Topic"s are not in chronological order so we want to + // ensure that the combinations of Topic / Story / Exploration that are visible will be marked + // as completed. storyProgressController.recordCompletedChapter( profileId, TEST_TOPIC_ID_0, @@ -233,15 +235,19 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** Marks full story progress for a particular profile. */ - fun markFullProgressForSecondTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + /** + * Marks full topic progress on SecondTestTopic for a particular profile. + * + * @param profileId The profile we are setting topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than + * one week ago. + */ + fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() } - // Stories and Explorations for "Test Topic"s are not in chronological order so we want to ensure - // that the combinations of Topic / Story / Exploration that are visible will be marked as completed. storyProgressController.recordCompletedChapter( profileId, TEST_TOPIC_ID_1, @@ -252,10 +258,11 @@ class StoryProgressTestHelper @Inject constructor( } /** - * Marks one story progress full in ratios exploration for a particular profile. + * Marks one story progress fully complete in the ratios topic for a particular profile. * * @param profileId The profile we are setting topic progress on ratios for. - * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. + * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week + * ago. */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, @@ -282,43 +289,12 @@ class StoryProgressTestHelper @Inject constructor( ) } - /** - * Marks one story progress full in ratios exploration for a particular profile. - * - * @param profileId The profile we are setting topic progress on ratios for. - * @param timestampOlderThanOneWeek If the timestamp for this progress is from more than one week ago. - */ - fun markLastChapterDoneOfFirstStoryTopicProgressForRatios( - profileId: ProfileId, - timestampOlderThanAWeek: Boolean - ) { - val timestamp = if (!timestampOlderThanAWeek) { - getCurrentTimestamp() - } else { - getOldTimestamp() - } - storyProgressController.recordCompletedChapter( - profileId, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_1, - timestamp - ) - storyProgressController.recordCompletedChapter( - profileId, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_0, - timestamp - ) - } - /** * Marks two partial story progress in ratios exploration for a particular profile. * * @param profileId The profile we are setting topic progress on ratios for. - * @param timestampOlderThanOneWeek If the timestamp for the progress on the two stories is from more than one week - * ago. + * @param timestampOlderThanOneWeek If the timestamp for the progress on the two stories is from + * more than one week ago. */ fun markTwoPartialStoryProgressForRatios(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { @@ -394,8 +370,8 @@ class StoryProgressTestHelper @Inject constructor( * Marks first exploration in both stories of Ratios as recently played for a particular profile. * * @param profileId The profile we are setting recently played for. - * @param timestampOlderThanOneWeek If the timestamp for the recently played story and explorations is more than - * a week ago. + * @param timestampOlderThanOneWeek If the timestamp for the recently played story and + * explorations is more than a week ago. */ fun markRecentlyPlayedForRatiosStory0Exploration0AndStory1Exploration2( profileId: ProfileId, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index b9d46d23311..b0503c3be43 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -83,6 +83,8 @@ val EXPLORATION_THUMBNAILS = mapOf( private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = "get_ongoing_story_list_provider_id" +private const val GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID = + "get_recommended_actvity_list_provider_id" private val EVICTION_TIME_MILLIS = TimeUnit.DAYS.toMillis(1) @@ -134,7 +136,7 @@ class TopicListController @Inject constructor( */ fun getRecommendedActivityList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) - .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { + .transformAsync(GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID) { val recommendedActivityList = createRecommendedActivityList(it) AsyncResult.success(recommendedActivityList) } @@ -230,7 +232,6 @@ class TopicListController @Inject constructor( return upcomingTopic.setTopicId(topicId) .setName(jsonObject.getString("topic_name")) .setVersion(jsonObject.optInt("version")) - .setEstimatedReleaseUnixTimestamp(oppiaClock.getCurrentCalendar().timeInMillis) .setTopicPlayAvailability(topicPlayAvailability) .setLessonThumbnail(createTopicThumbnail(jsonObject)) .build() @@ -250,7 +251,7 @@ class TopicListController @Inject constructor( val story = topicController.retrieveStory(topic.topicId, storyId) val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) - val lastCompletedChapterProgress: ChapterProgress? = + val mostRecentCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() val startedChapterProgressList = getStartedChapterProgressList(storyProgress) @@ -268,13 +269,13 @@ class TopicListController @Inject constructor( ongoingStoryListBuilder ) } - lastCompletedChapterProgress != null && - lastCompletedChapterProgress.explorationId != + mostRecentCompletedChapterProgress != null && + mostRecentCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { createOngoingStoryListBasedOnLastCompleted( storyId, story, - lastCompletedChapterProgress, + mostRecentCompletedChapterProgress, completedChapterProgressList, topic, ongoingStoryListBuilder @@ -287,34 +288,50 @@ class TopicListController @Inject constructor( return ongoingStoryListBuilder.build() } - private fun createOngoingStoryListBasedOnLastCompleted( + private fun getStartedChapterProgressList(storyProgress: StoryProgress): List { + return storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + } + + private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List { + return storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + } + + private fun createOngoingStoryListBasedOnRecentlyPlayed( storyId: String, story: StorySummary, - lastCompletedChapterProgress: ChapterProgress, + recentlyPlayerChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, ongoingStoryListBuilder: OngoingStoryList.Builder ) { - val lastChapterSummary: ChapterSummary? = + val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { + if (recentlyPlayerChapterSummary != null) { val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - - lastCompletedChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + recentlyPlayerChapterProgress.lastPlayedTimestamp + ) / TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong()) val promotedStory = createPromotedStory( storyId, topic, completedChapterProgressList.size, story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { ongoingStoryListBuilder.addRecentStory(promotedStory) } else { ongoingStoryListBuilder.addOlderStory(promotedStory) @@ -322,32 +339,34 @@ class TopicListController @Inject constructor( } } - private fun createOngoingStoryListBasedOnRecentlyPlayed( + private fun createOngoingStoryListBasedOnLastCompleted( storyId: String, story: StorySummary, - recentlyPlayerChapterProgress: ChapterProgress, + mostRecentCompletedChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, ongoingStoryListBuilder: OngoingStoryList.Builder ) { - val recentlyPlayerChapterSummary: ChapterSummary? = + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId } - if (recentlyPlayerChapterSummary != null) { + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + mostRecentCompletedChapterProgress.lastPlayedTimestamp + ) / TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong()) val promotedStory = createPromotedStory( storyId, topic, completedChapterProgressList.size, story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId + nextChapterSummary.name, + nextChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { ongoingStoryListBuilder.addRecentStory(promotedStory) } else { ongoingStoryListBuilder.addOlderStory(promotedStory) @@ -355,24 +374,6 @@ class TopicListController @Inject constructor( } } - private fun getStartedChapterProgressList(storyProgress: StoryProgress): List { - return storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - } - - private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List { - return storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - } - private fun createRecommendedActivityList( topicProgressList: List ): RecommendedActivityList { @@ -445,7 +446,7 @@ class TopicListController @Inject constructor( val story = topicController.retrieveStory(topic.topicId, storyId) val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) - val lastCompletedChapterProgress: ChapterProgress? = + val mostRecentCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() val startedChapterProgressList = getStartedChapterProgressList(storyProgress) @@ -463,7 +464,7 @@ class TopicListController @Inject constructor( val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + ) / (TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong())) val promotedStory = createPromotedStory( storyId, topic, @@ -472,27 +473,27 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { recommendedStoryBuilder.addOlderPlayedStory(promotedStory) } } } - lastCompletedChapterProgress != null -> { - if (lastCompletedChapterProgress.explorationId + mostRecentCompletedChapterProgress != null -> { + if (mostRecentCompletedChapterProgress.explorationId != story.chapterList.last().explorationId ) { val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - - lastCompletedChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + mostRecentCompletedChapterProgress.lastPlayedTimestamp + ) / (TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong())) val promotedStory = createPromotedStory( storyId, topic, @@ -501,7 +502,7 @@ class TopicListController @Inject constructor( nextChapterSummary.name, nextChapterSummary.explorationId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { recommendedStoryBuilder.addOlderPlayedStory(promotedStory) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 64b1a1896fe..a960e8db4a7 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -820,7 +820,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForSecondTopic_showRecommendedStories_listIsCorrect() { - storyProgressTestHelper.markFullProgressForSecondTopic( + storyProgressTestHelper.markFullProgressForSecondTestTopic( profileId, /* timestampOlderThanAWeek= */ false ) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 7a2c9a72610..f58321d2019 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -307,7 +307,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecommendedActivityList_markChapterCompletedFracStory0Exp0_recommendedStoryListIsCorrect() { // ktlint-disable max-line-length + fun testRetrieveRecommendedActivityList_markChapDoneFracStory0Exp1_storyListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -332,7 +332,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveSuggestedStoryList_markAllChaptersCompletedInFractions_suggestedStoryListIsCorrect() { // ktlint-disable max-line-length + fun testRetrieveSuggestedStoryList_markAllChapDoneInFractions_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -364,7 +364,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecentStoryList_markAllChaptersCompletedInFractions_fromRecommendedList_playedFirstTopicStory0Exploration0_recentStoryListIsCorrect() { // ktlint-disable max-line-length + fun testRetrieveRecentStoryList_markAllChapDoneInFractions_playedFirstTopicStory0Exploration0_recentStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -408,7 +408,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_fromRecommendedStories_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { // ktlint-disable max-line-length + fun testRetrieveRecentStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_playedRatioStory0Exp0_recentStoryListCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -491,7 +491,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) - .isEqualTo(3) + .isEqualTo(0) verifyOngoingStoryAsRatioStory0Exploration1( recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] ) From 8ec985006c903c0d48cf292914ca3d5b7ac2f8f8 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 9 Jan 2021 17:32:52 +0530 Subject: [PATCH 158/248] fixed issues --- .../domain/topic/StoryProgressController.kt | 38 +++++++++---------- .../domain/topic/TopicListController.kt | 16 ++++---- .../domain/topic/TopicListControllerTest.kt | 2 +- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index d93c3b89e19..a0a3da63bb0 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -115,7 +115,7 @@ class StoryProgressController @Inject constructor( val topicProgressBuilder = TopicProgress.newBuilder() - .setTopicId(topicId) + .setTopicId(topicId).setLastPlayedTimestamp(completionTimestamp) if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) @@ -123,15 +123,15 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() - val topicProgressStories = topicProgressBuilder.storyProgressMap.values - val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } - val topicProgressLastPlayedTimes = - topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) - val lastPlayedTimestamp = - topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. - if (lastPlayedTimestamp != null) { - topicProgressBuilder.lastPlayedTimestamp = lastPlayedTimestamp - } +// val topicProgressStories = topicProgressBuilder.storyProgressMap.values +// val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } +// val topicProgressLastPlayedTimes = +// topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) +// val lastPlayedTimestamp = +// topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. +// if (lastPlayedTimestamp != null) { +// topicProgressBuilder.lastPlayedTimestamp = lastPlayedTimestamp +// } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) @@ -214,15 +214,15 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() - val topicProgressStories = topicProgressBuilder.storyProgressMap.values - val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } - val topicProgressLastPlayedTimes = - topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) - val computedLastPlayedTimestamp = - topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. - if (computedLastPlayedTimestamp != null) { - topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp - } +// val topicProgressStories = topicProgressBuilder.storyProgressMap.values +// val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } +// val topicProgressLastPlayedTimes = +// topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) +// val computedLastPlayedTimestamp = +// topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. +// if (computedLastPlayedTimestamp != null) { +// topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp +// } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index b0503c3be43..3098540b3d2 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -322,7 +322,7 @@ class TopicListController @Inject constructor( val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong()) + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -331,7 +331,7 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId ) - if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { ongoingStoryListBuilder.addRecentStory(promotedStory) } else { ongoingStoryListBuilder.addOlderStory(promotedStory) @@ -357,7 +357,7 @@ class TopicListController @Inject constructor( val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - mostRecentCompletedChapterProgress.lastPlayedTimestamp - ) / TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong()) + ) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -366,7 +366,7 @@ class TopicListController @Inject constructor( nextChapterSummary.name, nextChapterSummary.explorationId ) - if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { ongoingStoryListBuilder.addRecentStory(promotedStory) } else { ongoingStoryListBuilder.addOlderStory(promotedStory) @@ -464,7 +464,7 @@ class TopicListController @Inject constructor( val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / (TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong())) + ) / (ONE_DAY_IN_MS) val promotedStory = createPromotedStory( storyId, topic, @@ -473,7 +473,7 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId ) - if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { recommendedStoryBuilder.addOlderPlayedStory(promotedStory) @@ -493,7 +493,7 @@ class TopicListController @Inject constructor( val numberOfDaysPassed = ( oppiaClock.getCurrentCalendar().timeInMillis - mostRecentCompletedChapterProgress.lastPlayedTimestamp - ) / (TimeUnit.MILLISECONDS.toDays(ONE_DAY_IN_MS.toLong())) + ) / (ONE_DAY_IN_MS) val promotedStory = createPromotedStory( storyId, topic, @@ -502,7 +502,7 @@ class TopicListController @Inject constructor( nextChapterSummary.name, nextChapterSummary.explorationId ) - if (numberOfDaysPassed < TimeUnit.MILLISECONDS.toDays(ONE_WEEK_IN_DAYS.toLong())) { + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) } else { recommendedStoryBuilder.addOlderPlayedStory(promotedStory) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index f58321d2019..f9f31c52df4 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -491,7 +491,7 @@ class TopicListControllerTest { val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) - .isEqualTo(0) + .isEqualTo(3) verifyOngoingStoryAsRatioStory0Exploration1( recommendedActivityList.recommendedStoryList.recentlyPlayedStoryList[0] ) From b08f6152cbfe78b6778b0830f6a506242c882b02 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 10 Jan 2021 18:11:58 +0530 Subject: [PATCH 159/248] Update TopicListController.kt --- .../domain/topic/TopicListController.kt | 139 +++++++++--------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 3098540b3d2..cd82e43ffa6 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -272,7 +272,7 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress != null && mostRecentCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { - createOngoingStoryListBasedOnLastCompleted( + createOngoingStoryListBasedOnMostRecentlyCompleted( storyId, story, mostRecentCompletedChapterProgress, @@ -288,21 +288,22 @@ class TopicListController @Inject constructor( return ongoingStoryListBuilder.build() } - private fun getStartedChapterProgressList(storyProgress: StoryProgress): List { - return storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.STARTED_NOT_COMPLETED - } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - } + private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = + getSortedChapterProgressListByPlayState( + storyProgress, playState = ChapterPlayState.STARTED_NOT_COMPLETED + ) - private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List { + private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List = + getSortedChapterProgressListByPlayState( + storyProgress, playState = ChapterPlayState.COMPLETED + ) + + private fun getSortedChapterProgressListByPlayState( + storyProgress: StoryProgress, + playState: ChapterPlayState + ): List { return storyProgress.chapterProgressMap.values - .filter { chapterProgress -> - chapterProgress.chapterPlayState == - ChapterPlayState.COMPLETED - } + .filter { chapterProgress -> chapterProgress.chapterPlayState == playState } .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } } @@ -319,10 +320,8 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + val numberOfDaysPassed = + (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -339,7 +338,7 @@ class TopicListController @Inject constructor( } } - private fun createOngoingStoryListBasedOnLastCompleted( + private fun createOngoingStoryListBasedOnMostRecentlyCompleted( storyId: String, story: StorySummary, mostRecentCompletedChapterProgress: ChapterProgress, @@ -354,10 +353,8 @@ class TopicListController @Inject constructor( val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - mostRecentCompletedChapterProgress.lastPlayedTimestamp - ) / ONE_DAY_IN_MS + val numberOfDaysPassed = + (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS val promotedStory = createPromotedStory( storyId, topic, @@ -381,7 +378,42 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() + // If initially only one topic is in progress populate combination of Recently-played stories + // and Recommended stories if (topicProgressList.size == 1) { + populateRecommendedStories( + topicProgressList, + recommendedStoryBuilder, + recommendedActivityListBuilder + ) + } else { + // Add recently played stories or last played stories in RecommendedActivityList. + populateRecentlyPlayedStories( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) + // If the above list is empty then populate Suggested stories or Upcoming stories + populateRecommendedStories( + topicProgressList, + recommendedStoryBuilder, + recommendedActivityListBuilder + ) + } + } + return recommendedActivityListBuilder.build() + } + + private fun populateRecommendedStories( + topicProgressList: List, + recommendedStoryBuilder: RecommendedStoryList.Builder, + recommendedActivityListBuilder: RecommendedActivityList.Builder + ) { + // If no recently played stories or last played stories then set suggested stories + // in RecommendedActivityList. + when { + recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList, @@ -391,47 +423,16 @@ class TopicListController @Inject constructor( ) recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - if (recommendedStoryBuilder.suggestedStoryCount == 0 && - recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 - ) { + // If user has completed all the topics then add upcoming topics in + // RecommendedActivityList. + if (recommendedStoryBuilder.suggestedStoryCount == 0) { recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } - } else { - // Add recently played stories or last played stories in RecommendedActivityList. - createRecentPlayedStories( - topicProgressList, - recommendedActivityListBuilder, - recommendedStoryBuilder - ) - - // If no recently played stories or last played stories then set suggested stories - // in RecommendedActivityList. - when { - recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { - recommendedStoryBuilder.addAllSuggestedStory( - createRecommendedStoryList( - topicProgressList, - recommendedActivityListBuilder, - recommendedStoryBuilder - ) - ) - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - - // If user has completed all the topics then add upcoming topics in - // RecommendedActivityList. - if (recommendedStoryBuilder.suggestedStoryCount == 0) { - recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() - } - } - } } } - return recommendedActivityListBuilder.build() } - private fun createRecentPlayedStories( + private fun populateRecentlyPlayedStories( topicProgressList: List, recommendedActivityListBuilder: RecommendedActivityList.Builder, recommendedStoryBuilder: RecommendedStoryList.Builder @@ -461,10 +462,8 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - recentlyPlayerChapterProgress.lastPlayedTimestamp - ) / (ONE_DAY_IN_MS) + val numberOfDaysPassed = + (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / (ONE_DAY_IN_MS) val promotedStory = createPromotedStory( storyId, topic, @@ -490,10 +489,8 @@ class TopicListController @Inject constructor( val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = ( - oppiaClock.getCurrentCalendar().timeInMillis - - mostRecentCompletedChapterProgress.lastPlayedTimestamp - ) / (ONE_DAY_IN_MS) + val numberOfDaysPassed = + (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / (ONE_DAY_IN_MS) val promotedStory = createPromotedStory( storyId, topic, @@ -516,6 +513,12 @@ class TopicListController @Inject constructor( } } + private fun ChapterProgress.getNumberOfDaysPassed(): Int { + return TimeUnit.MILLISECONDS.toDays( + oppiaClock.getCurrentCalendar().timeInMillis - this.lastPlayedTimestamp + ).toInt() + } + private fun createRecommendedStoryList( topicProgressList: List, recommendedActivityListBuilder: RecommendedActivityList.Builder, @@ -523,7 +526,7 @@ class TopicListController @Inject constructor( ): List { val recommendedStories = mutableListOf() - createRecentPlayedStories( + populateRecentlyPlayedStories( topicProgressList, recommendedActivityListBuilder, recommendedStoryBuilder @@ -542,7 +545,7 @@ class TopicListController @Inject constructor( createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null ) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) - return recommendedStories +// return recommendedStories } } return recommendedStories From 85a2900761be348c18746e84eb7872b89c588a26 Mon Sep 17 00:00:00 2001 From: Veena Date: Mon, 11 Jan 2021 12:57:59 +0530 Subject: [PATCH 160/248] Update model/src/main/proto/topic.proto Co-authored-by: Ben Henning --- model/src/main/proto/topic.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index db7c03674b0..8d739767ec9 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -258,7 +258,7 @@ message TopicProgress { // Map from story ID to StoryProgress. map story_progress = 2; - // Timestamp to record last time the exploration was played in ms. + // Timestamp to indicate the last time the exploration was played in ms. int64 last_played_timestamp = 3; } From 68150476c684560ed0b3d8391de49f7cade74da0 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 11 Jan 2021 14:35:28 +0530 Subject: [PATCH 161/248] Removed ongoingstory list. --- .../domain/topic/TopicListController.kt | 328 +++++++----------- .../topic/StoryProgressTestHelperTest.kt | 142 ++++---- model/src/main/proto/topic.proto | 9 - 3 files changed, 191 insertions(+), 288 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index cd82e43ffa6..6fcddca0826 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -8,7 +8,6 @@ import org.oppia.android.app.model.ChapterSummary import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic -import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.RecommendedActivityList @@ -81,8 +80,6 @@ val EXPLORATION_THUMBNAILS = mapOf( ) private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" -private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = - "get_ongoing_story_list_provider_id" private const val GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID = "get_recommended_actvity_list_provider_id" @@ -108,23 +105,6 @@ class TopicListController @Inject constructor( ) } - /** - * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. - * The total number of promoted stories should correspond to the ongoing story count within the - * [TopicList] returned by [getTopicList]. - * - * @param profileId the ID corresponding to the profile for which [PromotedStory] needs to be - * fetched. - * @return a [DataProvider] for an [OngoingStoryList]. - */ - fun getOngoingStoryList(profileId: ProfileId): DataProvider { - return storyProgressController.retrieveTopicProgressListDataProvider(profileId) - .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { - val ongoingStoryList = createOngoingStoryListFromProgress(it) - AsyncResult.success(ongoingStoryList) - } - } - /** * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. * The total number of promoted stories should correspond to the ongoing story count within the @@ -237,140 +217,6 @@ class TopicListController @Inject constructor( .build() } - private fun createOngoingStoryListFromProgress( - topicProgressList: List - ): OngoingStoryList { - val ongoingStoryListBuilder = OngoingStoryList.newBuilder() - if (topicProgressList.isNotEmpty()) { - val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - sortedTopicProgressList.forEach { topicProgress -> - val topic = topicController.retrieveTopic(topicProgress.topicId) - - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) - - val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) - val mostRecentCompletedChapterProgress: ChapterProgress? = - completedChapterProgressList.firstOrNull() - - val startedChapterProgressList = getStartedChapterProgressList(storyProgress) - val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() - - when { - recentlyPlayerChapterProgress != null -> { - createOngoingStoryListBasedOnRecentlyPlayed( - storyId, - story, - recentlyPlayerChapterProgress, - completedChapterProgressList, - topic, - ongoingStoryListBuilder - ) - } - mostRecentCompletedChapterProgress != null && - mostRecentCompletedChapterProgress.explorationId != - story.chapterList.last().explorationId -> { - createOngoingStoryListBasedOnMostRecentlyCompleted( - storyId, - story, - mostRecentCompletedChapterProgress, - completedChapterProgressList, - topic, - ongoingStoryListBuilder - ) - } - } - } - } - } - return ongoingStoryListBuilder.build() - } - - private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = - getSortedChapterProgressListByPlayState( - storyProgress, playState = ChapterPlayState.STARTED_NOT_COMPLETED - ) - - private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List = - getSortedChapterProgressListByPlayState( - storyProgress, playState = ChapterPlayState.COMPLETED - ) - - private fun getSortedChapterProgressListByPlayState( - storyProgress: StoryProgress, - playState: ChapterPlayState - ): List { - return storyProgress.chapterProgressMap.values - .filter { chapterProgress -> chapterProgress.chapterPlayState == playState } - .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } - } - - private fun createOngoingStoryListBasedOnRecentlyPlayed( - storyId: String, - story: StorySummary, - recentlyPlayerChapterProgress: ChapterProgress, - completedChapterProgressList: List, - topic: Topic, - ongoingStoryListBuilder: OngoingStoryList.Builder - ) { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } - } - } - - private fun createOngoingStoryListBasedOnMostRecentlyCompleted( - storyId: String, - story: StorySummary, - mostRecentCompletedChapterProgress: ChapterProgress, - completedChapterProgressList: List, - topic: Topic, - ongoingStoryListBuilder: OngoingStoryList.Builder - ) { - val lastChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - ongoingStoryListBuilder.addRecentStory(promotedStory) - } else { - ongoingStoryListBuilder.addOlderStory(promotedStory) - } - } - } - private fun createRecommendedActivityList( topicProgressList: List ): RecommendedActivityList { @@ -378,8 +224,8 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() - // If initially only one topic is in progress populate combination of Recently-played stories - // and Recommended stories + // If initially only one topic is in progress populate combination of Ongoing story + // and Suggested stories if (topicProgressList.size == 1) { populateRecommendedStories( topicProgressList, @@ -457,55 +303,26 @@ class TopicListController @Inject constructor( when { recentlyPlayerChapterProgress != null -> { - val recentlyPlayerChapterSummary: ChapterSummary? = - story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId - } - if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / (ONE_DAY_IN_MS) - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) - } else { - recommendedStoryBuilder.addOlderPlayedStory(promotedStory) - } - } + createOngoingStoryListBasedOnRecentlyPlayed( + storyId, + story, + recentlyPlayerChapterProgress, + completedChapterProgressList, + topic, + recommendedStoryBuilder + ) } - mostRecentCompletedChapterProgress != null -> { - if (mostRecentCompletedChapterProgress.explorationId - != story.chapterList.last().explorationId - ) { - val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId - } - val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / (ONE_DAY_IN_MS) - val promotedStory = createPromotedStory( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) - } else { - recommendedStoryBuilder.addOlderPlayedStory(promotedStory) - } - } - } + mostRecentCompletedChapterProgress != null && + mostRecentCompletedChapterProgress.explorationId != + story.chapterList.last().explorationId -> { + createOngoingStoryListBasedOnMostRecentlyCompleted( + storyId, + story, + mostRecentCompletedChapterProgress, + completedChapterProgressList, + topic, + recommendedStoryBuilder + ) } } } @@ -513,6 +330,108 @@ class TopicListController @Inject constructor( } } + private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = + getSortedChapterProgressListByPlayState( + storyProgress, playState = ChapterPlayState.STARTED_NOT_COMPLETED + ) + + private fun getCompletedChapterProgressList(storyProgress: StoryProgress): List = + getSortedChapterProgressListByPlayState( + storyProgress, playState = ChapterPlayState.COMPLETED + ) + + private fun getSortedChapterProgressListByPlayState( + storyProgress: StoryProgress, + playState: ChapterPlayState + ): List { + return storyProgress.chapterProgressMap.values + .filter { chapterProgress -> chapterProgress.chapterPlayState == playState } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + } + + private fun createOngoingStoryListBasedOnRecentlyPlayed( + storyId: String, + story: StorySummary, + recentlyPlayerChapterProgress: ChapterProgress, + completedChapterProgressList: List, + topic: Topic, + recommendedStoryBuilder: RecommendedStoryList.Builder + ) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS + addPromotedStoryInRecommendedStoryList( + numberOfDaysPassed, + recommendedStoryBuilder, + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId + ) + } + } + + private fun createOngoingStoryListBasedOnMostRecentlyCompleted( + storyId: String, + story: StorySummary, + mostRecentCompletedChapterProgress: ChapterProgress, + completedChapterProgressList: List, + topic: Topic, + recommendedStoryBuilder: RecommendedStoryList.Builder + ) { + val lastChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS + addPromotedStoryInRecommendedStoryList( + numberOfDaysPassed, + recommendedStoryBuilder, + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + } + } + + private fun addPromotedStoryInRecommendedStoryList( + numberOfDaysPassed: Int, + recommendedStoryBuilder: RecommendedStoryList.Builder, + storyId: String, + topic: Topic, + completedChapterProgressListSize: Int, + chapterCount: Int, + chapterSummaryName: String, + chapterSummaryExplorationId: String + ) { + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressListSize, + chapterCount, + chapterSummaryName, + chapterSummaryExplorationId + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) + } else { + recommendedStoryBuilder.addOlderPlayedStory(promotedStory) + } + } + private fun ChapterProgress.getNumberOfDaysPassed(): Int { return TimeUnit.MILLISECONDS.toDays( oppiaClock.getCurrentCalendar().timeInMillis - this.lastPlayedTimestamp @@ -545,7 +464,6 @@ class TopicListController @Inject constructor( createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null ) { recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) -// return recommendedStories } } return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index a960e8db4a7..0dd9c6fe3b3 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -23,10 +23,9 @@ import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.CompletedStoryList -import org.oppia.android.app.model.OngoingStoryList +import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.ProfileId -import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList @@ -79,9 +78,6 @@ class StoryProgressTestHelperTest { @Captor lateinit var completedStoryListResultCaptor: ArgumentCaptor> - @Mock - lateinit var mockOngoingStoryListObserver: Observer> - @Mock lateinit var mockRecommendedActivityListObserver: Observer> @@ -89,9 +85,6 @@ class StoryProgressTestHelperTest { lateinit var recommendedActivityListResultCaptor: ArgumentCaptor> - @Captor - lateinit var ongoingStoryListResultCaptor: ArgumentCaptor> - @Mock lateinit var mockOngoingTopicListObserver: Observer> @@ -745,49 +738,53 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getOngoingStoryListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getRecommendedActivityListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId, /* timestampOlderThanAWeek= */ false ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingStoryList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingStoryList.recentStoryCount).isEqualTo(1) - assertThat(ongoingStoryList.olderStoryCount).isEqualTo(0) - assertThat(ongoingStoryList.recentStoryList[0].explorationId).isEqualTo( - FRACTIONS_EXPLORATION_ID_0 - ) - assertThat(ongoingStoryList.recentStoryList[0].completedChapterCount).isEqualTo(0) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + with (recommendedActivityList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + FRACTIONS_EXPLORATION_ID_0 + ) + assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) + } } @Test - fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_getOngoingStoryListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_getRecommendedActivityListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( profileId, /* timestampOlderThanAWeek= */ false ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingStoryList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingStoryList.recentStoryCount).isEqualTo(1) - assertThat(ongoingStoryList.olderStoryCount).isEqualTo(0) - assertThat(ongoingStoryList.recentStoryList[0].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_0 - ) - assertThat(ongoingStoryList.recentStoryList[0].completedChapterCount).isEqualTo(0) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + with (recommendedActivityList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + RATIOS_EXPLORATION_ID_0 + ) + assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) + } } @Test @@ -798,24 +795,25 @@ class StoryProgressTestHelperTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - - val ongoingStoryList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingStoryList.recentStoryCount).isEqualTo(2) - assertThat(ongoingStoryList.olderStoryCount).isEqualTo(0) - assertThat(ongoingStoryList.recentStoryList[0].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_0 - ) - assertThat(ongoingStoryList.recentStoryList[0].completedChapterCount).isEqualTo(0) + verifyGetRecommendedActivityListSucceeded() - assertThat(ongoingStoryList.recentStoryList[1].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_2 - ) - assertThat(ongoingStoryList.recentStoryList[1].completedChapterCount).isEqualTo(0) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + with (recommendedActivityList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(2) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + RATIOS_EXPLORATION_ID_0 + ) + assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[1].explorationId).isEqualTo( + RATIOS_EXPLORATION_ID_2 + ) + assertThat(recentlyPlayedStoryList[1].completedChapterCount).isEqualTo(0) + } } @Test @@ -833,49 +831,53 @@ class StoryProgressTestHelperTest { verifyGetRecommendedActivityListSucceeded() val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - assertThat(recommendedActivityList.recommendedStoryList.recentlyPlayedStoryCount) - .isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.olderPlayedStoryCount) - .isEqualTo(0) - assertThat(recommendedActivityList.recommendedStoryList.suggestedStoryList[0].explorationId) - .isEqualTo( - FRACTIONS_EXPLORATION_ID_0 - ) + with (recommendedActivityList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(olderPlayedStoryCount) + .isEqualTo(0) + assertThat(suggestedStoryList[0].explorationId) + .isEqualTo( + FRACTIONS_EXPLORATION_ID_0 + ) + } } @Test - fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_ongoingStoryListCorrect() { + fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_RecommendedActivityListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId, /* timestampOlderThanAWeek= */ true ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getRecommendedActivityList(profileId).toLiveData() + .observeForever(mockRecommendedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetRecommendedActivityListSucceeded() - val ongoingStoryList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingStoryList.recentStoryCount).isEqualTo(0) - assertThat(ongoingStoryList.olderStoryCount).isEqualTo(3) + val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() + with (recommendedActivityList.recommendedStoryList){ + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(olderPlayedStoryCount).isEqualTo(3) - assertThat(ongoingStoryList.olderStoryList[0].explorationId).isEqualTo( + assertThat(olderPlayedStoryList[0].explorationId).isEqualTo( FRACTIONS_EXPLORATION_ID_0 ) - assertThat(ongoingStoryList.olderStoryList[0].completedChapterCount) + assertThat(olderPlayedStoryList[0].completedChapterCount) .isEqualTo(0) - assertThat(ongoingStoryList.olderStoryList[1].explorationId) + assertThat(olderPlayedStoryList[1].explorationId) .isEqualTo(RATIOS_EXPLORATION_ID_0) - assertThat(ongoingStoryList.olderStoryList[1].completedChapterCount) + assertThat(olderPlayedStoryList[1].completedChapterCount) .isEqualTo(0) - assertThat(ongoingStoryList.olderStoryList[2].explorationId) + assertThat(olderPlayedStoryList[2].explorationId) .isEqualTo(RATIOS_EXPLORATION_ID_2) - assertThat(ongoingStoryList.olderStoryList[2].completedChapterCount) + assertThat(olderPlayedStoryList[2].completedChapterCount) .isEqualTo(0) + } } private fun verifyGetTopicSucceeded() { @@ -904,14 +906,6 @@ class StoryProgressTestHelperTest { assertThat(completedStoryListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyGetOngoingStoryListSucceeded() { - verify( - mockOngoingStoryListObserver, - atLeastOnce() - ).onChanged(ongoingStoryListResultCaptor.capture()) - assertThat(ongoingStoryListResultCaptor.value.isSuccess()).isTrue() - } - private fun verifyGetRecommendedActivityListSucceeded() { verify( mockRecommendedActivityListObserver, diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 8d739767ec9..6e9cd606ed3 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -164,15 +164,6 @@ message CompletedStory { LessonThumbnail lesson_thumbnail = 5; } -// Corresponds to the list of stories the player is currently playing across all topics. -message OngoingStoryList { - // Ongoing stories from within the last 7 days. - repeated PromotedStory recent_story = 1; - - // Other ongoing stories from longer than 7 days ago. - repeated PromotedStory older_story = 2; -} - // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, // or because they have completed all other lessons and may find this one interesting. message PromotedStory { From c073c8d471b7acf1449f29a30367faeb56784f70 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 11 Jan 2021 09:05:10 -0800 Subject: [PATCH 162/248] Move test helpers beneath test cases --- .../app/home/TopicSummaryViewModelTest.kt | 38 ++++++------ .../android/app/home/WelcomeViewModelTest.kt | 48 +++++++-------- .../PromotedStoryListViewModelTest.kt | 58 +++++++++---------- .../PromotedStoryViewModelTest.kt | 32 +++++----- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index 277ae854e6a..33bff42cf5a 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -88,25 +88,6 @@ class TopicSummaryViewModelTest { setUpTestApplicationComponent() } - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - - private fun setUpTestFragment(activity: HomeFragmentTestActivity) { - activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) - .commitNow() - } - - private fun createBasicTopicSummaryViewModel(activity: AppCompatActivity): TopicSummaryViewModel { - return TopicSummaryViewModel( - activity = activity, - topicSummary = topicSummary1, - entityType = "entity", - topicSummaryClickListener = testFragment, - position = 5 - ) - } - @Test fun testTopicSummaryViewModelEquals_reflexiveBasicTopicSummaryViewModel_isEqual() { ActivityScenario.launch( @@ -306,6 +287,25 @@ class TopicSummaryViewModelTest { } } + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun setUpTestFragment(activity: HomeFragmentTestActivity) { + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) + .commitNow() + } + + private fun createBasicTopicSummaryViewModel(activity: AppCompatActivity): TopicSummaryViewModel { + return TopicSummaryViewModel( + activity = activity, + topicSummary = topicSummary1, + entityType = "entity", + topicSummaryClickListener = testFragment, + position = 5 + ) + } + // 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/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index 73f30daf729..ca96ea57a1a 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -90,30 +90,6 @@ class WelcomeViewModelTest { setUpTestApplicationComponent() } - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - - private fun setUpTestFragment(activity: HomeFragmentTestActivity) { - activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) - .commitNow() - } - - private fun setUpDifferentClockTimes() { - morningClock = OppiaClock() - morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) - eveningClock = OppiaClock() - eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) - } - - private fun createBasicWelcomeViewModel(fragment: Fragment): WelcomeViewModel { - return WelcomeViewModel( - fragment, - morningClock, - "Profile 1" - ) - } - @Test fun testWelcomeViewModelEquals_reflexiveBasicWelcomeViewModel_isEqual() { launch( @@ -298,6 +274,30 @@ class WelcomeViewModelTest { } } + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun setUpTestFragment(activity: HomeFragmentTestActivity) { + activity.supportFragmentManager.beginTransaction().add(testFragment, TEST_FRAGMENT_TAG) + .commitNow() + } + + private fun setUpDifferentClockTimes() { + morningClock = OppiaClock() + morningClock.setCurrentTimeMs(MORNING_TIMESTAMP) + eveningClock = OppiaClock() + eveningClock.setCurrentTimeMs(EVENING_TIMESTAMP) + } + + private fun createBasicWelcomeViewModel(fragment: Fragment): WelcomeViewModel { + return WelcomeViewModel( + fragment, + morningClock, + "Profile 1" + ) + } + // 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/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 9fd833b7f05..433ba41d511 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -91,35 +91,6 @@ class PromotedStoryListViewModelTest { setUpTestApplicationComponent() } - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - - private fun createPromotedStoryViewModelList( - activity: AppCompatActivity, - promotedStoryList: List - ): List { - return promotedStoryList.map { - PromotedStoryViewModel( - activity, - internalProfileId = 1, - totalStoryCount = promotedStoryList.size, - entityType = "entity", - promotedStory = it - ) - } - } - - private fun createPromotedStoryListViewModel( - activity: AppCompatActivity, - promotedStoryList: List - ): PromotedStoryListViewModel { - return PromotedStoryListViewModel( - activity, - createPromotedStoryViewModelList(activity, promotedStoryList) - ) - } - @Test fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isEqual() { ActivityScenario.launch( @@ -287,6 +258,35 @@ class PromotedStoryListViewModelTest { } } + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun createPromotedStoryViewModelList( + activity: AppCompatActivity, + promotedStoryList: List + ): List { + return promotedStoryList.map { + PromotedStoryViewModel( + activity, + internalProfileId = 1, + totalStoryCount = promotedStoryList.size, + entityType = "entity", + promotedStory = it + ) + } + } + + private fun createPromotedStoryListViewModel( + activity: AppCompatActivity, + promotedStoryList: List + ): PromotedStoryListViewModel { + return PromotedStoryListViewModel( + activity, + createPromotedStoryViewModelList(activity, promotedStoryList) + ) + } + // 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/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 6f6486d732f..788abf5789a 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -85,22 +85,6 @@ class PromotedStoryViewModelTest { setUpTestApplicationComponent() } - private fun setUpTestApplicationComponent() { - ApplicationProvider.getApplicationContext().inject(this) - } - - private fun createBasicPromotedStoryViewModel( - activity: AppCompatActivity - ): PromotedStoryViewModel { - return PromotedStoryViewModel( - activity = activity, - internalProfileId = 1, - totalStoryCount = 3, - entityType = "entity", - promotedStory = promotedStory1 - ) - } - @Test fun testPromotedStoryViewModelEquals_reflexiveBasicPromotedStoryViewModel_isEqual() { ActivityScenario.launch( @@ -319,6 +303,22 @@ class PromotedStoryViewModelTest { } } + private fun setUpTestApplicationComponent() { + ApplicationProvider.getApplicationContext().inject(this) + } + + private fun createBasicPromotedStoryViewModel( + activity: AppCompatActivity + ): PromotedStoryViewModel { + return PromotedStoryViewModel( + activity = activity, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 + ) + } + // 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 From 805efcdced0a5e809709d5e24e77fda08f4a6f32 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Mon, 11 Jan 2021 09:09:57 -0800 Subject: [PATCH 163/248] Address review comments --- .../app/home/TopicSummaryViewModelTest.kt | 85 ++++++++-------- .../android/app/home/WelcomeViewModelTest.kt | 18 ++-- .../PromotedStoryListViewModelTest.kt | 6 +- .../PromotedStoryViewModelTest.kt | 98 +++++++++---------- 4 files changed, 104 insertions(+), 103 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index 33bff42cf5a..f09d7d4c4b5 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -111,11 +111,11 @@ class TopicSummaryViewModelTest { it.onActivity { setUpTestFragment(it) val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) - val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) + val topicSummaryViewModelCopy = createBasicTopicSummaryViewModel(it) // Verify the symmetric property of equals(): a == b iff b == a. - assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) - assertThat(copyTopicSummaryViewModel).isEqualTo(topicSummaryViewModel) + assertThat(topicSummaryViewModel).isEqualTo(topicSummaryViewModelCopy) + assertThat(topicSummaryViewModelCopy).isEqualTo(topicSummaryViewModel) } } } @@ -147,12 +147,12 @@ class TopicSummaryViewModelTest { it.onActivity { setUpTestFragment(it) val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) - val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) - assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) + val topicSummaryViewModelCopy = createBasicTopicSummaryViewModel(it) + assertThat(topicSummaryViewModel).isEqualTo(topicSummaryViewModelCopy) // Verify the consistent property of equals(): if neither object is modified, then a == b // for multiple invocations - assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) + assertThat(topicSummaryViewModel).isEqualTo(topicSummaryViewModelCopy) } } } @@ -179,22 +179,23 @@ class TopicSummaryViewModelTest { ).use { it.onActivity { setUpTestFragment(it) - val topicSummaryViewModel1 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 + val topicSummaryViewModelTopicSummary1 = TopicSummaryViewModel( + activity = it, + topicSummary = topicSummary1, + entityType = "entity_1", + topicSummaryClickListener = testFragment, + position = 5 ) - val topicSummaryViewModel2 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary2, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 + val topicSummaryViewModelTopicSummary2 = TopicSummaryViewModel( + activity = it, + topicSummary = topicSummary2, + entityType = "entity_1", + topicSummaryClickListener = testFragment, + position = 5 ) - assertThat(topicSummaryViewModel1).isNotEqualTo(topicSummaryViewModel2) + assertThat(topicSummaryViewModelTopicSummary1) + .isNotEqualTo(topicSummaryViewModelTopicSummary2) } } } @@ -207,18 +208,18 @@ class TopicSummaryViewModelTest { it.onActivity { setUpTestFragment(it) val topicSummaryViewModelEntity1 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 + activity = it, + topicSummary = topicSummary1, + entityType = "entity_1", + topicSummaryClickListener = testFragment, + position = 5 ) val topicSummaryViewModelEntity2 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_2", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 + activity = it, + topicSummary = topicSummary1, + entityType = "entity_2", + topicSummaryClickListener = testFragment, + position = 5 ) assertThat(topicSummaryViewModelEntity1).isNotEqualTo(topicSummaryViewModelEntity2) @@ -234,18 +235,18 @@ class TopicSummaryViewModelTest { it.onActivity { setUpTestFragment(it) val topicSummaryViewModelPosition4 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 4 + activity = it, + topicSummary = topicSummary1, + entityType = "entity_1", + topicSummaryClickListener = testFragment, + position = 4 ) val topicSummaryViewModelPosition5 = TopicSummaryViewModel( - /* activity = */ it, - topicSummary1, - /* entityType = */ "entity_1", - /* topicSummaryCLickListener = */ testFragment, - /* position = */ 5 + activity = it, + topicSummary = topicSummary1, + entityType = "entity_1", + topicSummaryClickListener = testFragment, + position = 5 ) assertThat(topicSummaryViewModelPosition4).isNotEqualTo(topicSummaryViewModelPosition5) @@ -261,11 +262,11 @@ class TopicSummaryViewModelTest { it.onActivity { setUpTestFragment(it) val topicSummaryViewModel = createBasicTopicSummaryViewModel(it) - val copyTopicSummaryViewModel = createBasicTopicSummaryViewModel(it) - assertThat(topicSummaryViewModel).isEqualTo(copyTopicSummaryViewModel) + val topicSummaryViewModelCopy = createBasicTopicSummaryViewModel(it) + assertThat(topicSummaryViewModel).isEqualTo(topicSummaryViewModelCopy) // Verify that if a == b, then a.hashCode == b.hashCode - assertThat(topicSummaryViewModel.hashCode()).isEqualTo(copyTopicSummaryViewModel.hashCode()) + assertThat(topicSummaryViewModel.hashCode()).isEqualTo(topicSummaryViewModelCopy.hashCode()) } } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt index ca96ea57a1a..0ce7d708e22 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/WelcomeViewModelTest.kt @@ -113,11 +113,11 @@ class WelcomeViewModelTest { it.onActivity { setUpTestFragment(it) val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) - val copyWelcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) + val welcomeViewModelProfile1MorningCopy = createBasicWelcomeViewModel(testFragment) // Verify the symmetric property of equals(): a == b iff b == a. - assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) - assertThat(copyWelcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1Morning) + assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1MorningCopy) + assertThat(welcomeViewModelProfile1MorningCopy).isEqualTo(welcomeViewModelProfile1Morning) } } } @@ -155,12 +155,12 @@ class WelcomeViewModelTest { it.onActivity { setUpTestFragment(it) val welcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) - val copyWelcomeViewModelProfile1Morning = createBasicWelcomeViewModel(testFragment) - assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + val welcomeViewModelProfile1MorningCopy = createBasicWelcomeViewModel(testFragment) + assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1MorningCopy) // Verify the consistent property of equals(): if neither object is modified, then a == b // for multiple invocations - assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1MorningCopy) } } } @@ -239,16 +239,16 @@ class WelcomeViewModelTest { morningClock, "Profile 1" ) - val copyWelcomeViewModelProfile1Morning = WelcomeViewModel( + val welcomeViewModelProfile1MorningCopy = WelcomeViewModel( testFragment, morningClock, "Profile 1" ) - assertThat(welcomeViewModelProfile1Morning).isEqualTo(copyWelcomeViewModelProfile1Morning) + assertThat(welcomeViewModelProfile1Morning).isEqualTo(welcomeViewModelProfile1MorningCopy) // Verify that if a == b, then a.hashCode == b.hashCode assertThat(welcomeViewModelProfile1Morning.hashCode()) - .isEqualTo(copyWelcomeViewModelProfile1Morning.hashCode()) + .isEqualTo(welcomeViewModelProfile1MorningCopy.hashCode()) } } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 433ba41d511..129a81ed3b6 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -117,14 +117,14 @@ class PromotedStoryListViewModelTest { it, listOf(promotedStory1, promotedStory2) ) - val copyPromotedStoryListViewModel = createPromotedStoryListViewModel( + val promotedStoryListViewModelCopy = createPromotedStoryListViewModel( it, listOf(promotedStory1, promotedStory2) ) // Verify the symmetric property of equals(): a == b iff b == a. - assertThat(promotedStoryListViewModel).isEqualTo(copyPromotedStoryListViewModel) - assertThat(copyPromotedStoryListViewModel).isEqualTo(promotedStoryListViewModel) + assertThat(promotedStoryListViewModel).isEqualTo(promotedStoryListViewModelCopy) + assertThat(promotedStoryListViewModelCopy).isEqualTo(promotedStoryListViewModel) } } } diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 788abf5789a..7a2989eeaa9 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -106,11 +106,11 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) - val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) + val promotedStoryViewModelCopy = createBasicPromotedStoryViewModel(it) // Verify the symmetric property of equals(): a == b iff b == a. - assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) - assertThat(copyPromotedStoryViewModel).isEqualTo(promotedStoryViewModel) + assertThat(promotedStoryViewModel).isEqualTo(promotedStoryViewModelCopy) + assertThat(promotedStoryViewModelCopy).isEqualTo(promotedStoryViewModel) } } } @@ -140,12 +140,12 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) - val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) - assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) + val promotedStoryViewModelCopy = createBasicPromotedStoryViewModel(it) + assertThat(promotedStoryViewModel).isEqualTo(promotedStoryViewModelCopy) // Verify the consistent property of equals(): if neither object is modified, then a == b // for multiple invocations - assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) + assertThat(promotedStoryViewModel).isEqualTo(promotedStoryViewModelCopy) } } } @@ -170,18 +170,18 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModelProfile1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 ) val promotedStoryViewModelProfile2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */2, - /* totalStoryCount = */3, - /* entytType = */"entity", - promotedStory1 + activity = it, + internalProfileId = 2, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 ) assertThat(promotedStoryViewModelProfile1).isNotEqualTo(promotedStoryViewModelProfile2) @@ -196,18 +196,18 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModelStoryCount2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */2, - /* entytType = */"entity", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 2, + entityType = "entity", + promotedStory = promotedStory1 ) val promotedStoryViewModelStoryCount3 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 ) assertThat(promotedStoryViewModelStoryCount2) @@ -223,18 +223,18 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModelEntity1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity_1", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity_1", + promotedStory = promotedStory1 ) val promotedStoryViewModelEntity2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity_2", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity_2", + promotedStory = promotedStory1 ) assertThat(promotedStoryViewModelEntity1).isNotEqualTo(promotedStoryViewModelEntity2) @@ -251,18 +251,18 @@ class PromotedStoryViewModelTest { assertThat(promotedStory1.equals(promotedStory2)).isFalse() val promotedStoryViewModelStory1 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity_1", - promotedStory1 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory1 ) val promotedStoryViewModelStory2 = PromotedStoryViewModel( - /* activity = */ it, - /* internalProfileId = */1, - /* totalStoryCount = */3, - /* entytType = */"entity_2", - promotedStory2 + activity = it, + internalProfileId = 1, + totalStoryCount = 3, + entityType = "entity", + promotedStory = promotedStory2 ) assertThat(promotedStoryViewModelStory1).isNotEqualTo(promotedStoryViewModelStory2) @@ -277,12 +277,12 @@ class PromotedStoryViewModelTest { ).use { it.onActivity { val promotedStoryViewModel = createBasicPromotedStoryViewModel(it) - val copyPromotedStoryViewModel = createBasicPromotedStoryViewModel(it) - assertThat(promotedStoryViewModel).isEqualTo(copyPromotedStoryViewModel) + val promotedStoryViewModelCopy = createBasicPromotedStoryViewModel(it) + assertThat(promotedStoryViewModel).isEqualTo(promotedStoryViewModelCopy) // Verify that if a == b, then a.hashCode == b.hashCode assertThat(promotedStoryViewModel.hashCode()) - .isEqualTo(copyPromotedStoryViewModel.hashCode()) + .isEqualTo(promotedStoryViewModelCopy.hashCode()) } } } From 35c7b85a9036def1f324a60b63a150e72549626f Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 12 Jan 2021 01:13:38 +0530 Subject: [PATCH 164/248] Optimized code. --- .../domain/topic/TopicListController.kt | 105 ++++++++++-------- .../domain/topic/TopicListControllerTest.kt | 29 +---- 2 files changed, 58 insertions(+), 76 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 6fcddca0826..a8f99fe2762 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -33,7 +33,6 @@ import javax.inject.Inject import javax.inject.Singleton private const val ONE_WEEK_IN_DAYS = 7 -private const val ONE_DAY_IN_MS = 24 * 60 * 60 * 1000 private const val TOPIC_BG_COLOR = "#C6DCDA" @@ -225,13 +224,23 @@ class TopicListController @Inject constructor( if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() // If initially only one topic is in progress populate combination of Ongoing story - // and Suggested stories + // and Suggested stories. if (topicProgressList.size == 1) { - populateRecommendedStories( - topicProgressList, - recommendedStoryBuilder, - recommendedActivityListBuilder + recommendedStoryBuilder.addAllSuggestedStory( + createRecommendedStoryList( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + + if (recommendedStoryBuilder.suggestedStoryCount == 0 && + recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount == 0 + ) { + recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() + } } else { // Add recently played stories or last played stories in RecommendedActivityList. populateRecentlyPlayedStories( @@ -239,12 +248,17 @@ class TopicListController @Inject constructor( recommendedActivityListBuilder, recommendedStoryBuilder ) - // If the above list is empty then populate Suggested stories or Upcoming stories - populateRecommendedStories( - topicProgressList, - recommendedStoryBuilder, - recommendedActivityListBuilder - ) + // If the Recently-played or Older-played story list is empty then populate Suggested + // stories or Upcoming stories + if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && + recommendedStoryBuilder.olderPlayedStoryCount == 0 ){ + populateRecommendedStories( + topicProgressList, + recommendedStoryBuilder, + recommendedActivityListBuilder + ) + } + } } return recommendedActivityListBuilder.build() @@ -257,24 +271,19 @@ class TopicListController @Inject constructor( ) { // If no recently played stories or last played stories then set suggested stories // in RecommendedActivityList. - when { - recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 -> { - recommendedStoryBuilder.addAllSuggestedStory( - createRecommendedStoryList( - topicProgressList, - recommendedActivityListBuilder, - recommendedStoryBuilder - ) - ) - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + recommendedStoryBuilder.addAllSuggestedStory( + createRecommendedStoryList( + topicProgressList, + recommendedActivityListBuilder, + recommendedStoryBuilder + ) + ) + recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - // If user has completed all the topics then add upcoming topics in - // RecommendedActivityList. - if (recommendedStoryBuilder.suggestedStoryCount == 0) { - recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() - } - } + // If user has completed all the topics then add upcoming topics in + // RecommendedActivityList. + if (recommendedStoryBuilder.suggestedStoryCount == 0) { + recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } } @@ -362,8 +371,7 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = - (recentlyPlayerChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS + val numberOfDaysPassed = recentlyPlayerChapterProgress.getNumberOfDaysPassed() addPromotedStoryInRecommendedStoryList( numberOfDaysPassed, recommendedStoryBuilder, @@ -390,25 +398,26 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] - if (nextChapterSummary != null) { - val numberOfDaysPassed = - (mostRecentCompletedChapterProgress.getNumberOfDaysPassed()) / ONE_DAY_IN_MS - addPromotedStoryInRecommendedStoryList( - numberOfDaysPassed, - recommendedStoryBuilder, - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId - ) + if(story.chapterList.size > nextChapterIndex) { + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() + addPromotedStoryInRecommendedStoryList( + numberOfDaysPassed, + recommendedStoryBuilder, + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId + ) + } } } private fun addPromotedStoryInRecommendedStoryList( - numberOfDaysPassed: Int, + numberOfDaysPassed: Long, recommendedStoryBuilder: RecommendedStoryList.Builder, storyId: String, topic: Topic, @@ -432,10 +441,10 @@ class TopicListController @Inject constructor( } } - private fun ChapterProgress.getNumberOfDaysPassed(): Int { + private fun ChapterProgress.getNumberOfDaysPassed(): Long { return TimeUnit.MILLISECONDS.toDays( oppiaClock.getCurrentCalendar().timeInMillis - this.lastPlayedTimestamp - ).toInt() + ) } private fun createRecommendedStoryList( diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index f9f31c52df4..6ccafde8478 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -537,34 +537,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveComingSoonTopicList_markFirstStoryOfEveryTopicDoneWithinLastSevenDays_comingSoonListIsCorrect() { // ktlint-disable max-line-length - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - RATIOS_TOPIC_ID, - RATIOS_STORY_ID_0, - RATIOS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - + fun testRetrieveComingSoonTopicList_markFirstStoryOfRatiosTopicDoneWithinLastSevenDays_comingSoonListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, From 685ffb71f082d905c1e7951d1d6c0588da0cd411 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 12 Jan 2021 01:34:25 +0530 Subject: [PATCH 165/248] Update StoryProgressController.kt --- .../domain/topic/StoryProgressController.kt | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index a0a3da63bb0..67973f22533 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -123,15 +123,6 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() -// val topicProgressStories = topicProgressBuilder.storyProgressMap.values -// val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } -// val topicProgressLastPlayedTimes = -// topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) -// val lastPlayedTimestamp = -// topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. -// if (lastPlayedTimestamp != null) { -// topicProgressBuilder.lastPlayedTimestamp = lastPlayedTimestamp -// } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) @@ -214,15 +205,6 @@ class StoryProgressController @Inject constructor( topicProgressBuilder.putStoryProgress(storyId, storyProgress) val topicProgress = topicProgressBuilder.build() -// val topicProgressStories = topicProgressBuilder.storyProgressMap.values -// val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } -// val topicProgressLastPlayedTimes = -// topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) -// val computedLastPlayedTimestamp = -// topicProgressLastPlayedTimes.max() // Note this is null if there's no progress. -// if (computedLastPlayedTimestamp != null) { -// topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp -// } val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) From 39c7beb37e6c7c52b5e5a37cabaa5dfa4d524084 Mon Sep 17 00:00:00 2001 From: Veena Date: Tue, 12 Jan 2021 21:43:36 +0530 Subject: [PATCH 166/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 46d6ee0be6d..8c1a63dce86 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -236,7 +236,7 @@ class StoryProgressTestHelper @Inject constructor( } /** - * Marks full topic progress on SecondTestTopic for a particular profile. + * Marks full topic progress on the second test topic for a particular profile. * * @param profileId The profile we are setting topic progress for. * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than From 5c1959d032e0a07775c8696b4d9a2aee52f584d6 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 12 Jan 2021 23:51:18 +0530 Subject: [PATCH 167/248] fixing nit changes --- .../oppia/android/app/home/HomeViewModel.kt | 1 - .../domain/topic/StoryProgressController.kt | 1 - .../domain/topic/TopicListController.kt | 18 +++++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 0ae6fd9f527..c4c99679313 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -12,7 +12,6 @@ import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel -import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 67973f22533..4fc8927cea4 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -112,7 +112,6 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = TopicProgress.newBuilder() .setTopicId(topicId).setLastPlayedTimestamp(completionTimestamp) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index a8f99fe2762..4b37471cea2 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -251,13 +251,14 @@ class TopicListController @Inject constructor( // If the Recently-played or Older-played story list is empty then populate Suggested // stories or Upcoming stories if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 ){ - populateRecommendedStories( - topicProgressList, - recommendedStoryBuilder, - recommendedActivityListBuilder - ) - } + recommendedStoryBuilder.olderPlayedStoryCount == 0 + ) { + populateRecommendedStories( + topicProgressList, + recommendedStoryBuilder, + recommendedActivityListBuilder + ) + } } } @@ -306,7 +307,6 @@ class TopicListController @Inject constructor( completedChapterProgressList.firstOrNull() val startedChapterProgressList = getStartedChapterProgressList(storyProgress) - val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() @@ -398,7 +398,7 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 - if(story.chapterList.size > nextChapterIndex) { + if (story.chapterList.size > nextChapterIndex) { val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { val numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() From 597c3bf1d1a46f53c53794dbdfbe19d63364297b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 12 Jan 2021 23:52:04 +0530 Subject: [PATCH 168/248] Update HomeViewModel.kt --- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index c4c99679313..0ae6fd9f527 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -12,6 +12,7 @@ import org.oppia.android.app.home.promotedlist.PromotedStoryViewModel import org.oppia.android.app.home.topiclist.AllTopicsViewModel import org.oppia.android.app.home.topiclist.TopicSummaryClickListener import org.oppia.android.app.home.topiclist.TopicSummaryViewModel +import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.Profile import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.TopicList From ccac3da7349ee1c65c9acf31cc9a98d1d8a45929 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 10:34:57 -0800 Subject: [PATCH 169/248] Address comments for HomeActivityTest --- .../android/app/home/HomeActivityTest.kt | 103 +++++++++--------- 1 file changed, 50 insertions(+), 53 deletions(-) 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 460cdbe8fe9..3cc9b9c2b34 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 @@ -484,16 +484,13 @@ class HomeActivityTest { @Test fun testHomeActivity_allTopicsCompleted_hidesPromotedStories() { storyProgressTestHelper.markFullProgressForAllTopics( - ProfileId.newBuilder().setInternalId(internalProfileId).build(), + getProfileId(internalProfileId), timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() - launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) + scrollToPosition(position = 1) onView( atPositionOnView( R.id.home_recycler_view, @@ -506,31 +503,23 @@ class HomeActivityTest { @Test fun testHomeActivity_partialProgressForFractionsAndRatios_showsRecentlyPlayedStories() { + val profileId = getProfileId(internalProfileId) storyProgressTestHelper.markPartialTopicProgressForFractions( - ProfileId.newBuilder().setInternalId(internalProfileId).build(), + profileId = profileId, timestampOlderThanAWeek = false ) storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - ProfileId.newBuilder().setInternalId(internalProfileId).build(), + profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() - launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(1) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 1, - R.id.recently_played_stories_text_view - ) - ).check( - matches( - withText(R.string.recently_played_stories) - ) + scrollToPosition(position = 1) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 1, + targetViewId = R.id.recently_played_stories_text_view, + stringToMatch = context.getString(R.string.recently_played_stories) ) } } @@ -538,23 +527,17 @@ class HomeActivityTest { @Test fun testHomeActivity_allTopicsCompleted_displaysAllTopicsHeader() { storyProgressTestHelper.markFullProgressForAllTopics( - ProfileId.newBuilder().setInternalId(internalProfileId).build(), + profileId = getProfileId(internalProfileId), timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(2) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 2, - R.id.all_topics_text_view - ) - ).check( - matches(withText(R.string.all_topics)) + scrollToPosition(position = 2) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 2, + targetViewId = R.id.all_topics_text_view, + stringToMatch = context.getString((R.string.all_topics)) ) } } @@ -562,15 +545,13 @@ class HomeActivityTest { @Test fun testHomeActivity_allTopicsCompleted_displaysAllTopicCards() { storyProgressTestHelper.markFullProgressForAllTopics( - ProfileId.newBuilder().setInternalId(internalProfileId).build(), + profileId = getProfileId(internalProfileId), timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(3) - ) + scrollToPosition(position = 3) onView(withId(R.id.home_recycler_view)).check( // The "All Topics" section currently should display the four test topics in two rows. hasGridColumnCount(2) @@ -584,33 +565,45 @@ class HomeActivityTest { profileTestHelper.loginToNewUser() launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(2) - ) - onView( - atPositionOnView( - R.id.home_recycler_view, - 2, - R.id.all_topics_text_view - ) - ).check( - matches(withText(R.string.all_topics)) + scrollToPosition(position = 2) + verifyExactTextOnHomeListItemAtPosition( + itemPosition = 2, + targetViewId = R.id.all_topics_text_view, + stringToMatch = context.getString((R.string.all_topics)) ) } } @Test - fun testHomeActivity_noTopicsStarted_displaysAllTopicCards() { + fun testHomeActivity_noTopicsStarted_displaysAllTopicCardsInPortrait() { // Only new users will have no progress for any topics. profileTestHelper.loginToNewUser() launch(createHomeActivityIntent(internalProfileId)).use { testCoroutineDispatchers.runCurrent() - onView(withId(R.id.home_recycler_view)).perform( - scrollToPosition(3) + scrollToPosition(position = 3) + onView(withId(R.id.home_recycler_view)).check( + // The "All Topics" section currently should display all four test topics in two rows. + hasGridColumnCount(expectedColumnCount = 2) ) + } + } + + @Test + fun testHomeActivity_noTopicsStarted_displaysAllTopicCardsInLandscape() { + // Only new users will have no progress for any topics. + profileTestHelper.loginToNewUser() + launch(createHomeActivityIntent(internalProfileId)).use { + testCoroutineDispatchers.runCurrent() + onView(isRoot()).perform(orientationLandscape()) + scrollToPosition(position = 3) + var rowsUsed = 2 + if (context.resources.getBoolean(R.bool.isTablet)) { + // A landscape tablet can display the four test topics in one row. + rowsUsed = 1 + } onView(withId(R.id.home_recycler_view)).check( - // The "All Topics" section currently should display the four test topics in two rows. - hasGridColumnCount(2) + // The "All Topics" section currently should display all four test topics. + hasGridColumnCount(expectedColumnCount = rowsUsed) ) } } @@ -655,6 +648,10 @@ class HomeActivityTest { ).check(matches(withText(stringToMatch))) } + private fun getProfileId(internalProfileId: Int): ProfileId { + return ProfileId.newBuilder().setInternalId(internalProfileId).build() + } + // 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 From 1d6624859f6137b4970dd082842367f94232caca Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 10:47:27 -0800 Subject: [PATCH 170/248] Import ActivityScenario.launch for view model tests --- .../app/home/TopicSummaryViewModelTest.kt | 23 +++++++++--------- .../PromotedStoryListViewModelTest.kt | 20 ++++++++-------- .../PromotedStoryViewModelTest.kt | 24 +++++++++---------- 3 files changed, 34 insertions(+), 33 deletions(-) diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt index f09d7d4c4b5..9357141676c 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/TopicSummaryViewModelTest.kt @@ -3,7 +3,7 @@ package org.oppia.android.app.home import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat @@ -67,6 +67,7 @@ private const val TEST_FRAGMENT_TAG = "topic_summary_view_model_test_fragment" manifest = Config.NONE ) class TopicSummaryViewModelTest { + @Inject lateinit var context: Context @@ -90,7 +91,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_reflexiveBasicTopicSummaryViewModel_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -105,7 +106,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_symmetricBasicTopicSummaryViewModel_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -122,7 +123,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_transitiveBasicSummaryViewModel_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -141,7 +142,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_consistentBasicTopicSummaryViewModel_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -159,7 +160,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_basicTopicSummaryViewModelAndNull_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -174,7 +175,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_topicSummary1AndTopicSummary2_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -202,7 +203,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_entity1AndEntity2_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -229,7 +230,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelEquals_position4AndPosition5_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -256,7 +257,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -273,7 +274,7 @@ class TopicSummaryViewModelTest { @Test fun testTopicSummaryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt index 129a81ed3b6..77c5b2e9ae1 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModelTest.kt @@ -3,7 +3,7 @@ package org.oppia.android.app.home.promotedlist import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat @@ -93,7 +93,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_reflexiveStoryListOf2_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -109,7 +109,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_symmetricStoryListOf2_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -131,7 +131,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_transitiveStoryListOf2_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -158,7 +158,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_consistentStoryListOf2_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -181,7 +181,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_storyListOf2AndNull_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -198,7 +198,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelEquals_storyListOf2AndStoryListOf3_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -218,7 +218,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -241,7 +241,7 @@ class PromotedStoryListViewModelTest { @Test fun testPromotedStoryListViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -268,7 +268,7 @@ class PromotedStoryListViewModelTest { ): List { return promotedStoryList.map { PromotedStoryViewModel( - activity, + activity = activity, internalProfileId = 1, totalStoryCount = promotedStoryList.size, entityType = "entity", diff --git a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt index 7a2989eeaa9..41b748812b1 100644 --- a/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt +++ b/app/src/sharedTest/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModelTest.kt @@ -3,7 +3,7 @@ package org.oppia.android.app.home.promotedlist import android.app.Application import android.content.Context import androidx.appcompat.app.AppCompatActivity -import androidx.test.core.app.ActivityScenario +import androidx.test.core.app.ActivityScenario.launch import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.google.common.truth.Truth.assertThat @@ -87,7 +87,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_reflexiveBasicPromotedStoryViewModel_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -101,7 +101,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_symmetricBasicPromotedStoryViewModels_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -117,7 +117,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_transitiveBasicPromotedStoryViewModels_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -135,7 +135,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_consistentBasicPromotedStoryViewModels_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -152,7 +152,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_basicPromotedStoryViewModelAndNull_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -165,7 +165,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_profileId1AndProfileId2_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -191,7 +191,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_storyCount2AndStoryCount3_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -218,7 +218,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_entity1AndEntity2_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -244,7 +244,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelEquals_story1AndStory2_isNotEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -272,7 +272,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelHashCode_viewModelsEqualHashCodesEqual_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { @@ -289,7 +289,7 @@ class PromotedStoryViewModelTest { @Test fun testPromotedStoryViewModelHashCode_sameViewModelHashCodeDoesNotChange_isEqual() { - ActivityScenario.launch( + launch( HomeFragmentTestActivity.createHomeFragmentTestActivity(context) ).use { it.onActivity { From 65173e2b41ea29e31882f2264e05a64c7d86bcaa Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 10:56:30 -0800 Subject: [PATCH 171/248] Use named parameters in StoryProgressTestHelperTest --- .../topic/StoryProgressTestHelperTest.kt | 136 +++++++++--------- 1 file changed, 68 insertions(+), 68 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index d46aee3a193..bf2c451aea7 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -126,8 +126,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markPartialStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -149,8 +149,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markPartialStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -171,8 +171,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markPartialStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -191,8 +191,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markPartialStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -209,8 +209,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -232,8 +232,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -254,8 +254,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -274,8 +274,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -292,8 +292,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -315,8 +315,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -335,8 +335,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -354,8 +354,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -373,8 +373,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullTopicProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -396,8 +396,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullTopicProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -416,8 +416,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullTopicProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -435,8 +435,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullTopicProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -454,8 +454,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -482,8 +482,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -502,8 +502,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForAllTopicsMoreThanOneWeek_ongoingTopicListEmpty() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ true + profileId = profileId, + timestampOlderThanOneWeek = true ) testCoroutineDispatchers.runCurrent() @@ -521,8 +521,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForAllTopicsLessThanOneWeek_ongoingTopicListEmpty() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ false + profileId = profileId, + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -540,8 +540,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_fullProgressAllTopicsMoreThanOneWk_completedStoryListHasSixStories() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ true + profileId = profileId, + timestampOlderThanOneWeek = true ) testCoroutineDispatchers.runCurrent() @@ -558,8 +558,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_fullProgressAllTopicsLessThanOneWk_completedStoryListHasSixStories() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ false + profileId = profileId, + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -576,8 +576,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForAllTopicsMoreThanOneWeek_topicListHasFourStories() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ true + profileId = profileId, + timestampOlderThanOneWeek = true ) testCoroutineDispatchers.runCurrent() @@ -594,8 +594,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForAllTopicsLessThanOneWeek_topicListHasFourStories() { storyProgressTestHelper.markFullProgressForAllTopics( - profileId, - /* timestampOlderThanOneWeek= */ false + profileId = profileId, + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -612,8 +612,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -632,8 +632,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialTopicProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -651,8 +651,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -678,8 +678,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -701,8 +701,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -721,8 +721,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -739,8 +739,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getOngoingStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -762,8 +762,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_getOngoingStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -785,8 +785,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0AndStory1Exp2_storyListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0AndStory1Exploration2( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -813,8 +813,8 @@ class StoryProgressTestHelperTest { @Test fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_ongoingStoryListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( - profileId, - /* timestampOlderThanAWeek= */ true + profileId = profileId, + timestampOlderThanAWeek = true ) testCoroutineDispatchers.runCurrent() From 83c99b10a6796784fbb91c2226477989656600df Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 11:02:09 -0800 Subject: [PATCH 172/248] Clarify new user used for no story progress in ProfileTestHelpr --- .../org/oppia/android/testing/profile/ProfileTestHelper.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt index ba87e7b1263..edbbc382d57 100644 --- a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt +++ b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt @@ -99,7 +99,10 @@ class ProfileTestHelper @Inject constructor( /** Login to user profile. */ fun loginToUser() = logIntoProfile(internalProfileId = 1) - /** Login to a new user profile, since profile #2 is not used as a default user anywhere in this helper. */ + /** + * Login to a new user profile that has no progress for any topics or stories. This relies on other + * tests utilizing profile 1 as the default user profile so that profile 2 never has any progress. + */ fun loginToNewUser() = logIntoProfile(internalProfileId = 2) private fun logIntoProfile(internalProfileId: Int): LiveData> { From 1f25997c95f713b6c87c8443cc4ff346efef4956 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 11:04:22 -0800 Subject: [PATCH 173/248] Order view model alphabetically --- app/BUILD.bazel | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/BUILD.bazel b/app/BUILD.bazel index d417ad20a97..bfb240f148a 100644 --- a/app/BUILD.bazel +++ b/app/BUILD.bazel @@ -123,9 +123,9 @@ VIEW_MODELS_WITH_RESOURCE_IMPORTS = [ "src/main/java/org/oppia/android/app/help/HelpListViewModel.kt", "src/main/java/org/oppia/android/app/help/faq/FAQListViewModel.kt", "src/main/java/org/oppia/android/app/home/HomeViewModel.kt", - "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt", "src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryViewModel.kt", + "src/main/java/org/oppia/android/app/home/topiclist/TopicSummaryViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboadingSlideViewModel.kt", "src/main/java/org/oppia/android/app/onboarding/OnboardingViewModel.kt", "src/main/java/org/oppia/android/app/parser/StringToFractionParser.kt", From 356e03e51143840ca3ee102a9fbf3b803b57e888 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 11:09:18 -0800 Subject: [PATCH 174/248] Add readability fixes from review --- app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt | 2 +- .../android/app/home/promotedlist/PromotedStoryListView.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 0ae6fd9f527..15ddce895f4 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -167,7 +167,7 @@ class HomeViewModel( position = topicIndex ) } - return if (!allTopicsList.isEmpty()) { + return if (allTopicsList.isNotEmpty()) { listOf(AllTopicsViewModel) + allTopicsList } else emptyList() } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 71110e46703..e5286e3698f 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -54,7 +54,7 @@ class PromotedStoryListView @JvmOverloads constructor( * after scrolling. */ val snapHelper = StartSnapHelper() - this.setOnFlingListener(null) + this.onFlingListener = null snapHelper.attachToRecyclerView(this) } } From 0641c8e4a06078fd3721173666834deb36fe83d1 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 11:12:25 -0800 Subject: [PATCH 175/248] Fix comments --- .../main/java/org/oppia/android/app/shim/ViewBindingShim.kt | 4 ++-- .../org/oppia/android/app/testing/HomeFragmentTestActivity.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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 f4e946bd288..802cb5459e9 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 @@ -48,14 +48,14 @@ interface ViewBindingShim { profileInputView: View ): TextView - /** Handles binding inflation for [PromotedStoryListView] */ + /** Handles binding inflation for [PromotedStoryListView]. */ fun inflatePromotedStoryCardBinding( inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean ): View - /** Handles binding inflation for [PromotedStoryListView] and returns the view model.*/ + /** Handles binding inflation for [PromotedStoryListView] and returns the view model. */ fun providePromotedStoryViewModel( view: View, viewModel: PromotedStoryViewModel diff --git a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt index 00a6a6cf45c..8776b9ff57d 100644 --- a/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt +++ b/app/src/main/java/org/oppia/android/app/testing/HomeFragmentTestActivity.kt @@ -11,7 +11,7 @@ import org.oppia.android.app.home.RouteToTopicPlayStoryListener /** * Test Activity for testing view models on the [HomeFragment]. - * This activity must implement listeners so the test can use it as a [HomeFragmnet]. + * This activity must implement listeners so the tests can use it as a [HomeFragment]. */ class HomeFragmentTestActivity : RouteToTopicListener, From 86a2a36b130b212ec3c7501d6b5df52a86946fd3 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Tue, 12 Jan 2021 19:39:33 -0800 Subject: [PATCH 176/248] Add dummy data in promoted story list view to appropriately initiate adapter creation --- .../promotedlist/PromotedStoryListView.kt | 38 +++++++++++-------- .../PromotedStoryListViewModel.kt | 10 +++++ .../oppia/android/app/shim/ViewBindingShim.kt | 3 +- .../android/app/shim/ViewBindingShimImpl.kt | 6 +-- .../res/layout-land/promoted_story_list.xml | 1 + .../promoted_story_list.xml | 1 + .../promoted_story_list.xml | 1 + .../main/res/layout/promoted_story_list.xml | 3 ++ 8 files changed, 43 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index e5286e3698f..4bce4c89aef 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -24,6 +24,7 @@ class PromotedStoryListView @JvmOverloads constructor( @Inject lateinit var bindingInterface: ViewBindingShim + private lateinit var listType: PromotedActivityType override fun onAttachedToWindow() { super.onAttachedToWindow() @@ -31,30 +32,37 @@ class PromotedStoryListView @JvmOverloads constructor( (FragmentManager.findFragment(this) as ViewComponentFactory) .createViewComponent(this).inject(this) - adapter = BindableAdapter.SingleTypeBuilder.newBuilder() + /* + * The StartSnapHelper is used to snap between items rather than smooth scrolling, so that + * the item is completely visible in [HomeFragment] as soon as learner lifts the finger + * after scrolling. + */ + val snapHelper = StartSnapHelper() + this.onFlingListener = null + snapHelper.attachToRecyclerView(this) + } + + private fun createAdapter(): BindableAdapter { + return BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( inflateView = { parent -> - bindingInterface.inflatePromotedStoryCardBinding( - inflater = LayoutInflater.from(context), - parent = parent, - attachToParent = false + bindingInterface.providePromotedStoryCardInflatedView( + LayoutInflater.from(parent.context), + parent, + /* attachToParent= */ false ) }, bindView = { view, viewModel -> bindingInterface.providePromotedStoryViewModel( - view = view, - viewModel = viewModel + view, + viewModel ) } ).build() + } - /* - * The StartSnapHelper is used to snap between items rather than smooth scrolling, so that - * the item is completely visible in [HomeFragment] as soon as learner lifts the finger - * after scrolling. - */ - val snapHelper = StartSnapHelper() - this.onFlingListener = null - snapHelper.attachToRecyclerView(this) + fun setListType(type: PromotedActivityType) { + this.listType = type + adapter = createAdapter() } } diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index afe052b5ed9..4e2e7d9afc9 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -10,6 +10,10 @@ import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import java.util.Objects +enum class PromotedActivityType { + RECENTLY_PLAYED +} + /** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( private val activity: AppCompatActivity, @@ -28,6 +32,12 @@ class PromotedStoryListViewModel( activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) + /** Returns the type of PromotedActivity shown to the learner. */ + fun getListType(): PromotedActivityType { + // TODO: Update this when more activity types are implemented. + return PromotedActivityType.RECENTLY_PLAYED + } + /** Determines and returns the visibility for the "View All" button. */ fun getButtonVisibility(): Int { if (activity.resources.getBoolean(R.bool.isTablet)) { 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 396b84aa52d..1d23d947577 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 @@ -89,7 +89,7 @@ interface ViewBindingShim { fun getDefaultRegion(parentView: FrameLayout): View /** Handles binding inflation for [PromotedStoryListView]. */ - fun inflatePromotedStoryCardBinding( + fun providePromotedStoryCardInflatedView( inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean @@ -100,6 +100,7 @@ interface ViewBindingShim { view: View, viewModel: PromotedStoryViewModel ) + /** * Handles binding inflation for [SelectionInteractionView]'s ItemSelectionInteraction and * returns the binding's root. 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 63d0f5c3d0a..1c8eeea3c96 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 @@ -31,15 +31,13 @@ import javax.inject.Inject // TODO(#1619): Remove file post-Gradle class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { - override fun inflatePromotedStoryCardBinding( + override fun providePromotedStoryCardInflatedView( inflater: LayoutInflater, parent: ViewGroup, attachToParent: Boolean ): View { return PromotedStoryCardBinding.inflate( - LayoutInflater.from(parent.context), - parent, - attachToParent + LayoutInflater.from(parent.context), parent, /* attachToParent= */ false ).root } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 8d789dffe00..684d646b3bd 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -63,6 +63,7 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:listType="@{viewModel.getListType()}" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 63d902bc1f8..3a29a8d80a4 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -63,6 +63,7 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:listType="@{viewModel.getListType()}" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 184044bb647..4ad8383541c 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -63,6 +63,7 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:listType="@{viewModel.getListType()}" app:list="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 638eb0bcc44..dc8d127f84a 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -6,6 +6,8 @@ + + @@ -63,6 +65,7 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" + app:listType="@{viewModel.getListType()}" app:list="@{viewModel.promotedStoryList}" /> From b5c56f4d52de1028aae636698f9f709945dd79c9 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 14 Jan 2021 00:38:32 +0530 Subject: [PATCH 177/248] Merge commit 'refs/pull/2246/head' of https://github.com/oppia/oppia-android into refactor-topic-list-adapter-to-use-bindable-adapter-veena From 346fc1094aeba78fba4fc1e4e81a51cdaab2792b Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 13 Jan 2021 14:32:58 -0800 Subject: [PATCH 178/248] Use BindingAdapter on the data list of promtoed stories --- .../promotedlist/PromotedStoryListView.kt | 31 ++++++++++++++----- .../android/app/shim/ViewBindingShimImpl.kt | 2 +- .../res/layout-land/promoted_story_list.xml | 3 +- .../promoted_story_list.xml | 3 +- .../promoted_story_list.xml | 3 +- .../main/res/layout/promoted_story_list.xml | 3 +- 6 files changed, 29 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 4bce4c89aef..0e09b895c20 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,6 +3,7 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import androidx.databinding.BindingAdapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView @@ -24,7 +25,7 @@ class PromotedStoryListView @JvmOverloads constructor( @Inject lateinit var bindingInterface: ViewBindingShim - private lateinit var listType: PromotedActivityType + private var dataList: List = listOf() override fun onAttachedToWindow() { super.onAttachedToWindow() @@ -32,7 +33,7 @@ class PromotedStoryListView @JvmOverloads constructor( (FragmentManager.findFragment(this) as ViewComponentFactory) .createViewComponent(this).inject(this) - /* + /** * The StartSnapHelper is used to snap between items rather than smooth scrolling, so that * the item is completely visible in [HomeFragment] as soon as learner lifts the finger * after scrolling. @@ -42,6 +43,17 @@ class PromotedStoryListView @JvmOverloads constructor( snapHelper.attachToRecyclerView(this) } + /* Sets the list of promoted stories that this view shows to the learner. */ + fun setDataList(newDataList: List) { + // Update the adapter and the story list only if the list is new. The parent presenter should + // not render promoted stories if the list is empty, but default to showing the last list. + if (newDataList != null && !newDataList.isEmpty() && newDataList != dataList) { + dataList = newDataList + adapter = createAdapter() + (adapter as BindableAdapter).setDataUnchecked(newDataList) + } + } + private fun createAdapter(): BindableAdapter { return BindableAdapter.SingleTypeBuilder.newBuilder() .registerViewBinder( @@ -60,9 +72,14 @@ class PromotedStoryListView @JvmOverloads constructor( } ).build() } - - fun setListType(type: PromotedActivityType) { - this.listType = type - adapter = createAdapter() - } } + +/** + * Sets the list of promoted items for a specific [PromotedStoryListView] to show to the learner + * via data-binding. + * */ +@BindingAdapter("dataList") +fun setDataList( + promotedStoryListView: PromotedStoryListView, + newDataList: List +) = promotedStoryListView.setDataList(newDataList) 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 1c8eeea3c96..ff41e792dec 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 @@ -37,7 +37,7 @@ class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { attachToParent: Boolean ): View { return PromotedStoryCardBinding.inflate( - LayoutInflater.from(parent.context), parent, /* attachToParent= */ false + LayoutInflater.from(parent.context), parent, /* attachToParent= */ attachToParent ).root } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index 684d646b3bd..b3329f44e04 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -63,7 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:listType="@{viewModel.getListType()}" - app:list="@{viewModel.promotedStoryList}" /> + app:dataList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 3a29a8d80a4..20f80dd1ecc 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -63,7 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:listType="@{viewModel.getListType()}" - app:list="@{viewModel.promotedStoryList}" /> + app:dataList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 4ad8383541c..828d99603db 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -63,7 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:listType="@{viewModel.getListType()}" - app:list="@{viewModel.promotedStoryList}" /> + app:dataList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index dc8d127f84a..69173b8b049 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -65,7 +65,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:listType="@{viewModel.getListType()}" - app:list="@{viewModel.promotedStoryList}" /> + app:dataList="@{viewModel.promotedStoryList}" /> From 67eb4183b9363cee4b159ad503a3c82301efe2b8 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Wed, 13 Jan 2021 16:29:06 -0800 Subject: [PATCH 179/248] Remove static binding adapter for data-binding in promoted story list view --- .../home/promotedlist/PromotedStoryListView.kt | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index 0e09b895c20..a21db0f1696 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -3,7 +3,6 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater -import androidx.databinding.BindingAdapter import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView @@ -43,7 +42,11 @@ class PromotedStoryListView @JvmOverloads constructor( snapHelper.attachToRecyclerView(this) } - /* Sets the list of promoted stories that this view shows to the learner. */ + /** + * Sets the list of promoted stories that this view shows to the learner. + * + * @param newDataList the new list of stories to present + */ fun setDataList(newDataList: List) { // Update the adapter and the story list only if the list is new. The parent presenter should // not render promoted stories if the list is empty, but default to showing the last list. @@ -73,13 +76,3 @@ class PromotedStoryListView @JvmOverloads constructor( ).build() } } - -/** - * Sets the list of promoted items for a specific [PromotedStoryListView] to show to the learner - * via data-binding. - * */ -@BindingAdapter("dataList") -fun setDataList( - promotedStoryListView: PromotedStoryListView, - newDataList: List -) = promotedStoryListView.setDataList(newDataList) From e1e0703fe8d67b6cbae6e594ade38ed50260960a Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 14 Jan 2021 11:14:42 -0800 Subject: [PATCH 180/248] Address review comments --- .../oppia/android/app/home/HomeViewModel.kt | 6 +++- .../promotedlist/PromotedStoryListView.kt | 34 ++++++++++++------- .../PromotedStoryListViewModel.kt | 10 ------ .../android/app/shim/ViewBindingShimImpl.kt | 2 +- .../res/layout-land/promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../promoted_story_list.xml | 2 +- .../main/res/layout/promoted_story_list.xml | 2 +- 8 files changed, 31 insertions(+), 29 deletions(-) diff --git a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt index 15ddce895f4..8eb7d01cb01 100644 --- a/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/HomeViewModel.kt @@ -46,6 +46,10 @@ class HomeViewModel( private val profileId: ProfileId = ProfileId.newBuilder().setInternalId(internalProfileId).build() + private val promotedStoryListLimit = activity.resources.getInteger( + R.integer.promoted_story_list_limit + ) + private val profileDataProvider: DataProvider by lazy { profileManagementController.getProfile(profileId) } @@ -137,7 +141,7 @@ class HomeViewModel( // TODO(#936): Optimise this as part of recommended stories. ongoingStoryList.olderStoryList } - return storyList.take(R.integer.promoted_story_list_limit) + return storyList.take(promotedStoryListLimit) .map { promotedStory -> PromotedStoryViewModel( activity, diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt index a21db0f1696..36e2087c328 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListView.kt @@ -2,7 +2,9 @@ package org.oppia.android.app.home.promotedlist import android.content.Context import android.util.AttributeSet +import android.util.Log import android.view.LayoutInflater +import androidx.annotation.Nullable import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.recyclerview.widget.RecyclerView @@ -21,10 +23,10 @@ class PromotedStoryListView @JvmOverloads constructor( attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr) { + private val TAG = "PromotedStoryListView" @Inject lateinit var bindingInterface: ViewBindingShim - private var dataList: List = listOf() override fun onAttachedToWindow() { super.onAttachedToWindow() @@ -32,13 +34,11 @@ class PromotedStoryListView @JvmOverloads constructor( (FragmentManager.findFragment(this) as ViewComponentFactory) .createViewComponent(this).inject(this) - /** - * The StartSnapHelper is used to snap between items rather than smooth scrolling, so that - * the item is completely visible in [HomeFragment] as soon as learner lifts the finger - * after scrolling. - */ + // The StartSnapHelper is used to snap between items rather than smooth scrolling, so that + // the item is completely visible in [HomeFragment] as soon as learner lifts the finger + // after scrolling. val snapHelper = StartSnapHelper() - this.onFlingListener = null + onFlingListener = null snapHelper.attachToRecyclerView(this) } @@ -47,12 +47,20 @@ class PromotedStoryListView @JvmOverloads constructor( * * @param newDataList the new list of stories to present */ - fun setDataList(newDataList: List) { - // Update the adapter and the story list only if the list is new. The parent presenter should - // not render promoted stories if the list is empty, but default to showing the last list. - if (newDataList != null && !newDataList.isEmpty() && newDataList != dataList) { - dataList = newDataList + fun setPromotedStoryList(@Nullable newDataList: List) { + // To reliably bind data only after the adapter is created, we manually set the data so we can first + // check for the adapter; when using an existing [RecyclerViewBindingAdapter] there is no reliable + // way to check that the adapter is created. + // 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() + } + + if (newDataList == null || newDataList.isEmpty()) { + Log.w(TAG, ": failed to resolve new story list data") + } else { + // Only re-bind and display the data if it's a valid list of promoted items for learners (adapter as BindableAdapter).setDataUnchecked(newDataList) } } @@ -64,7 +72,7 @@ class PromotedStoryListView @JvmOverloads constructor( bindingInterface.providePromotedStoryCardInflatedView( LayoutInflater.from(parent.context), parent, - /* attachToParent= */ false + attachToParent = false ) }, bindView = { view, viewModel -> diff --git a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt index 4e2e7d9afc9..afe052b5ed9 100644 --- a/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt +++ b/app/src/main/java/org/oppia/android/app/home/promotedlist/PromotedStoryListViewModel.kt @@ -10,10 +10,6 @@ import org.oppia.android.app.home.HomeItemViewModel import org.oppia.android.app.home.RouteToRecentlyPlayedListener import java.util.Objects -enum class PromotedActivityType { - RECENTLY_PLAYED -} - /** [ViewModel] for the promoted story list displayed in [HomeFragment]. */ class PromotedStoryListViewModel( private val activity: AppCompatActivity, @@ -32,12 +28,6 @@ class PromotedStoryListViewModel( activity.resources.getDimensionPixelSize(R.dimen.home_padding_end) else activity.resources.getDimensionPixelSize(R.dimen.home_padding_start) - /** Returns the type of PromotedActivity shown to the learner. */ - fun getListType(): PromotedActivityType { - // TODO: Update this when more activity types are implemented. - return PromotedActivityType.RECENTLY_PLAYED - } - /** Determines and returns the visibility for the "View All" button. */ fun getButtonVisibility(): Int { if (activity.resources.getBoolean(R.bool.isTablet)) { 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 ff41e792dec..11b1e6b562f 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 @@ -37,7 +37,7 @@ class ViewBindingShimImpl @Inject constructor() : ViewBindingShim { attachToParent: Boolean ): View { return PromotedStoryCardBinding.inflate( - LayoutInflater.from(parent.context), parent, /* attachToParent= */ attachToParent + LayoutInflater.from(parent.context), parent, attachToParent ).root } diff --git a/app/src/main/res/layout-land/promoted_story_list.xml b/app/src/main/res/layout-land/promoted_story_list.xml index b3329f44e04..dc80008c345 100755 --- a/app/src/main/res/layout-land/promoted_story_list.xml +++ b/app/src/main/res/layout-land/promoted_story_list.xml @@ -63,6 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:dataList="@{viewModel.promotedStoryList}" /> + app:promotedStoryList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml index 20f80dd1ecc..06b2a34b6ff 100644 --- a/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-land/promoted_story_list.xml @@ -63,6 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:dataList="@{viewModel.promotedStoryList}" /> + app:promotedStoryList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml index 828d99603db..64bbb87f29b 100644 --- a/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml +++ b/app/src/main/res/layout-sw600dp-port/promoted_story_list.xml @@ -63,6 +63,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:dataList="@{viewModel.promotedStoryList}" /> + app:promotedStoryList="@{viewModel.promotedStoryList}" /> diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 69173b8b049..615c721bf15 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -65,6 +65,6 @@ android:paddingStart="@dimen/home_padding_start" android:paddingEnd="@{viewModel.endPadding}" app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" - app:dataList="@{viewModel.promotedStoryList}" /> + app:promotedStoryList="@{viewModel.promotedStoryList}" /> From f67521e45aba5f467086c35741521f470e205904 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 15 Jan 2021 00:59:27 +0530 Subject: [PATCH 181/248] updated --- .../domain/topic/TopicListController.kt | 50 +++--- .../domain/topic/TopicListControllerTest.kt | 161 ++++++++++++------ 2 files changed, 132 insertions(+), 79 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 4b37471cea2..57273f6f678 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -9,8 +9,8 @@ import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.PromotedStory -import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.RecommendedStoryList import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.StorySummary @@ -111,13 +111,13 @@ class TopicListController @Inject constructor( * * @param profileId the ID corresponding to the profile for which [PromotedStory] needs to be * fetched. - * @return a [DataProvider] for an [RecommendedActivityList]. + * @return a [DataProvider] for an [PromotedActivityList]. */ - fun getRecommendedActivityList(profileId: ProfileId): DataProvider { + fun getPromotedActivityList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) .transformAsync(GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID) { - val recommendedActivityList = createRecommendedActivityList(it) - AsyncResult.success(recommendedActivityList) + val PromotedActivityList = createPromotedActivityList(it) + AsyncResult.success(PromotedActivityList) } } @@ -216,10 +216,10 @@ class TopicListController @Inject constructor( .build() } - private fun createRecommendedActivityList( + private fun createPromotedActivityList( topicProgressList: List - ): RecommendedActivityList { - val recommendedActivityListBuilder = RecommendedActivityList.newBuilder() + ): PromotedActivityList { + val PromotedActivityListBuilder = PromotedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { val recommendedStoryBuilder = RecommendedStoryList.newBuilder() @@ -229,23 +229,23 @@ class TopicListController @Inject constructor( recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList, - recommendedActivityListBuilder, + PromotedActivityListBuilder, recommendedStoryBuilder ) ) - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) if (recommendedStoryBuilder.suggestedStoryCount == 0 && recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && recommendedStoryBuilder.olderPlayedStoryCount == 0 ) { - recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() + PromotedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } } else { - // Add recently played stories or last played stories in RecommendedActivityList. + // Add recently played stories or last played stories in PromotedActivityList. populateRecentlyPlayedStories( topicProgressList, - recommendedActivityListBuilder, + PromotedActivityListBuilder, recommendedStoryBuilder ) // If the Recently-played or Older-played story list is empty then populate Suggested @@ -256,41 +256,41 @@ class TopicListController @Inject constructor( populateRecommendedStories( topicProgressList, recommendedStoryBuilder, - recommendedActivityListBuilder + PromotedActivityListBuilder ) } } } - return recommendedActivityListBuilder.build() + return PromotedActivityListBuilder.build() } private fun populateRecommendedStories( topicProgressList: List, recommendedStoryBuilder: RecommendedStoryList.Builder, - recommendedActivityListBuilder: RecommendedActivityList.Builder + PromotedActivityListBuilder: PromotedActivityList.Builder ) { // If no recently played stories or last played stories then set suggested stories - // in RecommendedActivityList. + // in PromotedActivityList. recommendedStoryBuilder.addAllSuggestedStory( createRecommendedStoryList( topicProgressList, - recommendedActivityListBuilder, + PromotedActivityListBuilder, recommendedStoryBuilder ) ) - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) // If user has completed all the topics then add upcoming topics in - // RecommendedActivityList. + // PromotedActivityList. if (recommendedStoryBuilder.suggestedStoryCount == 0) { - recommendedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() + PromotedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() } } private fun populateRecentlyPlayedStories( topicProgressList: List, - recommendedActivityListBuilder: RecommendedActivityList.Builder, + PromotedActivityListBuilder: PromotedActivityList.Builder, recommendedStoryBuilder: RecommendedStoryList.Builder ) { val sortedTopicProgressList = @@ -335,7 +335,7 @@ class TopicListController @Inject constructor( } } } - recommendedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) } } @@ -449,14 +449,14 @@ class TopicListController @Inject constructor( private fun createRecommendedStoryList( topicProgressList: List, - recommendedActivityListBuilder: RecommendedActivityList.Builder, + PromotedActivityListBuilder: PromotedActivityList.Builder, recommendedStoryBuilder: RecommendedStoryList.Builder ): List { val recommendedStories = mutableListOf() populateRecentlyPlayedStories( topicProgressList, - recommendedActivityListBuilder, + PromotedActivityListBuilder, recommendedStoryBuilder ) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 148b61cf5cf..e4955e4193e 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -23,8 +23,8 @@ import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.PromotedStory -import org.oppia.android.app.model.RecommendedActivityList import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary import org.oppia.android.domain.oppialogger.LogStorageModule @@ -78,14 +78,14 @@ class TopicListControllerTest { lateinit var mockTopicListObserver: Observer> @Mock - lateinit var mockRecommendedActivityListObserver: Observer> + lateinit var mockPromotedActivityListObserver: Observer> @Captor lateinit var topicListResultCaptor: ArgumentCaptor> @Captor - lateinit var recommendedActivityListResultCaptor: - ArgumentCaptor> + lateinit var promotedActivityListResultCaptor: + ArgumentCaptor> private lateinit var profileId0: ProfileId @@ -101,7 +101,7 @@ class TopicListControllerTest { // TODO(#15): Add tests for recommended lessons rather than promoted, and tests for the 'continue playing' LiveData // not providing any data for cases when there are no ongoing lessons. Also, add tests for other uncovered cases - // (such as having and not having lessons in either of the RecommendedActivityList section, or AsyncResult errors). + // (such as having and not having lessons in either of the PromotedActivityList section, or AsyncResult errors). @Test fun testRetrieveTopicList_isSuccessful() { @@ -230,11 +230,11 @@ class TopicListControllerTest { @Test fun testRetrieveOngoingStoryList_defaultLesson_hasCorrectInfo() { - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getPromotedActivityList(profileId0).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifygetPromotedActivityListSucceeded() verifyDefaultOngoingStoryListSucceeded() } @@ -248,9 +248,11 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recentStoryList[0]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[0]) + } } @Test @@ -263,9 +265,11 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) + } } @Test @@ -287,9 +291,11 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) + } } @Test @@ -311,9 +317,11 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(4) - verifyDefaultOngoingStoryListSucceeded() + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(4) + verifyDefaultOngoingStoryListSucceeded() + } } @Test @@ -335,10 +343,12 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) + } } @Test @@ -360,10 +370,12 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(ongoingTopicList.recentStoryList[1]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) + } } @Test @@ -394,11 +406,13 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(3) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.recentStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[2]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(3) + verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[1]) + verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[2]) + } } @Test @@ -429,29 +443,33 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val ongoingTopicList = retrieveOngoingStoryList() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(1) - assertThat(ongoingTopicList.olderStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(ongoingTopicList.olderStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(ongoingTopicList.olderStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(ongoingTopicList.recentStoryList[0]) + val promotedStoryList = retrieveOngoingStoryList() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(1) + assertThat(olderPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration1(olderPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory0Exploration1(olderPlayedStoryList[1]) + verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[0]) + } } - private fun verifyGetOngoingStoryListSucceeded() { + private fun verifygetPromotedActivityListSucceeded() { verify( - mockOngoingStoryListObserver, + mockPromotedActivityListObserver, atLeastOnce() - ).onChanged(ongoingStoryListResultCaptor.capture()) - assertThat(ongoingStoryListResultCaptor.value.isSuccess()).isTrue() + ).onChanged(promotedActivityListResultCaptor.capture()) + assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } private fun verifyDefaultOngoingStoryListSucceeded() { - val ongoingTopicList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingTopicList.recentStoryCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(ongoingTopicList.recentStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(ongoingTopicList.recentStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration0(ongoingTopicList.recentStoryList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(ongoingTopicList.recentStoryList[3]) + val promotedStoryList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedStoryList.recommendedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(4) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsSecondTopicStory0Exploration0(recentlyPlayedStoryList[1]) + verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[2]) + verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[3]) + } } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { @@ -465,6 +483,29 @@ class TopicListControllerTest { assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyOngoingStoryAsSecondTopicStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) + assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) + assertThat(promotedStory.topicName).isEqualTo("Second Test Topic") + assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(1) + } + + private fun verifyPromotedStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) + assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) + assertThat(promotedStory.topicName).isEqualTo("Fractions") + assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } private fun verifyOngoingStoryAsFractionStory0Exploration1(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_1) @@ -501,6 +542,18 @@ class TopicListControllerTest { assertThat(promotedStory.completedChapterCount).isEqualTo(1) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + + private fun verifyOngoingStoryAsRatioStory1Exploration2(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_2) + assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_1) + assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) + assertThat(promotedStory.nextChapterName).isEqualTo("Equivalent Ratios") + assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } private fun verifyOngoingStoryAsRatioStory1Exploration3(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_3) @@ -531,13 +584,13 @@ class TopicListControllerTest { return topicListResultCaptor.value.getOrThrow() } - private fun retrieveOngoingStoryList(): OngoingStoryList { + private fun retrieveOngoingStoryList(): PromotedActivityList { testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId0).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getPromotedActivityList(profileId0).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() - return ongoingStoryListResultCaptor.value.getOrThrow() + verifygetPromotedActivityListSucceeded() + return promotedActivityListResultCaptor.value.getOrThrow() } // TODO(#89): Move this to a common test application component. From 60c9cfc81f1bd946746f0ffcd52167eee6fc5b31 Mon Sep 17 00:00:00 2001 From: jacqueli Date: Thu, 14 Jan 2021 11:31:15 -0800 Subject: [PATCH 182/248] Remove extra space in layout --- app/src/main/res/layout/promoted_story_list.xml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 615c721bf15..6807e95300b 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -5,9 +5,7 @@ - - - + From de22e9a9baa66cbfaa963dc872eae80c5f03f98c Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 18 Jan 2021 16:41:57 +0530 Subject: [PATCH 183/248] updated topic ontroller --- .../domain/topic/TopicListController.kt | 264 ++++++++++-------- model/src/main/proto/topic.proto | 18 +- 2 files changed, 157 insertions(+), 125 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 57273f6f678..880ccfa35b7 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -11,7 +11,7 @@ import org.oppia.android.app.model.LessonThumbnailGraphic import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.PromotedStory -import org.oppia.android.app.model.RecommendedStoryList +import org.oppia.android.app.model.PromotedStoryList import org.oppia.android.app.model.StoryProgress import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic @@ -79,7 +79,7 @@ val EXPLORATION_THUMBNAILS = mapOf( ) private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" -private const val GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID = +private const val GET_PROMOTED_ACTIVITY_LIST_PROVIDER_ID = "get_recommended_actvity_list_provider_id" private val EVICTION_TIME_MILLIS = TimeUnit.DAYS.toMillis(1) @@ -93,6 +93,9 @@ class TopicListController @Inject constructor( private val dataProviders: DataProviders, private val oppiaClock: OppiaClock ) { + + private var completedStoryTopicId: String = "" + /** * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to * [EVICTION_TIME_MILLIS] old. @@ -115,9 +118,9 @@ class TopicListController @Inject constructor( */ fun getPromotedActivityList(profileId: ProfileId): DataProvider { return storyProgressController.retrieveTopicProgressListDataProvider(profileId) - .transformAsync(GET_RECOMMENDED_ACTIVITY_LIST_PROVIDER_ID) { - val PromotedActivityList = createPromotedActivityList(it) - AsyncResult.success(PromotedActivityList) + .transformAsync(GET_PROMOTED_ACTIVITY_LIST_PROVIDER_ID) { + val promotedActivityList = computePromotedActivityList(it) + AsyncResult.success(promotedActivityList) } } @@ -136,7 +139,7 @@ class TopicListController @Inject constructor( return topicListBuilder.build() } - private fun createComingSoonTopicList(): ComingSoonTopicList { + private fun computeComingSoonTopicList(): ComingSoonTopicList { val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") @@ -216,88 +219,88 @@ class TopicListController @Inject constructor( .build() } - private fun createPromotedActivityList( - topicProgressList: List - ): PromotedActivityList { - val PromotedActivityListBuilder = PromotedActivityList.newBuilder() - + private fun computePromotedActivityList(topicProgressList: List): PromotedActivityList { + val promotedActivityListBuilder = PromotedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { - val recommendedStoryBuilder = RecommendedStoryList.newBuilder() - // If initially only one topic is in progress populate combination of Ongoing story - // and Suggested stories. - if (topicProgressList.size == 1) { - recommendedStoryBuilder.addAllSuggestedStory( - createRecommendedStoryList( - topicProgressList, - PromotedActivityListBuilder, - recommendedStoryBuilder - ) - ) - PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - - if (recommendedStoryBuilder.suggestedStoryCount == 0 && - recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 - ) { - PromotedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() - } - } else { - // Add recently played stories or last played stories in PromotedActivityList. - populateRecentlyPlayedStories( - topicProgressList, - PromotedActivityListBuilder, - recommendedStoryBuilder - ) - // If the Recently-played or Older-played story list is empty then populate Suggested - // stories or Upcoming stories - if (recommendedStoryBuilder.recentlyPlayedStoryCount == 0 && - recommendedStoryBuilder.olderPlayedStoryCount == 0 - ) { - populateRecommendedStories( - topicProgressList, - recommendedStoryBuilder, - PromotedActivityListBuilder - ) - } - + promotedActivityListBuilder.promotedStoryList = computePromotedStoryList(topicProgressList) + if (promotedActivityListBuilder.promotedStoryList.getTotalPromotedStoryCount() == 0) { + promotedActivityListBuilder.comingSoonTopicList = computeComingSoonTopicList() } } - return PromotedActivityListBuilder.build() + return promotedActivityListBuilder.build() } - private fun populateRecommendedStories( - topicProgressList: List, - recommendedStoryBuilder: RecommendedStoryList.Builder, - PromotedActivityListBuilder: PromotedActivityList.Builder - ) { - // If no recently played stories or last played stories then set suggested stories - // in PromotedActivityList. - recommendedStoryBuilder.addAllSuggestedStory( - createRecommendedStoryList( - topicProgressList, - PromotedActivityListBuilder, - recommendedStoryBuilder + private fun computePromotedStoryList(topicProgressList: List): PromotedStoryList { + val promotedStoryListBuilder = PromotedStoryList.newBuilder() + promotedStoryListBuilder + .addAllUpTo( + populateRecentlyPlayedStories(topicProgressList), + PromotedStoryList.Builder::addAllRecentlyPlayedStory, + limit = 3 + ) + .addAllUpTo( + populateOlderPlayedStories(topicProgressList), + PromotedStoryList.Builder::addAllOlderPlayedStory, + limit = 3 + ) + .addAllUpTo( + computeSuggestedStories(topicProgressList), + PromotedStoryList.Builder::addAllSuggestedStory, + limit = 3 ) - ) - PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) - // If user has completed all the topics then add upcoming topics in - // PromotedActivityList. - if (recommendedStoryBuilder.suggestedStoryCount == 0) { - PromotedActivityListBuilder.comingSoonTopicList = createComingSoonTopicList() - } + return promotedStoryListBuilder.build() + } + + private fun PromotedStoryList.getTotalPromotedStoryCount(): Int { + return recentlyPlayedStoryList.size + olderPlayedStoryList.size + suggestedStoryList.size + } + + private fun PromotedStoryList.Builder.getTotalPromotedStoryCount(): Int { + return recentlyPlayedStoryList.size + olderPlayedStoryList.size + suggestedStoryList.size + } + + private fun PromotedStoryList.Builder.addAllUpTo( + iterable: Iterable, + addAll: PromotedStoryList.Builder.(Iterable) -> PromotedStoryList.Builder, + limit: Int + ): PromotedStoryList.Builder { + return this.addAll(iterable.take(limit - this.getTotalPromotedStoryCount())) } private fun populateRecentlyPlayedStories( - topicProgressList: List, - PromotedActivityListBuilder: PromotedActivityList.Builder, - recommendedStoryBuilder: RecommendedStoryList.Builder - ) { + topicProgressList: List + ): List { + computePromotedStories(topicProgressList).let { + Pair(it.first, it.second) + if (it.second < ONE_WEEK_IN_DAYS) + return it.first + } + return emptyList() + } + + private fun populateOlderPlayedStories( + topicProgressList: List + ): List { + computePromotedStories(topicProgressList).let { + Pair(it.first, it.second) + if (it.second > ONE_WEEK_IN_DAYS) + return it.first + } + return emptyList() + } + + private fun computePromotedStories( + topicProgressList: List + ): Pair, Long> { + var numberOfDaysPassed = 0L + val recentlyPlayedPromotedStoryList = mutableListOf() val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) @@ -310,6 +313,8 @@ class TopicListController @Inject constructor( val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() + checkIfStoryIsCompleted(topic.topicId, mostRecentCompletedChapterProgress, story) + when { recentlyPlayerChapterProgress != null -> { createOngoingStoryListBasedOnRecentlyPlayed( @@ -318,8 +323,12 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress, completedChapterProgressList, topic, - recommendedStoryBuilder - ) + completedStoryTopicId + ).let { + Pair(it.first, it.second) + numberOfDaysPassed = it.second + it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } + } } mostRecentCompletedChapterProgress != null && mostRecentCompletedChapterProgress.explorationId != @@ -330,12 +339,28 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress, completedChapterProgressList, topic, - recommendedStoryBuilder - ) + completedStoryTopicId + ).let { + Pair(it.first, it.second) + numberOfDaysPassed = it.second + it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } + } } } } - PromotedActivityListBuilder.setRecommendedStoryList(recommendedStoryBuilder) + } + return Pair(recentlyPlayedPromotedStoryList, numberOfDaysPassed) + } + + private fun checkIfStoryIsCompleted( + topicId: String, + mostRecentCompletedChapterProgress: ChapterProgress?, + story: StorySummary + ) { + if(mostRecentCompletedChapterProgress != null && + mostRecentCompletedChapterProgress.explorationId == + story.chapterList.last().explorationId) { + completedStoryTopicId = topicId } } @@ -364,25 +389,28 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, - recommendedStoryBuilder: RecommendedStoryList.Builder - ) { + completedStoryTopicId: String + ): Pair { + val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { val numberOfDaysPassed = recentlyPlayerChapterProgress.getNumberOfDaysPassed() - addPromotedStoryInRecommendedStoryList( - numberOfDaysPassed, - recommendedStoryBuilder, - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId + return Pair( + addPromotedStoryInRecommendedStoryList( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId, + completedStoryTopicId + ), numberOfDaysPassed ) } + return Pair(null, 0) } private fun createOngoingStoryListBasedOnMostRecentlyCompleted( @@ -391,8 +419,9 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, - recommendedStoryBuilder: RecommendedStoryList.Builder - ) { + completedStoryTopicId: String + ): Pair { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId @@ -402,43 +431,40 @@ class TopicListController @Inject constructor( val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { val numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() - addPromotedStoryInRecommendedStoryList( - numberOfDaysPassed, - recommendedStoryBuilder, - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId + return Pair( + addPromotedStoryInRecommendedStoryList( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId, + completedStoryTopicId + ), numberOfDaysPassed ) } } + return Pair(null, 0) } private fun addPromotedStoryInRecommendedStoryList( - numberOfDaysPassed: Long, - recommendedStoryBuilder: RecommendedStoryList.Builder, storyId: String, topic: Topic, completedChapterProgressListSize: Int, chapterCount: Int, chapterSummaryName: String, - chapterSummaryExplorationId: String - ) { - val promotedStory = createPromotedStory( + chapterSummaryExplorationId: String, + completedStoryTopicId: String + ): PromotedStory { + return createPromotedStory( storyId, topic, completedChapterProgressListSize, chapterCount, chapterSummaryName, - chapterSummaryExplorationId + chapterSummaryExplorationId, + completedStoryTopicId ) - if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { - recommendedStoryBuilder.addRecentlyPlayedStory(promotedStory) - } else { - recommendedStoryBuilder.addOlderPlayedStory(promotedStory) - } } private fun ChapterProgress.getNumberOfDaysPassed(): Long { @@ -447,19 +473,11 @@ class TopicListController @Inject constructor( ) } - private fun createRecommendedStoryList( - topicProgressList: List, - PromotedActivityListBuilder: PromotedActivityList.Builder, - recommendedStoryBuilder: RecommendedStoryList.Builder + private fun computeSuggestedStories( + topicProgressList: List ): List { val recommendedStories = mutableListOf() - populateRecentlyPlayedStories( - topicProgressList, - PromotedActivityListBuilder, - recommendedStoryBuilder - ) - val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") @@ -517,7 +535,8 @@ class TopicListController @Inject constructor( completedChapterCount: Int, totalChapterCount: Int, nextChapterName: String?, - explorationId: String? + explorationId: String?, + completedStoryTopicId: String ): PromotedStory { val storySummary = topic.storyList.find { summary -> summary.storyId == storyId }!! val promotedStoryBuilder = PromotedStory.newBuilder() @@ -528,6 +547,7 @@ class TopicListController @Inject constructor( .setTopicName(topic.name) .setCompletedChapterCount(completedChapterCount) .setTotalChapterCount(totalChapterCount) + .setCompletedStoryTopicID(completedStoryTopicId) if (nextChapterName != null && explorationId != null) { promotedStoryBuilder.nextChapterName = nextChapterName promotedStoryBuilder.explorationId = explorationId diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 6e9cd606ed3..356692beb63 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -164,6 +164,15 @@ message CompletedStory { LessonThumbnail lesson_thumbnail = 5; } +// Corresponds to the list of stories the player is currently playing across all topics. +message OngoingStoryList { + // Ongoing stories from within the last 7 days. + repeated PromotedStory recent_story = 1; + + // Other ongoing stories from longer than 7 days ago. + repeated PromotedStory older_story = 2; +} + // The summary of a story that should be promoted, either because it's been started and not yet completed by the player, // or because they have completed all other lessons and may find this one interesting. message PromotedStory { @@ -194,6 +203,9 @@ message PromotedStory { // The thumbnail that should be displayed for this promoted story. LessonThumbnail lesson_thumbnail = 9; + + // The indicator to handle if story is completed. + string completedStoryTopicID = 10; } // A homescreen summary of a topic. @@ -256,15 +268,15 @@ message TopicProgress { // A structure corresponding to the promoted stories. This structure is set up // to properly account for recently played stories, recommended stories // and coming soon topics. -message RecommendedActivityList { +message PromotedActivityList { oneof recommendation_type { - RecommendedStoryList recommended_story_list = 1; + PromotedStoryList promoted_story_list = 1; ComingSoonTopicList coming_soon_topic_list = 2; } } // Corresponds to the list of stories the player is currently playing across all topics and recommended stories. -message RecommendedStoryList { +message PromotedStoryList { // Ongoing stories from within the last 7 days. repeated PromotedStory recently_played_story = 1; From 0d8408012285868ffaad054b3ae989932589ef6d Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 18 Jan 2021 17:06:14 +0530 Subject: [PATCH 184/248] Update promoted_story_list.xml --- app/src/main/res/layout/promoted_story_list.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/res/layout/promoted_story_list.xml b/app/src/main/res/layout/promoted_story_list.xml index 6807e95300b..98aff481781 100755 --- a/app/src/main/res/layout/promoted_story_list.xml +++ b/app/src/main/res/layout/promoted_story_list.xml @@ -5,7 +5,7 @@ - + From 1388c52f6c68d3a4b321abb42b39ead3f6e96b6e Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 18 Jan 2021 20:45:16 +0530 Subject: [PATCH 185/248] fixed implementation and updated testcases --- .../domain/topic/StoryProgressTestHelper.kt | 22 +++ .../topic/StoryProgressTestHelperTest.kt | 147 ++++++++---------- .../domain/topic/TopicListControllerTest.kt | 141 +++++++++++------ 3 files changed, 187 insertions(+), 123 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index d21248d56e6..a3fb72118c2 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -231,6 +231,28 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** + * Marks full topic progress on the second test topic for a particular profile. + * + * @param profileId The profile we are setting topic progress for. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than + * one week ago. + */ + fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + timestamp + ) + } + /** * Marks one story progress full in ratios exploration for a particular profile. * diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 6b1c8f7b306..ce4317ef665 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -23,7 +23,7 @@ import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.CompletedStoryList -import org.oppia.android.app.model.RecommendedActivityList +import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.StorySummary @@ -79,11 +79,11 @@ class StoryProgressTestHelperTest { lateinit var completedStoryListResultCaptor: ArgumentCaptor> @Mock - lateinit var mockRecommendedActivityListObserver: Observer> + lateinit var mockPromotedActivityListObserver: Observer> @Captor - lateinit var recommendedActivityListResultCaptor: - ArgumentCaptor> + lateinit var promotedActivityListResultCaptor: + ArgumentCaptor> @Mock lateinit var mockOngoingTopicListObserver: Observer> @@ -738,21 +738,21 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_getRecommendedActivityListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() - topicListController.getRecommendedActivityList(profileId).toLiveData() - .observeForever(mockRecommendedActivityListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetRecommendedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - with (recommendedActivityList.recommendedStoryList) { + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(1) assertThat(olderPlayedStoryCount).isEqualTo(0) assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( @@ -763,21 +763,21 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_getRecommendedActivityListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() - topicListController.getRecommendedActivityList(profileId).toLiveData() - .observeForever(mockRecommendedActivityListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetRecommendedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - with (recommendedActivityList.recommendedStoryList) { + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(1) assertThat(olderPlayedStoryCount).isEqualTo(0) assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( @@ -795,14 +795,14 @@ class StoryProgressTestHelperTest { ) testCoroutineDispatchers.runCurrent() - topicListController.getRecommendedActivityList(profileId).toLiveData() - .observeForever(mockRecommendedActivityListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetRecommendedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - with (recommendedActivityList.recommendedStoryList) { + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(2) assertThat(olderPlayedStoryCount).isEqualTo(0) assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( @@ -817,21 +817,21 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markFullProgressForSecondTopic_showRecommendedStories_listIsCorrect() { + fun testProgressTestHelper_markFullProgressForSecondTestTopic_promotedStoryListIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTestTopic( profileId, /* timestampOlderThanAWeek= */ false ) testCoroutineDispatchers.runCurrent() - topicListController.getRecommendedActivityList(profileId).toLiveData() - .observeForever(mockRecommendedActivityListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetRecommendedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - with (recommendedActivityList.recommendedStoryList) { + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount) .isEqualTo(0) assertThat(olderPlayedStoryCount) @@ -844,67 +844,66 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_storyListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId = profileId, timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() - topicListController.getOngoingStoryList(profileId).toLiveData() - .observeForever(mockOngoingStoryListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetOngoingStoryListSucceeded() + verifyGetPromotedActivityListSucceeded() - val ongoingStoryList = ongoingStoryListResultCaptor.value.getOrThrow() - assertThat(ongoingStoryList.recentStoryCount).isEqualTo(2) - assertThat(ongoingStoryList.olderStoryCount).isEqualTo(0) - assertThat(ongoingStoryList.recentStoryList[0].explorationId).isEqualTo( - TEST_EXPLORATION_ID_2 - ) - assertThat(ongoingStoryList.recentStoryList[0].completedChapterCount).isEqualTo(0) - - assertThat(ongoingStoryList.recentStoryList[1].explorationId).isEqualTo( - TEST_EXPLORATION_ID_4 - ) - assertThat(ongoingStoryList.recentStoryList[1].completedChapterCount).isEqualTo(0) + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(2) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + TEST_EXPLORATION_ID_2 + ) + assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) + assertThat(recentlyPlayedStoryList[1].explorationId).isEqualTo( + TEST_EXPLORATION_ID_4 + ) + assertThat(recentlyPlayedStoryList[1].completedChapterCount).isEqualTo(0) + } } @Test - fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_RecommendedActivityListCorrect() { + fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_PromotedActivityListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId = profileId, timestampOlderThanAWeek = true ) testCoroutineDispatchers.runCurrent() - topicListController.getRecommendedActivityList(profileId).toLiveData() - .observeForever(mockRecommendedActivityListObserver) + topicListController.getPromotedActivityList(profileId).toLiveData() + .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifyGetRecommendedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() - val recommendedActivityList = recommendedActivityListResultCaptor.value.getOrThrow() - with (recommendedActivityList.recommendedStoryList){ - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(olderPlayedStoryCount).isEqualTo(3) + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(olderPlayedStoryCount).isEqualTo(3) - assertThat(olderPlayedStoryList[0].explorationId).isEqualTo( - FRACTIONS_EXPLORATION_ID_0 - ) - assertThat(olderPlayedStoryList[0].completedChapterCount) - .isEqualTo(0) - - assertThat(olderPlayedStoryList[1].explorationId) - .isEqualTo(RATIOS_EXPLORATION_ID_0) - assertThat(olderPlayedStoryList[1].completedChapterCount) - .isEqualTo(0) - - assertThat(olderPlayedStoryList[2].explorationId) - .isEqualTo(RATIOS_EXPLORATION_ID_2) - assertThat(olderPlayedStoryList[2].completedChapterCount) - .isEqualTo(0) + assertThat(olderPlayedStoryList[0].explorationId).isEqualTo( + FRACTIONS_EXPLORATION_ID_0 + ) + assertThat(olderPlayedStoryList[0].completedChapterCount) + .isEqualTo(0) + assertThat(olderPlayedStoryList[1].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat(olderPlayedStoryList[1].completedChapterCount) + .isEqualTo(0) + assertThat(olderPlayedStoryList[2].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_2) + assertThat(olderPlayedStoryList[2].completedChapterCount) + .isEqualTo(0) } } @@ -934,20 +933,12 @@ class StoryProgressTestHelperTest { assertThat(completedStoryListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyGetRecommendedActivityListSucceeded() { + private fun verifyGetPromotedActivityListSucceeded() { verify( - mockRecommendedActivityListObserver, + mockPromotedActivityListObserver, atLeastOnce() - ).onChanged(recommendedActivityListResultCaptor.capture()) - assertThat(recommendedActivityListResultCaptor.value.isSuccess()).isTrue() - } - - private fun verifyGetTopicListSucceeded() { - verify( - mockTopicListObserver, - atLeastOnce() - ).onChanged(topicListResultCaptor.capture()) - assertThat(topicListResultCaptor.value.isSuccess()).isTrue() + ).onChanged(promotedActivityListResultCaptor.capture()) + assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } private fun verifyGetTopicListSucceeded() { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index e4955e4193e..3d753d2aae2 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -27,6 +27,7 @@ import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.PromotedStory import org.oppia.android.app.model.TopicList import org.oppia.android.app.model.TopicSummary +import org.oppia.android.app.model.UpcomingTopic import org.oppia.android.domain.oppialogger.LogStorageModule import org.oppia.android.testing.RobolectricModule import org.oppia.android.testing.TestCoroutineDispatchers @@ -229,17 +230,16 @@ class TopicListControllerTest { } @Test - fun testRetrieveOngoingStoryList_defaultLesson_hasCorrectInfo() { + fun testretrievePromotedActivityList_defaultLesson_hasCorrectInfo() { topicListController.getPromotedActivityList(profileId0).toLiveData() .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() verifygetPromotedActivityListSucceeded() - verifyDefaultOngoingStoryListSucceeded() } @Test - fun testRetrieveOngoingStoryList_markRecentlyPlayedFracStory0Exp0_ongoingStoryListIsCorrect() { + fun testRetrievePromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedActivityListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -247,16 +247,19 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_0, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(1) verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[0]) + assertThat(suggestedStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(suggestedStoryList[0]) } } @Test - fun testRetrieveOngoingStoryList_markChapterCompletedFracStory0Exp0_ongoingStoryListIsCorrect() { + fun testRetrievePromotedActivityList_markChapDoneFracStory0Exp0_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -264,16 +267,17 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_0, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(1) verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) } } @Test - fun testRetrieveStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_ongoingListCorrect() { + fun testRetrieveStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_promotedStoryListCorrect() { // ktlint-disable max-line-length storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -290,16 +294,17 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_1, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(1) verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) } } @Test - fun testRetrieveOngoingStoryList_markAllChaptersCompletedInFractions_ongoingStoryListIsCorrect() { + fun testRetrievePromotedActivityList_markAllChapsDoneInFractions_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -316,16 +321,17 @@ class TopicListControllerTest { FRACTIONS_EXPLORATION_ID_1, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(4) - verifyDefaultOngoingStoryListSucceeded() + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(suggestedStoryCount).isEqualTo(1) } } @Test - fun testRetrieveStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_ongoingListIsCorrect() { + fun testRetrieveStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_promotedStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressController.recordRecentlyPlayedChapter( profileId0, RATIOS_TOPIC_ID, @@ -342,10 +348,13 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(2) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(suggestedStoryCount).isEqualTo(0) verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[0]) verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) } @@ -369,15 +378,48 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(2) verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[0]) verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) } } + @Test + fun testRetrieveStoryList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(suggestedStoryCount).isEqualTo(0) + } + with(promotedActivityList.comingSoonTopicList) { + assertThat(upcomingTopicCount).isEqualTo(1) + verifyUpcomingTopic1(upcomingTopicList[0]) + } + } + @Test fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -406,12 +448,12 @@ class TopicListControllerTest { getCurrentTimestamp() ) - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { assertThat(recentlyPlayedStoryCount).isEqualTo(3) - verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[2]) + verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[2]) } } @@ -440,16 +482,17 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getCurrentTimestamp() + getOldTimestamp() ) - val promotedStoryList = retrieveOngoingStoryList() - with(promotedStoryList.recommendedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - assertThat(olderPlayedStoryCount).isEqualTo(2) - verifyOngoingStoryAsFractionStory0Exploration1(olderPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory0Exploration1(olderPlayedStoryList[1]) - verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[0]) + val promotedActivityList = retrievePromotedActivityList() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(olderPlayedStoryCount).isEqualTo(3) + + verifyOngoingStoryAsRatioStory0Exploration1(olderPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(olderPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(olderPlayedStoryList[2]) } } @@ -461,15 +504,15 @@ class TopicListControllerTest { assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyDefaultOngoingStoryListSucceeded() { - val promotedStoryList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedStoryList.recommendedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(recentlyPlayedStoryList[1]) - verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[3]) - } + private fun verifyDefaultPromotedActivityListSucceeded() { + val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() + with(promotedActivityList.promotedStoryList) { + assertThat(recentlyPlayedStoryCount).isEqualTo(4) + verifyOngoingStoryAsFirstTopicStory0Exploration0(recentlyPlayedStoryList[0]) + verifyOngoingStoryAsSecondTopicStory0Exploration0(recentlyPlayedStoryList[1]) + verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[2]) + verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[3]) + } } private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { @@ -483,6 +526,7 @@ class TopicListControllerTest { assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyOngoingStoryAsSecondTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) @@ -542,7 +586,14 @@ class TopicListControllerTest { assertThat(promotedStory.completedChapterCount).isEqualTo(1) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - + + private fun verifyUpcomingTopic1(upcomingTopic: UpcomingTopic) { + assertThat(upcomingTopic.topicId).isEqualTo(UPCOMING_TOPIC_ID_1) + assertThat(upcomingTopic.name).isEqualTo("Third Test Topic") + assertThat(upcomingTopic.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) + } + private fun verifyOngoingStoryAsRatioStory1Exploration2(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_2) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_1) @@ -584,7 +635,7 @@ class TopicListControllerTest { return topicListResultCaptor.value.getOrThrow() } - private fun retrieveOngoingStoryList(): PromotedActivityList { + private fun retrievePromotedActivityList(): PromotedActivityList { testCoroutineDispatchers.runCurrent() topicListController.getPromotedActivityList(profileId0).toLiveData() .observeForever(mockPromotedActivityListObserver) From 97f16f79c57005145c46c63930b8559224ff62f5 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 18 Jan 2021 20:45:30 +0530 Subject: [PATCH 186/248] updated --- .../android/domain/topic/StoryProgressController.kt | 1 + .../oppia/android/domain/topic/TopicListController.kt | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 4fc8927cea4..e8875025de0 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -36,6 +36,7 @@ const val RATIOS_EXPLORATION_ID_0 = "2mzzFVDLuAj8" const val RATIOS_EXPLORATION_ID_1 = "5NWuolNcwH6e" const val RATIOS_EXPLORATION_ID_2 = "k2bQ7z5XHNbK" const val RATIOS_EXPLORATION_ID_3 = "tIoSb3HZFN6e" +const val UPCOMING_TOPIC_ID_1 = "test_topic_id_2" private const val CACHE_NAME = "topic_progress_database" private const val RETRIEVE_TOPIC_PROGRESS_LIST_DATA_PROVIDER_ID = diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 880ccfa35b7..76fa0de10a0 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -313,7 +313,7 @@ class TopicListController @Inject constructor( val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() - checkIfStoryIsCompleted(topic.topicId, mostRecentCompletedChapterProgress, story) + checkIfStoryIsCompleted(topic.topicId, mostRecentCompletedChapterProgress, story) when { recentlyPlayerChapterProgress != null -> { @@ -357,10 +357,11 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress: ChapterProgress?, story: StorySummary ) { - if(mostRecentCompletedChapterProgress != null && + if (mostRecentCompletedChapterProgress != null && mostRecentCompletedChapterProgress.explorationId == - story.chapterList.last().explorationId) { - completedStoryTopicId = topicId + story.chapterList.last().explorationId + ) { + completedStoryTopicId = topicId } } From 16a68ad9c6a310c047f932d1f54c048855a447e4 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 18 Jan 2021 20:51:28 +0530 Subject: [PATCH 187/248] fixed lint errors --- .../oppia/android/domain/topic/TopicListController.kt | 10 +++++++--- .../domain/topic/StoryProgressTestHelperTest.kt | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 76fa0de10a0..b832dde1122 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -219,7 +219,9 @@ class TopicListController @Inject constructor( .build() } - private fun computePromotedActivityList(topicProgressList: List): PromotedActivityList { + private fun computePromotedActivityList( + topicProgressList: List + ): PromotedActivityList { val promotedActivityListBuilder = PromotedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { promotedActivityListBuilder.promotedStoryList = computePromotedStoryList(topicProgressList) @@ -408,7 +410,8 @@ class TopicListController @Inject constructor( recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId, completedStoryTopicId - ), numberOfDaysPassed + ), + numberOfDaysPassed ) } return Pair(null, 0) @@ -441,7 +444,8 @@ class TopicListController @Inject constructor( nextChapterSummary.name, nextChapterSummary.explorationId, completedStoryTopicId - ), numberOfDaysPassed + ), + numberOfDaysPassed ) } } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index ce4317ef665..7e0cf9fa9ff 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -844,7 +844,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedStoryListIsCorrect() { + fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedStoryListIsCorrect() { // ktlint-disable max-line-length storyProgressTestHelper.markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId = profileId, timestampOlderThanAWeek = false From de0cfbab8c7179cc271eb050e04bbadfc99842bd Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 19 Jan 2021 17:33:23 +0530 Subject: [PATCH 188/248] Update StoryProgressTestHelperTest.kt --- .../oppia/android/domain/topic/StoryProgressTestHelperTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 7e0cf9fa9ff..1ebc043ff79 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -819,8 +819,8 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markFullProgressForSecondTestTopic_promotedStoryListIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTestTopic( - profileId, - /* timestampOlderThanAWeek= */ false + profileId = profileId, + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() From 07ec5e6dca6560d678e3091da3acb4f45afa3f81 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 19 Jan 2021 20:26:41 +0530 Subject: [PATCH 189/248] Update StoryProgressTestHelperTest.kt --- .../oppia/android/domain/topic/StoryProgressTestHelperTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 1ebc043ff79..528cc621d38 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -23,9 +23,9 @@ import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule import org.oppia.android.app.model.ChapterPlayState import org.oppia.android.app.model.CompletedStoryList -import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.OngoingTopicList import org.oppia.android.app.model.ProfileId +import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.StorySummary import org.oppia.android.app.model.Topic import org.oppia.android.app.model.TopicList From d55273d4594b597b764ff5596214f3d2a0c4aa5b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 19 Jan 2021 21:28:11 +0530 Subject: [PATCH 190/248] fixed lint --- .../java/org/oppia/android/domain/topic/TopicListController.kt | 2 +- model/src/main/proto/topic.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index b832dde1122..3c32428a55b 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -552,7 +552,7 @@ class TopicListController @Inject constructor( .setTopicName(topic.name) .setCompletedChapterCount(completedChapterCount) .setTotalChapterCount(totalChapterCount) - .setCompletedStoryTopicID(completedStoryTopicId) + .setCompletedStoryTopicId(completedStoryTopicId) if (nextChapterName != null && explorationId != null) { promotedStoryBuilder.nextChapterName = nextChapterName promotedStoryBuilder.explorationId = explorationId diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 356692beb63..56c09cdf709 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -205,7 +205,7 @@ message PromotedStory { LessonThumbnail lesson_thumbnail = 9; // The indicator to handle if story is completed. - string completedStoryTopicID = 10; + string completedStoryTopicId = 10; } // A homescreen summary of a topic. From 8b2f3e36671fab5f2ca46dcb81d9d34f7db98a5d Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 19 Jan 2021 21:35:51 +0530 Subject: [PATCH 191/248] Update topic.proto --- model/src/main/proto/topic.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 56c09cdf709..5e5cae99af6 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -205,7 +205,7 @@ message PromotedStory { LessonThumbnail lesson_thumbnail = 9; // The indicator to handle if story is completed. - string completedStoryTopicId = 10; + string completed_story_topic_id = 10; } // A homescreen summary of a topic. From 47656becf93a6f1cbe1d47c8333066b65b01870b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 20 Jan 2021 02:01:03 +0530 Subject: [PATCH 192/248] Update TopicListController.kt --- .../android/domain/topic/TopicListController.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 3c32428a55b..f7b45fe6db6 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -394,13 +394,13 @@ class TopicListController @Inject constructor( topic: Topic, completedStoryTopicId: String ): Pair { - + var numberOfDaysPassed = 0L val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - val numberOfDaysPassed = recentlyPlayerChapterProgress.getNumberOfDaysPassed() + numberOfDaysPassed = recentlyPlayerChapterProgress.getNumberOfDaysPassed() return Pair( addPromotedStoryInRecommendedStoryList( storyId, @@ -414,7 +414,7 @@ class TopicListController @Inject constructor( numberOfDaysPassed ) } - return Pair(null, 0) + return Pair(null, numberOfDaysPassed) } private fun createOngoingStoryListBasedOnMostRecentlyCompleted( @@ -425,7 +425,7 @@ class TopicListController @Inject constructor( topic: Topic, completedStoryTopicId: String ): Pair { - + var numberOfDaysPassed = 0L val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId @@ -434,7 +434,7 @@ class TopicListController @Inject constructor( if (story.chapterList.size > nextChapterIndex) { val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - val numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() + numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() return Pair( addPromotedStoryInRecommendedStoryList( storyId, @@ -449,7 +449,7 @@ class TopicListController @Inject constructor( ) } } - return Pair(null, 0) + return Pair(null, numberOfDaysPassed) } private fun addPromotedStoryInRecommendedStoryList( From a021b8064baa7c0b0f6c7ce7e2f0aa6f9f5edfa2 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Wed, 20 Jan 2021 12:01:48 +0530 Subject: [PATCH 193/248] Fixed issues --- .../domain/topic/StoryProgressTestHelper.kt | 3 +-- .../domain/topic/TopicListController.kt | 15 +++++-------- .../domain/topic/TopicListControllerTest.kt | 21 +++++-------------- .../testing/profile/ProfileTestHelper.kt | 6 ------ 4 files changed, 11 insertions(+), 34 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index a3fb72118c2..68f63b6ea99 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -235,8 +235,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on the second test topic for a particular profile. * * @param profileId The profile we are setting topic progress for. - * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than - * one week ago. + * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. */ fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index f7b45fe6db6..2dbe28736d5 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -196,7 +196,6 @@ class TopicListController @Inject constructor( topicId: String, jsonObject: JSONObject ): UpcomingTopic { - val upcomingTopic = UpcomingTopic.newBuilder() var totalChapterCount = 0 val storyData = jsonObject.getJSONArray("canonical_story_dicts") for (i in 0 until storyData.length()) { @@ -211,7 +210,7 @@ class TopicListController @Inject constructor( TopicPlayAvailability.newBuilder().setAvailableToPlayInFuture(true).build() } - return upcomingTopic.setTopicId(topicId) + return UpcomingTopic.newBuilder().setTopicId(topicId) .setName(jsonObject.getString("topic_name")) .setVersion(jsonObject.optInt("version")) .setTopicPlayAvailability(topicPlayAvailability) @@ -233,8 +232,7 @@ class TopicListController @Inject constructor( } private fun computePromotedStoryList(topicProgressList: List): PromotedStoryList { - val promotedStoryListBuilder = PromotedStoryList.newBuilder() - promotedStoryListBuilder + return PromotedStoryList.newBuilder() .addAllUpTo( populateRecentlyPlayedStories(topicProgressList), PromotedStoryList.Builder::addAllRecentlyPlayedStory, @@ -249,9 +247,7 @@ class TopicListController @Inject constructor( computeSuggestedStories(topicProgressList), PromotedStoryList.Builder::addAllSuggestedStory, limit = 3 - ) - - return promotedStoryListBuilder.build() + ).build() } private fun PromotedStoryList.getTotalPromotedStoryCount(): Int { @@ -359,9 +355,8 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress: ChapterProgress?, story: StorySummary ) { - if (mostRecentCompletedChapterProgress != null && - mostRecentCompletedChapterProgress.explorationId == - story.chapterList.last().explorationId + if (mostRecentCompletedChapterProgress?.explorationId + == story.chapterList.last().explorationId ) { completedStoryTopicId = topicId } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 3d753d2aae2..0fd58e37a23 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -230,7 +230,7 @@ class TopicListControllerTest { } @Test - fun testretrievePromotedActivityList_defaultLesson_hasCorrectInfo() { + fun testRetrievePromotedActivityList_defaultLesson_hasCorrectInfo() { topicListController.getPromotedActivityList(profileId0).toLiveData() .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() @@ -239,7 +239,7 @@ class TopicListControllerTest { } @Test - fun testRetrievePromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedActivityListIsCorrect() { // ktlint-disable max-line-length + fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedActivityListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -277,7 +277,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_promotedStoryListCorrect() { // ktlint-disable max-line-length + fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_promotedStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -331,7 +331,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_promotedStoryListIsCorrect() { // ktlint-disable max-line-length + fun testGetStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_promotedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, RATIOS_TOPIC_ID, @@ -361,7 +361,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markExp0DoneAndExp2AsPlayedInRatios_ongoingStoryListIsCorrect() { + fun testGetPromotedStoryList_markExp0DoneAndExp2AsPlayedInRatios_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, @@ -504,17 +504,6 @@ class TopicListControllerTest { assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyDefaultPromotedActivityListSucceeded() { - val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(4) - verifyOngoingStoryAsFirstTopicStory0Exploration0(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsSecondTopicStory0Exploration0(recentlyPlayedStoryList[1]) - verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[2]) - verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[3]) - } - } - private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) diff --git a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt index ebbb23e5216..fd7a74293bc 100644 --- a/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt +++ b/testing/src/main/java/org/oppia/android/testing/profile/ProfileTestHelper.kt @@ -105,12 +105,6 @@ class ProfileTestHelper @Inject constructor( */ fun logIntoNewUser() = logIntoProfile(internalProfileId = 2) - /** - * Login to a new user profile that has no progress for any topics or stories. This relies on other - * tests utilizing profile 1 as the default user profile so that profile 2 never has any progress. - */ - fun loginToNewUser() = logIntoProfile(internalProfileId = 2) - private fun logIntoProfile(internalProfileId: Int): LiveData> { val result = profileManagementController.loginToProfile( ProfileId.newBuilder().setInternalId(internalProfileId).build() From 427de92d0a83b153e02ee11c323a4aaf9069f46f Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 20 Jan 2021 13:55:49 +0530 Subject: [PATCH 194/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 68f63b6ea99..4deae822d01 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -234,8 +234,8 @@ class StoryProgressTestHelper @Inject constructor( /** * Marks full topic progress on the second test topic for a particular profile. * - * @param profileId The profile we are setting topic progress for. - * @param timestampOlderThanOneWeek If the timestamp for completing the topic is from more than one week ago. + * @param profileId the profile we are setting topic progress for + * @param timestampOlderThanOneWeek if the timestamp for completing the topic is from more than one week ago */ fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { From 8f573deed598c0288f04f00343c8bf093181d7e8 Mon Sep 17 00:00:00 2001 From: Veena Date: Wed, 20 Jan 2021 20:30:33 +0530 Subject: [PATCH 195/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../java/org/oppia/android/domain/topic/TopicListController.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 2dbe28736d5..118969fc0dd 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -224,7 +224,7 @@ class TopicListController @Inject constructor( val promotedActivityListBuilder = PromotedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { promotedActivityListBuilder.promotedStoryList = computePromotedStoryList(topicProgressList) - if (promotedActivityListBuilder.promotedStoryList.getTotalPromotedStoryCount() == 0) { + if (promotedActivityListBuilder.promotedStoryList.totalPromotedStoryCount == 0) { promotedActivityListBuilder.comingSoonTopicList = computeComingSoonTopicList() } } From 9cf97013e749918cc75f19e750d61ca66555d89c Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 21 Jan 2021 02:03:34 +0530 Subject: [PATCH 196/248] fixed nit changes --- .../domain/topic/StoryProgressTestHelper.kt | 1 - .../domain/topic/TopicListController.kt | 55 ++++++++++--------- .../topic/StoryProgressTestHelperTest.kt | 13 ++--- .../domain/topic/TopicListControllerTest.kt | 18 +++--- model/src/main/proto/topic.proto | 7 +-- 5 files changed, 43 insertions(+), 51 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 4deae822d01..fe84931c83c 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -274,7 +274,6 @@ class StoryProgressTestHelper @Inject constructor( RATIOS_EXPLORATION_ID_0, timestamp ) - storyProgressController.recordCompletedChapter( profileId, RATIOS_TOPIC_ID, diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 118969fc0dd..1b8fefc4661 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -224,7 +224,7 @@ class TopicListController @Inject constructor( val promotedActivityListBuilder = PromotedActivityList.newBuilder() if (topicProgressList.isNotEmpty()) { promotedActivityListBuilder.promotedStoryList = computePromotedStoryList(topicProgressList) - if (promotedActivityListBuilder.promotedStoryList.totalPromotedStoryCount == 0) { + if (promotedActivityListBuilder.promotedStoryList.getTotalPromotedStoryCount() == 0) { promotedActivityListBuilder.comingSoonTopicList = computeComingSoonTopicList() } } @@ -234,12 +234,12 @@ class TopicListController @Inject constructor( private fun computePromotedStoryList(topicProgressList: List): PromotedStoryList { return PromotedStoryList.newBuilder() .addAllUpTo( - populateRecentlyPlayedStories(topicProgressList), + computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS }, PromotedStoryList.Builder::addAllRecentlyPlayedStory, limit = 3 ) .addAllUpTo( - populateOlderPlayedStories(topicProgressList), + computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS }, PromotedStoryList.Builder::addAllOlderPlayedStory, limit = 3 ) @@ -266,19 +266,9 @@ class TopicListController @Inject constructor( return this.addAll(iterable.take(limit - this.getTotalPromotedStoryCount())) } - private fun populateRecentlyPlayedStories( - topicProgressList: List - ): List { - computePromotedStories(topicProgressList).let { - Pair(it.first, it.second) - if (it.second < ONE_WEEK_IN_DAYS) - return it.first - } - return emptyList() - } - - private fun populateOlderPlayedStories( - topicProgressList: List + private fun computePlayedStories( + topicProgressList: List, + completionTimeFilter: (Long) -> Boolean ): List { computePromotedStories(topicProgressList).let { Pair(it.first, it.second) @@ -295,6 +285,7 @@ class TopicListController @Inject constructor( val recentlyPlayedPromotedStoryList = mutableListOf() val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + .filter { completionTimeFilter(numberOfDaysPassed) } sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) @@ -311,7 +302,11 @@ class TopicListController @Inject constructor( val recentlyPlayerChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() - checkIfStoryIsCompleted(topic.topicId, mostRecentCompletedChapterProgress, story) + val completedStoryTopicId = getTopicIdOfFullyCompletedStory( + topic.topicId, + mostRecentCompletedChapterProgress, + story + ) when { recentlyPlayerChapterProgress != null -> { @@ -319,15 +314,17 @@ class TopicListController @Inject constructor( storyId, story, recentlyPlayerChapterProgress, - completedChapterProgressList, + startedChapterProgressList, topic, completedStoryTopicId ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second + completionTimeFilter(numberOfDaysPassed) it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } } } + // Compute the ongoing story list for stories that are not fully completed yet mostRecentCompletedChapterProgress != null && mostRecentCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { @@ -341,25 +338,28 @@ class TopicListController @Inject constructor( ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second + completionTimeFilter(numberOfDaysPassed) it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } } } } } } - return Pair(recentlyPlayedPromotedStoryList, numberOfDaysPassed) + + return recentlyPlayedPromotedStoryList } - private fun checkIfStoryIsCompleted( + private fun getTopicIdOfFullyCompletedStory( topicId: String, mostRecentCompletedChapterProgress: ChapterProgress?, story: StorySummary - ) { + ): String { if (mostRecentCompletedChapterProgress?.explorationId == story.chapterList.last().explorationId ) { - completedStoryTopicId = topicId - } + return topicId + } else + return "" } private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = @@ -487,10 +487,11 @@ class TopicListController @Inject constructor( val index = topicIdList.indexOf(topicProgressList.last().topicId) for (i in (index + 1) until topicIdJsonArray.length()) { - if (topicIdJsonArray.length() > i && - createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) != null - ) { - recommendedStories.add(createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())!!) + if (topicIdJsonArray.length() > i) { + val recommendedStoriesIdFromAssets = + createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) + if (recommendedStoriesIdFromAssets != null) + recommendedStories.add(recommendedStoriesIdFromAssets) } } return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 528cc621d38..b6b9d5a4588 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -832,19 +832,14 @@ class StoryProgressTestHelperTest { val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount) - .isEqualTo(0) - assertThat(olderPlayedStoryCount) - .isEqualTo(0) - assertThat(suggestedStoryList[0].explorationId) - .isEqualTo( - FRACTIONS_EXPLORATION_ID_0 - ) + assertThat(recentlyPlayedStoryCount).isEqualTo(0) + assertThat(olderPlayedStoryCount).isEqualTo(0) + assertThat(suggestedStoryList[0].explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) } } @Test - fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedStoryListIsCorrect() { // ktlint-disable max-line-length + fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId = profileId, timestampOlderThanAWeek = false diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 0fd58e37a23..d9844ea173c 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -235,11 +235,11 @@ class TopicListControllerTest { .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifygetPromotedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() } @Test - fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedActivityListIsCorrect() { + fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -277,7 +277,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_promotedStoryListCorrect() { + fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_ongoingStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -361,7 +361,7 @@ class TopicListControllerTest { } @Test - fun testGetPromotedStoryList_markExp0DoneAndExp2AsPlayedInRatios_promotedStoryListIsCorrect() { + fun testGetStoryList_markExp0DoneAndExp2AsPlayedInRatios_ongoingStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, @@ -389,7 +389,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { + fun testRetrievePromotedActivityList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, @@ -421,7 +421,7 @@ class TopicListControllerTest { } @Test - fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { + fun testGetStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -482,7 +482,7 @@ class TopicListControllerTest { RATIOS_TOPIC_ID, RATIOS_STORY_ID_1, RATIOS_EXPLORATION_ID_2, - getOldTimestamp() + getCurrentTimestamp() ) val promotedActivityList = retrievePromotedActivityList() @@ -496,7 +496,7 @@ class TopicListControllerTest { } } - private fun verifygetPromotedActivityListSucceeded() { + private fun verifyGetPromotedActivityListSucceeded() { verify( mockPromotedActivityListObserver, atLeastOnce() @@ -629,7 +629,7 @@ class TopicListControllerTest { topicListController.getPromotedActivityList(profileId0).toLiveData() .observeForever(mockPromotedActivityListObserver) testCoroutineDispatchers.runCurrent() - verifygetPromotedActivityListSucceeded() + verifyGetPromotedActivityListSucceeded() return promotedActivityListResultCaptor.value.getOrThrow() } diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 5e5cae99af6..238e0a11abf 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -304,14 +304,11 @@ message UpcomingTopic { // The structural version of the topic. int32 version = 3; - // The estimated release date/timestamp of topic. - int64 estimated_release_unix_timestamp = 4; - // The associated thumbnail that should be displayed with this topic. - LessonThumbnail lesson_thumbnail = 5; + LessonThumbnail lesson_thumbnail = 4; // Specifics about whether this topic is playable. - TopicPlayAvailability topic_play_availability = 6; + TopicPlayAvailability topic_play_availability = 5; } // Represents the story progress. From 08b9eef4b22e0993f319b1f753cf870ba75cf450 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 21 Jan 2021 02:06:40 +0530 Subject: [PATCH 197/248] Update TopicListController.kt --- .../oppia/android/domain/topic/TopicListController.kt | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 1b8fefc4661..bff3d64ced4 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -270,17 +270,7 @@ class TopicListController @Inject constructor( topicProgressList: List, completionTimeFilter: (Long) -> Boolean ): List { - computePromotedStories(topicProgressList).let { - Pair(it.first, it.second) - if (it.second > ONE_WEEK_IN_DAYS) - return it.first - } - return emptyList() - } - private fun computePromotedStories( - topicProgressList: List - ): Pair, Long> { var numberOfDaysPassed = 0L val recentlyPlayedPromotedStoryList = mutableListOf() val sortedTopicProgressList = From 7f7ea3f7733928d649a98f965d0ce089d3246cb6 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 21 Jan 2021 18:04:22 +0530 Subject: [PATCH 198/248] Update TopicListController.kt --- .../domain/topic/TopicListController.kt | 41 +++++++++---------- 1 file changed, 20 insertions(+), 21 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index bff3d64ced4..0360a431f38 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -232,14 +232,16 @@ class TopicListController @Inject constructor( } private fun computePromotedStoryList(topicProgressList: List): PromotedStoryList { + val recentlyPlayedStories = computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS } + val olderPlayedStories = computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS } return PromotedStoryList.newBuilder() .addAllUpTo( - computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS }, + recentlyPlayedStories, PromotedStoryList.Builder::addAllRecentlyPlayedStory, limit = 3 ) .addAllUpTo( - computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS }, + olderPlayedStories, PromotedStoryList.Builder::addAllOlderPlayedStory, limit = 3 ) @@ -271,11 +273,10 @@ class TopicListController @Inject constructor( completionTimeFilter: (Long) -> Boolean ): List { - var numberOfDaysPassed = 0L - val recentlyPlayedPromotedStoryList = mutableListOf() + var numberOfDaysPassed: Long + val playedPromotedStoryList = mutableListOf() val sortedTopicProgressList = topicProgressList.sortedByDescending { it.lastPlayedTimestamp } - .filter { completionTimeFilter(numberOfDaysPassed) } sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) @@ -288,11 +289,11 @@ class TopicListController @Inject constructor( val mostRecentCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() - val startedChapterProgressList = getStartedChapterProgressList(storyProgress) + val recentlyStartedChapterProgressList = getStartedChapterProgressList(storyProgress) val recentlyPlayerChapterProgress: ChapterProgress? = - startedChapterProgressList.firstOrNull() + recentlyStartedChapterProgressList.firstOrNull() - val completedStoryTopicId = getTopicIdOfFullyCompletedStory( + setTopicIdIfAtleastOneStoryIsCompleted( topic.topicId, mostRecentCompletedChapterProgress, story @@ -304,17 +305,17 @@ class TopicListController @Inject constructor( storyId, story, recentlyPlayerChapterProgress, - startedChapterProgressList, + recentlyStartedChapterProgressList, topic, completedStoryTopicId ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second - completionTimeFilter(numberOfDaysPassed) - it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } + if (completionTimeFilter(numberOfDaysPassed)) + it.first?.let { it1 -> playedPromotedStoryList.add(it1) } } } - // Compute the ongoing story list for stories that are not fully completed yet + // Compute the ongoing story list for stories that are not fully completed yet. mostRecentCompletedChapterProgress != null && mostRecentCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { @@ -328,28 +329,26 @@ class TopicListController @Inject constructor( ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second - completionTimeFilter(numberOfDaysPassed) - it.first?.let { it1 -> recentlyPlayedPromotedStoryList.add(it1) } + if (completionTimeFilter(numberOfDaysPassed)) + it.first?.let { it1 -> playedPromotedStoryList.add(it1) } } } } } } - - return recentlyPlayedPromotedStoryList + return playedPromotedStoryList } - private fun getTopicIdOfFullyCompletedStory( + private fun setTopicIdIfAtleastOneStoryIsCompleted( topicId: String, mostRecentCompletedChapterProgress: ChapterProgress?, story: StorySummary - ): String { + ) { if (mostRecentCompletedChapterProgress?.explorationId == story.chapterList.last().explorationId ) { - return topicId - } else - return "" + completedStoryTopicId = topicId + } } private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = From f78db26837881e7eb8753fa97a8f8d4b8d75a9d4 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 22 Jan 2021 11:44:56 +0530 Subject: [PATCH 199/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 86 +++++++------------ 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index d9844ea173c..6c749927afc 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -250,12 +250,10 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0(recentlyPlayedStoryList[0]) - assertThat(suggestedStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(suggestedStoryList[0]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) + verifyPromotedStoryAsFractionStory0Exploration0(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0(promotedActivityList.promotedStoryList.suggestedStoryList[0]) } @Test @@ -270,10 +268,8 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) } @Test @@ -297,10 +293,8 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[0]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) } @Test @@ -324,10 +318,8 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(suggestedStoryCount).isEqualTo(1) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) } @Test @@ -351,13 +343,11 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(2) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(suggestedStoryCount).isEqualTo(0) - verifyOngoingStoryAsRatioStory0Exploration0(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) + verifyOngoingStoryAsRatioStory0Exploration0(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration2(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) } @Test @@ -381,11 +371,9 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(recentlyPlayedStoryList[1]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration2(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) } @Test @@ -409,15 +397,12 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(suggestedStoryCount).isEqualTo(0) - } - with(promotedActivityList.comingSoonTopicList) { - assertThat(upcomingTopicCount).isEqualTo(1) - verifyUpcomingTopic1(upcomingTopicList[0]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) + + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) + verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) } @Test @@ -449,12 +434,10 @@ class TopicListControllerTest { ) val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(recentlyPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(recentlyPlayedStoryList[2]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[2]) } @Test @@ -486,14 +469,11 @@ class TopicListControllerTest { ) val promotedActivityList = retrievePromotedActivityList() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(olderPlayedStoryCount).isEqualTo(3) - - verifyOngoingStoryAsRatioStory0Exploration1(olderPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(olderPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(olderPlayedStoryList[2]) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.olderPlayedStoryList[0]) + verifyOngoingStoryAsRatioStory1Exploration3(promotedActivityList.promotedStoryList.olderPlayedStoryList[1]) + verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.olderPlayedStoryList[2]) } private fun verifyGetPromotedActivityListSucceeded() { From b75d103e6a68df0ff72308cf2f26df1df40999af Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 22 Jan 2021 11:48:15 +0530 Subject: [PATCH 200/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 92 +++++++++++++------ 1 file changed, 64 insertions(+), 28 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 6c749927afc..7072a9936f7 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -250,10 +250,16 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0(promotedActivityList.promotedStoryList.suggestedStoryList[0]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test @@ -268,8 +274,11 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) } @Test @@ -293,8 +302,11 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsFractionStory0Exploration1( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) } @Test @@ -318,7 +330,8 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) } @@ -343,11 +356,16 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) - verifyOngoingStoryAsRatioStory0Exploration0(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) + verifyOngoingStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration2( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + ) } @Test @@ -371,9 +389,14 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration2(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) + verifyOngoingStoryAsRatioStory0Exploration1( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration2( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + ) } @Test @@ -397,11 +420,9 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) + .isEqualTo(1) verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) } @@ -434,10 +455,17 @@ class TopicListControllerTest { ) val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[2]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration3( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[2] + ) } @Test @@ -469,11 +497,19 @@ class TopicListControllerTest { ) val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(3) - verifyOngoingStoryAsRatioStory0Exploration1(promotedActivityList.promotedStoryList.olderPlayedStoryList[0]) - verifyOngoingStoryAsRatioStory1Exploration3(promotedActivityList.promotedStoryList.olderPlayedStoryList[1]) - verifyOngoingStoryAsFractionStory0Exploration1(promotedActivityList.promotedStoryList.olderPlayedStoryList[2]) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration3( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + promotedActivityList.promotedStoryList.olderPlayedStoryList[2] + ) } private fun verifyGetPromotedActivityListSucceeded() { From a37015ec1f8a7864a07ac1e388f4f6a1740f02ea Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 22 Jan 2021 18:11:29 +0530 Subject: [PATCH 201/248] updated implementation --- .../domain/topic/TopicListController.kt | 91 ++++++++++--------- model/src/main/proto/topic.proto | 2 +- 2 files changed, 49 insertions(+), 44 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 0360a431f38..36016585116 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -237,18 +237,15 @@ class TopicListController @Inject constructor( return PromotedStoryList.newBuilder() .addAllUpTo( recentlyPlayedStories, - PromotedStoryList.Builder::addAllRecentlyPlayedStory, - limit = 3 + PromotedStoryList.Builder::addAllRecentlyPlayedStory ) .addAllUpTo( olderPlayedStories, - PromotedStoryList.Builder::addAllOlderPlayedStory, - limit = 3 + PromotedStoryList.Builder::addAllOlderPlayedStory ) .addAllUpTo( computeSuggestedStories(topicProgressList), - PromotedStoryList.Builder::addAllSuggestedStory, - limit = 3 + PromotedStoryList.Builder::addAllSuggestedStory ).build() } @@ -262,10 +259,9 @@ class TopicListController @Inject constructor( private fun PromotedStoryList.Builder.addAllUpTo( iterable: Iterable, - addAll: PromotedStoryList.Builder.(Iterable) -> PromotedStoryList.Builder, - limit: Int + addAll: PromotedStoryList.Builder.(Iterable) -> PromotedStoryList.Builder ): PromotedStoryList.Builder { - return this.addAll(iterable.take(limit - this.getTotalPromotedStoryCount())) + return this.addAll(iterable) } private fun computePlayedStories( @@ -281,6 +277,8 @@ class TopicListController @Inject constructor( sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) + val isTopicConsideredCompleted = checkIfAtLeastOnStoryIsCompleted(topicProgress, topic) + topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId val story = topicController.retrieveStory(topic.topicId, storyId) @@ -289,25 +287,20 @@ class TopicListController @Inject constructor( val mostRecentCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() - val recentlyStartedChapterProgressList = getStartedChapterProgressList(storyProgress) - val recentlyPlayerChapterProgress: ChapterProgress? = - recentlyStartedChapterProgressList.firstOrNull() - - setTopicIdIfAtleastOneStoryIsCompleted( - topic.topicId, - mostRecentCompletedChapterProgress, - story - ) + val startedChapterProgressList = getStartedChapterProgressList(storyProgress) + val latestStartedChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + val isCurrentStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) when { - recentlyPlayerChapterProgress != null -> { + latestStartedChapterProgress != null -> { createOngoingStoryListBasedOnRecentlyPlayed( storyId, story, - recentlyPlayerChapterProgress, - recentlyStartedChapterProgressList, + latestStartedChapterProgress, + startedChapterProgressList, topic, - completedStoryTopicId + isTopicConsideredCompleted ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second @@ -316,16 +309,14 @@ class TopicListController @Inject constructor( } } // Compute the ongoing story list for stories that are not fully completed yet. - mostRecentCompletedChapterProgress != null && - mostRecentCompletedChapterProgress.explorationId != - story.chapterList.last().explorationId -> { + isCurrentStoryCompleted && mostRecentCompletedChapterProgress != null -> { createOngoingStoryListBasedOnMostRecentlyCompleted( storyId, story, mostRecentCompletedChapterProgress, completedChapterProgressList, topic, - completedStoryTopicId + isTopicConsideredCompleted ).let { Pair(it.first, it.second) numberOfDaysPassed = it.second @@ -339,16 +330,30 @@ class TopicListController @Inject constructor( return playedPromotedStoryList } - private fun setTopicIdIfAtleastOneStoryIsCompleted( - topicId: String, - mostRecentCompletedChapterProgress: ChapterProgress?, - story: StorySummary - ) { - if (mostRecentCompletedChapterProgress?.explorationId - == story.chapterList.last().explorationId - ) { - completedStoryTopicId = topicId + private fun checkIfAtLeastOnStoryIsCompleted( + topicProgress: TopicProgress, + topic: Topic + ): Boolean { + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) + val isStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) + if (isStoryCompleted) { + return true + } } + return false + } + + private fun checkIfStoryIsCompleted( + storyProgress: StoryProgress, + storySummary: StorySummary + ): Boolean { + val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) + val lastChapterSummary = storySummary.chapterList.lastOrNull() + return completedChapterProgressList.find { chapterProgress -> + chapterProgress.explorationId == lastChapterSummary?.explorationId + } != null } private fun getStartedChapterProgressList(storyProgress: StoryProgress): List = @@ -376,7 +381,7 @@ class TopicListController @Inject constructor( recentlyPlayerChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, - completedStoryTopicId: String + isTopicConsideredCompleted: Boolean ): Pair { var numberOfDaysPassed = 0L val recentlyPlayerChapterSummary: ChapterSummary? = @@ -393,7 +398,7 @@ class TopicListController @Inject constructor( story.chapterCount, recentlyPlayerChapterSummary.name, recentlyPlayerChapterSummary.explorationId, - completedStoryTopicId + isTopicConsideredCompleted ), numberOfDaysPassed ) @@ -407,7 +412,7 @@ class TopicListController @Inject constructor( mostRecentCompletedChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, - completedStoryTopicId: String + isTopicConsideredCompleted: Boolean ): Pair { var numberOfDaysPassed = 0L val lastChapterSummary: ChapterSummary? = @@ -427,7 +432,7 @@ class TopicListController @Inject constructor( story.chapterCount, nextChapterSummary.name, nextChapterSummary.explorationId, - completedStoryTopicId + isTopicConsideredCompleted ), numberOfDaysPassed ) @@ -443,7 +448,7 @@ class TopicListController @Inject constructor( chapterCount: Int, chapterSummaryName: String, chapterSummaryExplorationId: String, - completedStoryTopicId: String + isTopicConsideredCompleted: Boolean ): PromotedStory { return createPromotedStory( storyId, @@ -452,7 +457,7 @@ class TopicListController @Inject constructor( chapterCount, chapterSummaryName, chapterSummaryExplorationId, - completedStoryTopicId + isTopicConsideredCompleted ) } @@ -526,7 +531,7 @@ class TopicListController @Inject constructor( totalChapterCount: Int, nextChapterName: String?, explorationId: String?, - completedStoryTopicId: String + isTopicConsideredCompleted: Boolean ): PromotedStory { val storySummary = topic.storyList.find { summary -> summary.storyId == storyId }!! val promotedStoryBuilder = PromotedStory.newBuilder() @@ -537,7 +542,7 @@ class TopicListController @Inject constructor( .setTopicName(topic.name) .setCompletedChapterCount(completedChapterCount) .setTotalChapterCount(totalChapterCount) - .setCompletedStoryTopicId(completedStoryTopicId) + .setIsTopicLearned(isTopicConsideredCompleted) if (nextChapterName != null && explorationId != null) { promotedStoryBuilder.nextChapterName = nextChapterName promotedStoryBuilder.explorationId = explorationId diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 238e0a11abf..a58d81fdf7c 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -205,7 +205,7 @@ message PromotedStory { LessonThumbnail lesson_thumbnail = 9; // The indicator to handle if story is completed. - string completed_story_topic_id = 10; + bool is_topic_learned = 10; } // A homescreen summary of a topic. From b6529db0be101eeee3a775d1c8fd7956f75fe29e Mon Sep 17 00:00:00 2001 From: Veena Date: Sat, 23 Jan 2021 00:27:11 +0530 Subject: [PATCH 202/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index fe84931c83c..c2bd02b4d49 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -253,7 +253,7 @@ class StoryProgressTestHelper @Inject constructor( } /** - * Marks one story progress full in ratios exploration for a particular profile. + * Marks one story progress fully complete in the ratios topic for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago From fb553142e5896071b69f1a59bdf5eefe10045443 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 23 Jan 2021 01:43:43 +0530 Subject: [PATCH 203/248] updated storyProgressController --- .../domain/topic/StoryProgressController.kt | 31 +++++++++++++++---- .../domain/topic/TopicListControllerTest.kt | 4 +-- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index e8875025de0..b88b4321e3f 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -113,14 +113,23 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgress) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = - TopicProgress.newBuilder() - .setTopicId(topicId).setLastPlayedTimestamp(completionTimestamp) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) + // Compute lastPlayedTimeStamp from chapterProgress list. + val topicProgressStories = topicProgressBuilder.storyProgressMap.values + val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } + val topicProgressLastPlayedTimes = + topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) + val computedLastPlayedTimestamp = + topicProgressLastPlayedTimes.max() + if (computedLastPlayedTimestamp != null) { + topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp + } val topicProgress = topicProgressBuilder.build() val topicDatabaseBuilder = @@ -196,15 +205,25 @@ class StoryProgressController @Inject constructor( storyProgressBuilder.putChapterProgress(explorationId, chapterProgressBuilder.build()) val storyProgress = storyProgressBuilder.build() - val topicProgressBuilder = - TopicProgress.newBuilder().setTopicId(topicId).setLastPlayedTimestamp(lastPlayedTimestamp) + val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) + // Compute lastPlayedTimeStamp from chapterProgress list. + if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) - val topicProgress = topicProgressBuilder.build() + val topicProgressStories = topicProgressBuilder.storyProgressMap.values + val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } + val topicProgressLastPlayedTimes = + topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) + val computedLastPlayedTimestamp = + topicProgressLastPlayedTimes.maxOrNull() + if (computedLastPlayedTimestamp != null) { + topicProgressBuilder.setLastPlayedTimestamp(computedLastPlayedTimestamp).build() + } + val topicProgress = topicProgressBuilder.build() val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 7072a9936f7..10724286e89 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -263,7 +263,7 @@ class TopicListControllerTest { } @Test - fun testRetrievePromotedActivityList_markChapDoneFracStory0Exp0_promotedStoryListIsCorrect() { + fun testGetPromotedStoryList_markChapDoneFracStory0Exp0_ongoingStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -310,7 +310,7 @@ class TopicListControllerTest { } @Test - fun testRetrievePromotedActivityList_markAllChapsDoneInFractions_promotedStoryListIsCorrect() { + fun testGetPromotedStoryList_markAllChapsDoneInFractions_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, From d54f6b96f8efe8ca9acef34fdce27f782eed48e0 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 23 Jan 2021 12:48:55 +0530 Subject: [PATCH 204/248] updated changes --- .../domain/topic/StoryProgressController.kt | 23 +--- .../domain/topic/TopicListController.kt | 30 +++-- .../domain/topic/TopicListControllerTest.kt | 105 ++++++++++++++---- 3 files changed, 96 insertions(+), 62 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index b88b4321e3f..104fb6c5d20 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -13,7 +13,6 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.logging.ConsoleLogger -import org.oppia.android.util.system.OppiaClock import javax.inject.Inject import javax.inject.Singleton @@ -57,7 +56,6 @@ private const val RECORD_RECENTLY_PLAYED_CHAPTER_PROVIDER_ID = class StoryProgressController @Inject constructor( private val cacheStoreFactory: PersistentCacheStore.Factory, private val dataProviders: DataProviders, - private val oppiaClock: OppiaClock, private val logger: ConsoleLogger ) { // TODO(#21): Determine whether chapters can have missing prerequisites in the initial prototype, @@ -120,16 +118,7 @@ class StoryProgressController @Inject constructor( .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) - // Compute lastPlayedTimeStamp from chapterProgress list. - val topicProgressStories = topicProgressBuilder.storyProgressMap.values - val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } - val topicProgressLastPlayedTimes = - topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) - val computedLastPlayedTimestamp = - topicProgressLastPlayedTimes.max() - if (computedLastPlayedTimestamp != null) { - topicProgressBuilder.lastPlayedTimestamp = computedLastPlayedTimestamp - } + val topicProgress = topicProgressBuilder.build() val topicDatabaseBuilder = @@ -206,7 +195,6 @@ class StoryProgressController @Inject constructor( val storyProgress = storyProgressBuilder.build() val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) - // Compute lastPlayedTimeStamp from chapterProgress list. if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder @@ -214,15 +202,6 @@ class StoryProgressController @Inject constructor( } topicProgressBuilder.putStoryProgress(storyId, storyProgress) - val topicProgressStories = topicProgressBuilder.storyProgressMap.values - val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } - val topicProgressLastPlayedTimes = - topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) - val computedLastPlayedTimestamp = - topicProgressLastPlayedTimes.maxOrNull() - if (computedLastPlayedTimestamp != null) { - topicProgressBuilder.setLastPlayedTimestamp(computedLastPlayedTimestamp).build() - } val topicProgress = topicProgressBuilder.build() val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 36016585116..2c42890b79a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -94,8 +94,6 @@ class TopicListController @Inject constructor( private val oppiaClock: OppiaClock ) { - private var completedStoryTopicId: String = "" - /** * Returns the list of [TopicSummary]s currently tracked by the app, possibly up to * [EVICTION_TIME_MILLIS] old. @@ -253,10 +251,6 @@ class TopicListController @Inject constructor( return recentlyPlayedStoryList.size + olderPlayedStoryList.size + suggestedStoryList.size } - private fun PromotedStoryList.Builder.getTotalPromotedStoryCount(): Int { - return recentlyPlayedStoryList.size + olderPlayedStoryList.size + suggestedStoryList.size - } - private fun PromotedStoryList.Builder.addAllUpTo( iterable: Iterable, addAll: PromotedStoryList.Builder.(Iterable) -> PromotedStoryList.Builder @@ -269,15 +263,20 @@ class TopicListController @Inject constructor( completionTimeFilter: (Long) -> Boolean ): List { - var numberOfDaysPassed: Long val playedPromotedStoryList = mutableListOf() val sortedTopicProgressList = - topicProgressList.sortedByDescending { it.lastPlayedTimestamp } + topicProgressList.sortedByDescending { + val topicProgressStories = it.storyProgressMap.values + val topicProgressChapters = topicProgressStories.flatMap { it.chapterProgressMap.values } + val topicProgressLastPlayedTimes = + topicProgressChapters.map(ChapterProgress::getLastPlayedTimestamp) + topicProgressLastPlayedTimes.maxOrNull() + } sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - val isTopicConsideredCompleted = checkIfAtLeastOnStoryIsCompleted(topicProgress, topic) + val isTopicConsideredCompleted = checkIfAtLeastOneStoryIsCompleted(topicProgress, topic) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId @@ -290,7 +289,6 @@ class TopicListController @Inject constructor( val startedChapterProgressList = getStartedChapterProgressList(storyProgress) val latestStartedChapterProgress: ChapterProgress? = startedChapterProgressList.firstOrNull() - val isCurrentStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) when { latestStartedChapterProgress != null -> { @@ -303,13 +301,14 @@ class TopicListController @Inject constructor( isTopicConsideredCompleted ).let { Pair(it.first, it.second) - numberOfDaysPassed = it.second - if (completionTimeFilter(numberOfDaysPassed)) + if (completionTimeFilter(it.second)) it.first?.let { it1 -> playedPromotedStoryList.add(it1) } } } // Compute the ongoing story list for stories that are not fully completed yet. - isCurrentStoryCompleted && mostRecentCompletedChapterProgress != null -> { + mostRecentCompletedChapterProgress != null && + mostRecentCompletedChapterProgress.explorationId != + story.chapterList.last().explorationId -> { createOngoingStoryListBasedOnMostRecentlyCompleted( storyId, story, @@ -319,8 +318,7 @@ class TopicListController @Inject constructor( isTopicConsideredCompleted ).let { Pair(it.first, it.second) - numberOfDaysPassed = it.second - if (completionTimeFilter(numberOfDaysPassed)) + if (completionTimeFilter(it.second)) it.first?.let { it1 -> playedPromotedStoryList.add(it1) } } } @@ -330,7 +328,7 @@ class TopicListController @Inject constructor( return playedPromotedStoryList } - private fun checkIfAtLeastOnStoryIsCompleted( + private fun checkIfAtLeastOneStoryIsCompleted( topicProgress: TopicProgress, topic: Topic ): Boolean { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 10724286e89..900b648bbb4 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -239,7 +239,7 @@ class TopicListControllerTest { } @Test - fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_promotedStoryListIsCorrect() { + fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_ongoindStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -255,11 +255,6 @@ class TopicListControllerTest { verifyPromotedStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) } @Test @@ -310,7 +305,7 @@ class TopicListControllerTest { } @Test - fun testGetPromotedStoryList_markAllChapsDoneInFractions_promotedStoryListIsCorrect() { + fun testGetPromotedStoryList_markAllChapsDoneInFractions_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -330,9 +325,10 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) - .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) + verifyRecommendedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test @@ -358,8 +354,6 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -468,6 +462,43 @@ class TopicListControllerTest { ) } + @Test + fun testGetStoryList_markOneStoryDoneAndPlayNextStoryOfFirstTestTopic_ongoingListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsFirstTopicStory1Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + } + @Test fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastMonth_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -498,17 +529,17 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) - .isEqualTo(0) + .isEqualTo(1) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) - .isEqualTo(3) + .isEqualTo(2) verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) - verifyOngoingStoryAsRatioStory1Exploration3( + verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) - verifyOngoingStoryAsFractionStory0Exploration1( - promotedActivityList.promotedStoryList.olderPlayedStoryList[2] + verifyOngoingStoryAsRatioStory1Exploration3( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) } @@ -520,15 +551,29 @@ class TopicListControllerTest { assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } - private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) - assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) + private fun verifyOngoingStoryAsFirstTopicStory1Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_1) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_1) assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_0) assertThat(promotedStory.topicName).isEqualTo("First Test Topic") - assertThat(promotedStory.nextChapterName).isEqualTo("Prototype Exploration") + assertThat(promotedStory.nextChapterName).isEqualTo("Second Exploration") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.COMPARING_FRACTIONS) + assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.isTopicLearned).isTrue() + assertThat(promotedStory.totalChapterCount).isEqualTo(3) + } + + private fun verifyOngoingStoryAsFirstTopicStory0Exploration1(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_5) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) + assertThat(promotedStory.topicName).isEqualTo("First Test Topic") + assertThat(promotedStory.nextChapterName).isEqualTo("Image Region Selection Exploration") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.BAKER) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.completedChapterCount).isEqualTo(2) + assertThat(promotedStory.isTopicLearned).isTrue() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -552,7 +597,7 @@ class TopicListControllerTest { assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.completedChapterCount).isEqualTo(1) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -568,7 +613,7 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - private fun verifyOngoingStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { + private fun verifyRecommendedStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_0) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) @@ -580,6 +625,18 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyOngoingStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) + assertThat(promotedStory.nextChapterName).isEqualTo("What is a Ratio?") + assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) + assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + private fun verifyOngoingStoryAsRatioStory0Exploration1(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_1) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) @@ -607,7 +664,7 @@ class TopicListControllerTest { assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.completedChapterCount).isEqualTo(1) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } From f1d4b803be3689de36c57ff12fdc2d568545f1bf Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 23 Jan 2021 12:49:23 +0530 Subject: [PATCH 205/248] Update topic.proto --- model/src/main/proto/topic.proto | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index a58d81fdf7c..0f4b4777bed 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -204,7 +204,7 @@ message PromotedStory { // The thumbnail that should be displayed for this promoted story. LessonThumbnail lesson_thumbnail = 9; - // The indicator to handle if story is completed. + // Indicates whether the topic containing this story is 'learned' (meaning at least one story was completed). bool is_topic_learned = 10; } @@ -260,9 +260,6 @@ message TopicProgress { // Map from story ID to StoryProgress. map story_progress = 2; - - // Timestamp to indicate the last time the exploration was played in ms. - int64 last_played_timestamp = 3; } // A structure corresponding to the promoted stories. This structure is set up From ff2a983094df4584c91bd014dd43a0f212baadfd Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 23 Jan 2021 17:42:50 +0530 Subject: [PATCH 206/248] Updated changes --- .../domain/topic/TopicListController.kt | 25 ++---- .../domain/topic/TopicListControllerTest.kt | 86 ++++++++++++++++++- model/src/main/proto/topic.proto | 3 +- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 2c42890b79a..60a62142c16 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -233,31 +233,22 @@ class TopicListController @Inject constructor( val recentlyPlayedStories = computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS } val olderPlayedStories = computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS } return PromotedStoryList.newBuilder() - .addAllUpTo( - recentlyPlayedStories, - PromotedStoryList.Builder::addAllRecentlyPlayedStory + .addAllRecentlyPlayedStory( + recentlyPlayedStories ) - .addAllUpTo( - olderPlayedStories, - PromotedStoryList.Builder::addAllOlderPlayedStory + .addAllOlderPlayedStory( + olderPlayedStories ) - .addAllUpTo( - computeSuggestedStories(topicProgressList), - PromotedStoryList.Builder::addAllSuggestedStory - ).build() + .addAllSuggestedStory( + computeSuggestedStories(topicProgressList) + ) + .build() } private fun PromotedStoryList.getTotalPromotedStoryCount(): Int { return recentlyPlayedStoryList.size + olderPlayedStoryList.size + suggestedStoryList.size } - private fun PromotedStoryList.Builder.addAllUpTo( - iterable: Iterable, - addAll: PromotedStoryList.Builder.(Iterable) -> PromotedStoryList.Builder - ): PromotedStoryList.Builder { - return this.addAll(iterable) - } - private fun computePlayedStories( topicProgressList: List, completionTimeFilter: (Long) -> Boolean diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 900b648bbb4..4baae398229 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -252,7 +252,7 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0( + verifyOngoingStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) } @@ -499,6 +499,64 @@ class TopicListControllerTest { ) } + @Test + fun testGetStoryList_story0DonePlayStory1FirstTestTopic_PlaySecondTestTopic_storyListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(2) + verifyOngoingStoryAsFirstTopicStory1Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + ) + verifyOngoingStoryAsSecondTopicStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) + } + @Test fun testRetrieveStoryList_markFirstExpOfEveryStoryDoneWithinLastMonth_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -585,11 +643,23 @@ class TopicListControllerTest { assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.completedChapterCount).isEqualTo(1) assertThat(promotedStory.totalChapterCount).isEqualTo(1) } private fun verifyPromotedStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) + assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) + assertThat(promotedStory.topicName).isEqualTo("Fractions") + assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + + private fun verifyOngoingStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) @@ -637,6 +707,18 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyPromotedStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) + assertThat(promotedStory.nextChapterName).isEqualTo("What is a Ratio?") + assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + private fun verifyOngoingStoryAsRatioStory0Exploration1(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_1) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) diff --git a/model/src/main/proto/topic.proto b/model/src/main/proto/topic.proto index 0f4b4777bed..9106276857f 100755 --- a/model/src/main/proto/topic.proto +++ b/model/src/main/proto/topic.proto @@ -204,7 +204,8 @@ message PromotedStory { // The thumbnail that should be displayed for this promoted story. LessonThumbnail lesson_thumbnail = 9; - // Indicates whether the topic containing this story is 'learned' (meaning at least one story was completed). + // Indicates whether the topic containing this story is 'learned' + // (meaning at least one story was completed). bool is_topic_learned = 10; } From 0aa5327409d333c21a37412d83c359b68e0c4cbe Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 00:16:57 +0530 Subject: [PATCH 207/248] Update domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 4baae398229..33797ab9bbb 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -500,7 +500,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_story0DonePlayStory1FirstTestTopic_PlaySecondTestTopic_storyListIsCorrect() { + fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playSecondTestTopic_storyListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, From fc94cec15ea18b4d3aa3f0cbcc7195080e47134b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 24 Jan 2021 04:09:32 +0530 Subject: [PATCH 208/248] implemented changes --- .../domain/topic/StoryProgressController.kt | 5 +- .../domain/topic/StoryProgressTestHelper.kt | 24 +++ .../domain/topic/TopicListController.kt | 141 ++++++++---------- .../topic/StoryProgressTestHelperTest.kt | 139 ++++++++++------- .../domain/topic/TopicListControllerTest.kt | 86 +++++++++-- 5 files changed, 244 insertions(+), 151 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt index 104fb6c5d20..d16fcb3da5e 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressController.kt @@ -112,13 +112,11 @@ class StoryProgressController @Inject constructor( val storyProgress = storyProgressBuilder.build() val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) - if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) - val topicProgress = topicProgressBuilder.build() val topicDatabaseBuilder = @@ -195,14 +193,13 @@ class StoryProgressController @Inject constructor( val storyProgress = storyProgressBuilder.build() val topicProgressBuilder = TopicProgress.newBuilder().setTopicId(topicId) - if (topicProgressDatabase.topicProgressMap[topicId] != null) { topicProgressBuilder .putAllStoryProgress(topicProgressDatabase.topicProgressMap[topicId]!!.storyProgressMap) } topicProgressBuilder.putStoryProgress(storyId, storyProgress) - val topicProgress = topicProgressBuilder.build() + val topicDatabaseBuilder = topicProgressDatabase.toBuilder().putTopicProgress(topicId, topicProgress) Pair(topicDatabaseBuilder.build(), StoryProgressActionStatus.SUCCESS) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index c2bd02b4d49..16b1c890696 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -283,6 +283,30 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** + * Marks one story progress full in ratios exploration for a particular profile. + * + * @param profileId the profile we are setting topic progress on ratios for + * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago + */ + fun markChapDoneOfRatiosStory0Exp2( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + timestamp + ) + } + /** * Marks two partial story progress in ratios exploration for a particular profile. * diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 60a62142c16..7e374568d6a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -254,6 +254,7 @@ class TopicListController @Inject constructor( completionTimeFilter: (Long) -> Boolean ): List { + var numberOfDaysPassed: Long val playedPromotedStoryList = mutableListOf() val sortedTopicProgressList = topicProgressList.sortedByDescending { @@ -274,7 +275,7 @@ class TopicListController @Inject constructor( val story = topicController.retrieveStory(topic.topicId, storyId) val completedChapterProgressList = getCompletedChapterProgressList(storyProgress) - val mostRecentCompletedChapterProgress: ChapterProgress? = + val latestCompletedChapterProgress: ChapterProgress? = completedChapterProgressList.firstOrNull() val startedChapterProgressList = getStartedChapterProgressList(storyProgress) @@ -287,30 +288,32 @@ class TopicListController @Inject constructor( storyId, story, latestStartedChapterProgress, - startedChapterProgressList, + completedChapterProgressList, topic, isTopicConsideredCompleted ).let { - Pair(it.first, it.second) - if (completionTimeFilter(it.second)) - it.first?.let { it1 -> playedPromotedStoryList.add(it1) } + numberOfDaysPassed = latestStartedChapterProgress.getNumberOfDaysPassed() + if (completionTimeFilter(numberOfDaysPassed)) { + playedPromotedStoryList.add(it!!) + } } } // Compute the ongoing story list for stories that are not fully completed yet. - mostRecentCompletedChapterProgress != null && - mostRecentCompletedChapterProgress.explorationId != + latestCompletedChapterProgress != null && + latestCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { createOngoingStoryListBasedOnMostRecentlyCompleted( storyId, story, - mostRecentCompletedChapterProgress, + latestCompletedChapterProgress, completedChapterProgressList, topic, isTopicConsideredCompleted ).let { - Pair(it.first, it.second) - if (completionTimeFilter(it.second)) - it.first?.let { it1 -> playedPromotedStoryList.add(it1) } + numberOfDaysPassed = latestCompletedChapterProgress.getNumberOfDaysPassed() + if (completionTimeFilter(numberOfDaysPassed)) { + playedPromotedStoryList.add(it!!) + } } } } @@ -367,87 +370,57 @@ class TopicListController @Inject constructor( private fun createOngoingStoryListBasedOnRecentlyPlayed( storyId: String, story: StorySummary, - recentlyPlayerChapterProgress: ChapterProgress, + latestStartedChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, isTopicConsideredCompleted: Boolean - ): Pair { - var numberOfDaysPassed = 0L + ): PromotedStory? { val recentlyPlayerChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + latestStartedChapterProgress.explorationId == chapterSummary.explorationId } if (recentlyPlayerChapterSummary != null) { - numberOfDaysPassed = recentlyPlayerChapterProgress.getNumberOfDaysPassed() - return Pair( - addPromotedStoryInRecommendedStoryList( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - recentlyPlayerChapterSummary.name, - recentlyPlayerChapterSummary.explorationId, - isTopicConsideredCompleted - ), - numberOfDaysPassed + return createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId, + isTopicConsideredCompleted ) } - return Pair(null, numberOfDaysPassed) + return null } private fun createOngoingStoryListBasedOnMostRecentlyCompleted( storyId: String, story: StorySummary, - mostRecentCompletedChapterProgress: ChapterProgress, + latestCompletedChapterProgress: ChapterProgress, completedChapterProgressList: List, topic: Topic, isTopicConsideredCompleted: Boolean - ): Pair { - var numberOfDaysPassed = 0L + ): PromotedStory? { val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> - mostRecentCompletedChapterProgress.explorationId == chapterSummary.explorationId + latestCompletedChapterProgress.explorationId == chapterSummary.explorationId } val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 if (story.chapterList.size > nextChapterIndex) { val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] if (nextChapterSummary != null) { - numberOfDaysPassed = mostRecentCompletedChapterProgress.getNumberOfDaysPassed() - return Pair( - addPromotedStoryInRecommendedStoryList( - storyId, - topic, - completedChapterProgressList.size, - story.chapterCount, - nextChapterSummary.name, - nextChapterSummary.explorationId, - isTopicConsideredCompleted - ), - numberOfDaysPassed + return createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId, + isTopicConsideredCompleted ) } } - return Pair(null, numberOfDaysPassed) - } - - private fun addPromotedStoryInRecommendedStoryList( - storyId: String, - topic: Topic, - completedChapterProgressListSize: Int, - chapterCount: Int, - chapterSummaryName: String, - chapterSummaryExplorationId: String, - isTopicConsideredCompleted: Boolean - ): PromotedStory { - return createPromotedStory( - storyId, - topic, - completedChapterProgressListSize, - chapterCount, - chapterSummaryName, - chapterSummaryExplorationId, - isTopicConsideredCompleted - ) + return null } private fun ChapterProgress.getNumberOfDaysPassed(): Long { @@ -456,25 +429,33 @@ class TopicListController @Inject constructor( ) } + private fun getDependentLisOfTopicForOngoingTopic(topicId: String): List { + val listOfTopicIds = mutableListOf() + if (topicId == TEST_TOPIC_ID_0) { + listOfTopicIds.add(FRACTIONS_TOPIC_ID) + } else if (topicId == TEST_TOPIC_ID_1) { + listOfTopicIds.add(TEST_TOPIC_ID_0) + listOfTopicIds.add(RATIOS_TOPIC_ID) + } + return listOfTopicIds + } + private fun computeSuggestedStories( topicProgressList: List ): List { val recommendedStories = mutableListOf() - - val topicIdJsonArray = jsonAssetRetriever - .loadJsonFromAsset("topics.json")!! - .getJSONArray("topic_id_list") - - val topicIdList = (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } - - val index = topicIdList.indexOf(topicProgressList.last().topicId) - - for (i in (index + 1) until topicIdJsonArray.length()) { - if (topicIdJsonArray.length() > i) { - val recommendedStoriesIdFromAssets = - createRecommendedStoryFromAssets(topicIdJsonArray[i].toString()) - if (recommendedStoriesIdFromAssets != null) - recommendedStories.add(recommendedStoriesIdFromAssets) + topicProgressList.forEach { + val dependentListOfTopics = + getDependentLisOfTopicForOngoingTopic(it.topicId) + for (j in dependentListOfTopics.indices) { + val found = topicProgressList.any { it.topicId == dependentListOfTopics[j] } + if (!found) { + val recommendedStoriesIdFromAssets = + createRecommendedStoryFromAssets(dependentListOfTopics[j]) + if (recommendedStoriesIdFromAssets != null) { + recommendedStories.add(recommendedStoriesIdFromAssets) + } + } } } return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index b6b9d5a4588..06ed410d3bd 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -752,14 +752,17 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].explorationId) + .isEqualTo( FRACTIONS_EXPLORATION_ID_0 ) - assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) - } + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].completedChapterCount + ).isEqualTo(0) } @Test @@ -777,14 +780,16 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(1) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_0 - ) - assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].completedChapterCount + ) + .isEqualTo(0) } @Test @@ -802,18 +807,21 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(2) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_0 - ) - assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[1].explorationId).isEqualTo( - RATIOS_EXPLORATION_ID_2 - ) - assertThat(recentlyPlayedStoryList[1].completedChapterCount).isEqualTo(0) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].completedChapterCount + ) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_2) + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1].completedChapterCount + ) + .isEqualTo(0) } @Test @@ -831,11 +839,13 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(suggestedStoryList[0].explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryList[0].explorationId) + .isEqualTo(TEST_EXPLORATION_ID_2) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryList[1].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_0) } @Test @@ -853,18 +863,24 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(2) - assertThat(olderPlayedStoryCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[0].explorationId).isEqualTo( + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].explorationId) + .isEqualTo( TEST_EXPLORATION_ID_2 ) - assertThat(recentlyPlayedStoryList[0].completedChapterCount).isEqualTo(0) - assertThat(recentlyPlayedStoryList[1].explorationId).isEqualTo( + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].completedChapterCount + ).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1].explorationId) + .isEqualTo( TEST_EXPLORATION_ID_4 ) - assertThat(recentlyPlayedStoryList[1].completedChapterCount).isEqualTo(0) - } + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1].completedChapterCount + ).isEqualTo(0) } @Test @@ -882,24 +898,33 @@ class StoryProgressTestHelperTest { verifyGetPromotedActivityListSucceeded() val promotedActivityList = promotedActivityListResultCaptor.value.getOrThrow() - with(promotedActivityList.promotedStoryList) { - assertThat(recentlyPlayedStoryCount).isEqualTo(0) - assertThat(olderPlayedStoryCount).isEqualTo(3) - - assertThat(olderPlayedStoryList[0].explorationId).isEqualTo( - FRACTIONS_EXPLORATION_ID_0 - ) - assertThat(olderPlayedStoryList[0].completedChapterCount) - .isEqualTo(0) - assertThat(olderPlayedStoryList[1].explorationId) - .isEqualTo(RATIOS_EXPLORATION_ID_0) - assertThat(olderPlayedStoryList[1].completedChapterCount) - .isEqualTo(0) - assertThat(olderPlayedStoryList[2].explorationId) - .isEqualTo(RATIOS_EXPLORATION_ID_2) - assertThat(olderPlayedStoryList[2].completedChapterCount) - .isEqualTo(0) - } + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(3) + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0].explorationId + ).isEqualTo( + FRACTIONS_EXPLORATION_ID_0 + ) + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0].completedChapterCount + ) + .isEqualTo(0) + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1].explorationId + ) + .isEqualTo(RATIOS_EXPLORATION_ID_0) + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1].completedChapterCount + ) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[2].explorationId) + .isEqualTo(RATIOS_EXPLORATION_ID_2) + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[2].completedChapterCount + ) + .isEqualTo(0) } private fun verifyGetTopicSucceeded() { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 33797ab9bbb..c3f6aa800b0 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -305,7 +305,7 @@ class TopicListControllerTest { } @Test - fun testGetPromotedStoryList_markAllChapsDoneInFractions_suggestedStoryListIsCorrect() { + fun testGetPromotedStoryList_markAllChapsDoneInFractions_storyListIsEmpty() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -325,10 +325,10 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) - verifyRecommendedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(0) } @Test @@ -447,6 +447,7 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) @@ -462,6 +463,58 @@ class TopicListControllerTest { ) } + @Test + fun testGetStoryList_markRecentlyPlayedforFirstTestTopic_promotedListIsCorrect() { + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + verifyOngoingStoryAsFirstTopicStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + } + + @Test + fun testGetStoryList_markOneStoryDoneForFirstTestTopic_suggestedListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + } + @Test fun testGetStoryList_markOneStoryDoneAndPlayNextStoryOfFirstTestTopic_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -617,7 +670,7 @@ class TopicListControllerTest { assertThat(promotedStory.nextChapterName).isEqualTo("Second Exploration") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.COMPARING_FRACTIONS) - assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.isTopicLearned).isTrue() assertThat(promotedStory.totalChapterCount).isEqualTo(3) } @@ -635,6 +688,19 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_0) + assertThat(promotedStory.topicName).isEqualTo("First Test Topic") + assertThat(promotedStory.nextChapterName).isEqualTo("Prototype Exploration") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.BAKER) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + private fun verifyOngoingStoryAsSecondTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) @@ -643,7 +709,7 @@ class TopicListControllerTest { assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) - assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(1) } @@ -667,7 +733,7 @@ class TopicListControllerTest { assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) - assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -703,7 +769,7 @@ class TopicListControllerTest { assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) - assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -746,7 +812,7 @@ class TopicListControllerTest { assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) - assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) assertThat(promotedStory.totalChapterCount).isEqualTo(2) } From f797fa30bab407253b9138324b482411ca091eeb Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 24 Jan 2021 13:43:53 +0530 Subject: [PATCH 209/248] updated list ids --- .../domain/topic/StoryProgressTestHelper.kt | 117 +++++++++++++- .../domain/topic/TopicListController.kt | 144 +++++++++++++----- .../topic/StoryProgressTestHelperTest.kt | 5 +- .../domain/topic/TopicListControllerTest.kt | 71 ++++++--- 4 files changed, 270 insertions(+), 67 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 16b1c890696..380a9e41ebe 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -41,6 +41,28 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** + * Creates a partial story progress for a particular profile. + * + * @param profileId the profile we are setting partial progress of the fraction story for + * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago + */ + + fun markChapDoneFrac0Story0Expl(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + timestamp + ) + } + /** * Creates a partial topic progress for a particular profile. * @@ -252,6 +274,27 @@ class StoryProgressTestHelper @Inject constructor( ) } +/** + * Marks recently played on the second test topic for a particular profile. + * + * @param profileId the profile we are setting topic progress for + * @param timestampOlderThanOneWeek if the timestamp for completing the topic is from more than one week ago + */ + fun markRecentlyPlayedForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordRecentlyPlayedChapter( + profileId, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + timestamp + ) + } + /** * Marks one story progress fully complete in the ratios topic for a particular profile. * @@ -289,7 +332,31 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting topic progress on ratios for * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago */ - fun markChapDoneOfRatiosStory0Exp2( + fun markChapDoneOfRatiosStory0Exp0( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + timestamp + ) + } + + /** + * Marks one story progress full in ratios exploration for a particular profile. + * + * @param profileId the profile we are setting topic progress on ratios for + * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago + */ + fun markChapDoneOfRatiosStory0Exp1( profileId: ProfileId, timestampOlderThanAWeek: Boolean ) { @@ -490,4 +557,52 @@ class StoryProgressTestHelper @Inject constructor( timestamp ) } + + /** + * Marks one explorations in first test topic as completed played for a particular profile. + * + * @param profileId the profile we are setting recently played for + * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + */ + fun markChapterDoneFirstTestTopicStory0Exploration0( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + timestamp + ) + } + + /** + * Marks one explorations in first test topic as completed for a particular profile. + * + * @param profileId the profile we are setting recently played for + * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + */ + fun markChapterDoneFirstTestTopicStory0Exploration1( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + timestamp + ) + } } diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 7e374568d6a..7e395cade20 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -48,6 +48,12 @@ const val FRACTIONS_TOPIC_ID = "GJ2rLXRKD5hw" const val SUBTOPIC_TOPIC_ID = 1 const val SUBTOPIC_TOPIC_ID_2 = 2 const val RATIOS_TOPIC_ID = "omzF4oqgeTXd" +const val PLACE_VALUE_TOPIC_ID = "id0" +const val ADDITION_AND_SUBTRACTION_TOPIC_ID = "id1" +const val MULTIPLICATION_TOPIC_ID = "id2" +const val DIVISION_TOPIC_ID = "id3" +const val EXPRESSION_AND_EQUATION_TOPIC_ID = "id4" +const val DECIMALS_TOPIC_ID = "id5" val TOPIC_THUMBNAILS = mapOf( FRACTIONS_TOPIC_ID to createTopicThumbnail0(), RATIOS_TOPIC_ID to createTopicThumbnail1(), @@ -254,7 +260,6 @@ class TopicListController @Inject constructor( completionTimeFilter: (Long) -> Boolean ): List { - var numberOfDaysPassed: Long val playedPromotedStoryList = mutableListOf() val sortedTopicProgressList = topicProgressList.sortedByDescending { @@ -284,17 +289,17 @@ class TopicListController @Inject constructor( when { latestStartedChapterProgress != null -> { - createOngoingStoryListBasedOnRecentlyPlayed( - storyId, - story, - latestStartedChapterProgress, - completedChapterProgressList, - topic, - isTopicConsideredCompleted - ).let { - numberOfDaysPassed = latestStartedChapterProgress.getNumberOfDaysPassed() - if (completionTimeFilter(numberOfDaysPassed)) { - playedPromotedStoryList.add(it!!) + val numberOfDaysPassed = latestStartedChapterProgress.getNumberOfDaysPassed() + if (completionTimeFilter(numberOfDaysPassed)) { + createOngoingStoryListBasedOnRecentlyPlayed( + storyId, + story, + latestStartedChapterProgress, + completedChapterProgressList, + topic, + isTopicConsideredCompleted + )?.let { promotedStory -> + playedPromotedStoryList.add(promotedStory) } } } @@ -302,17 +307,17 @@ class TopicListController @Inject constructor( latestCompletedChapterProgress != null && latestCompletedChapterProgress.explorationId != story.chapterList.last().explorationId -> { - createOngoingStoryListBasedOnMostRecentlyCompleted( - storyId, - story, - latestCompletedChapterProgress, - completedChapterProgressList, - topic, - isTopicConsideredCompleted - ).let { - numberOfDaysPassed = latestCompletedChapterProgress.getNumberOfDaysPassed() - if (completionTimeFilter(numberOfDaysPassed)) { - playedPromotedStoryList.add(it!!) + val numberOfDaysPassed = latestCompletedChapterProgress.getNumberOfDaysPassed() + if (completionTimeFilter(numberOfDaysPassed)) { + createOngoingStoryListBasedOnMostRecentlyCompleted( + storyId, + story, + latestCompletedChapterProgress, + completedChapterProgressList, + topic, + isTopicConsideredCompleted + )?.let { promotedStory -> + playedPromotedStoryList.add(promotedStory) } } } @@ -429,13 +434,37 @@ class TopicListController @Inject constructor( ) } - private fun getDependentLisOfTopicForOngoingTopic(topicId: String): List { + // TODO(#2550): Remove hardcoded order of topics. Compute list of suggested stories from backend structures + /** Returns a list of topic IDs for which the specified topic ID expects to be completed before being suggested. */ + private fun retrieveTopicDependencies(topicId: String): List { val listOfTopicIds = mutableListOf() - if (topicId == TEST_TOPIC_ID_0) { - listOfTopicIds.add(FRACTIONS_TOPIC_ID) - } else if (topicId == TEST_TOPIC_ID_1) { - listOfTopicIds.add(TEST_TOPIC_ID_0) - listOfTopicIds.add(RATIOS_TOPIC_ID) + when (topicId) { + FRACTIONS_TOPIC_ID -> { + listOfTopicIds.add(TEST_TOPIC_ID_0) + } + RATIOS_TOPIC_ID -> { + listOfTopicIds.add(TEST_TOPIC_ID_0) + listOfTopicIds.add(TEST_TOPIC_ID_1) + } + ADDITION_AND_SUBTRACTION_TOPIC_ID -> { + listOfTopicIds.add(PLACE_VALUE_TOPIC_ID) + } + MULTIPLICATION_TOPIC_ID -> { + listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + } + DIVISION_TOPIC_ID -> { + listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + } + EXPRESSION_AND_EQUATION_TOPIC_ID -> { + listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + listOfTopicIds.add(DIVISION_TOPIC_ID) + } + DECIMALS_TOPIC_ID -> { + listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + listOfTopicIds.add(DIVISION_TOPIC_ID) + } } return listOfTopicIds } @@ -444,16 +473,43 @@ class TopicListController @Inject constructor( topicProgressList: List ): List { val recommendedStories = mutableListOf() - topicProgressList.forEach { - val dependentListOfTopics = - getDependentLisOfTopicForOngoingTopic(it.topicId) - for (j in dependentListOfTopics.indices) { - val found = topicProgressList.any { it.topicId == dependentListOfTopics[j] } - if (!found) { - val recommendedStoriesIdFromAssets = - createRecommendedStoryFromAssets(dependentListOfTopics[j]) - if (recommendedStoriesIdFromAssets != null) { - recommendedStories.add(recommendedStoriesIdFromAssets) + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") + + // Check if any prerequisite topic user needs to learn. + for (i in 0 until topicIdJsonArray.length()) { + val topicInProgressFound = topicProgressList.any { it.topicId == topicIdJsonArray[i] } + if (topicInProgressFound) { + val dependentListOfTopics = + retrieveTopicDependencies(topicIdJsonArray[i].toString()) + for (j in dependentListOfTopics.indices) { + val dependentTopicIdsFound = + topicProgressList.any { it.topicId == dependentListOfTopics[j] } + val recommendedTopicAlreadyExist = + recommendedStories.any { it.topicId == dependentListOfTopics[j] } + if (!dependentTopicIdsFound && !recommendedTopicAlreadyExist) { + fetchListOfRecommendedStories(dependentListOfTopics[j])?.let { + recommendedStories.add(it) + } + } + } + } + } + + // If no any dependent topics to recommend. Recommend next topic,only if any ongoing topic is completed. + if (recommendedStories.size == 0) { + val topicIdList = + (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } + val index = topicIdList.indexOf(topicProgressList.last().topicId) + val topic = topicController.retrieveTopic(topicProgressList.last().topicId) + if (checkIfAtLeastOneStoryIsCompleted(topicProgressList.last(), topic)) { + for (i in (index + 1) until topicIdJsonArray.length()) { + if (topicIdJsonArray.length() > i) { + fetchListOfRecommendedStories(topicIdJsonArray[i].toString())?.let { + recommendedStories.add(it) + return recommendedStories + } } } } @@ -461,6 +517,16 @@ class TopicListController @Inject constructor( return recommendedStories } + private fun fetchListOfRecommendedStories(topicId: String): PromotedStory? { + val recommendedStoriesIdFromAssets = + createRecommendedStoryFromAssets(topicId) + if (recommendedStoriesIdFromAssets != null) { + return recommendedStoriesIdFromAssets + } else { + return null + } + } + private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!! if (!topicJson.getBoolean("published")) { diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 06ed410d3bd..e5554453921 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -842,10 +842,9 @@ class StoryProgressTestHelperTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) assertThat(promotedActivityList.promotedStoryList.suggestedStoryList[0].explorationId) - .isEqualTo(TEST_EXPLORATION_ID_2) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryList[1].explorationId) - .isEqualTo(RATIOS_EXPLORATION_ID_0) + .isEqualTo(FRACTIONS_EXPLORATION_ID_0) } @Test diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index c3f6aa800b0..5e1f9702c25 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -277,7 +277,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_ongoingStoryListCorrect() { + fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_suggestedStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -302,10 +302,15 @@ class TopicListControllerTest { verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test - fun testGetPromotedStoryList_markAllChapsDoneInFractions_storyListIsEmpty() { + fun testGetPromotedStoryList_markAllChapsDoneInFractions_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -328,7 +333,7 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(0) + .isEqualTo(1) } @Test @@ -415,9 +420,14 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) - .isEqualTo(1) - verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(2) + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + verifyPromotedStoryAsSecondTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) } @Test @@ -464,7 +474,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markRecentlyPlayedforFirstTestTopic_promotedListIsCorrect() { + fun testGetStoryList_markRecentlyPlayedForFirstTestTopic_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, TEST_TOPIC_ID_0, @@ -481,14 +491,11 @@ class TopicListControllerTest { promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) + .isEqualTo(0) } @Test - fun testGetStoryList_markOneStoryDoneForFirstTestTopic_suggestedListIsCorrect() { + fun testGetStoryList_markOneStoryDoneForFracTopic_suggestedListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -508,11 +515,8 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) } @Test @@ -595,19 +599,13 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) + .isEqualTo(0) verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) verifyOngoingStoryAsSecondTopicStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) - verifyPromotedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] - ) } @Test @@ -662,6 +660,19 @@ class TopicListControllerTest { assertThat(promotedActivityListResultCaptor.value.isSuccess()).isTrue() } + private fun verifyPromotedStoryAsFirstTestTopicStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_0) + assertThat(promotedStory.topicName).isEqualTo("First Test Topic") + assertThat(promotedStory.nextChapterName).isEqualTo("Prototype Exploration") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.BAKER) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + private fun verifyOngoingStoryAsFirstTopicStory1Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_1) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_1) @@ -713,6 +724,18 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(1) } + private fun verifyPromotedStoryAsSecondTestTopicStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) + assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) + assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) + assertThat(promotedStory.topicName).isEqualTo("Second Test Topic") + assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.totalChapterCount).isEqualTo(1) + } + private fun verifyPromotedStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) From ad91320f057058c1aa22342cfe9e369598baaebf Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 15:48:39 +0530 Subject: [PATCH 210/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 380a9e41ebe..917da1f0864 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -562,7 +562,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks one explorations in first test topic as completed played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago */ fun markChapterDoneFirstTestTopicStory0Exploration0( profileId: ProfileId, From 6c4d2f1e626dbb8a93f931fa62fc3baa6610c83d Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 15:48:53 +0530 Subject: [PATCH 211/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 917da1f0864..cdc7a8fecb8 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -354,7 +354,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks one story progress full in ratios exploration for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago + * @param timestampOlderThanAWeek if the timestamp for this progress is from more than one week ago */ fun markChapDoneOfRatiosStory0Exp1( profileId: ProfileId, From 03244c138dde8b38e0fa32fe1bba7b6dee93bdbb Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 18:04:02 +0530 Subject: [PATCH 212/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index cdc7a8fecb8..002ee8c5217 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -586,7 +586,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks one explorations in first test topic as completed for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago */ fun markChapterDoneFirstTestTopicStory0Exploration1( profileId: ProfileId, From 06af4c7d63ca7f0a126368e14c2ce3302f86bd94 Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 18:04:29 +0530 Subject: [PATCH 213/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 002ee8c5217..fabcfecca6a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -330,7 +330,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks one story progress full in ratios exploration for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago + * @param timestampOlderThanAWeek if the timestamp for this progress is from more than one week ago */ fun markChapDoneOfRatiosStory0Exp0( profileId: ProfileId, From 3e157bc70688111f62ff38cdb78fd85e42a7d3d9 Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 18:04:46 +0530 Subject: [PATCH 214/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index fabcfecca6a..6562dc18733 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -257,7 +257,7 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on the second test topic for a particular profile. * * @param profileId the profile we are setting topic progress for - * @param timestampOlderThanOneWeek if the timestamp for completing the topic is from more than one week ago + * @param timestampOlderThanAWeek if the timestamp for completing the topic is from more than one week ago */ fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { From 5bb456697bda4f55608a2c23d25d113087dfb42a Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 24 Jan 2021 18:05:31 +0530 Subject: [PATCH 215/248] Update domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt Co-authored-by: Farees Hussain --- .../org/oppia/android/domain/topic/StoryProgressTestHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 6562dc18733..ed4469e8672 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -45,7 +45,7 @@ class StoryProgressTestHelper @Inject constructor( * Creates a partial story progress for a particular profile. * * @param profileId the profile we are setting partial progress of the fraction story for - * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago + * @param timestampOlderThanAWeek if the timestamp for this topic progress is more than one week ago */ fun markChapDoneFrac0Story0Expl(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { From 3d437453e645266c37aeda67ba42314204f57da3 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 24 Jan 2021 18:21:57 +0530 Subject: [PATCH 216/248] updated --- .../domain/topic/StoryProgressTestHelper.kt | 4 +- .../domain/topic/TopicListController.kt | 134 +++++++++--------- .../domain/topic/TopicListControllerTest.kt | 123 ++++++++++++++-- 3 files changed, 176 insertions(+), 85 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index ed4469e8672..e9e9404103a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -274,7 +274,7 @@ class StoryProgressTestHelper @Inject constructor( ) } -/** + /** * Marks recently played on the second test topic for a particular profile. * * @param profileId the profile we are setting topic progress for @@ -559,7 +559,7 @@ class StoryProgressTestHelper @Inject constructor( } /** - * Marks one explorations in first test topic as completed played for a particular profile. + * Marks one exploration in first test topic as completed played for a particular profile. * * @param profileId the profile we are setting recently played for * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 7e395cade20..ca502c6cf45 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -439,12 +439,22 @@ class TopicListController @Inject constructor( private fun retrieveTopicDependencies(topicId: String): List { val listOfTopicIds = mutableListOf() when (topicId) { - FRACTIONS_TOPIC_ID -> { + TEST_TOPIC_ID_0 -> { + listOfTopicIds.add(FRACTIONS_TOPIC_ID) + } + TEST_TOPIC_ID_1 -> { listOfTopicIds.add(TEST_TOPIC_ID_0) + listOfTopicIds.add(RATIOS_TOPIC_ID) + } + FRACTIONS_TOPIC_ID -> { + listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + listOfTopicIds.add(DIVISION_TOPIC_ID) } RATIOS_TOPIC_ID -> { - listOfTopicIds.add(TEST_TOPIC_ID_0) - listOfTopicIds.add(TEST_TOPIC_ID_1) + listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + listOfTopicIds.add(DIVISION_TOPIC_ID) } ADDITION_AND_SUBTRACTION_TOPIC_ID -> { listOfTopicIds.add(PLACE_VALUE_TOPIC_ID) @@ -476,39 +486,30 @@ class TopicListController @Inject constructor( val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") + val topicIdList = + (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } - // Check if any prerequisite topic user needs to learn. - for (i in 0 until topicIdJsonArray.length()) { + // Suggest prerequisite topic user needs to learn after completing any of the topics. + for (i in 0 until topicIdList.size) { val topicInProgressFound = topicProgressList.any { it.topicId == topicIdJsonArray[i] } - if (topicInProgressFound) { + if (!topicInProgressFound) { val dependentListOfTopics = - retrieveTopicDependencies(topicIdJsonArray[i].toString()) + retrieveTopicDependencies(topicIdList[i]) for (j in dependentListOfTopics.indices) { - val dependentTopicIdsFound = - topicProgressList.any { it.topicId == dependentListOfTopics[j] } - val recommendedTopicAlreadyExist = - recommendedStories.any { it.topicId == dependentListOfTopics[j] } - if (!dependentTopicIdsFound && !recommendedTopicAlreadyExist) { - fetchListOfRecommendedStories(dependentListOfTopics[j])?.let { - recommendedStories.add(it) - } - } - } - } - } - - // If no any dependent topics to recommend. Recommend next topic,only if any ongoing topic is completed. - if (recommendedStories.size == 0) { - val topicIdList = - (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } - val index = topicIdList.indexOf(topicProgressList.last().topicId) - val topic = topicController.retrieveTopic(topicProgressList.last().topicId) - if (checkIfAtLeastOneStoryIsCompleted(topicProgressList.last(), topic)) { - for (i in (index + 1) until topicIdJsonArray.length()) { - if (topicIdJsonArray.length() > i) { - fetchListOfRecommendedStories(topicIdJsonArray[i].toString())?.let { - recommendedStories.add(it) - return recommendedStories + topicProgressList.mapIndexed { index, topicProgress -> + if (topicProgress.topicId == dependentListOfTopics[j]) { + val topic = topicController.retrieveTopic(topicProgressList[index].topicId) + if (checkIfAtLeastOneStoryIsCompleted(topicProgressList[index], topic)) { + val recommendedTopicAlreadyExist = + recommendedStories.any { it.topicId == topicIdList[i] } + if (!recommendedTopicAlreadyExist) { + val recommendedStoriesIdFromAssets = + createRecommendedStoryFromAssets(topicIdList[i]) + if (recommendedStoriesIdFromAssets != null) { + recommendedStories.add(recommendedStoriesIdFromAssets) + } + } + } } } } @@ -517,47 +518,42 @@ class TopicListController @Inject constructor( return recommendedStories } - private fun fetchListOfRecommendedStories(topicId: String): PromotedStory? { - val recommendedStoriesIdFromAssets = - createRecommendedStoryFromAssets(topicId) - if (recommendedStoriesIdFromAssets != null) { - return recommendedStoriesIdFromAssets - } else { - return null - } - } - private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { - val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json")!! - if (!topicJson.getBoolean("published")) { - // Do not recommend unpublished topics. - return null - } - val storyData = topicJson.getJSONArray("canonical_story_dicts") - if (storyData.length() == 0) { - return PromotedStory.getDefaultInstance() - } - val totalChapterCount = storyData - .getJSONObject(0) - .getJSONArray("node_titles") - .length() - val storyId = storyData.optJSONObject(0).optString("id") - val storySummary = topicController.retrieveStory(topicId, storyId) + val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json") + if (topicJson!!.optString("topic_name").isNullOrEmpty()) { + return null + } else { + if (!topicJson.getBoolean("published")) { + // Do not recommend unpublished topics. + return null + } - val promotedStoryBuilder = PromotedStory.newBuilder() - .setStoryId(storyId) - .setStoryName(storySummary.storyName) - .setLessonThumbnail(storySummary.storyThumbnail) - .setTopicId(topicId) - .setTopicName(topicJson.optString("topic_name")) - .setCompletedChapterCount(0) - .setTotalChapterCount(totalChapterCount) - if (storySummary.chapterList.isNotEmpty()) { - promotedStoryBuilder.nextChapterName = storySummary.chapterList[0].name - promotedStoryBuilder.explorationId = storySummary.chapterList[0].explorationId + val storyData = topicJson.getJSONArray("canonical_story_dicts") + if (storyData.length() == 0) { + return PromotedStory.getDefaultInstance() + } + val totalChapterCount = storyData + .getJSONObject(0) + .getJSONArray("node_titles") + .length() + val storyId = storyData.optJSONObject(0).optString("id") + val storySummary = topicController.retrieveStory(topicId, storyId) + + val promotedStoryBuilder = PromotedStory.newBuilder() + .setStoryId(storyId) + .setStoryName(storySummary.storyName) + .setLessonThumbnail(storySummary.storyThumbnail) + .setTopicId(topicId) + .setTopicName(topicJson.optString("topic_name")) + .setCompletedChapterCount(0) + .setTotalChapterCount(totalChapterCount) + if (storySummary.chapterList.isNotEmpty()) { + promotedStoryBuilder.nextChapterName = storySummary.chapterList[0].name + promotedStoryBuilder.explorationId = storySummary.chapterList[0].explorationId + } + return promotedStoryBuilder.build() } - return promotedStoryBuilder.build() } private fun createPromotedStory( diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 5e1f9702c25..2be2fe2eb4b 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -277,7 +277,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_suggestedStoryListCorrect() { + fun testGetStoryList_markChapDoneFracStory0Exp0_playedFracStory0Exp1_ongoingStoryListCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -302,11 +302,6 @@ class TopicListControllerTest { verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) } @Test @@ -334,6 +329,9 @@ class TopicListControllerTest { .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test @@ -399,7 +397,42 @@ class TopicListControllerTest { } @Test - fun testRetrievePromotedActivityList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { + fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, @@ -421,13 +454,77 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + .isEqualTo(1) + + verifyPromotedStoryAsSecondTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) - verifyPromotedStoryAsSecondTestTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] + } + + @Test + fun testRetrievePromotedActivityList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) + .isEqualTo(1) } @Test @@ -490,12 +587,10 @@ class TopicListControllerTest { verifyOngoingStoryAsFirstTopicStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(0) } @Test - fun testGetStoryList_markOneStoryDoneForFracTopic_suggestedListIsCorrect() { + fun testGetStoryList_markOneStoryDoneForFirstTestTopic_ongoingStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, From 6f12d2d52d81be1f87e4d02858bc51a7a5af5eff Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 25 Jan 2021 00:03:42 +0530 Subject: [PATCH 217/248] added helper tests --- .../domain/topic/StoryProgressTestHelper.kt | 28 +++++++++++++++++-- .../topic/StoryProgressTestHelperTest.kt | 8 +++--- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index e9e9404103a..6d9bf27c49d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -26,7 +26,7 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting partial progress of the fraction story for * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago */ - fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + fun markChapDoneFrac0Story0Exp0(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { @@ -42,7 +42,7 @@ class StoryProgressTestHelper @Inject constructor( } /** - * Creates a partial story progress for a particular profile. + * Mark a partial story progress for a particular profile. * * @param profileId the profile we are setting partial progress of the fraction story for * @param timestampOlderThanAWeek if the timestamp for this topic progress is more than one week ago @@ -582,6 +582,30 @@ class StoryProgressTestHelper @Inject constructor( ) } + /** + * Marks one exploration in first test topic as completed played for a particular profile. + * + * @param profileId the profile we are setting recently played for + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago + */ + fun markRecentlyPlayedFirstTestTopicStory1Exploration1( + profileId: ProfileId, + timestampOlderThanAWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordRecentlyPlayedChapter( + profileId, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_1, + timestamp + ) + } + /** * Marks one explorations in first test topic as completed for a particular profile. * diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index e5554453921..c038007a982 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -126,7 +126,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getTopicIsCorrect() { - storyProgressTestHelper.markPartialStoryProgressForFractions( + storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, timestampOlderThanAWeek = false ) @@ -149,7 +149,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getStoryIsCorrect() { - storyProgressTestHelper.markPartialStoryProgressForFractions( + storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, timestampOlderThanAWeek = false ) @@ -171,7 +171,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getOngoingTopicListIsCorrect() { - storyProgressTestHelper.markPartialStoryProgressForFractions( + storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, timestampOlderThanAWeek = false ) @@ -191,7 +191,7 @@ class StoryProgressTestHelperTest { @Test fun testProgressTestHelper_markPartialStoryProgressForFractions_getCompletedStoryListIsCorrect() { - storyProgressTestHelper.markPartialStoryProgressForFractions( + storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, timestampOlderThanAWeek = false ) From 615d2f5333dd9a1ce3181d773da2db07bbf4e8ba Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 25 Jan 2021 01:00:21 +0530 Subject: [PATCH 218/248] Update StoryProgressTestHelperTest.kt --- .../android/domain/topic/StoryProgressTestHelperTest.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index c038007a982..e3dc6c59fa8 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -825,7 +825,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markFullProgressForSecondTestTopic_promotedStoryListIsCorrect() { + fun testProgressTestHelper_markFullProgressForSecondTestTopic_comingSooTopicIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTestTopic( profileId = profileId, timestampOlderThanAWeek = false @@ -842,9 +842,8 @@ class StoryProgressTestHelperTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(1) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryList[0].explorationId) - .isEqualTo(FRACTIONS_EXPLORATION_ID_0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) } @Test From 394566abb695ae3e80b264cd490bfa31f96f1ed6 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 25 Jan 2021 01:10:13 +0530 Subject: [PATCH 219/248] Update TopicController.kt --- .../java/org/oppia/android/domain/topic/TopicController.kt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt index 9161578a77d..0ef8cc76fcb 100755 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicController.kt @@ -269,11 +269,6 @@ class TopicController @Inject constructor( } } } - - // If there is no completed chapter, it cannot be an ongoing-topic. - if (completedChapterProgressList.isEmpty()) { - return false - } return false } From fb155e26a75a6276a0b369480929c8a49a6f27ae Mon Sep 17 00:00:00 2001 From: veena14cs Date: Mon, 25 Jan 2021 15:17:13 +0530 Subject: [PATCH 220/248] Updated Suggestion logic --- .../domain/topic/TopicListController.kt | 105 +++++++++++------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index ca502c6cf45..47a365f91a7 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -273,7 +273,7 @@ class TopicListController @Inject constructor( sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - val isTopicConsideredCompleted = checkIfAtLeastOneStoryIsCompleted(topicProgress, topic) + val isTopicConsideredCompleted = topicHasAtLeastOnStoryCompleted(topicProgress) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId @@ -327,21 +327,6 @@ class TopicListController @Inject constructor( return playedPromotedStoryList } - private fun checkIfAtLeastOneStoryIsCompleted( - topicProgress: TopicProgress, - topic: Topic - ): Boolean { - topicProgress.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) - val isStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) - if (isStoryCompleted) { - return true - } - } - return false - } - private fun checkIfStoryIsCompleted( storyProgress: StoryProgress, storySummary: StorySummary @@ -486,38 +471,80 @@ class TopicListController @Inject constructor( val topicIdJsonArray = jsonAssetRetriever .loadJsonFromAsset("topics.json")!! .getJSONArray("topic_id_list") + + // The list of started or completed topic IDs. + val startedTopicIds = topicProgressList.map(TopicProgress::getTopicId) + // All topics that could potentially be recommended. val topicIdList = (0 until topicIdJsonArray.length()).map { topicIdJsonArray[it].toString() } - + // The list of topic IDs that qualify for being recommended. + val unstartedTopicIdList = topicIdList.filterNot { startedTopicIds.contains(it) } + + // A map of topic IDs to their dependencies. + val topicDependencyMap = topicIdList.associateWith { + retrieveTopicDependencies(it).toSet() + }.withDefault { setOf() } + // The list of topic IDs that are considered "finished" from a recommendation perspective. + val fullyCompletedTopicIds = topicProgressList.filter { + topicHasAtLeastOnStoryCompleted(it) + }.map(TopicProgress::getTopicId) + // A set of topic IDs that can be considered topics that should not be recommended. + val impliedFinishedTopicIds = computeImpliedCompletedDependencies( + fullyCompletedTopicIds, topicDependencyMap + ) // Suggest prerequisite topic user needs to learn after completing any of the topics. - for (i in 0 until topicIdList.size) { - val topicInProgressFound = topicProgressList.any { it.topicId == topicIdJsonArray[i] } - if (!topicInProgressFound) { - val dependentListOfTopics = - retrieveTopicDependencies(topicIdList[i]) - for (j in dependentListOfTopics.indices) { - topicProgressList.mapIndexed { index, topicProgress -> - if (topicProgress.topicId == dependentListOfTopics[j]) { - val topic = topicController.retrieveTopic(topicProgressList[index].topicId) - if (checkIfAtLeastOneStoryIsCompleted(topicProgressList[index], topic)) { - val recommendedTopicAlreadyExist = - recommendedStories.any { it.topicId == topicIdList[i] } - if (!recommendedTopicAlreadyExist) { - val recommendedStoriesIdFromAssets = - createRecommendedStoryFromAssets(topicIdList[i]) - if (recommendedStoriesIdFromAssets != null) { - recommendedStories.add(recommendedStoriesIdFromAssets) - } - } - } - } - } + for (topicId in unstartedTopicIdList) { + // All of the topic's prerequisites must be completed before it can be suggested. + val dependentTopicIds = topicDependencyMap[topicId] + if (topicId !in impliedFinishedTopicIds && startedTopicIds.containsAll(dependentTopicIds!!)) { + createRecommendedStoryFromAssets(topicId)?.let { + recommendedStories.add(it) } } } return recommendedStories } + private fun topicHasAtLeastOnStoryCompleted(it: TopicProgress): Boolean { + val topic = topicController.retrieveTopic(it.topicId) + it.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) + val isStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) + if (isStoryCompleted) { + return true + } + } + return false + } + + /** Returns the list of topic IDs that are completed or can be implied completed based on actually completed topics. */ + private fun computeImpliedCompletedDependencies( + fullyCompletedTopicIds: List, + topicDependencyMap: Map> + ): Set { + // For each completed topic ID, compute the transitive closure of all of its dependencies & then combine them into a single list with the actual completed topic IDs. The returned list is a list of either completed or assumed completed topics which will eliminate potential recommendations. + return ( + fullyCompletedTopicIds.flatMap { topicId -> + computeTransitiveDependencyClosure(topicId, topicDependencyMap) + } + fullyCompletedTopicIds + ).toSet() + } + + private fun computeTransitiveDependencyClosure( + topicId: String, + topicDependencyMap: Map> + ): Set { + // Compute the total list of dependent topics that must be completed before the specified topic can be recommended. Note that this will cause a stack overflow if the graph has cycles. + val topicDependencyList = topicDependencyMap[topicId]?.flatMap { dependentId -> + computeTransitiveDependencyClosure( + dependentId, + topicDependencyMap + ) + } + return topicDependencyList?.toSet() ?: emptySet() + } + private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json") From 486ba33a439ed9a456edab7170398d222aea7ac1 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 26 Jan 2021 18:07:44 +0530 Subject: [PATCH 221/248] Update TopicListController.kt --- .../domain/topic/TopicListController.kt | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 47a365f91a7..f7f6c665e87 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -273,7 +273,7 @@ class TopicListController @Inject constructor( sortedTopicProgressList.forEach { topicProgress -> val topic = topicController.retrieveTopic(topicProgress.topicId) - val isTopicConsideredCompleted = topicHasAtLeastOnStoryCompleted(topicProgress) + val isTopicConsideredCompleted = topicHasAtLeastOneStoryCompleted(topicProgress) topicProgress.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId @@ -486,7 +486,7 @@ class TopicListController @Inject constructor( }.withDefault { setOf() } // The list of topic IDs that are considered "finished" from a recommendation perspective. val fullyCompletedTopicIds = topicProgressList.filter { - topicHasAtLeastOnStoryCompleted(it) + topicHasAtLeastOneStoryCompleted(it) }.map(TopicProgress::getTopicId) // A set of topic IDs that can be considered topics that should not be recommended. val impliedFinishedTopicIds = computeImpliedCompletedDependencies( @@ -495,7 +495,7 @@ class TopicListController @Inject constructor( // Suggest prerequisite topic user needs to learn after completing any of the topics. for (topicId in unstartedTopicIdList) { // All of the topic's prerequisites must be completed before it can be suggested. - val dependentTopicIds = topicDependencyMap[topicId] + val dependentTopicIds = topicDependencyMap[topicId] ?: listOf() if (topicId !in impliedFinishedTopicIds && startedTopicIds.containsAll(dependentTopicIds!!)) { createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) @@ -505,7 +505,7 @@ class TopicListController @Inject constructor( return recommendedStories } - private fun topicHasAtLeastOnStoryCompleted(it: TopicProgress): Boolean { + private fun topicHasAtLeastOneStoryCompleted(it: TopicProgress): Boolean { val topic = topicController.retrieveTopic(it.topicId) it.storyProgressMap.values.forEach { storyProgress -> val storyId = storyProgress.storyId @@ -518,24 +518,30 @@ class TopicListController @Inject constructor( return false } - /** Returns the list of topic IDs that are completed or can be implied completed based on actually completed topics. */ + /** Returns the list of topic IDs that are completed or can be implied completed based on actually + * completed topics. + * */ private fun computeImpliedCompletedDependencies( fullyCompletedTopicIds: List, topicDependencyMap: Map> ): Set { - // For each completed topic ID, compute the transitive closure of all of its dependencies & then combine them into a single list with the actual completed topic IDs. The returned list is a list of either completed or assumed completed topics which will eliminate potential recommendations. - return ( + // For each completed topic ID, compute the transitive closure of all of its dependencies & + // then combine them into a single list with the actual completed topic IDs. The returned list + // is a list of either completed or assumed completed topics which will eliminate potential + // recommendations. + val completedTopicIds = fullyCompletedTopicIds.flatMap { topicId -> computeTransitiveDependencyClosure(topicId, topicDependencyMap) } + fullyCompletedTopicIds - ).toSet() + return completedTopicIds.toSet() } private fun computeTransitiveDependencyClosure( topicId: String, topicDependencyMap: Map> ): Set { - // Compute the total list of dependent topics that must be completed before the specified topic can be recommended. Note that this will cause a stack overflow if the graph has cycles. + // Compute the total list of dependent topics that must be completed before the specified topic + // can be recommended. Note that this will cause a stack overflow if the graph has cycles. val topicDependencyList = topicDependencyMap[topicId]?.flatMap { dependentId -> computeTransitiveDependencyClosure( dependentId, From c8e99b8ebb0c49a5cbe6f772227bf83fae33e64b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Tue, 26 Jan 2021 23:46:07 +0530 Subject: [PATCH 222/248] rename testcase --- .../domain/topic/TopicListController.kt | 2 +- .../domain/topic/TopicListControllerTest.kt | 18 ++++-------------- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index f7f6c665e87..36ee721421e 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -495,7 +495,7 @@ class TopicListController @Inject constructor( // Suggest prerequisite topic user needs to learn after completing any of the topics. for (topicId in unstartedTopicIdList) { // All of the topic's prerequisites must be completed before it can be suggested. - val dependentTopicIds = topicDependencyMap[topicId] ?: listOf() + val dependentTopicIds = topicDependencyMap[topicId] if (topicId !in impliedFinishedTopicIds && startedTopicIds.containsAll(dependentTopicIds!!)) { createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 2be2fe2eb4b..b7b96c1938f 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -652,7 +652,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playSecondTestTopic_storyListIsCorrect() { + fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playRatios_storyListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -669,23 +669,13 @@ class TopicListControllerTest { TEST_EXPLORATION_ID_5, getCurrentTimestamp() ) - - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - TEST_TOPIC_ID_0, - TEST_STORY_ID_1, - TEST_EXPLORATION_ID_1, - getCurrentTimestamp() - ) testCoroutineDispatchers.runCurrent() storyProgressController.recordRecentlyPlayedChapter( profileId0, - TEST_TOPIC_ID_1, - TEST_STORY_ID_2, - TEST_EXPLORATION_ID_4, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() From 6255455d4a0faf7c90e4d6a97506d5148e61006f Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 28 Jan 2021 03:30:58 +0530 Subject: [PATCH 223/248] Updated implementation changes and testcases as per discussion. --- .../domain/topic/TopicListController.kt | 29 ++++++-- .../domain/topic/TopicListControllerTest.kt | 68 +++++++++++++++---- 2 files changed, 79 insertions(+), 18 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 36ee721421e..a99b228b384 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -492,16 +492,37 @@ class TopicListController @Inject constructor( val impliedFinishedTopicIds = computeImpliedCompletedDependencies( fullyCompletedTopicIds, topicDependencyMap ) - // Suggest prerequisite topic user needs to learn after completing any of the topics. + // Suggest prerequisite topic user needs to learn while user is learning any of the topics. for (topicId in unstartedTopicIdList) { - // All of the topic's prerequisites must be completed before it can be suggested. - val dependentTopicIds = topicDependencyMap[topicId] - if (topicId !in impliedFinishedTopicIds && startedTopicIds.containsAll(dependentTopicIds!!)) { + // All of the topic's prerequisites can be suggested if the topic is ongoing. + val dependentTopicIds = topicDependencyMap[topicId] ?: listOf() + if (topicId !in impliedFinishedTopicIds && startedTopicIds.any { it in dependentTopicIds } && + !impliedFinishedTopicIds.containsAll(dependentTopicIds) + ) { createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) } } } + + // Suggest next topic user might be interested to learn while user is learning or completed + // any of the topics. + val nextTopicIndex = topicIdList.indexOf(startedTopicIds.last()) + 1 + if (topicIdList.size > nextTopicIndex) { + val dependentTopicIds = topicDependencyMap[topicIdList[nextTopicIndex]] ?: listOf() + if (topicIdList[nextTopicIndex] !in impliedFinishedTopicIds && + topicIdList[nextTopicIndex] !in dependentTopicIds + ) { + val recommendedTopicAlreadyExist = + recommendedStories.any { it.topicId == topicIdList[nextTopicIndex] } + if (!recommendedTopicAlreadyExist) { + createRecommendedStoryFromAssets(topicIdList[nextTopicIndex])?.let { + recommendedStories.add(it) + return recommendedStories + } + } + } + } return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index b7b96c1938f..20b3858cdd0 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -329,9 +329,36 @@ class TopicListControllerTest { .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + } + + @Test + fun testGetPromotedStoryList_markRecentlyPlayedFractStory0Exp0_suggestedStoryListIsCorrect() { + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(2) + verifyOngoingStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) verifyPromotedStoryAsFirstTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) } @Test @@ -357,12 +384,17 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) verifyOngoingStoryAsRatioStory1Exploration2( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) + verifyPromotedStoryAsSecondTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test @@ -379,25 +411,22 @@ class TopicListControllerTest { storyProgressController.recordRecentlyPlayedChapter( profileId0, RATIOS_TOPIC_ID, - RATIOS_STORY_ID_1, - RATIOS_EXPLORATION_ID_2, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_1, getCurrentTimestamp() ) testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) - .isEqualTo(2) + .isEqualTo(1) verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - verifyOngoingStoryAsRatioStory1Exploration2( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] - ) } @Test - fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryListIsCorrect() { + fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_comingSoonTopicListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -454,11 +483,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) .isEqualTo(1) - - verifyPromotedStoryAsSecondTestTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) + verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) } @Test @@ -652,7 +680,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playRatios_storyListIsCorrect() { + fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playRatios_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -671,6 +699,15 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_1, + TEST_EXPLORATION_ID_1, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + storyProgressController.recordRecentlyPlayedChapter( profileId0, RATIOS_TOPIC_ID, @@ -684,12 +721,15 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(0) + .isEqualTo(1) + verifyOngoingStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) verifyOngoingStoryAsSecondTopicStory0Exploration0( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } From 2441187aa8744bb1b2ae5dd0aeb47dce93f3e414 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 28 Jan 2021 12:46:53 +0530 Subject: [PATCH 224/248] updated with develop code to pass ci tests. --- .../domain/topic/TopicListController.kt | 124 ++++++++++++++++++ 1 file changed, 124 insertions(+) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index a99b228b384..d5ddaa41edd 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -8,6 +8,7 @@ import org.oppia.android.app.model.ChapterSummary import org.oppia.android.app.model.ComingSoonTopicList import org.oppia.android.app.model.LessonThumbnail import org.oppia.android.app.model.LessonThumbnailGraphic +import org.oppia.android.app.model.OngoingStoryList import org.oppia.android.app.model.ProfileId import org.oppia.android.app.model.PromotedActivityList import org.oppia.android.app.model.PromotedStory @@ -28,11 +29,13 @@ import org.oppia.android.util.data.DataProvider import org.oppia.android.util.data.DataProviders import org.oppia.android.util.data.DataProviders.Companion.transformAsync import org.oppia.android.util.system.OppiaClock +import java.util.Date import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton private const val ONE_WEEK_IN_DAYS = 7 +private const val ONE_DAY_IN_MS = 24 * 60 * 60 * 1000 private const val TOPIC_BG_COLOR = "#C6DCDA" @@ -85,6 +88,8 @@ val EXPLORATION_THUMBNAILS = mapOf( ) private const val GET_TOPIC_LIST_PROVIDER_ID = "get_topic_list_provider_id" +private const val GET_ONGOING_STORY_LIST_PROVIDER_ID = + "get_ongoing_story_list_provider_id" private const val GET_PROMOTED_ACTIVITY_LIST_PROVIDER_ID = "get_recommended_actvity_list_provider_id" @@ -111,6 +116,23 @@ class TopicListController @Inject constructor( ) } + /** + * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. + * The total number of promoted stories should correspond to the ongoing story count within the + * [TopicList] returned by [getTopicList]. + * + * @param profileId the ID corresponding to the profile for which [PromotedStory] needs to be + * fetched. + * @return a [DataProvider] for an [OngoingStoryList]. + */ + fun getOngoingStoryList(profileId: ProfileId): DataProvider { + return storyProgressController.retrieveTopicProgressListDataProvider(profileId) + .transformAsync(GET_ONGOING_STORY_LIST_PROVIDER_ID) { + val ongoingStoryList = createOngoingStoryListFromProgress(it) + AsyncResult.success(ongoingStoryList) + } + } + /** * Returns the list of ongoing [PromotedStory]s that can be viewed via a link on the homescreen. * The total number of promoted stories should correspond to the ongoing story count within the @@ -222,6 +244,108 @@ class TopicListController @Inject constructor( .build() } + private fun createOngoingStoryListFromProgress( + topicProgressList: List + ): OngoingStoryList { + val ongoingStoryListBuilder = OngoingStoryList.newBuilder() + topicProgressList.forEach { topicProgress -> + val topic = topicController.retrieveTopic(topicProgress.topicId) + topicProgress.storyProgressMap.values.forEach { storyProgress -> + val storyId = storyProgress.storyId + val story = topicController.retrieveStory(topic.topicId, storyId) + + val completedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val lastCompletedChapterProgress: ChapterProgress? = + completedChapterProgressList.firstOrNull() + + val startedChapterProgressList = + storyProgress.chapterProgressMap.values + .filter { chapterProgress -> + chapterProgress.chapterPlayState == + ChapterPlayState.STARTED_NOT_COMPLETED + } + .sortedByDescending { chapterProgress -> chapterProgress.lastPlayedTimestamp } + + val recentlyPlayerChapterProgress: ChapterProgress? = + startedChapterProgressList.firstOrNull() + if (recentlyPlayerChapterProgress != null) { + val recentlyPlayerChapterSummary: ChapterSummary? = + story.chapterList.find { chapterSummary -> + recentlyPlayerChapterProgress.explorationId == chapterSummary.explorationId + } + if (recentlyPlayerChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - recentlyPlayerChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + recentlyPlayerChapterSummary.name, + recentlyPlayerChapterSummary.explorationId, + isTopicConsideredCompleted = false + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } else if (lastCompletedChapterProgress != null && + lastCompletedChapterProgress.explorationId != story.chapterList.last().explorationId + ) { + val lastChapterSummary: ChapterSummary? = story.chapterList.find { chapterSummary -> + lastCompletedChapterProgress.explorationId == chapterSummary.explorationId + } + val nextChapterIndex = story.chapterList.indexOf(lastChapterSummary) + 1 + val nextChapterSummary: ChapterSummary? = story.chapterList[nextChapterIndex] + if (nextChapterSummary != null) { + val numberOfDaysPassed = + (Date().time - lastCompletedChapterProgress.lastPlayedTimestamp) / ONE_DAY_IN_MS + val promotedStory = createPromotedStory( + storyId, + topic, + completedChapterProgressList.size, + story.chapterCount, + nextChapterSummary.name, + nextChapterSummary.explorationId, + isTopicConsideredCompleted = true + ) + if (numberOfDaysPassed < ONE_WEEK_IN_DAYS) { + ongoingStoryListBuilder.addRecentStory(promotedStory) + } else { + ongoingStoryListBuilder.addOlderStory(promotedStory) + } + } + } + } + } + if ((ongoingStoryListBuilder.olderStoryCount + ongoingStoryListBuilder.recentStoryCount) == 0) { + ongoingStoryListBuilder.addAllRecentStory(createRecommendedStoryList()) + } + return ongoingStoryListBuilder.build() + } + + private fun createRecommendedStoryList(): List { + val recommendedStories = ArrayList() + val topicIdJsonArray = jsonAssetRetriever + .loadJsonFromAsset("topics.json")!! + .getJSONArray("topic_id_list") + for (i in 0 until topicIdJsonArray.length()) { + createRecommendedStoryFromAssets(topicIdJsonArray[i].toString())?.let { + recommendedStories.add(it) + } + } + return recommendedStories + } + private fun computePromotedActivityList( topicProgressList: List ): PromotedActivityList { From 530b13a08a86c4e1ccb99c89c44e395e520ce08b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 28 Jan 2021 17:34:19 +0530 Subject: [PATCH 225/248] fixed changes --- .../domain/topic/TopicListController.kt | 41 ++++++++----------- .../domain/topic/TopicListControllerTest.kt | 25 +++-------- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index d5ddaa41edd..50955590674 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -544,7 +544,19 @@ class TopicListController @Inject constructor( } // TODO(#2550): Remove hardcoded order of topics. Compute list of suggested stories from backend structures - /** Returns a list of topic IDs for which the specified topic ID expects to be completed before being suggested. */ + /** Returns a list of topic IDs for which the specified topic ID expects to be completed before being suggested. + * Dependent hierarchy + * TEST_TOPIC_ID_0 (Fractions) + * TEST_TOPIC_ID_1 (TEST_TOPIC_ID_0,Ratios) + * Addition and Subtraction (depends on Place Values) + * Multiplication (depends on Addition and Subtraction) + * Division (depends on Multiplication) + * Expressions and Equations (depends on A+S, Multiplication, Division) + * Fractions (depends on A+S, Multiplication, Division) + * Ratios (depends on A+S, Multiplication, Division) + * Decimals (depends on A+S, Multiplication, Division) + * + * */ private fun retrieveTopicDependencies(topicId: String): List { val listOfTopicIds = mutableListOf() when (topicId) { @@ -616,37 +628,20 @@ class TopicListController @Inject constructor( val impliedFinishedTopicIds = computeImpliedCompletedDependencies( fullyCompletedTopicIds, topicDependencyMap ) - // Suggest prerequisite topic user needs to learn while user is learning any of the topics. + // Suggest prerequisite topic user needs to learn after completing any of the topics. + // The order in which the topic IDs are enumerated matters, and that it should be in the order + // of the list itself. for (topicId in unstartedTopicIdList) { // All of the topic's prerequisites can be suggested if the topic is ongoing. val dependentTopicIds = topicDependencyMap[topicId] ?: listOf() - if (topicId !in impliedFinishedTopicIds && startedTopicIds.any { it in dependentTopicIds } && - !impliedFinishedTopicIds.containsAll(dependentTopicIds) + if (topicId !in impliedFinishedTopicIds && + impliedFinishedTopicIds.any { it in dependentTopicIds } ) { createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) } } } - - // Suggest next topic user might be interested to learn while user is learning or completed - // any of the topics. - val nextTopicIndex = topicIdList.indexOf(startedTopicIds.last()) + 1 - if (topicIdList.size > nextTopicIndex) { - val dependentTopicIds = topicDependencyMap[topicIdList[nextTopicIndex]] ?: listOf() - if (topicIdList[nextTopicIndex] !in impliedFinishedTopicIds && - topicIdList[nextTopicIndex] !in dependentTopicIds - ) { - val recommendedTopicAlreadyExist = - recommendedStories.any { it.topicId == topicIdList[nextTopicIndex] } - if (!recommendedTopicAlreadyExist) { - createRecommendedStoryFromAssets(topicIdList[nextTopicIndex])?.let { - recommendedStories.add(it) - return recommendedStories - } - } - } - } return recommendedStories } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 20b3858cdd0..e839fdd0fde 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -329,13 +329,13 @@ class TopicListControllerTest { .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsRatioStory0Exploration0( + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @Test - fun testGetPromotedStoryList_markRecentlyPlayedFractStory0Exp0_suggestedStoryListIsCorrect() { + fun testGetPromotedStoryList_markRecentlyPlayedFractStory0Exp0_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -348,17 +348,9 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) verifyOngoingStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) - verifyPromotedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] - ) } @Test @@ -384,17 +376,12 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) verifyOngoingStoryAsRatioStory1Exploration2( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) - verifyPromotedStoryAsSecondTestTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) } @Test @@ -426,7 +413,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_comingSoonTopicListIsCorrect() { + fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryistIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -483,10 +470,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(0) - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) .isEqualTo(1) - verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) + verifyPromotedStoryAsSecondTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test From dddbcdaa429660e978cd84cda515731e73d8159c Mon Sep 17 00:00:00 2001 From: veena14cs Date: Thu, 28 Jan 2021 23:48:06 +0530 Subject: [PATCH 226/248] Update TopicListControllerTest.kt --- .../oppia/android/domain/topic/TopicListControllerTest.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index e839fdd0fde..042e0815ef9 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -477,7 +477,7 @@ class TopicListControllerTest { } @Test - fun testRetrievePromotedActivityList_markAllChapDoneInRatios_comingSoonTopicListIsCorrect() { + fun testRetrievePromotedActivityList_markAllChapDoneInAllTopics_comingSoonTopicListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, @@ -513,7 +513,7 @@ class TopicListControllerTest { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_1, - TEST_STORY_ID_2, + TEST_STORY_ID_0, TEST_EXPLORATION_ID_4, getCurrentTimestamp() ) @@ -747,6 +747,7 @@ class TopicListControllerTest { RATIOS_EXPLORATION_ID_2, getCurrentTimestamp() ) + testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) From e78f7ab3ea9a92932477dca38a893e9a88e88754 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 13:26:09 +0530 Subject: [PATCH 227/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../android/domain/topic/TopicListController.kt | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 50955590674..4ec433c5a8a 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -360,18 +360,10 @@ class TopicListController @Inject constructor( } private fun computePromotedStoryList(topicProgressList: List): PromotedStoryList { - val recentlyPlayedStories = computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS } - val olderPlayedStories = computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS } return PromotedStoryList.newBuilder() - .addAllRecentlyPlayedStory( - recentlyPlayedStories - ) - .addAllOlderPlayedStory( - olderPlayedStories - ) - .addAllSuggestedStory( - computeSuggestedStories(topicProgressList) - ) + .addAllRecentlyPlayedStory(computePlayedStories(topicProgressList) { it < ONE_WEEK_IN_DAYS }) + .addAllOlderPlayedStory(computePlayedStories(topicProgressList) { it > ONE_WEEK_IN_DAYS }) + .addAllSuggestedStory(computeSuggestedStories(topicProgressList)) .build() } From d5f074e280f46412f14ffe36c5f3655f059e7d85 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 13:33:41 +0530 Subject: [PATCH 228/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../domain/topic/TopicListController.kt | 48 ++++++------------- 1 file changed, 14 insertions(+), 34 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 4ec433c5a8a..98c583ad24f 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -550,46 +550,26 @@ class TopicListController @Inject constructor( * * */ private fun retrieveTopicDependencies(topicId: String): List { - val listOfTopicIds = mutableListOf() - when (topicId) { - TEST_TOPIC_ID_0 -> { - listOfTopicIds.add(FRACTIONS_TOPIC_ID) - } - TEST_TOPIC_ID_1 -> { - listOfTopicIds.add(TEST_TOPIC_ID_0) - listOfTopicIds.add(RATIOS_TOPIC_ID) - } + return when (topicId) { + TEST_TOPIC_ID_0 -> listOf(FRACTIONS_TOPIC_ID) + TEST_TOPIC_ID_1 -> listOf(TEST_TOPIC_ID_0, RATIOS_TOPIC_ID) FRACTIONS_TOPIC_ID -> { - listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) - listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) - listOfTopicIds.add(DIVISION_TOPIC_ID) - } - RATIOS_TOPIC_ID -> { - listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) - listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) - listOfTopicIds.add(DIVISION_TOPIC_ID) - } - ADDITION_AND_SUBTRACTION_TOPIC_ID -> { - listOfTopicIds.add(PLACE_VALUE_TOPIC_ID) - } - MULTIPLICATION_TOPIC_ID -> { - listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) + listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } - DIVISION_TOPIC_ID -> { - listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) + RATIOS_TOPIC_ID -> { + listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } - EXPRESSION_AND_EQUATION_TOPIC_ID -> { - listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) - listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) - listOfTopicIds.add(DIVISION_TOPIC_ID) + ADDITION_AND_SUBTRACTION_TOPIC_ID -> listOf(PLACE_VALUE_TOPIC_ID) + MULTIPLICATION_TOPIC_ID -> listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID) + DIVISION_TOPIC_ID -> listOf(MULTIPLICATION_TOPIC_ID) + EXPRESSION_AND_EQUATION_TOPIC_ID -> { + listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } - DECIMALS_TOPIC_ID -> { - listOfTopicIds.add(ADDITION_AND_SUBTRACTION_TOPIC_ID) - listOfTopicIds.add(MULTIPLICATION_TOPIC_ID) - listOfTopicIds.add(DIVISION_TOPIC_ID) + DECIMALS_TOPIC_ID -> { + listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } + else -> listOf() } - return listOfTopicIds } private fun computeSuggestedStories( From ed9185f45a04aa52ad4ef56fb5c6d5abd077d6d6 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 13:33:58 +0530 Subject: [PATCH 229/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../java/org/oppia/android/domain/topic/TopicListController.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 98c583ad24f..23595aa8f20 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -664,7 +664,6 @@ class TopicListController @Inject constructor( } private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { - val topicJson = jsonAssetRetriever.loadJsonFromAsset("$topicId.json") if (topicJson!!.optString("topic_name").isNullOrEmpty()) { return null From 193344d373a582c75306150460f32717946747a1 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 13:34:12 +0530 Subject: [PATCH 230/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListController.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 23595aa8f20..2a831107462 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -630,9 +630,10 @@ class TopicListController @Inject constructor( return false } - /** Returns the list of topic IDs that are completed or can be implied completed based on actually + /** + * Return the list of topic IDs that are completed or can be implied completed based on actually * completed topics. - * */ + */ private fun computeImpliedCompletedDependencies( fullyCompletedTopicIds: List, topicDependencyMap: Map> From e9dd45422e93d0ea25835af3da2d716047567e16 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 15:53:59 +0530 Subject: [PATCH 231/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../oppia/android/domain/topic/TopicListController.kt | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 2a831107462..f9a9685e012 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -619,15 +619,10 @@ class TopicListController @Inject constructor( private fun topicHasAtLeastOneStoryCompleted(it: TopicProgress): Boolean { val topic = topicController.retrieveTopic(it.topicId) - it.storyProgressMap.values.forEach { storyProgress -> - val storyId = storyProgress.storyId - val story = topicController.retrieveStory(topic.topicId, storyId) - val isStoryCompleted = checkIfStoryIsCompleted(storyProgress, story) - if (isStoryCompleted) { - return true - } + return it.storyProgressMap.values.any { storyProgress -> + val story = topicController.retrieveStory(topic.topicId, storyProgress.storyId) + return@any checkIfStoryIsCompleted(storyProgress, story) } - return false } /** From ddf4bb08a17082da41571436c9afe2a136a25347 Mon Sep 17 00:00:00 2001 From: Veena Date: Fri, 29 Jan 2021 15:55:54 +0530 Subject: [PATCH 232/248] Update domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 042e0815ef9..a5869515a60 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -413,7 +413,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryistIsCorrect() { + fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, FRACTIONS_TOPIC_ID, From 70fcf8ad7e9cb6d474398467a891a487d5d8e00d Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 29 Jan 2021 17:39:09 +0530 Subject: [PATCH 233/248] fixed testcases and implementation --- .../domain/topic/StoryProgressTestHelper.kt | 99 +++++++------ .../domain/topic/TopicListController.kt | 32 +++-- .../topic/StoryProgressTestHelperTest.kt | 60 ++++---- .../domain/topic/TopicListControllerTest.kt | 135 ++++++++++-------- 4 files changed, 181 insertions(+), 145 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 6d9bf27c49d..055d5daa549 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -26,8 +26,8 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting partial progress of the fraction story for * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago */ - fun markChapDoneFrac0Story0Exp0(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markChapDoneFrac0Story0Exp0(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -45,11 +45,11 @@ class StoryProgressTestHelper @Inject constructor( * Mark a partial story progress for a particular profile. * * @param profileId the profile we are setting partial progress of the fraction story for - * @param timestampOlderThanAWeek if the timestamp for this topic progress is more than one week ago + * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago */ - fun markChapDoneFrac0Story0Expl(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markChapDoneFrac0Story0Expl(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -69,8 +69,11 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting partial progress of the fraction topic for * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago */ - fun markPartialTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markPartialTopicProgressForFractions( + profileId: ProfileId, + timestampOlderThanOneWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -90,8 +93,8 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting full on the fraction story progress for * @param timestampOlderThanOneWeek if the timestamp for completing the story is more than one week ago */ - fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -119,8 +122,8 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting fraction topic progress for * @param timestampOlderThanOneWeek if the timestamp for completing the topic is more than one week ago */ - fun markFullTopicProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markFullTopicProgressForFractions(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -257,10 +260,10 @@ class StoryProgressTestHelper @Inject constructor( * Marks full topic progress on the second test topic for a particular profile. * * @param profileId the profile we are setting topic progress for - * @param timestampOlderThanAWeek if the timestamp for completing the topic is from more than one week ago + * @param timestampOlderThanOneWeek if the timestamp for completing the topic is from more than one week ago */ - fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markFullProgressForSecondTestTopic(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -280,8 +283,11 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting topic progress for * @param timestampOlderThanOneWeek if the timestamp for completing the topic is from more than one week ago */ - fun markRecentlyPlayedForSecondTestTopic(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markRecentlyPlayedForSecondTestTopic( + profileId: ProfileId, + timestampOlderThanOneWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -303,9 +309,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -330,13 +336,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one story progress full in ratios exploration for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanAWeek if the timestamp for this progress is from more than one week ago + * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago */ fun markChapDoneOfRatiosStory0Exp0( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -354,13 +360,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one story progress full in ratios exploration for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanAWeek if the timestamp for this progress is from more than one week ago + * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago */ fun markChapDoneOfRatiosStory0Exp1( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -381,8 +387,11 @@ class StoryProgressTestHelper @Inject constructor( * @param timestampOlderThanOneWeek if the timestamp for the progress on the two stories is from more than one week * ago. */ - fun markTwoPartialStoryProgressForRatios(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { - val timestamp = if (!timestampOlderThanAWeek) { + fun markTwoPartialStoryProgressForRatios( + profileId: ProfileId, + timestampOlderThanOneWeek: Boolean + ) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -412,9 +421,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markRecentlyPlayedForFractionsStory0Exploration0( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -436,9 +445,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markRecentlyPlayedForRatiosStory0Exploration0( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -461,9 +470,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markRecentlyPlayedForRatiosStory0Exploration0AndStory1Exploration2( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -494,9 +503,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -535,9 +544,9 @@ class StoryProgressTestHelper @Inject constructor( */ fun markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -562,13 +571,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one exploration in first test topic as completed played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago */ fun markChapterDoneFirstTestTopicStory0Exploration0( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -586,13 +595,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one exploration in first test topic as completed played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago */ fun markRecentlyPlayedFirstTestTopicStory1Exploration1( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -610,13 +619,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one explorations in first test topic as completed for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago */ fun markChapterDoneFirstTestTopicStory0Exploration1( profileId: ProfileId, - timestampOlderThanAWeek: Boolean + timestampOlderThanOneWeek: Boolean ) { - val timestamp = if (!timestampOlderThanAWeek) { + val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() } else { getOldTimestamp() diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index f9a9685e012..ae151fcf9d6 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -536,35 +536,34 @@ class TopicListController @Inject constructor( } // TODO(#2550): Remove hardcoded order of topics. Compute list of suggested stories from backend structures - /** Returns a list of topic IDs for which the specified topic ID expects to be completed before being suggested. - * Dependent hierarchy - * TEST_TOPIC_ID_0 (Fractions) - * TEST_TOPIC_ID_1 (TEST_TOPIC_ID_0,Ratios) - * Addition and Subtraction (depends on Place Values) - * Multiplication (depends on Addition and Subtraction) - * Division (depends on Multiplication) - * Expressions and Equations (depends on A+S, Multiplication, Division) - * Fractions (depends on A+S, Multiplication, Division) - * Ratios (depends on A+S, Multiplication, Division) - * Decimals (depends on A+S, Multiplication, Division) - * + /** Returns a list of topic IDs for which the specified topic ID expects to be completed before + * being suggested. * */ private fun retrieveTopicDependencies(topicId: String): List { return when (topicId) { + // TEST_TOPIC_ID_0 (depends on Fractions) TEST_TOPIC_ID_0 -> listOf(FRACTIONS_TOPIC_ID) + // TEST_TOPIC_ID_1 (depends on TEST_TOPIC_ID_0,Ratios) TEST_TOPIC_ID_1 -> listOf(TEST_TOPIC_ID_0, RATIOS_TOPIC_ID) + // Fractions (depends on A+S, Multiplication, Division) FRACTIONS_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } + // Ratios (depends on A+S, Multiplication, Division) RATIOS_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } + // Addition and Subtraction (depends on Place Values) ADDITION_AND_SUBTRACTION_TOPIC_ID -> listOf(PLACE_VALUE_TOPIC_ID) + // Multiplication (depends on Addition and Subtraction) MULTIPLICATION_TOPIC_ID -> listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID) + // Division (depends on Multiplication) DIVISION_TOPIC_ID -> listOf(MULTIPLICATION_TOPIC_ID) + // Expressions and Equations (depends on A+S, Multiplication, Division) EXPRESSION_AND_EQUATION_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } + // Decimals (depends on A+S, Multiplication, Division) DECIMALS_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } @@ -607,11 +606,18 @@ class TopicListController @Inject constructor( // All of the topic's prerequisites can be suggested if the topic is ongoing. val dependentTopicIds = topicDependencyMap[topicId] ?: listOf() if (topicId !in impliedFinishedTopicIds && - impliedFinishedTopicIds.any { it in dependentTopicIds } + impliedFinishedTopicIds.containsAll(dependentTopicIds) ) { createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) } + } else if (impliedFinishedTopicIds.any { it in dependentTopicIds }) { + val nextTopicsListToRecommend = dependentTopicIds.filter { it !in impliedFinishedTopicIds } + nextTopicsListToRecommend.forEach { depId -> + createRecommendedStoryFromAssets(depId)?.let { + recommendedStories.add(it) + } + } } } return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index e3dc6c59fa8..ea5a0c9b4dd 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -128,7 +128,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialStoryProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -151,7 +151,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialStoryProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -173,7 +173,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialStoryProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -193,7 +193,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialStoryProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markChapDoneFrac0Story0Exp0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -211,7 +211,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -234,7 +234,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -256,7 +256,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -276,7 +276,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -294,7 +294,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -317,7 +317,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -337,7 +337,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -356,7 +356,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -375,7 +375,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullTopicProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -398,7 +398,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullTopicProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -418,7 +418,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullTopicProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -437,7 +437,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullTopicProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullTopicProgressForFractions( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -456,7 +456,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -484,7 +484,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -614,7 +614,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -634,7 +634,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -653,7 +653,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -680,7 +680,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -703,7 +703,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -723,7 +723,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -741,7 +741,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -769,7 +769,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -796,7 +796,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0AndStory1Exp2_storyListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0AndStory1Exploration2( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -828,7 +828,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullProgressForSecondTestTopic_comingSooTopicIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTestTopic( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -850,7 +850,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId = profileId, - timestampOlderThanAWeek = false + timestampOlderThanOneWeek = false ) testCoroutineDispatchers.runCurrent() @@ -885,7 +885,7 @@ class StoryProgressTestHelperTest { fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_PromotedActivityListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId = profileId, - timestampOlderThanAWeek = true + timestampOlderThanOneWeek = true ) testCoroutineDispatchers.runCurrent() diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index a5869515a60..84d0438b468 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -385,7 +385,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markExp0DoneAndExp2AsPlayedInRatios_ongoingStoryListIsCorrect() { + fun testGetStoryList_markExp0DoneAndExp2InRatios_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, @@ -395,7 +395,7 @@ class TopicListControllerTest { ) testCoroutineDispatchers.runCurrent() - storyProgressController.recordRecentlyPlayedChapter( + storyProgressController.recordCompletedChapter( profileId0, RATIOS_TOPIC_ID, RATIOS_STORY_ID_0, @@ -405,32 +405,15 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyOngoingStoryAsRatioStory0Exploration1( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @Test - fun testGetStoryList_markStoryDoneOfFracRatiosFirstTestTopic_suggestedStoryListIsCorrect() { - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_1, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() + fun testGetStoryList_markStoryDoneOfRatiosAndFirstTestTopic_suggestedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -513,7 +496,7 @@ class TopicListControllerTest { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_1, - TEST_STORY_ID_0, + TEST_STORY_ID_2, TEST_EXPLORATION_ID_4, getCurrentTimestamp() ) @@ -542,6 +525,28 @@ class TopicListControllerTest { .isEqualTo(1) } + @Test + fun testGetStoryList_markAllChapDoneInSecondTestTopic_doesNotPromoteAnyStories() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) + .isEqualTo(1) + } + @Test fun testGetStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -585,6 +590,49 @@ class TopicListControllerTest { ) } + @Test + fun testGetStoryList_markFirstExpOfEveryStoryDoneWithinLastMonth_ongoingOlderListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + getOldTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_0, + RATIOS_EXPLORATION_ID_0, + getOldTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + RATIOS_TOPIC_ID, + RATIOS_STORY_ID_1, + RATIOS_EXPLORATION_ID_2, + getOldTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(3) + verifyOngoingStoryAsRatioStory0Exploration1( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + ) + verifyOngoingStoryAsRatioStory1Exploration3( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + ) + verifyOngoingStoryAsFractionStory0Exploration1( + promotedActivityList.promotedStoryList.olderPlayedStoryList[2] + ) + } + @Test fun testGetStoryList_markRecentlyPlayedForFirstTestTopic_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( @@ -605,7 +653,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markOneStoryDoneForFirstTestTopic_ongoingStoryListIsCorrect() { + fun testGetStoryList_markOneStoryDoneForFirstTestTopic_promotedStoryListIsCorrect() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -625,8 +673,11 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) - .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(1) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) } @Test @@ -707,17 +758,12 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) - verifyOngoingStoryAsSecondTopicStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) } @Test @@ -799,19 +845,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(3) } - private fun verifyOngoingStoryAsFirstTopicStory0Exploration1(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_5) - assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) - assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) - assertThat(promotedStory.topicName).isEqualTo("First Test Topic") - assertThat(promotedStory.nextChapterName).isEqualTo("Image Region Selection Exploration") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.BAKER) - assertThat(promotedStory.completedChapterCount).isEqualTo(2) - assertThat(promotedStory.isTopicLearned).isTrue() - assertThat(promotedStory.totalChapterCount).isEqualTo(2) - } - private fun verifyOngoingStoryAsFirstTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_2) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_0) @@ -849,18 +882,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(1) } - private fun verifyPromotedStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) - assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) - assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) - assertThat(promotedStory.topicName).isEqualTo("Fractions") - assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(2) - } - private fun verifyOngoingStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) From d06fcc67b7ebee26e434a3eabe60b7d26d36811b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Fri, 29 Jan 2021 17:40:16 +0530 Subject: [PATCH 234/248] Update TopicListController.kt --- .../org/oppia/android/domain/topic/TopicListController.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index ae151fcf9d6..e3bfc7a2a7e 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -550,7 +550,7 @@ class TopicListController @Inject constructor( listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } // Ratios (depends on A+S, Multiplication, Division) - RATIOS_TOPIC_ID -> { + RATIOS_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } // Addition and Subtraction (depends on Place Values) @@ -560,11 +560,11 @@ class TopicListController @Inject constructor( // Division (depends on Multiplication) DIVISION_TOPIC_ID -> listOf(MULTIPLICATION_TOPIC_ID) // Expressions and Equations (depends on A+S, Multiplication, Division) - EXPRESSION_AND_EQUATION_TOPIC_ID -> { + EXPRESSION_AND_EQUATION_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } // Decimals (depends on A+S, Multiplication, Division) - DECIMALS_TOPIC_ID -> { + DECIMALS_TOPIC_ID -> { listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) } else -> listOf() From d91733c8839d5b464ada67cbe76842c233b0e77e Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 02:19:28 +0530 Subject: [PATCH 235/248] fixing changes --- .../domain/topic/StoryProgressTestHelper.kt | 1 - .../domain/topic/TopicListController.kt | 9 +-- .../domain/topic/TopicListControllerTest.kt | 60 +++++-------------- 3 files changed, 15 insertions(+), 55 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 055d5daa549..7bd4597775d 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -47,7 +47,6 @@ class StoryProgressTestHelper @Inject constructor( * @param profileId the profile we are setting partial progress of the fraction story for * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago */ - fun markChapDoneFrac0Story0Expl(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { val timestamp = if (!timestampOlderThanOneWeek) { getCurrentTimestamp() diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index e3bfc7a2a7e..5f6f0879516 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -538,7 +538,7 @@ class TopicListController @Inject constructor( // TODO(#2550): Remove hardcoded order of topics. Compute list of suggested stories from backend structures /** Returns a list of topic IDs for which the specified topic ID expects to be completed before * being suggested. - * */ + */ private fun retrieveTopicDependencies(topicId: String): List { return when (topicId) { // TEST_TOPIC_ID_0 (depends on Fractions) @@ -611,13 +611,6 @@ class TopicListController @Inject constructor( createRecommendedStoryFromAssets(topicId)?.let { recommendedStories.add(it) } - } else if (impliedFinishedTopicIds.any { it in dependentTopicIds }) { - val nextTopicsListToRecommend = dependentTopicIds.filter { it !in impliedFinishedTopicIds } - nextTopicsListToRecommend.forEach { depId -> - createRecommendedStoryFromAssets(depId)?.let { - recommendedStories.add(it) - } - } } } return recommendedStories diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 84d0438b468..87404f392d9 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -329,32 +329,13 @@ class TopicListControllerTest { .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + verifyPromotedStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @Test - fun testGetPromotedStoryList_markRecentlyPlayedFractStory0Exp0_ongoingStoryListIsCorrect() { - storyProgressController.recordRecentlyPlayedChapter( - profileId0, - FRACTIONS_TOPIC_ID, - FRACTIONS_STORY_ID_0, - FRACTIONS_EXPLORATION_ID_0, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - val promotedActivityList = retrievePromotedActivityList() - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) - .isEqualTo(1) - verifyOngoingStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - ) - } - - @Test - fun testGetStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_promotedStoryListIsCorrect() { + fun testGetStoryList_markRecentPlayedFirstChapInAllStoriesInRatios_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, RATIOS_TOPIC_ID, @@ -653,7 +634,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markOneStoryDoneForFirstTestTopic_promotedStoryListIsCorrect() { + fun testGetStoryList_markOneStoryDoneForFirstTestTopic_markIsTopicLearned() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -673,6 +654,9 @@ class TopicListControllerTest { testCoroutineDispatchers.runCurrent() val promotedActivityList = retrievePromotedActivityList() + + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned) + .isTrue() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) verifyPromotedStoryAsRatioStory0Exploration0( @@ -712,6 +696,7 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -858,18 +843,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - private fun verifyOngoingStoryAsSecondTopicStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) - assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) - assertThat(promotedStory.topicId).isEqualTo(TEST_TOPIC_ID_1) - assertThat(promotedStory.topicName).isEqualTo("Second Test Topic") - assertThat(promotedStory.nextChapterName).isEqualTo("Fifth Exploration") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(1) - } - private fun verifyPromotedStoryAsSecondTestTopicStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(TEST_EXPLORATION_ID_4) assertThat(promotedStory.storyId).isEqualTo(TEST_STORY_ID_2) @@ -879,6 +852,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DERIVE_A_RATIO) assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(1) } @@ -891,6 +865,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -906,18 +881,6 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } - private fun verifyRecommendedStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { - assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_0) - assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) - assertThat(promotedStory.topicId).isEqualTo(RATIOS_TOPIC_ID) - assertThat(promotedStory.nextChapterName).isEqualTo("What is a Ratio?") - assertThat(promotedStory.topicName).isEqualTo("Ratios and Proportional Reasoning") - assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) - .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) - assertThat(promotedStory.completedChapterCount).isEqualTo(0) - assertThat(promotedStory.totalChapterCount).isEqualTo(2) - } - private fun verifyOngoingStoryAsRatioStory0Exploration0(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(RATIOS_EXPLORATION_ID_0) assertThat(promotedStory.storyId).isEqualTo(RATIOS_STORY_ID_0) @@ -927,6 +890,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -939,6 +903,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -951,6 +916,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_FRACTIONS_HOMEWORK) assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -970,6 +936,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } @@ -982,6 +949,7 @@ class TopicListControllerTest { assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) .isEqualTo(LessonThumbnailGraphic.CHILD_WITH_CUPCAKES) assertThat(promotedStory.completedChapterCount).isEqualTo(1) + assertThat(promotedStory.isTopicLearned).isFalse() assertThat(promotedStory.totalChapterCount).isEqualTo(2) } From 17afb192fb0189a47127b5286d50534b8857c46b Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 02:42:30 +0530 Subject: [PATCH 236/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 87404f392d9..ade717a1b69 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -603,19 +603,25 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(3) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + .isTopicLearned).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[2] + .isTopicLearned).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[2] ) } @Test - fun testGetStoryList_markRecentlyPlayedForFirstTestTopic_ongoingStoryListIsCorrect() { + fun testGetStoryList_markRecentlyPlayedForFirstExpOFFirstTestTopic_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, TEST_TOPIC_ID_0, @@ -628,42 +634,13 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned).isFalse() verifyOngoingStoryAsFirstTopicStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) } - @Test - fun testGetStoryList_markOneStoryDoneForFirstTestTopic_markIsTopicLearned() { - storyProgressController.recordCompletedChapter( - profileId0, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_2, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - storyProgressController.recordCompletedChapter( - profileId0, - TEST_TOPIC_ID_0, - TEST_STORY_ID_0, - TEST_EXPLORATION_ID_5, - getCurrentTimestamp() - ) - testCoroutineDispatchers.runCurrent() - - val promotedActivityList = retrievePromotedActivityList() - - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned) - .isTrue() - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyPromotedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) - } - @Test fun testGetStoryList_markOneStoryDoneAndPlayNextStoryOfFirstTestTopic_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -696,7 +673,8 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned).isTrue() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -743,9 +721,13 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned).isFalse() verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + .isTopicLearned).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) @@ -785,12 +767,19 @@ class TopicListControllerTest { .isEqualTo(1) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(2) + + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + .isTopicLearned).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) From a74776e00e1e17fa29de34a1493fe4cc421786eb Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 02:44:38 +0530 Subject: [PATCH 237/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 60 ++++++++++++------- 1 file changed, 40 insertions(+), 20 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index ade717a1b69..b9b3b6bada2 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -603,18 +603,24 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(3) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[1] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[2] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[2] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[2] ) @@ -634,8 +640,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsFirstTopicStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -673,8 +681,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned).isTrue() + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned + ).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -721,13 +731,17 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] - .isTopicLearned).isTrue() + assertThat( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] + .isTopicLearned + ).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) @@ -768,18 +782,24 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(2) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[1] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[1] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) - assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned).isFalse() + assertThat( + promotedActivityList.promotedStoryList.olderPlayedStoryList[0] + .isTopicLearned + ).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) From b6697fa345ba249a5a8eb910fb0afd82944487b0 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 04:05:24 +0530 Subject: [PATCH 238/248] Fixed suggested changes --- .../domain/topic/StoryProgressTestHelper.kt | 36 +++--- .../domain/topic/TopicListController.kt | 21 +--- .../topic/StoryProgressTestHelperTest.kt | 44 +++---- .../domain/topic/TopicListControllerTest.kt | 114 ++++++++++-------- 4 files changed, 109 insertions(+), 106 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 7bd4597775d..8b466566b4f 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -66,13 +66,13 @@ class StoryProgressTestHelper @Inject constructor( * Creates a partial topic progress for a particular profile. * * @param profileId the profile we are setting partial progress of the fraction topic for - * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago + * @param timestampOlderThanAWeek if the timestamp for this topic progress is more than one week ago */ fun markPartialTopicProgressForFractions( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -90,10 +90,10 @@ class StoryProgressTestHelper @Inject constructor( * Marks full story progress for a particular profile. * * @param profileId the profile we are setting full on the fraction story progress for - * @param timestampOlderThanOneWeek if the timestamp for completing the story is more than one week ago + * @param timestampOlderThanAWeek if the timestamp for completing the story is more than one week ago */ - fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanOneWeek: Boolean) { - val timestamp = if (!timestampOlderThanOneWeek) { + fun markFullStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -304,13 +304,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one story progress fully complete in the ratios topic for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanOneWeek if the timestamp for this progress is from more than one week ago + * @param timestampOlderThanAWeek if the timestamp for this progress is from more than one week ago */ fun markFullStoryPartialTopicProgressForRatios( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -383,14 +383,14 @@ class StoryProgressTestHelper @Inject constructor( * Marks two partial story progress in ratios exploration for a particular profile. * * @param profileId the profile we are setting topic progress on ratios for - * @param timestampOlderThanOneWeek if the timestamp for the progress on the two stories is from more than one week + * @param timestampOlderThanAWeek if the timestamp for the progress on the two stories is from more than one week * ago. */ fun markTwoPartialStoryProgressForRatios( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -416,13 +416,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks exploration [FRACTIONS_EXPLORATION_ID_0] as recently played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago */ fun markRecentlyPlayedForFractionsStory0Exploration0( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -440,13 +440,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks exploration [RATIOS_EXPLORATION_ID_0] as recently played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago */ fun markRecentlyPlayedForRatiosStory0Exploration0( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 5f6f0879516..ac095de45e4 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -51,12 +51,6 @@ const val FRACTIONS_TOPIC_ID = "GJ2rLXRKD5hw" const val SUBTOPIC_TOPIC_ID = 1 const val SUBTOPIC_TOPIC_ID_2 = 2 const val RATIOS_TOPIC_ID = "omzF4oqgeTXd" -const val PLACE_VALUE_TOPIC_ID = "id0" -const val ADDITION_AND_SUBTRACTION_TOPIC_ID = "id1" -const val MULTIPLICATION_TOPIC_ID = "id2" -const val DIVISION_TOPIC_ID = "id3" -const val EXPRESSION_AND_EQUATION_TOPIC_ID = "id4" -const val DECIMALS_TOPIC_ID = "id5" val TOPIC_THUMBNAILS = mapOf( FRACTIONS_TOPIC_ID to createTopicThumbnail0(), RATIOS_TOPIC_ID to createTopicThumbnail1(), @@ -540,6 +534,8 @@ class TopicListController @Inject constructor( * being suggested. */ private fun retrieveTopicDependencies(topicId: String): List { + // The comments describe the correct dependencies, but those might not be available until the + // topic is introduced into the app. return when (topicId) { // TEST_TOPIC_ID_0 (depends on Fractions) TEST_TOPIC_ID_0 -> listOf(FRACTIONS_TOPIC_ID) @@ -547,26 +543,17 @@ class TopicListController @Inject constructor( TEST_TOPIC_ID_1 -> listOf(TEST_TOPIC_ID_0, RATIOS_TOPIC_ID) // Fractions (depends on A+S, Multiplication, Division) FRACTIONS_TOPIC_ID -> { - listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) + listOf() } // Ratios (depends on A+S, Multiplication, Division) RATIOS_TOPIC_ID -> { - listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) + listOf() } // Addition and Subtraction (depends on Place Values) - ADDITION_AND_SUBTRACTION_TOPIC_ID -> listOf(PLACE_VALUE_TOPIC_ID) // Multiplication (depends on Addition and Subtraction) - MULTIPLICATION_TOPIC_ID -> listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID) // Division (depends on Multiplication) - DIVISION_TOPIC_ID -> listOf(MULTIPLICATION_TOPIC_ID) // Expressions and Equations (depends on A+S, Multiplication, Division) - EXPRESSION_AND_EQUATION_TOPIC_ID -> { - listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) - } // Decimals (depends on A+S, Multiplication, Division) - DECIMALS_TOPIC_ID -> { - listOf(ADDITION_AND_SUBTRACTION_TOPIC_ID, MULTIPLICATION_TOPIC_ID, DIVISION_TOPIC_ID) - } else -> listOf() } } diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index ea5a0c9b4dd..cdd7c955967 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -211,7 +211,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -234,7 +234,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -256,7 +256,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -276,7 +276,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markPartialTopicProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -294,7 +294,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -317,7 +317,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -337,7 +337,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -356,7 +356,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryProgressForFractions_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryProgressForFractions( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -456,7 +456,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -484,7 +484,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markFullStoryPartialTopicProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -614,7 +614,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -634,7 +634,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markPartialTopicProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markFullStoryPartialTopicProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -653,7 +653,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getTopicIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -680,7 +680,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getStoryIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -703,7 +703,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getOngoingTopicListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -723,7 +723,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markTwoPartialStoryProgressForRatios_getCompletedStoryListIsCorrect() { storyProgressTestHelper.markTwoPartialStoryProgressForRatios( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -741,7 +741,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_fractionsStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForFractionsStory0Exploration0( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -769,7 +769,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_ratiosStory0Exp0_promotedStoryListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForRatiosStory0Exploration0( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -825,7 +825,7 @@ class StoryProgressTestHelperTest { } @Test - fun testProgressTestHelper_markFullProgressForSecondTestTopic_comingSooTopicIsCorrect() { + fun testProgressTestHelper_markFullProgressForSecondTestTopic_suggestedStoryListIsCorrect() { storyProgressTestHelper.markFullProgressForSecondTestTopic( profileId = profileId, timestampOlderThanOneWeek = false @@ -842,8 +842,8 @@ class StoryProgressTestHelperTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(2) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(0) } @Test @@ -882,7 +882,7 @@ class StoryProgressTestHelperTest { } @Test - fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_PromotedActivityListCorrect() { + fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_promotedActivityListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId = profileId, timestampOlderThanOneWeek = true diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index b9b3b6bada2..689223fc0cf 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -328,10 +328,13 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) - verifyPromotedStoryAsRatioStory0Exploration0( + .isEqualTo(2) + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) } @Test @@ -388,7 +391,7 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + verifyPromotedStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @@ -434,10 +437,13 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(1) + .isEqualTo(2) verifyPromotedStoryAsSecondTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) } @Test @@ -523,9 +529,13 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(0) - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) - .isEqualTo(1) + .isEqualTo(2) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) } @Test @@ -603,31 +613,19 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(3) - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[1] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[2] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[2] ) } @Test - fun testGetStoryList_markRecentlyPlayedForFirstExpOFFirstTestTopic_ongoingStoryListIsCorrect() { + fun testGetStoryList_markRecentlyPlayedForFirstTestTopic_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, TEST_TOPIC_ID_0, @@ -640,15 +638,43 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsFirstTopicStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) } + @Test + fun testGetStoryList_markOneStoryDoneForFirstTestTopic_suggestedStoryListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_5, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(2) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) + } + @Test fun testGetStoryList_markOneStoryDoneAndPlayNextStoryOfFirstTestTopic_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -681,10 +707,8 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(1) - assertThat( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned - ).isTrue() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned) + .isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -731,17 +755,9 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - assertThat( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - assertThat( - promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] - .isTopicLearned - ).isTrue() verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) @@ -781,25 +797,12 @@ class TopicListControllerTest { .isEqualTo(1) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(2) - - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsRatioStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[0] ) - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[1] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsFractionStory0Exploration1( promotedActivityList.promotedStoryList.olderPlayedStoryList[1] ) - assertThat( - promotedActivityList.promotedStoryList.olderPlayedStoryList[0] - .isTopicLearned - ).isFalse() verifyOngoingStoryAsRatioStory1Exploration3( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) @@ -878,6 +881,19 @@ class TopicListControllerTest { assertThat(promotedStory.totalChapterCount).isEqualTo(2) } + private fun verifyPromotedStoryAsFractionStory0Exploration0(promotedStory: PromotedStory) { + assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_0) + assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) + assertThat(promotedStory.topicId).isEqualTo(FRACTIONS_TOPIC_ID) + assertThat(promotedStory.topicName).isEqualTo("Fractions") + assertThat(promotedStory.nextChapterName).isEqualTo("What is a Fraction?") + assertThat(promotedStory.lessonThumbnail.thumbnailGraphic) + .isEqualTo(LessonThumbnailGraphic.DUCK_AND_CHICKEN) + assertThat(promotedStory.completedChapterCount).isEqualTo(0) + assertThat(promotedStory.isTopicLearned).isFalse() + assertThat(promotedStory.totalChapterCount).isEqualTo(2) + } + private fun verifyOngoingStoryAsFractionStory0Exploration1(promotedStory: PromotedStory) { assertThat(promotedStory.explorationId).isEqualTo(FRACTIONS_EXPLORATION_ID_1) assertThat(promotedStory.storyId).isEqualTo(FRACTIONS_STORY_ID_0) From 804a506a5e59d6c4d31411fd3d99d197fdaeaff5 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 04:14:13 +0530 Subject: [PATCH 239/248] Update StoryProgressTestHelper.kt --- .../android/domain/topic/StoryProgressTestHelper.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index 8b466566b4f..f39712c3ce4 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -498,13 +498,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks first exploration in all stories of Ratios & Fractions as recently played for a particular profile. * * @param profileId the profile we are setting recently played for. - * @param timestampOlderThanOneWeek the timestamp for the recently played explorations is more than a week ago. + * @param timestampOlderThanAWeek the timestamp for the recently played explorations is more than a week ago. */ fun markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() @@ -539,13 +539,13 @@ class StoryProgressTestHelper @Inject constructor( * Marks one explorations in each of the two two test topics as recently played for a particular profile. * * @param profileId the profile we are setting recently played for - * @param timestampOlderThanOneWeek if the timestamp for the recently played story is more than a week ago + * @param timestampOlderThanAWeek if the timestamp for the recently played story is more than a week ago */ fun markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId: ProfileId, - timestampOlderThanOneWeek: Boolean + timestampOlderThanAWeek: Boolean ) { - val timestamp = if (!timestampOlderThanOneWeek) { + val timestamp = if (!timestampOlderThanAWeek) { getCurrentTimestamp() } else { getOldTimestamp() From 834e4712a47388cf8050e230d42f53449701bb9d Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 04:15:06 +0530 Subject: [PATCH 240/248] Update StoryProgressTestHelperTest.kt --- .../oppia/android/domain/topic/StoryProgressTestHelperTest.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index cdd7c955967..35a9c0c29f3 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -850,7 +850,7 @@ class StoryProgressTestHelperTest { fun testProgressTestHelper_markRecentlyPlayed_firstStoryInTestTopic1And2_promotedListIsCorrect() { storyProgressTestHelper.markRecentlyPlayedForOneExplorationInTestTopics1And2( profileId = profileId, - timestampOlderThanOneWeek = false + timestampOlderThanAWeek = false ) testCoroutineDispatchers.runCurrent() @@ -885,7 +885,7 @@ class StoryProgressTestHelperTest { fun testHelper_recentlyPlayed_firstExpInAllFracRatio_asOldStories_promotedActivityListCorrect() { storyProgressTestHelper.markRecentlyPlayedForFirstExplorationInAllStoriesInFractionsAndRatios( profileId = profileId, - timestampOlderThanOneWeek = true + timestampOlderThanAWeek = true ) testCoroutineDispatchers.runCurrent() From 6b83e0967562970a27796e03468c6a3115899a5e Mon Sep 17 00:00:00 2001 From: Veena Date: Sat, 30 Jan 2021 10:23:57 +0530 Subject: [PATCH 241/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListController.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index ac095de45e4..43ecee6162e 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -542,13 +542,9 @@ class TopicListController @Inject constructor( // TEST_TOPIC_ID_1 (depends on TEST_TOPIC_ID_0,Ratios) TEST_TOPIC_ID_1 -> listOf(TEST_TOPIC_ID_0, RATIOS_TOPIC_ID) // Fractions (depends on A+S, Multiplication, Division) - FRACTIONS_TOPIC_ID -> { - listOf() - } + FRACTIONS_TOPIC_ID -> listOf() // Ratios (depends on A+S, Multiplication, Division) - RATIOS_TOPIC_ID -> { - listOf() - } + RATIOS_TOPIC_ID -> listOf() // Addition and Subtraction (depends on Place Values) // Multiplication (depends on Addition and Subtraction) // Division (depends on Multiplication) From 6351f1d2bcd4ca1744215c04b641f1b3b036402d Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sat, 30 Jan 2021 12:10:33 +0530 Subject: [PATCH 242/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 689223fc0cf..bf5bc0ab1c1 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -391,7 +391,7 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsFractionStory0Exploration0( + verifyPromotedStoryAsFirstTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @@ -437,13 +437,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) + .isEqualTo(1) verifyPromotedStoryAsSecondTestTopicStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] - ) } @Test @@ -529,13 +526,7 @@ class TopicListControllerTest { assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) - verifyPromotedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] - ) + .isEqualTo(0) } @Test @@ -755,10 +746,10 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - verifyOngoingStoryAsRatioStory0Exploration0( + verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - verifyOngoingStoryAsFirstTopicStory1Exploration0( + verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) } From 357ba9a5c0fbd452faf8f93f2e0ac1911b93f363 Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 31 Jan 2021 01:49:37 +0530 Subject: [PATCH 243/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListController.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 43ecee6162e..8d367b9f3c3 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -632,13 +632,14 @@ class TopicListController @Inject constructor( ): Set { // Compute the total list of dependent topics that must be completed before the specified topic // can be recommended. Note that this will cause a stack overflow if the graph has cycles. - val topicDependencyList = topicDependencyMap[topicId]?.flatMap { dependentId -> + val directDependencies = topicDependencyMap[topicId] ?: listOf() + val transitiveDependencies = directDependencies.flatMap { dependentId -> computeTransitiveDependencyClosure( dependentId, topicDependencyMap ) } - return topicDependencyList?.toSet() ?: emptySet() + return (transitiveDependencies + directDependencies).toSet() } private fun createRecommendedStoryFromAssets(topicId: String): PromotedStory? { From cc9b9b59c43a71273181547196426961ae225fd9 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 31 Jan 2021 02:27:52 +0530 Subject: [PATCH 244/248] Fixed itestcases --- .../domain/topic/StoryProgressTestHelper.kt | 21 ++++++++++ .../topic/StoryProgressTestHelperTest.kt | 4 +- .../domain/topic/TopicListControllerTest.kt | 42 +++++++++++++++---- 3 files changed, 56 insertions(+), 11 deletions(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt index f39712c3ce4..a8d44a04102 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/StoryProgressTestHelper.kt @@ -20,6 +20,27 @@ class StoryProgressTestHelper @Inject constructor( return Date().time - EIGHT_DAYS_IN_MS } + /** + * Creates a partial story progress for a particular profile. + * + * @param profileId the profile we are setting partial progress of the fraction story for + * @param timestampOlderThanOneWeek if the timestamp for this topic progress is more than one week ago + */ + fun markPartialStoryProgressForFractions(profileId: ProfileId, timestampOlderThanAWeek: Boolean) { + val timestamp = if (!timestampOlderThanAWeek) { + getCurrentTimestamp() + } else { + getOldTimestamp() + } + storyProgressController.recordCompletedChapter( + profileId, + FRACTIONS_TOPIC_ID, + FRACTIONS_STORY_ID_0, + FRACTIONS_EXPLORATION_ID_0, + timestamp + ) + } + /** * Creates a partial story progress for a particular profile. * diff --git a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt index 35a9c0c29f3..5f869adbc83 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/StoryProgressTestHelperTest.kt @@ -842,8 +842,8 @@ class StoryProgressTestHelperTest { assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(0) assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount).isEqualTo(0) - assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(2) - assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount).isEqualTo(0) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount).isEqualTo(1) } @Test diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index bf5bc0ab1c1..b2651842439 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -391,7 +391,7 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(1) - verifyPromotedStoryAsFirstTestTopicStory0Exploration0( + verifyPromotedStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @@ -443,6 +443,29 @@ class TopicListControllerTest { ) } + @Test + fun testGetStoryList_markRecentlyPlayedFirstTestTopic_defaultsuggestedStoryListIsCorrect() { + storyProgressController.recordRecentlyPlayedChapter( + profileId0, + TEST_TOPIC_ID_0, + TEST_STORY_ID_0, + TEST_EXPLORATION_ID_2, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(2) + verifyPromotedStoryAsFractionStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[0] + ) + verifyPromotedStoryAsRatioStory0Exploration0( + promotedActivityList.promotedStoryList.suggestedStoryList[1] + ) + } + @Test fun testRetrievePromotedActivityList_markAllChapDoneInAllTopics_comingSoonTopicListIsCorrect() { storyProgressController.recordCompletedChapter( @@ -657,12 +680,9 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) - .isEqualTo(2) - verifyPromotedStoryAsFractionStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[0] - ) + .isEqualTo(1) verifyPromotedStoryAsRatioStory0Exploration0( - promotedActivityList.promotedStoryList.suggestedStoryList[1] + promotedActivityList.promotedStoryList.suggestedStoryList[0] ) } @@ -706,7 +726,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playRatios_promotedStoryListIsCorrect() { + fun testGetStoryList_story0DonePlayStory1FirstTestTopic_playRatios_firstTestTopicisLearned() { storyProgressController.recordCompletedChapter( profileId0, TEST_TOPIC_ID_0, @@ -746,10 +766,14 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) .isEqualTo(2) - verifyOngoingStoryAsFirstTopicStory1Exploration0( + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0].isTopicLearned) + .isFalse() + verifyOngoingStoryAsRatioStory0Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] ) - verifyOngoingStoryAsRatioStory0Exploration0( + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1].isTopicLearned) + .isTrue() + verifyOngoingStoryAsFirstTopicStory1Exploration0( promotedActivityList.promotedStoryList.recentlyPlayedStoryList[1] ) } From 07d7113cbdbfd95edd755adccf710526a4632f82 Mon Sep 17 00:00:00 2001 From: veena14cs Date: Sun, 31 Jan 2021 17:53:54 +0530 Subject: [PATCH 245/248] Update TopicListControllerTest.kt --- .../domain/topic/TopicListControllerTest.kt | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index b2651842439..5487f5cc4b8 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -456,8 +456,13 @@ class TopicListControllerTest { val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(1) assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) .isEqualTo(2) + verifyOngoingStoryAsFirstTopicStory0Exploration0( + promotedActivityList.promotedStoryList.recentlyPlayedStoryList[0] + ) verifyPromotedStoryAsFractionStory0Exploration0( promotedActivityList.promotedStoryList.suggestedStoryList[0] ) @@ -552,6 +557,29 @@ class TopicListControllerTest { .isEqualTo(0) } + @Test + fun testGetStoryList_markAllChapDoneInSecondTestTopic_comingSoonTopicListIsCorrect() { + storyProgressController.recordCompletedChapter( + profileId0, + TEST_TOPIC_ID_1, + TEST_STORY_ID_2, + TEST_EXPLORATION_ID_4, + getCurrentTimestamp() + ) + testCoroutineDispatchers.runCurrent() + + val promotedActivityList = retrievePromotedActivityList() + assertThat(promotedActivityList.promotedStoryList.recentlyPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.olderPlayedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.promotedStoryList.suggestedStoryCount) + .isEqualTo(0) + assertThat(promotedActivityList.comingSoonTopicList.upcomingTopicCount) + .isEqualTo(1) + verifyUpcomingTopic1(promotedActivityList.comingSoonTopicList.upcomingTopicList[0]) + } + @Test fun testGetStoryList_markFirstExpOfEveryStoryDoneWithinLastSevenDays_ongoingListIsCorrect() { storyProgressController.recordCompletedChapter( From 47a48978359224368d29a7e8efd7bf3713d750a2 Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 31 Jan 2021 21:19:57 +0530 Subject: [PATCH 246/248] Update domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 5487f5cc4b8..5d64ae8b029 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -444,7 +444,7 @@ class TopicListControllerTest { } @Test - fun testGetStoryList_markRecentlyPlayedFirstTestTopic_defaultsuggestedStoryListIsCorrect() { + fun testGetStoryList_markRecentlyPlayedFirstTestTopic_defaultSuggestedStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, TEST_TOPIC_ID_0, From 1e7d32a9489b8cbe8019e2bd0916c3b86765f2ff Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 31 Jan 2021 21:20:42 +0530 Subject: [PATCH 247/248] Update domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt Co-authored-by: Ben Henning --- .../org/oppia/android/domain/topic/TopicListControllerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt index 5d64ae8b029..7cc82eb0e8e 100644 --- a/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt +++ b/domain/src/test/java/org/oppia/android/domain/topic/TopicListControllerTest.kt @@ -239,7 +239,7 @@ class TopicListControllerTest { } @Test - fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_ongoindStoryListIsCorrect() { + fun testGetPromotedActivityList_markRecentlyPlayedFracStory0Exp0_ongoingStoryListIsCorrect() { storyProgressController.recordRecentlyPlayedChapter( profileId0, FRACTIONS_TOPIC_ID, From 51a4c09ad08c21fa24cd9638cb627cfc83c0fa36 Mon Sep 17 00:00:00 2001 From: Veena Date: Sun, 31 Jan 2021 21:21:19 +0530 Subject: [PATCH 248/248] Update domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt Co-authored-by: Ben Henning --- .../java/org/oppia/android/domain/topic/TopicListController.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt index 8d367b9f3c3..1d6bcbc39ec 100644 --- a/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt +++ b/domain/src/main/java/org/oppia/android/domain/topic/TopicListController.kt @@ -530,7 +530,8 @@ class TopicListController @Inject constructor( } // TODO(#2550): Remove hardcoded order of topics. Compute list of suggested stories from backend structures - /** Returns a list of topic IDs for which the specified topic ID expects to be completed before + /** + * Returns a list of topic IDs for which the specified topic ID expects to be completed before * being suggested. */ private fun retrieveTopicDependencies(topicId: String): List {