Commit Graph
15 Commits
Author SHA1 Message Date
KeelrLeek 24c6857847 android: tap-to-sync, the per-track auto-sync switch, the vocal-reduced copy
The editor the desktop drives with a mouse is better under a thumb: the
song plays, the line to time sits large in the middle of the screen with
the one behind and the one ahead faint around it, and a tap anywhere
stamps it. One layer the back gesture peels, and a set left mid-tap is
offered back by the row that opened it; Save writes the track's own
document, lines never tapped left out of it and the button saying how
many are kept. The lyrics sheet also gains the per-track auto-sync switch
and the desktop's reduced-vocals copy — the same title, artist and
duration, so the words keep following it, and one row puts the original
back.
2026-09-13 23:04:49 -05:00
KeelrLeek e693dfb868 android: your own Soulseek interests, and who the server says is like you
Community's fourth tab is Taste: the likes and hates this client
publishes to the Soulseek server (slsk_interests_mine, slsk_interest_set),
added and taken back as chips, and the people the server ranks as close to
them (slsk_similar_users) — a row each into the peer sheet the app already
has. Every declaration asks the server again and the chips stay quiet
until it has answered, the way the desktop does, because the ranking only
moves when its input does. The lists live in taste.svelte.js, read once
per account when the tab is opened; the mock walk declares a like, watches
the match grow, declares a hate and takes the like back.
2026-09-13 22:52:03 -05:00
KeelrLeek 7eae0ee945 android: a name of your own for anyone on the network
The desktop's local contact metadata on the phone: a peer's sheet ends in
Name and notes — a petname, a group, a private note and the Favorite and
Trusted marks, kept in the app's own config and published nowhere. The
petname stands in for the username on the buddy list, in the chat list, on
a thread's bar, in the peer sheet, in a room's roster and on a room line,
and the real username stays with it — on the line beneath, or beside the
name in a room — so a stranger is never quietly turned into someone you
know. Favourites sit at the top of the buddy list, and clearing a person's
details drops the entry rather than storing an empty one — the backend's
own rule.
2026-09-13 22:40:17 -05:00
KeelrLeek f792d7955d android: a peer in full — their card, their interests, and what they have that you don't
The peer sheet's new "About this user" row opens a screen of its own: the
card their client serves (their own words, their picture, the upload slot
and the queue), the likes and hates they declared, and the comparison this
phone makes of their share against the library. The comparison is the
point of opening a stranger — every record they have by an artist in your
library that you don't, each row opening the search that finds it, and a
way to forget the whole comparison again. Nothing is uploaded to work it
out. Their picture opens in the artwork viewer, which now takes a data:
key beside a library path and an https URL.
2026-09-13 22:28:38 -05:00
KeelrLeek 694a29eb0d android: downloads on Wi-Fi only
One switch the desktop never needed, off by default: on mobile data every
Save the phone can start — a record, a track, a folder, a file, a
playlist's bulk, the now-playing Save — waits, with the reason on the bar;
streaming is never held back. The walk flips the switch, makes the
connection cellular and sees a download refused.
2026-09-13 22:15:07 -05:00
KeelrLeek 3c8989dfa6 android: the hub's filters on the network results, pasted lyrics
The raw results take the Soulseek hub's filters — a free slot only, FLAC
or MP3 320+ — as chips above the folders. The lyrics sheet has the
desktop's paste door: plain text, or LRC with timestamps, kept for the
track.
2026-09-13 22:03:57 -05:00
KeelrLeek 59be9f6c3e android: the nav's badges — transfers in flight on You, unread chats on Community
The desktop's title-bar download ring and its unread indicator, on the
phone's nav: a count on You while Save is fetching, a count on Community
when a chat has unread lines.
2026-09-13 21:52:53 -05:00
KeelrLeek f8c3b90665 android: hours on the library's count line, By format, Jump back in on the empty search
The desktop Library summary's hours on the phone's count line; a By format
order from the file stats (lossless by depth and rate first, then by
bitrate, the badge as the card's line); the empty Search page's Jump back
in — the last records played — as the desktop's empty search shows them.
2026-09-13 21:31:16 -05:00
KeelrLeek b50577fc81 android: a playlist's cover from a photo on the phone
The storage plugin gains pick_image — the document picker limited to
images, the picked content copied into the app's cache so the Rust side
gets a plain path. playlist_cover_set(id, path) is the desktop pick's
install step split out and shared (squared, the master cover, the row's
revision moved). A playlist's sheet offers Choose cover photo and Remove
custom cover; the mock walk exercises both.
2026-09-13 21:20:11 -05:00
KeelrLeek d95c3f48d1 android: the room list filtered by name, the rest on demand
Soulseek lists hundreds of rooms; the phone showed the first 80 and no way
to the rest. Community → Rooms now has a filter by name and extends the
list 200 at a time.
2026-09-13 21:07:11 -05:00
KeelrLeek 60303c8a95 android: reorder from the sheet — a playlist row up, down or to the top; a queue row up or down
Without a drag: a playlist row's sheet moves it up, down or to the top and
persists the whole order in one call (playlist_set_order, as the desktop's
drop does); a queue row's sheet moves it up or down, never past the track
playing. Also src-tauri/android/ship.sh — one round end to end: the mock
walk, the embedded build installed, the phone walk, the commit, each step
gated on the one before.
2026-09-13 20:55:50 -05:00
KeelrLeek 991d52d0cc android: the library's file stats on the cards, the artist's own plays, the thumbnail prewarm
The desktop Library's per-record file stats on the phone (library_album_stats,
one call for the whole library): FLAC 24/96 or MP3 320k badges on the cards,
the size on the list rows and the record page. The artist page's own
listening (artist_play_stats): the time played as a chip, the most played
track under "On this phone". The whole-library thumbnail warm a moment after
boot, at the cards' edge, one decode at a time behind the tiles' gate.
2026-09-13 20:37:51 -05:00
KeelrLeek 26928b706d android: the repair sheet, browse, every long-press sheet, You's last sections, the lyrics tools — and the walk's audio check made honest
The playlist repair (Find a local match: the library searched by the
row's name, a pick relinks it through playlist_relink_item; an unknown
row takes the track's identity). A peer's sheet on the raw results (play
or save the folder, browse their files, message, buddy) and the Browse
screen — the hub's Browse tab: a user's whole share with sizes and totals,
a folder played or saved whole; a share can hold thousands of folders, so
it filters and renders 80 at a time. "Look up a user" on Community →
Buddies. The sheets the phone lacked: a queue row's (Play now, Move to
next, Remove from queue), a catalog song's, a catalog card's and the
record page's own, a raw file's (in the results and in Browse), a room
name's, a buddy's, the now-playing Save (the desktop's Save menu for a
streamed track or record). The artwork viewer with pinch zoom, one layer
the back gesture peels. Search's recent searches and its spelling
suggestion from the names this phone knows. You → Streaming, Downloads,
Sharing, Lyrics, Album artwork, and Clear play history; a record's
Re-fetch the cover. The lyrics tools on the sheet's face: the offset
nudged and kept per track, another LRCLIB candidate chosen, the lookup
forgotten and done again (lyrics.svelte.js, shared by the face and the
lyrics sheet).

