Files
step3/scripts/ui/flashcard_prefill_dialog.gd
T
hz 48f404518f Fix GDScript editor warnings (shadowed vars, unused param, integer division)
Renames locals/params that shadowed base-class properties (Node.name,
Control.size, BoxContainer.alignment), prefixes an intentionally-unused
parameter, and annotates a deliberate integer division so the console
stays clean during development.
2026-07-23 14:30:48 -05:00

179 lines
5.5 KiB
GDScript

extends Control
# Prefilled basic-card editor opened from the question toolbar once a question's answer has
# been resolved. Saving creates a new flashcard note in the user's default deck; the user can
# move/retag it from the flashcards library afterward.
const Brand := preload("res://scripts/ui/medmind_style.gd")
const Style := preload("res://scripts/ui/ui_style.gd")
signal saved
var front_input: TextEdit
var back_input: TextEdit
var tags_input: LineEdit
var image_checkbox: CheckBox
var error_label: Label
var save_button: Button
var pending_image_asset_id := ""
var source_question_external_id := ""
func _ready() -> void:
visible = false
top_level = true
mouse_filter = Control.MOUSE_FILTER_STOP
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
var dim := ColorRect.new()
dim.color = Color(0, 0, 0, 0.72)
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
dim.gui_input.connect(func(event: InputEvent):
if event is InputEventMouseButton and event.pressed:
hide_dialog())
add_child(dim)
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(center)
var panel := PanelContainer.new()
panel.custom_minimum_size = Vector2(600, 520)
panel.add_theme_stylebox_override("panel", Brand.panel_box(UIThemeService.is_dark_mode()))
center.add_child(panel)
var content := VBoxContainer.new()
content.add_theme_constant_override("separation", 10)
panel.add_child(content)
var header := HBoxContainer.new()
content.add_child(header)
var title := Label.new()
title.text = "Save as flashcard"
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
title.add_theme_font_size_override("font_size", 22)
header.add_child(title)
var close_button := Button.new()
close_button.icon = preload("res://assets/icons/lucide/x.svg")
close_button.custom_minimum_size = Vector2(40, 40)
close_button.pressed.connect(hide_dialog)
header.add_child(close_button)
content.add_child(_field_label("Front"))
front_input = TextEdit.new()
front_input.custom_minimum_size = Vector2(0, 110)
front_input.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY
content.add_child(front_input)
content.add_child(_field_label("Back"))
back_input = TextEdit.new()
back_input.custom_minimum_size = Vector2(0, 140)
back_input.wrap_mode = TextEdit.LINE_WRAPPING_BOUNDARY
content.add_child(back_input)
content.add_child(_field_label("Tags (comma separated)"))
tags_input = LineEdit.new()
content.add_child(tags_input)
image_checkbox = CheckBox.new()
image_checkbox.text = "Attach question image"
image_checkbox.visible = false
content.add_child(image_checkbox)
error_label = Label.new()
error_label.add_theme_color_override("font_color", Style.RED)
error_label.visible = false
content.add_child(error_label)
save_button = Button.new()
save_button.text = "Save Flashcard"
save_button.custom_minimum_size = Vector2(0, 48)
Style.style_primary_button(save_button)
save_button.pressed.connect(_save)
content.add_child(save_button)
FlashcardService.note_saved.connect(_on_saved)
FlashcardService.request_failed.connect(_on_failed)
func _field_label(text: String) -> Label:
var label := Label.new()
label.text = text
label.add_theme_font_size_override("font_size", 13)
return label
func open_for_question(question: Dictionary, _current_answer: Dictionary) -> void:
var stem := str(question.get("stem", "")).strip_edges()
var lead_in := str(question.get("lead_in", "")).strip_edges()
front_input.text = "%s\n\n%s" % [stem, lead_in] if not lead_in.is_empty() else stem
var choices: Array = question.get("choices", [])
var correct_id := str(question.get("correct_choice_id", ""))
var correct_text := ""
for choice in choices:
if str(choice.get("id", "")) == correct_id:
correct_text = str(choice.get("text", ""))
break
var takeaway := str(question.get("key_takeaway", "")).strip_edges()
if takeaway.is_empty():
takeaway = str(question.get("explanation", "")).strip_edges()
back_input.text = "%s\n\n%s" % [correct_text, takeaway] if not takeaway.is_empty() else correct_text
var tags: Array = []
var system := str(question.get("system", "")).strip_edges()
if not system.is_empty():
tags.append(system)
for tag in question.get("tags", []):
var trimmed := str(tag).strip_edges()
if not trimmed.is_empty() and not tags.has(trimmed):
tags.append(trimmed)
tags_input.text = ", ".join(PackedStringArray(tags))
var media: Array = question.get("media", [])
pending_image_asset_id = str(media[0]) if media.size() > 0 else ""
image_checkbox.visible = not pending_image_asset_id.is_empty()
image_checkbox.button_pressed = false
source_question_external_id = str(question.get("id", ""))
error_label.visible = false
visible = true
func hide_dialog() -> void:
visible = false
func _save() -> void:
var tags: Array = []
for tag in tags_input.text.split(","):
var trimmed := tag.strip_edges()
if not trimmed.is_empty():
tags.append(trimmed)
var images: Array = []
if image_checkbox.button_pressed and not pending_image_asset_id.is_empty():
images.append({"kind": "question", "assetId": pending_image_asset_id})
var payload := {
"deckId": "",
"stableId": "",
"type": "basic",
"prompt": front_input.text,
"answer": back_input.text,
"extra": "",
"tags": tags,
"images": images,
"sourceQuestionExternalId": source_question_external_id,
"expectedRevision": null
}
FlashcardService.save_note("", payload)
func _on_saved(_note: Dictionary) -> void:
if not visible:
return
hide_dialog()
saved.emit()
func _on_failed(_tag: String, message: String) -> void:
if not visible:
return
error_label.text = message
error_label.visible = true