Skip to content

Improve landing QR code refresh flow#1949

Merged
crossle merged 1 commit intomainfrom
fix/landing-qrcode-refresh
Mar 31, 2026
Merged

Improve landing QR code refresh flow#1949
crossle merged 1 commit intomainfrom
fix/landing-qrcode-refresh

Conversation

@YeungKC
Copy link
Copy Markdown
Collaborator

@YeungKC YeungKC commented Mar 31, 2026

What changed

  • make landing QR codes auto-refresh once when they expire instead of immediately forcing a manual retry
  • prevent stale async provisioning requests from overwriting newer QR codes
  • surface retry UI after repeated polling failures instead of silently leaving stale QR state
  • force QR widget rebuilds when the auth URL changes
  • add cubit tests for expiry refresh, retry fallback, and stale request protection

Validation

  • flutter test test/ui/landing/bloc/landing_qrcode_cubit_test.dart
  • flutter analyze lib/ui/landing/bloc/landing_cubit.dart lib/ui/landing/bloc/landing_state.dart lib/ui/landing/landing_qrcode.dart test/ui/landing/bloc/landing_qrcode_cubit_test.dart

@YeungKC YeungKC marked this pull request as ready for review March 31, 2026 06:36
@crossle crossle requested a review from Copilot March 31, 2026 07:04
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves the landing-page QR login flow by making QR expiry and polling failures behave more robustly, reducing stale async overwrites, and ensuring the QR widget refreshes correctly when the auth URL changes.

Changes:

  • Add request-versioning to prevent stale async provisioning responses from overwriting newer QR codes.
  • Auto-refresh QR codes on expiry and surface a retry UI after repeated polling failures.
  • Force QR widget rebuilds on auth URL changes and add targeted cubit tests for the new behaviors.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
lib/ui/landing/bloc/landing_cubit.dart Adds injected loaders/streams for testability, request-versioning guards, auto-refresh + retry-state logic, and polling failure handling.
lib/ui/landing/bloc/landing_state.dart Extends copyWith to support clearing/updating errorMessage.
lib/ui/landing/landing_qrcode.dart Keys the QR widget by URL to force rebuild when the auth URL changes.
test/ui/landing/bloc/landing_qrcode_cubit_test.dart Adds tests covering stale request protection, expiry refresh, and retry fallback behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +168 to +169
? 'Failed to refresh QR code: $error'
: 'Failed to request auth: $error',
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

The user-visible retry Tooltip error message is built from raw exceptions (e.g., "Failed to request auth: $error" / "Failed to refresh QR code: $error"). This can leak internal details and is not localized. Consider logging the detailed exception but emitting a localized, user-friendly message (optionally mapping known error types to specific copy).

Suggested change
? 'Failed to refresh QR code: $error'
: 'Failed to request auth: $error',
? 'Failed to refresh QR code. Please try again.'
: 'Failed to request authentication. Please try again.',

Copilot uses AI. Check for mistakes.
if (_pollingFailureCount >= pollingFailureLimit) {
_cancelPeriodicSubscription();
w('landing qr polling failed, entering retry state');
emit(state.needReload(_expiredMessageBuilder()));
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

When provisioning polling fails repeatedly, the cubit emits _expiredMessageBuilder() which defaults to Localization.current.qrCodeExpiredDesc. That message is misleading for network/provisioning failures. Consider using a dedicated (localized) message for polling failures, or passing an error-specific builder separate from the QR-expired copy.

Suggested change
emit(state.needReload(_expiredMessageBuilder()));
emit(
state.needReload(
'Unable to refresh the QR code due to network or server issues. Please try again.',
),
);

Copilot uses AI. Check for mistakes.
Comment on lines 213 to 216
final (acount, privateKey) = await _verify(secret, keyPair);
if (requestVersion != _requestVersion) return;
multiAuthChangeNotifier.signIn(
AuthState(account: acount, privateKey: privateKey),
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

Typo in destructuring assignment: acount should be account to avoid confusion and keep naming consistent with AuthState(account: ...) and the Account type.

Suggested change
final (acount, privateKey) = await _verify(secret, keyPair);
if (requestVersion != _requestVersion) return;
multiAuthChangeNotifier.signIn(
AuthState(account: acount, privateKey: privateKey),
final (account, privateKey) = await _verify(secret, keyPair);
if (requestVersion != _requestVersion) return;
multiAuthChangeNotifier.signIn(
AuthState(account: account, privateKey: privateKey),

Copilot uses AI. Check for mistakes.
Comment on lines 206 to 210
if (secret.isEmpty) return;

_cancelPeriodicSubscription();
if (requestVersion != _requestVersion) return;
emit(state.copyWith(status: LandingStatus.provisioning));
Copy link

Copilot AI Mar 31, 2026

Choose a reason for hiding this comment

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

Potential stale-request side effect: _cancelPeriodicSubscription() is called before the requestVersion != _requestVersion guard. If an older in-flight _checkLanding completes after a newer requestAuthUrl() has started, it can cancel the newer polling subscription before returning. Add a version/subscription guard immediately after the await (and before canceling/resetting state) so stale _checkLanding invocations become no-ops.

Copilot uses AI. Check for mistakes.
@crossle
Copy link
Copy Markdown
Member

crossle commented Mar 31, 2026

@claude[agent] revew the change

Copilot stopped work on behalf of crossle due to an error March 31, 2026 07:38
@Claude Claude AI requested a review from crossle March 31, 2026 07:38
@crossle crossle merged commit 34fe924 into main Mar 31, 2026
7 of 8 checks passed
@crossle crossle deleted the fix/landing-qrcode-refresh branch March 31, 2026 07:42
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.

3 participants