Commit Graph
64 Commits
Author SHA1 Message Date
tyiuandClaude Sonnet 5 1c67182187 Hide currency row controls when there's only one currency
With a single currency shown there's nothing to reorder or remove, so
the per-row "..." menu (Compose) and the Edit button plus swipe-to-
delete/drag-to-reorder (iOS) no longer appear. This also covers
Manual, which always shows just the default currency.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 23:50:05 +03:00
tyiuandClaude Sonnet 5 94508c291c Hide the "Not priced by Manual" label for Manual
Manual's default-currency field being unpriced just means no rate has
been typed in yet, not an actual pricing error, so the label (and the
red error styling that came with it) no longer applies when it's the
active source.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 23:45:30 +03:00
tyiuandClaude Sonnet 5 0927a04fe8 Hide the Manual status line, clear fiat amounts when its rate is gone
"via Manual" had nothing useful left to say once the "updated" part
was dropped, so statusLine() now returns empty for Manual and both
UIs skip rendering it entirely instead of showing a blank line/footer.

onManualRateChanged also now clears manualSource.rate whenever the
field doesn't parse (emptied, or mid-edit on an incomplete number)
rather than only ever updating it on a successful parse. refresh()'s
early-return for a null Manual rate now also clears the cached rates
and pricedCurrencyCodes, so a cleared/incomplete manual rate stops
fiat amounts from continuing to show a stale computed value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 23:42:23 +03:00
tyiuandClaude Sonnet 5 583b9bd14e Hide refresh for Manual, seed its rate from another source
Refreshing has no meaning for a manually-typed rate, so the button
(and its loading spinner) is now hidden while Manual is selected.

Switching to Manual for the first time now seeds its rate field from
whichever source was active before, falling back to any other
source's last cached rate for the default currency. When neither is
available, the rate and amount fields are left empty instead of
showing stale values.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 09:03:18 +03:00
tyiuandClaude Sonnet 5 f3f018741c Hide currency flags shared by more than 3 countries
XCD, XOF, and XAF each have 6-8 issuing countries, which is too many
flags to cram side by side next to a currency code.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 08:57:19 +03:00
tyiuandClaude Sonnet 5 dda836274c Simplify Manual source UI to just the default currency
The manual rate source only ever prices the default currency, so the
currency selector, additional currency rows, and the "updated" part
of the status line no longer make sense for it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FXcrACM5sok3M1KQJ8kByy
2026-09-09 08:56:24 +03:00
tyiuandClaude Sonnet 5 f21bdd48f8 Show a flag emoji next to each currency code
Derives a country flag from the ISO 4217 code's country prefix, with
an explicit map of country codes for currencies shared by multiple
countries (XAF, XCD, XCG, XOF, XPF) showing every issuing country's
flag, and the EU flag as a special case for EUR.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-09 08:47:35 +03:00
tyiuandClaude Sonnet 5 1a16f96739 Simplify currency row menu labels, add move to top/bottom
Move up/down/Remove no longer repeat the currency code in the menu item
text — the row's own field already shows it right next to the button.
Also adds Move to top / Move to bottom, enabled under the same conditions
as the existing up/down actions.

Switches from material-icons-core to material-icons-extended: the core set
is a bare ~50-icon subset with nothing suited to "move to top/bottom" (no
double-chevron or vertical-align icons), so KeyboardDoubleArrowUp/Down
needed the fuller set.

Compose-only: the native SwiftUI screen has no three-dot menu, it uses
native list reordering instead.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-09 08:09:21 +03:00
tyiuandClaude Sonnet 5 5587428ca7 Add locale-aware digit grouping to displayed amounts
Adds groupDigits(), a display-only formatter that inserts the current
locale's digit-grouping separators into an amount's integer part (e.g.
"1,000,000.5" in en-US vs "1.000.000,5" in de-DE, where the roles of ","
and "." are swapped, or hi-IN's irregular "12,34,567"). Delegates to each
platform's native locale APIs (java.text.NumberFormat/DecimalFormatSymbols,
NSNumberFormatter/NSLocale, Intl.NumberFormat with BigInt for arbitrary
precision) rather than reimplementing grouping rules, and never touches the
canonical '.'-decimal strings the rest of the app parses and stores.

Applied via a Compose VisualTransformation (BTC/Sats/fiat/manual-rate
fields, plus the read-only rate display) and, on the native SwiftUI screen,
by re-deriving the field's displayed text on every change. Also made input
parsing locale-aware: sanitizeDecimalInput now recognizes the locale's own
decimal separator (e.g. what a locale-aware decimal keypad sends), not just
"." — with a stricter rule on the SwiftUI side specifically, since its
single text buffer re-feeds the grouped display back through sanitize, so
a "." can be grouping noise there rather than a decimal point.

