Add clinical progression ranks and records
This commit is contained in:
@@ -553,6 +553,9 @@ func _apply_first_attempt_response(parsed: Dictionary) -> void:
|
||||
_apply_rating_change(rating)
|
||||
CreditsService.apply_award_response(parsed)
|
||||
DailyMissionService.apply_response(parsed)
|
||||
if typeof(parsed.get("progression")) == TYPE_DICTIONARY:
|
||||
DashboardService.data["progression"] = parsed.get("progression")
|
||||
DashboardService.dashboard_changed.emit()
|
||||
# Let Tutor users inspect the final answer before the summary replaces the player.
|
||||
StudySessionService.apply_response(parsed, true)
|
||||
choice_percentages_updated.emit(question_id, percentages)
|
||||
@@ -560,6 +563,9 @@ func _apply_first_attempt_response(parsed: Dictionary) -> void:
|
||||
|
||||
|
||||
func _apply_skip_response(parsed: Dictionary) -> void:
|
||||
if typeof(parsed.get("progression")) == TYPE_DICTIONARY:
|
||||
DashboardService.data["progression"] = parsed.get("progression")
|
||||
DashboardService.dashboard_changed.emit()
|
||||
var question_id := str(parsed.get("questionExternalId", parsed.get("question_external_id", "")))
|
||||
var correct_choice_id := str(parsed.get("correctChoiceId", parsed.get("correct_choice_id", "")))
|
||||
var percentages: Dictionary = parsed.get("choiceSelectionPercentages", parsed.get("choice_selection_percentages", {}))
|
||||
|
||||
@@ -199,6 +199,9 @@ func _on_attempt_completed(result: int, response_code: int, _headers_value: Pack
|
||||
if typeof(parsed) == TYPE_DICTIONARY:
|
||||
CreditsService.apply_award_response(parsed)
|
||||
DailyMissionService.apply_response(parsed)
|
||||
if typeof(parsed.get("progression")) == TYPE_DICTIONARY:
|
||||
DashboardService.data["progression"] = parsed.get("progression")
|
||||
DashboardService.dashboard_changed.emit()
|
||||
StudySessionService.apply_response(parsed, true)
|
||||
pending_count = int(parsed.get("pendingCount", parsed.get("pending_count", pending_count)))
|
||||
synced_question_id = str(parsed.get("questionExternalId", parsed.get("question_external_id", "")))
|
||||
|
||||
@@ -25,6 +25,7 @@ var recent_list: VBoxContainer
|
||||
var weekly_summary: VBoxContainer
|
||||
var mission_content: VBoxContainer
|
||||
var weekly_goal_content: VBoxContainer
|
||||
var rank_content: VBoxContainer
|
||||
var metric_values: Dictionary = {}
|
||||
var metric_details: Dictionary = {}
|
||||
var metric_trends: Dictionary = {}
|
||||
@@ -165,6 +166,9 @@ func _build() -> void:
|
||||
right_column.add_theme_constant_override("separation", 12)
|
||||
right_column.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
analytics_grid.add_child(right_column)
|
||||
rank_content = VBoxContainer.new()
|
||||
rank_content.add_theme_constant_override("separation", 9)
|
||||
right_column.add_child(_card(rank_content, 16))
|
||||
focus_content = VBoxContainer.new()
|
||||
focus_content.add_theme_constant_override("separation", 10)
|
||||
right_column.add_child(_card(focus_content, 16))
|
||||
@@ -224,6 +228,7 @@ func _render() -> void:
|
||||
_render_systems(data.get("systems", []))
|
||||
_render_focus(data.get("systems", []))
|
||||
_render_review(data)
|
||||
_render_rank(data.get("progression", {}))
|
||||
var weekly: Array = data.get("weeklyActivity", [])
|
||||
activity_chart.set_days(weekly, UIThemeService.is_dark_mode())
|
||||
_render_weekly(data, weekly)
|
||||
@@ -232,6 +237,40 @@ func _render() -> void:
|
||||
_render_weekly_goal()
|
||||
|
||||
|
||||
func _render_rank(value: Variant) -> void:
|
||||
if rank_content == null:
|
||||
return
|
||||
_clear(rank_content)
|
||||
rank_content.add_child(_section_title("Clinical progression"))
|
||||
var progression: Dictionary = value if typeof(value) == TYPE_DICTIONARY else {}
|
||||
if progression.is_empty():
|
||||
rank_content.add_child(_label("Loading rank progress...", 13, Brand.muted_color(UIThemeService.is_dark_mode())))
|
||||
return
|
||||
var title := _label(str(progression.get("displayName", "Case Scout III")), 23, Brand.PURPLE, true)
|
||||
rank_content.add_child(title)
|
||||
var next_name = progression.get("nextRankName")
|
||||
if next_name == null:
|
||||
rank_content.add_child(_label("Highest division earned", 12, Brand.SUCCESS, true))
|
||||
else:
|
||||
rank_content.add_child(_label("Next: %s %s" % [str(next_name), str(progression.get("nextDivision", ""))], 12, Brand.muted_color(UIThemeService.is_dark_mode())))
|
||||
var requirements: Array = progression.get("nextRequirements", [])
|
||||
for requirement_value in requirements.slice(0, mini(3, requirements.size())):
|
||||
var requirement: Dictionary = requirement_value
|
||||
var row := HBoxContainer.new()
|
||||
var label := _label(str(requirement.get("label", "Progress")), 11, Brand.text_color(UIThemeService.is_dark_mode()))
|
||||
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(label)
|
||||
row.add_child(_label("%d / %d" % [int(requirement.get("current", 0)), int(requirement.get("required", 0))], 11,
|
||||
Brand.SUCCESS if bool(requirement.get("complete", false)) else Brand.ROYAL_BLUE, true))
|
||||
rank_content.add_child(row)
|
||||
var view := Button.new()
|
||||
view.text = "View ladder and records"
|
||||
view.flat = true
|
||||
view.alignment = HORIZONTAL_ALIGNMENT_LEFT
|
||||
view.pressed.connect(func(): main.show_screen("profile"))
|
||||
rank_content.add_child(view)
|
||||
|
||||
|
||||
func _render_missions() -> void:
|
||||
if mission_content == null:
|
||||
return
|
||||
|
||||
@@ -21,6 +21,7 @@ var outcome_delete: Button
|
||||
var connected_accounts_list: VBoxContainer
|
||||
var return_screen := ""
|
||||
var back_to_session_button: Button
|
||||
var progression_content: VBoxContainer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -95,6 +96,7 @@ func _build() -> void:
|
||||
right.add_theme_constant_override("separation", 14)
|
||||
columns.add_child(right)
|
||||
right.add_child(_outcome_card())
|
||||
right.add_child(_progression_card())
|
||||
right.add_child(_connected_accounts_card())
|
||||
right.add_child(_account_actions_card())
|
||||
_refresh_back_to_session_visibility()
|
||||
@@ -227,6 +229,13 @@ func _outcome_card() -> PanelContainer:
|
||||
return _card(body)
|
||||
|
||||
|
||||
func _progression_card() -> PanelContainer:
|
||||
progression_content = VBoxContainer.new()
|
||||
progression_content.add_theme_constant_override("separation", 10)
|
||||
progression_content.add_child(_section_header("Clinical Progression", "Breadth, challenge, and retention"))
|
||||
return _card(progression_content)
|
||||
|
||||
|
||||
func _account_actions_card() -> PanelContainer:
|
||||
var body := VBoxContainer.new()
|
||||
body.add_theme_constant_override("separation", 9)
|
||||
@@ -279,9 +288,73 @@ func _render() -> void:
|
||||
_set_metric("cases", str(int(data.get("ccsCasesCompleted", 0))))
|
||||
_set_metric("streak", "%d days" % int(data.get("currentStreak", 0)))
|
||||
_render_systems(data.get("systems", []))
|
||||
_render_progression(data.get("progression", {}))
|
||||
_render_outcome()
|
||||
|
||||
|
||||
func _render_progression(value: Variant) -> void:
|
||||
if progression_content == null:
|
||||
return
|
||||
_clear(progression_content)
|
||||
progression_content.add_child(_section_header("Clinical Progression", "Breadth, challenge, and retention"))
|
||||
var progression: Dictionary = value if typeof(value) == TYPE_DICTIONARY else {}
|
||||
if progression.is_empty():
|
||||
progression_content.add_child(_label("Loading progression...", 13, Brand.muted_color(_dark())))
|
||||
return
|
||||
progression_content.add_child(_label(str(progression.get("displayName", "Case Scout III")), 24, Brand.PURPLE, true))
|
||||
var badges: Array = progression.get("earnedBadges", [])
|
||||
progression_content.add_child(_label("Earned: %s" % ", ".join(PackedStringArray(badges)), 12, Brand.muted_color(_dark())))
|
||||
var ladder := GridContainer.new()
|
||||
ladder.columns = 3
|
||||
ladder.add_theme_constant_override("h_separation", 7)
|
||||
ladder.add_theme_constant_override("v_separation", 7)
|
||||
var rank_names := ["Case Scout", "Pattern Hunter", "Diagnostic Tactician", "Management Strategist", "Clinical Vanguard"]
|
||||
var divisions := ["III", "II", "I"]
|
||||
var earned_ordinal := int(progression.get("rankOrdinal", 0))
|
||||
var earned_dates: Dictionary = progression.get("earnedRanksUtc", {})
|
||||
var ladder_data: Array = progression.get("ladder", [])
|
||||
for ordinal in 15:
|
||||
var earned := ordinal <= earned_ordinal
|
||||
var caption := "%s %s" % [rank_names[floori(float(ordinal) / 3.0)], divisions[ordinal % 3]]
|
||||
var date := str(earned_dates.get(str(ordinal), "")).left(10)
|
||||
if earned and not date.is_empty():
|
||||
caption += "\n%s" % date
|
||||
var cell := _label(caption, 10, Brand.SUCCESS if earned else Brand.muted_color(_dark()), earned)
|
||||
cell.custom_minimum_size = Vector2(105, 38)
|
||||
cell.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
cell.vertical_alignment = VERTICAL_ALIGNMENT_CENTER
|
||||
if ordinal < ladder_data.size() and typeof(ladder_data[ordinal]) == TYPE_DICTIONARY:
|
||||
cell.tooltip_text = str((ladder_data[ordinal] as Dictionary).get("requirementSummary", ""))
|
||||
ladder.add_child(cell)
|
||||
progression_content.add_child(ladder)
|
||||
var next_name = progression.get("nextRankName")
|
||||
if next_name != null:
|
||||
progression_content.add_child(_label("Next: %s %s" % [str(next_name), str(progression.get("nextDivision", ""))], 14, Brand.text_color(_dark()), true))
|
||||
for requirement_value in progression.get("nextRequirements", []):
|
||||
var requirement: Dictionary = requirement_value
|
||||
var row := HBoxContainer.new()
|
||||
var text := _label(str(requirement.get("label", "Requirement")), 11, Brand.text_color(_dark()))
|
||||
text.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
row.add_child(text)
|
||||
row.add_child(_label("%d / %d" % [int(requirement.get("current", 0)), int(requirement.get("required", 0))], 11,
|
||||
Brand.SUCCESS if bool(requirement.get("complete", false)) else Brand.ROYAL_BLUE, true))
|
||||
progression_content.add_child(row)
|
||||
progression_content.add_child(HSeparator.new())
|
||||
progression_content.add_child(_label("Personal records", 15, Brand.text_color(_dark()), true))
|
||||
for record_value in progression.get("records", []):
|
||||
var record: Dictionary = record_value
|
||||
var suffix := "%d%%" % int(record.get("value", 0)) if str(record.get("key", "")) == "timed_block" else str(int(record.get("value", 0)))
|
||||
var title := _label("%s %s" % [str(record.get("label", "Record")), suffix], 12, Brand.text_color(_dark()), true)
|
||||
title.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
progression_content.add_child(title)
|
||||
var definition := str(record.get("definition", ""))
|
||||
if bool(record.get("trackingFromLaunch", false)):
|
||||
definition += " Tracking since %s." % str(progression.get("trackingStartedUtc", "")).left(10)
|
||||
var detail := _label(definition, 10, Brand.muted_color(_dark()))
|
||||
detail.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
|
||||
progression_content.add_child(detail)
|
||||
|
||||
|
||||
func _render_connected_accounts(provider_values: Variant, available_values: Variant) -> void:
|
||||
if connected_accounts_list == null:
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user