| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
/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
|
| |
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
screen no longer shadows a restored wallet; stop() no longer throws.
Reconcile now asks the server about a 'pending' coin no live action or
standing renewal order holds: spendable again, or gone. Thirty zap-sized
coins another device had already spent counted in a balance for weeks.
A nav saved by a page with no wallet (the start screen) was restored over a
wallet that had since been saved to the device, painting the start page.
messages.stop() referenced feedAt, which no longer exists, so the rest of the
teardown never ran on an account switch.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
|
| |
|
|
|
|
|
|
|
| |
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
|
| |
|
|
|
|
|
|
|
|
|
|
| |
padlock moves from the header to this page.
The identity chip used to put the npub in the URL and leave the list on
screen (the profile only paints over the wallet screen). Lock/Unlock now sits
with the other device-wide actions (log out, clear); the padlock tests reach it
through the Accounts page and lose their stale "Wallets" button.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VhUKyXKtsJ67QAFfb7QR9D
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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
|