Commit Graph
1063 Commits
Author SHA1 Message Date
austinried fdb3e7ec0a tools: read the GitLab token from GL_TOKEN 2026-10-04 00:30:08 +00:00
austinried 774ac34bae tools: add a submit script for the F-Droid recipe
The fdroiddata recipe is now kept in tools/fdroid/ as the source of truth. tools/fdroid-submit.nu pushes it to the fork and opens the merge request via the GitLab API, so no fdroiddata clone or manual web editing is needed. Also runnable from a Forgejo Actions workflow_dispatch.
2026-10-04 00:30:08 +00:00
austinried 673e492765 docs: centre the screenshots and show five 2026-10-04 00:30:08 +00:00
austinried 94498d71e4 metadata: mirror the README feature list in the store description 2026-10-04 00:30:08 +00:00
austinried 4333522256 docs: rebuild the README for the native rewrite 2026-10-04 00:30:08 +00:00
austinried 5d9d9e5d7e brand: refresh the app icon, logo and feature graphic 2026-10-04 00:30:08 +00:00
austinried cdba272f98 metadata: harden the screenshot generator and changelog test
Only cache a cover after a successful response and drop the file if decoding
fails, so a transient error cannot poison the cache permanently. Fail with a
clear message instead of a bare NoSuchElementException when a demo album has
no songs or the artist list is empty, and normalize line endings before the
changelog length check.
2026-10-04 00:30:08 +00:00
austinried e34363c1ac metadata: show the cross-library search screenshot
Render the dedicated SearchScreen with results across playlists, artists and
albums instead of the album tab's in-list search.
2026-10-04 00:30:08 +00:00
austinried 8e6c1593dc metadata: say Subsonic-compatible and use lowercase subtracks
Drop the "API" from the server compatibility wording, and lowercase the brand
in the title, description, old changelog and the app name to match the logo.
2026-10-04 00:30:08 +00:00
austinried 4bf34ea20a Add a test for the 500-char changelog limit
Both F-Droid and Google Play cap release notes at 500 characters. Check every
metadata changelog in the unit test suite (which CI already runs), and trim the
two old Flutter changelogs that were over the limit.
2026-10-04 00:30:08 +00:00
austinried 3ead9f6fb6 metadata: make the 3.0 changelog plain text under 500 chars
Neither F-Droid nor Google Play renders Markdown in release notes, and both
cap them at 500 characters. Drop the Markdown header and bullets and trim the
copy to fit.
2026-10-04 00:30:08 +00:00
austinried 5bd63d44d7 metadata: only show albums and artists that have cover art
The demo library has plenty of entries with no artwork, which render as
placeholders in the store screenshots. Filter the album and artist lists (and
the home rows) to entries the sync marked with a coverArt id, so no extra
image loads are needed to decide.
2026-10-04 00:30:08 +00:00
austinried 468451c7cb metadata: tint library screens from the playing track
The library accent follows the playback artwork (LibraryRoute derives it from
the current item), so pass the playing album instead of the first list entry,
which made the tab bar disagree with the miniplayer. Inset the miniplayer
progress bar when the tab bar is present, matching AppRoot.
2026-10-04 00:30:08 +00:00
austinried 9976fbeb20 metadata: stack the miniplayer above the library tabs
Render the miniplayer in a column below the screen instead of overlaying it, so
the library tab bar and the list-options FAB are no longer covered. Use Ugress
for the artist screen, drop Various Artists from the home artist rows, and have
the album screen play its first track so the row indicator and the miniplayer
colours match the album.
2026-10-04 00:30:08 +00:00
austinried 0e96b5872c metadata: theme each screenshot and show the miniplayer
Use a different album for the now-playing and album screens (Chillhop Winter,
My latin way) so the store shots show distinct colour schemes, tint the home
screen with the playing album so the logo pops, and render the miniplayer on
the albums, album, artists and search screens. Search now runs "chill".

