Skip to content

Fix login error message for incorrect credentials#507

Open
hiraljj05 wants to merge 7 commits intoCircuitVerse:masterfrom
hiraljj05:fix/login-error-message
Open

Fix login error message for incorrect credentials#507
hiraljj05 wants to merge 7 commits intoCircuitVerse:masterfrom
hiraljj05:fix/login-error-message

Conversation

@hiraljj05
Copy link
Copy Markdown

@hiraljj05 hiraljj05 commented Feb 25, 2026

Fixes #502

Describe the changes you have made in this PR -

Added proper error handling for login with incorrect credentials.
Implemented a ScaffoldMessenger SnackBar to show a clear message like "Incorrect email or password." when login fails.
Ensured that valid logins continue to navigate to the landing page without any issues.
No other code logic or functionality has been affected; only the login feedback mechanism has been enhanced.
Form resets automatically when incorrect credentials are entered to allow the user to retry.

1.mp4

Screenshots of the changes (If any) -

Note: Please check Allow edits from maintainers. if you would like us to assist in the PR.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Google account sign-in option for authentication
    • Email verification now required before login access
    • Improved authentication error messaging and user feedback with modal dialogs
  • Chores

    • Updated Android SDK versions and Kotlin plugin for enhanced device compatibility
    • Added new platform support

@netlify
Copy link
Copy Markdown

netlify Bot commented Feb 25, 2026

Deploy Preview for cv-mobile-app-web ready!

Name Link
🔨 Latest commit 64dd75c
🔍 Latest deploy log https://app.netlify.com/projects/cv-mobile-app-web/deploys/699ee7a87dcdf800081f23ac
😎 Deploy Preview https://deploy-preview-507--cv-mobile-app-web.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 25, 2026

Walkthrough

This pull request updates the authentication system with OAuth improvements, email verification enforcement, and API contract refinements. It modifies login and signup flows to return non-nullable Future<String> and Future<void> respectively, implements Google OAuth integration with explicit token exchange, and enforces email verification checks. The UI is updated with ScaffoldMessenger-based snackbars and verification dialogs. Android build configurations are updated with SDK versions and Gradle plugin versions. Environment config is adjusted for OAuth constants, and Windows plugin registration is added for quill_native_bridge_windows.

Possibly related PRs

Suggested labels

released

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning Significant out-of-scope changes detected: Android SDK upgrades, Gradle plugin updates, Google OAuth implementation, signup flow modifications, and unrelated build configuration changes. Scope this PR to focus only on login error message display. Move Android/Gradle updates, Google OAuth refactoring, signup flow changes, and build config updates to separate PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'Fix login error message for incorrect credentials' clearly and specifically describes the main change—displaying an error message when login credentials are incorrect.
Linked Issues check ✅ Passed The PR addresses all coding requirements from issue #502: displays 'Incorrect email or password' message via ScaffoldMessenger, prevents login with invalid credentials, avoids sensitive exposure, and improves error feedback.

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

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 14

🧹 Nitpick comments (6)
lib/viewmodels/authentication/auth_options_viewmodel.dart (1)

22-61: Remove the 40-line commented-out block.

This dead code adds noise. The new implementation below is the active path — the old one should be deleted.

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

In `@lib/viewmodels/authentication/auth_options_viewmodel.dart` around lines 22 -
61, Remove the large commented-out legacy googleAuth implementation: delete the
entire commented block that defines the old Future googleAuth(...)
implementation (the lines referencing GoogleSignIn, GOOGLE_OAUTH, ViewState,
_userApi, _storage, AuthType) so only the new active authentication
implementation remains; ensure there are no leftover commented references to
GOOGLE_OAUTH or ViewState related to that old flow.
lib/utils/api_utils.dart (1)

48-49: Remove commented-out debug prints.

These commented-out statements would log statusCode and response.body (which may contain auth tokens or PII) if ever uncommented. They shouldn't be committed — use a proper logging framework with configurable levels instead of leaving commented-out print calls in production code.