The exceeds-max-supply warning's "21,000,000 BTC" is no longer baked into
the localized string with hardcoded grouping; it's substituted in at
runtime via groupDigits so the link-detection text always matches exactly,
in every locale.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-09 07:37:46 +03:00
tyiuandClaude Sonnet 5 323ca43472 Exclude withdrawn currencies from the picker, keep precious metals
Currency.getAvailableCurrencies() (JVM/Android) and NSLocale.ISOCurrencyCodes
(iOS/macOS) return every ISO 4217 code the platform has ever known about —
withdrawn currencies like the Deutsche Mark and French Franc, and test/
placeholder codes (XTS, XXX), included. Measured on the JVM: 232 total
codes, only 156 still assigned to a country.

Filters the list down to currencies actually assigned to an ISO country
today, which drops the withdrawn ones without needing a maintained
exclusion list. Precious metals (XAU, XAG, XPD, XPT) are added back in
since they're still actively traded despite not being tied to any country.
Web is left unfiltered — there's no reliable country-to-currency API there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 17:20:09 +03:00
tyiuandClaude Sonnet 5 b0f3744851 Always show all currencies, flagging ones the active source doesn't price
Previously a currency the active price source had no rate for was hidden
entirely, so switching sources (e.g. to CoinGecko, which quotes far fewer
fiat currencies than Coinbase) could silently drop it from the picker and
even from the user's own selection.

Every system currency is now always offered. ConverterUiState tracks which
codes the latest fetch actually priced, and both UIs (Compose and the
native SwiftUI screen, since iOS/macOS don't render Compose UI at all) show
a "Not priced by <source>" indicator for the rest, with the amount field
emptied and disabled rather than showing a stale or meaningless value.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 17:19:48 +03:00
tyiuandClaude Sonnet 5 84df992a82 Sort localization string keys alphabetically
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 11:04:52 +03:00
tyiuandClaude Sonnet 5 e71b01b0e3 Fix dyld crash on macOS from missing sqlite3 extension symbols
The earlier -Wl,-U,_sqlite3_enable_load_extension fix only satisfied the
linker; at runtime, Kotlin/Native's cinterop wrapper for that function still
resolves against the symbol the moment SQLDelight's native-driver opens a
connection, and Apple's system libsqlite3 doesn't export it on macOS — so
the app now crashed instead of failing to build.

Adds weak no-op definitions of sqlite3_enable_load_extension and
sqlite3_load_extension, compiled directly into the app (Xcode's
file-system-synchronized group picks the file up with no project.pbxproj
changes needed beyond what Xcode itself rewrote on this build). Weak means
a platform whose system library does provide the real symbol keeps using
that one; this only fills in where it's missing.

Verified there's no longer a crash by running the built macOS binary
directly and by installing/launching it on the iOS Simulator — neither
produced a dyld error or a crash report, versus two reproducible crash
reports beforehand with the exact reported failure signature.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 10:39:29 +03:00
tyiuandClaude Sonnet 5 f35fb05e7c Make the max-supply warning's BTC amount a link on every platform
Tapping "21,000,000 BTC" in the exceeds-max-supply warning now sets the BTC
field to that value, on both Compose (Android/Desktop/Web) and the native
SwiftUI screen (iOS/macOS) — Compose UI isn't rendered on iOS/macOS at all,
so that side needed its own AttributedString-based link.

The link is styled to match the surrounding warning text: Compose's
LinkAnnotation otherwise falls back to the theme's accent color unless every
interaction state's style is set explicitly, and SwiftUI renders `.link`
runs in the accent color regardless of the Text's own foregroundColor
modifier unless it's set directly on the link's AttributedString range.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 10:30:10 +03:00
tyiuandClaude Sonnet 5 b77455bfc8 Move currency row overflow menu to the right of the amount field
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 09:46:38 +03:00
tyiuandClaude Sonnet 5 200319de86 Fix Intl interop crash on Kotlin/JS web target
js("new Foo(x).bar()") can misparse so `new` binds to the whole chain
instead of just the constructor call, throwing "X.resolvedOptions is not a
constructor" at runtime on the JS target (Kotlin/Wasm was unaffected, since
its js() compiles through a different path). Binding the constructor result
to a local variable first removes the ambiguity.

This was also silently breaking systemCurrencies() and the currency display
name lookup, and had been cascading into an unrelated CoinGecko test
failure in the same karma bundle.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 09:34:40 +03:00
tyiuandClaude Sonnet 5 14298d450e Persist exchange rates, selected currencies, and price source via SQLDelight
Adds a SQLDelight-backed AppDatabase (Android, Desktop, iOS/macOS) so the
converter survives restarts: the last-known rates per price source, the
user's selected fiat currencies (with order preserved), and the last-used
price source all reload before the first network fetch completes. Web isn't
a shipped platform and SQLDelight's driver there needs a worker plus a wasm
sqlite binary, so it gets a lighter localStorage-backed implementation of
the same store interfaces instead.