The generator stages the sync into an on-disk database and caches cover bytes
under the temp dir, and only fetches full-resolution art for the covers shown
large; grid art uses the thumbnail endpoint.
2026-10-04 00:30:08 +00:00
austinried 0410ed026c metadata: show the playing album tint on the home screenshot
Tint the home screen with the artwork theme the app derives from the playing
album, so the subtracks logo and accents pick up a vivid colour (The Knife -
Shaking The Habitual) instead of the default scheme. Switch the now-playing and
album screens to The Polish Ambassador - Future, Sex, Computers, and search for
"chill" so the result grid shows the Chillhop Essentials covers.
2026-10-04 00:30:08 +00:00
austinried 7815f211e4 metadata: render phone screenshots from the Navidrome demo library
Replace the placeholder-art screenshots with renders of a real library, so the
store listing shows real album and artist art and names.

The generator (DemoScreenshotTest, run with `gradle :app:demoScreenshots`) syncs
the public Navidrome demo (demo.navidrome.org) into an in-memory database using
the normal SyncService pipeline, derives the theme colours from the fetched
cover art, and renders each screen. The synced data and cover art stay in memory
and are never written to the repository; only the resulting PNGs are committed.
The test is excluded from the unit-test tasks and is not part of CI.

Also reverts the screenshot fixture palette tweak from the previous commit,
which the real art makes unnecessary.
2026-10-04 00:30:08 +00:00
austinried e7ee6fa9a2 release: bump to 3.0.0 and refresh F-Droid metadata
Bump versionCode to 13 and versionName to 3.0.0. The Flutter app ended at
2.0.0-alpha.3+12 (versionCode 12), so 13 keeps the eventual com.subtracks
release an in-place upgrade.

Metadata was still inherited from the Flutter app:
- add the changelog for versionCode 13
- rewrite the descriptions for the native app
- replace the Flutter phone screenshots with native renders, and mute the
  screenshot fixture palette so the placeholder artwork reads as covers
2026-10-04 00:30:08 +00:00
austinried 836d0636d1 search: tighten the filter bar's vertical padding 2026-10-04 00:30:08 +00:00
austinried f6e087b6ab search: list playlists before artists, albums and songs
Order the result sections smallest-first and apply the review fixes: pad
the filter bar for the navigation bar, keep at least one filter enabled,
hide the clear button on an empty field, drop the unused autoFocus and
bar-modifier parameters, and test the filter mask and section order.
2026-10-04 00:30:08 +00:00
austinried 5d81c2dc41 library: match the list options search rounding to the search field 2026-10-04 00:30:07 +00:00
austinried f54ea54566 search: outline the shared search field to match the list options entry 2026-10-04 00:30:07 +00:00
austinried 3bef469acc search: add a type filter bar and share the search field
Add a filter chip bar above the keyboard to toggle songs, albums, artists
and playlists independently, all on by default and scrolling when it
overflows. Extract one compact 48dp search field and use it in both the
cross-library screen and the library tabs.
2026-10-04 00:30:07 +00:00
austinried 12ad62813e search: localize the cross-library search strings 2026-10-04 00:30:07 +00:00
austinried b25b9deacd search: address review findings
Prefix result keys per type so ids shared across songs, albums, artists
and playlists cannot collide and crash the list; add a loading state so
a query in flight no longer reads as no results; gate on code points to
match SQLite's length(); bind the three-character floor to one constant;
label the search field for TalkBack; and drop the vacuous trigram-plan
test. Cancel the ViewModel scope in its test teardown so it cannot leak
into later Robolectric tests.
2026-10-04 00:30:07 +00:00
austinried c1081b4ae7 search: require three characters and play songs in album context
Drop the library-wide instr fallback: below three characters the
cross-type search now returns nothing instead of scanning every table,
and the screen asks for more input. Lock in that a song result plays its
album context rather than a search queue.
2026-10-04 00:30:07 +00:00
austinried 5a3d5ded78 search: expose cross-library search from a home FAB
Add FTS5-backed search across songs, albums, artists and playlists,
reachable from a search FAB on the Home tab. Terms of three characters
or more run through the trigram indices; shorter terms fall back to the
instr scan, matching the per-tab filters. Results are grouped by type
and route into detail screens or song playback.
2026-10-04 00:30:07 +00:00
austinried da57ac08af gradle: let AGP download missing SDK components 2026-10-04 00:30:07 +00:00
austinried 98a3d336a8 port the library tab labels from the old plural names
Albums/Artists/Playlists were new keys because the old Flutter strings
were plurals, so their translations went unused. Take the `other` form of
resourcesAlbumName/resourcesArtistName/resourcesPlaylistName into the three
plain-string resources for the 26-27 locales that translated them. Arabic
`resources_album_name` and Hungarian `resources_playlist_name` stay English
because their upstream `other` form is empty.
2026-10-04 00:30:07 +00:00
austinried 699a6e86f5 address review: localize connection errors, tighten i18n guard, drop dead resources
- AddSourceViewModel resolves SubsonicException.uiMessage too, so malformed/
  HTTP/truncated responses show localized text instead of the raw parser
  message; add a regression test.
