android: the handoff — the pending rounds, the pipeline, and what is unverified
Everything written this session that has not been through the device: rounds 43 to 48 (each patch adversarially verified, 43's transient-notice expectation fixed), a partial round 49, the pipeline scripts, the Android Auto design and the icon comparison mock. Also the two harness changes that were never A/B'd — adaptive waits, which may only shorten a declared wait and never lengthen it, and a ship that runs the mock walk and the deploy at the same time. The A/B and its 255-step baseline are in handoff/tools; main stays at what the phone has actually walked.
This commit is contained in:
1 parent
867fd42972
commit
9f0601027c
400 files changed
+26401
-3
No files matched your search
@@ -0,0 +1,80 @@
|
||||
/* Taste: what this device has told the Soulseek server it likes and what
|
||||
it hates, and the people the server ranks as close to it. The desktop
|
||||
keeps all three in `community.svelte.js` and follows one rule — the
|
||||
ranking only moves when its input does, so every declaration asks the
|
||||
server again and the chips stay quiet until it has answered. The lists
|
||||
are THIS CLIENT's: the backend keeps them and re-declares every one of
|
||||
them at login, because the server's own copy belongs to the account and
|
||||
another client signed in elsewhere can change it under us. */
|
||||
import * as api from "../lib/api.js";
|
||||
import { slsk } from "./slsk.svelte.js";
|
||||
import { player } from "./player.svelte.js";
|
||||
|
||||
export const taste = $state({
|
||||
/** the things declared, as the backend last answered */
|
||||
likes: [],
|
||||
hates: [],
|
||||
/** null until asked; { users: [{ username, rating }] } after */
|
||||
similar: null,
|
||||
/** a declaration in flight, so the chips go quiet */
|
||||
busy: false,
|
||||
asking: false,
|
||||
/** the server's word when it would not answer */
|
||||
error: "",
|
||||
});
|
||||
|
||||
/* the account these lists were read for — a plain variable, never $state:
|
||||
the screen's effect is what calls loadTaste, and reading this inside it
|
||||
would arm that effect on our own write */
|
||||
let readFor = null;
|
||||
|
||||
/** What this device has declared. Once per account, unless forced. */
|
||||
export async function loadTaste(force = false) {
|
||||
const who = slsk.username || slsk.savedUser || "";
|
||||
if (readFor === who && !force) return;
|
||||
readFor = who;
|
||||
try {
|
||||
const v = await api.slskInterestsMine();
|
||||
taste.likes = v?.likes ?? [];
|
||||
taste.hates = v?.hates ?? [];
|
||||
} catch (e) {
|
||||
player.error = String(e);
|
||||
}
|
||||
await askSimilar(true);
|
||||
}
|
||||
|
||||
/** Declare a thing, or take it back. The backend answers with both lists,
|
||||
* and the server's match is asked again before the chips come back — it
|
||||
* ranks on exactly this, so a second declaration must not overtake it. */
|
||||
export async function setInterest(thing, like, on) {
|
||||
const t = String(thing || "").trim();
|
||||
if (!t || taste.busy) return false;
|
||||
taste.busy = true;
|
||||
try {
|
||||
const v = await api.slskInterestSet(t, like, on);
|
||||
taste.likes = v?.likes ?? [];
|
||||
taste.hates = v?.hates ?? [];
|
||||
await askSimilar(true);
|
||||
return true;
|
||||
} catch (e) {
|
||||
player.error = String(e);
|
||||
return false;
|
||||
} finally {
|
||||
taste.busy = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** The people the server puts near us, by the likes we declared. */
|
||||
export async function askSimilar(force = false) {
|
||||
if ((taste.similar && !force) || taste.asking) return;
|
||||
taste.asking = true;
|
||||
taste.error = "";
|
||||
try {
|
||||
taste.similar = { users: (await api.slskSimilarUsers()) || [] };
|
||||
} catch (e) {
|
||||
taste.similar = { users: [] };
|
||||
taste.error = String(e);
|
||||
} finally {
|
||||
taste.asking = false;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user