Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #1468: Retain Drag and Drop state after an incorrect answer #5541

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
46375af
Fix #1468: Retain Drag and Drop state after an incorrect answer
Rd4dev Sep 22, 2024
541c0ae
Removed unused import
Rd4dev Sep 22, 2024
0307892
Fix Ktlint issues
Rd4dev Sep 22, 2024
a09bbf4
Updating the UI via live data - reset works; the empty input error re…
Rd4dev Sep 28, 2024
8e093cd
Updated the original choice items with a new instance of the choice I…
Rd4dev Sep 28, 2024
090c244
Initializing the _choiceItems to a empty list to never have a null re…
Rd4dev Sep 28, 2024
94e86f4
Debugging save lobby before swiching to test in base branch
Rd4dev Sep 29, 2024
43a73e8
Temporary Fix to handle grouping - resets (does not retain)
Rd4dev Sep 29, 2024
58ef353
Implementation of a retaining the reordered state with linking / grou…
Rd4dev Sep 29, 2024
f761445
Refactored the result retrieval with wrongAnswerList and added Robole…
Rd4dev Sep 29, 2024
aa4f2de
Ktlint indentation fix
Rd4dev Sep 29, 2024
7d1ab3a
Added test case to check the retained wrong Answer list text when mer…
Rd4dev Sep 29, 2024
41f1195
Added/Verified Espresso Tests - bumped Mockitor to 3.11.1
Rd4dev Sep 30, 2024
2989b1a
Revert mockito version introduced to workaround locally
Rd4dev Oct 1, 2024
83349ef
Using the original choice items as a fall back value if the async res…
Rd4dev Oct 2, 2024
3fa675d
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Nov 7, 2024
6785bf5
Using Transformations map to transform the live data
Rd4dev Nov 20, 2024
ee95884
Utilized Transformations switch map to proide the live data
Rd4dev Nov 21, 2024
2620f1a
Utilized MediatorLiveData to set a initial Pending value to avoid NPE
Rd4dev Nov 21, 2024
1b97d3d
Cleanup of debugging logs and intermediate values
Rd4dev Nov 22, 2024
8f6abca
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Nov 22, 2024
a82e5d4
Fix ktlint indentation issues
Rd4dev Nov 22, 2024
1863715
Fix spelling of variable - answerErrorCategory
Rd4dev Nov 22, 2024
a62a52c
Merge branch 'develop' of https://github.com/Rd4dev/oppia-android int…
Rd4dev Dec 10, 2024
a63bd67
Merge branch 'develop' into drag_drop_retain_state_incorrect_answer
adhiamboperes Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@ package org.oppia.android.app.player.state.itemviewmodel
import androidx.annotation.StringRes
import androidx.databinding.Observable
import androidx.databinding.ObservableField
import androidx.lifecycle.LiveData
import androidx.lifecycle.MediatorLiveData
import androidx.lifecycle.Transformations
import androidx.recyclerview.widget.RecyclerView
import org.oppia.android.R
import org.oppia.android.app.model.AnswerErrorCategory
import org.oppia.android.app.model.EphemeralState
import org.oppia.android.app.model.Interaction
import org.oppia.android.app.model.InteractionObject
import org.oppia.android.app.model.ListOfSetsOfHtmlStrings
Expand All @@ -24,7 +28,10 @@ import org.oppia.android.app.recyclerview.BindableAdapter
import org.oppia.android.app.recyclerview.OnDragEndedListener
import org.oppia.android.app.recyclerview.OnItemDragListener
import org.oppia.android.app.translation.AppLanguageResourceHandler
import org.oppia.android.domain.exploration.ExplorationProgressController
import org.oppia.android.domain.translation.TranslationController
import org.oppia.android.util.data.AsyncResult
import org.oppia.android.util.data.DataProviders.Companion.toLiveData
import javax.inject.Inject

