Add flashcards feature with spaced repetition scheduling
Adds a full flashcards system: FSRS-based scheduling, cloze/basic card types, CSV import/export, media storage, and study UI, wired into navigation and the dashboard alongside existing question flows.
This commit is contained in:
@@ -2,6 +2,7 @@ extends VBoxContainer
|
||||
|
||||
const Style := preload("res://scripts/ui/ui_style.gd")
|
||||
const Brand := preload("res://scripts/ui/medmind_style.gd")
|
||||
const FlashcardPrefillDialog := preload("res://scripts/ui/flashcard_prefill_dialog.gd")
|
||||
const CLEAR_HIGHLIGHT_DARK_ICON := preload("res://assets/icons/medmind/clear-highlight-dark.svg")
|
||||
const CLEAR_HIGHLIGHT_LIGHT_ICON := preload("res://assets/icons/medmind/clear-highlight-light.svg")
|
||||
const LABS_DARK_ICON := preload("res://assets/icons/medmind/labs-dark.svg")
|
||||
@@ -84,6 +85,8 @@ var clear_highlight_button: Button
|
||||
var flag_button: Button
|
||||
var report_button: Button
|
||||
var notes_button: Button
|
||||
var flashcard_button: Button
|
||||
var flashcard_prefill_dialog: Control
|
||||
var bookmark_button: Button
|
||||
var app_feedback_button: Button
|
||||
var theme_button: Button
|
||||
@@ -280,6 +283,22 @@ func _ready() -> void:
|
||||
)
|
||||
question_toolbar.add_child(flag_button)
|
||||
|
||||
flashcard_button = Button.new()
|
||||
flashcard_button.tooltip_text = "Save as flashcard (available once answered)"
|
||||
flashcard_button.icon = preload("res://assets/icons/lucide/clipboard-plus.svg")
|
||||
flashcard_button.custom_minimum_size = Vector2(44, 44)
|
||||
flashcard_button.add_theme_constant_override("icon_max_width", 22)
|
||||
flashcard_button.alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
flashcard_button.icon_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
flashcard_button.focus_mode = Control.FOCUS_NONE
|
||||
flashcard_button.disabled = true
|
||||
UISoundService.set_button_sound(flashcard_button, "toggle")
|
||||
flashcard_button.pressed.connect(_toggle_flashcard_current_question)
|
||||
question_toolbar.add_child(flashcard_button)
|
||||
flashcard_prefill_dialog = FlashcardPrefillDialog.new()
|
||||
flashcard_prefill_dialog.name = "FlashcardPrefillDialog"
|
||||
add_child(flashcard_prefill_dialog)
|
||||
|
||||
bookmark_button = Button.new()
|
||||
bookmark_button.tooltip_text = "Save question"
|
||||
bookmark_button.icon = preload("res://assets/icons/lucide/bookmark.svg")
|
||||
@@ -865,7 +884,7 @@ func _apply_question_theme() -> void:
|
||||
var navigator_heading := navigator_popup.find_child("NavigatorHeading", true, false) as Label
|
||||
if navigator_heading != null:
|
||||
navigator_heading.add_theme_color_override("font_color", Brand.text_color(dark))
|
||||
for control in [text_smaller_button, text_larger_button, flag_button, bookmark_button, notes_button, app_feedback_button]:
|
||||
for control in [text_smaller_button, text_larger_button, flag_button, bookmark_button, notes_button, flashcard_button, app_feedback_button]:
|
||||
if control == null:
|
||||
continue
|
||||
var active: bool = (control == flag_button and flagged) or (control == bookmark_button and BookmarkService.is_bookmarked(str(BlockSessionService.get_current_question().get("id", ""))))
|
||||
@@ -1423,6 +1442,7 @@ func _show_answer_review() -> void:
|
||||
skip_button.disabled = false if BlockSessionService.session_kind == "bookmark" else true
|
||||
if question_scroll != null:
|
||||
question_scroll.call_deferred("ensure_control_visible", explanation_label)
|
||||
_refresh_toolbar_state()
|
||||
|
||||
|
||||
func _set_answer_review_timer_visibility() -> void:
|
||||
@@ -1969,6 +1989,9 @@ func _refresh_toolbar_state() -> void:
|
||||
report_button.tooltip_text = "Report submitted; report another issue" if reported_question_ids.has(question_id) else "Report question"
|
||||
if notes_button != null:
|
||||
notes_button.visible = BlockSessionService.session_kind != "simulation"
|
||||
if flashcard_button != null:
|
||||
flashcard_button.visible = BlockSessionService.session_kind != "simulation"
|
||||
flashcard_button.disabled = current_answer.is_empty()
|
||||
if bookmark_button != null:
|
||||
bookmark_button.visible = BlockSessionService.session_kind != "simulation"
|
||||
var bookmark_question_id := str(BlockSessionService.get_current_question().get("id", ""))
|
||||
@@ -1984,6 +2007,15 @@ func _toggle_bookmark_current_question() -> void:
|
||||
BookmarkService.toggle_question(question)
|
||||
|
||||
|
||||
func _toggle_flashcard_current_question() -> void:
|
||||
if current_answer.is_empty():
|
||||
return
|
||||
var question := BlockSessionService.get_current_question()
|
||||
if question.is_empty() or flashcard_prefill_dialog == null:
|
||||
return
|
||||
flashcard_prefill_dialog.open_for_question(question, current_answer)
|
||||
|
||||
|
||||
func _on_bookmark_status_changed(question_id: String, value: bool, pending: bool) -> void:
|
||||
if question_id != str(BlockSessionService.get_current_question().get("id", "")) or bookmark_button == null:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user