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.
30 lines
932 B
GDScript
30 lines
932 B
GDScript
extends Control
|
|
|
|
var values: PackedFloat32Array = []
|
|
var accent := Color.WHITE
|
|
var value_range := Vector2(0.0, 100.0)
|
|
|
|
|
|
func set_values(next_values: Array, next_accent: Color, next_range := Vector2(0.0, 100.0)) -> void:
|
|
values = PackedFloat32Array(next_values)
|
|
accent = next_accent
|
|
value_range = next_range
|
|
queue_redraw()
|
|
|
|
|
|
func _draw() -> void:
|
|
if values.size() < 2:
|
|
if values.size() == 1:
|
|
draw_circle(Vector2(size.x - 4.0, size.y * 0.5), 3.0, accent)
|
|
return
|
|
var span: float = maxf(0.0001, value_range.y - value_range.x)
|
|
var points := PackedVector2Array()
|
|
var count: int = values.size()
|
|
for index in range(count):
|
|
var x: float = lerpf(0.0, size.x, float(index) / float(count - 1))
|
|
var ratio: float = clampf((values[index] - value_range.x) / span, 0.0, 1.0)
|
|
var y: float = lerpf(size.y, 0.0, ratio)
|
|
points.append(Vector2(x, y))
|
|
draw_polyline(points, accent, 2.0, true)
|
|
draw_circle(points[-1], 3.0, accent)
|