Skip to content

feat: enable QR scanner for NWC wallet import#516

Merged
grunch merged 3 commits into
mainfrom
feat/qr-scanner-nwc-import
Mar 9, 2026
Merged

feat: enable QR scanner for NWC wallet import#516
grunch merged 3 commits into
mainfrom
feat/qr-scanner-nwc-import

Conversation

@mostronatorcoder

@mostronatorcoder mostronatorcoder Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Replaces the "coming soon" placeholder with a functional QR code scanner on the Connect Wallet screen, allowing users to scan nostr+walletconnect:// URIs from compatible wallets (Alby, Mutiny, etc.).

Closes #513

Changes

New: QrScannerScreen (lib/shared/widgets/qr_scanner_screen.dart)

  • Full-screen camera scanner using mobile_scanner v7.0.1
  • Optional uriPrefix parameter filters scanned codes (only NWC URIs accepted)
  • Torch toggle and camera switch buttons
  • Viewfinder overlay for scan area indication
  • Returns scanned value via Navigator.pop()
  • Reusable for future scanning needs (Lightning invoices, npubs, etc.)

Updated: ConnectWalletScreen

  • _showQrComingSoon() replaced with _openQrScanner() — requests camera permission, launches scanner, auto-fills URI field on successful scan
  • Scan icon color changed from textSecondary (gray) to activeColor (green) to indicate it is now functional
  • Clears validation errors when URI is scanned

Platform Config

  • Android: Added CAMERA permission to AndroidManifest.xml
  • iOS: NSCameraUsageDescription was already present

Localization

  • Added cameraPermissionDenied string in EN, ES, FR, IT ARB files

Dependency

  • Added mobile_scanner: ^7.0.1 — uses CameraX (Android) and AVFoundation (iOS)

Documentation

  • Added docs/QR_SCANNER_NWC_IMPLEMENTATION.md explaining implementation decisions

UX Flow

  1. User taps QR scan icon (now green/active)
  2. Camera permission requested if needed
  3. Full-screen scanner opens with viewfinder
  4. Point camera at NWC QR code
  5. URI auto-fills in text field
  6. Tap "Connect Wallet" to complete

Testing

  • Scan QR code from Alby wallet
  • Scan QR code from Mutiny wallet
  • Scan non-NWC QR code (should be ignored)
  • Deny camera permission (should show snackbar)
  • Manual URI paste still works

Summary by CodeRabbit

  • New Features

    • Added QR code scanner for wallet connections with URI filtering.
    • Enhanced scan icon visibility with color adjustment.
  • Documentation

    • Added comprehensive QR scanner implementation guide including design decisions and feature overview.
  • Localization

    • Added camera permission denial message across English, Spanish, French, and Italian locales.

Replace the 'coming soon' placeholder with a functional QR code scanner
on the Connect Wallet screen.

Changes:
- Add mobile_scanner v7.0.1 dependency for camera-based QR scanning
- Create reusable QrScannerScreen widget with URI prefix filtering,
  torch toggle, camera switch, and viewfinder overlay
- Update ConnectWalletScreen to launch scanner with
  'nostr+walletconnect://' prefix filter
- Add CAMERA permission to Android manifest (iOS already had it)
- Add cameraPermissionDenied localization string (EN, ES, FR, IT)
- Change scan icon color from textSecondary to activeColor

Closes #513
- Replace deprecated torchState ValueListenable with local state
  tracking (mobile_scanner v7 API change)
- Fix use_build_context_synchronously warnings by capturing
  ScaffoldMessenger and Navigator before async gaps
@grunch

grunch commented Mar 6, 2026

Copy link
Copy Markdown
Member

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8f95b4b6-4274-41e4-a3ed-ee267e73086e

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR enables QR code scanning for the NWC wallet import flow. It adds a new reusable QrScannerScreen widget using the mobile_scanner package, integrates it into the Connect Wallet screen, requests Android camera permissions, and includes camera permission denial messages across English, Spanish, French, and Italian locales. Implementation documentation is provided.

Changes

Cohort / File(s) Summary
QR Scanner Widget
lib/shared/widgets/qr_scanner_screen.dart
New full-screen QR scanner widget with optional URI prefix filtering, torch and camera switching controls, overlay UI, and detection logic that prevents multiple results via a flag.
Connect Wallet Screen
lib/features/wallet/screens/connect_wallet_screen.dart
Updated scan icon color and replaced "Coming soon" dialog with QR scanner launch; added async permission request flow with mounted checks, SnackBar error handling, and URI field population on successful scan.
Localization
lib/l10n/intl_en.arb, lib/l10n/intl_es.arb, lib/l10n/intl_fr.arb, lib/l10n/intl_it.arb
Added "cameraPermissionDenied" translation string with appropriate camera permission denial messages for each language.
Platform & Dependencies
android/app/src/main/AndroidManifest.xml, pubspec.yaml
Added Android CAMERA permission declaration; added mobile_scanner ^7.0.1 dependency.
Documentation
docs/QR_SCANNER_NWC_IMPLEMENTATION.md
New implementation guide documenting feature goals, design decisions (permission handling, package choice), runtime permission flow, UX sequence, and key files involved.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant ConnectWallet as ConnectWalletScreen
    participant PermHandler as PermissionHandler
    participant QRScanner as QrScannerScreen
    participant Camera as MobileScannerController
    
    User->>ConnectWallet: Tap QR scan icon
    ConnectWallet->>PermHandler: Request CAMERA permission
    alt Permission Denied
        PermHandler-->>ConnectWallet: Permission denied
        ConnectWallet-->>User: Show SnackBar (cameraPermissionDenied)
    else Permission Granted
        PermHandler-->>ConnectWallet: Permission granted
        ConnectWallet->>QRScanner: Navigate with uriPrefix filter
        activate QRScanner
        User->>Camera: Aim at QR code
        Camera->>QRScanner: onDetect callback (barcode data)
        QRScanner->>QRScanner: Apply prefix filter & validation
        QRScanner-->>ConnectWallet: Pop with scanned URI
        deactivate QRScanner
        ConnectWallet->>ConnectWallet: Populate _uriController with result
        ConnectWallet->>ConnectWallet: Clear _validationError
        ConnectWallet-->>User: Display URI in text field
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A scanner hops into the flow,
With camera permissions aglow,
QR codes now dance in the light,
Wallets connect with a tap so right,
No more "coming soon" in sight! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely summarizes the main change: enabling a QR scanner functionality for NWC wallet import, which directly aligns with the primary objective of replacing the 'coming soon' placeholder with a working QR scanner on the Connect Wallet screen.
Linked Issues check ✅ Passed The PR fully implements all requirements from issue #513: QR scanner functional on Connect Wallet screen, scans nostr+walletconnect:// URIs, camera permission handling, localization support, and a reusable QrScannerScreen widget with optional URI prefix filtering.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the QR scanner feature for NWC wallet import. No unrelated modifications detected; all code, documentation, permissions, and localization changes support the stated objective.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/qr-scanner-nwc-import

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
lib/features/wallet/screens/connect_wallet_screen.dart (1)

255-262: Defer the permission-denied SnackBar to a post-frame callback.

This branch fires a UI side effect directly after the async permission request. The repo guideline asks SnackBars/dialogs to be scheduled with a post-frame callback instead.

Suggested change
       if (mounted) {
-        messenger.showSnackBar(
-          SnackBar(
-            content: Text(permDeniedMsg),
-            backgroundColor: AppTheme.backgroundCard,
-            behavior: SnackBarBehavior.floating,
-          ),
-        );
+        WidgetsBinding.instance.addPostFrameCallback((_) {
+          if (!mounted) return;
+          messenger.showSnackBar(
+            SnackBar(
+              content: Text(permDeniedMsg),
+              backgroundColor: AppTheme.backgroundCard,
+              behavior: SnackBarBehavior.floating,
+            ),
+          );
+        });
       }

As per coding guidelines, "Keep UI code declarative and side-effect free. Use post-frame callbacks for side effects like SnackBars/dialogs."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/features/wallet/screens/connect_wallet_screen.dart` around lines 255 -
262, The SnackBar is being shown immediately after an async permission request;
move that UI side effect into a post-frame callback by wrapping the
messenger.showSnackBar(...) call (the branch that uses permDeniedMsg and
mounted) inside a WidgetsBinding.instance.addPostFrameCallback (or
SchedulerBinding.instance.addPostFrameCallback) to ensure the SnackBar is
scheduled after the current frame; keep the mounted check and same SnackBar
content/behavior when invoking messenger.showSnackBar.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@lib/shared/widgets/qr_scanner_screen.dart`:
- Around line 54-80: The three IconButton controls (the leading close HeroIcon,
the torch toggle IconButton using _torchOn and _controller.toggleTorch, and the
camera switch IconButton calling _controller.switchCamera) lack accessibility
labels; add localized tooltips or semantics labels by creating ARB entries (e.g.
"close", "toggleTorch", "switchCamera") and replace hard-coded strings with
S.of(context)!.close, S.of(context)!.toggleTorch, S.of(context)!.switchCamera,
then set each IconButton's tooltip: parameter (or wrap with Semantics(label:
...)) so TalkBack/VoiceOver announces the localized labels. Ensure you use the
same S.of(context) access pattern used elsewhere in this file.

