diff --git a/scripts/ui/question_player.gd b/scripts/ui/question_player.gd index d3e04ae..9aa0b38 100644 --- a/scripts/ui/question_player.gd +++ b/scripts/ui/question_player.gd @@ -73,10 +73,7 @@ var correct_review_panel: PanelContainer var teaching_cards: HFlowContainer var review_followups_section: VBoxContainer var review_followups_content: VBoxContainer -var wrong_options_section: VBoxContainer -var wrong_options_content: VBoxContainer var review_followup_states: Array = [] -var wrong_option_expanded := {} var question_scroll: ScrollContainer var question_elo_label: Label var next_button: Button @@ -635,19 +632,6 @@ func _build_answer_review_ui() -> void: review_followups_content.add_theme_constant_override("separation", 8) review_followups_section.add_child(review_followups_content) - wrong_options_section = VBoxContainer.new() - wrong_options_section.visible = false - wrong_options_section.add_theme_constant_override("separation", 8) - question_content.add_child(wrong_options_section) - var wrong_options_heading := Label.new() - wrong_options_heading.text = "WHY OTHER OPTIONS ARE INCORRECT" - wrong_options_heading.name = "WrongOptionsHeading" - _set_scaled_label(wrong_options_heading, 15, Brand.text_color(true)) - wrong_options_section.add_child(wrong_options_heading) - wrong_options_content = VBoxContainer.new() - wrong_options_content.add_theme_constant_override("separation", 6) - wrong_options_section.add_child(wrong_options_content) - func _fit_modal_panels() -> void: var available := get_viewport_rect().size - Vector2(32, 32) @@ -875,19 +859,6 @@ func _review_followup_box(_dark: bool, accent: Color, answered: bool) -> StyleBo return box -func _wrong_option_box(dark: bool) -> StyleBoxFlat: - var box := StyleBoxFlat.new() - box.bg_color = Color("0b172b") if dark else Color("ffffff") - box.border_color = Color("2b3958") if dark else Brand.LIGHT_BORDER - box.set_border_width_all(1) - box.set_corner_radius_all(6) - box.content_margin_left = 10 - box.content_margin_right = 10 - box.content_margin_top = 6 - box.content_margin_bottom = 6 - return box - - func _style_review_followup_option(button: Button, dark: bool, option_id: String, selected_id: String, correct_id: String, answered: bool) -> void: var state := "default" if answered and option_id == correct_id: @@ -929,9 +900,6 @@ func _apply_question_theme() -> void: var review_followup_subtitle := find_child("ReviewFollowupSubtitle", true, false) as Label if review_followup_subtitle != null: review_followup_subtitle.add_theme_color_override("font_color", Brand.muted_color(dark)) - var wrong_options_heading := find_child("WrongOptionsHeading", true, false) as Label - if wrong_options_heading != null: - wrong_options_heading.add_theme_color_override("font_color", Brand.text_color(dark)) if correct_review_panel != null: correct_review_panel.add_theme_stylebox_override("panel", _correct_review_panel_box(dark)) question_elo_label.add_theme_color_override("font_color", Brand.AMBER) @@ -975,7 +943,7 @@ func _apply_question_theme() -> void: if correct_review_panel != null and correct_review_panel.visible: _render_teaching_cards() _render_review_followups() - _render_wrong_option_reviews() + _render_unselected_distractor_explanations() func on_show(_payload: Variant = null) -> void: @@ -1542,7 +1510,7 @@ func _dock_correct_review_panel(correct_id: String) -> void: func _render_answer_review_sections() -> void: _render_teaching_cards() _render_review_followups() - _render_wrong_option_reviews() + _render_unselected_distractor_explanations() func _clear_answer_review() -> void: @@ -1552,13 +1520,9 @@ func _clear_answer_review() -> void: correct_review_panel.visible = false _clear_container_children(teaching_cards) _clear_container_children(review_followups_content) - _clear_container_children(wrong_options_content) review_followup_states.clear() - wrong_option_expanded.clear() if review_followups_section != null: review_followups_section.visible = false - if wrong_options_section != null: - wrong_options_section.visible = false _update_content_vertical_alignment() @@ -1699,58 +1663,53 @@ func _answer_review_followup(index: int, choice_id: String) -> void: _render_review_followups() -func _render_wrong_option_reviews() -> void: - if wrong_options_content == null: - return - _clear_container_children(wrong_options_content) +func _render_unselected_distractor_explanations() -> void: + # Choices the user never picked (so never triggered the wrong-answer + # follow-up quiz) still need their "why incorrect" explanation shown - + # nest it directly in that choice's own card instead of a repeated + # aggregate list at the bottom. Choices that DID trigger a follow-up + # already show this same explanation inside the resolved quiz view. var question := BlockSessionService.get_current_question() var correct_id := str(question.get("correct_choice_id", "")) - var explanations: Dictionary = question.get("choice_explanations", {}) - var incorrect_count := 0 - for choice in _get_presented_choices(): + var choices := _get_presented_choices() + for index in range(choices.size()): + if index >= choice_followup_panels.size(): + continue + var choice: Dictionary = choices[index] if typeof(choice) != TYPE_DICTIONARY: continue var choice_id := str(choice.get("id", "")) - if choice_id == correct_id: + if choice_id == "" or choice_id == correct_id or followup_states.has(choice_id): continue - incorrect_count += 1 - _add_wrong_option_review(choice, str(explanations.get(choice_id, ""))) - wrong_options_section.visible = incorrect_count > 0 + _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.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART + _set_scaled_label(explanation, 14, Brand.text_color(_followup_is_dark())) + body_content.add_child(explanation) + choice_followup_panels[index].add_theme_stylebox_override( + "panel", + _attached_panel_box(_followup_is_dark(), Color("fb7185")) + ) + choice_followup_panels[index].visible = true + _style_choice_button_for_state(index, choice_id) -func _add_wrong_option_review(choice: Dictionary, explanation: String) -> void: - var dark := _followup_is_dark() - var choice_id := str(choice.get("id", "")) - var expanded := bool(wrong_option_expanded.get(choice_id, false)) - var card := PanelContainer.new() - card.add_theme_stylebox_override("panel", _wrong_option_box(dark)) - wrong_options_content.add_child(card) - var content := VBoxContainer.new() - content.add_theme_constant_override("separation", 6) - card.add_child(content) - var header := Button.new() - header.flat = true - header.alignment = HORIZONTAL_ALIGNMENT_LEFT - header.text = "%s. %s" % [_display_label_for_choice_id(choice_id), str(choice.get("text", ""))] - header.icon = preload("res://assets/icons/lucide/chevron-down.svg") if expanded else preload("res://assets/icons/lucide/chevron-right.svg") - header.icon_alignment = HORIZONTAL_ALIGNMENT_RIGHT - header.expand_icon = false - header.add_theme_color_override("font_color", Brand.text_color(dark)) - header.add_theme_color_override("icon_normal_color", Brand.muted_color(dark)) - _set_scaled_button_font(header, 14) - header.pressed.connect(_toggle_wrong_option_review.bind(choice_id)) - content.add_child(header) - if expanded: - var detail := Label.new() - detail.text = explanation - detail.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART - _set_scaled_label(detail, 14, Brand.muted_color(dark)) - content.add_child(detail) - - -func _toggle_wrong_option_review(choice_id: String) -> void: - wrong_option_expanded[choice_id] = not bool(wrong_option_expanded.get(choice_id, false)) - _render_wrong_option_reviews() +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: