-
Notifications
You must be signed in to change notification settings - Fork 535
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
Fixes #5572 : Softer redirection for learners who need to revisit earlier cards #5626
Open
subhajitxyz
wants to merge
28
commits into
oppia:develop
Choose a base branch
from
subhajitxyz:softer-redirection-earlier-card
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
d819e70
Merge pull request #1 from oppia/develop
subhajitxyz c6f54ea
Merge branch 'oppia:develop' into develop
subhajitxyz d44015b
Merge remote-tracking branch 'upstream/develop' into develop
subhajitxyz d604bc2
Merge pull request #2 from oppia/develop
subhajitxyz cc0ddef
Merge pull request #3 from oppia/develop
subhajitxyz 52c6bb1
Merge pull request #4 from oppia/develop
subhajitxyz 773c810
Merge remote-tracking branch 'upstream/develop' into develop
subhajitxyz 56af5ae
Merge pull request #5 from oppia/develop
subhajitxyz 3883f70
Merge pull request #6 from oppia/develop
subhajitxyz 10c8e6e
Fix #5404: Migrate away from onBackPressed for remaining activities (…
dattasneha 5e140e9
Fix #5404: Migrate away from onBackPressed for RevisionCardActivity (…
dattasneha b4ad7a3
Merge branch 'oppia:develop' into develop
subhajitxyz 238645d
Merge pull request #8 from oppia/develop
subhajitxyz 5a546b9
Merge pull request #9 from oppia/develop
subhajitxyz b1ca8e1
Merge pull request #10 from oppia/develop
subhajitxyz ad7e380
Merge pull request #11 from oppia/develop
subhajitxyz b938a4c
Fix #5508: Skipping redundant code coverage and APK/AAB report commen…
Rd4dev fc2f932
Fix part of #4865: Use profileId in classroom activity and presenter …
tobioyelekan 35f937b
Merge branch 'oppia:develop' into develop
subhajitxyz 21b0986
Merge branch 'oppia:develop' into develop
subhajitxyz d891a5a
Merge branch 'oppia:develop' into develop
subhajitxyz 7c12668
Merge branch 'oppia:develop' into develop
subhajitxyz 040c157
Merge branch 'oppia:develop' into develop
subhajitxyz c5db6ea
Merge branch 'oppia:develop' into develop
subhajitxyz b031bd3
Add functionality for softer redirection
subhajitxyz ccb1874
Added missinig kdoc
subhajitxyz c45ebc2
update kdoc
subhajitxyz fe86e2f
initialize shouldRevisitEarlierCard in resumedeck
subhajitxyz File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,6 +24,7 @@ class StateDeck constructor( | |
private val previousStates: MutableList<EphemeralState> = ArrayList() | ||
private val currentDialogInteractions: MutableList<AnswerAndResponse> = ArrayList() | ||
private var stateIndex: Int = 0 | ||
private var shouldRevisitEarlierCard: Boolean = false | ||
|
||
/** Resets this deck to a new, specified initial [State]. */ | ||
fun resetDeck(initialState: State) { | ||
|
@@ -46,6 +47,7 @@ class StateDeck constructor( | |
this.previousStates.addAll(previousStates) | ||
this.currentDialogInteractions.addAll(currentDialogInteractions) | ||
this.stateIndex = stateIndex | ||
if (getStateIndexOfEarlierCard(pendingTopState.name) != null) shouldRevisitEarlierCard = true | ||
} | ||
|
||
/** Navigates to the previous state in the deck, or fails if this isn't possible. */ | ||
|
@@ -57,12 +59,19 @@ class StateDeck constructor( | |
/** Navigates to the next state in the deck, or fails if this isn't possible. */ | ||
fun navigateToNextState() { | ||
check(!isCurrentStateTopOfDeck()) { "Cannot navigate to next state; at most recent state." } | ||
val previousState = previousStates[stateIndex] | ||
stateIndex++ | ||
if (!previousState.hasNextState) { | ||
// Update the previous state to indicate that it has a next state now that its next state has | ||
// actually been reated' by navigating to it. | ||
previousStates[stateIndex - 1] = previousState.toBuilder().setHasNextState(true).build() | ||
|
||
val revisionIdx = getStateIndexOfEarlierCard(pendingTopState.name) | ||
|
||
if (revisionIdx != null && stateIndex == previousStates.size - 1 && shouldRevisitEarlierCard) { | ||
handleRevisitEarlierCard(revisionIdx) | ||
} else { | ||
val previousState = previousStates[stateIndex] | ||
stateIndex++ | ||
if (!previousState.hasNextState) { | ||
// Update the previous state to indicate that it has a next state now that its next state has | ||
// actually been created' by navigating to it. | ||
previousStates[stateIndex - 1] = previousState.toBuilder().setHasNextState(true).build() | ||
} | ||
} | ||
} | ||
|
||
|
@@ -151,7 +160,9 @@ class StateDeck constructor( | |
.setContinueButtonAnimationTimestampMs(timestamp) | ||
.setShowContinueButtonAnimation(!isContinueButtonAnimationSeen && isCurrentStateInitial()) | ||
.build() | ||
currentDialogInteractions.clear() | ||
if (!shouldRevisitEarlierCard || getStateIndexOfEarlierCard(state.name) == null) { | ||
currentDialogInteractions.clear() | ||
} | ||
pendingTopState = state | ||
} | ||
|
||
|
@@ -251,4 +262,52 @@ class StateDeck constructor( | |
private fun isTopOfDeckTerminal(): Boolean { | ||
return isTopOfDeckTerminalChecker(pendingTopState) | ||
} | ||
|
||
/** | ||
* Handles revisiting an earlier card when the user clicks the continue button. | ||
* | ||
* This function adjusts the state to facilitate revisiting a previously viewed card. | ||
* - Removes the last added ephemeral state from [previousStates], which was added when user | ||
* submitted a wrong answer. | ||
* - Updates [pendingTopState] to the current state with the stored [currentDialogInteractions], | ||
* marking it as a pending state where the user needs to submit a correct answer. | ||
* - Updates [stateIndex] to the provided [revisionIdx]. | ||
* - Turns off the revisit mode by setting [shouldRevisitEarlierCard] to `false`. | ||
* | ||
* @param revisionIdx the index of the state to revisit. | ||
*/ | ||
private fun handleRevisitEarlierCard(revisionIdx: Int) { | ||
val timestamp = previousStates[previousStates.size - 1].continueButtonAnimationTimestampMs | ||
val showContinueButtonSeen = | ||
previousStates[previousStates.size - 1].showContinueButtonAnimation | ||
val currentState = previousStates[previousStates.size - 1].state | ||
|
||
previousStates.removeAt(previousStates.size - 1) | ||
|
||
pendingTopState = EphemeralState.newBuilder() | ||
.setState(currentState) | ||
.setHasPreviousState(!isCurrentStateInitial()) | ||
.setPendingState(PendingState.newBuilder().addAllWrongAnswer(currentDialogInteractions)) | ||
.setContinueButtonAnimationTimestampMs(timestamp) | ||
.setShowContinueButtonAnimation(showContinueButtonSeen) | ||
.build().state | ||
|
||
stateIndex = revisionIdx | ||
turnOnRevisitEarlierCard(false) | ||
} | ||
|
||
/** Returns [stateIndex] if state present on [previousStates] list. */ | ||
private fun getStateIndexOfEarlierCard(stateName: String): Int? { | ||
for (i in previousStates.size - 1 downTo 0) { | ||
if (previousStates[i].state.name == stateName) { | ||
return i | ||
} | ||
} | ||
return null | ||
} | ||
|
||
/** Sets whether the user should revisit an earlier card. */ | ||
fun turnOnRevisitEarlierCard(value: Boolean) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about: |
||
shouldRevisitEarlierCard = value | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that, while this works, I worry the mechanism is potentially fragile because it seems that it's essentially detecting a scenario where we want to redirect back to an earlier state and then triggering an override behavior in
StateDeck
to 'catch' this before a real state is pushed onto the stack.I wonder if this could be done more simply. We could, for example, update the
AnswerOutcome
proto to have a new destination such asstring previous_state_name
and updatecomputeAnswerOutcomeForResult
to compute this scenario (i.e. the detection is moved to that method, instead).That would mean a new case needs to be handled here, which actually should allow us to simplify the state deck behavior as well.
StateDeck
already supports navigation to/from specific cards. Could we, perhaps, add a method toStateDeck
that's essentially "navigateToMostRecentState()" that takes a state name? That seems like it could be much simpler to manage.Finally, I think the original issue also asks that we introduce a new blue "Learn Again" button. This would need to replace "Continue" which, in turn, means updating
EphemeralState
to include a new type, probably something likeCompletedState need_to_revisit_old_card
which would signal to the UI that a different button other than 'Continue' needs to be shown.I have some other thoughts on how to manage replacing the latest state so that it can be tried again, and possibly some thoughts on the specific state computation. However, I'll leave that for a review after the above is addressed since those will involve rearranging and, hopefully, simplifying much of the logic here (plus adding the necessary new pieces for the button change).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @BenHenning , for the suggestion. I think it could be done more simply in the way you mentioned above. I will try introducing a new "Learn Again" button.
I would love to hear your thoughts on how to manage replacing the latest state so that it can be tried again, as well as the specific state computation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, I am not fully able to understand how this navigateToMostRecentState() will help us.
After reaching to the old card, Do we want to skip all the previously seen states with one click ?