Files
step3/scripts/ui/session_expiry_dialog.gd
T
hz ace04ab268 Fix low-contrast session-expiry dialog in dark mode
The panel's shared Brand.panel_box background is ~80% opaque, which
compounded with the dialog's own dim backdrop let the screen behind
show through and washed out the card against it. Force full opacity
on this dialog's panel specifically, since other panel_box overlays
still rely on the shared translucency.
2026-07-21 16:47:54 -05:00

183 lines
5.7 KiB
GDScript

extends Control
const Brand := preload("res://scripts/ui/medmind_style.gd")
signal logout_requested
var panel: PanelContainer
var title_label: Label
var message_label: Label
var error_label: Label
var stay_button: Button
var logout_button: Button
func _ready() -> void:
visible = false
top_level = true
mouse_filter = Control.MOUSE_FILTER_STOP
set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
_build_ui()
AuthState.session_warning.connect(_show_warning)
AuthState.session_countdown_changed.connect(_update_countdown)
AuthState.session_refresh_started.connect(_refresh_started)
AuthState.session_refreshed.connect(_refresh_succeeded)
AuthState.session_refresh_failed.connect(_refresh_failed)
UIThemeService.theme_changed.connect(func(_dark: bool): _apply_theme())
resized.connect(_refresh_size)
_refresh_size()
_apply_theme()
func _build_ui() -> void:
var dim := ColorRect.new()
dim.color = Color(0, 0, 0, 0.74)
dim.mouse_filter = Control.MOUSE_FILTER_STOP
dim.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(dim)
var center := CenterContainer.new()
center.set_anchors_preset(Control.PRESET_FULL_RECT)
add_child(center)
panel = PanelContainer.new()
panel.custom_minimum_size = Vector2(520, 280)
center.add_child(panel)
var content := VBoxContainer.new()
content.add_theme_constant_override("separation", 16)
panel.add_child(content)
title_label = Label.new()
title_label.text = "Stay logged in?"
title_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
title_label.add_theme_font_size_override("font_size", 28)
content.add_child(title_label)
message_label = Label.new()
message_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
message_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
message_label.add_theme_font_size_override("font_size", 17)
content.add_child(message_label)
error_label = Label.new()
error_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
error_label.autowrap_mode = TextServer.AUTOWRAP_WORD_SMART
error_label.add_theme_font_size_override("font_size", 14)
content.add_child(error_label)
var actions := HBoxContainer.new()
actions.add_theme_constant_override("separation", 12)
content.add_child(actions)
logout_button = Button.new()
logout_button.text = "Log out"
logout_button.custom_minimum_size = Vector2(150, 48)
logout_button.pressed.connect(_request_logout)
actions.add_child(logout_button)
stay_button = Button.new()
stay_button.text = "Stay logged in"
stay_button.custom_minimum_size = Vector2(0, 48)
stay_button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
stay_button.pressed.connect(AuthState.request_session_refresh)
actions.add_child(stay_button)
func _show_warning(seconds_remaining: int) -> void:
error_label.text = ""
stay_button.disabled = false
logout_button.disabled = false
stay_button.text = "Stay logged in"
visible = true
_update_countdown(seconds_remaining)
move_to_front()
BlockSessionService.pause_current_question_timer()
func _update_countdown(seconds_remaining: int) -> void:
if not visible:
return
var minutes := floori(float(seconds_remaining) / 60.0)
var seconds := seconds_remaining % 60
message_label.text = "Your session expires in %02d:%02d. Renew it to continue studying." % [minutes, seconds]
func _refresh_started() -> void:
if not visible:
return
stay_button.disabled = true
logout_button.disabled = true
stay_button.text = "Renewing..."
error_label.text = ""
func _refresh_succeeded() -> void:
_hide_dialog()
func _refresh_failed(message: String, terminal: bool) -> void:
if not visible:
return
error_label.text = message
stay_button.text = "Stay logged in"
stay_button.disabled = terminal
logout_button.disabled = false
func _request_logout() -> void:
logout_requested.emit()
func _hide_dialog() -> void:
visible = false
error_label.text = ""
stay_button.text = "Stay logged in"
stay_button.disabled = false
logout_button.disabled = false
BlockSessionService.resume_current_question_timer()
func dismiss_for_logout() -> void:
if visible:
_hide_dialog()
func _unhandled_input(event: InputEvent) -> void:
if visible and event.is_action_pressed("ui_cancel"):
get_viewport().set_input_as_handled()
func _refresh_size() -> void:
if panel == null:
return
panel.custom_minimum_size = Vector2(
minf(520.0, maxf(288.0, size.x - 32.0)),
minf(280.0, maxf(250.0, size.y - 32.0)))
func _apply_theme() -> void:
if panel == null:
return
var dark := UIThemeService.is_dark_mode()
var panel_style := Brand.panel_box(dark)
panel_style.bg_color.a = 1.0
panel_style.content_margin_left = 32
panel_style.content_margin_right = 32
panel_style.content_margin_top = 30
panel_style.content_margin_bottom = 30
panel.add_theme_stylebox_override("panel", panel_style)
for label in [title_label, message_label]:
label.add_theme_color_override("font_color", Brand.text_color(dark))
error_label.add_theme_color_override("font_color", Color("fb7185") if dark else Color("be123c"))
stay_button.add_theme_stylebox_override("normal", Brand.gradient_button_box())
stay_button.add_theme_stylebox_override("hover", Brand.gradient_button_box())
stay_button.add_theme_stylebox_override("pressed", Brand.gradient_button_box())
stay_button.add_theme_color_override("font_color", Color.WHITE)
stay_button.add_theme_color_override("font_hover_color", Color.WHITE)
logout_button.add_theme_stylebox_override("normal", Brand.secondary_button_box(dark))
logout_button.add_theme_stylebox_override("hover", Brand.secondary_button_box(dark, true))
logout_button.add_theme_stylebox_override("pressed", Brand.secondary_button_box(dark, true))
logout_button.add_theme_color_override("font_color", Brand.text_color(dark))
logout_button.add_theme_color_override("font_hover_color", Brand.text_color(dark))