Add CHANGE_LANGUAGE feature to teacher settings
Reorders the left sidebar so risky actions sit at the bottom with a gap: Dashboard, Synchronize, Logout | Change Language (red), Delete Account. The new Change Language button opens a warning popup with a language dropdown. On confirm, if the selected locale differs from the current one, the client calls POST /reset_language. On success it wipes the local teacher folder (progression, remediation, confusion matrix…), applies the new language to device and teacher settings, logs out and reloads from the splash screen. On error the user sees an error popup and nothing local changes.
This commit is contained in:
@@ -434,6 +434,9 @@ CHECKING_DATA,Vérification des données...,Comprobando datos...,Verificação d
|
||||
TEACHER_SETTINGS_HELP,"Pour accéder aux paramètres, veuillez appuyer sur le plus et la barre verticale, puis maintenez le bouton ""Paramètres"" pendant 5 secondes","Para acceder a los ajustes, pulse el signo más y la barra vertical y, a continuación, mantenga pulsado el botón «Configuración» durante 5 segundos","Para acessar as configurações, pressione o sinal de mais e a barra vertical e, em seguida, mantenha pressionado o botão ""Parâmetros"" por 5 segundos","Per accedere alle impostazioni, premi il segno più e la barra verticale, quindi tieni premuto il pulsante ""Impostazioni"" per 5 secondi"
|
||||
DELETE_ACCOUNT,Supprimer le compte,Eliminar cuenta,Excluir conta,Elimina account
|
||||
DELETE_ACCOUNT_POPUP,Voulez-vous vraiment supprimer votre compte ? Cette action est irréversible !,¿De verdad quieres eliminar tu cuenta? ¡Esta acción es irreversible!,Você realmente deseja excluir sua conta? Essa ação é irreversível!,Vuoi davvero eliminare il tuo account? Questa azione è irreversibile!
|
||||
CHANGE_LANGUAGE,Changer la langue,Cambiar el idioma,Mudar o idioma,Cambia lingua
|
||||
CHANGE_LANGUAGE_POPUP,"Changer la langue du compte supprimera toute la progression et les données de tous les élèves. Cette action est irréversible. Sélectionnez la nouvelle langue ci-dessous.","Cambiar el idioma de la cuenta borrará todo el progreso y los datos de todos los alumnos. Esta acción es irreversible. Seleccione el nuevo idioma a continuación.","Mudar o idioma da conta apagará todo o progresso e os dados de todos os alunos. Essa ação é irreversível. Selecione o novo idioma abaixo.","Cambiare la lingua dell'account cancellerà tutti i progressi e i dati di tutti gli studenti. Questa azione è irreversibile. Seleziona di seguito la nuova lingua."
|
||||
CHANGE_LANGUAGE_ERROR,"Impossible de changer la langue. Veuillez vérifier votre connexion et réessayer.","No se pudo cambiar el idioma. Compruebe su conexión y vuelva a intentarlo.","Não foi possível mudar o idioma. Verifique sua conexão e tente novamente.","Impossibile cambiare la lingua. Verifica la connessione e riprova."
|
||||
DISCONNECTED_ERROR,Vous avez été déconnecté. Veuillez renseigner vos identifiants à nouveau.,Se ha cerrado la sesión. Vuelva a introducir sus datos de acceso.,Você foi desconectado. Digite seus detalhes de login novamente.,Sei stato disconnesso. Inserisci nuovamente le tue credenziali.
|
||||
INVALID_LANGUAGE_DIRECTORY,Dossier de langue invalide,Carpeta de idioma no válida,Pasta de idioma inválida,Cartella lingua non valida
|
||||
NO_INTERNET_ACCESS,Vous n'êtes pas connecté à Internet. Veuillez vérifier votre connexion et réessayer.,No está conectado a Internet. Compruebe su conexión e inténtelo de nuevo.,Você não está conectado à Internet. Verifique sua conexão e tente novamente.,Non sei connesso a Internet. Verifica la connessione e riprova.
|
||||
|
||||
|
Can't render this file because it contains an unexpected character in line 41 and column 273.
|
@@ -3,6 +3,7 @@ extends Control
|
||||
|
||||
const MAIN_MENU_PATH: String = "res://sources/menus/main/main_menu.tscn"
|
||||
const LOGIN_MENU_PATH: String = "res://sources/menus/login/login.tscn"
|
||||
const SPLASH_SCREEN_PATH: String = "res://sources/menus/splash_screen/splash_screen.tscn"
|
||||
const DEVICE_SELECTION_SCENE_PATH: String = "res://sources/menus/device_selection/device_selection.tscn"
|
||||
const DEVICE_TAB_SCENE: PackedScene = preload("res://sources/menus/settings/device_tab.tscn")
|
||||
const PASSWORD_VISUALIZER_SCENE: PackedScene = preload("res://sources/menus/components/password_visualizer.tscn")
|
||||
@@ -18,6 +19,8 @@ var last_device_id: int = -1
|
||||
@onready var devices_tab_container: TabContainer = %DevicesTabContainer
|
||||
@onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks
|
||||
@onready var delete_popup: ConfirmPopup = %DeletePopup
|
||||
@onready var change_language_popup: ChangeLanguagePopup = %ChangeLanguagePopup
|
||||
@onready var change_language_error_popup: ConfirmPopup = %ChangeLanguageErrorPopup
|
||||
@onready var loading_popup: LoadingPopup = %LoadingPopup
|
||||
@onready var account_type_option_button: OptionButton = %AccountTypeOptionButton
|
||||
@onready var education_method_option_button: OptionButton = %EducationMethodOptionButton
|
||||
@@ -125,6 +128,36 @@ func _on_logout_button_pressed() -> void:
|
||||
get_tree().change_scene_to_file(MAIN_MENU_PATH)
|
||||
|
||||
|
||||
func _on_change_language_button_pressed() -> void:
|
||||
var current_language: String = UserDataManager.get_language()
|
||||
change_language_popup.show_for_current_language(current_language)
|
||||
|
||||
|
||||
func _on_change_language_popup_accepted(new_language: String) -> void:
|
||||
if not new_language:
|
||||
Log.warn("SettingsTeacherSettings: Change language cancelled - no language selected")
|
||||
return
|
||||
var current_language: String = UserDataManager.get_language()
|
||||
if new_language == current_language:
|
||||
Log.info("SettingsTeacherSettings: Change language skipped - selected language matches current (%s)" % current_language)
|
||||
return
|
||||
Log.warn("SettingsTeacherSettings: Change language from %s to %s" % [current_language, new_language])
|
||||
|
||||
var res: Dictionary = await ServerManager.reset_language(new_language)
|
||||
if res.code != 200:
|
||||
Log.error("SettingsTeacherSettings: Reset language request failed. Error code %d" % res.code)
|
||||
change_language_error_popup.show()
|
||||
return
|
||||
|
||||
# Server confirmed: wipe all local teacher data, apply new language, and restart from splash.
|
||||
UserDataManager.delete_teacher_data()
|
||||
if UserDataManager.teacher_settings:
|
||||
UserDataManager.teacher_settings.server_language_validated = false
|
||||
UserDataManager.set_language(new_language, true)
|
||||
UserDataManager.logout()
|
||||
get_tree().change_scene_to_file(SPLASH_SCREEN_PATH)
|
||||
|
||||
|
||||
func _on_devices_tab_container_tab_changed(tab: int) -> void:
|
||||
var device_tab: DeviceTab = devices_tab_container.get_tab_control(tab) as DeviceTab
|
||||
if not device_tab:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
[ext_resource type="Theme" uid="uid://dqjvrt5nrtwn1" path="res://resources/themes/kalulu_theme.tres" id="8_7h0sa"]
|
||||
[ext_resource type="PackedScene" uid="uid://qsvbq6ruc44v" path="res://sources/menus/settings/lesson_unlocks.tscn" id="9_mljfd"]
|
||||
[ext_resource type="PackedScene" uid="uid://dhowigt8un22u" path="res://sources/ui/loading_popup.tscn" id="10_i488h"]
|
||||
[ext_resource type="PackedScene" path="res://sources/ui/change_language_popup.tscn" id="11_chglg"]
|
||||
|
||||
[node name="TeacherSettings" type="Control" unique_id=149147235]
|
||||
layout_mode = 3
|
||||
@@ -71,6 +72,30 @@ theme_type_variation = &"FlatButton"
|
||||
theme_override_font_sizes/font_size = 40
|
||||
text = "SYNCHRONIZE_ACCOUNT"
|
||||
|
||||
[node name="LogoutButton" type="Button" parent="InterfaceLeft/Container" unique_id=808130432]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 40
|
||||
text = "LOGOUT"
|
||||
|
||||
[node name="DangerSpacer" type="Control" parent="InterfaceLeft/Container" unique_id=312700845]
|
||||
custom_minimum_size = Vector2(0, 100)
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ChangeLanguageButton" type="Button" parent="InterfaceLeft/Container" unique_id=144215823]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DangerButton"
|
||||
theme_override_font_sizes/font_size = 40
|
||||
text = "CHANGE_LANGUAGE"
|
||||
|
||||
[node name="ChangeLanguagePopup" parent="InterfaceLeft/Container/ChangeLanguageButton" unique_id=144215824 instance=ExtResource("11_chglg")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
|
||||
[node name="ChangeLanguageErrorPopup" parent="InterfaceLeft/Container/ChangeLanguageButton" unique_id=144215825 instance=ExtResource("7_jetb7")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
content_text = "CHANGE_LANGUAGE_ERROR"
|
||||
|
||||
[node name="DeleteButton" type="Button" parent="InterfaceLeft/Container" unique_id=721919922]
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DangerButton"
|
||||
@@ -82,11 +107,6 @@ unique_name_in_owner = true
|
||||
visible = false
|
||||
content_text = "DELETE_ACCOUNT_POPUP"
|
||||
|
||||
[node name="LogoutButton" type="Button" parent="InterfaceLeft/Container" unique_id=808130432]
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 40
|
||||
text = "LOGOUT"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="." unique_id=2087046145]
|
||||
custom_minimum_size = Vector2(1970, 1800)
|
||||
layout_mode = 1
|
||||
@@ -243,9 +263,11 @@ access = 2
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/BackButton" to="." method="_on_back_button_pressed"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/Dashboard" to="." method="_on_dashboard_button_pressed"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/SynchronizeButton" to="." method="_on_synchronize_button_pressed"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/LogoutButton" to="." method="_on_logout_button_pressed"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/ChangeLanguageButton" to="." method="_on_change_language_button_pressed"]
|
||||
[connection signal="accepted" from="InterfaceLeft/Container/ChangeLanguageButton/ChangeLanguagePopup" to="." method="_on_change_language_popup_accepted"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/DeleteButton" to="." method="_on_delete_button_pressed"]
|
||||
[connection signal="accepted" from="InterfaceLeft/Container/DeleteButton/DeletePopup" to="." method="_on_delete_popup_accepted"]
|
||||
[connection signal="pressed" from="InterfaceLeft/Container/LogoutButton" to="." method="_on_logout_button_pressed"]
|
||||
[connection signal="item_selected" from="VBoxContainer/HBoxContainer/AccountTypeOptionButton" to="." method="_on_account_type_option_button_item_selected"]
|
||||
[connection signal="item_selected" from="VBoxContainer/HBoxContainer/EducationMethodOptionButton" to="." method="_on_education_method_option_button_item_selected"]
|
||||
[connection signal="tab_changed" from="VBoxContainer/DevicesTabContainer" to="." method="_on_devices_tab_container_tab_changed"]
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
@tool
|
||||
class_name ChangeLanguagePopup
|
||||
extends CanvasLayer
|
||||
|
||||
signal accepted(language: String)
|
||||
signal refused()
|
||||
|
||||
@export_multiline var content_text: String = "CHANGE_LANGUAGE_POPUP": set = _set_content_text
|
||||
@export var close_on_action: bool = true
|
||||
|
||||
var _locales: Array[String] = []
|
||||
|
||||
@onready var content_label: Label = %ChangeLanguageContentLabel
|
||||
@onready var language_field: OptionButton = %ChangeLanguageLanguageField
|
||||
@onready var confirm_button: Button = %ChangeLanguageConfirmButton
|
||||
@onready var cancel_button: Button = %ChangeLanguageCancelButton
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_set_content_text(content_text)
|
||||
if not Engine.is_editor_hint():
|
||||
_populate_language_field()
|
||||
|
||||
|
||||
func show_for_current_language(current_language: String) -> void:
|
||||
_populate_language_field(current_language)
|
||||
show()
|
||||
|
||||
|
||||
func get_selected_language() -> String:
|
||||
if not language_field:
|
||||
return ""
|
||||
var selected_id: int = language_field.get_selected_id()
|
||||
if selected_id < 0 or selected_id >= _locales.size():
|
||||
return ""
|
||||
return _locales[selected_id]
|
||||
|
||||
|
||||
func _populate_language_field(preselected_locale: String = "") -> void:
|
||||
if not language_field:
|
||||
return
|
||||
_locales.clear()
|
||||
language_field.clear()
|
||||
var index: int = 0
|
||||
for locale: String in Utils.SUPPORTED_LOCALES.keys():
|
||||
if not locale:
|
||||
continue
|
||||
var locale_name: String = Utils.SUPPORTED_LOCALES[locale]
|
||||
if not locale_name:
|
||||
continue
|
||||
language_field.add_item(locale_name, index)
|
||||
_locales.append(locale)
|
||||
if locale == preselected_locale:
|
||||
language_field.select(index)
|
||||
index += 1
|
||||
if language_field.get_selected_id() == -1 and _locales.size() > 0:
|
||||
language_field.select(0)
|
||||
|
||||
|
||||
func _set_content_text(p_content_text: String) -> void:
|
||||
content_text = p_content_text
|
||||
if content_label:
|
||||
content_label.text = content_text
|
||||
|
||||
|
||||
func _on_confirm_button_pressed() -> void:
|
||||
var selected_language: String = get_selected_language()
|
||||
accepted.emit(selected_language)
|
||||
if close_on_action:
|
||||
hide()
|
||||
|
||||
|
||||
func _on_cancel_button_pressed() -> void:
|
||||
refused.emit()
|
||||
if close_on_action:
|
||||
hide()
|
||||
@@ -0,0 +1 @@
|
||||
uid://bxqtlx38skcu3
|
||||
@@ -0,0 +1,92 @@
|
||||
[gd_scene format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://sources/ui/change_language_popup.gd" id="1_chglg"]
|
||||
[ext_resource type="Theme" path="res://resources/themes/kalulu_theme.tres" id="2_chglg"]
|
||||
|
||||
[sub_resource type="Gradient" id="Gradient_chglg"]
|
||||
colors = PackedColorArray(0.2, 0.2, 0.2, 0.505882, 0.2, 0.2, 0.2, 0.505882)
|
||||
|
||||
[sub_resource type="GradientTexture1D" id="GradientTexture1D_chglg"]
|
||||
gradient = SubResource("Gradient_chglg")
|
||||
|
||||
[node name="ChangeLanguagePopup" type="CanvasLayer"]
|
||||
script = ExtResource("1_chglg")
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="."]
|
||||
top_level = true
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 0
|
||||
texture = SubResource("GradientTexture1D_chglg")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="TextureRect"]
|
||||
layout_mode = 1
|
||||
anchors_preset = 8
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -20.0
|
||||
offset_top = -20.0
|
||||
offset_right = 20.0
|
||||
offset_bottom = 20.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_type_variation = &"PanelKalulu"
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="TextureRect/PanelContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="MarginContainer" type="MarginContainer" parent="TextureRect/PanelContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/margin_left = 50
|
||||
theme_override_constants/margin_top = 50
|
||||
theme_override_constants/margin_right = 50
|
||||
theme_override_constants/margin_bottom = 25
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer"]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 30
|
||||
|
||||
[node name="ChangeLanguageContentLabel" type="Label" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(1200, 0)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 1
|
||||
theme_override_font_sizes/font_size = 60
|
||||
text = "CHANGE_LANGUAGE_POPUP"
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="ChangeLanguageLanguageField" type="OptionButton" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(0, 120)
|
||||
layout_mode = 2
|
||||
theme = ExtResource("2_chglg")
|
||||
theme_override_font_sizes/font_size = 60
|
||||
autowrap_mode = 2
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="ChangeLanguageConfirmButton" type="Button" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_type_variation = &"DangerButton"
|
||||
theme_override_font_sizes/font_size = 70
|
||||
text = "VALIDATE"
|
||||
|
||||
[node name="Separator" type="Control" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ChangeLanguageCancelButton" type="Button" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_font_sizes/font_size = 70
|
||||
text = "CANCEL"
|
||||
|
||||
[connection signal="pressed" from="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/ChangeLanguageConfirmButton" to="." method="_on_confirm_button_pressed"]
|
||||
[connection signal="pressed" from="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/ChangeLanguageCancelButton" to="." method="_on_cancel_button_pressed"]
|
||||
@@ -174,6 +174,14 @@ func set_user_language(language: String) -> Dictionary:
|
||||
await _post_request("set_language", data)
|
||||
return _response()
|
||||
|
||||
|
||||
func reset_language(language: String) -> Dictionary:
|
||||
loading_rect.show()
|
||||
Log.warn("ServerManager: Reset language request initiated for %s" % language)
|
||||
var data: Dictionary = {"language": language}
|
||||
await _post_request("reset_language", data)
|
||||
return _response()
|
||||
|
||||
#region Sender functions
|
||||
|
||||
func check_internet_access() -> bool:
|
||||
|
||||
Reference in New Issue
Block a user