aboutsummaryrefslogtreecommitdiffstats
path: root/src/i18n.js
Commit message (Collapse)AuthorAgeFilesLines
* Relay panel: the hint says what changing relays does and doesn't changeAdam Soltys2026-10-031-1/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Relay panel: plainer wordingAdam Soltys2026-10-031-2/+2
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Media pager: a button opens the post itself (count of replies on it)Adam Soltys2026-10-031-0/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_011bvzKaZosXGHkigcGcSzAR
* Renewing asks first, and a renewal links to its round's transactionAdam Soltys2026-10-031-1/+7
| | | | | | | | | | | | | | | | | | | | | - The coins page's Renew button opens a confirmation instead of renewing at once: how many coins, their amount, the fee, and what is left to spend meanwhile — with a red notice when that is nothing (the button selects every coin by default, which is how a user locked their whole balance for an hour on 2026-10-03). It says the coins can't be spent until the round's transaction confirms and that a renewal can't be cancelled; the wallet renews for free near expiry anyway. The inline notice from 328f2db moves into it. - A renewal keeps its round's transaction id as soon as the round has run (before it confirms): the in-progress card on the coins page links to it, and the finished renewal's history row carries it, so its detail shows the id with View/Copy like any on-chain movement. Renewals finished before this change have no id recorded. tools/ark/renew-confirm-ui-test.js, tools/ark/renew-txid-test.js Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
* A Lightning payment that can't be covered says why, not 'Payment failed'Adam Soltys2026-10-031-0/+3
| | | | | | | | | | | | | | | | | | | | | | | | A user renewed all ten of their coins (55,611 sats) from the coins page, tried to pay a 55,300-sat invoice three minutes later, and was told only 'Payment failed'. Nothing had failed: the renewal's round ran at once, but its coins stay unspendable until the round's transaction confirms on-chain, and that block took 64 minutes. The quote found no spendable coin and gave up with the generic message; nothing reached the server. - The quote now tells apart (lnShortfall): money held by another payment (wait, as before — now by sum, not one coin covering it all), money a renewal holds ('Nothing was sent. N sats are being renewed…'), and a real shortfall ('needs X sats with its fee, Y available'). Coins leaving in an offboard or exit are never waited for. - The manager's 'insufficient ark balance' names a renewal too. - The coins page says before the tap that renewed coins can't be spent until the round confirms, and that renewing every coin leaves nothing to pay with meanwhile. tools/ark/ln-shortfall-test.js Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
* Videos: know what a clip costs before fetching it; vertical clips onlyAdam Soltys2026-10-031-1/+5
| | | | | | | | | | | | | | | | | | | | | | | | | | - What a clip costs is learned up front: the post's imeta (size, dim, image) when it says, else one 64 KB ranged request — the total from Content-Range, whether ranges are served, whether the MP4's index (moov) comes before its data, and the picture size from the track header. Up to three at a time; remembered across sessions. It also replaces the player-based shape probe the feed ran on every clip. - Clips over 25 MB (8 MB on 2G/3G, 3 MB with data saver), above 1080p, index-last files over 8 MB from servers without ranges, or clips that couldn't be measured wait for a tap: a cover saying what they cost ("50 MB", "4K"). Settings → Nostr → Videos: Autoplay large videos. - The pager loads only the clip on screen in full; the next gets its opening if within budget; everything else holds nothing. Sizes are asked three slides ahead. - Feed clips fetch nothing until they're about to play (preload none), with the post's still as a poster. - Video grid tiles show a first frame only for small clips that start quickly; others show their cost. - Videos lists only clips known to stand taller than wide; one of unknown shape is measured and joins when it qualifies; choosing Videos with none known yet opens the pager on the first that turns up. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
* Feed media views: a grid of pictures, videos to flip throughAdam Soltys2026-10-031-0/+5
| | | | | | | | | | | | | | | | | | | | | | | All / Images / Videos sits under the feed chips (remembered). - Images lays the feed's pictures out as a three-column grid. - Videos opens straight into a full-screen pager: one clip per screen, snapping, the one on screen playing with sound (muted with an Unmute button when the browser refuses), the next a flick or ↓ away. Closing it leaves a grid of the clips. - The pager shows only the media until tapped; a tap shows the author (tap for their profile), the post's words as a caption without the media links (tap to expand), and likes and sats in the bottom right, which also like and zap. - It is a place: Back or Escape closes it. Built outside the morph, so a repaint never restarts a clip; off-screen clips let go of their media. - Near the end of the grid or the pager the feed fetches older posts and new slides are appended. - Toasts now sit above full-screen viewers. tools/feed-media-views-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
* Settings → Nostr: manage your relaysAdam Soltys2026-10-031-0/+18
| | | | | | | | | | | | | | | | | | | | A Relays card edits the two relay lists other Nostr apps go by: the NIP-65 list (each relay Read, Write or both) and the NIP-17 DM inbox. Each relay shows whether it answers (a dot; 'unreachable' spelled out). Both lists are replaceable events other clients write too, so the card edits only a copy it looked up across the index and archive relays, looks again just before publishing, and backs off (reloading the newer copy) if another app saved since. Only a list that changed is republished, to the relays it names, the ones it used to name, and the indexers. Saving updates our own idea of where we write (outbox lookups and wallet sync relays) and resubscribes the DM inbox at once. tools/relays-settings-test.js Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01ULQZS9MQa6iAsXnrJUD9Du
* Zaps find lightning addresses our relays have prunedAdam Soltys2026-10-021-0/+1
| | | | | | | | | | | | | | | Zapping a post looked the author's lightning address up on our four home relays only. Those prune old events, so anyone whose kind 0 hadn't changed in a while (1776, Brad Mills) came back as "no Lightning address or Ark address" — while their profile page, which also asks the index relays and the author's own relays, showed the address right there. The zap lookup now asks both ways at once and takes whichever carries a lightning address. And when someone does have one but Lightning can't be paid right now, the toast says that instead of claiming they have no address. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VKv2uEFRR42Gp6NyqcN3A9
* White Noise attachments (encrypted-media-v2)Adam Soltys2026-10-021-1/+0
| | | | | | | | | | | | | | | | | | | Pictures and files now travel in White Noise groups and direct chats, both ways. A file is sealed under the group's media secret for the epoch its message goes out in (MLS exporter "encrypted-media" -> HKDF -> ChaCha20-Poly1305, AAD bound to hash, type and name), uploaded to Blossom, and sent as a kind 9 with a v2 imeta tag. A commit landing mid-upload moves the epoch, so the file is sealed again rather than sent under a stale key. Receivers keep each epoch's media secret for as long as a message from it is in the log, so older pictures still open. Groups founded here now carry and require marmot.group.encrypted-media.v2 (blossom-v1 on blossom.ditto.pub and nostr.download). Checked against MDK's wn: our pictures decrypt in wn, wn's in ours, and wn uploads into our groups by our policy. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* DM threads: choose by hand whether a message goes by White Noise or Nostr DMAdam Soltys2026-10-021-0/+7
| | | | | | | | | | Where a person can be reached both ways (a direct White Noise group with them, or a KeyPackage from another app), the thread header now carries a small pill naming the way the next message will travel. Tapping it pins White Noise or Nostr DM for that thread, or puts it back on Automatic (reply the way they last wrote). Threads with only one road show nothing. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* White Noise (Marmot) chats: MLS group messaging in native JSAdam Soltys2026-10-021-0/+28
| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | The Chat tab now speaks the protocol the White Noise app speaks, beside Concord communities and NIP-17 DMs, without anyone having to pick one: - A two-person group with no name is a direct message. It lands in the same thread as that person's NIP-17 messages, and a reply goes back the way their last message came. A first message goes by White Noise only to someone whose KeyPackage another app published (a coinos wallet reads NIP-17 on all its devices; an MLS group reaches one). - Groups get rows of their own in the Messages list, a New group button, an invitation card, members, add/remove/rename for admins, leave. - Every wallet publishes a KeyPackage (kind 30443), so it can be invited. src/mls.js is RFC 9420 for ciphersuite 0x0001 on the noble libs (no WebAssembly), with the extensions-draft pieces Marmot needs (app_data_dictionary, app_data_update, app_ephemeral, self_remove). src/marmot.js is the Marmot layer: components, the account identity proof, the 30443/444/445 event shapes and the group engine (publish-before-apply, retained epochs, same-epoch tie-break). State is per device, in IndexedDB (src/marmot-store.js). The whole stack is one lazy chunk (72 KB). Tested against the RFC 9420 vectors (tools/mls-vectors-test.js) and against the Rust reference, MDK's wn CLI, at the protocol level (tools/marmot-interop-test.js) and through the real UI (tools/marmot-chat-test.js). Not yet: attachments in these chats, push for group messages, the app-message witness boost in fork selection. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Ark send review: network fee "none", without the explanationAdam Soltys2026-10-021-1/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Feed form: relays and an every-post firehose; its Back works; a stronger ↵Adam Soltys2026-10-021-0/+4
| | | | | | | | | | | | | | | | | | | new-post tint - The new/edit feed form gets a Relays field (read this feed from these relays only) and "Every post on these relays", which saves a firehose feed (optionally curated) named after its relay and hides the people, packs and topics it doesn't need. It used to take a hand-typed /feed/all?r= link. - The form's Back did nothing visible: opening it made no history entry, so Back went to the page behind the feed and left the form up. The editor (and the gear page's Spending/Savings view) are now part of the navigation state. - New-post tint 9% -> 16% green in light mode; dark mode unchanged. - tools/feed-editor-relays-test.js. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Onboarding avatar step: "Continue", not "Continue with my default"Adam Soltys2026-10-021-1/+1
| | | | | Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Profile npub: full and monospace again, behind a Public key linkAdam Soltys2026-10-021-0/+1
| | | | | | | | | The truncated key button took a whole row on every profile. A "Public key" link now ends the Following/Followers line; it reveals the npub in full, monospace, tap to copy, and hides it again. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Balance card gear replaces Accounts; Spending's coins live behind itAdam Soltys2026-10-021-0/+2
| | | | | | | | | | | | | | | | | | | | - The "Accounts" pill on each balance face is now a gear. It opens that face's settings: Spending leads with its coins (renewal, the co-operative move to Savings, unilateral exit), then Security (lock, change password), the recovery phrase, auto-logout; Savings adds its public key. A wallet with no nostr identity also gets sign-in and log-out there, since it has no profile page to hold them. - The exit cost is no longer said under the balance; the Spending settings state it, always, not only when coin chains run deep. - The lone Manage link under the balance is gone (the gear is the way in); warning notices that are about the coins link to the same page. - The Accounts list, Add wallet and Delete all are no longer reached from the wallet (Delete all stays behind profile > Log out > forget). - Tests follow the gear: padlock-ask, lock-wallet and account-access pass again; cooperative-exit-ui clicks the Spending gear. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Never write a follow list over one we failed to findAdam Soltys2026-10-021-0/+8
| | | | | | | | | | | | | | | | | | | | | | | A kind 3 is replaceable: publishing one built on a list we didn't find wipes the real one wherever it lands. 2026-10-02, an Amethyst user with 398 follows (kept on her own relays and an archive) signed in to coinos for the first time; the starter-follows seed asked only our relays, saw nothing, and published Adam + coinos over her list. - deepContactList: our relays, the profile indexes, the archives, the person's own NIP-65 write relays, and Primal's signed copy (verified). - Starter follows only for a key with no follow list AND no profile anywhere ('new' meant new to coinos, not new to nostr). - A follow, follow-many or mute made while we have never seen the list does the deep lookup first and builds on what it finds. - Settings > Nostr > Follow list: find older copies on history-keeping relays and restore one as a union with the current list (nobody is removed), for anyone already hit. - tools/follows-overwrite-test.js: fake relay network, only an archive holds the list; fails on the old code with the exact two-person event. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Profiles show Following and Followers, each a list you can openAdam Soltys2026-10-021-0/+6
| | | | | | | | | | | | | | | | | | Under the bio: "116 Following · 572 Followers". Tapping either opens the people below it (50 at a time); tapping a person opens their profile. Follows are the person's kind 3, now read from Primal's cache alongside the relays (a list kept only on their outbox relays used to read as nobody). Followers, which no relay counts, come from Primal: the count from user_profile, the list from user_followers, a first screenful fast and the rest after, without reordering what is on screen. Every event taken from Primal is signature-checked in the verify worker first, and the profiles among them fill names and faces the relays lacked. Also translates the post-zap "no address" message. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Zapping a post never falls back to an Ark gift DMAdam Soltys2026-10-011-0/+1
| | | | | | | | | A post's author with no Lightning or Ark address now gets a toast saying so (or a notice on the hold-to-zap card) instead of a locked gift sent by DM. Paying a person from Pay / the send form still falls back to one. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Dmcrt9KyNDKVWFKnb8BREo
* Sending on-chain from Spending states the fee and minimum up front.Adam Soltys2026-10-011-0/+4
| | | | | | | | | | | The form asks the ASP for a co-operative offboard quote (mining share + service fee, minimum = fee + dust) for the address on screen, disables Send for a balance below it and points to Lightning. A too-small amount reads in words instead of the manager's internal error, and the unilateral-exit note only appears when co-operation actually failed. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
* Add cooperative coin exits and clarify profile, preview and zap controlsAdam Soltys2026-10-011-0/+4
|
* The standalone wallet opened from a disk shows its avatars, font and languages.Adam Soltys2026-10-011-1/+2
| | | | | | | | | | With no files beside it, relative punks/, locales/, nip46.js and jsqr.js looked on the disk. From file:// they now come from v3.coinos.io (images and scripts need no CORS; /locales/ now sends Access-Control-Allow-Origin on the server), and standalone.html carries Public Sans inline. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
* Zaps and reactions get their own notification switches.Adam Soltys2026-10-011-0/+2
| | | | | | | | | | | | The notifier now watches kind-7 reactions p-tagged at the user (opt-in by an explicit flag, so older apps that can't word them stay quiet) and sends zap receipts as 'zap' to apps that report the category, 'payment' to older ones. Coinos zap receipts carry their amount into the push. The service worker names the reactor when it knows them and stays quiet for a muted one. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01VP5Ljqk7EYcm5QQAbzDwog
* "Post" floats at the feed's bottom right instead of sitting in the header.Adam Soltys2026-09-301-0/+1
| | | | | | | | | | A pill with the pencil and "Post", fixed above the bottom nav inside the page column, wherever the reader is in the feed; the tap scrolls to the top, opens the composer and focuses it. Hidden while the composer is open (it has its own Post button) and for visitors. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
* A picture or video on its way shows a bar with its percentage — shrinking, ↵Adam Soltys2026-09-301-2/+2
| | | | | | | | | | | | | | | | then uploading; the pencil reads "New post". ui.mediaProgress { stage, pct } (a render per whole percent) drawn as a labelled bar under the reply and post composers, instead of only the paperclip turning into a spinner. Upload progress comes from XMLHttpRequest upload events (fetch() has none) in uploadPublicMedia's new onProgress; injected fetchers (tests) keep the fetch path. upload-progress-test: 1.2 MB at 400 KB/s climbs 0→100 in steps. video-compress-test: the bar counts the shrink, then the upload. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
* Videos are shrunk on the phone before upload; nostr.build is the first media ↵Adam Soltys2026-09-301-0/+2
| | | | | | | | | | | | | | | | | | | | | | host. No public Blossom host transcodes (nostr.build's and primal's BUD-05 /media return the same bitrate), so a 15-20 Mbps phone clip stalled on playback. src/video-compress.js re-encodes on the device with WebCodecs via Mediabunny (a lazily loaded chunk, left out of the SW precache and the standalone file): H.264, short edge 720, ~2.5 Mbps, moov first, audio passed through, rotation baked in. Anything short of a clear win uploads the original. A toast counts the shrinking down. Media hosts: blossom.nostr.build first, nostr.download second (it was unreachable for hours); a HEAD probe skips a host that doesn't answer within 5 s instead of waiting out the whole upload timeout. video-compress-test: 1080p 20 Mbps 5 s (landscape and rotated portrait) → 1.6 MB H.264 720p 2.49 Mbps with audio, moov first, in 2-3 s. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
* Confirm discarding substantial post draftsAdam Soltys2026-09-291-0/+4
|
* Fix public media uploads and feed tab navigationAdam Soltys2026-09-291-3/+5
|
* "Save feed" on someone's timeline adds it to your feeds at once, instead of ↵Adam Soltys2026-09-281-0/+1
| | | | | | | | | | | | | an editor listing every person they follow. The editor copied their whole follow list into the form, one row each — long enough to freeze the browser. A saved timeline now keeps only the person (of: pk); their follow list is read from the relays when it is opened, so it stays small in sync and follows who they follow. Its ⋯ offers Delete rather than Edit, and list pickers leave it out. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
* Polls (NIP-88): options with each one's share of the vote, votable from the ↵Adam Soltys2026-09-281-0/+5
| | | | | | | | | | | | | | feed and the thread. A kind 1068 poll showed as "an event this app doesn't show". Now its options are rows with the vote share behind them (kind 1018 votes, each person's latest counts, single/multiple choice, endsAt honored); a tap votes, marked as yours at once. A quoted poll is pictured in its card. Feeds and profiles list polls alongside notes, and a thread's root is looked up by id with any kind, so replies to a poll find it. Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Du1qT1wbkYwYK6zkGH79Rp
* The chat list shows four conversations and four communities, the rest behind ↵Adam Soltys2026-09-281-0/+1
| | | | | | Show all. Co-Authored-By: Claude Opus 5.5 <[email protected]>
* The feed header keeps its room on a phone: a ⋯ menu for the feed itself, a ↵Adam Soltys2026-09-281-0/+1
| | | | | | | | | | | pencil for a new post. Save feed, Relays, Share and New post sat in the title row and wrapped on a phone. Share, Relays and Save or Edit now live in the feed's ⋯ sheet, and New post is a pencil; the title has the width. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* An event of a kind this app has no renderer for shows as what its author's ↵Adam Soltys2026-09-271-0/+1
| | | | | | | | | | client said it is (NIP-31 alt), not as raw content dressed as a post. A chess game (kind 64) reached through a reaction to it painted its PGN as a reply. Now it reads "♟ Daily chess game #11: …". Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Expired dust gets a quiet line and a Forget button, not a red warning.Adam Soltys2026-09-271-0/+4
| | | | | | | | | | | A coin past its expiry and under the 330-sat floor can be renewed by nobody and exited by nobody; the home page said "the server can still renew it" in red over 21 sats. Now a muted line points at Manage, where the coin's row offers Forget: held as spent, quietly, so it stops counting and stops warning. Larger expired coins keep the warning. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* The visitor's sheet offers a new account, not a wallet: what they came for ↵Adam Soltys2026-09-271-2/+2
| | | | | | | is a nostr account. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* A visitor who taps zap, reply, react or boost is shown the way in; the ↵Adam Soltys2026-09-271-0/+4
| | | | | | | | | | | | | | public header has Search and Sign in. Reading is free. A tap on an action without a wallet opens a sheet with the sign-in doors (Google, passkey, Nostr), Create a new wallet, and Not now; the missing-identity path lands there too instead of a toast, and zapping is never offered to a visitor as if it could go through. The header on a public page (a feed, a profile, a thread) carries Search and Sign in. The page is remembered, so a sign-in lands back on it. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* The default public feed is Popular, not the firehose: what people reacted ↵Adam Soltys2026-09-271-0/+2
| | | | | | | | | | | | | | | | | | | | | | to, in your language, with the machine posts gone. A brand-new post has no reactions yet (of 73 fresh English posts on the four relays, one had two), so Popular starts from the other end: the latest reactions, reposts and zaps, counted per post by distinct people, then the posts two or more people touched. Older pages walk the reactions back in time; new ones arrive by a two-minute poll. At the door, JSON and other machine output are dropped, and so is anything not in the reader's language (script first, then a vote of function words among the Latin-script languages the app speaks; unknown passes). The raw firehose stays at /feed/all. A language selector sits under every feed, and changing it rebuilds the curated ones. A tall video scrolled past used to let go of its media at once and collapse, shifting the page under a thumb; it now waits a moment and holds its height until the clip is back. A tap on a full-screen picture closes it. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Relays are picked from a list, the firehose reads four of them, and a reader ↵Adam Soltys2026-09-271-0/+2
| | | | | | | | | | | | | | | | | | | | | | | with no web of trust borrows coinos's. Each relay in a feed's list is a select over popular relays that answer a bare "everything" query, with Other… for one typed in; the firehose reads coinos, damus, nos.lol and primal by default. A relay chosen by hand or named in a link is tried even if it had been marked sick, which had made a hand-picked nos.lol fetch nothing. A visitor, or a wallet that follows fewer than five people, has no follows whose flags could fold anything, so the public feeds showed the relays raw. They now get the moderation the coinos account gets: its follows' reports (and, for visitors, its mute list), read every few hours and kept on the device. A wallet's own follows and flags always come first. The new-posts pill: the generic button press moved it half its width to the right (its centring transform was replaced), so the tap never landed, and the generic hover painted it light over light text. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Everything on the coinos relay is a feed of its own, and every feed can read ↵Adam Soltys2026-09-271-0/+10
| | | | | | | | | | | | | | | | | | | | from relays of your choosing. Plain /feed is the firehose: every post relay.coinos.io carries, no filter. It sits beside Following as a built-in chip for wallets and opens as a session feed for a visitor. A feed's relay list is independent of what it asks for. The Relays button in the header opens a panel to add to or take from the list; empty means the usual choice (each author's outbox, the wide relays for a topic, the coinos relay for the firehose). The list rides in the URL as ?r=…, on every kind of feed, so a shared link reads where you read. A feed state dropped while its fetch was still out used to swallow the answers meant for its replacement; a relay change showed nothing. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Every feed has a public URL, and anyone can read it without a wallet.Adam Soltys2026-09-271-0/+7
| | | | | | | | | | | | | | | | /feed/<npub> is the timeline that person sees: their follow list, read from the relays, as a feed. /feed/<naddr> is a follow pack or a follow set, /feed/t/<tag> a topic, and /feed?p=…&t=…&pack=…&name=… any mix. A visitor gets the feed over the front door, can open a post's thread and come back; the composer, chips and editing stay with a wallet. Every feed has a Share button (the built-in Following shares as your own timeline), a profile page has "Their timeline", and Back/Forward walk through feeds by id. Public pages used to miss their repaint: the scheduler only painted the wallet screen, so a visitor's feed filled up invisibly. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Sending to a coinos.io name shows the person, not the ark address it became.Adam Soltys2026-09-271-5/+6
| | | | | | | | | The recipient box keeps the name, with their face beside it and "Sent instantly, no fee."; the review names them too. The ark1… the name resolved to is plumbing, and read as gibberish to anyone new to this. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Copy: no more em dashes, anywhere people read.Adam Soltys2026-09-271-114/+114
| | | | | | | | | Every English string, the translations, the README and the messages the code shows people now break with a full stop, a colon or a comma instead. Only console logs and the "—" placeholder for an empty cell keep the dash. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Amber (NIP-55) signs you in on Android: one intent per request, the answer ↵Adam Soltys2026-09-271-0/+6
| | | | | | | | | | | | | | | read off the clipboard or pasted. Closes #7. A "Sign in with Amber" door on Android opens nostrsigner: intents for get_public_key, sign_event and nip44 encrypt/decrypt, with a waiting card that reads the clipboard when the tab returns (or takes a paste). Requests queue one at a time — a sign-in fires the backup, relay list and follows together — and each answer is checked for its type so a stale clipboard is never mistaken for one. An interactive signer is not asked to decrypt DMs or private lists that arrive on their own; each trip through Amber is a deliberate one. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Feed: the foot says when older posts are loading, and when there are none left.Adam Soltys2026-09-271-0/+2
| | | | | Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Renewal: a submitted round the server has forgotten is repaired, not asked ↵Adam Soltys2026-09-261-0/+1
| | | | | | | | | | | | | | | | | | | | | | about forever. Adam's wallet carried a refresh action from August 31 in step 'submitted' whose unlock hash the server never ran: the round went through under a later submission (another hash), the inputs were spent by it and the 5,233-sat output reached the wallet through the mailbox — but the original action kept asking RoundParticipationStatus on every sync for four weeks, and since this week's coins page shows renewals in flight, it showed up as "in progress" with the raw gRPC error underneath. On "not found" the manager now checks the inputs: all spent means the round ran under another submission and the record is retired (failed, superseded — no history row, no card); none spent means the server dropped it before a round ran, so it is submitted again; a mix goes through the existing input repair. The coins page never prints a server error string; a failed check reads as "the wallet keeps trying". Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
* Coins page: a renewal in flight keeps the whole page; a renewal you asked ↵Adam Soltys2026-09-241-0/+10
| | | | | | | | | | | | | | | | for is in history. Tapping Renew marked the coins pending and the page, finding nothing spendable, collapsed to a single "Pending: N sats" line — no table, no exit explainer. Coins in a round now stay in the table (greyed, tagged renewing), with a card saying where the round is (queued, in a round waiting for a confirmation, finishing). The page no longer closes on Renew. History: a manual renewal shows as "Renewing · in progress" while the round runs, and as "Renewed" after, even when it was free (automatic free renewals stay out of history, as before). Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
* Videos play by themselves, muted, while on screen — with an Unmute button; ↵Adam Soltys2026-09-231-0/+2
| | | | | | | | | | | | | | | | | | | YouTube too. An inline video starts as it scrolls into view (muted, the only way a browser lets a page start one), pauses as it leaves, and a corner button turns the sound on; the native controls' own mute keeps the button honest. A YouTube box loads its player muted once in view (enablejsapi, so the same button can unmute it over the iframe API) and pauses out of view; a tap on the poster still means sound. One IntersectionObserver watches every player. Data Saver keeps tap-to-play. Tests adapted to the feed's new admission rule (a row waits for its author's face and pictures): the markdown and post-actions tests seed the poster's profile and serve their pictures locally; a picture that cannot be decoded is now a link, by design. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Moderation: the whole mute list everywhere, follows' reports fold posts, ↵Adam Soltys2026-09-231-0/+30
| | | | | | | | | | | | | | | | | | | | | | strangers' spam hidden. Mutes were only applied when the feed merged and painted. One predicate (hiddenWhy / hiddenPk) now gates the feed, thread replies, notifications, the who-reacted panel and counts, quote cards, rooms, the DM list and the DM push. The list itself is read in full — people, words, hashtags, whole threads, and the nip44 private half — and edited through one publish path (mute thread and hidden words from the ⋯ menu and a Settings → Nostr card). Reports (NIP-56) from the people you follow are read from their outbox relays every half hour; a post or author they flagged is folded behind who said so, with Show. Report… in the ⋯ menu publishes a kind 1984 and hides the post for you. Amethyst's stranger rules: a post of 60+ characters repeated under another id is a duplicate and five duplicates hide the author for the session; more than ten hashtags hides the post. Both switchable in Settings. Co-Authored-By: Claude Fable 5.1 <[email protected]>
* Social: NIP-51 lists as feeds, posts and people in the address bar, the ⋯ ↵Adam Soltys2026-09-231-0/+11
| | | | | | | | | | | | | | | | | | | | | | menu on every screen. Lists: a feed of hand-picked people is published under your key as a kind-30000 follow set (title, p tags, t tags), so Coracle, Nostria and friends show it; your existing follow sets from other clients turn up as feeds (relay copy wins when newer; private nip44 members read and followed, never rewritten). "Keep as a nostr list" in the editor; unticking sends a NIP-09 deletion and the feed stays. "Add to a list" from a profile or a post's ⋯; someone's lists show on their profile and open as feeds (a kind-30000 naddr works as a pack too). Links: a thread puts its nevent in the address bar, a profile its npub — copy, share, reload; Copy link / Share in the ⋯ sheet. Boot-time renders after a reload share one history slot, so Back goes to the screen before. Fix: the ⋯ sheet and the reaction picker were only drawn by the feed and notification views, so the button did nothing on a thread or a profile. Co-Authored-By: Claude Fable 5.1 <[email protected]>