Add freemium access economy and token store

This commit is contained in:
hz
2026-07-27 22:20:21 -05:00
parent 1d5d03a4f6
commit 4bbac27b84
40 changed files with 1807 additions and 37 deletions
+16 -2
View File
@@ -137,6 +137,8 @@ func _connect_services() -> void:
ExamSimulationService.state_changed.connect(_on_simulation_loaded)
if not ExamSimulationService.request_failed.is_connected(_on_request_failed):
ExamSimulationService.request_failed.connect(_on_request_failed)
if not AccessService.status_changed.is_connected(_on_access_changed):
AccessService.status_changed.connect(_on_access_changed)
func on_show(_payload: Variant = null) -> void:
@@ -147,6 +149,7 @@ func on_show(_payload: Variant = null) -> void:
load_more_button.disabled = true
ExamSimulationService.load_readiness()
ExamSimulationService.load_active()
AccessService.refresh()
_load_history_page()
@@ -223,7 +226,8 @@ func _render_active_section() -> void:
card_layout.add_child(actions)
var primary := Button.new()
primary.name = "PrimarySimulationAction"
primary.text = "Resume Simulation" if active else "Start Simulation"
var has_exam_token := int(AccessService.status.get("examTokens", 0)) > 0
primary.text = "Resume Simulation" if active else ("Start Simulation" if has_exam_token else "Get Exam Token")
primary.custom_minimum_size = Vector2(0, 48)
primary.disabled = pending_launch or (not active and not bool(ExamSimulationService.readiness.get("ready", false)))
_style_gradient_button(primary)
@@ -452,6 +456,7 @@ func _on_simulation_loaded() -> void:
return
if pending_launch:
pending_launch = false
AccessService.refresh()
_route_loaded_simulation()
return
if not pending_simulation_id.is_empty():
@@ -483,6 +488,9 @@ func _route_loaded_simulation() -> void:
func _launch_or_resume() -> void:
if not _has_active_simulation() and int(AccessService.status.get("examTokens", 0)) <= 0:
main.show_screen("access_store")
return
pending_launch = true
pending_simulation_id = ""
_render_active_section()
@@ -538,6 +546,11 @@ func _on_request_failed(message: String) -> void:
_render_active_section()
func _on_access_changed(_status: Dictionary) -> void:
if visible:
_render_active_section()
func _update_responsive_layout() -> void:
var use_compact := size.x < 940
if compact_layout == use_compact:
@@ -564,7 +577,8 @@ func _active_history_summary() -> Dictionary:
func _readiness_message() -> String:
if bool(ExamSimulationService.readiness.get("ready", false)):
return "The question bank is ready. Start when you have enough uninterrupted time for a full simulation."
var tokens := int(AccessService.status.get("examTokens", 0))
return "Exam tokens available: %d. One token is consumed when a new simulation is created." % tokens
var available := int(ExamSimulationService.readiness.get("availableQuestions", 0))
var required := int(ExamSimulationService.readiness.get("requiredQuestions", 232))
return "Simulation unlocks when %d published questions are available. Currently %d/%d." % [required, available, required]