Proposed fix
-    //   print("STATUS CODE: ${response.statusCode}");
-    // print("RAW BODY: ${response.body}");
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/utils/api_utils.dart` around lines 48 - 49, Remove the commented-out
debug prints that reference response.statusCode and response.body in
lib/utils/api_utils.dart; delete the lines "//   print("STATUS CODE:
${response.statusCode}");" and "// print("RAW BODY: ${response.body}");" and if
you need runtime diagnostics replace them with calls to the project's logging
utility at an appropriate log level (never log response.body or sensitive
tokens) — locate the call site where the local variable response is used and
swap in logger.debug/info with sanitized output instead of leaving commented
print statements.
lib/config/environment_config.dart (1)

17-34: Remove commented-out code; consider using String.fromEnvironment for the Google client ID for consistency.

Lines 25–31 are dead commented-out code and should be removed.

The GOOGLE_OAUTH_CLIENT_ID is hardcoded while GITHUB_OAUTH_CLIENT_ID uses String.fromEnvironment. For consistency and flexibility (e.g., different client IDs per environment/flavor), consider the same pattern:

Proposed change
-  // Google OAUTH ENV VARIABLES
-  static const String GOOGLE_OAUTH_CLIENT_ID =
-      "30473033321-4v4ap4b3r16e8vq9c100d8bi0edbnbbs.apps.googleusercontent.com";
+  // Google OAuth
+  static const String GOOGLE_OAUTH_CLIENT_ID = String.fromEnvironment(
+    'GOOGLE_OAUTH_CLIENT_ID',
+    defaultValue: '30473033321-4v4ap4b3r16e8vq9c100d8bi0edbnbbs.apps.googleusercontent.com',
+  );

   // GITHUB OAUTH ENV VARIABLES
   static const String GITHUB_OAUTH_CLIENT_ID = String.fromEnvironment(
     'GITHUB_OAUTH_CLIENT_ID',
   );
-  // static const String GITHUB_OAUTH_CLIENT_SECRET = String.fromEnvironment(
-  //   'GITHUB_OAUTH_CLIENT_SECRET',
-  // );
-  // static const String GITHUB_OAUTH_REDIRECT_URI = String.fromEnvironment(
-  //   'GITHUB_OAUTH_REDIRECT_URI',
-  //   defaultValue: 'circuitverse://auth/callback/github',
-  // );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/config/environment_config.dart` around lines 17 - 34, Remove the dead
commented-out block that references GITHUB_OAUTH_CLIENT_SECRET and the commented
GITHUB_OAUTH_REDIRECT_URI, and make the Google client ID follow the same pattern
as GitHub by replacing the hardcoded GOOGLE_OAUTH_CLIENT_ID with a
String.fromEnvironment lookup (e.g., use
String.fromEnvironment('GOOGLE_OAUTH_CLIENT_ID', defaultValue:
'<current-id-or-empty>')) while leaving GITHUB_OAUTH_CLIENT_ID and the active
GITHUB_OAUTH_REDIRECT_URI symbol unchanged.
lib/ui/views/authentication/login_view.dart (1)

133-135: Please remove stale commented-out code blocks.

The old focus/snackbar snippets (Line 133, Line 143, Line 155) add noise and make this flow harder to scan.

Also applies to: 143-145, 155-161

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

In `@lib/ui/views/authentication/login_view.dart` around lines 133 - 135, Remove
the stale commented-out focus/snackbar snippets inside the login view widget
(e.g., the commented FocusScope.of(context).requestFocus(FocusNode()) and the
old snackbar/focus blocks found near the login form in LoginView/_LoginViewState
build/submit handlers); simply delete those commented lines (the blocks around
the FocusScope and old SnackBar code) so the code is cleaner and easier to scan,
leaving any active keyboard dismissals or snackbar logic intact if already
implemented elsewhere.
android/app/build.gradle (2)

136-136: Use the plugins {} block instead of the legacy apply plugin syntax.

apply plugin: 'com.google.gms.google-services' is the legacy Groovy syntax. Since com.google.gms.google-services is already declared in android/settings.gradle with apply false, the idiomatic approach is to add it to the existing plugins {} block at the top of this file.

♻️ Proposed refactor
 plugins {
     id "com.android.application"
     id "kotlin-android"
     id "dev.flutter.flutter-gradle-plugin"
+    id "com.google.gms.google-services"
 }

Then remove:

