Skip to content

Commit

Permalink
Fix oppia#3303, oppia#3305 and oppia#3306: Implement logic to modify …
Browse files Browse the repository at this point in the history
…lesson progress (oppia#3445)

* Implement Developer Options Starter

* Fix lint issues

* Implement Developer Options Menu Item in Nav Drawer

* Fix lint issues

* Added Kdoc. abstract class -> interface

* Added tests for Developer Options menu item

* Fixed lint issues

* Introduced ApplicationComponentForDevMode

* Added KDocs and fixed lint issues

* Added test to check unavailibility of Dev Options menu item when not in dev mode

* Added initial test for DeveloperOptionsActivity. Added KDocs. Fixed lint issues

* Introduced DebugApplicationComponent

* Implement developer options menu ui

* Modified way of passing data to recycler view

* removed unnecessary isMultipane boolean

* added view models to app/BUILD.bazel

* Added tests for DeveloperOptionsActivityTest

* Fixed lint issues

* Corrected key mismatch error. Changed isDevMode to isDebugMode. Nit fixes

* Fixed Robolectric test for NavigationDrawerActivityTest

* Updated developer_options_fragment layout

* Added test for hints switch

* Added eof. Changed dev mode to debug mode

* Initial progress on UI of MarkChaptersCompleted

* Fixed lint issues

* Fixed populating recyclerview

* Fixed lint issues

* Removed unnecessary lastLoadedFragment flag

* fixed lint issues

* Added dependencies to app/BUILD.bazel

* Corrected imports

* Removed unnecessary code from DeveloperOptionsActivityTest

* Modified approach for Application Components

* nit fix

* nit fix

* Implemented UI of MarkStoriesCompleted

* Implemented UI of MarkTopicsCompleted

* Added tests and Kdocs + nit fixes

* Code reformating

* Separated dev and prod tests for NavigationDrawerActivityTest

* Added tests to check intents in DeveloperOptionsActivityTest

* Added tests for MarkChaptersCompletedActivityTest

* Added tests for MarkStoriesCompletedActivityTest

* Add tests for MarkTopicsCompletedActivityTest

* nit fix

* Renamed NavigationDrawerActivityDevTest to NavigationDrawerActivityDebugTest

* nit fixes. created helper functions

* Moved starter to devoptions

* Moved starter to devoptions

* nit fix

* Added TODOs

* Added named arguments

* Arranged activity titles in app/strings.xml

* Removed unnecessary code. Nit fixes

* Added accessiblity test rule. Modified UI for the same

* Nit fix

* Created ModifyLessonProgressController

* Added TODO

* Added Kdoc to DeveloperOptionsViewModel

* Added KDocs

* Added method to getAllStoriesWithProgress

* Modified approach to get chapter list with progress

* Added tests related to all stories in ModifyLessonProgressControllerTest

* Added check if completed functions and tests for the same

* Added isCompleted flag to topi and story view models

* Nit fixes

* Nit changes in strings.xml

* Added KDocs + nit fixes

* Corrected imports in test files

* Fixed cobine topi and topicProgress function

* Implemented topic selection logic

* Implemented story selection logic

* Nit fixes

* Added disabled checkbox color

* Changed controller method to return map of stories and topic id. Changed from nested recycler view to MultiType recycler view in MarkChaptersCompleted

* Fixed recycler view crashing

* Implemented all check for MarkChaptersCompleted

* Corrected tests in ModifyLessonProgressControllerTest

* Nit fixes

* Added configChange tests in DeveloperOptionsActivityTest. Corrected tests in MarkChapters/Stories/TopicsCompletedActivityTest

* Added more tests to MarkChaptersCompletedActivityTest

* Changed UI according to accessibilityTestRule

* Modified UI according to accessibilityTestRule for stories and topics as well

* Moved ModifyLessonProgressController to devoptions package

* Nits and kdocs

* Fixed bazel build failure

* Added more tests for MarkStoriesCompleted

* Added more tests for MarkTopicsCompleted

* Added TODOs and nit fixes

* Modifed chapters recycler view interaction logic

* updated Kdocs. Nit fixes

* Code refactor for topics and stories

* Code refactored for chapters

* Implemented mark topics completed feature

* Implemented logic to mark stories completed

* Fixed bazel build failure

* Implement logic to mark chapters completed

* Made all checkbox checked whenall lessons are already completed

* Added tests for ModifyLessonProgressControllerTest

* Added tests to MarkChapters/Stories/TopicsCompletedTest

* Fixed failing tests

* Nit fixes

* Removed unnecessary boolean return

* Fixed lint issue

* Nit fix

* Nit fix

* Fixed MARK COMPLETED button alignment

* Code refactor and renamed tests

* Fixed finish activity test

* Fixed failing build and tests

* Added files to test_file_exemptions

* Removed unnecessary tests

* Nit fixes
  • Loading branch information
yashraj-01 authored Jul 11, 2021
1 parent aff7827 commit d685571
Show file tree
Hide file tree
Showing 13 changed files with 375 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,22 @@ import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.MarkChaptersCompletedChapterSummaryViewBinding
import org.oppia.android.databinding.MarkChaptersCompletedFragmentBinding
import org.oppia.android.databinding.MarkChaptersCompletedStorySummaryViewBinding
import org.oppia.android.domain.devoptions.ModifyLessonProgressController
import javax.inject.Inject

/** The presenter for [MarkChaptersCompletedFragment]. */
@FragmentScope
class MarkChaptersCompletedFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<MarkChaptersCompletedViewModel>
private val viewModelProvider: ViewModelProvider<MarkChaptersCompletedViewModel>,
private val modifyLessonProgressController: ModifyLessonProgressController
) : ChapterSelector {
private lateinit var binding: MarkChaptersCompletedFragmentBinding
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var bindingAdapter: BindableAdapter<MarkChaptersCompletedItemViewModel>
lateinit var selectedExplorationIdList: ArrayList<String>
private lateinit var profileId: ProfileId

fun handleCreateView(
inflater: LayoutInflater,
Expand All @@ -51,9 +54,8 @@ class MarkChaptersCompletedFragmentPresenter @Inject constructor(

this.selectedExplorationIdList = selectedExplorationIdList

getMarkChaptersCompletedViewModel().setProfileId(
ProfileId.newBuilder().setInternalId(internalProfileId).build()
)
profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build()
getMarkChaptersCompletedViewModel().setProfileId(profileId)

linearLayoutManager = LinearLayoutManager(activity.applicationContext)

Expand All @@ -79,6 +81,15 @@ class MarkChaptersCompletedFragmentPresenter @Inject constructor(
}
}

binding.markChaptersCompletedMarkCompletedTextView.setOnClickListener {
modifyLessonProgressController.markMultipleChaptersCompleted(
profileId = profileId,
chapterMap = getMarkChaptersCompletedViewModel().getChapterMap()
.filterKeys { selectedExplorationIdList.contains(it) }
)
activity.finish()
}

return binding.root
}

Expand Down Expand Up @@ -111,6 +122,12 @@ class MarkChaptersCompletedFragmentPresenter @Inject constructor(
model: ChapterSummaryViewModel
) {
binding.viewModel = model
val notCompletedChapterCount = getMarkChaptersCompletedViewModel().getItemList().count {
it is ChapterSummaryViewModel && !it.checkIfChapterIsCompleted()
}
if (notCompletedChapterCount == 0) {
this.binding.isAllChecked = true
}
if (model.checkIfChapterIsCompleted()) {
binding.isChapterChecked = true
binding.isChapterCheckboxEnabled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,11 @@ class MarkChaptersCompletedViewModel @Inject constructor(

/** Returns a list of [MarkChaptersCompletedItemViewModel]s. */
fun getItemList(): List<MarkChaptersCompletedItemViewModel> = itemList.toList()

/** Returns a list of [ChapterSummaryViewModel]s mapped to corresponding exploration IDs. */
fun getChapterMap(): Map<String, Pair<String, String>> =
itemList.filterIsInstance<ChapterSummaryViewModel>().associateBy(
{ it.chapterSummary.explorationId },
{ Pair(it.storyId, it.topicId) }
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.MarkStoriesCompletedFragmentBinding
import org.oppia.android.databinding.MarkStoriesCompletedStorySummaryViewBinding
import org.oppia.android.domain.devoptions.ModifyLessonProgressController
import javax.inject.Inject

/** The presenter for [MarkStoriesCompletedFragment]. */
@FragmentScope
class MarkStoriesCompletedFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<MarkStoriesCompletedViewModel>
private val viewModelProvider: ViewModelProvider<MarkStoriesCompletedViewModel>,
private val modifyLessonProgressController: ModifyLessonProgressController
) : StorySelector {
private lateinit var binding: MarkStoriesCompletedFragmentBinding
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var bindingAdapter: BindableAdapter<StorySummaryViewModel>
lateinit var selectedStoryIdList: ArrayList<String>
private lateinit var profileId: ProfileId

fun handleCreateView(
inflater: LayoutInflater,
Expand All @@ -49,9 +52,8 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor(

this.selectedStoryIdList = selectedStoryIdList

getMarkStoriesCompletedViewModel().setProfileId(
ProfileId.newBuilder().setInternalId(internalProfileId).build()
)
profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build()
getMarkStoriesCompletedViewModel().setProfileId(profileId)

linearLayoutManager = LinearLayoutManager(activity.applicationContext)

Expand All @@ -68,14 +70,23 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor(

binding.markStoriesCompletedAllCheckBox.setOnCheckedChangeListener { _, isChecked ->
if (isChecked) {
getMarkStoriesCompletedViewModel().getStorySummaryList().forEach { viewModel ->
getMarkStoriesCompletedViewModel().getStorySummaryMap().values.forEach { viewModel ->
if (!viewModel.isCompleted)
storySelected(viewModel.storySummary.storyId)
}
}
bindingAdapter.notifyDataSetChanged()
}

binding.markStoriesCompletedMarkCompletedTextView.setOnClickListener {
modifyLessonProgressController.markMultipleStoriesCompleted(
profileId,
getMarkStoriesCompletedViewModel().getStorySummaryMap()
.filterKeys { selectedStoryIdList.contains(it) }.mapValues { it.value.topicId }
)
activity.finish()
}

return binding.root
}

Expand All @@ -94,6 +105,11 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor(
model: StorySummaryViewModel
) {
binding.viewModel = model
if (getMarkStoriesCompletedViewModel().getStorySummaryMap().values
.count { !it.isCompleted } == 0
) {
this.binding.isAllChecked = true
}
if (model.isCompleted) {
binding.isStoryChecked = true
binding.markStoriesCompletedStoryCheckBox.isEnabled = false
Expand All @@ -119,7 +135,7 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor(
}

if (selectedStoryIdList.size ==
getMarkStoriesCompletedViewModel().getStorySummaryList().count { !it.isCompleted }
getMarkStoriesCompletedViewModel().getStorySummaryMap().values.count { !it.isCompleted }
) {
binding.isAllChecked = true
}
Expand All @@ -131,7 +147,7 @@ class MarkStoriesCompletedFragmentPresenter @Inject constructor(
}

if (selectedStoryIdList.size !=
getMarkStoriesCompletedViewModel().getStorySummaryList().count { !it.isCompleted }
getMarkStoriesCompletedViewModel().getStorySummaryMap().values.count { !it.isCompleted }
) {
binding.isAllChecked = false
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class MarkStoriesCompletedViewModel @Inject constructor(

private lateinit var profileId: ProfileId

private val itemList = mutableListOf<StorySummaryViewModel>()
private val itemList = mutableMapOf<String, StorySummaryViewModel>()

/**
* List of [StorySummaryViewModel] used to populate recyclerview of [MarkStoriesCompletedFragment]
Expand Down Expand Up @@ -65,16 +65,20 @@ class MarkStoriesCompletedViewModel @Inject constructor(
storyMap.forEach {
it.value.forEach { storySummary ->
val isCompleted = modifyLessonProgressController.checkIfStoryIsCompleted(storySummary)
itemList.add(StorySummaryViewModel(storySummary, isCompleted, topicId = it.key))
itemList[storySummary.storyId] =
StorySummaryViewModel(storySummary, isCompleted, topicId = it.key)
}
}
return itemList
return itemList.values.toList()
}

fun setProfileId(profileId: ProfileId) {
this.profileId = profileId
}

/** Returns a list of [StorySummaryViewModel]s whose progress can be modified. */
fun getStorySummaryList(): List<StorySummaryViewModel> = itemList.toList()
/**
* Returns a list of [StorySummaryViewModel]s mapped to corresponding story IDs whose progress
* can be modified.
*/
fun getStorySummaryMap(): Map<String, StorySummaryViewModel> = itemList.toMap()
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,19 +12,22 @@ import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.app.viewmodel.ViewModelProvider
import org.oppia.android.databinding.MarkTopicsCompletedFragmentBinding
import org.oppia.android.databinding.MarkTopicsCompletedTopicViewBinding
import org.oppia.android.domain.devoptions.ModifyLessonProgressController
import javax.inject.Inject

/** The presenter for [MarkTopicsCompletedFragment]. */
@FragmentScope
class MarkTopicsCompletedFragmentPresenter @Inject constructor(
private val activity: AppCompatActivity,
private val fragment: Fragment,
private val viewModelProvider: ViewModelProvider<MarkTopicsCompletedViewModel>
private val viewModelProvider: ViewModelProvider<MarkTopicsCompletedViewModel>,
private val modifyLessonProgressController: ModifyLessonProgressController
) : TopicSelector {
private lateinit var binding: MarkTopicsCompletedFragmentBinding
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var bindingAdapter: BindableAdapter<TopicViewModel>
lateinit var selectedTopicIdList: ArrayList<String>
private lateinit var profileId: ProfileId

fun handleCreateView(
inflater: LayoutInflater,
Expand All @@ -49,9 +52,8 @@ class MarkTopicsCompletedFragmentPresenter @Inject constructor(

this.selectedTopicIdList = selectedTopicIdList

getMarkTopicsCompletedViewModel().setProfileId(
ProfileId.newBuilder().setInternalId(internalProfileId).build()
)
this.profileId = ProfileId.newBuilder().setInternalId(internalProfileId).build()
getMarkTopicsCompletedViewModel().setProfileId(profileId)

linearLayoutManager = LinearLayoutManager(activity.applicationContext)

Expand All @@ -75,6 +77,14 @@ class MarkTopicsCompletedFragmentPresenter @Inject constructor(
bindingAdapter.notifyDataSetChanged()
}

binding.markTopicsCompletedMarkCompletedTextView.setOnClickListener {
modifyLessonProgressController.markMultipleTopicsCompleted(
profileId,
selectedTopicIdList
)
activity.finish()
}

return binding.root
}

Expand All @@ -93,6 +103,9 @@ class MarkTopicsCompletedFragmentPresenter @Inject constructor(
model: TopicViewModel
) {
binding.viewModel = model
if (getMarkTopicsCompletedViewModel().getTopicList().count { !it.isCompleted } == 0) {
this.binding.isAllChecked = true
}
if (model.isCompleted) {
binding.isTopicChecked = true
binding.markTopicsCompletedTopicCheckBox.isEnabled = false
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/layout/mark_chapters_completed_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="center_vertical"
android:minWidth="48dp"
android:minHeight="48dp"
android:text="@string/mark_completed_uppercase"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/layout/mark_stories_completed_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="center_vertical"
android:minWidth="48dp"
android:minHeight="48dp"
android:text="@string/mark_completed_uppercase"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/res/layout/mark_topics_completed_fragment.xml
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="16dp"
android:gravity="center_vertical"
android:minWidth="48dp"
android:minHeight="48dp"
android:text="@string/mark_completed_uppercase"
android:textColor="@color/white"
app:layout_constraintBottom_toBottomOf="parent"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,46 @@ class MarkChaptersCompletedActivityTest {
}
}

@Test
fun testMarkChaptersCompletedActivity_clickMarkCompleted_activityFinishes() {
activityTestRule.launchActivity(createMarkChaptersCompletedActivityIntent(internalProfileId))
testCoroutineDispatchers.runCurrent()
onView(withId(R.id.mark_chapters_completed_mark_completed_text_view)).perform(click())
assertThat(activityTestRule.activity.isFinishing).isTrue()
}

@Test
fun testMarkChaptersCompletedActivity_configChange_clickMarkCompleted_activityFinishes() {
activityTestRule.launchActivity(createMarkChaptersCompletedActivityIntent(internalProfileId))
testCoroutineDispatchers.runCurrent()
onView(isRoot()).perform(orientationLandscape())
onView(withId(R.id.mark_chapters_completed_mark_completed_text_view)).perform(click())
assertThat(activityTestRule.activity.isFinishing).isTrue()
}

@Test
fun testMarkChaptersCompletedActivity_allLessonsAreCompleted_allCheckboxIsChecked() {
markAllLessonsCompleted()
launch<MarkChaptersCompletedActivity>(
createMarkChaptersCompletedActivityIntent(internalProfileId)
).use {
testCoroutineDispatchers.runCurrent()
onView(withId(R.id.mark_chapters_completed_all_check_box)).check(matches(isChecked()))
}
}

@Test
fun testMarkChaptersCompletedActivity_allLessonsAreCompleted_configChange_allCheckboxIsChecked() {
markAllLessonsCompleted()
launch<MarkChaptersCompletedActivity>(
createMarkChaptersCompletedActivityIntent(internalProfileId)
).use {
testCoroutineDispatchers.runCurrent()
onView(isRoot()).perform(orientationLandscape())
onView(withId(R.id.mark_chapters_completed_all_check_box)).check(matches(isChecked()))
}
}

private fun createMarkChaptersCompletedActivityIntent(internalProfileId: Int): Intent {
return MarkChaptersCompletedActivity.createMarkChaptersCompletedIntent(
context, internalProfileId
Expand Down Expand Up @@ -799,6 +839,13 @@ class MarkChaptersCompletedActivityTest {
)
}

private fun markAllLessonsCompleted() {
storyProgressTestHelper.markAllTopicsAsCompleted(
profileId,
timestampOlderThanOneWeek = false
)
}

private fun scrollToPosition(position: Int) {
onView(withId(R.id.mark_chapters_completed_recycler_view)).perform(
scrollToPosition<ViewHolder>(
Expand Down
Loading

0 comments on commit d685571

Please sign in to comment.