extends VBoxContainer const Style := preload("res://scripts/ui/ui_style.gd") var main: Control var status_label: Label var daily_label: Label var elo_label: Label var streak_label: Label var bank_label: Label var error_label: Label var begin_button: Button var retry_button: Button func _ready() -> void: set_anchors_preset(Control.PRESET_FULL_RECT) add_theme_constant_override("separation", 18) if not QuestionBankService.questions_changed.is_connected(_refresh): QuestionBankService.questions_changed.connect(_refresh) if not QuestionBankService.ratings_changed.is_connected(_refresh): QuestionBankService.ratings_changed.connect(_refresh) if not ProfileService.profile_changed.is_connected(_refresh): ProfileService.profile_changed.connect(_refresh) var title := Label.new() title.text = "Core Mode" Style.set_label(title, 36, Style.TEXT) add_child(title) var subtitle := Label.new() subtitle.text = "Begin a continuous STEP 3 question run. Keep your energy up, build score, and stay on pace." subtitle.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(subtitle, 17, Style.MUTED) add_child(subtitle) var summary := HBoxContainer.new() summary.add_theme_constant_override("separation", 14) add_child(summary) daily_label = _add_metric(summary, "Today") elo_label = _add_metric(summary, "ELO") streak_label = _add_metric(summary, "Streak") bank_label = _add_metric(summary, "Question Bank") var action_panel := PanelContainer.new() action_panel.add_theme_stylebox_override("panel", Style.panel_box(Color("172337"), Color("405475"))) action_panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL add_child(action_panel) var actions := VBoxContainer.new() actions.add_theme_constant_override("separation", 12) action_panel.add_child(actions) status_label = Label.new() status_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(status_label, 22, Style.CYAN) actions.add_child(status_label) error_label = Label.new() error_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(error_label, 15, Style.RED) actions.add_child(error_label) var button_row := HBoxContainer.new() button_row.add_theme_constant_override("separation", 12) actions.add_child(button_row) begin_button = Button.new() begin_button.text = "Begin" begin_button.custom_minimum_size = Vector2(260, 60) Style.style_primary_button(begin_button) begin_button.pressed.connect(_begin_core_mode) button_row.add_child(begin_button) retry_button = Button.new() retry_button.text = "Retry Questions" retry_button.custom_minimum_size = Vector2(170, 54) Style.style_chip(retry_button, Style.AMBER) retry_button.pressed.connect(QuestionBankService.retry_now) button_row.add_child(retry_button) var spacer := Control.new() spacer.size_flags_vertical = Control.SIZE_EXPAND_FILL add_child(spacer) func on_show(_payload: Variant = null) -> void: if QuestionBankService.load_state == "idle" and AuthState.is_logged_in: QuestionBankService.load_questions_from_api() _refresh() func _add_metric(parent: HBoxContainer, metric_name: String) -> Label: var panel := PanelContainer.new() panel.add_theme_stylebox_override("panel", Style.panel_box(Style.SURFACE, Color("33415c"))) panel.size_flags_horizontal = Control.SIZE_EXPAND_FILL parent.add_child(panel) var label := Label.new() label.text = metric_name label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART Style.set_label(label, 18, Style.TEXT) panel.add_child(label) return label func _refresh() -> void: if daily_label == null: return var profile := ProfileService.get_profile() var answered := int(profile.get("daily_questions_answered", 0)) var goal := int(profile.get("daily_goal_questions", 10)) if goal < 1: goal = 1 var progress := int(round(float(answered) / float(goal) * 100.0)) if progress > 100: progress = 100 daily_label.text = "Today\n%d/%d questions\n%d%% complete" % [answered, goal, progress] elo_label.text = "ELO\n%d overall\n%d rated" % [ QuestionBankService.overall_elo, QuestionBankService.rated_question_count ] streak_label.text = "Streak\n%d current\n%d best" % [ int(profile.get("current_streak", 0)), int(profile.get("best_streak", 0)) ] bank_label.text = "Question Bank\n%d available\n%s" % [ QuestionBankService.get_all_questions().size(), QuestionBankService.load_state.capitalize() ] var state := QuestionBankService.load_state var has_questions := QuestionBankService.has_questions() begin_button.disabled = not has_questions retry_button.disabled = state == "loading" retry_button.visible = state != "ready" error_label.text = "" if state == "ready": status_label.text = BlockSessionService.core_status_message if BlockSessionService.core_status_message != "" else "Question bank ready. Begin core mode when you are ready." elif state == "loading": status_label.text = "Loading question bank..." elif state == "retrying": status_label.text = "Question API unavailable. Retrying in %d seconds." % QuestionBankService.next_retry_seconds error_label.text = QuestionBankService.last_error elif state == "failed": status_label.text = "Question bank is not available." error_label.text = QuestionBankService.last_error else: status_label.text = "Question bank has not loaded yet." func _begin_core_mode() -> void: if not QuestionBankService.has_questions(): return if BlockSessionService.start_core_run(): main.show_screen("player") else: _refresh()