-apply plugin: 'com.google.gms.google-services'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/app/build.gradle` at line 136, Replace the legacy Groovy "apply
plugin: 'com.google.gms.google-services'" line by adding the plugin id into the
existing plugins { } block at the top of the Gradle file (use id
"com.google.gms.google-services") since it is declared apply false in
settings.gradle, then remove the old apply plugin line; ensure the plugins block
is used consistently for other plugins in the file.

129-133: The forced androidx.browser:browser:1.8.0 is a maintenance liability.

Pinning a transitive dependency to an exact version via resolutionStrategy.force will block all future upgrades to that library until manually updated. If the version that brings the dependency naturally evolves, this pin will silently override it. Prefer constraining only the minimum version (prefer/strictly with a lower bound) if the goal is to resolve a version conflict, and include a comment explaining the root cause.

♻️ Suggested alternative
 configurations.all {
     resolutionStrategy {
-        force "androidx.browser:browser:1.8.0"
+        // TODO: Remove once <dependency X> updates its own browser dependency.
+        // Force minimum 1.8.0 to resolve conflict with <library>.
+        force "androidx.browser:browser:1.8.0"
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@android/app/build.gradle` around lines 129 - 133, Replace the hard force of
"androidx.browser:browser:1.8.0" in the configurations.all resolutionStrategy
(the resolutionStrategy.force call) with a version constraint that only sets a
minimum/preferred version (e.g., use prefer/strictly with a lower bound or an
eachDependency rule that sets version if missing) so transitive upgrades are not
blocked; update the resolutionStrategy usage (targeting the same dependency
group:artifact "androidx.browser:browser") and add a short comment explaining
the root cause of the original conflict and why the minimum version is required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@android/app/build.gradle`:
- Line 54: The PR bumps compileSdk to 36 which together with a simultaneous bump
of targetSdkVersion to 36 enforces Android edge-to-edge behavior; confirm
window-insets-safe handling across your UI or avoid the behavior change by
keeping targetSdkVersion at 35 for now. Inspect the Android manifest and UI code
paths that handle system bars (window insets handling,
CoordinatorLayout/AppCompat themes, insets listeners) and ensure components
correctly consume/apply Insets before setting targetSdkVersion to 36, or change
only compileSdk to 36 while leaving targetSdkVersion at 35 until you audit and
adapt all screens.
- Line 76: The change replaced the hardcoded minSdkVersion 23 with
flutter.minSdkVersion which can resolve to API 16–19 depending on Flutter
version; to prevent lowering device support, restore a safe minimum by setting
minSdkVersion back to 23 (replace flutter.minSdkVersion with 23 in the
minSdkVersion declaration) or explicitly enforce a project-wide minSdk (e.g., in
gradle.properties or the android block) so that the Gradle symbol minSdkVersion
uses API 23 at build time.

In `@android/settings.gradle`:
- Line 23: Update the Gradle plugin declaration for the Google Services plugin
by changing the version string for id "com.google.gms.google-services" from
"4.4.0" to "4.4.4" so the project uses the latest stable release; locate the
line containing id "com.google.gms.google-services" in android/settings.gradle
and replace the version token accordingly, then re-sync/refresh Gradle to verify
no compatibility issues.

In `@l10n.yaml`:
- Line 5: Restore the explicit synthetic-package setting in l10n.yaml by
re-adding the "synthetic-package: false" entry so the generator respects the
configured output-dir (lib/gen_l10n/) and avoids writing to
.dart_tool/flutter_gen/, preventing stale/missing imports like
package:mobile_app/gen_l10n/app_localizations.dart and future incompatibility
with package:flutter_gen removal.

In `@lib/services/API/users_api.dart`:
- Around line 96-112: The signup method body (function signup) is mis-indented
and appears as a top-level function; re-indent the entire method block so its
signature and body align with other class members (match the class indentation
level used by other methods in the same file), ensuring the opening and closing
braces are inside the class scope and the try/catch and internal statements are
consistently indented; verify no stray top-level whitespace remains so signup is
clearly a class method.
- Line 104: Remove the debug print that leaks API response data by deleting the
print(response) call in users_api.dart; if you need to retain observability,
replace it with a proper logging call (e.g., use the existing app logger) and
guard it behind a debug flag or environment check so sensitive response bodies
or tokens are never printed in production — locate the print(response)
invocation in the signup/response-handling function and either remove it or swap
it for a debug-only logger call.
- Around line 233-282: Remove the stray duplicate `@override` and the leftover
commented-out blocks around the sendResetPasswordInstructions method: keep the
valid Future<bool> sendResetPasswordInstructions(String email) implementation
(with its single `@override`) and delete the earlier dangling `@override` and both
commented-out code regions above and below the method so there is no
dead/commented duplicate code or duplicate annotations.
- Around line 56-59: The user-verification check in users_api.dart is
misindented and currently throws a Failure with a human-readable string which
LoginViewModel then pattern-matches on; fix by aligning the if block with the
surrounding try/catch and replace the string-based Failure with a structured
error (either throw a dedicated EmailNotVerifiedException or throw Failure with
a stable errorCode like 'EMAIL_NOT_VERIFIED' on the
jsonResponse['user']['is_verified'] == false branch); update the throw in the
users API (search for the if block around jsonResponse['user']['is_verified']
and the Failure construction) so LoginViewModel can check f.errorCode ==
'EMAIL_NOT_VERIFIED' or catch EmailNotVerifiedException instead.
- Around line 69-76: The current catch chain in the login/auth method swallows a
previously-thrown Failure (e.g., "Please verify your email before logging in.")
because the broad `on Exception` handler catches all Exceptions; update the
catch clauses in the function that contains the
UnauthorizedException/NotFoundException handlers (the login method in
users_api.dart) by inserting an `on Failure { rethrow; }` clause before the
general `on Exception` handler so user-generated Failure instances propagate
unchanged, and add a separate `on FormatException { throw Failure("Response
format error"); }` (or other suitable message) to handle malformed JSON
explicitly instead of mapping it to "Incorrect email or password".

In `@lib/ui/views/authentication/login_view.dart`:
- Around line 163-176: Don't compare against the localized message string;
instead use a stable error code/type exposed by the model (e.g., add or use an
enum or constant like LoginError.invalidCredentials or a method like
_model.errorCodeFor(_model.LOGIN)) and check that value before calling
_formKey.currentState?.reset(); update the view to call the stable accessor
(replace the raw string equality check) and, if needed, modify the model to
return an error code or property representing the "incorrect credentials" case
so the UI resets only when that error code is present.

In `@lib/ui/views/authentication/signup_view.dart`:
- Around line 145-164: Replace the hardcoded dialog strings in the
Get.defaultDialog call with localized strings from AppLocalizations (e.g.
AppLocalizations.of(context)!.verify_email_title, verify_email_message, ok) and
remove the dead commented SnackBarUtils/Future/Get.offAllNamed block; keep the
dialog behavior intact (Get.back(), Get.offAllNamed(LoginView.id)). Add the
corresponding keys (verify_email_title, verify_email_message, ok) to the .arb
localization files and ensure any new keys are referenced via
AppLocalizations.of(context)! in signup_view.dart rather than literal strings.

In `@lib/viewmodels/authentication/auth_options_viewmodel.dart`:
- Around line 63-121: The googleAuth method body is indented at top-level,
making it appear outside the class; re-indent the entire googleAuth method so
its opening/closing braces and body are aligned with the other instance methods
(e.g., githubAuth) inside the same class in auth_options_viewmodel.dart, ensure
the method is nested within the class declaration (adjust surrounding braces if
necessary) and match the same indentation style used by githubAuth to keep the
class structure and readability consistent.

In `@lib/viewmodels/authentication/login_viewmodel.dart`:
- Around line 30-42: Remove the dead commented-out catch block, re-indent the
existing catch body so it aligns with the surrounding try block, and replace the
two hardcoded strings passed to setErrorMessageFor(LOGIN, ...) with localization
lookups (e.g. AppLocalizations.of(context).emailNotVerified and
AppLocalizations.of(context).incorrectEmailOrPassword) instead of raw literals;
also stop coupling on f.message text — check a structured property on Failure
such as f.code == 'not_verified' or a FailureType (update users_api.dart to
populate that code) and use that to decide which localized message to set.

In `@lib/viewmodels/authentication/signup_viewmodel.dart`:
- Around line 15-49: Delete the large commented-out signup block and re-indent
the remaining Future<void> signup(String name, String email, String password)
async { ... } so it is defined as a method inside the SignupViewModel class (not
a top-level function); ensure the closing braces of SignupViewModel align
correctly and remove any stray extra brace so SignupViewModel contains the
signup method and there is no dead commented code.

---

Nitpick comments:
In `@android/app/build.gradle`:
- Line 136: Replace the legacy Groovy "apply plugin:
'com.google.gms.google-services'" line by adding the plugin id into the existing
plugins { } block at the top of the Gradle file (use id
"com.google.gms.google-services") since it is declared apply false in
settings.gradle, then remove the old apply plugin line; ensure the plugins block
is used consistently for other plugins in the file.
- Around line 129-133: Replace the hard force of
"androidx.browser:browser:1.8.0" in the configurations.all resolutionStrategy
(the resolutionStrategy.force call) with a version constraint that only sets a
minimum/preferred version (e.g., use prefer/strictly with a lower bound or an
eachDependency rule that sets version if missing) so transitive upgrades are not
blocked; update the resolutionStrategy usage (targeting the same dependency
group:artifact "androidx.browser:browser") and add a short comment explaining
the root cause of the original conflict and why the minimum version is required.

In `@lib/config/environment_config.dart`:
- Around line 17-34: Remove the dead commented-out block that references
GITHUB_OAUTH_CLIENT_SECRET and the commented GITHUB_OAUTH_REDIRECT_URI, and make
the Google client ID follow the same pattern as GitHub by replacing the
hardcoded GOOGLE_OAUTH_CLIENT_ID with a String.fromEnvironment lookup (e.g., use
String.fromEnvironment('GOOGLE_OAUTH_CLIENT_ID', defaultValue:
'<current-id-or-empty>')) while leaving GITHUB_OAUTH_CLIENT_ID and the active
GITHUB_OAUTH_REDIRECT_URI symbol unchanged.

In `@lib/ui/views/authentication/login_view.dart`:
- Around line 133-135: Remove the stale commented-out focus/snackbar snippets
inside the login view widget (e.g., the commented
FocusScope.of(context).requestFocus(FocusNode()) and the old snackbar/focus
blocks found near the login form in LoginView/_LoginViewState build/submit
handlers); simply delete those commented lines (the blocks around the FocusScope
and old SnackBar code) so the code is cleaner and easier to scan, leaving any
active keyboard dismissals or snackbar logic intact if already implemented
elsewhere.

In `@lib/utils/api_utils.dart`:
- Around line 48-49: Remove the commented-out debug prints that reference
response.statusCode and response.body in lib/utils/api_utils.dart; delete the
lines "//   print("STATUS CODE: ${response.statusCode}");" and "// print("RAW
BODY: ${response.body}");" and if you need runtime diagnostics replace them with
calls to the project's logging utility at an appropriate log level (never log
response.body or sensitive tokens) — locate the call site where the local
variable response is used and swap in logger.debug/info with sanitized output
instead of leaving commented print statements.

In `@lib/viewmodels/authentication/auth_options_viewmodel.dart`:
- Around line 22-61: Remove the large commented-out legacy googleAuth
implementation: delete the entire commented block that defines the old Future
googleAuth(...) implementation (the lines referencing GoogleSignIn,
GOOGLE_OAUTH, ViewState, _userApi, _storage, AuthType) so only the new active
authentication implementation remains; ensure there are no leftover commented
references to GOOGLE_OAUTH or ViewState related to that old flow.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f621531 and 64dd75c.

⛔ Files ignored due to path filters (1)
  • pubspec.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .gitignore
  • android/app/build.gradle
  • android/settings.gradle
  • l10n.yaml
  • lib/config/environment_config.dart
  • lib/services/API/users_api.dart
  • lib/ui/views/authentication/forgot_password_view.dart
  • lib/ui/views/authentication/login_view.dart
  • lib/ui/views/authentication/signup_view.dart
  • lib/utils/api_utils.dart
  • lib/viewmodels/authentication/auth_options_viewmodel.dart
  • lib/viewmodels/authentication/login_viewmodel.dart
  • lib/viewmodels/authentication/signup_viewmodel.dart
  • windows/flutter/generated_plugin_registrant.cc
  • windows/flutter/generated_plugins.cmake

Comment thread android/app/build.gradle
Comment thread android/app/build.gradle
Comment thread android/settings.gradle
Comment thread l10n.yaml
Comment thread lib/services/API/users_api.dart
Comment thread lib/ui/views/authentication/login_view.dart
Comment thread lib/ui/views/authentication/signup_view.dart
Comment thread lib/viewmodels/authentication/auth_options_viewmodel.dart
Comment thread lib/viewmodels/authentication/login_viewmodel.dart
Comment thread lib/viewmodels/authentication/signup_viewmodel.dart
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.

No Error Message Displayed for Incorrect Email or Password

1 participant