- StringResourcesTest now requires an 'other' quantity in every plural and
  asserts exact placeholder (index and conversion) equality, both of which
  could previously pass while crashing getQuantityString at runtime.
- Map the pre-enum song_downloads.error sentences back to their DownloadError
  so existing failed rows keep their specific message.
- Localize the media-session star/unstar button label.
- Remove 12 unreferenced resources (queue name, filter year, sync_failed, and
  the unused codec_* strings; codec labels stay in AudioEncoding).
- Make buildTree's fallback arguments required; only tests used the defaults.
2026-10-04 00:30:07 +00:00
austinried 3162ac07d5 localize transient messages and the download notification
Route user-facing messages produced below the UI through a typed UiMessage
(string-resource id plus format args) instead of pre-built English strings:
showMessage, SyncStatus.Failed, playback errors and download toasts now
resolve in the current locale at the UI edge. Subsonic and page-cap
exceptions carry a UiMessage alongside their developer message, and the
download progress notification is formatted from resources.

Internal invariants and log tags stay plain strings.
2026-10-04 00:30:07 +00:00
austinried a1e45380cc leave the fixed ID3v1 genre names untranslated 2026-10-04 00:30:07 +00:00
austinried 24757bda3f localize user-facing text into string resources
Move every exposed UI string into res/values/strings.xml (+ plurals) and
read it via stringResource/pluralStringResource or getString, with 27
locale files carried over from the Flutter app's Weblate translations.
Only strings whose English is unchanged reuse an old translation; reworded
ones get fresh keys.

