Show soundtrack covers and edit alternative names (#49)
Build / test (push) Successful in 1m43s
Build / build (push) Successful in 1m14s

Covers: statistics cards show the soundtrack's cover on the left, and the
statistics popup shows it large. Until it arrives, and without a cover, the
soundtrack's initials stand in. Covers load only for cards on or near the
screen, three at a time, and are cached in covers/ next to the settings
(CoverCache), downloaded again only when cover_modified changes. The index and
file handling are shared with CharacterCache in a new FileCache.

Alternative names: the popup shows them and has an editor (add, remove, save)
that sends PUT /soundtracks/{uuid}/alternative-names. The statistics search and
the Search popup find soundtracks by them; Search shows the matching name after
the real one. Search now loads /soundtracks, falling back to the plain list.

The API types are regenerated from the server's spec, with a SoundtrackCover
theme style in every theme.

Closes #49

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
SansanandClaude Opus 5.5 committed 2026-10-14 22:06:30 +02:00
1 parent a735c515bf
commit ef6ac8f1fd
37 files changed
+8029 -1763

No files matched your search

+4
View File
@@ -25,6 +25,9 @@ var requested_paths: Array[String] = []
var requested_methods: Array[int] = []
## Headers of each request, in the same order as [member requested_paths].
var requested_headers: Array[PackedStringArray] = []
## The JSON body of each request, empty for none, in the same order as
## [member requested_paths].
var requested_bodies: Array[String] = []
## How many tokens have been asked for.
var token_requests: int = 0
## The JSON body of the last token request.
@@ -120,6 +123,7 @@ func request(
requested_paths.append(path)
requested_methods.append(method)
requested_headers.append(headers)
requested_bodies.append(body)
if !OPEN_PATHS.has(path.get_slice("?", 0)) && !_has_valid_token(headers):
on_complete.call(401, JSON.stringify({"error": "Unauthorized"}).to_utf8_buffer(),
PackedStringArray())
+16
View File
@@ -91,6 +91,12 @@ static func make_server() -> FakeHttpTransport:
server.respond_bytes("/sync", PackedByteArray())
server.respond_json("/sync/progress", SYNC_PROGRESS)
server.respond_json("/statistics/soundtracks", soundtrack_statistics())
# The character pictures stand in for covers
var pictures: Array[String] = character_names()
for i: int in SOUNDTRACKS.size():
server.respond_bytes("/soundtracks/soundtrack-%d/cover" % i,
FileAccess.get_file_as_bytes(CHARACTERS_DIR.path_join(
pictures[i % pictures.size()])))
server.respond_json("/version/history", SERVER_HISTORY)
return server
@@ -118,6 +124,11 @@ static func soundtrack_statistics() -> Array[Dictionary]:
}
if played > 0:
soundtrack.soundtrack_last_played = "2026-09-%02dT20:00:00Z" % (i + 1)
# Every other soundtrack has a cover, the rest show their initials
if i % 2 == 0:
soundtrack.cover_modified = 1700000000
if i == 0:
soundtrack.alternative_names = ["CT", "クロノ・トリガー"]
statistics.append(soundtrack)
return statistics
@@ -292,6 +303,11 @@ func run(on_state: Callable) -> void:
break
await _settle()
await on_state.call("popup_SoundtrackStats", stats_popup)
stats_popup.edit_names()
stats_popup.new_name_field.text = "Chrono"
await _settle()
await on_state.call("popup_SoundtrackStats_names", stats_popup)
stats_popup.stop_editing()
stats_popup.close()
_main.show_tab(&"quiz")
await _settle()