Android needs an app Context for its driver, wired via a new
SatsPriceApplication. iOS/macOS need libsqlite3 linked explicitly (Swift's
autolinking only covers Shared.framework itself, not its C library
dependencies), plus two extension-loading symbols marked optional since
macOS's system sqlite build omits them.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 09:34:21 +03:00
tyiuandClaude Sonnet 5 8a73b140c4 Stop tracking moko-resources generated webpack/karma config
These config.d fragments are regenerated identically by the moko-resources
Gradle plugin on every build, so they're build output rather than source.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QpjMKWGoiT5aJBzhxvXkwp
2026-09-08 09:33:59 +03:00
tyiu 14ec044c44 Fix currencies screen padding and section header styling 2026-09-07 22:39:35 +03:00
tyiu d42a3c3241 Upgrade Gradle and plugin version 2026-09-07 22:25:51 +03:00
tyiu 2925c845bd Add manual currency sorting and improve currency categorization 2026-09-07 22:15:29 +03:00
tyiu deef01a58a Add support for macOS and backport to older OS versions 2026-09-03 20:06:59 +03:00
tyiu abf7cf2e83 Replace Skip implementation with Kotlin Multiplatform implementation 2026-09-02 22:11:32 +03:00
tyiu 902b683779 Add logo.png to attempt to fix Android app store listings 2025-03-31 08:58:34 -04:00
tyiu d2721d8dde Update zapstore description 2025-03-31 00:53:43 -04:00
tyiu 482e50b6ba Update version to v1.2.0 v1.2.0 2025-03-30 23:05:34 -04:00
tyiu 0d9debf7ca Update README (#1) 2025-03-30 23:02:38 -04:00
tyiu 82dbf16466 Improve formatting of numbers by adding grouping separators and limiting the number of fractional digits 2025-03-30 22:00:25 -04:00
tyiu 5cd4d9189b Fix indentation on #if macros 2024-12-01 19:28:14 +01:00
tyiu 44251a85a6 Add zapstore.yaml 2024-11-21 00:46:33 +02:00
tyiu 38310d922f Fix proguard-rules to keep com.sun.jna.** so that Android release APKs run on device v1.1.0 2024-11-20 23:26:25 +02:00
tyiu b13a472b10 Update app version to 1.1.0 (9) 2024-11-20 21:16:16 +02:00
tyiu d7cbd96e09 Consolidate sections for current currency and selected currencies 2024-11-20 20:33:23 +02:00
tyiu da21b78588 Add persistence of selected currencies to disk via SQLite 2024-11-20 20:22:39 +02:00
tyiu 303cad1076 Create separate CurrencyPickerView and tighten up ContentView 2024-11-11 00:45:39 +01:00
tyiu 9321f920b4 Add support for multiple currencies 2024-11-10 23:10:33 +01:00
tyiu 9faaa24e8d Add PriceFetcher API to fetch prices of multiple currencies 2024-11-10 14:08:25 +01:00
tyiu 6e8ef69136 Update build number to 8 2024-09-17 07:10:15 -07:00
tyiu e6eb78faa2 Fix macOS entitlements to enable outgoing connections 2024-09-17 07:08:13 -07:00
tyiu 5e11ffd3b1 Update version to 1.0.0 (7) v1.0.0 2024-09-14 21:21:06 -04:00
tyiu f11d6f437a Add missing titles to text fields 2024-09-14 21:16:22 -04:00
tyiu c39ab5ca7b Update app version to 0.2.0 (6) 2024-09-14 12:22:23 -04:00
tyiu 9a615b139b Fix build for macOS 2024-09-14 12:20:53 -04:00
tyiu ad61ff0575 Update app version to 0.2.0 (5) 2024-09-14 12:06:04 -04:00
tyiu e38c8dac85 Change currency picker style to navigation link 2024-09-14 11:35:22 -04:00
tyiu ba0be8bb93 Update build version to 0.2.0 (4) 2024-09-07 06:30:59 +03:00
tyiu c99cca7f87 Fix bug where clearing out currency value field does not clear out BTC value field 2024-09-07 06:30:27 +03:00
tyiu 3560b12c24 Add warning when BTC and sats exceed the maximum 2024-09-07 06:10:09 +03:00
tyiu edb10c48e6 Add support for currency selection 2024-09-07 05:55:34 +03:00
tyiu cb0397ba98 Update build version to 0.2.0 (2) 2024-09-02 10:14:58 +03:00