diff --git a/client/data/ui-strings.yaml b/client/data/ui-strings.yaml index 492700c0f..425a896e7 100644 --- a/client/data/ui-strings.yaml +++ b/client/data/ui-strings.yaml @@ -199,6 +199,7 @@ settings: ai_dialogue_toggle: "AI-Enhanced Dialogue" ai_status_checking: "Speed not yet measured — will check on first enable." ai_status_ram_marginal: "Low memory — performance may vary." + ai_battery_warning: "High battery usage" # ============================================================ # CHARACTER SELECTION (if applicable in v0.1) diff --git a/client/ui/settings_dialog.gd b/client/ui/settings_dialog.gd index a9fd7bc27..0f48940b7 100644 --- a/client/ui/settings_dialog.gd +++ b/client/ui/settings_dialog.gd @@ -37,6 +37,7 @@ var _container: VBoxContainer = null var _ai_hw_status: String = "" # "pass" | "marginal" | "fail" | "" (not yet checked) var _ai_check_node: CheckButton = null var _ai_inference_suspended: bool = false # D-138 §8 Layer 3 battery auto-suspend state +var _ai_battery_warning_label: Label = null # shown when on battery; toggle stays enabled signal closed signal debug_console_toggled(enabled: bool) # #581: debug console enabled/disabled @@ -214,7 +215,7 @@ func _build_ui() -> void: _ai_check_node = CheckButton.new() _ai_check_node.button_pressed = GameState.ai_enhanced_dialogue_enabled - _ai_check_node.disabled = (_ai_hw_status == "fail") or _ai_inference_suspended + _ai_check_node.disabled = (_ai_hw_status == "fail") ai_hbox.add_child(_ai_check_node) # Status message label — only shown when non-empty @@ -235,6 +236,14 @@ func _build_ui() -> void: ai_status_label.visible = not status_msg.is_empty() _container.add_child(ai_status_label) + # Battery warning label — visible when on battery power; toggle stays enabled per D-138. + _ai_battery_warning_label = Label.new() + _ai_battery_warning_label.text = UIStrings.get_text("settings.ai_battery_warning") + _ai_battery_warning_label.add_theme_font_size_override("font_size", FONT_SIZE_SMALL) + _ai_battery_warning_label.add_theme_color_override("font_color", STATUS_YELLOW) + _ai_battery_warning_label.visible = _ai_inference_suspended + _container.add_child(_ai_battery_warning_label) + _ai_check_node.toggled.connect(func(enabled: bool) -> void: GameState.ai_enhanced_dialogue_enabled = enabled _save_ai_pref(enabled) @@ -271,7 +280,8 @@ func _destroy_ui() -> void: if _container: _container.queue_free() _container = null - _ai_check_node = null # freed with _container + _ai_check_node = null # freed with _container + _ai_battery_warning_label = null # -- #646: AI Dialogue testable API ------------------------------------------- @@ -293,9 +303,9 @@ func set_ai_dialogue_hardware_status(status: String) -> void: ## Returns true if the AI-Enhanced Dialogue toggle is currently enabled (not greyed out). -## Disabled by RAM "fail" OR by active battery suspension (D-138 §8 Layer 3). +## Only disabled by RAM "fail" — battery suspension shows a warning but never greys the toggle. func is_ai_dialogue_toggle_enabled() -> bool: - return _ai_hw_status != "fail" and not _ai_inference_suspended + return _ai_hw_status != "fail" ## Returns true if AI inference is currently auto-suspended due to battery power (D-138 §8 Layer 3). @@ -305,14 +315,13 @@ func is_ai_inference_suspended() -> bool: ## Update battery suspension display state. +## Shows/hides the battery warning label; toggle stays enabled — player autonomy wins (D-138). ## Called when PlatformInfo.power_profile_changed fires (via main.gd or HardwareDetector). -## Tests can inject suspended=true to verify UI reacts correctly. +## Tests can inject suspended=true to verify the warning label appears. func set_ai_inference_suspended(suspended: bool) -> void: _ai_inference_suspended = suspended - # If the dialog is currently open and built, update the status label to reflect suspension. - # The next open() call will rebuild from scratch with the correct state anyway. - if _ai_check_node != null: - _ai_check_node.disabled = suspended or (_ai_hw_status == "fail") + if _ai_battery_warning_label != null: + _ai_battery_warning_label.visible = suspended ## Persist the AI Dialogue enabled state to the local prefs file.