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.
125 lines
3.2 KiB
GDScript
125 lines
3.2 KiB
GDScript
class_name SearchPopup
|
|
extends BasePopup
|
|
## Searches every soundtrack on the server as you type, with [SoundtrackSearch].
|
|
|
|
var soundtracks: Array = []
|
|
var label_pool: Array[Label] = []
|
|
|
|
var _matcher: SoundtrackSearch = SoundtrackSearch.new()
|
|
|
|
@onready var search_list: VBoxContainer = %SearchResults
|
|
@onready var search_panel: Panel = %SearchPanel
|
|
@onready var clear_button: Button = $ClearButton
|
|
@onready var search_bar: TextEdit = $Searchbar
|
|
|
|
|
|
func _ready() -> void:
|
|
clear_button.pressed.connect(clear)
|
|
search_bar.grab_focus()
|
|
search_bar.text_changed.connect(search)
|
|
visibility_changed.connect(focus)
|
|
|
|
|
|
func focus() -> void:
|
|
if visible:
|
|
search_bar.grab_focus()
|
|
clear()
|
|
|
|
|
|
func close() -> void:
|
|
clear()
|
|
super()
|
|
|
|
|
|
func search() -> void:
|
|
GameLog.debug(search_bar.text)
|
|
var search_text: String = search_bar.text
|
|
|
|
if search_text == "":
|
|
show_all_soundtracks()
|
|
return
|
|
|
|
perform_search(search_text)
|
|
|
|
|
|
func show_all_soundtracks() -> void:
|
|
# Hide all visible labels and add to pool
|
|
for child: Label in search_list.get_children():
|
|
if child.visible:
|
|
child.visible = false
|
|
label_pool.append(child)
|
|
|
|
# Show all soundtracks in order
|
|
for soundtrack: String in soundtracks:
|
|
add_soundtrack_reuse(soundtrack)
|
|
|
|
|
|
func perform_search(search_text: String) -> void:
|
|
# Hide all visible labels and add to pool
|
|
for child: Label in search_list.get_children():
|
|
if child.visible:
|
|
child.visible = false
|
|
label_pool.append(child)
|
|
|
|
for soundtrack: String in _matcher.find_matches(search_text):
|
|
add_soundtrack_reuse(soundtrack)
|
|
|
|
|
|
func add_soundtrack(soundtrack: String) -> void:
|
|
# Backward compatibility - delegates to reuse version
|
|
add_soundtrack_reuse(soundtrack)
|
|
|
|
|
|
## Shows [param soundtrack], reusing a hidden label from the pool when there is one.
|
|
func add_soundtrack_reuse(soundtrack: String) -> void:
|
|
var label: Label
|
|
if label_pool.size() > 0:
|
|
label = label_pool.pop_front()
|
|
label.text = soundtrack
|
|
label.visible = true
|
|
# Move to end to maintain display order
|
|
search_list.move_child(label, search_list.get_child_count() - 1)
|
|
else:
|
|
label = Label.new()
|
|
label.text = soundtrack
|
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
|
search_list.add_child(label)
|
|
label.visible = true
|
|
|
|
|
|
func check_if_soundtrack_exists(soundtrack: String) -> bool:
|
|
var soundtrack_exists: bool = false
|
|
for child: Label in search_list.get_children():
|
|
if child.text == soundtrack and child.visible:
|
|
soundtrack_exists = true
|
|
return soundtrack_exists
|
|
|
|
|
|
func get_list_of_soundtracks() -> void:
|
|
GameLog.debug("get_list_of_soundtracks")
|
|
var handle_soundtracks: Callable = func handle_soundtracks(array: Variant) -> void:
|
|
if typeof(array) == TYPE_ARRAY:
|
|
# Reuse existing labels: hide all and add to pool
|
|
for child: Label in search_list.get_children():
|
|
child.visible = false
|
|
label_pool.append(child)
|
|
set_soundtracks(array)
|
|
for soundtrack: String in soundtracks:
|
|
add_soundtrack_reuse(soundtrack)
|
|
else:
|
|
GameLog.warning("Unexpected data")
|
|
MusicServerClient.fetch_all_soundtracks_ordered(handle_soundtracks)
|
|
|
|
|
|
## Replaces the searchable soundtracks.
|
|
func set_soundtracks(list: Array) -> void:
|
|
soundtracks = []
|
|
soundtracks.append_array(list)
|
|
_matcher.set_names(soundtracks)
|
|
|
|
|
|
func clear() -> void:
|
|
search_bar.text = ""
|
|
show_all_soundtracks()
|
|
search_bar.grab_focus()
|