Simplify resolved wrong-answer explanation cards per design feedback

Drop the redundant header row (duplicate percentage badge + collapse
chevron), the "Why this is appropriate/less appropriate:"/"Why this
is incorrect:" heading labels, and the nested sub-box - now that
these cards live inside their own choice's colored border, all of
that was repeating what the color and position already say. Both the
selected-wrong-choice resolved follow-up and the never-selected
distractor cards now just show the plain explanation sentence, with
the leading "Correct."/"Incorrect." verdict word stripped too.

Removing the toggle chevron removes the only way to reach the
collapse/expand behavior, so that machinery (_collapse_resolved_followups,
_toggle_followup_state, the "collapsed" state field) comes out too
rather than linger unreachable.
This commit is contained in:
hz
2026-07-23 04:19:10 -05:00
parent d69a1fd0e3
commit b3a8dec379
2 changed files with 23 additions and 91 deletions
+13 -72
View File
@@ -1346,7 +1346,6 @@ func _submit_or_next() -> void:
return
var question_id_for_attempt := str(BlockSessionService.get_current_question().get("id", ""))
if BlockSessionService.session_kind in ["core", "bookmark", "review"]:
_collapse_resolved_followups()
var attempted_choice := selected_choice
if BlockSessionService.session_kind == "core":
QuestionBankService.record_first_attempt(
@@ -1558,7 +1557,7 @@ func _render_teaching_cards() -> void:
if takeaway == "":
var correct_id := str(question.get("correct_choice_id", ""))
var explanations: Dictionary = question.get("choice_explanations", {})
takeaway = _strip_correct_prefix(str(explanations.get(correct_id, "")).strip_edges())
takeaway = _strip_verdict_prefix(str(explanations.get(correct_id, "")).strip_edges())
var pearl := str(question.get("usmle_pearl", "")).strip_edges()
if takeaway != "":
_add_teaching_card("KEY TAKEAWAY", takeaway, Brand.SKY_BLUE)
@@ -1686,16 +1685,11 @@ func _render_unselected_distractor_explanations() -> void:
continue
_clear_followup_content(index)
var content := choice_followup_contents[index]
var body_content := _add_followup_body(content, false)
var heading := Label.new()
heading.text = "Why this is incorrect:"
_set_scaled_label(heading, 14, Color("fb5f6d"))
body_content.add_child(heading)
var explanation := Label.new()
explanation.text = _distractor_explanation_text(choice_id)
explanation.text = _strip_verdict_prefix(_distractor_explanation_text(choice_id))
explanation.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_set_scaled_label(explanation, 14, Brand.text_color(_followup_is_dark()))
body_content.add_child(explanation)
content.add_child(explanation)
choice_followup_panels[index].add_theme_stylebox_override(
"panel",
_attached_panel_box(_followup_is_dark(), Color("fb7185"))
@@ -1708,16 +1702,16 @@ func _distractor_explanation_text(choice_id: String) -> String:
var question := BlockSessionService.get_current_question()
var explanations: Dictionary = question.get("choice_explanations", {})
var explanation := str(explanations.get(choice_id, "")).strip_edges()
if explanation.begins_with("Correct. "):
explanation = explanation.substr(9)
if explanation != "":
return explanation
return "Review the stem finding that makes this option less appropriate."
func _strip_correct_prefix(value: String) -> String:
func _strip_verdict_prefix(value: String) -> String:
if value.begins_with("Correct. "):
return value.substr(9)
if value.begins_with("Incorrect. "):
return value.substr(11)
return value
@@ -3162,7 +3156,6 @@ func _build_followup_panel(_index: int, choice_id: String) -> void:
"selected_option_text": "",
"was_correct": false,
"resolved": false,
"collapsed": false,
"has_authored_choices": bool(followup.get("has_authored_choices", false)),
"is_main_correct": false
}
@@ -3177,7 +3170,7 @@ func _append_followup_attempt(choice_id: String) -> void:
func _render_active_followup(index: int, state: Dictionary) -> void:
var content := choice_followup_contents[index]
_build_followup_header(content, state, true, false)
_build_followup_header(content, state)
var body_content := _add_followup_body(content, false)
var prompt := Label.new()
@@ -3235,7 +3228,6 @@ func _resolve_followup(_followup: Dictionary, selected_button: Button, _style_se
state["selected_option_text"] = selected_option_text
state["was_correct"] = is_correct
state["resolved"] = true
state["collapsed"] = false
followup_states[resolved_choice_id] = state
_render_followup_state(resolved_choice_id)
@@ -3251,28 +3243,6 @@ func _unlock_after_followup() -> void:
_apply_saved_choice_state()
func _collapse_resolved_followups() -> void:
for choice_id in followup_states.keys():
var state: Dictionary = followup_states[choice_id]
if bool(state.get("resolved", false)):
state["collapsed"] = true
followup_states[choice_id] = state
_render_followup_state(choice_id)
_apply_saved_choice_state()
func _toggle_followup_state(choice_id: String) -> void:
if not followup_states.has(choice_id) or followup_required:
return
var state: Dictionary = followup_states[choice_id]
if not bool(state.get("resolved", false)):
return
state["collapsed"] = not bool(state.get("collapsed", false))
followup_states[choice_id] = state
_render_followup_state(choice_id)
_apply_saved_choice_state()
func _render_followup_state(choice_id: String) -> void:
if not followup_states.has(choice_id):
return
@@ -3284,8 +3254,6 @@ func _render_followup_state(choice_id: String) -> void:
_style_followup_card(index, state)
if not bool(state.get("resolved", false)):
_render_active_followup(index, state)
elif bool(state.get("collapsed", false)):
_build_followup_header(choice_followup_contents[index], state, false, true)
else:
_build_resolved_followup(index, state)
choice_followup_panels[index].visible = true
@@ -3294,22 +3262,14 @@ func _render_followup_state(choice_id: String) -> void:
func _build_resolved_followup(index: int, state: Dictionary) -> void:
var content := choice_followup_contents[index]
_build_followup_header(content, state, true, true)
var is_main_correct := bool(state.get("is_main_correct", false))
var body_content := _add_followup_body(content, is_main_correct)
var heading := Label.new()
heading.text = "Why this is appropriate:" if is_main_correct else "Why this is less appropriate:"
_set_scaled_label(heading, 14, Brand.SUCCESS if is_main_correct else Color("fb5f6d"))
body_content.add_child(heading)
var explanation := Label.new()
explanation.text = _choice_review_explanation(str(state.get("choice_id", "")), state)
explanation.text = _strip_verdict_prefix(_choice_review_explanation(str(state.get("choice_id", "")), state))
explanation.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
_set_scaled_label(explanation, 14, Brand.text_color(_followup_is_dark()))
body_content.add_child(explanation)
content.add_child(explanation)
func _build_followup_header(content: VBoxContainer, state: Dictionary, expanded: bool, interactive: bool) -> void:
func _build_followup_header(content: VBoxContainer, state: Dictionary) -> void:
var dark := _followup_is_dark()
var is_main_correct := bool(state.get("is_main_correct", false))
var accent := Brand.SUCCESS if is_main_correct else Color("fb5f6d")
@@ -3317,9 +3277,8 @@ func _build_followup_header(content: VBoxContainer, state: Dictionary, expanded:
row.add_theme_constant_override("separation", 10)
content.add_child(row)
# The choice button above this panel already shows the letter badge, choice
# text, and percentage, so the header only needs a spacer plus the collapse
# toggle - repeating "Review: B. ..." and a status icon here was redundant.
# The choice button above this panel already shows the letter badge and
# choice text, so the header only needs a spacer plus the percentage badge.
var spacer := Control.new()
spacer.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(spacer)
@@ -3334,17 +3293,6 @@ func _build_followup_header(content: VBoxContainer, state: Dictionary, expanded:
_set_scaled_label(percentage_label, 14, accent)
row.add_child(percentage_label)
if interactive:
var toggle := Button.new()
toggle.name = "FollowupToggle"
toggle.flat = true
toggle.tooltip_text = "Collapse review" if expanded else "Expand review"
toggle.icon = preload("res://assets/icons/lucide/chevron-down.svg") if expanded else preload("res://assets/icons/lucide/chevron-right.svg")
toggle.custom_minimum_size = Vector2(34, 30)
toggle.add_theme_color_override("icon_normal_color", Brand.text_color(dark))
toggle.pressed.connect(_toggle_followup_state.bind(str(state.get("choice_id", ""))))
row.add_child(toggle)
func _add_followup_body(content: VBoxContainer, is_correct: bool) -> VBoxContainer:
var body := PanelContainer.new()
@@ -3390,8 +3338,6 @@ func _choice_review_explanation(choice_id: String, state: Dictionary) -> String:
var question := BlockSessionService.get_current_question()
var explanations: Dictionary = question.get("choice_explanations", {})
var explanation := str(explanations.get(choice_id, "")).strip_edges()
if explanation.begins_with("Correct. "):
explanation = explanation.substr(9)
if explanation != "":
return explanation
var teaching_point := str(state.get("teaching_point", "")).strip_edges()
@@ -3403,11 +3349,6 @@ func _choice_review_explanation(choice_id: String, state: Dictionary) -> String:
func _ensure_answer_review_followups() -> void:
for attempted_id in followup_states.keys():
var attempted_state: Dictionary = followup_states[attempted_id]
if bool(attempted_state.get("resolved", false)):
attempted_state["collapsed"] = true
followup_states[attempted_id] = attempted_state
for choice_id in followup_attempt_order:
_render_followup_state(str(choice_id))