Files
step3/scripts/ui/settings_screen.gd
T
hz 489b9c3d7c Fix text zoom not actually syncing, and expose it in Settings
Two real gaps meant the account-synced zoom (from the previous
"sync through the account" change) never reached the screen:
_load_cache() updated AccountProfileService.preferences but never
emitted profile_changed, so question_player.gd/ccs_service.gd (already
built and listening before login even happens) never found out a
cached value had loaded. And nothing forced a server refresh
right after login - it only fired if the user happened to open the
profile/progress screen, so a fresh device/session had no path to
the true synced value at all.

main.gd now calls AccountProfileService.refresh() once per login
(not on every silent token refresh) so the real preferences GET
always runs right after signing in, on any device.

Also added Question bank/CCS case text size steppers to the Settings
screen next to dark mode, per user request, reusing the same
AccountProfileService/CCSService plumbing as the in-screen A-/A+
buttons.
2026-07-23 04:37:45 -05:00

170 lines
6.1 KiB
GDScript

extends VBoxContainer
const Brand := preload("res://scripts/ui/medmind_style.gd")
const QUESTION_TEXT_SCALE_MIN := 0.85
const QUESTION_TEXT_SCALE_MAX := 1.35
const QUESTION_TEXT_SCALE_STEP := 0.1
var main: Control
var theme_toggle: CheckButton
var sound_toggle: CheckButton
var question_scale_value_label: Label
var ccs_scale_value_label: Label
func _ready() -> void:
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
add_theme_constant_override("separation", 18)
var eyebrow := Label.new()
eyebrow.text = "PREFERENCES"
eyebrow.add_theme_font_override("font", Brand.font)
eyebrow.add_theme_font_size_override("font_size", 14)
eyebrow.add_theme_color_override("font_color", Brand.SKY_BLUE)
add_child(eyebrow)
var title := Label.new()
title.text = "Settings"
title.add_theme_font_override("font", Brand.font)
title.add_theme_font_size_override("font_size", 34)
add_child(title)
var subtitle := Label.new()
subtitle.text = "Adjust RanaZe's appearance and interface sounds."
subtitle.add_theme_font_override("font", Brand.font)
subtitle.add_theme_font_size_override("font_size", 17)
subtitle.add_theme_color_override("font_color", Brand.SLATE)
add_child(subtitle)
var panel := PanelContainer.new()
panel.custom_minimum_size = Vector2(520, 0)
panel.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
panel.add_theme_stylebox_override("panel", Brand.panel_box(UIThemeService.is_dark_mode()))
add_child(panel)
var content := VBoxContainer.new()
content.add_theme_constant_override("separation", 18)
panel.add_child(content)
theme_toggle = CheckButton.new()
theme_toggle.text = "Dark mode"
theme_toggle.custom_minimum_size = Vector2(0, 52)
theme_toggle.toggled.connect(_on_theme_toggled)
content.add_child(theme_toggle)
sound_toggle = CheckButton.new()
sound_toggle.text = "Interface sounds"
sound_toggle.custom_minimum_size = Vector2(0, 52)
sound_toggle.toggled.connect(UISoundService.set_sounds_enabled)
content.add_child(sound_toggle)
content.add_child(_build_text_scale_row("Question bank text size", "question"))
content.add_child(_build_text_scale_row("CCS case text size", "ccs"))
var legal_panel := PanelContainer.new()
legal_panel.custom_minimum_size = Vector2(520, 0)
legal_panel.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
legal_panel.add_theme_stylebox_override("panel", Brand.panel_box(UIThemeService.is_dark_mode()))
legal_panel.set_meta("legal_panel", true)
add_child(legal_panel)
var legal_content := VBoxContainer.new()
legal_content.add_theme_constant_override("separation", 10)
legal_panel.add_child(legal_content)
var legal_heading := Label.new()
legal_heading.text = "Legal"
legal_heading.add_theme_font_override("font", Brand.font)
legal_heading.add_theme_font_size_override("font_size", 20)
legal_content.add_child(legal_heading)
for spec in [["Terms of Service", "terms"], ["Privacy Policy", "privacy"]]:
var button := Button.new()
button.text = spec[0]
button.alignment = HORIZONTAL_ALIGNMENT_LEFT
button.pressed.connect(_open_legal_document.bind(str(spec[1])))
legal_content.add_child(button)
UIThemeService.theme_changed.connect(_on_theme_changed)
AccountProfileService.profile_changed.connect(_refresh_text_scale_labels)
CCSService.text_scale_changed.connect(_refresh_text_scale_labels)
_refresh_text_scale_labels()
func on_show(_payload: Variant = null) -> void:
theme_toggle.set_pressed_no_signal(UIThemeService.is_dark_mode())
sound_toggle.set_pressed_no_signal(UISoundService.are_sounds_enabled())
_refresh_text_scale_labels()
func _build_text_scale_row(label_text: String, kind: String) -> HBoxContainer:
var row := HBoxContainer.new()
row.custom_minimum_size = Vector2(0, 52)
row.add_theme_constant_override("separation", 12)
var label := Label.new()
label.text = label_text
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(label)
var smaller := Button.new()
smaller.text = "A-"
smaller.tooltip_text = "Decrease text size"
smaller.custom_minimum_size = Vector2(44, 44)
row.add_child(smaller)
var value_label := Label.new()
value_label.custom_minimum_size = Vector2(56, 0)
value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
row.add_child(value_label)
var larger := Button.new()
larger.text = "A+"
larger.tooltip_text = "Increase text size"
larger.custom_minimum_size = Vector2(44, 44)
row.add_child(larger)
if kind == "question":
question_scale_value_label = value_label
smaller.pressed.connect(_adjust_question_text_scale.bind(-QUESTION_TEXT_SCALE_STEP))
larger.pressed.connect(_adjust_question_text_scale.bind(QUESTION_TEXT_SCALE_STEP))
else:
ccs_scale_value_label = value_label
smaller.pressed.connect(_adjust_ccs_text_scale.bind(-CCSService.TEXT_SCALE_STEP))
larger.pressed.connect(_adjust_ccs_text_scale.bind(CCSService.TEXT_SCALE_STEP))
return row
func _adjust_question_text_scale(delta: float) -> void:
var current: float = AccountProfileService.preferences.get("questionTextScale", 1.0)
var next_scale: float = clamp(current + delta, QUESTION_TEXT_SCALE_MIN, QUESTION_TEXT_SCALE_MAX)
AccountProfileService.update_text_scale(next_scale)
_refresh_text_scale_labels()
func _adjust_ccs_text_scale(delta: float) -> void:
CCSService.adjust_text_scale(delta)
_refresh_text_scale_labels()
func _refresh_text_scale_labels() -> void:
if question_scale_value_label != null:
var question_scale: float = AccountProfileService.preferences.get("questionTextScale", 1.0)
question_scale_value_label.text = "%d%%" % round(question_scale * 100)
if ccs_scale_value_label != null:
ccs_scale_value_label.text = "%d%%" % round(CCSService.text_scale * 100)
func _on_theme_toggled(enabled: bool) -> void:
UIThemeService.set_dark_mode(enabled)
func _open_legal_document(kind: String) -> void:
main.open_legal_document(kind)
func _on_theme_changed(is_dark: bool) -> void:
theme_toggle.set_pressed_no_signal(is_dark)
var panel := theme_toggle.get_parent().get_parent() as PanelContainer
if panel != null:
panel.add_theme_stylebox_override("panel", Brand.panel_box(is_dark))
for node in get_children():
if node is PanelContainer and node.has_meta("legal_panel"):
node.add_theme_stylebox_override("panel", Brand.panel_box(is_dark))