Repository navigation
Conversation
Use new Service Worker
Migration helpers
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughReplace direct IndexedDB contract persistence with injected SwapRepository/localStorage, migrate worker/lightning/wallet to a MessageBus + service-worker model, add Delegates settings UI and tests, refactor async swap subscription cleanup, and bump boltz-swap/sdk deps with pnpm config. Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Client/UI
participant SW as ServiceWorker (MessageBus)
participant Wallet as ServiceWorkerWallet
participant SwapRepo as IndexedDbSwapRepository
participant Lightning as ServiceWorkerArkadeLightning
Note over UI,SW: Initialization
UI->>SW: start/create MessageBus
SW->>Wallet: setup(storage: {walletRepository, contractRepository})
SW->>SwapRepo: instantiate IndexedDbSwapRepository
SW->>Lightning: ServiceWorkerArkadeLightning.create(swapRepository, arkServerUrl)
Lightning-->>SW: ready
Wallet-->>SW: wallet ready
SW-->>UI: started
Note over UI,SwapRepo: Backup / Restore
UI->>SW: trigger fullBackup()/restore()
SW->>SwapRepo: read/write swaps via swapRepository.saveSwap(...)
SwapRepo-->>SW: ack
SW-->>UI: operation complete
Note over Lightning,SwapRepo: Runtime swap persistence
Lightning->>SwapRepo: swapRepository.saveSwap(swap)
SwapRepo-->>Lightning: ack
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
* fix(ui): match iOS/Android status bar color to app theme
The status bar stayed white in dark mode because:
- The theme-color meta tag was hardcoded to #000000
- Safari doesn't reliably support media queries on theme-color
- The html element had no background-color, so the safe area defaulted to white
Fix: inline script in <head> reads the stored theme from localStorage
and sets theme-color + ion-palette-dark class before first paint.
applyTheme() keeps it in sync on manual toggle. Root element background
now follows --ion-background-color so the safe area fills correctly.
* fix(ui): add dev-only logging to theme bootstrap catch block
Address CodeRabbit nitpick: log theme init failures on localhost
so broken localStorage/config parsing is visible during development.
* fix(ios): status bar color matching and content overlap for iOS 26+ PWA
iOS 26+ ignores the theme-color meta tag — it derives the status bar
color from the actual rendered content at the top of the page. Add a
position:fixed body::before pseudo-element that sits behind the
transparent status bar and uses var(--ion-background-color), so iOS
samples the correct theme color instantly on theme switch.
Push .ion-page below the safe area with top: env(safe-area-inset-top)
using ion-app > .ion-page selector (higher specificity than Ionic's
core .ion-page { top: 0 } which loads later in the cascade).
Also fix manifest.json theme_color (#fff) and improve inline theme
bootstrap comments in index.html.
* style: fix prettier formatting in ionic.css
* fix(ui): match theme enum casing in bootstrap script
The Themes enum uses capitalized values ('Dark', 'Light', 'Auto') but
the inline bootstrap script compared against lowercase. This caused
the dark-mode flash prevention to fail when theme was explicitly set.
Also makes the iOS status bar comment version-agnostic per review.
---------
Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com>
…60227 # Conflicts: # src/index.css
* fix max balance when sending btc with assets * fix keyboard when sending assets
fix(pwa): fix swipe-back navigation for iOS standalone mode
* style(assets): rebrand Assets to Arkade Mint with pixel coin icon - Rename "Assets" to "Arkade Mint" across all asset screens (list, settings, mint success) - Replace placeholder "A" icon with Mario-style pixel coin in Arkade purple - New icon matches size/format of other app icons (55px/78px) * style(apps): redesign app cards with subtle surface treatment Replace Shadow border+borderPurple cards with whisper-surface style: - Subtle background tint instead of gray bg + harsh purple border - Tactile press state with scale(0.97) + background darken - Touch events matching Button component pattern (mouse + touch) - Icon aligned to top-left, description nested under title - Inline accessibility (role, tabIndex, keyboard handler) src/screens/Apps/Index.tsx * style: fix prettier formatting * fix(test): update test selectors after Assets → Arkade Mint rename The app card testId changed from 'app-assets' to 'app-arkade-mint' and the header/settings text changed accordingly. * fix(test): update 'Back to Assets' → 'Back to Arkade Mint' in tests MintSuccess button text was renamed but tests still referenced old text. --------- Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: Andrew Camilleri <evilkukka@gmail.com> Co-authored-by: Pietro Grandi <dev@pietro.uno>
* Upgrade ts-sdk@0.4.3 and boltz-swap@0.3.2 * Update SW
…stall banner (#375) * feat(onboarding): remove onboarding carousel, skip straight to wallet Remove the 4-step onboarding carousel (Onboard.tsx) and all supporting components (StepBars, Bullet, AlertBox, Announcement, Onboard1-4 SVGs). New users now go directly from Init → InitConnect → Wallet instead of through the carousel. The announcement/PSA system is also removed as it interrupted the flow without providing value. Files removed: - src/screens/Wallet/Onboard.tsx (carousel screen) - src/components/AlertBox.tsx, Announcement.tsx, Bullet.tsx, StepBars.tsx - src/icons/Onboard1-4.tsx (~10,800 lines of SVG illustrations) - src/providers/announcements.tsx (PSA announcement system) - Associated tests for removed components Files modified: - src/App.tsx: route to Init instead of Onboard for new wallets - src/screens/Init/*.tsx: navigate to InitConnect instead of InitSuccess - src/providers/navigation.tsx: remove Onboard from Pages enum - src/index.tsx: remove AnnouncementProvider wrapper - src/test/e2e/utils.ts: remove onboard steps from createWallet helper * feat(wallet): add dismissible PWA install banner and password nudge Add a new DismissibleBanner component used for both the PWA install prompt and the password creation nudge. The banner features Framer Motion enter/exit animations (EASE_OUT_QUINT, y:-24, scale:0.97), horizontal swipe-to-dismiss gesture, layout animation for smooth sibling reflow, and prefers-reduced-motion support with 44px touch targets. PWA install banner: - Mobile-only gating (isIOS || isAndroid) — hidden on desktop - Platform-specific descriptions (iOS share sheet vs Android install) - Module-level beforeinstallprompt capture for native install prompt - Respects persistent dismissed state via config.dismissedBanners Password nudge: - Replaced old AlertBox with DismissibleBanner (expanded layout) - Added nudgeVisible/nudgeCheckComplete to context for PWA banner priority coordination (PWA banner waits for nudge check) - Fixed error handling: .catch/.finally on async password check Config: replaced announcementsSeen with dismissedBanners (existing configs handled gracefully via ?? [] fallbacks). New files: - src/components/DismissibleBanner.tsx Modified: - src/screens/Wallet/Index.tsx (PWA banner integration) - src/providers/nudge.tsx (DismissibleBanner + error handling) - src/lib/pwa.ts (usePwaInstalled, beforeinstallprompt, promptPwaInstall) - src/lib/types.ts, src/providers/config.tsx (dismissedBanners) - src/ionic.css (--purple10 color variable) - src/test/setup.ts (matchMedia mock) * fix: address CodeRabbit review feedback - Password.tsx: reset restoring flag when navigating to InitConnect to prevent stale state from a previous restore attempt - DismissibleBanner.tsx: disable layout animation and popLayout mode when prefers-reduced-motion is active - Wallet/Index.tsx: only show Install action button when native prompt is available (Android); iOS shows instruction-only banner Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(wallet): clarify iOS PWA banner instruction text Update the iOS PWA install banner description to reference "the share icon in Safari's toolbar" instead of generic "the share button" so users know exactly where to look. * fix(pwa): return prompt outcome and auto-dismiss banner after install promptPwaInstall() now returns 'accepted' | 'dismissed' | null instead of void. On Android, the banner auto-dismisses after the user interacts with the native install prompt, rather than staying visible. * fix(banner): add haptic feedback to DismissibleBanner interactions Fire hapticSubtle() on button taps (Dismiss, Install, Set password) and on swipe-to-dismiss gesture, consistent with all other interactive elements in the app. * feat(onboarding): add animated SVG logo morph sequence with delight effects Redesign the Init screen with a rich onboarding animation: - OnboardingLogo: SVG cross-fade between Arcade, Space Invader, and Heart shapes with deep squash-stretch bounces using Framer Motion async animation controls. Final bounce flies logo to header position via FLIP. - PixelSplash: burst of purple pixel particles on each bounce - PixelSunrise: pixelated purple gradient at screen top (fixed position) - Three bullet points with outlined icon components (Bolt, Globe, ShieldCheck) replacing the old paragraph text - Reduced motion: all animations skip, content renders instantly Files: OnboardingLogo.tsx, PixelSplash.tsx, PixelSunrise.tsx, BoltOutline.tsx, GlobeOutline.tsx, ShieldCheckOutline.tsx, Init.tsx, ionic.css * style(onboarding): fix Prettier formatting in OnboardingLogo and Init * style(onboarding): smooth radial gradient, layout + status bar fixes - PixelSunrise: replace pixelated grid with smooth radial-gradient, remove all pixel dissolution code - Init: move content to bottom of screen (flex-end + paddingBottom), stack logo above title with optical alignment to bullet icons - Status bar: add apple-mobile-web-app-capable for PWA bleed-through, set theme-color to #8771BC (computed gradient top on white), fix manifest.json theme_color mismatch - Dynamic theme-color useEffect on Init screen for Safari tinting * style(onboarding): fix Prettier formatting in Init * fix(onboarding): stable fly target, gradient portal, dark mode prep - Always render content in DOM (hidden until ready) so logoTargetRef position is stable during fly animation instead of shifting on mount - Portal OnboardingLogo and PixelSunrise to document.body so they escape IonPage's max-width: 640px container on desktop - Add color-scheme light/dark to :root and .ion-palette-dark - Add color-scheme meta tag and body background-color for Safari - Sunrise animation synced with fly via onFlyStart callback - Snappier bounce physics: deeper squash, higher overshoot, faster timings * style(onboarding): fix Prettier formatting in Init.tsx * feat(onboarding): pixel morph animation, spring physics, loading bypass Logo morph animation: - Rewrite OnboardingLogo to use pixel-shapes.ts grid system instead of opacity crossfade between SVG path components - Arcade "A" always renders as clean SVG paths (never pixelated), while Invader and Heart shapes use pixel rects with CSS transform transitions - Spring-based bounce recovery (stiffness: 600, damping: 18, mass: 0.6) replaces scripted multi-step keyframes for natural overshoot feel - Morph + bounce happen simultaneously — shape swap at squash peak - Faster timing: 180ms initial pause, 60ms between morphs, ~1s total - Portal to document.body so logo escapes IonPage max-width on desktop Pixel splash particles: - Increase from 12-17 to 20-28 particles per burst - Wider velocity range (25-105) and more size variation (2.5-6.5px) Skip loading screen for new users: - New users (no wallet in storage) bypass ASP + JS capability gates, going straight to Init where the logo morph serves as intro visual - Wallet provider reads from localStorage synchronously via lazy useState initializer, eliminating one-frame Loading flash - "Create wallet" button stays disabled until ASP resolves Revert status bar changes: - All theme-color, color-scheme, and apple-mobile-web-app changes from this branch reverted — will be handled in a separate PR - Remove temp replay button and associated state Files: OnboardingLogo.tsx, PixelSplash.tsx, Init.tsx, App.tsx, wallet.tsx, index.html, manifest.json, ionic.css, index.css * fix(wallet): remove unused setWalletLoaded setter walletLoaded is now always true (synchronous init), so the setter is dead code. Replace useState with a constant to satisfy eslint. * Apply suggestion from @tiero Signed-off-by: Marco Argentieri <3596602+tiero@users.noreply.github.com> * fix: use named export for PageTransition to fix Rollup tree-shaking Rollup's module concatenation was dropping the default export definition while keeping the JSX references, causing 'PageTransition is not defined' at runtime. Named exports are handled more reliably. * fix: update e2e helpers for new onboarding flow (no more InitSuccess page) The onboarding flow now goes Init → InitConnect → Wallet directly, skipping the InitSuccess page. The createWallet() and restoreWallet() helpers were waiting for "Your new wallet is live!" / clicking "Go to wallet" which no longer exist, causing all Playwright tests to hang indefinitely. --------- Signed-off-by: Marco Argentieri <3596602+tiero@users.noreply.github.com> Co-authored-by: Sahil Chaturvedi <sahilc0@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Marco Argentieri <3596602+tiero@users.noreply.github.com> Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
…virtual (#394) * test: add smoke test for TransactionsList with large tx history Reproduces the reported lag on wallets with several thousand transactions. TransactionsList renders every row into the DOM at once with no windowing; render time scales linearly (~1.8ms/tx in jsdom), so: 100 txs → 471ms ✓ 500 txs → 1,475ms ✗ 1000 txs → 2,258ms ✗ 3000 txs → 5,477ms ✗ 5000 txs → 9,206ms ✗ The fix is to virtualise the list (e.g. @tanstack/react-virtual). This test will serve as the regression gate once that is in place. https://claude.ai/code/session_01LDxnFdhREuPcK3yPCkQUMU * perf(transactions): virtualise TransactionsList with @tanstack/react-virtual Fixes the wallet freeze / extreme lag reported for wallets with several thousand transactions. Root cause ---------- TransactionsList rendered every Tx into the DOM unconditionally via a plain .map() call. With no windowing, render time scaled linearly with the transaction count (~1.8 ms/tx in jsdom, worse in a real browser due to layout and paint): Before fix (all DOM nodes mounted): 100 txs → 471 ms 500 txs → 1 475 ms 1000 txs → 2 258 ms 3000 txs → 5 477 ms 5000 txs → 9 206 ms Fix --- Replace the plain map() with @tanstack/react-virtual's useVirtualizer. Only the rows that fit in the viewport (+ a 5-row overscan buffer above and below) are ever mounted in the DOM. The total DOM node count is now O(visible rows) ≈ 15–25 regardless of wallet history size. After fix (virtual rows only): 100 txs → 4 ms ✓ 500 txs → 3 ms ✓ 1000 txs → 4 ms ✓ 3000 txs → 4 ms ✓ 5000 txs → 3 ms ✓ The list renders in a self-contained scrollable container (height: calc(100dvh - 380px), min-height: 200px) so the balance/buttons section above it remains static — a common pattern in mobile wallet UIs. Smoke test update ----------------- - Added a DOM-count assertion: at most MAX_DOM_ROWS (20) rows may be mounted at any one time, ensuring virtualisation cannot regress silently. - Retained the per-count render-time assertions (≤ 500 ms) as a belt-and- braces guard. https://claude.ai/code/session_01LDxnFdhREuPcK3yPCkQUMU * feat(TransactionsList): add ArrowUp/ArrowDown keyboard navigation with virtualizer scroll-sync Add focusedIndex state and handleListKeyDown on the parentRef scroll container. Arrow key presses call virtualizer.scrollToIndex(next) then requestAnimationFrame to focus the target Focusable row once it is mounted. Existing Enter → handleClick and Escape → focusOnOuterShell behaviour is preserved; Tab is unchanged. https://claude.ai/code/session_01LDxnFdhREuPcK3yPCkQUMU * fix(TransactionsList): guard focusRow and focusOnFirstRow against empty/out-of-range indices Add an early-return bounds check in focusRow (index < 0 || index >= txs.length) to prevent virtualizer.scrollToIndex and key(txs[index]) from executing on invalid indices. Move the txs.length === 0 guard before setFocused(true) in focusOnFirstRow so focused is never set true when there are no rows to navigate. The focusRow guard also covers the edge case in handleListKeyDown where txs.length === 0 would produce a -1 next index. https://claude.ai/code/session_01LDxnFdhREuPcK3yPCkQUMU * remove transactions smoke test https://claude.ai/code/session_01LDxnFdhREuPcK3yPCkQUMU * fix(keyboard): sync focusedIndex with actual DOM focus on row focus events (#397) * Initial plan * fix(keyboard): sync focusedIndex with actual DOM focus on row focus events Co-authored-by: tiero <3596602+tiero@users.noreply.github.com> * chore: remove accidentally committed package-lock.json Co-authored-by: tiero <3596602+tiero@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: tiero <3596602+tiero@users.noreply.github.com> * fix: hide virtualizer scrollbar and address review feedback - Hide scrollbar on transaction list (reported by @Kukks) - Remove package-lock.json from .gitignore (feedback from @pietro909) - Remove redundant setFocusedIndex calls (CodeRabbit nitpick) --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: Andrew Camilleri <evilkukka@gmail.com>
Rows with asset info (e.g. "-14.7 BB") are taller than the 61px estimate, causing overlap. Enable measureElement so @tanstack/react-virtual measures actual DOM heights instead of relying on the fixed estimate.
* remove tooltip from Text * show amounts in separate line in coin list
- Switch DismissibleBanner button color from --purple to --purpletext - Add --purpletext dark mode override (#9678f7) for better contrast
The onFocus handler on virtualised rows called setState (setFocused, setFocusedIndex), triggering a React re-render that destroyed the clicked DOM element before the click event completed. Convert both to refs since they're only used in event handlers, not render output.
Used to get an up-to-date version of next.
Summary by CodeRabbit
New Features
Bug Fixes
Chores
Tests