The harness: every CDP call times out and the reload step re-attaches
(a WebView that stopped answering hung a walk for ten minutes); the
audio check counts SoulStream's own tracks' underruns from the mixer dump
instead of the thread-wide counters that any app's notification moves —
the afternoon's "dropouts" were other apps' sounds, and the browse of a
49,544-file share measured at zero; __settle resets every tab to its root
through the nav; an adb step kind; the walks cover all of the above on
the mock and on the phone.
2026-09-13 19:56:20 -05:00
KeelrLeek 6e39dc43f3 android: playlists, the import doors, the share sheet, You → Sources — and three bugs the walks found
The desktop's two playlist pages on the phone: the shelf (pinned first,
mosaic covers, badges, New playlist, Import) and the page (kind, Pinned
chip, description, the meta line's warnings, Play / Shuffle / more, a
filter, rows tagged unresolved / set audio / file missing). Sheets for a
card, the page's overflow, a row, pick-a-playlist, a prompt and a confirm;
Add to playlist on every track and record sheet; a removal undoable for
seven seconds from the neutral toast (notice.svelte.js); stream rows play
through the resolver as path-less entries, a set slice starts and ends at
its cues; Add to library / Download all tracks with the desktop's bulk
rules; nav.replace for a review that became the thing it made.

The import doors that need no file — a link (YouTube · Spotify · Apple
Music · TIDAL · Deezer), a pasted tracklist, a YouTube DJ set — with the
review screen and the desktop's catalog verification pass. A share plugin
crate (crates/tauri-plugin-share): Share → SoulStream from any app keeps
the text in a ShareActivity and the WebView hands it to the import when it
comes back to the front. You → Sources: the source-quality window and the
priority per mode.

Found by the walks and fixed: set_settings takes camelCase arguments, so
the phone's normalization and library-folder saves never landed;
Cover.svelte's non-eager wrapper has no layout box, so its intersection
observer never fired and row thumbnails never loaded (the Artists tab too);
a history push while a history.go was still in flight left the nav mirror
one entry ahead and the page blank after a confirmed delete — the mirror
now applies once per microtask and never pushes during a pending traversal.

The harness names unmocked commands, carries console warnings' frames (the
smoke bundle is built unminified), probes the history mirror on every step,
mocks app_status / play_local / waveform / lyrics_get / player_state and
applies settings patches, runs adb steps on the phone (the share intent),
and walks playlists, the imports, the share and the settings on both the
mock and the phone. ANDROID.md documents all of it.
2026-09-13 17:56:52 -05:00
KeelrLeek bb828ff2dc android: the phone, on the real core — the mockup shell, playback, the media card, the catalog, the resolver, Save, the dev flavour
The same Tauri 2 project builds for Android: mobile.html as a third Vite
entry (src/mobile/, the mockup on real data), tauri.android.conf.json, the
mobile stubs (updater, lyric alignment, vocal separation), rustls reqwest
on Android, the AAudio buffer, and a hand-driven detour build
(src-tauri/android/{env,build,deploy,dev}.sh) while Developer Mode is off.
ANDROID.md is the recipe.

Playback: the media-session plugin crate (lock-screen card, MediaStyle
notification, audio focus, headset buttons, a foreground service that
promotes itself first — Android 14 kills the app otherwise), session
restore across reload and restart, solid chrome after measuring the
backdrop-filter lag.

The catalog: Search is the desktop's top bar (the top-result rule, artist
cards), the artist page and the record page are the desktop's, Home is the
desktop's landing page, Gaps per followed shelf. Playing goes through the
desktop's own source rules, moved verbatim from state.svelte.js into
src/lib/sources.js so both apps share one resolver; the phone readies the
next three tracks and crosses boundaries gapless. Save fetches a record or
a track into the library by the download rules; Transfers shows the
burst. The raw Soulseek search stays, offered on request, a peer's copy
streaming with the lane rising as the bytes arrive. Community is the
Soulseek side (rooms, chat, buddies); the private layer waits.

The opener and storage plugins (social links, the picked library folder,
all-files access), the volume normalization switch, and the harness:
tests/mobile/smoke.mjs walks the mock (a fake network behind
src/lib/events.js) and the real phone over CDP, perf.mjs measures frames.
2026-09-13 09:30:06 -05:00