mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 11:48:24 +00:00
When the sender and the note's author both publish a payment target of the same protocol, the zap picker now offers a chip that hands off to the app that owns it. Gated on a new opt-in setting (default off), on the note carrying no NIP-57 zap split, and on an installed app actually resolving the URI. The chip carries no amount. Zap presets are sats and there is no rate anywhere in the repo to turn them into a Venmo or IBAN figure, so no number is shown and no RFC-8905 amount= is emitted; the receiving app asks. It ends in OpenInNew rather than the send arrow every amount segment uses, and long-press copies the authority instead of opening the sat-preset editor, which would mean nothing here. Nothing is published, so the zap counter does not move and none of the zap progress state is touched. It renders beside the amount pills rather than inside each pill's rail toggle. Carrying no amount, it would otherwise repeat identically once per preset, and keeping it out of the toggle leaves ZapRail a plain enum instead of forcing it into a data-carrying sealed interface. Discovery needs the new <queries> entries: targetSdk is 37, so Android 11+ package visibility returns nothing from queryIntentActivities for an undeclared scheme, and the chip would be invisible on every modern device. Unknown types all fall back to payto://<type>/<authority>, so one payto entry covers the open-ended tail of the vocabulary. Specific <intent> filters, never QUERY_ALL_PACKAGES. The mark is the resolved app's own icon, from the same ResolveInfo the probe already holds, decoded once at the chip's size during the warm step and masked round the way a launcher draws it. It falls back to the brand-coloured glyph paymentTargetStyleFor already assigns when the hand-off would open a chooser or merely a browser: https targets resolve to any browser, so a control probe against an unownable host separates a real app handler from Chrome. The availability cache is keyed on scheme plus host, not scheme, because an app may declare host="iban" and a scheme-only hit would wrongly claim payto://upi is handled. It is warmed from the sender's own target list when the picker opens, so it is bounded by how many ways the user says they can be paid rather than growing with the feed, and it is a StateFlow because a plain map write is invisible to Compose. Shared plumbing moves to commons: PaymentTargetTypes now owns the alias and scheme tables that were duplicated inside the profile UI file, and PayToRailMatcher holds the matching and the gate decision as pure functions, free of Note, Context and the availability singleton so the gates are testable on their own. RailCapability gains a defaulted payToTargets, and peek gains defaulted parameters so zapClick's one-tap fast path stays Lightning-only. PaymentTarget becomes a data class: without value equality it compares by identity, which breaks list keys and dedupe. 25 new tests in commons; amethyst, commons and quartz suites all pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JXKZeV6FNhXF9BBjgEtfvS