Skip to content

Fix double camera permission request on OS back and refactor qr scanner#655

Draft
pepina-dev wants to merge 4 commits into
masterfrom
refactor/qr-scanner
Draft

Fix double camera permission request on OS back and refactor qr scanner#655
pepina-dev wants to merge 4 commits into
masterfrom
refactor/qr-scanner

Conversation

@pepina-dev

@pepina-dev pepina-dev commented May 13, 2026

Copy link
Copy Markdown
Collaborator

Description

Moves scan qr logic to its own hook. Fix os back case on camera permission that caused to reopen the camera permission.

Type of Change

  • ✨ New feature (non-breaking change which adds functionality)
  • 🛠️ Bug fix (non-breaking change which fixes an issue)
  • ❌ Breaking change (fix or feature that would cause existing functionality to change)
  • 🧹 Code refactor
  • ✅ Build configuration change
  • 📝 Documentation
  • 🗑️ Chore
  • 🧪 Tests

How I Tested This

Os back case before deny or approve (on android)

  • sign up
  • go to start chat
  • click on qr code icon
  • Wait for camera permission request to be visible
  • go back with os back
  • Check that permission request doesn't appear again

Denied case

  • sign up
  • go to start chat
  • click on qr code icon
  • deny permision
  • click go to settings
  • give permission
  • check that then the camera opens

Granted case

  • sign up
  • go to start chat
  • click on qr code icon
  • give permission
  • check that then the camera opens
  • scan an npub from other device
  • Check that the profile is shown

Checklist

  • just precommit passes
  • Related issue linked (Closes #NNN)
  • CHANGELOG.md updated (if user-visible change)
  • Screenshots added (for UI changes)

Summary by CodeRabbit

  • New Features

    • Added a reusable QR scanner hook and public scanner helpers; widget now uses an explicit onQrCodeDetected callback.
  • Improvements

    • Improved camera permission flows, UI states, and app-resume handling for more reliable scanning.
    • Unified scanner state handling and controller lifecycle.
  • Bug Fixes

    • Trimmed QR payloads, ignored empty scans, and suppressed duplicate/overlapping detections.
  • Tests

    • Added comprehensive tests for scanning, permissions, lifecycle, error flows, and UI behavior.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Extracts QR scanning and permission lifecycle into a reusable useQrScanner hook; refactors QrScanner to consume the hook and rename its callback to onQrCodeDetected; updates screens and tests to use the new API.

Changes

QR Scanner Hook Extraction and Integration

Layer / File(s) Summary
Hook Configuration and Contracts
lib/hooks/use_qr_scanner.dart
ScannerState enum and globally overridable factories/requesters/checkers for controller creation and camera permission handling, with reset functions.
Hook Initialization and Permission Lifecycle
lib/hooks/use_qr_scanner.dart
Hook mount tracking with async permission request, transitions to ready or permissionDenied, and denial snapshot capture.
Hook Scanner Control and Detection
lib/hooks/use_qr_scanner.dart
Controller memoization keyed by retry key, start guard, barcode stream subscription extracting and trimming QR values, 500ms processing gate, cleanup, and retryScanner/setErrorState.
App Lifecycle & Resume Handling
lib/hooks/use_qr_scanner.dart
App lifecycle resume handling that re-checks permissions and conditionally retries using the stored denial snapshot.
QrScanner Widget Hook Integration
lib/widgets/qr_scanner.dart
Widget refactored to consume hook state/actions, constructor callback renamed onQrCodeDetected, MobileScanner key updated to ValueKey(controller), error handling delegated to hook, and hook APIs re-exported.
Screen Callback Integration
lib/screens/scan_npub_screen.dart, lib/screens/scan_nsec_screen.dart
ScanNpubScreen and ScanNsecScreen wired to onQrCodeDetected while preserving npub conversion and nsec pop behavior; related tests updated.
Hook Comprehensive Test Suite
test/hooks/use_qr_scanner_test.dart
New widget tests covering detection, trimming, throttling, lifecycle/resume flows, permission permutations, controller recreation, UI states, and start-guard.
QrScanner Widget & Screen Tests Update
test/widgets/qr_scanner_test.dart, test/screens/*
Existing widget and screen tests updated to use onQrCodeDetected, obsolete groups removed, imports cleaned, and expectations reformatted.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • dannym-arx
  • cypherpinkdev
  • jgmontoya
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Refactor qr scanner' is related to the changeset but lacks the recommended type prefix and is overly broad, not clearly summarizing the main architectural change (extraction of QR scanning logic into a dedicated hook). Use the recommended format: 'refactor(qr-scanner): extract scanning logic into useQrScanner hook' to clearly indicate the scope and primary architectural change.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/qr-scanner

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

@pepina-dev pepina-dev changed the title Refactor/qr scanner Refactor qr scanner May 13, 2026
@erskingardner
erskingardner force-pushed the fix/camera-permission branch 2 times, most recently from added72 to ee99e85 Compare May 13, 2026 09:49
Base automatically changed from fix/camera-permission to master May 14, 2026 15:34
@pepina-dev
pepina-dev force-pushed the refactor/qr-scanner branch from 59d3fea to 472b382 Compare May 15, 2026 05:11

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/hooks/use_qr_scanner.dart`:
- Around line 129-132: The cleanup closure in use_qr_scanner currently calls
subscription.cancel() with unawaited but calls controller.dispose() directly;
wrap controller.dispose() in unawaited as well (i.e., replace
controller.dispose(); with unawaited(controller.dispose());) to silence the
unawaited_futures lint and keep behavior consistent (also add the unawaited
import if not already present).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2947cdea-40e8-45a0-8611-6026017b1898

📥 Commits

Reviewing files that changed from the base of the PR and between b8b9e05 and 472b382.

📒 Files selected for processing (8)
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/screens/scan_nsec_screen_test.dart
  • test/widgets/qr_scanner_test.dart
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Test (3/4)
  • GitHub Check: Check
  • GitHub Check: Test (4/4)
  • GitHub Check: Test (2/4)
  • GitHub Check: Test (1/4)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

**/*.dart: Use single quotes for strings in Dart/Flutter code
Enable and respect prefer_const_constructors lint rule in Dart/Flutter code
Enable and respect prefer_final_locals lint rule in Dart/Flutter code
Set line width to 100 characters in Dart/Flutter code
Preserve trailing commas in Dart/Flutter code
Maintain minimum test coverage of 99%; never submit a PR that reduces test coverage
Avoid using // coverage:ignore, // coverage:ignore-line, // coverage:ignore-start, or // coverage:ignore-end to bypass coverage requirements; write tests instead (only exception: truly unreachable code)

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
**/*.{dart,rs}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add comments except for code that is really complex or hard to understand

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
test/**/*_test.dart

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*_test.dart: Test files should mirror source structure with _test.dart suffix
Use helpers from test/test_helpers.dart in tests: setUpTestView(), mountTestApp(), mountHook(), mountWidget(), mountStackedWidget()
Mock Rust API by extending MockWnApi from test/mocks/mock_wn_api.dart instead of implementing RustLibApi directly
Prefer find.byKey() over find.byIcon() in tests; add keys to icons in widgets and use find.byKey(const Key('icon_name')) in tests
Use valid 64-character hex strings for pubkeys in tests, not dummy values like 'abc' or 'test-pubkey'

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
test/**

⚙️ CodeRabbit configuration file

test/**: IMPORTANT: CI enforces coverage regression (coverage must never decrease). It does not enforce a fixed 95% minimum threshold.
Rules:

  • Test files mirror source structure with _test.dart suffix
  • Use helpers from test/test_helpers.dart (setUpTestView, mountTestApp, etc.)
  • Mock Rust API using RustLib.initMock(api: mockApi)
  • Always extend MockWnApi from test/mocks/mock_wn_api.dart
  • Prefer find.byKey() over find.byIcon() for widget testing
  • Use valid 64-char hex strings for pubkeys, not dummy values like 'abc'
  • Tests must be deterministic — no external service dependencies

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
lib/**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

lib/**/*.dart: Use flutter_screenutil for all size values (padding, margins, gaps, icon sizes, font sizes, border radius, container dimensions) to ensure responsive layouts. Use .w for width, .h for height, .sp for font size/letter spacing, and .r for radius
Avoid StatefulWidget; prefer providers (for shared app-wide state) or hooks (for widget-local state) instead

Files:

  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
lib/screens/**

⚙️ CodeRabbit configuration file

lib/screens/**: This is a Flutter screen (full-page widget).
Architecture rules:

  • Screens should WATCH Riverpod providers for shared state
  • Use flutter_hooks for ephemeral/local state (NOT StatefulWidget)
  • Pass data to hooks, not refs
  • Use flutter_screenutil (.w, .h, .sp, .r) for all size values
  • Widgets should use const constructors where possible
  • No comments except for truly complex logic
  • When a widget is extracted from a screen and only used in that one
    screen, it should be prefixed with the screen name (e.g.
    ChatListTile for a widget only used in the chat list screen).
    These are screen-scoped widgets and do NOT use the Wn prefix.

Files:

  • lib/screens/scan_nsec_screen.dart
  • lib/screens/scan_npub_screen.dart
lib/widgets/!(wn_)*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Complex reusable widgets should not have wn_/Wn prefix and may contain translations, hooks with Rust API calls, or other complex logic

Files:

  • lib/widgets/qr_scanner.dart
lib/widgets/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Screen-scoped widgets extracted from a single screen should be prefixed with the screen name and only used in that one screen

Files:

  • lib/widgets/qr_scanner.dart
lib/widgets/**

⚙️ CodeRabbit configuration file

lib/widgets/**: This is a reusable widget.
There are two kinds of reusable widgets:

  1. Design system widgets — simple, presentational widgets that match
    the Figma design system in name and structure. They have Widgetbook
    stories, contain only presentational logic, and do NOT have
    translations or Rust API calls.

    • File MUST be prefixed with wn_ (e.g. wn_filled_button.dart)
    • Class MUST be prefixed with Wn (e.g. WnFilledButton)
  2. Complex reusable widgets — used across multiple screens but contain
    translations, hooks with Rust API calls, or other complex logic
    that makes them harder to display in Widgetbook.

    • These do NOT use the wn_/Wn prefix
    • Example: OnboardingCarousel (used in multiple screens, has
      translations and a page controller inside)

General rules for all widgets in this directory:

  • Use const constructors where possible
  • Use flutter_screenutil (.w, .h, .sp, .r) for all dimensions
  • Avoid StatefulWidget — prefer hooks for local state
  • No comments except for truly complex logic

Files:

  • lib/widgets/qr_scanner.dart
lib/hooks/use_*.dart

📄 CodeRabbit inference engine (AGENTS.md)

lib/hooks/use_*.dart: Hook files should be prefixed with use_ (e.g., use_chat_list.dart)
Hook functions should start with use (e.g., useChatList())

Files:

  • lib/hooks/use_qr_scanner.dart
lib/hooks/**

⚙️ CodeRabbit configuration file

lib/hooks/**: This is a flutter_hooks hook (ephemeral widget-local state).
Rules:

  • Files must be prefixed with use_ (e.g. use_chat_list.dart)
  • Hook functions must start with use (e.g. useChatList())
  • Hooks receive data as parameters, not widget refs
  • Ensure proper cleanup/dispose of subscriptions and resources

Files:

  • lib/hooks/use_qr_scanner.dart
🧠 Learnings (38)
📚 Learning: 2025-12-23T14:37:11.241Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 9
File: test/screens/error_screen_test.dart:60-71
Timestamp: 2025-12-23T14:37:11.241Z
Learning: In tests for screen widgets that are not wired through the app's Routes.build (e.g., ErrorScreen under lib/screens/error_screen.dart), avoid mounting the full app with mountTestApp. instead, configure a minimal test harness with a custom router or navigator setup (e.g., a MaterialApp with a mock router) to render the screen in isolation. This ensures the test focuses on the screen's behavior without depending on the app's global routing configuration.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
📚 Learning: 2026-01-05T21:28:05.652Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: test/screens/profile_keys_screen_test.dart:14-23
Timestamp: 2026-01-05T21:28:05.652Z
Learning: In test mocks for the marmot-protocol/sloth project, allow skipping bounds checking for substring operations when test inputs are controlled and have proven sufficient length (e.g., 'test_pubkey' is always 12 characters). Favor simpler, deterministic mock implementations in such controlled test contexts, but avoid relaxing bounds checks in production code or tests with variable inputs. Apply this guideline primarily to test files under the test/ directory.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-07T16:49:18.694Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 33
File: test/screens/chat_screen_test.dart:245-282
Timestamp: 2026-01-07T16:49:18.694Z
Learning: In the marmot-protocol/sloth repository, it is acceptable to use force-unwrapping (!) in Dart test files as an implicit assertion: if a value is unexpectedly null, the test will fail. This guideline applies only to test code under the test/ directory and should not be used in production code.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-11T22:43:09.610Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 36
File: test/screens/chat_list_screen_test.dart:74-76
Timestamp: 2026-01-11T22:43:09.610Z
Learning: In Dart tests (e.g., test/screens/chat_list_screen_test.dart and related files), use setUp() to call _api.reset() to clean up StreamController resources. Do not suggest or rely on tearDownAll for this cleanup.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-04-14T03:52:37.716Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 565
File: test/providers/offline_provider_test.dart:63-177
Timestamp: 2026-04-14T03:52:37.716Z
Learning: In this repository, it’s acceptable to use fixed-time waits for test timing using `Future.delayed` (e.g., `await Future.delayed(const Duration(milliseconds: 10))`) inside test files. During code reviews, don’t recommend replacing these fixed sleeps with event-based or poll-based synchronization when the change is localized to Dart test files under the `test/` directory.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-06T01:08:41.552Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/widgets/wn_warning_box.dart:28-79
Timestamp: 2026-01-06T01:08:41.552Z
Learning: In reviews for the marmot-protocol/sloth repository, avoid suggesting accessibility, design, or general improvements unless they are strictly relevant to the PR description and its stated goals. Focus feedback on the specific PR objectives and requirements; ignore unrelated stylistic or broad improvement suggestions.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-15T14:42:54.111Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 39
File: lib/hooks/use_user_search.dart:47-53
Timestamp: 2026-01-15T14:42:54.111Z
Learning: When using npubFromHex(String hexPubkey) from lib/utils/formatting.dart, it already handles errors internally and returns null on failure. Do not wrap calls to this function in try/catch blocks. Instead, check for a null return and handle accordingly (e.g., treat as invalid hex). This guideline applies to all Dart files in the repository that may call this function.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-16T17:35:32.431Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 43
File: lib/hooks/use_network_relays.dart:155-184
Timestamp: 2026-01-16T17:35:32.431Z
Learning: In Dart/Flutter code, prefer void as the return type for fire-and-forget async functions that are intended to run in the background without blocking the caller. Using Future or Future<void> would allow callers to accidentally await, which could block for long periods. This pattern makes the call fire-and-forget by design. Apply to functions that intentionally should not be awaited; document the intent where appropriate. (Example context: pollRelayStatus in lib/hooks/use_network_relays.dart uses void to prevent callers from awaiting a potentially long-running background task.)

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-19T15:50:56.684Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 52
File: lib/screens/app_settings_screen.dart:30-40
Timestamp: 2026-01-19T15:50:56.684Z
Learning: Target the Flutter SDK version >= 3.27 across the repo. Since features like Column.spacing and Row.spacing were added in Flutter 3.27, you can safely use them in Dart files (e.g., lib/screens/app_settings_screen.dart) as long as the pubspec.yaml environment specifies Flutter >= 3.27. If needed, enforce this by validating the environment constraint (e.g., flutter, sdk: flutter) in pubspec.yaml.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-29T03:02:34.290Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 100
File: lib/widgets/wn_dropdown_selector.dart:126-139
Timestamp: 2026-01-29T03:02:34.290Z
Learning: Global font-family usage guideline: Since Manrope is configured in lib/theme.dart for both light and dark themes, individual TextStyle declarations should not specify fontFamily: 'Manrope'. During reviews, verify that no TextStyle instances override fontFamily unnecessarily; rely on theme inheritance instead. If a TextStyle must specify a font for a specific case, ensure it is clearly justified and localized, and document why the override is needed. This guideline applies across Dart files in the project (e.g., lib/widgets/wn_dropdown_selector.dart and related components).

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-29T16:02:52.588Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 129
File: test/widgets/wn_overlay_test.dart:84-91
Timestamp: 2026-01-29T16:02:52.588Z
Learning: In Dart/Flutter code, when constructing widgets inside an already-const context (for example, within a const Scaffold with a child that is a collection of widgets), avoid adding explicit const keywords to the children. The Dart analyzer treats these as implicitly const, and adding explicit const can trigger the unnecessary_const lint. Review test files and general Dart files to ensure you do not redundantly prefix children with const in const contexts; rely on the implicit const behavior instead.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-07T03:58:22.587Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/services/android_signer_service.dart:13-13
Timestamp: 2026-02-07T03:58:22.587Z
Learning: In Dart files across the repository, retain NIP (Nostr Implementation Possibilities) and MIP (Marmot Implementation Possibilities) protocol reference comments that link code to their specifications. While general guidance discourages extraneous comments, these references improve traceability and maintainability by documenting the protocol context for related implementation details. Keep them in Dart sources (e.g., lib/services/android_signer_service.dart) and ensure they are kept up-to-date.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-11T17:29:43.985Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/screens/app_settings_screen.dart:64-69
Timestamp: 2026-02-11T17:29:43.985Z
Learning: In the whitenoise Flutter app, after deleting all data and resetting auth, use Routes.goToHome(context) instead of Routes.goToLogin(context) because the home screen is the app entry point and will manage authentication routing. Apply this change to navigation calls that should land on the home screen after a data reset or auth reset. Update lib/screens/app_settings_screen.dart and any similar navigation points accordingly.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-18T18:36:13.394Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 315
File: lib/screens/edit_group_screen.dart:45-47
Timestamp: 2026-02-18T18:36:13.394Z
Learning: Whitenoise uses automated code formatting through the precommit workflow (just precommit). Do not tweak line wrapping or formatting manually; follow the formatter's output. Run the precommit formatter locally and ensure the code matches its styling decisions, and only deviate if the formatter cannot express the intended style (in which case adjust the code to satisfy the formatter).

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-04-06T09:36:06.726Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 553
File: lib/widgets/wn_copyable_field.dart:38-40
Timestamp: 2026-04-06T09:36:06.726Z
Learning: In Dart, `String.operator*` is a valid built-in operator for repeating strings (e.g., `'⬤' * 16`). In code reviews of Dart (`.dart`) files, do not treat expressions like `'text' * n` as invalid syntax and do not recommend replacing them with alternatives such as `List.filled(...).join()`; the operator is supported by `dart:core`.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-05-13T13:46:32.612Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 656
File: lib/hooks/use_block_actions.dart:3-3
Timestamp: 2026-05-13T13:46:32.612Z
Learning: In marmot-protocol/whitenoise code reviews, do not flag imports that reference FRB-generated bindings under `package:rust_lib_whitenoise/src/rust/...` as private-internals violations. In `rust_lib_whitenoise`, Dart bindings are intentionally generated into `lib/src/rust/`, and `analysis_options.yaml` sets `implementation_imports: false` to suppress the related Dart lint—so `package:rust_lib_whitenoise/src/rust/...` imports are the correct/only way to consume that FRB-generated API.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-05-13T13:46:39.250Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 656
File: lib/services/foreground_service.dart:13-16
Timestamp: 2026-05-13T13:46:39.250Z
Learning: In this repo (marmot-protocol/whitenoise), `rust_lib_whitenoise` is an FRB-generated Flutter package where the generated Dart bindings are intentionally exposed under `lib/src/rust/` as the public API surface. Do not treat imports like `package:rust_lib_whitenoise/src/rust/...` as breaking package API boundaries in code reviews (the project also sets `implementation_imports: false` in `analysis_options.yaml` to opt into this). Never raise concerns about `src/` imports from `rust_lib_whitenoise`.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-05T11:59:09.400Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 189
File: test/widgets/wn_filter_chip_test.dart:1-3
Timestamp: 2026-02-05T11:59:09.400Z
Learning: In Dart/Flutter test files, Offset is exported by package:flutter_test/flutter_test.dart. If you already import flutter_test, you do not need to import dart:ui for Offset. Ensure there are no conflicting Offset symbols when both imports occur.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-04-28T17:39:39.941Z
Learnt from: pepina-dev
Repo: marmot-protocol/whitenoise PR: 600
File: test/hooks/use_leave_group_test.dart:67-78
Timestamp: 2026-04-28T17:39:39.941Z
Learning: In this repo’s Dart test files under `test/` (e.g., `test/hooks/use_leave_group_test.dart`), it’s acceptable to avoid calling `mockApi.reset()` at the start of `setUp()` when the test suite already manually resets all relevant individual mock fields in `setUp()`. Reviewers should not flag the absence of a `reset()` call as long as every field that could leak state between tests is explicitly reinitialized and the tests are passing.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-05T20:05:32.918Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/screens/settings_screen.dart:76-88
Timestamp: 2026-01-05T20:05:32.918Z
Learning: In the Sloth project, tooltips should not be used for UI elements. During code reviews, verify that UI components do not include Tooltip widgets and replace them with accessible alternatives (e.g., long-press hints, labels, or interactive guidance). Apply this guidance across Dart UI files under lib (not just settings_screen.dart) to maintain a consistent design approach.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-09T13:25:18.531Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 33
File: lib/services/message_service.dart:14-26
Timestamp: 2026-01-09T13:25:18.531Z
Learning: When errors are presented to users in the Sloth codebase (UI layers such as snackbars, dialogs, toasts), show friendly, user-facing messages instead of raw Rust error messages. Implement a mapping from internal error types or codes to clear, non-technical messages, and surface actionable guidance for end users where appropriate. Avoid exposing internal stack traces or language runtime details; centralize common user-facing error wording in a dedicated utility or service and translate backend errors into concise, helpful UI messages.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-04-06T09:40:41.044Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 552
File: lib/screens/profile_keys_screen.dart:71-71
Timestamp: 2026-04-06T09:40:41.044Z
Learning: In this Flutter/Dart codebase, when using flutter_screenutil (e.g., ScreenUtil or ScreenUtil-based sizing like `w`, `h`), do not require scaled units for literal zero values. Specifically, in EdgeInsets (and similar sizing/padding/margin/gap APIs), bare numeric `0` should be allowed (e.g., `EdgeInsets.all(0)`, `EdgeInsets.symmetric(vertical: 0)`, `SizedBox(width: 0)`), because scaling `0` remains `0`. Only flag ScreenUtil violations when a non-zero literal needs to be expressed via `0.w`/`0.h` equivalents; do not flag bare `0`.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-01-15T15:00:17.356Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 39
File: lib/screens/user_search_screen.dart:50-75
Timestamp: 2026-01-15T15:00:17.356Z
Learning: In lib/screens/user_search_screen.dart and similar screen widgets in the sloth repository, prefer using inline ternary expressions for conditional rendering (e.g., isLoading → empty state → list) over extracting into separate widget classes when the conditional UI is simple. This improves readability by keeping the render logic in a single place. Reserve extracting to a separate widget only when the conditional UI becomes sufficiently complex or is reused across multiple screens.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-10T04:57:31.475Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 208
File: lib/screens/signup_screen.dart:66-70
Timestamp: 2026-02-10T04:57:31.475Z
Learning: In Dart/Flutter using flutter_hooks, a ValueNotifier (from useState) is disposed when the widget unmounts. Async callbacks (e.g., .then() on animations) may still run after disposal and throw 'A ValueNotifier was used after being disposed'. Reviewers should ensure that state updates in async callbacks are guarded by a mounted check (e.g., if (mounted) { notifier.value = ... } or cancel/avoid updating after disposal). This guideline applies to screen widgets under lib/screens and similar Dart files using hooks that manage widget lifecycle. Update code patterns to prevent post-disposal state updates, and document the rationale in comments where necessary.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-19T10:33:16.889Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 315
File: lib/screens/group_info_screen.dart:146-149
Timestamp: 2026-02-19T10:33:16.889Z
Learning: Pubkey validation (length/format) is performed by the Rust crate before data reaches Dart. Do not add defensive substring guards in Dart for pubkeys in lib/screens/**/*.dart or other Flutter code consuming group member pubkeys, as this would duplicate validation and be unnecessary. If any validation is needed in Dart, keep it to lightweight sanity checks only after data enters Dart and ensure it aligns with the Rust validation rules.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-04-06T09:40:51.965Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 552
File: lib/screens/sign_out_screen.dart:86-86
Timestamp: 2026-04-06T09:40:51.965Z
Learning: When reviewing Flutter/Dart code that uses ScreenUtil (e.g., ScreenUtil `.h`/`.w`/`.sp`), do not require converting a literal `0` used for padding/margin/sizing to a ScreenUtil expression. In sizing contexts like `EdgeInsets` (or other `EdgeInsets`/layout parameters), raw `0` is mathematically invariant (`0 * scale = 0`) and should not be flagged as a ScreenUtil violation. Only non-zero literal size values should be checked for ScreenUtil usage.

Applied to files:

  • lib/screens/scan_nsec_screen.dart
  • lib/screens/scan_npub_screen.dart
📚 Learning: 2026-02-19T02:12:52.425Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 316
File: test/hooks/use_chat_scroll_test.dart:96-114
Timestamp: 2026-02-19T02:12:52.425Z
Learning: In hook tests under test/hooks, using tester.pumpWidget directly is acceptable for simple hook logic tests that do not rely on localizations, providers, or screen utilities. If the test requires those features, use the mountWidget helper from test/test_helpers.dart (which wires in localizations, providers, and screen utilities). Apply this guideline to all files matching *_test.dart in test/hooks.

Applied to files:

  • test/hooks/use_qr_scanner_test.dart
📚 Learning: 2026-01-05T22:40:27.888Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/widgets/wn_image_picker.dart:127-143
Timestamp: 2026-01-05T22:40:27.888Z
Learning: In marmot-protocol's Sloth project (lib/widgets/...): image hosting URLs returned by blossom servers are always lowercase (http:// or https://). Do not implement or rely on case-insensitive URL protocol detection in WN image picker code; assume the protocol is lowercase. If URL protocol checks are needed, compare against the exact literals 'http://' and 'https://'. Add tests that assert URLs use lowercase protocols. This guideline applies to all Dart files under lib/widgets that handle image URLs.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-02-04T10:35:43.112Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 170
File: lib/widgets/wn_list_item.dart:232-234
Timestamp: 2026-02-04T10:35:43.112Z
Learning: In this repository ( marmot-protocol/sloth ), when writing widget build methods in Dart files under lib/widgets, only extract a local typography variable if context.typographyScaled or context.typography is used multiple times within the same build method. If typography is used only once, keep the inline access to avoid an unnecessary extra line. This guideline helps maintain readability and avoids premature refactoring.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-02-14T05:09:20.007Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 260
File: lib/widgets/wn_message_quote.dart:32-88
Timestamp: 2026-02-14T05:09:20.007Z
Learning: In Dart widget files under lib/widgets (matching lib/widgets/**/*.dart), spacing literals such as padding, gap values, and border radii should not be extracted into constants based on josefinalliende's preference. Apply this rule consistently across widget files to improve readability and avoid over-abstracting simple literals.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-01-22T20:15:04.277Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 78
File: lib/hooks/use_accounts.dart:21-38
Timestamp: 2026-01-22T20:15:04.277Z
Learning: In the Sloth Flutter app, for hook files under lib/hooks (e.g., use_accounts.dart), prefer logging errors using the project's logger (e.g., _logger.severe) rather than displaying SnackBars. SnackBars should not be used in hooks or for error handling; log errors centrally and surface user notifications only at UI layers. Ensure consistent use of logging severity and avoid UI side effects within hooks.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-05T20:27:05.455Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/hooks/use_android_signer.dart:38-41
Timestamp: 2026-02-05T20:27:05.455Z
Learning: In Dart files under lib/hooks that use useMemoized (flutter_hooks), if a platform check like platformIsAndroid is used only to construct a service and the platform will not change at runtime, you can omit that platform check from the useMemoized dependency list. Do not include invariant platform values in the dependencies, which prevents unnecessary recomputations. Apply this pattern to all relevant files in lib/hooks where the platform is constant over the app lifecycle.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-11T17:51:41.426Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/hooks/use_delete_all_data.dart:34-49
Timestamp: 2026-02-11T17:51:41.426Z
Learning: In the whitenoise Flutter app, within custom hooks under lib/hooks, do not wrap returned functions with useCallback. Define functions inline inside the hook body to maintain consistency across all hooks. This aligns with the project-wide convention for consistency. If a function must be stable across rebuilds, consider using appropriate Dart/Flutter patterns (e.g., local closures or memoization strategies) per the framework's guidance.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-11T23:40:32.726Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/hooks/use_delete_all_data.dart:7-24
Timestamp: 2026-02-11T23:40:32.726Z
Learning: In the whitenoise Flutter app, internal hook state classes (e.g., DeleteAllDataState in use_delete_all_data.dart) should implement manual copyWith methods rather than using Freezed. The Freezed package is appropriate for UI states, but not for hook-internal state classes. During reviews, flag hook state implementations that rely on Freezed and prefer explicit, hand-written copyWith for reliability and lighter dependencies. Apply this pattern broadly to all Dart files under lib/hooks/*.dart and any similar hook directories.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-04-02T18:58:10.024Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 494
File: lib/hooks/use_scroll_to_message.dart:17-18
Timestamp: 2026-04-02T18:58:10.024Z
Learning: When reviewing Flutter/Dart hooks that use `flutter_hooks` (e.g., `useRef` / “latest-value ref” pattern), do not treat `useRef.current`/`ref.value` reads inside async loops as a stale-closure bug. If a parameter like `hasMoreMessages` is passed into the hook and immediately synced at the top of the build (`ref.value = hasMoreMessages`), then async code should read the latest `ref.value` on each iteration, reflecting the most recent rebuild triggered by state changes. The stale-closure concern should apply to captured local variables that are not updated via a `useRef`, not to `useRef`-backed fields.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-07T04:45:18.077Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/hooks/use_nsec.dart:76-79
Timestamp: 2026-02-07T04:45:18.077Z
Learning: In Flutter, localization strings should be resolved and presented by widgets/screens, not inside hooks. Hooks (like those under lib/hooks) should return error codes (e.g., nsec_load_failed). Widgets should provide helper functions to map these codes to localized strings via AppLocalizations (e.g., _noticeMessageL10n, _signerErrorL10n). Apply this pattern across all hook files: hub on returning error codes, while UI components handle localization lookups using AppLocalizations.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-02T21:11:03.835Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 157
File: test/widgets/wn_middle_ellipsis_text_test.dart:11-20
Timestamp: 2026-02-02T21:11:03.835Z
Learning: In widget tests (files matching test/widgets/**/*_test.dart) that use the mountWidget helper from test/test_helpers.dart, you do not need to call setUpTestView(tester) separately before mounting. Rely on mountWidget for necessary setup to avoid redundant setUpTestView calls in these tests. If a test does not use mountWidget, continue using setUpTestView as before.

Applied to files:

  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-02T21:11:17.594Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 157
File: test/widgets/wn_copy_card_test.dart:8-16
Timestamp: 2026-02-02T21:11:17.594Z
Learning: In test/widgets/**/*_test.dart, when using the mountWidget helper, you do not need to call setUpTestView(tester) separately because mountWidget performs the necessary setup for widget tests. Rely on mountWidget to prepare the test environment and avoid redundant setUpTestView calls.

Applied to files:

  • test/widgets/qr_scanner_test.dart
🔇 Additional comments (14)
test/hooks/use_qr_scanner_test.dart (1)

1-335: LGTM!

test/widgets/qr_scanner_test.dart (1)

25-214: LGTM!

test/screens/scan_npub_screen_test.dart (1)

113-145: LGTM!

test/screens/scan_nsec_screen_test.dart (1)

120-130: LGTM!

lib/widgets/qr_scanner.dart (1)

7-24: LGTM!

Also applies to: 29-35, 41-48, 62-82

lib/screens/scan_npub_screen.dart (1)

22-30: LGTM!

Also applies to: 46-48

lib/screens/scan_nsec_screen.dart (1)

44-46: LGTM!

lib/hooks/use_qr_scanner.dart (7)

8-49: LGTM!


51-57: LGTM!


65-95: LGTM!


135-138: LGTM!


140-157: LGTM!


159-163: LGTM!


165-170: LGTM!

Comment thread lib/hooks/use_qr_scanner.dart
@github-actions

github-actions Bot commented May 15, 2026

Copy link
Copy Markdown

✅ Coverage: 99.03% → 99.03% (0.00%)

History
  • 0ffbfe0 2026-05-15 05:19:23 UTC — 99.37% (0.00% vs base)
  • 5d8587e 2026-05-15 06:03:47 UTC — 99.37% (0.00% vs base)
  • 402309a 2026-05-15 06:08:25 UTC — 99.37% (0.00% vs base)
  • 768b0da 2026-05-15 06:17:28 UTC — 99.37% (0.00% vs base)
  • b487062 2026-05-20 04:01:18 UTC — 99.03% (0.00% vs base)
  • 670dc52 2026-05-20 04:06:28 UTC — 99.03% (0.00% vs base)
  • 3788530 2026-05-20 04:33:59 UTC — 99.03% (0.00% vs base)
  • 128b841 2026-05-23 23:01:40 UTC — 99.03% (0.00% vs base)

@pepina-dev
pepina-dev force-pushed the refactor/qr-scanner branch 3 times, most recently from 8f8946f to 21b9b69 Compare May 15, 2026 06:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (1)
lib/hooks/use_qr_scanner.dart (1)

96-103: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add callback to useRef to capture the latest handler.

The handleQrCode listener closes over the callback from the build that installed it, but the effect at line 119 doesn't re-subscribe when onQrCodeDetected changes. If the parent rebuilds with a new handler, scans will keep invoking the stale closure until the scanner is retried.

Store the callback in a useRef and update it on every build so the listener always calls the latest version:

Suggested fix
  final scannerState = useState(ScannerState.loading);
  final permissionStatusAtDenial = useRef<PermissionStatus?>(null);
+  final onQrCodeDetectedRef = useRef(onQrCodeDetected);
+  onQrCodeDetectedRef.value = onQrCodeDetected;

  useEffect(() {
    if (scannerState.value != ScannerState.ready) return null;
    ...
    void handleQrCode(BarcodeCapture capture) {
      ...
-      onQrCodeDetected(rawValue.trim());
+      onQrCodeDetectedRef.value(rawValue.trim());
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/hooks/use_qr_scanner.dart` around lines 96 - 103, The handleQrCode
listener currently closes over the initial onQrCodeDetected and can become
stale; change the hook to store the latest onQrCodeDetected in a ref (e.g. final
qrHandlerRef = useRef<FunctionType?>(onQrCodeDetected)) and update
qrHandlerRef.value = onQrCodeDetected on every build, then have handleQrCode
call qrHandlerRef.value?.call(rawValue.trim()) instead of calling
onQrCodeDetected directly; this ensures the listener (installed by the effect
that sets up the scanner) always invokes the latest handler without
re-subscribing.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/hooks/use_qr_scanner.dart`:
- Around line 67-85: The permission-check effect can suffer a race where an
earlier checkPermission() finishes after a newer retry, overwriting state;
modify the effect around
checkPermission/requestCameraPermission/checkCameraPermissionStatus to use a
cancellation token (e.g., capture scannerRetryKey.value or create a local
bool/abort flag) checked before any state updates (isMounted check plus the
token) and ensure the cleanup returned by useEffect flips the token to cancel
the in-flight operation so older responses do not set
permissionStatusAtDenial.value or scannerState.value; reference the
functions/values checkPermission, requestCameraPermission,
checkCameraPermissionStatus, scannerRetryKey, isMounted,
permissionStatusAtDenial, scannerState, ScannerState and keep using
unawaited(checkPermission()) but guard updates with the cancellation check.
- Around line 100-103: Normalize the barcode payload by trimming before
validating: compute a trimmed value from barcode.rawValue (e.g., trimmed =
(barcode.rawValue ?? '').trim()), then return early if trimmed.isEmpty; only
after that set isProcessing.value = true and call onQrCodeDetected(trimmed).
Update references in this block (rawValue, isProcessing.value, onQrCodeDetected)
so the callback always receives the trimmed payload and whitespace-only scans
are ignored.
- Around line 67-84: The call to controller.start() inside startController can
throw MobileScannerException and currently isn't handled; wrap the
controller.start() invocation in a try-catch that catches MobileScannerException
(and optionally any other Exception), and on failure set scannerState.value =
ScannerState.initError (and optionally log or store the exception) so the hook
transitions to the init error state; update startController to perform this
try-catch around controller.start().

---

Duplicate comments:
In `@lib/hooks/use_qr_scanner.dart`:
- Around line 96-103: The handleQrCode listener currently closes over the
initial onQrCodeDetected and can become stale; change the hook to store the
latest onQrCodeDetected in a ref (e.g. final qrHandlerRef =
useRef<FunctionType?>(onQrCodeDetected)) and update qrHandlerRef.value =
onQrCodeDetected on every build, then have handleQrCode call
qrHandlerRef.value?.call(rawValue.trim()) instead of calling onQrCodeDetected
directly; this ensures the listener (installed by the effect that sets up the
scanner) always invokes the latest handler without re-subscribing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c1e69708-7ac6-4252-bcb1-93a99aa18c8e

📥 Commits

Reviewing files that changed from the base of the PR and between e7555de and 8f8946f.

📒 Files selected for processing (8)
  • lib/hooks/use_qr_scanner.dart
  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/widgets/qr_scanner.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/screens/scan_nsec_screen_test.dart
  • test/widgets/qr_scanner_test.dart
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: Test (2/4)
  • GitHub Check: Test (3/4)
  • GitHub Check: Test (4/4)
  • GitHub Check: Test (1/4)
🧰 Additional context used
📓 Path-based instructions (11)
**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

**/*.dart: Use single quotes for strings in Dart/Flutter code
Enable and respect prefer_const_constructors lint rule in Dart/Flutter code
Enable and respect prefer_final_locals lint rule in Dart/Flutter code
Set line width to 100 characters in Dart/Flutter code
Preserve trailing commas in Dart/Flutter code
Maintain minimum test coverage of 99%; never submit a PR that reduces test coverage
Avoid using // coverage:ignore, // coverage:ignore-line, // coverage:ignore-start, or // coverage:ignore-end to bypass coverage requirements; write tests instead (only exception: truly unreachable code)

Files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
**/*.{dart,rs}

📄 CodeRabbit inference engine (AGENTS.md)

Do not add comments except for code that is really complex or hard to understand

Files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
test/**/*_test.dart

📄 CodeRabbit inference engine (AGENTS.md)

test/**/*_test.dart: Test files should mirror source structure with _test.dart suffix
Use helpers from test/test_helpers.dart in tests: setUpTestView(), mountTestApp(), mountHook(), mountWidget(), mountStackedWidget()
Mock Rust API by extending MockWnApi from test/mocks/mock_wn_api.dart instead of implementing RustLibApi directly
Prefer find.byKey() over find.byIcon() in tests; add keys to icons in widgets and use find.byKey(const Key('icon_name')) in tests
Use valid 64-character hex strings for pubkeys in tests, not dummy values like 'abc' or 'test-pubkey'

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
test/**

⚙️ CodeRabbit configuration file

test/**: IMPORTANT: CI enforces coverage regression (coverage must never decrease). It does not enforce a fixed 95% minimum threshold.
Rules:

  • Test files mirror source structure with _test.dart suffix
  • Use helpers from test/test_helpers.dart (setUpTestView, mountTestApp, etc.)
  • Mock Rust API using RustLib.initMock(api: mockApi)
  • Always extend MockWnApi from test/mocks/mock_wn_api.dart
  • Prefer find.byKey() over find.byIcon() for widget testing
  • Use valid 64-char hex strings for pubkeys, not dummy values like 'abc'
  • Tests must be deterministic — no external service dependencies

Files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
lib/**/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

lib/**/*.dart: Use flutter_screenutil for all size values (padding, margins, gaps, icon sizes, font sizes, border radius, container dimensions) to ensure responsive layouts. Use .w for width, .h for height, .sp for font size/letter spacing, and .r for radius
Avoid StatefulWidget; prefer providers (for shared app-wide state) or hooks (for widget-local state) instead

Files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
lib/screens/**

⚙️ CodeRabbit configuration file

lib/screens/**: This is a Flutter screen (full-page widget).
Architecture rules:

  • Screens should WATCH Riverpod providers for shared state
  • Use flutter_hooks for ephemeral/local state (NOT StatefulWidget)
  • Pass data to hooks, not refs
  • Use flutter_screenutil (.w, .h, .sp, .r) for all size values
  • Widgets should use const constructors where possible
  • No comments except for truly complex logic
  • When a widget is extracted from a screen and only used in that one
    screen, it should be prefixed with the screen name (e.g.
    ChatListTile for a widget only used in the chat list screen).
    These are screen-scoped widgets and do NOT use the Wn prefix.

Files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
lib/hooks/use_*.dart

📄 CodeRabbit inference engine (AGENTS.md)

lib/hooks/use_*.dart: Hook files should be prefixed with use_ (e.g., use_chat_list.dart)
Hook functions should start with use (e.g., useChatList())

Files:

  • lib/hooks/use_qr_scanner.dart
lib/hooks/**

⚙️ CodeRabbit configuration file

lib/hooks/**: This is a flutter_hooks hook (ephemeral widget-local state).
Rules:

  • Files must be prefixed with use_ (e.g. use_chat_list.dart)
  • Hook functions must start with use (e.g. useChatList())
  • Hooks receive data as parameters, not widget refs
  • Ensure proper cleanup/dispose of subscriptions and resources

Files:

  • lib/hooks/use_qr_scanner.dart
lib/widgets/!(wn_)*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Complex reusable widgets should not have wn_/Wn prefix and may contain translations, hooks with Rust API calls, or other complex logic

Files:

  • lib/widgets/qr_scanner.dart
lib/widgets/*.dart

📄 CodeRabbit inference engine (AGENTS.md)

Screen-scoped widgets extracted from a single screen should be prefixed with the screen name and only used in that one screen

Files:

  • lib/widgets/qr_scanner.dart
lib/widgets/**

⚙️ CodeRabbit configuration file

lib/widgets/**: This is a reusable widget.
There are two kinds of reusable widgets:

  1. Design system widgets — simple, presentational widgets that match
    the Figma design system in name and structure. They have Widgetbook
    stories, contain only presentational logic, and do NOT have
    translations or Rust API calls.

    • File MUST be prefixed with wn_ (e.g. wn_filled_button.dart)
    • Class MUST be prefixed with Wn (e.g. WnFilledButton)
  2. Complex reusable widgets — used across multiple screens but contain
    translations, hooks with Rust API calls, or other complex logic
    that makes them harder to display in Widgetbook.

    • These do NOT use the wn_/Wn prefix
    • Example: OnboardingCarousel (used in multiple screens, has
      translations and a page controller inside)

General rules for all widgets in this directory:

  • Use const constructors where possible
  • Use flutter_screenutil (.w, .h, .sp, .r) for all dimensions
  • Avoid StatefulWidget — prefer hooks for local state
  • No comments except for truly complex logic

Files:

  • lib/widgets/qr_scanner.dart
🧠 Learnings (38)
📚 Learning: 2025-12-23T14:37:11.241Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 9
File: test/screens/error_screen_test.dart:60-71
Timestamp: 2025-12-23T14:37:11.241Z
Learning: In tests for screen widgets that are not wired through the app's Routes.build (e.g., ErrorScreen under lib/screens/error_screen.dart), avoid mounting the full app with mountTestApp. instead, configure a minimal test harness with a custom router or navigator setup (e.g., a MaterialApp with a mock router) to render the screen in isolation. This ensures the test focuses on the screen's behavior without depending on the app's global routing configuration.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
📚 Learning: 2026-01-05T21:28:05.652Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: test/screens/profile_keys_screen_test.dart:14-23
Timestamp: 2026-01-05T21:28:05.652Z
Learning: In test mocks for the marmot-protocol/sloth project, allow skipping bounds checking for substring operations when test inputs are controlled and have proven sufficient length (e.g., 'test_pubkey' is always 12 characters). Favor simpler, deterministic mock implementations in such controlled test contexts, but avoid relaxing bounds checks in production code or tests with variable inputs. Apply this guideline primarily to test files under the test/ directory.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-07T16:49:18.694Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 33
File: test/screens/chat_screen_test.dart:245-282
Timestamp: 2026-01-07T16:49:18.694Z
Learning: In the marmot-protocol/sloth repository, it is acceptable to use force-unwrapping (!) in Dart test files as an implicit assertion: if a value is unexpectedly null, the test will fail. This guideline applies only to test code under the test/ directory and should not be used in production code.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-11T22:43:09.610Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 36
File: test/screens/chat_list_screen_test.dart:74-76
Timestamp: 2026-01-11T22:43:09.610Z
Learning: In Dart tests (e.g., test/screens/chat_list_screen_test.dart and related files), use setUp() to call _api.reset() to clean up StreamController resources. Do not suggest or rely on tearDownAll for this cleanup.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-04-14T03:52:37.716Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 565
File: test/providers/offline_provider_test.dart:63-177
Timestamp: 2026-04-14T03:52:37.716Z
Learning: In this repository, it’s acceptable to use fixed-time waits for test timing using `Future.delayed` (e.g., `await Future.delayed(const Duration(milliseconds: 10))`) inside test files. During code reviews, don’t recommend replacing these fixed sleeps with event-based or poll-based synchronization when the change is localized to Dart test files under the `test/` directory.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-06T01:08:41.552Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/widgets/wn_warning_box.dart:28-79
Timestamp: 2026-01-06T01:08:41.552Z
Learning: In reviews for the marmot-protocol/sloth repository, avoid suggesting accessibility, design, or general improvements unless they are strictly relevant to the PR description and its stated goals. Focus feedback on the specific PR objectives and requirements; ignore unrelated stylistic or broad improvement suggestions.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-15T14:42:54.111Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 39
File: lib/hooks/use_user_search.dart:47-53
Timestamp: 2026-01-15T14:42:54.111Z
Learning: When using npubFromHex(String hexPubkey) from lib/utils/formatting.dart, it already handles errors internally and returns null on failure. Do not wrap calls to this function in try/catch blocks. Instead, check for a null return and handle accordingly (e.g., treat as invalid hex). This guideline applies to all Dart files in the repository that may call this function.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-16T17:35:32.431Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 43
File: lib/hooks/use_network_relays.dart:155-184
Timestamp: 2026-01-16T17:35:32.431Z
Learning: In Dart/Flutter code, prefer void as the return type for fire-and-forget async functions that are intended to run in the background without blocking the caller. Using Future or Future<void> would allow callers to accidentally await, which could block for long periods. This pattern makes the call fire-and-forget by design. Apply to functions that intentionally should not be awaited; document the intent where appropriate. (Example context: pollRelayStatus in lib/hooks/use_network_relays.dart uses void to prevent callers from awaiting a potentially long-running background task.)

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-19T15:50:56.684Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 52
File: lib/screens/app_settings_screen.dart:30-40
Timestamp: 2026-01-19T15:50:56.684Z
Learning: Target the Flutter SDK version >= 3.27 across the repo. Since features like Column.spacing and Row.spacing were added in Flutter 3.27, you can safely use them in Dart files (e.g., lib/screens/app_settings_screen.dart) as long as the pubspec.yaml environment specifies Flutter >= 3.27. If needed, enforce this by validating the environment constraint (e.g., flutter, sdk: flutter) in pubspec.yaml.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-29T03:02:34.290Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 100
File: lib/widgets/wn_dropdown_selector.dart:126-139
Timestamp: 2026-01-29T03:02:34.290Z
Learning: Global font-family usage guideline: Since Manrope is configured in lib/theme.dart for both light and dark themes, individual TextStyle declarations should not specify fontFamily: 'Manrope'. During reviews, verify that no TextStyle instances override fontFamily unnecessarily; rely on theme inheritance instead. If a TextStyle must specify a font for a specific case, ensure it is clearly justified and localized, and document why the override is needed. This guideline applies across Dart files in the project (e.g., lib/widgets/wn_dropdown_selector.dart and related components).

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-29T16:02:52.588Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 129
File: test/widgets/wn_overlay_test.dart:84-91
Timestamp: 2026-01-29T16:02:52.588Z
Learning: In Dart/Flutter code, when constructing widgets inside an already-const context (for example, within a const Scaffold with a child that is a collection of widgets), avoid adding explicit const keywords to the children. The Dart analyzer treats these as implicitly const, and adding explicit const can trigger the unnecessary_const lint. Review test files and general Dart files to ensure you do not redundantly prefix children with const in const contexts; rely on the implicit const behavior instead.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-07T03:58:22.587Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/services/android_signer_service.dart:13-13
Timestamp: 2026-02-07T03:58:22.587Z
Learning: In Dart files across the repository, retain NIP (Nostr Implementation Possibilities) and MIP (Marmot Implementation Possibilities) protocol reference comments that link code to their specifications. While general guidance discourages extraneous comments, these references improve traceability and maintainability by documenting the protocol context for related implementation details. Keep them in Dart sources (e.g., lib/services/android_signer_service.dart) and ensure they are kept up-to-date.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-11T17:29:43.985Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/screens/app_settings_screen.dart:64-69
Timestamp: 2026-02-11T17:29:43.985Z
Learning: In the whitenoise Flutter app, after deleting all data and resetting auth, use Routes.goToHome(context) instead of Routes.goToLogin(context) because the home screen is the app entry point and will manage authentication routing. Apply this change to navigation calls that should land on the home screen after a data reset or auth reset. Update lib/screens/app_settings_screen.dart and any similar navigation points accordingly.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-18T18:36:13.394Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 315
File: lib/screens/edit_group_screen.dart:45-47
Timestamp: 2026-02-18T18:36:13.394Z
Learning: Whitenoise uses automated code formatting through the precommit workflow (just precommit). Do not tweak line wrapping or formatting manually; follow the formatter's output. Run the precommit formatter locally and ensure the code matches its styling decisions, and only deviate if the formatter cannot express the intended style (in which case adjust the code to satisfy the formatter).

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-04-06T09:36:06.726Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 553
File: lib/widgets/wn_copyable_field.dart:38-40
Timestamp: 2026-04-06T09:36:06.726Z
Learning: In Dart, `String.operator*` is a valid built-in operator for repeating strings (e.g., `'⬤' * 16`). In code reviews of Dart (`.dart`) files, do not treat expressions like `'text' * n` as invalid syntax and do not recommend replacing them with alternatives such as `List.filled(...).join()`; the operator is supported by `dart:core`.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-05-13T13:46:32.612Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 656
File: lib/hooks/use_block_actions.dart:3-3
Timestamp: 2026-05-13T13:46:32.612Z
Learning: In marmot-protocol/whitenoise code reviews, do not flag imports that reference FRB-generated bindings under `package:rust_lib_whitenoise/src/rust/...` as private-internals violations. In `rust_lib_whitenoise`, Dart bindings are intentionally generated into `lib/src/rust/`, and `analysis_options.yaml` sets `implementation_imports: false` to suppress the related Dart lint—so `package:rust_lib_whitenoise/src/rust/...` imports are the correct/only way to consume that FRB-generated API.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-05-13T13:46:39.250Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 656
File: lib/services/foreground_service.dart:13-16
Timestamp: 2026-05-13T13:46:39.250Z
Learning: In this repo (marmot-protocol/whitenoise), `rust_lib_whitenoise` is an FRB-generated Flutter package where the generated Dart bindings are intentionally exposed under `lib/src/rust/` as the public API surface. Do not treat imports like `package:rust_lib_whitenoise/src/rust/...` as breaking package API boundaries in code reviews (the project also sets `implementation_imports: false` in `analysis_options.yaml` to opt into this). Never raise concerns about `src/` imports from `rust_lib_whitenoise`.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • lib/screens/scan_npub_screen.dart
  • test/screens/scan_npub_screen_test.dart
  • lib/screens/scan_nsec_screen.dart
  • test/hooks/use_qr_scanner_test.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-05T11:59:09.400Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 189
File: test/widgets/wn_filter_chip_test.dart:1-3
Timestamp: 2026-02-05T11:59:09.400Z
Learning: In Dart/Flutter test files, Offset is exported by package:flutter_test/flutter_test.dart. If you already import flutter_test, you do not need to import dart:ui for Offset. Ensure there are no conflicting Offset symbols when both imports occur.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-04-28T17:39:39.941Z
Learnt from: pepina-dev
Repo: marmot-protocol/whitenoise PR: 600
File: test/hooks/use_leave_group_test.dart:67-78
Timestamp: 2026-04-28T17:39:39.941Z
Learning: In this repo’s Dart test files under `test/` (e.g., `test/hooks/use_leave_group_test.dart`), it’s acceptable to avoid calling `mockApi.reset()` at the start of `setUp()` when the test suite already manually resets all relevant individual mock fields in `setUp()`. Reviewers should not flag the absence of a `reset()` call as long as every field that could leak state between tests is explicitly reinitialized and the tests are passing.

Applied to files:

  • test/screens/scan_nsec_screen_test.dart
  • test/screens/scan_npub_screen_test.dart
  • test/hooks/use_qr_scanner_test.dart
  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-01-05T20:05:32.918Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/screens/settings_screen.dart:76-88
Timestamp: 2026-01-05T20:05:32.918Z
Learning: In the Sloth project, tooltips should not be used for UI elements. During code reviews, verify that UI components do not include Tooltip widgets and replace them with accessible alternatives (e.g., long-press hints, labels, or interactive guidance). Apply this guidance across Dart UI files under lib (not just settings_screen.dart) to maintain a consistent design approach.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-01-09T13:25:18.531Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 33
File: lib/services/message_service.dart:14-26
Timestamp: 2026-01-09T13:25:18.531Z
Learning: When errors are presented to users in the Sloth codebase (UI layers such as snackbars, dialogs, toasts), show friendly, user-facing messages instead of raw Rust error messages. Implement a mapping from internal error types or codes to clear, non-technical messages, and surface actionable guidance for end users where appropriate. Avoid exposing internal stack traces or language runtime details; centralize common user-facing error wording in a dedicated utility or service and translate backend errors into concise, helpful UI messages.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-04-06T09:40:41.044Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 552
File: lib/screens/profile_keys_screen.dart:71-71
Timestamp: 2026-04-06T09:40:41.044Z
Learning: In this Flutter/Dart codebase, when using flutter_screenutil (e.g., ScreenUtil or ScreenUtil-based sizing like `w`, `h`), do not require scaled units for literal zero values. Specifically, in EdgeInsets (and similar sizing/padding/margin/gap APIs), bare numeric `0` should be allowed (e.g., `EdgeInsets.all(0)`, `EdgeInsets.symmetric(vertical: 0)`, `SizedBox(width: 0)`), because scaling `0` remains `0`. Only flag ScreenUtil violations when a non-zero literal needs to be expressed via `0.w`/`0.h` equivalents; do not flag bare `0`.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
  • lib/hooks/use_qr_scanner.dart
  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-01-15T15:00:17.356Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 39
File: lib/screens/user_search_screen.dart:50-75
Timestamp: 2026-01-15T15:00:17.356Z
Learning: In lib/screens/user_search_screen.dart and similar screen widgets in the sloth repository, prefer using inline ternary expressions for conditional rendering (e.g., isLoading → empty state → list) over extracting into separate widget classes when the conditional UI is simple. This improves readability by keeping the render logic in a single place. Reserve extracting to a separate widget only when the conditional UI becomes sufficiently complex or is reused across multiple screens.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
📚 Learning: 2026-02-10T04:57:31.475Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 208
File: lib/screens/signup_screen.dart:66-70
Timestamp: 2026-02-10T04:57:31.475Z
Learning: In Dart/Flutter using flutter_hooks, a ValueNotifier (from useState) is disposed when the widget unmounts. Async callbacks (e.g., .then() on animations) may still run after disposal and throw 'A ValueNotifier was used after being disposed'. Reviewers should ensure that state updates in async callbacks are guarded by a mounted check (e.g., if (mounted) { notifier.value = ... } or cancel/avoid updating after disposal). This guideline applies to screen widgets under lib/screens and similar Dart files using hooks that manage widget lifecycle. Update code patterns to prevent post-disposal state updates, and document the rationale in comments where necessary.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
📚 Learning: 2026-02-19T10:33:16.889Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 315
File: lib/screens/group_info_screen.dart:146-149
Timestamp: 2026-02-19T10:33:16.889Z
Learning: Pubkey validation (length/format) is performed by the Rust crate before data reaches Dart. Do not add defensive substring guards in Dart for pubkeys in lib/screens/**/*.dart or other Flutter code consuming group member pubkeys, as this would duplicate validation and be unnecessary. If any validation is needed in Dart, keep it to lightweight sanity checks only after data enters Dart and ensure it aligns with the Rust validation rules.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
📚 Learning: 2026-04-06T09:40:51.965Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 552
File: lib/screens/sign_out_screen.dart:86-86
Timestamp: 2026-04-06T09:40:51.965Z
Learning: When reviewing Flutter/Dart code that uses ScreenUtil (e.g., ScreenUtil `.h`/`.w`/`.sp`), do not require converting a literal `0` used for padding/margin/sizing to a ScreenUtil expression. In sizing contexts like `EdgeInsets` (or other `EdgeInsets`/layout parameters), raw `0` is mathematically invariant (`0 * scale = 0`) and should not be flagged as a ScreenUtil violation. Only non-zero literal size values should be checked for ScreenUtil usage.

Applied to files:

  • lib/screens/scan_npub_screen.dart
  • lib/screens/scan_nsec_screen.dart
📚 Learning: 2026-02-19T02:12:52.425Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 316
File: test/hooks/use_chat_scroll_test.dart:96-114
Timestamp: 2026-02-19T02:12:52.425Z
Learning: In hook tests under test/hooks, using tester.pumpWidget directly is acceptable for simple hook logic tests that do not rely on localizations, providers, or screen utilities. If the test requires those features, use the mountWidget helper from test/test_helpers.dart (which wires in localizations, providers, and screen utilities). Apply this guideline to all files matching *_test.dart in test/hooks.

Applied to files:

  • test/hooks/use_qr_scanner_test.dart
📚 Learning: 2026-01-22T20:15:04.277Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 78
File: lib/hooks/use_accounts.dart:21-38
Timestamp: 2026-01-22T20:15:04.277Z
Learning: In the Sloth Flutter app, for hook files under lib/hooks (e.g., use_accounts.dart), prefer logging errors using the project's logger (e.g., _logger.severe) rather than displaying SnackBars. SnackBars should not be used in hooks or for error handling; log errors centrally and surface user notifications only at UI layers. Ensure consistent use of logging severity and avoid UI side effects within hooks.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-05T20:27:05.455Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/hooks/use_android_signer.dart:38-41
Timestamp: 2026-02-05T20:27:05.455Z
Learning: In Dart files under lib/hooks that use useMemoized (flutter_hooks), if a platform check like platformIsAndroid is used only to construct a service and the platform will not change at runtime, you can omit that platform check from the useMemoized dependency list. Do not include invariant platform values in the dependencies, which prevents unnecessary recomputations. Apply this pattern to all relevant files in lib/hooks where the platform is constant over the app lifecycle.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-11T17:51:41.426Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/hooks/use_delete_all_data.dart:34-49
Timestamp: 2026-02-11T17:51:41.426Z
Learning: In the whitenoise Flutter app, within custom hooks under lib/hooks, do not wrap returned functions with useCallback. Define functions inline inside the hook body to maintain consistency across all hooks. This aligns with the project-wide convention for consistency. If a function must be stable across rebuilds, consider using appropriate Dart/Flutter patterns (e.g., local closures or memoization strategies) per the framework's guidance.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-11T23:40:32.726Z
Learnt from: untreu2
Repo: marmot-protocol/whitenoise PR: 225
File: lib/hooks/use_delete_all_data.dart:7-24
Timestamp: 2026-02-11T23:40:32.726Z
Learning: In the whitenoise Flutter app, internal hook state classes (e.g., DeleteAllDataState in use_delete_all_data.dart) should implement manual copyWith methods rather than using Freezed. The Freezed package is appropriate for UI states, but not for hook-internal state classes. During reviews, flag hook state implementations that rely on Freezed and prefer explicit, hand-written copyWith for reliability and lighter dependencies. Apply this pattern broadly to all Dart files under lib/hooks/*.dart and any similar hook directories.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-04-02T18:58:10.024Z
Learnt from: dannym-arx
Repo: marmot-protocol/whitenoise PR: 494
File: lib/hooks/use_scroll_to_message.dart:17-18
Timestamp: 2026-04-02T18:58:10.024Z
Learning: When reviewing Flutter/Dart hooks that use `flutter_hooks` (e.g., `useRef` / “latest-value ref” pattern), do not treat `useRef.current`/`ref.value` reads inside async loops as a stale-closure bug. If a parameter like `hasMoreMessages` is passed into the hook and immediately synced at the top of the build (`ref.value = hasMoreMessages`), then async code should read the latest `ref.value` on each iteration, reflecting the most recent rebuild triggered by state changes. The stale-closure concern should apply to captured local variables that are not updated via a `useRef`, not to `useRef`-backed fields.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-02-07T04:45:18.077Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 193
File: lib/hooks/use_nsec.dart:76-79
Timestamp: 2026-02-07T04:45:18.077Z
Learning: In Flutter, localization strings should be resolved and presented by widgets/screens, not inside hooks. Hooks (like those under lib/hooks) should return error codes (e.g., nsec_load_failed). Widgets should provide helper functions to map these codes to localized strings via AppLocalizations (e.g., _noticeMessageL10n, _signerErrorL10n). Apply this pattern across all hook files: hub on returning error codes, while UI components handle localization lookups using AppLocalizations.

Applied to files:

  • lib/hooks/use_qr_scanner.dart
📚 Learning: 2026-01-05T22:40:27.888Z
Learnt from: untreu2
Repo: marmot-protocol/sloth PR: 22
File: lib/widgets/wn_image_picker.dart:127-143
Timestamp: 2026-01-05T22:40:27.888Z
Learning: In marmot-protocol's Sloth project (lib/widgets/...): image hosting URLs returned by blossom servers are always lowercase (http:// or https://). Do not implement or rely on case-insensitive URL protocol detection in WN image picker code; assume the protocol is lowercase. If URL protocol checks are needed, compare against the exact literals 'http://' and 'https://'. Add tests that assert URLs use lowercase protocols. This guideline applies to all Dart files under lib/widgets that handle image URLs.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-02-04T10:35:43.112Z
Learnt from: erskingardner
Repo: marmot-protocol/sloth PR: 170
File: lib/widgets/wn_list_item.dart:232-234
Timestamp: 2026-02-04T10:35:43.112Z
Learning: In this repository ( marmot-protocol/sloth ), when writing widget build methods in Dart files under lib/widgets, only extract a local typography variable if context.typographyScaled or context.typography is used multiple times within the same build method. If typography is used only once, keep the inline access to avoid an unnecessary extra line. This guideline helps maintain readability and avoids premature refactoring.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-02-14T05:09:20.007Z
Learnt from: josefinalliende
Repo: marmot-protocol/whitenoise PR: 260
File: lib/widgets/wn_message_quote.dart:32-88
Timestamp: 2026-02-14T05:09:20.007Z
Learning: In Dart widget files under lib/widgets (matching lib/widgets/**/*.dart), spacing literals such as padding, gap values, and border radii should not be extracted into constants based on josefinalliende's preference. Apply this rule consistently across widget files to improve readability and avoid over-abstracting simple literals.

Applied to files:

  • lib/widgets/qr_scanner.dart
📚 Learning: 2026-02-02T21:11:03.835Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 157
File: test/widgets/wn_middle_ellipsis_text_test.dart:11-20
Timestamp: 2026-02-02T21:11:03.835Z
Learning: In widget tests (files matching test/widgets/**/*_test.dart) that use the mountWidget helper from test/test_helpers.dart, you do not need to call setUpTestView(tester) separately before mounting. Rely on mountWidget for necessary setup to avoid redundant setUpTestView calls in these tests. If a test does not use mountWidget, continue using setUpTestView as before.

Applied to files:

  • test/widgets/qr_scanner_test.dart
📚 Learning: 2026-02-02T21:11:17.594Z
Learnt from: josefinalliende
Repo: marmot-protocol/sloth PR: 157
File: test/widgets/wn_copy_card_test.dart:8-16
Timestamp: 2026-02-02T21:11:17.594Z
Learning: In test/widgets/**/*_test.dart, when using the mountWidget helper, you do not need to call setUpTestView(tester) separately because mountWidget performs the necessary setup for widget tests. Rely on mountWidget to prepare the test environment and avoid redundant setUpTestView calls.

Applied to files:

  • test/widgets/qr_scanner_test.dart
🔇 Additional comments (7)
test/hooks/use_qr_scanner_test.dart (1)

1-345: LGTM!

test/widgets/qr_scanner_test.dart (1)

25-214: LGTM!

lib/widgets/qr_scanner.dart (1)

7-7: LGTM!

Also applies to: 13-24, 29-29, 34-34, 41-49, 62-62, 71-71, 81-81

lib/screens/scan_npub_screen.dart (1)

22-22: LGTM!

Also applies to: 47-47

lib/screens/scan_nsec_screen.dart (1)

45-45: LGTM!

test/screens/scan_nsec_screen_test.dart (1)

120-120: LGTM!

Also applies to: 124-124

test/screens/scan_npub_screen_test.dart (1)

113-113: LGTM!

Also applies to: 119-119, 125-125, 129-129, 136-136, 140-140

Comment thread lib/hooks/use_qr_scanner.dart Outdated
Comment thread lib/hooks/use_qr_scanner.dart
Comment thread lib/hooks/use_qr_scanner.dart
@pepina-dev
pepina-dev force-pushed the refactor/qr-scanner branch from 21b9b69 to 3f2c215 Compare May 20, 2026 03:53
@pepina-dev pepina-dev changed the title Refactor qr scanner Fix double camera permission request on OS back and efactor qr scanner May 20, 2026
@pepina-dev pepina-dev changed the title Fix double camera permission request on OS back and efactor qr scanner Fix double camera permission request on OS back and refactor qr scanner May 20, 2026
@pepina-dev
pepina-dev force-pushed the refactor/qr-scanner branch from 81e0c92 to a3f4306 Compare May 20, 2026 04:26
@pepina-dev
pepina-dev force-pushed the refactor/qr-scanner branch from a3f4306 to 838992f Compare May 23, 2026 16:49
@stage-review

stage-review Bot commented May 23, 2026

Copy link
Copy Markdown

Ready to review this PR? Stage has broken it down into 4 individual chapters for you:

Title
1 Extract QR scanner logic into a reusable hook
2 Refactor QrScanner widget to use the new hook
3 Update screen implementations and tests
4 Document changes in CHANGELOG
Open in Stage

Chapters generated by Stage for commit 838992f on May 23, 2026 4:49pm UTC.

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.

1 participant