| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Every render builds a fresh tree to diff against the live one, and a media
element starts downloading the moment its src is set, even off the
document: a sixteen-second feed scroll built 204 <video> and 1,416 <img>
elements whose loads the morph then threw away — 375 cancelled video
range requests, and full re-downloads from hosts that send no cache
headers. h() now puts the source on data-lazy-src and it becomes src only
once the node is in the page (render promotes it; a MutationObserver covers
nodes appended by hand); the morph treats the two as one attribute.
The thumbnail maker fetched every original with cache: 'reload' (38 MB in
one scroll); the face was just painted from that URL, so the cache serves.
holdScroll now recovers an anchor row that a large insert above pushed out
of the window, from the height cache. Tests: the YouTube test accepts the
in-view players autoplay loads; the stability test watches the notice for
the catch-up, since the new rows land inside the window's spacer.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
nothing.
With stale nodes still in front, every kept row's position was off by the
stale count and each one was pulled out and re-inserted — a remove and an
add per row per repaint. The feed's window evicting rows at the top did
this to every mounted row on every scroll step; a moved <video> leaves the
document and comes back, restarting its loading (one clip was fetched 61
times in 40 seconds), and images were refetched. Measured with a
MutationObserver on the live tab: 160 of 179 row additions during a
20-second scroll were the same key going out and back in.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
|
| |
|
|
|
|
|
|
|
|
|
| |
and QR.
Creating, importing, unlocking or switching to an account (and finishing
the onboarding wizard) now opens the Receive tab instead of History. A
refresh still resumes wherever you were; loading a seed into a watch-only
wallet mid-flow keeps its place too.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Lightning.
Settings → Advanced → Ark server: coinos, Second (ark.second.tech) or a
custom server, per network — the stored choice is honoured on mainnet
again. Ark state is kept per server, so switching hides but never loses
coins; the card says what the current server holds and asks before letting
go. After a switch the reusable address, the nostr advert and the payment
name's ark= instruction follow the new server.
Sends between servers can't be arkoor, so an Ark address that names a
different server (its first bytes hash the server key) is treated as no
Ark address at all in the pay ladder — a coinos name or npub then goes
over Lightning by itself — and a pasted one is refused with the reason.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
| |
one row.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
| |
of sale; the show/hide toggle is gone.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
| |
Six tiles still: Wallet, Payments, Point of sale, Nostr, Notifications,
Advanced. The network and explorer cards sit at the top of Advanced.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
| |
last account's.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
screen, Not now one tap away.
The wizard's spend step (claim a name, get a payment address) now follows
the seed screen and the sign-in backup screen, wherever Spending can be
set up (Ark-capable network with the names registrar, a signing account).
Not now lands on Savings like before. namesAvailable answers 'yes'/'no'
rather than a boolean, which featureHook would read as no answer.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
door to the previous one.
Word grids flow down a column then the next, with the row count from the
word count — on a phone the first column is 1–6, the way a hand copies a
list. pomegranate.js takes the central as an option (CENTRALS.coinos is
auth.coinos.io, now deployed; the default stays auth.njump.me until its
Google client is live), and the sign-in card grows a "previous server"
line once the default moves, so accounts made under njump keep working.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
|
|
|
|
| |
No create/import tabs and no Generate button inside the wizard: the words
appear the moment the button is tapped. Underneath, "Have an existing seed
or entropy to import?" swaps to the import pane (which has its own entropy
door), and "Create a new wallet instead" swaps back with fresh words. The
create/import card elsewhere (adding an account) keeps its tabs. Tests
that entered through the old tab go through the new line.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
| |
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
the Receive tab.
v3.coinos.io/pos opens the point of sale once a wallet is up (claimed at
boot before any feature reads the path), so the till can be bookmarked or
put on a home screen. Settings → Payments gains "Start in point of sale on
this device" (localStorage, not synced: the till, not every phone the
owner carries). The amount and the custom tip get a 3×4 pad that edits the
same field a keyboard or a paste would. The button under the payment
address on Receive is gone.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
|
| |
|
|
|
|
|
|
|
|
| |
bitcoin: links.
njump's "Your default web app" is a web+nostr: link: it opens whichever
site registered that scheme. A card offers to register this app (the
browser asks), and ?u= now accepts the web+nostr: form.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
route there; posts name the NIP-89 handler.
A NIP-89 handler event (kind 31990, d=coinos) under the coinos key points
njump and other pickers at /<npub> for people and /<note> for notes. The
client tag on public posts now carries that coordinate.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
Nostr.
A prefs flag (zapSound, absent = on) synced with the zap amount. The strike
and the tally are unchanged; only the clip stays quiet, and the clip chunk
is not even fetched while it's off.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
grants.
Header buttons always leave the current feature screen; an account with
no remembered nostr identity opens Accounts instead of nothing. Logout
confirms in place. A scan finishing after logout or an account switch no
longer drops the new session into offline mode (stateGeneration guards in
sync + ark). Spending restores from the snapshot first. A migration grant
names the identity that owns an address; its manager may register it
without becoming that identity (names/ownership.js). Browser tests for
account access, profile retry, spending restore, thread reply focus,
custom-emoji reactions and registry ownership.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
A tapped history row claims the whole tab area whichever tab is picked,
so jumping to ui.tab = 'send' from a profile's Pay button (or a zap's
form fallback) with a renewal's detail still open showed that detail
instead of the form. showSend() closes any open detail first; the three
feature paths that jump to Send use it.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JuwQqNWtDJcxPWtEm9134z
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The "still unwritten" line keyed off a flag held only in session storage
and the vault, so a silent sign-in that rebuilt the account (every app
open on a phone) started it over as unseen. The flag now rides the
wallet's snapshot — the local cache and the synced copy, merged
commutatively so it only ever turns on — and the account directory, so
a rebuilt account finds it before any sync arrives. Seeing the phrase
marks every account on the same seed and saves the cache at once, so it
pushes to the other devices right away.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01JuwQqNWtDJcxPWtEm9134z
|
| |
|
|
|
|
|
|
|
| |
Switching between Create and Import, backing out of the entropy page,
signing into another account or going home all drop whatever was typed;
the entropy page always opens empty instead of refilling from an
earlier visit. Secret material is not a draft.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
Every feature balance line landed on the Spending face, but a gift's
locked reservation is on-chain money still sitting in Savings. Lines now
say which side they belong to and draw on that card: gifts on Savings
beside pending incoming, ark's Moving… on Spending as before.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
start page.
The photo viewer made no history entry, so the phone's Back popped the
screen underneath it instead — and on a session whose history began at
the sign-in page, that was the start page, so the photo's × then looked
like a logout. The viewer is now a navigation entry of its own: Back,
×, Escape and a backdrop tap all pop it and leave the room in place. And
with a wallet open, Back into a pre-sign-in entry lands on the wallet
home rather than the welcome screen.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
With several identities signed in, the profile's Log out now signs out
only the current one: its accounts leave the session, directory, cache
and vault, the others stay put, and the next identity takes the screen.
The confirmation names who is leaving and says whether they can sign
straight back in (a nostr login) or need their recovery phrase (a bare
seed). Logging out of every account is a second, explicit button. Alone
on the device, Log out is unchanged.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
The active account lived only in sessionStorage, so a link clicked from
outside (a fresh tab or the installed app window) unlocked the vault and
always reopened the first wallet in the directory. The last activated id
is now also kept in localStorage and preferred at every fresh-session
entry point: silent vault unlock, watch-only seeding, the password
prompt, Skip, and the home fallback.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
On the wallet settings page the phrase sat under the name and the key;
it is the one thing there that matters if the phone is lost tonight, so
it leads now — on the Settings tab and the per-account screen alike.
Beside "Reveal the words", Hide was a small button tucked next to a big
one; the two are now equal halves of the row.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A post let in at the top of an open feed was there on the next paint —
one frame nothing, the next a whole row, the page shoved down by that
much. Now it opens over a third of a second: height from nothing to its
own, fading in as it goes, and a repaint mid-way resumes where it was.
The same happens to the posts the pill lets in.
That needed the morph to know which row is which. Children were matched
by position, so a new first row was patched onto the old first row's
node and every row below onto its neighbour's — the node the new post
was built as never reached the page. A list whose every child carries a
data-key is now reconciled by key: new rows are inserted as themselves,
the rest keep their nodes and move. Feed rows and their hairlines carry
the post id. Partially keyed lists keep the positional rule.
feed-live-test catches the arriving row mid-animation: shorter than it
will be, one animation running, and settled clean afterwards.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYJfZ4A1TDCEY4Foq3CApR
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A phone freezes a backgrounded tab: timers stop and the relay sockets are
cut, so the feed came back holding whatever it had when you left and only
caught up if you pulled it down by hand. Features now hear about the
return — app.js calls f.resumed(awayMs) on focus — and the feed answers
it by forcing a pass past the thirty-second throttle and rebuilding its
subscriptions, which were talking to sockets that no longer exist. A
blink between apps (under five seconds) is left alone.
That catch-up raises the second problem rather than solving it: dropping
eight posts in at the top moves the words under the thumb of whoever was
reading. So posts that arrive on their own — live, or as a catch-up —
wait when you're scrolled away from the top. A floating pill says how
many, and the tap that lets them in also takes you up to them. Scrolling
back to the top by yourself lets them in too, since up there they cost
nothing. Anything you actually asked for still goes straight in.
Also, on profiles that still show an npub: the batch now falls back to
the relays whose whole job is indexing kind 0 (purplepag.es and friends),
which we never read notes from and so never asked. profile-batch-test's
"handful of asks" bound was a fraction of the row count, which that
fallback broke; the property it means to assert is that the number does
NOT grow with the rows, so it is a constant now.
tools/feed-live-test.js drives a real signed event down a real open
subscription — an unsigned fake is dropped by the signature gate and
would prove nothing — and checks the page does not move, the pill says
"1 new post", tapping it scrolls to the top, and coming back from hidden
re-asks the relays on its own.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Four buttons of equal weight, and only the sign-in ones said what they
did. "Get started" said nothing, so the concrete offer on that screen was
Google — which is a convenience wrapped around a seed phrase, not an
alternative to one.
Now the page says what the wallet is before it offers a button, the way
in reads "Create a new wallet" with the cost under it (a minute, twelve
words), and the three sign-ins sit below a line labelled "or, if you
already have an account".
And the second half of the same problem: a wallet that arrives by sign-in
has a recovery phrase its owner has never seen and nobody can reissue.
So the wizard shows it once, right after the first login, while it still
reads as setting up rather than as a warning out of nowhere. "I've
written it down" is the way on; "Later" is a real answer, and the wallet
then keeps one quiet line — not a modal, not dismissible, gone the moment
the phrase is actually seen, here or in settings.
seedSeen records that per account: creating shows the words, importing
means they typed them, revealing in settings counts. Only a derived seed
starts false, which is exactly the case worth asking about.
tools/onboard-backup-test.js covers both halves, including that "Later"
leaves a reminder that survives a reload and leads somewhere.
The sixteen tests that clicked the old button by its text are updated,
and it has an id now so its copy can change without breaking them again.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Three signed-in identities produced three rows all called "Savings", one
under the other, with nothing to tell them apart — indistinguishable from
duplicates, which is exactly what they looked like. The wallets ARE
per-identity; the screen just never said so.
They're grouped under the person they belong to now: face, name, and a mark
on the identity you're currently signed in as. One identity on the device
gets no heading, because there's nothing to tell apart.
"Whose wallet is this" also becomes one function rather than two: the
accounts screen and the identity switcher were each working it out, and they
have to agree or they describe different worlds.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Tested on a real phone, and the first attempt didn't work at all:
Background started FGS: Disallowed [... code:DENIED ...]
startForegroundService() not allowed due to mAllowStartForeground false
Android 12 forbids starting a foreground service from a broadcast receiver.
An expedited job is the sanctioned replacement — it runs promptly from the
background and needs no notification of its own to apologise for existing —
so WakeService is now WakeJob, and the notification is decided by what
arrived rather than by whether we could wake: a payment or a message is news
either way, a wallet-connect request the wallet answers by itself is not.
Two more things the phone found. A job with a connectivity constraint needs
ACCESS_NETWORK_STATE, or schedule() throws and nothing runs at all. And a
wake with nothing to answer used to hold a WebView open for the full thirty
seconds — a locked wallet, no wallet on the device, or no NWC connections all
end the job immediately now.
Also a bug worth naming: ctx carried `wakeDone` by shorthand, which captured
the binding while it was still undefined (ctx is built before it's defined).
The page could never say it had finished, so every wake ran its full timeout.
It reads through a closure now, like its neighbour.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The attach control was a .btn-sm holding a 16px icon, wedged between two
full-height buttons — a sliver to aim at on a phone. It's a 48px square the
height of the row now, with a 20px clip in it.
And tapping an image opens it full screen: the image centred on a dark
ground, tap anywhere (or Escape) to close. Posts crop images to 320px so a
feed stays a feed, which makes a photograph a thumbnail — this is where you
actually look at one.
Two details in the viewer. The page underneath stops scrolling while it's
open, and the scrollbar gutter the page keeps reserved stands down with it:
fixed positioning is sized to the viewport WITHOUT that gutter, so an
"inset: 0" backdrop leaves a pale stripe down the side of an otherwise
full-screen picture.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
| |
A tap is "the finger didn't move AND the strip didn't scroll", the same pair
the mouse path has always used. Scroll position alone would have been enough
for a finger (native panning moves the strip while it's down, so a real drag
never looks like a tap), but only because the snap-back happens after the
finger lifts — which is a timing detail to be relying on. The touchmove flag
says it outright.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Tapping the unit tag on a phone took the best part of a second to change the
number. Measured on the device: 824ms, three taps running. The same tap on a
laptop was 30ms.
The balance carousel freezes itself while a finger is down — renders are held
and the strip is marked _skipMorph, so a background repaint can't rebuild it
mid-drag and yank the scroll. Touch-end lifts the render hold but leaves the
strip frozen until a scroll settles... and a TAP produces no scroll events at
all. So the freeze stood until the 700ms safety net fired, and every render in
between was refused by the morph — including the one the tap had just asked
for.
The mouse path has always had this guard (it only freezes once the pointer has
moved four pixels, and unfreezes immediately on a release that never moved),
which is why this never showed up on a laptop. The touch path now notices the
same thing the only way it can: the strip's scroll position is recorded when
the finger lands, and if it hasn't moved by the time the finger lifts, that
was a tap and the strip unfreezes there and then.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The balance read "US$74.67 USD" — the symbol and the unit tag saying the same
thing twice. Amounts now format bare, like sats and BTC do: whatever labels
the number says which money it is. The currency symbol stays where a number
stands alone in prose, which is the "Worth then" line and nowhere else.
The '~' marking a payment older than any price we sampled is gone too. It was
bookkeeping the beta doesn't need: a payment we have a price for is shown at
that price, one we don't is shown at today's, and nobody has to learn a
squiggle.
The currency picker has moved to sit beside the language picker at the foot
of the page — display preferences together, where they're findable. It spent
one day under Settings → Network, where it wasn't.
And a bug this feature exposed rather than caused: nine notices end in the
word "sats" in every language we ship, and were being handed the display
unit. "Uncooperative exit costs about US$2.03 sats" — and long before fiat,
"about 0.00435397 sats" for anyone in BTC. They're given sats now, which is
what they claim to be showing.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
A payment is worth what it was worth WHEN IT HAPPENED, and that number is
gone by the time you look at it unless someone wrote it down. So every price
the app fetches is kept as a sample — one an hour, a few months back — and a
payment's fiat value is read off the sample nearest its own timestamp. The
history rows and both detail pages (on-chain and Spending) pass the time the
money moved; balances and forms use the live price, as they should.
A payment older than any sample we hold is priced at today's number and says
so with a '~', because that is a different claim and shouldn't look like the
same one. The detail page spells it out: "Worth then $X · $Y now".
Fiat is a third position on the unit toggle rather than a second number
beside the first: sats → BTC → your money → sats. One figure, and which
figure is your choice. The ring skips fiat entirely until a price has been
fetched — a third position showing blanks is worse than two that work. Typing
an amount with the unit on USD means dollars, priced now.
The rates are coinos' own endpoint, a map of every currency it knows, so
there's no third party watching what the wallet asks about; the currency
picker under Settings → Network lists all of them. Changing it starts the
recorded history again rather than relabelling samples taken in another
currency.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
FOLLOWING. A profile page gains Follow / Following beside DM and Pay. The
contact list is the kind-3 event, kept locally so the button is right in the
first frame and refreshed from relays behind it. Publishing one is delicate:
a contact list is a shared document — other clients keep relay hints in its
content and petnames in its tags — so a follow re-fetches the newest list
first and adds or removes exactly one p tag, preserving everything else. The
button flips immediately and flips back if the publish fails. The service
worker's friend filter reads the same list, so following someone also means
their DMs stop being treated as a stranger's.
THE FEED. Posts by the people you follow, newest first, at the top of the
messages home. Replies are left out: a reply belongs to its thread, and a
timeline of half-conversations reads like eavesdropping. The last screenful
is kept locally so it opens with posts in it rather than a spinner, new posts
arrive over a live subscription while you're looking at it, and older ones
stream in as you reach the bottom — the same shape as the profile pages. A
wallet that follows nobody is told so and offered the people search.
MEDIA. The composer (now shared by the feed and the profile page) takes a
picture or a video: it uploads when you pick it and appends the URL to the
text, which is how every nostr client reads media, with a NIP-92 imeta tag
published beside it for the ones that would rather be told than guess. Posts
already render images and video inline, so they show up where they land.
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|
| | |
|
| | |
|
| | |
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The art is 240x240 (20KB each, 1.5MB for the set) because that's what a punk
published as someone's nostr picture should be — but the circles the app
draws are 18 to 64px, so a new wallet with nothing cached was fetching eight
times the pixels it could show, one request per face.
punks-sm carries a 128px copy of each: 4KB instead of 20KB, indistinguishable
at 64px. Small circles and the wizard's picker tiles load those; only the 64px
profile avatar and the value the wizard publishes stay full-size.
The bigger win is that a punk picture is our own art wherever it turns up.
Everyone who keeps the default publishes v3.coinos.io/punks/N.webp as their
nostr picture, so those faces now paint straight off disk at the size being
drawn — no request, no thumbnail to make, and no broken circle when the
legacy coinos.io copies 502 (which they do for a third of the set).
Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_019mrt228Upn9nNCwGixzSLx
|