---

Nitpick comments:
In `@lib/features/wallet/screens/connect_wallet_screen.dart`:
- Around line 255-262: The SnackBar is being shown immediately after an async
permission request; move that UI side effect into a post-frame callback by
wrapping the messenger.showSnackBar(...) call (the branch that uses
permDeniedMsg and mounted) inside a WidgetsBinding.instance.addPostFrameCallback
(or SchedulerBinding.instance.addPostFrameCallback) to ensure the SnackBar is
scheduled after the current frame; keep the mounted check and same SnackBar
content/behavior when invoking messenger.showSnackBar.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 430c7be5-1118-49d7-a841-27dff3bc27a3

📥 Commits

Reviewing files that changed from the base of the PR and between 795302e and 8a6ef5b.

📒 Files selected for processing (9)
  • android/app/src/main/AndroidManifest.xml
  • docs/QR_SCANNER_NWC_IMPLEMENTATION.md
  • lib/features/wallet/screens/connect_wallet_screen.dart
  • lib/l10n/intl_en.arb
  • lib/l10n/intl_es.arb
  • lib/l10n/intl_fr.arb
  • lib/l10n/intl_it.arb
  • lib/shared/widgets/qr_scanner_screen.dart
  • pubspec.yaml

Comment on lines +54 to +80
leading: IconButton(
icon: const HeroIcon(HeroIcons.xMark, color: Colors.white),
onPressed: () => context.pop(),
),
title: Text(
S.of(context)!.scanQrCode,
style: const TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
actions: [
IconButton(
icon: Icon(
_torchOn ? Icons.flash_on : Icons.flash_off,
color: _torchOn ? AppTheme.activeColor : Colors.white,
),
onPressed: () async {
await _controller.toggleTorch();
setState(() => _torchOn = !_torchOn);
},
),
IconButton(
icon: const Icon(Icons.cameraswitch, color: Colors.white),
onPressed: () => _controller.switchCamera(),
),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add localized labels to the scanner action buttons.

These three icon-only controls are currently unlabeled, so TalkBack/VoiceOver will expose them as generic buttons. Please add localized tooltips or explicit semantics labels for close, torch, and camera switch before shipping this screen.

As per coding guidelines, "Localize all user-facing strings via ARB files and access them with S.of(context) rather than hard-coded string literals."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/shared/widgets/qr_scanner_screen.dart` around lines 54 - 80, The three
IconButton controls (the leading close HeroIcon, the torch toggle IconButton
using _torchOn and _controller.toggleTorch, and the camera switch IconButton
calling _controller.switchCamera) lack accessibility labels; add localized
tooltips or semantics labels by creating ARB entries (e.g. "close",
"toggleTorch", "switchCamera") and replace hard-coded strings with
S.of(context)!.close, S.of(context)!.toggleTorch, S.of(context)!.switchCamera,
then set each IconButton's tooltip: parameter (or wrap with Semantics(label:
...)) so TalkBack/VoiceOver announces the localized labels. Ensure you use the
same S.of(context) access pattern used elsewhere in this file.

…timing

- Add localized tooltips to QR scanner IconButtons (close, toggleTorch,
  switchCamera) for TalkBack/VoiceOver accessibility
- Add toggleTorch and switchCamera localization strings (EN, ES, FR, IT)
- Wrap permission-denied SnackBar in addPostFrameCallback to ensure
  it schedules after the current frame completes

@grunch grunch left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK

@grunch grunch merged commit 12eaee4 into main Mar 9, 2026
2 checks passed
@grunch grunch deleted the feat/qr-scanner-nwc-import branch March 9, 2026 12:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enable QR scanner for NWC wallet import

4 participants