Merge develop into feature/50-upload-soundtrack
Build / test (pull_request) Successful in 2m3s
Build / build (pull_request) Skipped

The API spec is now formatted like before (2-space indents, sorted keys):
develop's spec with the upload paths and types added, so the diff to
develop is only the upload API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SansanandClaude Opus 5.5 committed 2026-10-16 11:29:18 +02:00
commit 8263781abc
20 files changed
+5661 -45

No files matched your search

+292 -22
View File
@@ -3965,7 +3965,7 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
@@ -3974,7 +3974,34 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
230.0,
228.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
230.0,
228.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
230.0,
228.0,
1300.0,
32.0
],
"visible": false
},
@@ -11977,7 +12004,7 @@
230.0,
310.0,
1460.0,
27.0
32.0
],
"visible": false
},
@@ -11986,7 +12013,34 @@
310.0,
310.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
310.0,
310.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
310.0,
310.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
310.0,
310.0,
1300.0,
32.0
],
"visible": false
},
@@ -16983,7 +17037,7 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
@@ -16992,7 +17046,34 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
230.0,
228.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
230.0,
228.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
230.0,
228.0,
1300.0,
32.0
],
"visible": false
},
@@ -21854,7 +21935,7 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
@@ -21863,7 +21944,34 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
230.0,
228.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
230.0,
228.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
230.0,
228.0,
1300.0,
32.0
],
"visible": false
},
@@ -27246,7 +27354,7 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
@@ -27255,7 +27363,34 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
230.0,
228.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
230.0,
228.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
230.0,
228.0,
1300.0,
32.0
],
"visible": false
},
@@ -33456,7 +33591,7 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
@@ -33465,7 +33600,34 @@
230.0,
228.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
230.0,
228.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
230.0,
228.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
230.0,
228.0,
1300.0,
32.0
],
"visible": false
},
@@ -50019,7 +50181,7 @@
230.0,
228.0,
1460.0,
109.0
114.0
],
"visible": false
},
@@ -50055,7 +50217,7 @@
230.0,
310.0,
1460.0,
27.0
32.0
],
"visible": false
},
@@ -50064,7 +50226,34 @@
310.0,
310.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
310.0,
310.0,
522.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
310.0,
310.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
310.0,
310.0,
1300.0,
32.0
],
"visible": false
},
@@ -50696,7 +50885,7 @@
230.0,
228.0,
1460.0,
109.0
114.0
],
"visible": true
},
@@ -50732,7 +50921,7 @@
230.0,
310.0,
1460.0,
27.0
32.0
],
"visible": true
},
@@ -50741,7 +50930,34 @@
310.0,
310.0,
1300.0,
27.0
32.0
],
"visible": true
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
310.0,
310.0,
522.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
310.0,
310.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
310.0,
310.0,
1300.0,
32.0
],
"visible": true
},
@@ -50986,7 +51202,7 @@
230.0,
310.0,
1460.0,
27.0
32.0
],
"visible": false
},
@@ -50995,7 +51211,34 @@
310.0,
310.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
310.0,
310.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
310.0,
310.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
310.0,
310.0,
1300.0,
32.0
],
"visible": false
},
@@ -55524,7 +55767,7 @@
230.0,
310.0,
1460.0,
27.0
32.0
],
"visible": false
},
@@ -55533,7 +55776,34 @@
310.0,
310.0,
1300.0,
27.0
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0": {
"rect": [
310.0,
310.0,
0.0,
32.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#0/#0": {
"rect": [
310.0,
310.0,
0.0,
0.0
],
"visible": false
},
"SyncPopup/SyncPanel/ScrollContainer/SyncVBoxContainer/ProgressHBoxContainer/SyncProgressBar/#1": {
"rect": [
310.0,
310.0,
1300.0,
32.0
],
"visible": false
},
+2 -2
View File
@@ -18,7 +18,7 @@ const SONG_INFO: Dictionary = {
"SongNo": 0, "Soundtrack": "Chrono Trigger", "SoundtrackUuid": "soundtrack-0",
"Song": "Corridors of Time",
}
const SYNC_PROGRESS: Dictionary = {"progress": 40, "time_spent": "00:00:02"}
const SYNC_PROGRESS: Dictionary = {"progress": 40, "time_spent": "00:02"}
const SYNC_RESULT: Dictionary = {
"soundtracks_added": ["Terranigma", "Lufia II"],
"soundtracks_re_added": [],
@@ -26,7 +26,7 @@ const SYNC_RESULT: Dictionary = {
"soundtracks_changed_content": ["Chrono Trigger"],
"soundtracks_removed": ["Old Soundtrack"],
"catched_errors": [],
"total_time": "00:00:03",
"total_time": "00:03",
}
## The server's version history, newest first.
+1 -1
View File
@@ -226,7 +226,7 @@ func test_click_on_top_bar_while_quiz_popup_is_open_only_closes_it() -> void:
func test_sync_disables_quiz_buttons_until_finished() -> void:
_server.respond_bytes("/sync", PackedByteArray())
_server.respond_json("/sync/progress", {"progress": 10, "time_spent": "00:00:01"})
_server.respond_json("/sync/progress", {"progress": 10, "time_spent": "00:01"})
var sync_popup: BasePopup = _window.get_node("SyncPopup")
_top_bar_button("SyncButton").pressed.emit()
+23 -4
View File
@@ -10,6 +10,8 @@ var _window: Control
func before_test() -> void:
_snapshot = AutoloadSnapshot.take([Settings])
Settings.currently_syncing = false
# The bar jumps to its values and the result shows at once
Settings.reduce_animations = true
_server = FakeHttpTransport.new().install()
_server.respond_bytes("/sync", PackedByteArray())
_runner = scene_runner("res://popups/SyncPopup.tscn")
@@ -38,7 +40,7 @@ func _empty_result() -> Dictionary:
"soundtracks_changed_content": [],
"soundtracks_removed": [],
"catched_errors": [],
"total_time": "00:00:03",
"total_time": "00:03",
}
@@ -64,12 +66,29 @@ func test_start_sync_does_nothing_while_already_syncing() -> void:
func test_progress_updates_progress_bar() -> void:
_runner.invoke("start_sync")
_server.respond_json("/sync/progress", {"progress": "42", "time_spent": "00:00:12"})
_server.respond_json("/sync/progress", {"progress": "42", "time_spent": "00:12"})
_runner.invoke("_on_sync_timeout")
assert_float(_node("SyncProgressBar").value).is_equal(42.0)
assert_str(_node("SyncTime").text).is_equal("00:00:12")
assert_str(_node("SyncTime").text).is_equal("00:12")
func test_finished_sync_fills_the_bar_before_the_result() -> void:
Settings.reduce_animations = false
_runner.invoke("start_sync")
var bar: AnimatedProgressBar = _node("SyncProgressBar")
assert_bool(bar.indeterminate).is_true()
_finish_sync(_empty_result())
assert_bool(_node("ProgressHBoxContainer").visible).is_true()
await await_millis(int(Anim.SLOW * 1000) + 100)
assert_float(bar.value).is_equal(100.0)
assert_bool(_node("ProgressHBoxContainer").visible).is_true()
await await_millis(int(Anim.SLOW * 1000) + 100)
assert_bool(_node("ProgressHBoxContainer").visible).is_false()
assert_str(_node("SyncTitleLabel").text).is_equal("Sync Result")
func test_finished_sync_shows_only_sections_with_changes() -> void:
@@ -88,7 +107,7 @@ func test_finished_sync_shows_only_sections_with_changes() -> void:
assert_bool(_node("NoChangesLabel").visible).is_false()
# Header plus one label per soundtrack
assert_int(_node("SoundtracksAddedVBox").get_child_count()).is_equal(3)
assert_str(_node("SyncTime").text).is_equal("Total time: 00:00:03")
assert_str(_node("SyncTime").text).is_equal("Total time: 00:03")
assert_bool(Settings.currently_syncing).is_false()
await assert_signal(_window).is_emitted("sync_finished")
+4
View File
@@ -48,6 +48,9 @@ const STYLES: Dictionary = {
"PlayerTime": "Label",
"PlayerIcon": "Button",
"UpdateButton": "Button",
"SyncProgressBar": "ProgressBar",
"SyncProgressBarFill": "Panel",
"SyncProgressBarText": "Label",
"ProgressSlider": "HSlider",
"VolumeBar": "HSlider",
"StatisticsCard": "PanelContainer",
@@ -67,6 +70,7 @@ const STYLES: Dictionary = {
## Theme types that only scripts read from, so they are not styles a node can pick.
const CODE_ONLY_TYPES: Dictionary = {
"Palette": ["backdrop", "first_point", "match_point", "flash"],
"SyncProgressBar": ["shine"],
"ScoreGraph": [
"player_1", "player_2", "player_3", "player_4", "player_5", "player_6", "player_7",
"grid", "axis_text", "winning_line",
+88
View File
@@ -0,0 +1,88 @@
extends GdUnitTestSuite
## The sync popup's progress bar: busy until there is progress, gliding to new values,
## a highlight on the filled part, and plain jumps with Reduce animations.
var _runner: GdUnitSceneRunner
var _bar: AnimatedProgressBar
var _reduce_before: bool
func before_test() -> void:
_reduce_before = Settings.reduce_animations
Settings.reduce_animations = false
var holder: Control = auto_free(Control.new())
holder.size = Vector2(1000, 100)
_bar = AnimatedProgressBar.new()
_bar.theme_type_variation = &"SyncProgressBar"
_bar.size = Vector2(1000, 32)
holder.add_child(_bar)
_runner = scene_runner(holder)
await _runner.simulate_frames(1)
func after_test() -> void:
Settings.reduce_animations = _reduce_before
func _label() -> Label:
return _bar.get_child(1) as Label
func test_waits_with_the_busy_animation() -> void:
_bar.wait()
assert_bool(_bar.indeterminate).is_true()
assert_str(_label().text).is_empty()
func test_progress_ends_the_wait_and_glides() -> void:
_bar.wait()
_bar.move_to(40)
assert_bool(_bar.indeterminate).is_false()
assert_float(_bar.value).is_less(40.0)
await await_millis(int(Anim.SLOW * 1000) + 150)
assert_float(_bar.value).is_equal(40.0)
assert_str(_label().text).is_equal("40%")
func test_reduce_animations_jumps_and_never_waits() -> void:
Settings.reduce_animations = true
_bar.wait()
assert_bool(_bar.indeterminate).is_false()
_bar.move_to(75)
assert_float(_bar.value).is_equal(75.0)
assert_str(_label().text).is_equal("75%")
func test_highlight_stays_on_the_filled_part() -> void:
Settings.reduce_animations = true
_bar.move_to(50)
Settings.reduce_animations = false
await _runner.simulate_frames(3)
var mask: Control = _bar.get_child(0)
assert_bool(mask.visible).is_true()
assert_float(mask.size.x).is_equal(_bar.fill_width())
assert_float(_bar.fill_width()).is_between(490.0, 510.0)
func test_no_highlight_without_progress_or_animations() -> void:
await _runner.simulate_frames(2)
assert_bool((_bar.get_child(0) as Control).visible).is_false()
Settings.reduce_animations = true
_bar.move_to(50)
await _runner.simulate_frames(2)
assert_bool((_bar.get_child(0) as Control).visible).is_false()
func test_highlight_takes_the_themes_colour() -> void:
var shine: TextureRect = _bar.get_child(0).get_child(0)
var gradient: Gradient = (shine.texture as GradientTexture2D).gradient
assert_object(gradient.get_color(1)).is_equal(_bar.get_theme_color(&"shine"))
assert_float(gradient.get_color(0).a).is_equal(0.0)
@@ -0,0 +1 @@
uid://bgb6no4urwpc7
+4 -4
View File
@@ -118,7 +118,7 @@ func test_sync_response() -> void:
"soundtracks_added": ["Terranigma"], "soundtracks_re_added": [],
"soundtracks_changed_title": {"FF6": "Final Fantasy VI"},
"soundtracks_changed_content": ["Chrono Trigger"], "soundtracks_removed": ["Old"],
"catched_errors": ["Could not read x.mp3"], "total_time": "00:00:03"}"""))
"catched_errors": ["Could not read x.mp3"], "total_time": "00:03"}"""))
assert_array(result.soundtracks_added).contains_exactly(["Terranigma"])
assert_array(result.soundtracks_re_added).is_empty()
@@ -126,15 +126,15 @@ func test_sync_response() -> void:
assert_array(result.soundtracks_changed_content).contains_exactly(["Chrono Trigger"])
assert_array(result.soundtracks_removed).contains_exactly(["Old"])
assert_array(result.catched_errors).contains_exactly(["Could not read x.mp3"])
assert_str(result.total_time).is_equal("00:00:03")
assert_str(result.total_time).is_equal("00:03")
func test_progress_response() -> void:
var progress: ProgressResponse = ProgressResponse.from_dict(_parse("""{
"progress": "40", "time_spent": "00:00:02"}"""))
"progress": "40", "time_spent": "00:02"}"""))
assert_str(progress.progress).is_equal("40")
assert_str(progress.time_spent).is_equal("00:00:02")
assert_str(progress.time_spent).is_equal("00:02")
func test_version_data() -> void: