aboutsummaryrefslogtreecommitdiffstats
path: root/tools
Commit message (Collapse)AuthorAgeFilesLines
...
* GIFs in replies. The thread's reply box gets the same GIF button as the post ↵Adam Soltys5 days1-0/+16
| | | | | | | composer: a pick lands in the draft (preview opened) and the reply goes out with the GIF's NIP-92 imeta. tools/gif-picker-test.js covers it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Feed: your own posts are in Following. The follows feed read only the people ↵Adam Soltys5 days2-4/+11
| | | | | | | you follow, so your own post was there just after you sent it (the optimistic row) and gone after a reload — Adam didn't see his latest. Like every other client, a follows feed now includes you. Someone who follows nobody still gets the "find people" invitation, with their own posts under it. feed-live-test's catch-up queue now goes only to an ask naming the post's author (the feed also asks for yours); tools/feed-repost-test.js checks your own post shows. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Feed: reposts. Amethyst showed Zapstore's repost of LWB's "Tankful" post in ↵Adam Soltys5 days1-0/+76
| | | | | | | Adam's follows; we showed nothing — a feed asked only for posts (kinds 1, 1068). A feed of people now asks for their reposts too (NIP-18 kind 6; topic and firehose asks stay posts-only), and a repost shows as the note itself, under "🔁 <name> reposted" — its reactions, zaps, ⋯ and thread are the note's. Only reposts that carry the note and whose copy checks out (kind 1/1068, the id the e tag names, a valid signature); a muted author's note stays out. A note shows once: as itself, or under the first repost of it to arrive, counting rows still warming at the door. Media grids skip reposts. tools/feed-repost-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* GIF search, from nostr.build's GIF index (gifs.nostr.build). A GIF button in ↵Adam Soltys5 days1-0/+89
| | | | | | | the post composer and in every chat composer (DMs, groups, communities) opens a picker: "GIFs from nostr.build" (linked, as their terms require), starter chips (gm, lol, yes, wow, …; the first runs on open), a search field (debounced 250 ms, no one-letter searches, one shared request per normalised query, never aborted, 429/403/503 answered in words), and a masonry grid whose tiles play the small H.264 copy only while near the screen, over the lqip blur, falling back to the animated preview (stills under reduced motion). A pick puts the original URL in a post — published with a NIP-92 imeta (m, dim, size, alt) — or, in a chat, sends it at once after whatever was typed. Media URLs not on gifs.nostr.build are dropped. Browser calls carry no headers: production needs v3.coinos.io registered in the nostr.build dashboard (localhost works as their shared dev client). tools/gif-picker-test.js runs against the live API. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Videos: a tap on the picture goes full screen. The corner full-screen button ↵Adam Soltys5 days2-1/+92
| | | | | | | is a reach on a phone, so a tap anywhere on a feed clip — outside the player's own big play button and control bar, judged from the tap's position since those live inside the video element — now goes full screen (a wide clip asks for landscape). Full screen, a tap pauses a playing clip, and a tap on a paused one (again outside its play button and controls) comes back out. A video's taps no longer reach the post either: a tap on the player's controls used to open the thread, which in full screen took the player out from under the reader. tools/video-tap-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Feed: a slow picture keeps loading in place instead of turning into a link. ↵Adam Soltys5 days1-0/+73
| | | | | | | A feed row waits up to 8 s for its pictures, then freezes as it is; a picture still downloading at that moment (Juraj's 3.5 MB PNG from blossom.primal.net, on a phone) was frozen as its bare URL, and only showed when the post was opened. Now a picture that was merely slow is drawn in a fixed 4:3 box (fitted inside, so nothing moves when it lands) and keeps loading; only a picture that refused to load (an error, not a timeout — mediaFailed) is still a link. tools/slow-image-test.js (a picture served after 11 s; on the old code it was a link). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Messages: NIP-42 inbox relays. isolabellart's kind-10050 inbox is ↵Adam Soltys5 days1-0/+131
| | | | | | | auth.nostr1.com and a personal relay, both of which answer a REQ for their gift wraps with CLOSED "auth-required" — we never authenticated, so DMs delivered only there (anything sent from Amethyst and other 10050-only clients) never reached v3. The DM subscription on our own inbox relays now authenticates as the DM identity (subscribeAuthed: per relay, AUTH then ask again, still closable; the AUTH event is signed before nostr-tools' cached auth promise so a failing signer can't wedge the socket), sends to a peer's inbox authenticate when a relay refuses the write with auth-required, and our sent copy also goes to our own inbox relays so other clients reading that list see it. Never Amber by intent (an app trip per connection). Checked live: auth.nostr1.com accepts the handshake. tools/dm-nip42-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Messages: Amber users can read their DMs. Signed in with Amber by intent ↵Adam Soltys5 days1-0/+154
| | | | | | | (NIP-55), nothing sealed to the login npub was ever decrypted — each decrypt would be a trip through the app — so isolabellart's thread with Adam showed only what that phone had sent. Worse, decryptorsComplete() counted the Amber signer as complete, so those wraps were tried on the wallet key alone and logged as opened, hidden for good. Now an interactive signer counts as incomplete (wraps wait, uncounted); Messages and the DM thread say "messages sent to you can't be opened here" with Connect Amber, which opens a nostrconnect:// link for the SAME account over NIP-46 (Amber's bunker mode; a different npub is refused, a callbackUrl reload resumes the handshake). Once a signer that can decrypt takes over, a wallet that ran with Amber re-runs the heal pass over every wrap the relays hold, so messages the old code wrote off come back. tools/amber-dm-upgrade-test.js (plays the remote signer over a shimmed relay). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Posts: inline markdown. **bold** / __bold__, *italic* / _italic_, ↵Adam Soltys5 days1-0/+43
| | | | | | | ***both***, ~~struck~~ and `code` render in a post's plain text — what newsletter bots and Amethyst users type and Amethyst shows; we showed the asterisks. Strict about edges, so snake_case, x__init__y, 2*3*4, "$5 * 2" and a lone star stay as typed, and markers never reach across a link, mention or hashtag. No headings or lists in posts: "#" at a line's start is a hashtag here, and articles render their own headings. tools/post-markdown-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Sensitive posts: Popular leaves them out. The NSFW posts Adam saw (and ↵Adam Soltys5 days1-0/+102
| | | | | | | blocked) in Popular were Misskey artists over the mostr bridge — every one carried a content-warning tag (Misskey's "sensitive" media), and their profiles said so too (":role_nsfw:", "🔞成人向け"); the posts had no words to fail the language test, and nothing read the tag. Popular (and its picture/video grids) now drops a post marked sensitive (NIP-36 content-warning, a NIP-32 content-warning/nsfw label, an NSFW hashtag, :nsfw: or 🔞 in the text) and the posts of accounts whose own name or bio says they post adult work. Everywhere else a marked post is folded behind its warning ("Sensitive: <reason>") with Show, and left out of media grids — Settings → Nostr → "Fold posts marked sensitive" (on by default). On the live snapshot: 6 of 184 posts dropped. tools/sensitive-feed-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Messages: a tap on a conversation's face opens THAT person. The avatar's tap ↵Adam Soltys5 days1-0/+110
| | | | | | | handlers were attached with addEventListener, holding the person it was first drawn for; the morph transplants only h()'s on* properties, so when a new message re-sorted the list and the rows were patched in place, a face kept its old handler — a tap on Bill opened someone else's profile, and once that page had opened, a fresh render hid the evidence. The avatar now sets onclick/onpointerdown claimed in _evs (transplanted like any h() handler), and conversation rows are keyed by person so a re-sort moves them. tools/dm-row-resort-test.js (on the old code, Bill's face opened Alice). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Spending: one coin, one "Received" row — across devices. The Daniel still ↵Adam Soltys5 days1-0/+8
| | | | | | | saw four "Received 1,000" rows and "Payment received! 4,000" for what the ASP shows is a single 1,000 sat coin (and two rows for his 1,005). A receive movement is recorded by every device or tab that sees the coin arrive, each under its own id, and the cross-device merge unions movements by id — so each kept its own row, and the registrar-receipt tagging marked some ⚡. lnFoldedIds now also folds receives of the same coin: the ⚡-tagged one stays (its icon is right), else the earliest. Same read-time derivation as the claim twins (history, celebration, arkMovements, LN tagging), so nothing is deleted and no synced copy brings a twin back. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Spending: a Lightning receive is one row. The ASP settles it as an arkoor ↵Adam Soltys5 days1-0/+31
| | | | | | | the wallet claims — recorded as ln-receive, without its coin's id — and the same coin can reach the mailbox too, which (seeing no movement for that coin) recorded a plain receive as well: two "Received 1,005" rows and a "Payment received! 2,010" (The Daniel). The claim now stamps its coins' ids on the ln-receive, the mailbox backfill counts them, and lnFoldedIds leaves a receive of a claimed coin out of history, the celebration, the arkMovements hook and the LN tagging — derived at read time, never deleted, so a synced copy can't bring the twin back. Claims recorded before the stamp match by amount within ten minutes. tools/ln-receive-twin-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* @mentions: "@" and a few letters in a post, a reply or an edit open a list ↵Adam Soltys5 days1-0/+117
| | | | | | | of people under the box — the ones you follow whose name matches first (at once, from what's here), then the header's people search. Picking one (tap, Tab or Enter) puts nostr:npub… in the text, shown everywhere as @name (NIP-27), and the post or reply goes out with their p tag so they're told; Escape closes. coinos-text's setSelectionRange walks into the <div>s Chrome wraps lines in after an Enter — it used to put any position past the first line at the end of the field. tools/mention-ac-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Zap receipts read as zaps. A receipt (9735, or coinos's 9737) reached as a ↵Adam Soltys6 days1-0/+71
| | | | | | | note — someone reacted to a zap, and the reaction was followed — showed as "a kind 9735 event this app doesn't show" under the LNURL server's name. It now shows the zapper's face and name, "⚡ zapped 21 sats" and what they said with it. tools/zap-receipt-row-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Profiles: Posts / Replies tabs. Replies were mixed into a profile's list, ↵Adam Soltys6 days2-2/+100
| | | | | | | tagged "↩ reply" — now Posts (the default) is what they posted and Replies is their side of other people's threads (NIP-10 replies, NIP-22 comments). Profiles load thirty mixed notes a page and older pages only on scroll, so a tab that holds few of its kind (someone who mostly replies, or never does) fetches older pages by itself — five at most per tab, so a person who never replies doesn't have their whole history paged through. tools/profile-replies-test.js; profile-feed-test waits for rows (the tabs come before them; the old "Latest posts" heading only appeared with notes in hand). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Video stills: past a black opening. vmedia took its still at half a second, ↵Adam Soltys6 days1-1/+1
| | | | | | | and a clip that fades in from black (7 of the 68 made in three hours) gave a black tile. Each frame's mean brightness now comes out of ffmpeg (signalstats YAVG on pipe:2 — /dev/stderr can't be opened from a Bun-spawned pipe), and a dark one sends it further in (2, 5, 10, 20, 40 s) for the first bright frame; a clip dark all the way through (a night scene, a boot screen) gets its brightest frame with the levels stretched (normalize). Stills are made again under a new key and URL (v=4), so neither the server's nor the CDN's black copies are served. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Videos grid: a tile without a still of its own shows the server's (vmedia ↵Adam Soltys6 days1-0/+95
| | | | | | | thumb.jpg) at once — about a second the first time anyone asks for that clip, a CDN hit after — instead of waiting on the browser's probe (64 KB) and frame grab (≈1 MB of the clip, decoded) per tile, which on a phone left most of the grid as empty boxes. The frame grab still runs for a clip the server had no picture for. A known-heavy clip wears its size badge over the still. vmedia makes 8 stills at once (was 4). tools/video-tile-poster-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Reactions: a custom-emoji reaction draws as its picture in the feed. ↵Adam Soltys6 days1-2/+12
| | | | | | | emojiImg falls back to :code: text while a row's media isn't ready, and the feed freezes that choice per row (so a post's body never reflows) — a reaction usually lands after its row was frozen, so :kek_lord: stayed text for good. Reaction emoji sit in the action bar at a fixed height, so they skip the freeze (reactImg), on the like button, the chips and the who-reacted panel. post-edit-test checks it (fails on the old code). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Translation: a hashtag in a script the reader can't read gets its ↵Adam Soltys6 days1-2/+5
| | | | | | | translation in brackets after it — "#総合部絵チャ (…)" — the tag itself kept as the link it is. A post that is only such hashtags now counts as foreign (it was judged by its prose alone, of which it has none, so nothing ever offered to translate it), and ⋯ → Translate on a post with no words says so instead of "already in your language". The registrar's language detection reads the glossed tags too; lang-guess's scriptOf takes a minimum (a two-character tag has a script too). Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Translation: posts in another language are shown in yours — "Translated ↵Adam Soltys6 days1-0/+116
| | | | | | | from Spanish · Show original" under the words, automatic by default for posts the language guess calls foreign (Settings → Nostr → Translation switches it off and leaves a Translate link instead), and ⋯ → Translate for any post. The browser's on-device Translator does it when the language pair is already installed (desktop Chrome); otherwise the registrar's new POST /translate (names/translate.js): a cached, 4-at-a-time front for a LibreTranslate container on cs (names/compose-libretranslate.yml, v1.9.6, 32 languages; none for sw/mr/ta/te, so those readers get no offer). Links, nostr: mentions, :emoji:, #tags and long codes are never sent to the model — only the prose between them, batched in one call (src/translate-split.js, shared). Translations are remembered (coinos-translations, 300). tools/translate-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Accounts: switching no longer leaks the previous identity's notifications ↵Adam Soltys6 days3-2/+125
| | | | | | | and DMs into the next. A notifications query (up to 5 s on the relays) or a wrap mid-decrypt that was still out at the switch landed in the NEW account's list and was saved there under its key — a throwaway account showed adam's zaps, reactions and conversations for good. A session counter bumped in stop() is checked after every await on both paths; notifications only take events p-tagging this identity, and an incoming DM must come from or name it. Healing: notification caches saved before this (no notifsV 2) are dropped once and refetched; a cached DM thread holding a row from someone who is neither us nor the peer is swept. tools/account-switch-leak-test.js (fails on the old code: the reaction and the thread both leak) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Posts: edit and delete your own. The ⋯ menu on your post gains Edit (a ↵Adam Soltys6 days1-0/+156
| | | | | | | kind 1010 edit beside the original — the draft NIP-41 Amethyst reads and writes; the feed, thread and quote cards show the newest text with "· edited") and Delete (a NIP-09 kind 5, after a confirmation). Edits and deletions are asked for in the same REQ as each post's tallies and its live subscription, and count only when signed by the post's own author; they're remembered between sessions (postEdits cache) so a deleted post never flashes back from a cached feed. A post signed by the wallet key before a login was linked is still signed by that key. A deleted thread root keeps its place as "deleted by its author". relay.coinos.io now accepts kind 1010. tools/post-edit-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Vps2H27rhbG9ZqseGfMrc3
* Feeds: Everything and Follows + lists are no longer built-in chips; any ↵Adam Soltys6 days1-12/+19
| | | | | | | custom feed can be one. The editor gains "Everyone on my lists and packs" (the people of all your other feeds and packs, read fresh each time the feed opens) and "Posts from anyone on hashtags I follow" (your topic feeds' tags and your kind-10015 interests, OR'd in beside the feed's people, or the whole feed when it has no people). The editor reads a feed as saved, never expanded, so the lists don't get copied into it Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MgAFLnkF7KrdhuyCLMNgtL
* Feed: the "new posts" pill only ever takes you up. It counts the new posts ↵Adam Soltys6 days1-2/+17
| | | | | | | you haven't scrolled up to yet (going up to one, or past it, takes it and everything below it off), and the tap glides to the nearest of them above the post at the top of your screen — reading one newer than the oldest, you were sent back down to the oldest. A new post peeking in at the top edge still counts as above you. The count updates as you scroll up, and the notice clears when none are left (this replaces the at-the-top check) Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01MgAFLnkF7KrdhuyCLMNgtL
* Ark: a Lightning payment's HTLC vtxo is never a coin to spend. The reconcile ↵Adam Soltys6 days1-0/+46
| | | | | | pass held an in-flight action's inputs but not its HTLC outputs, so between two quick zaps it took the first zap's HTLC coin for an unheld 'pending' orphan, the server called it unspent, and it came back 'spendable' — the second zap chose it as its input and the server refused the policy ("not spendable as a round, offboard or arkoor input (policy: server-htlc-send-v1)"). HTLC outputs are now held with their action, _free() refuses any non-pubkey coin whatever its state (records learn their policy from their bytes), and a pass heals HTLC coins an earlier pass freed Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Front door: a "Migrate a coinos account" button under the sign-in doors, ↵Adam Soltys6 days1-0/+70
| | | | | | opening a page that says a wallet and its twelve words come first (Create, or the sign-in doors), and /migrate on a device without a wallet opens on that page instead of an unexplained welcome; while a move is queued the recovery-phrase step offers no Later. Spending step: an account whose custom name the registrar handed back (a wallet a sign-in restored) leaves the wizard instead of being shown a claim form it could only retype its own name into — claiming it again "succeeded" onto the same page; the claim form also waits behind "Getting things ready…" until the registrar lookups settle Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Feed images: the column copy and the grid tile are decoded, resized and ↵Adam Soltys6 days1-0/+55
| | | | | | WebP-encoded in a worker, one picture at a time, instead of on the page thread between scroll frames (a profile of the live feed showed 1.8 s of convertToBlob there, in tasks up to 383 ms). A picture that hangs or crashes the worker is given up and the worker restarts for the next; three in a row and originals paint for the session, as they do wherever workers can't run Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Restart wheel coast timing and respond immediately on reversalAdam Soltys6 days2-0/+64
|
* Change username: a name this wallet's key claimed before a login identity ↵Adam Soltys6 days1-4/+21
| | | | | | was attached no longer reads as taken — the identity-signed claim is refused, so retry signed by the wallet key that owns the record Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Reuse feed overscan to reduce rendering during scroll coastsAdam Soltys6 days1-0/+63
|
* Feed scrolls faster on a desktop: a wheel notch pushes a quarter further, ↵Adam Soltys6 days1-1/+1
| | | | | | and a grab-and-flick throws twice as hard with a higher top speed Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Grab-and-flick no longer opens the post: a flick that starts a little ↵Adam Soltys6 days1-1/+16
| | | | | | sideways still scrolls (only a clearly sideways drag selects text), and any press that moved eats the click Chrome still fires. A wheel push at the very top of the page no longer dies on its first frame (a frame stamp older than the push read as a step up) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop feed scrolls like a phone: a mouse-wheel notch coasts and slows ↵Adam Soltys6 days1-0/+97
| | | | | | (quick turns stack, a reverse turn brakes, trackpads left alone), and a mouse can grab the feed and flick it (a sideways drag still selects text, a drag doesn't click what it started on) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Footer: "Show your support" beside How it works opens the hat shop from any ↵Adam Soltys6 days1-0/+49
| | | | | | page (shown once a wallet is open, since the shop pays from it) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Keep carousel flick destination through stale scroll-end eventsAdam Soltys6 days1-0/+103
|
* Asset paths are site-absolute: relative ones resolved against a deep page ↵Adam Soltys6 days1-34/+0
| | | | | | (/feed/…, /nevent1…) and fetched the app's HTML, which broke the coinos community's logo (and would have broken the QR decoder, signer module and language packs there). Dev server serves the app icons. The live Concord delivery test is gone: it posted "delivery test" messages into the real coinos #general Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Amethyst's feed model: an Everything feed (your follows, everyone on your ↵Adam Soltys6 days1-7/+23
| | | | | | lists and packs, and posts from anyone on a hashtag you follow: your topic feeds' tags and your NIP-51 interests, kind 10015) and a Follows + lists feed beside Following, built from your feeds and offered once there's something to add. Long names in search results end in an ellipsis instead of running off the card Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Max in fiat sends every sat: the figure a Max fill wrote is remembered with ↵Adam Soltys6 days1-2/+3
| | | | | | its exact sats, so the cent-rounded amount no longer parses back a few sats short and strands them. Anything typed parses as typed Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Max fills the amount in the unit the field shows: in fiat that's money ↵Adam Soltys6 days1-0/+50
| | | | | | floored to the cent (so it never parses back above the maximum), not a BTC figure under a CAD label. One ctx.amountField helper for the ark send/LN Max, the gift Max and fixed-amount zap/BOLT 12 fills Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Prefetch visible post threads after a bounded reading dwellAdam Soltys7 days2-0/+49
|
* Coins in another device's renewal are busy here too: the renewal sliver ↵Adam Soltys7 days1-1/+20
| | | | | | names its inputs, and ArkManager._free / freeCoins exclude coins an in-flight remote renewal holds from balance (counted pending), send/LN/offboard/exit selection, auto-renew, the backstop and the coins page (greyed with the round). Freed the moment that renewal reads finished, failed or lapsed Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Renewals show on every device: the sync snapshot carries each device's own ↵Adam Soltys7 days1-0/+53
| | | | | | renewals as display-only slivers (step, amounts, fee, round txid; no signing material), merged into remoteRenewals furthest-step-wins, never as actions; the coins page lists another device's renewal in progress with its round transaction until it finishes there or a 'Renewed' row syncs (two-day cap) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A renewal refused for 'insufficient refresh fee' re-reads the server's fee ↵Adam Soltys7 days1-0/+58
| | | | | | schedule and re-prices instead of resubmitting the same underpaying set on every sync; if the new fee leaves under 330 sats (or the price didn't change) it fails and frees the coins. Backstop registration re-reads the schedule on the same refusal Co-Authored-By: Claude Opus 5.5 <[email protected]>
* A finished renewal adopted twice no longer shows 'Renewal in progress' ↵Adam Soltys7 days1-0/+57
| | | | | | forever: once its done action is pruned, a re-read round breadcrumb adopted it again as a rescue at step 'issued', whose spent inputs had lost their bytes, so every sync threw. A round counts as claimed when its 'Renewed' movement or its fresh coins are already in the wallet; the breadcrumb and rescueParticipation skip it, and a stuck issued action retires without a row Co-Authored-By: Claude Opus 5.5 <[email protected]>
* No speaker pop on opening the app: the zap sound decodes in an ↵Adam Soltys7 days1-0/+7
| | | | | | | OfflineAudioContext and makes its real AudioContext on the first tap (one made at load ran at once in the installed app, re-opening the phone's audio output on every open/refocus), suspended again after the sound and when the app is hidden Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01PCGjEEMD23CweKrefbTDJp
* Feed videos before they play: the picture fills the box with only the play ↵Adam Soltys7 days4-5/+23
| | | | | | button and size (no seek bar or sound button until playing); hovering the cover no longer paints it over with the app's button grey; upright phone clips (stored sideways with a quarter-turn matrix) paint upright, v1 size caches dropped; a clip the probe found HEVC switches to the copy before fetching the original Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Videos: posters for clips that came without one, and an H.264 copy for a ↵Adam Soltys7 days2-0/+121
| | | | | | clip this browser can't picture (an iPhone's HEVC on Chrome for Linux played sound over black) — vmedia container on cs (bun + ffmpeg, /vmedia/), switch on zero-width metadata or an HEVC header from the probe, a line saying why if the copy fails too Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop Send focus: a mouse click leaves the Send button focused, and that ↵Adam Soltys8 days1-1/+18
| | | | | | blocked the recipient field — only a field you're typing in is protected now (test opens Send with a real click) Co-Authored-By: Claude Opus 5.5 <[email protected]>
* Desktop: Send opens with the cursor in the recipient field (once per visit, ↵Adam Soltys8 days1-0/+3
| | | | | | never off another field, never on phones); the amount field still takes it once a recipient resolves Co-Authored-By: Claude Opus 5.5 <[email protected]>