Frontend half of the dashboard stat-card redesign, matching the provided mockup. The 4 metrics used to be plain rows sharing one bordered box (_add_metric -> a single metric_grid inside one _card). Replaced with 4 independently-_card-wrapped panels in a responsive GridContainer (4 cols / 2 compact, same threshold _update_responsive already used). Each card now has: a colored icon badge, title + info glyph, a big value, a colored trend/status line, a small visual, and a footer caption: - Question Bank Rating / CCS Rating: a new minimal DashboardSparkline (dashboard_sparkline.gd) fed from the current rating and the week-ago snapshot (reconstructed client-side from the delta the API already returns - no separate history endpoint needed). Trend line and caption come from the new delta/percentile fields; both degrade to a plain single-point sparkline and a rated-count caption when no snapshot exists yet. - Exam Readiness: a new DashboardSegmentBar (dashboard_segment_bar.gd - nothing like a segmented pill progress indicator existed anywhere in the codebase) instead of a sparkline, colored by the High/Medium/Low label; shows a neutral "complete a simulation" state when the user has none yet rather than a fabricated readiness. - Average Score: reuses the existing ProgressBar/_style_progress, relabeled from "First-Attempt Accuracy". Dropped the old "Study Time" card (not part of the mockup - the underlying data still drives the weekly activity chart below, it just no longer gets a dedicated top-line number) and the now-fully-unused _format_duration. Verified headlessly: instantiated the real screen against fake DashboardService data, confirmed every card's value/trend/caption text and the segment-bar/progress-bar values match the mockup exactly, and rendered actual screenshots of both the populated and "no data yet" fallback states.
35 lines
1.1 KiB
GDScript
35 lines
1.1 KiB
GDScript
extends Control
|
|
|
|
const Brand := preload("res://scripts/ui/medmind_style.gd")
|
|
const GAP := 6.0
|
|
const CORNER_RADIUS := 4
|
|
|
|
var filled_segments := 0
|
|
var total_segments := 4
|
|
var accent := Color.WHITE
|
|
var dark := true
|
|
|
|
|
|
func set_progress(next_filled: int, next_total: int, next_accent: Color, dark_mode: bool) -> void:
|
|
filled_segments = next_filled
|
|
total_segments = maxi(1, next_total)
|
|
accent = next_accent
|
|
dark = dark_mode
|
|
queue_redraw()
|
|
|
|
|
|
func _draw() -> void:
|
|
var segment_width: float = (size.x - GAP * float(total_segments - 1)) / float(total_segments)
|
|
if segment_width <= 0.0:
|
|
return
|
|
var filled_box := StyleBoxFlat.new()
|
|
filled_box.bg_color = accent
|
|
filled_box.set_corner_radius_all(CORNER_RADIUS)
|
|
var track_box := StyleBoxFlat.new()
|
|
track_box.bg_color = Brand.muted_color(dark).lerp(Brand.background_color(dark), 0.5)
|
|
track_box.set_corner_radius_all(CORNER_RADIUS)
|
|
for index in range(total_segments):
|
|
var x: float = index * (segment_width + GAP)
|
|
var rect := Rect2(x, 0.0, segment_width, size.y)
|
|
draw_style_box(filled_box if index < filled_segments else track_box, rect)
|