Wire flashcard CSV/JSON import/export and fix theme/responsive gaps
Import and export were stubbed with status-text placeholders; wire them to the existing backend endpoints with a real file picker (web JS bridge or native FileDialog) and browser/desktop download, plus an import preview with create/update/skip/error counts before commit. Also fix the library and study screens' theme-refresh handlers, which were no-op stubs so cards never restyled on a theme toggle, and add responsive layout handling for narrow viewports.
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
extends SceneTree
|
||||
|
||||
# Flashcards previously had no coverage for theme switching or narrow-viewport layout: the
|
||||
# library screen's `_refresh_status()` and the study screen's `refresh_theme_controls()` were
|
||||
# both no-op stubs, and neither screen reacted to its own resize. This drives both screens
|
||||
# through a dark/light toggle and a phone-width resize with no network calls (mirrors
|
||||
# flashcard_study_render_test.gd: content is injected directly rather than fetched).
|
||||
|
||||
const Brand := preload("res://scripts/ui/medmind_style.gd")
|
||||
|
||||
var failures := 0
|
||||
|
||||
|
||||
func _initialize() -> void:
|
||||
call_deferred("_run")
|
||||
|
||||
|
||||
func _run() -> void:
|
||||
var host := Control.new()
|
||||
host.size = Vector2(1280, 800)
|
||||
root.add_child(host)
|
||||
|
||||
var theme_service = root.get_node("UIThemeService")
|
||||
var prior_dark: bool = theme_service.is_dark_mode()
|
||||
|
||||
var Hub := load("res://scripts/ui/flashcards_hub.gd")
|
||||
var hub = Hub.new()
|
||||
hub.size = host.size
|
||||
host.add_child(hub)
|
||||
await process_frame
|
||||
|
||||
hub.notes = [{"id": "note-1", "type": "basic", "prompt": "2 + 2", "answer": "4", "tags": []}]
|
||||
|
||||
theme_service.set_dark_mode(true)
|
||||
hub._render_notes()
|
||||
await process_frame
|
||||
var dark_card := hub.list_container.get_child(0) as PanelContainer
|
||||
var dark_box := dark_card.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
_assert(dark_box.bg_color.is_equal_approx(Brand.content_card_box(true, false, Brand.ROYAL_BLUE).bg_color),
|
||||
"flashcard note cards should use the dark surface while dark mode is active")
|
||||
|
||||
theme_service.set_dark_mode(false)
|
||||
await process_frame
|
||||
var light_card := hub.list_container.get_child(0) as PanelContainer
|
||||
var light_box := light_card.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
_assert(light_box.bg_color.is_equal_approx(Brand.content_card_box(false, false, Brand.ROYAL_BLUE).bg_color),
|
||||
"toggling the app theme should rebuild flashcard note cards with the light surface (the library screen's theme_changed handler was previously a no-op)")
|
||||
var light_menu_box := hub.export_menu.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
_assert(light_menu_box.bg_color.is_equal_approx(Brand.panel_box(false).bg_color),
|
||||
"the export menu panel should also restyle to the light surface after a theme toggle")
|
||||
|
||||
theme_service.set_dark_mode(prior_dark)
|
||||
|
||||
hub.size = Vector2(360, 800)
|
||||
hub._update_responsive_layout()
|
||||
await process_frame
|
||||
_assert(hub.compact_layout, "the flashcards library should detect a phone-width viewport")
|
||||
var compact_card := hub.list_container.get_child(0) as PanelContainer
|
||||
var compact_row := compact_card.get_child(0) as BoxContainer
|
||||
_assert(compact_row.vertical, "phone-width flashcard rows should stack their content above the edit/archive actions instead of clipping")
|
||||
_assert(compact_card.get_combined_minimum_size().x <= hub.size.x,
|
||||
"a phone-width flashcard row should fit inside the viewport (minimum %.1f px)" % compact_card.get_combined_minimum_size().x)
|
||||
|
||||
hub.size = Vector2(1280, 800)
|
||||
hub._update_responsive_layout()
|
||||
await process_frame
|
||||
_assert(not hub.compact_layout, "a wide viewport should restore the flashcards library's desktop row layout")
|
||||
var wide_row := (hub.list_container.get_child(0) as PanelContainer).get_child(0) as BoxContainer
|
||||
_assert(not wide_row.vertical, "a wide viewport should lay flashcard row content out horizontally again")
|
||||
|
||||
hub.free()
|
||||
|
||||
var Study := load("res://scripts/ui/flashcards_study.gd")
|
||||
var study = Study.new()
|
||||
study._build()
|
||||
|
||||
theme_service.set_dark_mode(true)
|
||||
study.refresh_theme_controls()
|
||||
var dark_study_box := study.card_panel.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
_assert(dark_study_box.bg_color.is_equal_approx(Brand.content_card_box(true, true, Brand.ROYAL_BLUE).bg_color),
|
||||
"the study card should use the dark active-card surface while dark mode is active")
|
||||
|
||||
theme_service.set_dark_mode(false)
|
||||
study.refresh_theme_controls()
|
||||
var light_study_box := study.card_panel.get_theme_stylebox("panel") as StyleBoxFlat
|
||||
_assert(light_study_box.bg_color.is_equal_approx(Brand.content_card_box(false, true, Brand.ROYAL_BLUE).bg_color),
|
||||
"toggling the app theme should restyle the study card to the light surface (refresh_theme_controls was previously a no-op)")
|
||||
_assert(light_study_box.border_color.is_equal_approx(Brand.ROYAL_BLUE),
|
||||
"the study card should keep its accent border after a theme refresh")
|
||||
|
||||
theme_service.set_dark_mode(prior_dark)
|
||||
|
||||
study.size = Vector2(360, 720)
|
||||
study._update_responsive_layout()
|
||||
_assert(study.compact_layout, "the study screen should detect a phone-width viewport")
|
||||
_assert(study.card_panel.custom_minimum_size.x <= study.size.x,
|
||||
"the study card should shrink to fit a phone-width viewport instead of overflowing (minimum %.1f px on a %.1f px viewport)" % [study.card_panel.custom_minimum_size.x, study.size.x])
|
||||
|
||||
study.size = Vector2(1280, 720)
|
||||
study._update_responsive_layout()
|
||||
_assert(not study.compact_layout, "a wide viewport should restore the study screen's desktop layout")
|
||||
_assert(is_equal_approx(study.card_panel.custom_minimum_size.x, 640.0),
|
||||
"a wide viewport should restore the study card's full 640px width")
|
||||
|
||||
study.free()
|
||||
host.queue_free()
|
||||
await process_frame
|
||||
quit(1 if failures > 0 else 0)
|
||||
|
||||
|
||||
func _assert(condition: bool, message: String) -> void:
|
||||
if condition:
|
||||
return
|
||||
failures += 1
|
||||
push_error(message)
|
||||
Reference in New Issue
Block a user