/** Represents the type of errors that can be thrown by drag and drop sort interaction. */
Expand All @@ -49,11 +56,13 @@ class DragAndDropSortInteractionViewModel private constructor(
private val writtenTranslationContext: WrittenTranslationContext,
private val resourceHandler: AppLanguageResourceHandler,
private val translationController: TranslationController,
userAnswerState: UserAnswerState
userAnswerState: UserAnswerState,
private val explorationProgressController: ExplorationProgressController
) : StateItemViewModel(ViewType.DRAG_DROP_SORT_INTERACTION),
InteractionAnswerHandler,
OnItemDragListener,
OnDragEndedListener {

private val allowMultipleItemsInSamePosition: Boolean by lazy {
interaction.customizationArgsMap["allowMultipleItemsInSamePosition"]?.boolValue ?: false
}
Expand All @@ -72,19 +81,18 @@ class DragAndDropSortInteractionViewModel private constructor(
subtitledHtml.contentId to translatedHtml
}

private var answerErrorCetegory: AnswerErrorCategory = AnswerErrorCategory.NO_ERROR
private var answerErrorCategory: AnswerErrorCategory = AnswerErrorCategory.NO_ERROR

private val _originalChoiceItems: MutableList<DragDropInteractionContentViewModel> =
private var _originalChoiceItems: MutableList<DragDropInteractionContentViewModel> =
computeOriginalChoiceItems(contentIdHtmlMap, choiceSubtitledHtmls, this, resourceHandler)

private val _choiceItems = computeSelectedChoiceItems(
contentIdHtmlMap,
choiceSubtitledHtmls,
this,
resourceHandler,
userAnswerState
)
val choiceItems: List<DragDropInteractionContentViewModel> = _choiceItems
lateinit var choiceItems: LiveData<List<DragDropInteractionContentViewModel>>
private var _choiceItems: MutableList<DragDropInteractionContentViewModel> =
computeSelectedChoiceItems(
contentIdHtmlMap,
this,
resourceHandler
)

private var pendingAnswerError: String? = null
private val isAnswerAvailable = ObservableField(false)
Expand Down Expand Up @@ -170,7 +178,7 @@ class DragAndDropSortInteractionViewModel private constructor(
* updates the error string based on the specified error category.
*/
override fun checkPendingAnswerError(category: AnswerErrorCategory): String? {
answerErrorCetegory = category
answerErrorCategory = category
pendingAnswerError = when (category) {
AnswerErrorCategory.REAL_TIME -> null
AnswerErrorCategory.SUBMIT_TIME ->
Expand Down Expand Up @@ -252,7 +260,8 @@ class DragAndDropSortInteractionViewModel private constructor(
/** Implementation of [StateItemViewModel.InteractionItemFactory] for this view model. */
class FactoryImpl @Inject constructor(
private val resourceHandler: AppLanguageResourceHandler,
private val translationController: TranslationController
private val translationController: TranslationController,
private val explorationProgressController: ExplorationProgressController
) : InteractionItemFactory {
override fun create(
entityId: String,
Expand All @@ -275,15 +284,16 @@ class DragAndDropSortInteractionViewModel private constructor(
writtenTranslationContext,
resourceHandler,
translationController,
userAnswerState
userAnswerState,
explorationProgressController
)
}
}

override fun getUserAnswerState(): UserAnswerState {
if (_choiceItems == _originalChoiceItems) {
return UserAnswerState.newBuilder().apply {
this.answerErrorCategory = answerErrorCetegory
this.answerErrorCategory = answerErrorCategory
}.build()
}
return UserAnswerState.newBuilder().apply {
Expand All @@ -292,7 +302,7 @@ class DragAndDropSortInteractionViewModel private constructor(
ListOfSetsOfTranslatableHtmlContentIds.newBuilder().apply {
addAllContentIdLists(htmlContentIds)
}.build()
answerErrorCategory = answerErrorCetegory
answerErrorCategory = answerErrorCategory
}.build()
}

Expand Down Expand Up @@ -324,25 +334,69 @@ class DragAndDropSortInteractionViewModel private constructor(

private fun computeSelectedChoiceItems(
contentIdHtmlMap: Map<String, String>,
choiceStrings: List<SubtitledHtml>,
dragAndDropSortInteractionViewModel: DragAndDropSortInteractionViewModel,
resourceHandler: AppLanguageResourceHandler,
userAnswerState: UserAnswerState
resourceHandler: AppLanguageResourceHandler
): MutableList<DragDropInteractionContentViewModel> {
return if (userAnswerState.listOfSetsOfTranslatableHtmlContentIds.contentIdListsCount == 0) {
_originalChoiceItems.toMutableList()
} else {
userAnswerState.listOfSetsOfTranslatableHtmlContentIds.contentIdListsList
.mapIndexed { index, contentId ->
DragDropInteractionContentViewModel(
contentIdHtmlMap = contentIdHtmlMap,
htmlContent = contentId,
itemIndex = index,
listSize = choiceStrings.size,
dragAndDropSortInteractionViewModel = dragAndDropSortInteractionViewModel,
resourceHandler = resourceHandler
val explorationEphemeralStateLiveData = MediatorLiveData<AsyncResult<EphemeralState>>().apply {
value = AsyncResult.Pending()
addSource(explorationProgressController.getCurrentState().toLiveData()) { result ->
value = result
}
}

choiceItems = Transformations.map(explorationEphemeralStateLiveData) { result ->
when (result) {
is AsyncResult.Failure, is AsyncResult.Pending -> {
_originalChoiceItems
}
is AsyncResult.Success -> {
_choiceItems = processEphemeralStateResult(
result.value,
contentIdHtmlMap,
dragAndDropSortInteractionViewModel,
resourceHandler
)
}.toMutableList()
_originalChoiceItems = _choiceItems.toMutableList()
_choiceItems
}
else -> _originalChoiceItems
}
}

return _choiceItems.takeIf { !it.isNullOrEmpty() }
?: _originalChoiceItems.toMutableList()
}

private fun processEphemeralStateResult(
state: EphemeralState,
contentIdHtmlMap: Map<String, String>,
dragAndDropSortInteractionViewModel: DragAndDropSortInteractionViewModel,
resourceHandler: AppLanguageResourceHandler
): MutableList<DragDropInteractionContentViewModel> {
val wrongAnswerList = state.pendingState.wrongAnswerList
return if (wrongAnswerList.isNotEmpty()) {
val latestWrongAnswerContentIdList = wrongAnswerList.last()
.userAnswer.answer.listOfSetsOfTranslatableHtmlContentIds.contentIdListsList
latestWrongAnswerContentIdList.mapIndexed { index, setOfTranslatableHtmlContentIds ->
DragDropInteractionContentViewModel(
contentIdHtmlMap = contentIdHtmlMap,
htmlContent = SetOfTranslatableHtmlContentIds.newBuilder().apply {
for (contentIds in setOfTranslatableHtmlContentIds.contentIdsList) {
addContentIds(
TranslatableHtmlContentId.newBuilder().apply {
contentId = contentIds.contentId
}
)
}
}.build(),
itemIndex = index,
listSize = latestWrongAnswerContentIdList.size,
dragAndDropSortInteractionViewModel = dragAndDropSortInteractionViewModel,
resourceHandler = resourceHandler
)
}.toMutableList()
} else {
_originalChoiceItems.toMutableList()
}
}
}
Loading
Loading