Persisted download failures become a DownloadError enum mapped to string
resources (stored by name, unknown legacy values degrade to Failed), the
per-app locale config is generated by AGP, and StringResourcesTest guards
locale keys and placeholders.
2026-10-04 00:30:07 +00:00
austinried 88cd3764bf align the swipe peek with the skip and harden its edges
Resolve previousItem/upcomingItem through the same offline download scan the transport uses, so the peeking art is the track the swipe will actually play. Clear a frozen strip when a fallback swipe fires, prefer the dragged direction over an opposite fling, and simplify the hand-back and ratio prefetch.
2026-10-04 00:30:07 +00:00
austinried 73add672e1 keep the previous artwork visible and stop the neighbour flashing mid-swipe
Swipe-back now goes to the previous track (previousTrack) instead of restarting, so the previous peek stays visible past the restart threshold. The frozen strip only hands back once the live neighbour props match it, so a stale neighbour can no longer flash while the slide settles.
2026-10-04 00:30:07 +00:00
austinried b4539b9ba5 peek the adjacent artwork while swiping the now playing screen
Resolve the previous/next queue items and render a three-slot cover strip that follows the drag, so the neighbouring cover slides in from the side on release. The strip is rotated optimistically at commit and hands back to live state once the controller reports the new track (or after a grace period), so a prop update mid-animation cannot desync it. Ratio prefetch and layered cover loading keep the incoming art from snapping as it loads.
2026-10-04 00:30:07 +00:00
austinried 317a8f4e09 swipe between tracks on the now playing screen
Left/right drags on the cover art skip to the next/previous track, mirroring the transport buttons; the cover follows the finger and settles back on release. Also drops the ripple on the title/artist block.
2026-10-04 00:30:07 +00:00
austinried 4ddbefe7cd downloads: address review on the cancel/progress rows
Name the cancel and delete buttons after the row so screen readers can
tell them apart, show an indeterminate bar when a running track has no
known total, and drop the no-op media refresh on cancel. Trim the dead
size alias and a redundant guard, and cover a queued row with no engine
id plus a failed track in the progress denominator.
2026-10-04 00:30:07 +00:00
austinried 196733f9a7 downloads: base album/artist progress on completed tracks
The aggregate summed bytes over only the currently active songs, so it
reset each time a track finished and the next one started. Count completed
tracks (plus the fraction of each running track) over the node's full track
count instead, so it climbs one track at a time.
2026-10-04 00:30:07 +00:00
austinried 5e074db834 downloads: show progress and cancel on album and artist rows too
A node with any active download now shows the aggregate progress bar and
cancels all its active downloads instead of offering delete; a node with
only finished downloads keeps the trash.
2026-10-04 00:30:07 +00:00
austinried 814331c402 downloads: show progress and a cancel button for in-progress downloads
In-progress rows on Manage downloads now render a determinate progress bar
and a cancel button; completed and failed rows keep the delete button.
Cancelling removes only the active rows, so any completed downloads stay
and can still be deleted.
2026-10-04 00:30:07 +00:00
austinried c3bfb612f8 address review: fix reveal anchoring and ID3v1 names
RevealNewFrontItem compared the post-anchor firstVisibleItemIndex against the
front threshold, so it only worked when the row was at index 0 and exactly one
item was prepended. Recover the pre-change position by subtracting the number
of items now before the old front, and cover the one-in and multi-prepend cases
with integration tests.

Adopt the canonical TagLib/mutagen names for two extended indices: 133 is
Worldbeat (was Negerpunk) and 148 is Abstract (was Christmas). Drop the unused
default on SongInfoDialog's genres argument.
2026-10-04 00:30:07 +00:00
austinried e8ac683b42 normalize every song genre into song_genres
Split genre tags on Navidrome's separators (semicolon, slash, comma) and
resolve ID3v1 numeric indices to their names, so a song's genres are one
deduped list. songs.genre is now derived data with no reader: drop the
column and its index, and read the song info dialog's genres from
song_genres.
2026-10-04 00:30:07 +00:00
austinried 31ed5064a5 home: reveal new front items and brick-pack genre chips
Scroll a recently played row back to the front when a new first item
appears while it is already at/near the start; the lazy layout otherwise
anchors the old first item and hides the new one. Balance the three
genre rows by estimated width and tighten their gap.
2026-10-04 00:30:07 +00:00
austinried ea74fce758 library: route the rediscover list through the download-free query too
Also assert the default pager still observes album writes and cover the
quoted-search path.
2026-10-04 00:30:07 +00:00
austinried c2acbd0eae downloads: skip redundant progress writes 2026-10-04 00:30:07 +00:00
austinried 487296e75e library: stop download writes from invalidating the browse lists
The album/artist/playlist paging SQL named song_downloads, so Room
invalidated the pages on every download progress tick, janking the list
and resetting scroll when a download started. Route the default (filter
off) path through a raw query that only observes its own table; the
downloaded/offline path keeps the download-aware queries.
2026-10-04 00:30:07 +00:00
austinried adc206337b settings: add icons to Manage downloads and Licenses 2026-10-04 00:30:07 +00:00
austinried 0cd6f30c88 address review: keep the notification tap when the activity is recreated 2026-10-04 00:30:07 +00:00
austinried b3cad97869 address review: signal now playing with an event flow, not an int 2026-10-04 00:30:07 +00:00