diff --git a/resources/themes/kalulu_theme.tres b/resources/themes/kalulu_theme.tres index c25068ac..e487ef3e 100644 --- a/resources/themes/kalulu_theme.tres +++ b/resources/themes/kalulu_theme.tres @@ -594,6 +594,7 @@ PopupMenu/font_sizes/font_size = 100 PopupMenu/fonts/font = ExtResource("1_10vt2") PopupMenu/fonts/font_separator = ExtResource("1_10vt2") PopupMenu/fonts/title_font = null +ProgressBar/font_sizes/font_size = 50 ProgressBar/fonts/font = ExtResource("1_10vt2") ProgressBar/styles/background = SubResource("StyleBoxEmpty_nolh0") ProgressBar/styles/fill = SubResource("StyleBoxFlat_unu58") diff --git a/sources/menus/settings/teacher_settings.gd b/sources/menus/settings/teacher_settings.gd index cfb6811e..4d0dfce5 100644 --- a/sources/menus/settings/teacher_settings.gd +++ b/sources/menus/settings/teacher_settings.gd @@ -11,6 +11,8 @@ const device_tab_scene: PackedScene = preload("res://sources/menus/settings/devi @onready var lesson_unlocks: LessonUnlocks = $LessonUnlocks @onready var delete_popup: ConfirmPopup = %DeletePopup @onready var sync_choice_popup: ConfirmPopup = %SyncChoicePopup +@onready var loading_popup: LoadingPopup = %LoadingPopup + @onready var account_type_option_button: OptionButton = %AccountTypeOptionButton @onready var education_method_option_button: OptionButton = %EducationMethodOptionButton @@ -96,6 +98,21 @@ func _on_delete_button_pressed() -> void: delete_popup.show() +func startSync() -> void: + synchronizing = true + loading_popup.set_finished(false) + loading_popup.set_progress(0.0) + loading_popup.show() + + +func stopSync(success: bool = false) -> void: + synchronizing = false + if success: + loading_popup.set_progress(100.0) + await get_tree().create_timer(1).timeout + loading_popup.set_finished(true) + + func _on_synchronize_button_pressed() -> void: #synchronizing = false #await ServerManager.update_user_data(UserDataManager.teacher_settings, "2025-05-23T09:39:47", true) @@ -104,13 +121,13 @@ func _on_synchronize_button_pressed() -> void: if synchronizing: Logger.trace("SettingsTeacherSettings: User synchronization already started, cancel double-call.") return - synchronizing = true + startSync() var resGetTeacherTimestamp: Dictionary = await ServerManager.get_user_data_timestamp() if resGetTeacherTimestamp.success: Logger.trace("SettingsTeacherSettings: Server timestamp for user data = " + str(resGetTeacherTimestamp.body["last_modified"])) else: Logger.trace("Cannot get server timestamp for user data. Canceling synchronization.") - synchronizing = false + stopSync() return var unixTimeServer: int = Time.get_unix_time_from_datetime_string(resGetTeacherTimestamp.body["last_modified"] as String) @@ -122,7 +139,7 @@ func _on_synchronize_button_pressed() -> void: Logger.trace("SettingsTeacherSettings: Local user file timestamp = " + localStringTime) else: Logger.warn("SettingsTeacherSettings: Cannot find modification date for local user data: " + error_string(localResult.error as int)) - synchronizing = false + stopSync() return var localUnixTime: int = Time.get_unix_time_from_datetime_string(localStringTime) @@ -130,11 +147,12 @@ func _on_synchronize_button_pressed() -> void: Logger.trace("SettingsTeacherSettings: User data timestamp is the same in local and on server. No synchronization necessary") elif localUnixTime > unixTimeServer: _on_sync_choice_local() + return else: Logger.trace("SettingsTeacherSettings: Local user data timestamp is obsolete, we need to choose a priority") sync_choice_popup.show() return - synchronizing = false + stopSync(true) func _on_delete_popup_accepted() -> void: @@ -225,8 +243,8 @@ func _on_sync_choice_server() -> void: Logger.trace("SettingsTeacherSettings: Synchronization priority defined to server") var resGetUserData: Dictionary = await ServerManager.get_user_data() if resGetUserData.success: - # {"email": "cvbn@yopmail.com", "account_type": 0, "education_method": 0, "created_at": "2025-05-15T12:27:34Z", "last_modified": "2025-05-22T14:05:42Z"} if resGetUserData.has("body"): + # {"email": "cvbn@yopmail.com", "account_type": 0, "education_method": 0, "created_at": "2025-05-15T12:27:34Z", "last_modified": "2025-05-22T14:05:42Z"} var resultBody: Dictionary = resGetUserData.body if resultBody.has("account_type"): UserDataManager.teacher_settings.account_type = resultBody.account_type @@ -240,9 +258,13 @@ func _on_sync_choice_server() -> void: Logger.warn("SettingsTeacherSettings: user data received from the server has no education_method") else: Logger.warn("SettingsTeacherSettings: user data received from the server has no body") + stopSync() + return else: Logger.warn("SettingsTeacherSettings: Failed to get user data from the server") - synchronizing = false + stopSync() + return + stopSync(true) func _on_sync_choice_local() -> void: @@ -250,6 +272,16 @@ func _on_sync_choice_local() -> void: var resSetUserTimestamp: Dictionary = await ServerManager.update_user_data(UserDataManager.teacher_settings, localStringTime, true) if resSetUserTimestamp.success: Logger.trace("SettingsTeacherSettings: user data successfully sent to the server") + stopSync(true) else: Logger.warn("SettingsTeacherSettings: Failed to send update of user data to the server") - synchronizing = false + stopSync() + + +func _on_loading_popup_ok() -> void: + loading_popup.hide() + + +func _on_loading_popup_cancel() -> void: + #TODO + loading_popup.hide() diff --git a/sources/menus/settings/teacher_settings.tscn b/sources/menus/settings/teacher_settings.tscn index 29b4cf85..fdd390eb 100644 --- a/sources/menus/settings/teacher_settings.tscn +++ b/sources/menus/settings/teacher_settings.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=10 format=3 uid="uid://ci7ueo06f24k3"] +[gd_scene load_steps=11 format=3 uid="uid://ci7ueo06f24k3"] [ext_resource type="Script" uid="uid://cil0o87dsb7q4" path="res://sources/menus/settings/teacher_settings.gd" id="1_ojivk"] [ext_resource type="PackedScene" uid="uid://wdjp1sv55q4f" path="res://sources/menus/components/night_sky/night_sky.tscn" id="1_v06h8"] @@ -9,6 +9,7 @@ [ext_resource type="PackedScene" uid="uid://bhdh5xfyauss0" path="res://sources/ui/Popup.tscn" id="7_jetb7"] [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/LoadingPopup.tscn" id="10_i488h"] [node name="TeacherSettings" type="Control"] layout_mode = 3 @@ -212,6 +213,9 @@ content_text = "SYNC_CHOICE_POPUP" confirm_text_override = "SERVER_PRIORITY" cancel_text_override = "LOCAL_PRIORITY" +[node name="LoadingPopup" parent="." instance=ExtResource("10_i488h")] +unique_name_in_owner = true + [connection signal="pressed" from="InterfaceLeft/Container/BackButton" to="." method="_on_back_button_pressed"] [connection signal="pressed" from="InterfaceLeft/Container/SynchronizeButton" to="." method="_on_synchronize_button_pressed"] [connection signal="accepted" from="InterfaceLeft/Container/SynchronizeButton/DeletePopup" to="." method="_on_delete_popup_accepted"] @@ -228,3 +232,5 @@ cancel_text_override = "LOCAL_PRIORITY" [connection signal="accepted" from="DeleteStudentPopup" to="." method="_on_delete_student_popup_accepted"] [connection signal="accepted" from="SyncChoicePopup" to="." method="_on_sync_choice_server"] [connection signal="refused" from="SyncChoicePopup" to="." method="_on_sync_choice_local"] +[connection signal="cancel" from="LoadingPopup" to="." method="_on_loading_popup_cancel"] +[connection signal="ok" from="LoadingPopup" to="." method="_on_loading_popup_ok"] diff --git a/sources/ui/LoadingPopup.gd b/sources/ui/LoadingPopup.gd new file mode 100644 index 00000000..e7ae38dd --- /dev/null +++ b/sources/ui/LoadingPopup.gd @@ -0,0 +1,58 @@ +@tool +extends CanvasLayer +class_name LoadingPopup + +signal cancel +signal ok + +@export_multiline var content_text: String = "": set = _set_content_text + +@onready var content_label: Label = %ContentLabel +@onready var progress_bar: ProgressBar = %ProgressBar + +@onready var cancel_button: Button = %CancelButton +@onready var ok_button: Button = %OKButton + +@export var cancel_text_override: String = "" + + +func set_progress(percent: float) -> void: + progress_bar.value = percent + if percent >= 100.0: + cancel_button.hide() + ok_button.show() + + +func set_finished(finished: bool) -> void: + if finished: + cancel_button.hide() + ok_button.show() + else: + ok_button.hide() + cancel_button.show() + + +func _ready() -> void: + _set_content_text(content_text) + if cancel_text_override != "": + _set_cancel_text(cancel_text_override) + + +func _set_content_text(p_content_text: String) -> void: + content_text = p_content_text + if content_label: + content_label.text = content_text + + +func _set_cancel_text(p_content_text: String) -> void: + cancel_button.text = p_content_text + + +func _on_cancel_button_pressed() -> void: + cancel.emit() + hide() + + +func _on_ok_button_pressed() -> void: + ok.emit() + hide() diff --git a/sources/ui/LoadingPopup.gd.uid b/sources/ui/LoadingPopup.gd.uid new file mode 100644 index 00000000..f58c4dd1 --- /dev/null +++ b/sources/ui/LoadingPopup.gd.uid @@ -0,0 +1 @@ +uid://bmv36ejdmk3hc diff --git a/sources/ui/LoadingPopup.tscn b/sources/ui/LoadingPopup.tscn new file mode 100644 index 00000000..bb0c38e8 --- /dev/null +++ b/sources/ui/LoadingPopup.tscn @@ -0,0 +1,103 @@ +[gd_scene load_steps=5 format=3 uid="uid://dhowigt8un22u"] + +[ext_resource type="Script" uid="uid://bmv36ejdmk3hc" path="res://sources/ui/LoadingPopup.gd" id="1_edhv8"] +[ext_resource type="Theme" uid="uid://dqjvrt5nrtwn1" path="res://resources/themes/kalulu_theme.tres" id="2_t7x2v"] + +[sub_resource type="Gradient" id="Gradient_22q4u"] +colors = PackedColorArray(0.2, 0.2, 0.2, 0.505882, 0.2, 0.2, 0.2, 0.505882) + +[sub_resource type="GradientTexture1D" id="GradientTexture1D_ymust"] +gradient = SubResource("Gradient_22q4u") + +[node name="LoadingPopup" type="CanvasLayer"] +script = ExtResource("1_edhv8") + +[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_ymust") + +[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 = 20 + +[node name="ContentLabel" type="Label" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(1000, 0) +layout_mode = 2 +size_flags_vertical = 1 +theme = ExtResource("2_t7x2v") +theme_type_variation = &"HeaderMedium" +text = "CONTENT TEXT" +autowrap_mode = 2 + +[node name="ProgressBar" type="ProgressBar" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"] +unique_name_in_owner = true +custom_minimum_size = Vector2(0, 70) +layout_mode = 2 +theme = ExtResource("2_t7x2v") +value = 25.0 + +[node name="HBoxContainer" type="HBoxContainer" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer"] +layout_mode = 2 + +[node name="VSeparatorLeft" type="VSeparator" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 +theme = ExtResource("2_t7x2v") + +[node name="OKButton" type="Button" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +visible = false +layout_mode = 2 +size_flags_horizontal = 4 +theme = ExtResource("2_t7x2v") +theme_type_variation = &"DangerButton" +theme_override_font_sizes/font_size = 50 +text = "OK" + +[node name="CancelButton" type="Button" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 4 +theme = ExtResource("2_t7x2v") +theme_type_variation = &"DangerButton" +theme_override_font_sizes/font_size = 50 +text = "CANCEL" + +[node name="VSeparatorRight" type="VSeparator" parent="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer"] +layout_mode = 2 +size_flags_horizontal = 3 + +[connection signal="pressed" from="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/OKButton" to="." method="_on_ok_button_pressed"] +[connection signal="pressed" from="TextureRect/PanelContainer/VBoxContainer/MarginContainer/VBoxContainer/HBoxContainer/CancelButton" to="." method="_on_cancel_button_pressed"]