Add a Statistics tab with a card for every soundtrack
Build / test (push) Successful in 40s
Build / build (push) Successful in 1m16s

Part of #41. The top bar has Quiz and Statistics tabs instead of the
Statistics button. The Statistics tab replaces the quiz below the top bar
(the song keeps playing) and shows every soundtrack as a card with its
plays, last played date and most and least played songs, loaded from the
new GET /api/v1/statistics/soundtracks. The cards can be searched (with
the Search popup's matching, now in SoundtrackSearch), filtered on played
or never played, and sorted A-Z, Z-A, most or least played. Clicking a
card opens a popup with all its songs.

Screenshots of the other states only differ in the top bar, and the
layout baseline is taken again with the new statistics states.
This commit is contained in:
Sansan committed 2026-10-06 23:33:00 +02:00
1 parent f7619baf34
commit a21b6e9b22
30 files changed
+25379 -2306

No files matched your search

+14 -23
View File
@@ -9,6 +9,8 @@
[ext_resource type="PackedScene" uid="uid://btupbowehiyyu" path="res://popups/QRPopup.tscn" id="15_qr_window"]
[ext_resource type="PackedScene" uid="uid://cp54idaudb8dp" path="res://popups/AboutPopup.tscn" id="16_about_window"]
[ext_resource type="PackedScene" uid="uid://bijh5h5yrivm3" path="res://popups/LogPopup.tscn" id="14_26rwn"]
[ext_resource type="PackedScene" path="res://statistics/StatisticsView.tscn" id="statistics_view_scene"]
[ext_resource type="PackedScene" path="res://popups/SoundtrackStatsPopup.tscn" id="soundtrack_stats_popup_scene"]
[node name="MainWindow" type="Control" unique_id=407149696]
layout_mode = 3
@@ -33,6 +35,10 @@ theme_type_variation = &"WindowBackground"
[node name="Quiz" parent="." unique_id=1357908642 instance=ExtResource("quiz_scene")]
[node name="StatisticsView" parent="." unique_id=1212999001 instance=ExtResource("statistics_view_scene")]
visible = false
layout_mode = 1
[node name="SearchPopup" parent="." unique_id=1661250375 instance=ExtResource("9_5ijvr")]
visible = false
layout_mode = 1
@@ -68,29 +74,6 @@ offset_top = 160.0
offset_right = 1262.0
offset_bottom = 860.0
[node name="StatisticsPopupPanel" type="PopupPanel" parent="." unique_id=298311407]
oversampling_override = 1.0
initial_position = 2
size = Vector2i(450, 100)
[node name="Label" type="Label" parent="StatisticsPopupPanel" unique_id=548316493]
offset_left = 4.0
offset_top = 4.0
offset_right = 446.0
offset_bottom = 96.0
text = "Statistics"
horizontal_alignment = 1
[node name="StatisticsLabel" type="Label" parent="StatisticsPopupPanel" unique_id=58226477]
unique_name_in_owner = true
offset_left = 4.0
offset_top = 4.0
offset_right = 446.0
offset_bottom = 96.0
text = "Total amount of soundtracks in the playlist: 9000"
horizontal_alignment = 1
vertical_alignment = 1
[node name="AboutPopup" parent="." unique_id=141261008 instance=ExtResource("16_about_window")]
unique_name_in_owner = true
visible = false
@@ -108,3 +91,11 @@ offset_left = 562.0
offset_top = 132.0
offset_right = 1262.0
offset_bottom = 832.0
[node name="SoundtrackStatsPopup" parent="." unique_id=1213999001 instance=ExtResource("soundtrack_stats_popup_scene")]
visible = false
layout_mode = 1
offset_left = 610.0
offset_top = 140.0
offset_right = 610.0
offset_bottom = 140.0
+29 -10
View File
@@ -10,6 +10,8 @@ keycode = 83
[sub_resource type="Shortcut" id="Shortcut_fbju4"]
events = [SubResource("InputEventKey_ujjlu")]
[sub_resource type="ButtonGroup" id="ButtonGroup_tabs"]
[node name="TopBar" type="Control" unique_id=1489162753]
layout_mode = 3
anchors_preset = 10
@@ -55,16 +57,6 @@ action_mode = 0
shortcut = SubResource("Shortcut_fbju4")
text = "Search"
[node name="StatisticsButton" type="Button" parent="." unique_id=2045021269]
layout_mode = 0
offset_left = 1530.0
offset_top = 8.0
offset_right = 1600.0
offset_bottom = 48.0
focus_mode = 0
action_mode = 0
text = "Statistics"
[node name="ShortcutsButton" type="Button" parent="." unique_id=2066498226]
layout_mode = 0
offset_left = 1626.0
@@ -94,3 +86,30 @@ offset_bottom = 48.0
focus_mode = 0
action_mode = 0
text = "QR"
[node name="QuizTab" type="Button" parent="." unique_id=1903412671]
layout_mode = 0
offset_left = 840.0
offset_top = 8.0
offset_right = 955.0
offset_bottom = 48.0
focus_mode = 0
theme_type_variation = &"TabButton"
toggle_mode = true
button_pressed = true
action_mode = 0
button_group = SubResource("ButtonGroup_tabs")
text = "Quiz"
[node name="StatisticsTab" type="Button" parent="." unique_id=1903412672]
layout_mode = 0
offset_left = 965.0
offset_top = 8.0
offset_right = 1080.0
offset_bottom = 48.0
focus_mode = 0
theme_type_variation = &"TabButton"
toggle_mode = true
action_mode = 0
button_group = SubResource("ButtonGroup_tabs")
text = "Statistics"
+20 -12
View File
@@ -1,9 +1,9 @@
class_name MainWindow
extends Control
## The main window: the top bar, the popups opened from it and the quiz below it.
## The main window: the top bar, the popups opened from it, and below it the quiz or the
## statistics, depending on the chosen tab.
##
## Everything that is not part of a quiz lives here, so other views can be added next
## to the quiz later.
## Everything that is not part of a quiz lives here.
## Dims the window behind an open popup and keeps clicks from reaching the buttons under it.
var popup_backdrop: PopupBackdrop
@@ -16,8 +16,8 @@ var popup_backdrop: PopupBackdrop
@onready var qr_popup: QRPopup = %QRPopup
@onready var about_popup: AboutPopup = %AboutPopup
@onready var log_popup: LogPopup = %LogPopup
@onready var statistic_popup: PopupPanel = $StatisticsPopupPanel
@onready var statistic_label: Label = %StatisticsLabel
@onready var statistics_view: StatisticsView = $StatisticsView
@onready var soundtrack_stats_popup: SoundtrackStatsPopup = $SoundtrackStatsPopup
func _ready() -> void:
@@ -26,7 +26,7 @@ func _ready() -> void:
GameLog.debug("is_mac")
top_bar.search_pressed.connect(show_search)
top_bar.sync_pressed.connect(sync_soundtracks)
top_bar.statistics_pressed.connect(get_statistics)
top_bar.tab_selected.connect(show_tab)
top_bar.shortcuts_pressed.connect(show_shortcuts)
top_bar.about_pressed.connect(show_about)
top_bar.qr_pressed.connect(show_qr)
@@ -35,6 +35,7 @@ func _ready() -> void:
sync_popup.sync_finished.connect(_on_sync_finished)
quiz.server_changed.connect(search_popup.get_list_of_soundtracks)
quiz.event_logged.connect(log_popup.add_log_row)
statistics_view.soundtrack_selected.connect(soundtrack_stats_popup.show_soundtrack)
search_popup.get_list_of_soundtracks()
@@ -55,7 +56,8 @@ func _input(event: InputEvent) -> void:
func _popups() -> Array[BasePopup]:
return [search_popup, sync_popup, qr_popup, shortcuts_popup, about_popup, log_popup]
return [search_popup, sync_popup, qr_popup, shortcuts_popup, about_popup, log_popup,
soundtrack_stats_popup]
func show_search() -> void:
@@ -78,11 +80,15 @@ func show_qr() -> void:
qr_popup.open()
func get_statistics() -> void:
GameLog.debug("get_statistics")
statistic_popup.visible = true
statistic_label.text = "Total amount of soundtracks in the playlist: " \
+ str(search_popup.soundtracks.size())
## Shows the quiz for [code]&"quiz"[/code] or the statistics for [code]&"statistics"[/code].
## A hidden quiz keeps playing its song.
func show_tab(tab: StringName) -> void:
GameLog.debug("show_tab ", tab)
top_bar.select_tab(tab)
statistics_view.visible = tab == &"statistics"
quiz.visible = !statistics_view.visible
if statistics_view.visible:
statistics_view.refresh()
func sync_soundtracks() -> void:
@@ -100,3 +106,5 @@ func _on_sync_finished() -> void:
GameLog.debug("_on_sync_finished")
search_popup.get_list_of_soundtracks()
quiz.on_sync_finished()
if statistics_view.visible:
statistics_view.refresh()
+14 -4
View File
@@ -1,22 +1,32 @@
class_name TopBar
extends Control
## The bar along the top of the main window, with the title and the buttons for things
## that are not part of a quiz.
## The bar along the top of the main window, with the title, the Quiz and Statistics tabs
## and the buttons for things that are not part of a quiz.
signal search_pressed
signal sync_pressed
signal statistics_pressed
signal shortcuts_pressed
signal about_pressed
signal qr_pressed
## Emitted when a tab is chosen: [code]&"quiz"[/code] or [code]&"statistics"[/code].
signal tab_selected(tab: StringName)
@onready var sync_button: Button = $SyncButton
@onready var quiz_tab: Button = $QuizTab
@onready var statistics_tab: Button = $StatisticsTab
func _ready() -> void:
$SearchButton.pressed.connect(search_pressed.emit)
sync_button.pressed.connect(sync_pressed.emit)
$StatisticsButton.pressed.connect(statistics_pressed.emit)
$ShortcutsButton.pressed.connect(shortcuts_pressed.emit)
$AboutButton.pressed.connect(about_pressed.emit)
$QRButton.pressed.connect(qr_pressed.emit)
quiz_tab.pressed.connect(tab_selected.emit.bind(&"quiz"))
statistics_tab.pressed.connect(tab_selected.emit.bind(&"statistics"))
## Shows [param tab] as the chosen tab, without emitting [signal tab_selected].
func select_tab(tab: StringName) -> void:
quiz_tab.set_pressed_no_signal(tab == &"quiz")
statistics_tab.set_pressed_no_signal(tab == &"statistics")