Files
step3/scripts/ui/settings_screen.gd
T
hz 118c215608 Add a setting to turn off follow-up questions
The optional "FOLLOW-UP QUESTIONS" reinforcement section shown during
answer review is now gated behind a Settings toggle (on by default),
persisted locally the same way as dark mode and interface sounds.
2026-07-24 23:01:06 -05:00

220 lines
8.0 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
const CORE_BLOCK_SIZE_STEP := 5
var main: Control
var theme_toggle: CheckButton
var sound_toggle: CheckButton
var followups_toggle: CheckButton
var question_scale_value_label: Label
var ccs_scale_value_label: Label
var core_block_size_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)
followups_toggle = CheckButton.new()
followups_toggle.text = "Follow-up questions"
followups_toggle.tooltip_text = "Optional reinforcement questions shown after you answer"
followups_toggle.custom_minimum_size = Vector2(0, 52)
followups_toggle.toggled.connect(BlockSessionService.set_show_review_followups)
content.add_child(followups_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"))
content.add_child(_build_core_block_size_row())
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())
followups_toggle.set_pressed_no_signal(BlockSessionService.show_review_followups)
_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 _build_core_block_size_row() -> 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 = "Question block size"
label.size_flags_horizontal = Control.SIZE_EXPAND_FILL
row.add_child(label)
var smaller := Button.new()
smaller.text = "-"
smaller.tooltip_text = "Fewer questions per block"
smaller.custom_minimum_size = Vector2(44, 44)
smaller.pressed.connect(_adjust_core_block_size.bind(-CORE_BLOCK_SIZE_STEP))
row.add_child(smaller)
core_block_size_value_label = Label.new()
core_block_size_value_label.custom_minimum_size = Vector2(56, 0)
core_block_size_value_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
row.add_child(core_block_size_value_label)
var larger := Button.new()
larger.text = "+"
larger.tooltip_text = "More questions per block"
larger.custom_minimum_size = Vector2(44, 44)
larger.pressed.connect(_adjust_core_block_size.bind(CORE_BLOCK_SIZE_STEP))
row.add_child(larger)
return row
func _adjust_core_block_size(delta: int) -> void:
BlockSessionService.set_core_block_size(BlockSessionService.core_block_size + delta)
_refresh_text_scale_labels()
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)
if core_block_size_value_label != null:
core_block_size_value_label.text = str(BlockSessionService.core_block_size)
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))