Redesign study navigation and light theme

This commit is contained in:
hz
2026-07-16 02:37:37 -05:00
parent 0eca0c4cbf
commit 6d1787b3eb
57 changed files with 2629 additions and 301 deletions
+92 -1
View File
@@ -6,7 +6,10 @@ var main: Control
var list: VBoxContainer
var status_label: Label
var load_more_button: Button
var launch_button: Button
var readiness_label: Label
var pending_simulation_id := ""
var pending_launch := false
func _ready() -> void:
@@ -14,6 +17,8 @@ func _ready() -> void:
add_theme_constant_override("separation", 12)
if not ExamSimulationService.history_changed.is_connected(_render_history):
ExamSimulationService.history_changed.connect(_render_history)
if not ExamSimulationService.readiness_changed.is_connected(_refresh_readiness):
ExamSimulationService.readiness_changed.connect(_refresh_readiness)
if not ExamSimulationService.state_changed.is_connected(_on_simulation_loaded):
ExamSimulationService.state_changed.connect(_on_simulation_loaded)
if not ExamSimulationService.request_failed.is_connected(_on_request_failed):
@@ -34,6 +39,32 @@ func _ready() -> void:
var balance := Control.new()
balance.custom_minimum_size = Vector2(100, 0)
top.add_child(balance)
var launch_panel := PanelContainer.new()
launch_panel.add_theme_stylebox_override("panel", Style.panel_box(Color("07192c"), Style.CYAN))
add_child(launch_panel)
var launch_content := HBoxContainer.new()
launch_content.add_theme_constant_override("separation", 18)
launch_panel.add_child(launch_content)
var launch_copy := VBoxContainer.new()
launch_copy.size_flags_horizontal = Control.SIZE_EXPAND_FILL
launch_copy.add_theme_constant_override("separation", 5)
launch_content.add_child(launch_copy)
var launch_title := Label.new()
launch_title.text = "Step 3 Day 1 Simulation"
Style.set_label(launch_title, 22, Style.TEXT)
launch_copy.add_child(launch_title)
readiness_label = Label.new()
readiness_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
Style.set_label(readiness_label, 15, Style.MUTED)
launch_copy.add_child(readiness_label)
launch_button = Button.new()
launch_button.text = "Checking readiness..."
launch_button.custom_minimum_size = Vector2(210, 48)
launch_button.size_flags_vertical = Control.SIZE_SHRINK_CENTER
launch_button.disabled = true
Style.style_primary_button(launch_button)
launch_button.pressed.connect(_launch_or_resume)
launch_content.add_child(launch_button)
status_label = Label.new()
status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
Style.set_label(status_label, 16, Style.MUTED)
@@ -57,6 +88,9 @@ func _ready() -> void:
func on_show(payload: Variant = null) -> void:
pending_simulation_id = ""
pending_launch = false
_refresh_readiness()
ExamSimulationService.load_readiness()
if str(payload) == "preserve" and not ExamSimulationService.history.is_empty():
return
status_label.text = "Loading simulation history..."
@@ -104,15 +138,26 @@ func _summary_text(summary: Dictionary) -> String:
func _open_simulation(simulation_id: String) -> void:
pending_launch = false
pending_simulation_id = simulation_id
status_label.text = "Opening simulation..."
ExamSimulationService.load_simulation(simulation_id)
func _on_simulation_loaded() -> void:
if not visible or pending_simulation_id.is_empty() or ExamSimulationService.simulation.is_empty():
if not visible or ExamSimulationService.simulation.is_empty():
return
if pending_launch:
pending_launch = false
_route_loaded_simulation()
return
if pending_simulation_id.is_empty():
return
pending_simulation_id = ""
_route_loaded_simulation()
func _route_loaded_simulation() -> void:
var state := str(ExamSimulationService.simulation.get("state", ""))
if state == "completed":
main.show_screen("simulation_results", {"simulation": ExamSimulationService.simulation, "return_screen": "simulation_history"})
@@ -128,6 +173,42 @@ func _on_simulation_loaded() -> void:
main.show_screen("simulation_break")
else:
status_label.text = "This simulation can no longer be resumed."
_refresh_readiness()
func _launch_or_resume() -> void:
pending_launch = true
pending_simulation_id = ""
launch_button.disabled = true
readiness_label.text = "Opening your simulation..."
if _has_active_simulation():
ExamSimulationService.load_active()
else:
ExamSimulationService.create_simulation()
func _refresh_readiness() -> void:
if launch_button == null:
return
var simulation_ready := bool(ExamSimulationService.readiness.get("ready", false))
var active := _has_active_simulation()
var available := int(ExamSimulationService.readiness.get("availableQuestions", 0))
launch_button.text = "Resume Simulation" if active else "Start Simulation"
launch_button.disabled = pending_launch or (not simulation_ready and not active)
if pending_launch:
readiness_label.text = "Opening your simulation..."
elif active:
readiness_label.text = "Your progress is saved between blocks. Resume where you left off."
elif simulation_ready:
readiness_label.text = "Full-length, 12-block simulation with a provisional predicted score."
else:
readiness_label.text = "Unlocks when 232 published questions are available. Currently %d/232." % available
func _has_active_simulation() -> bool:
return has_active_simulation(
ExamSimulationService.readiness,
ExamSimulationService.simulation)
func _load_more() -> void:
@@ -138,9 +219,11 @@ func _load_more() -> void:
func _on_request_failed(message: String) -> void:
if not visible:
return
pending_launch = false
pending_simulation_id = ""
status_label.text = message
load_more_button.disabled = false
_refresh_readiness()
static func _action_for_state(state: String) -> String:
@@ -153,3 +236,11 @@ static func _state_color(state: String) -> Color:
if state == "completed": return Style.LIME
if state == "block_active" or state == "between_blocks": return Style.CYAN
return Style.MUTED
static func has_active_simulation(readiness: Dictionary, simulation: Dictionary) -> bool:
if bool(readiness.get("hasActiveSimulation", false)):
return true
if simulation.is_empty():
return false
return str(simulation.get("state", "")) in ["between_blocks", "block_active"]