Skip to content

Conversation

@josefinalliende
Copy link
Contributor

@josefinalliende josefinalliende commented Sep 10, 2025

Description

This PR simplifies a bit the general settings screen account loading and account switching logic. By making this changes, I realized that there was a bug in the switcher for the logout case #623 , where account that is about to be logged out is still shown.

Just changing the active pubkey is enough now, there is no need to reload groups of follows manually from the settings screen cause those providers are listening to the active pubkey provider.

This PR:

  • Adds a tiny widget that listens to active account provider, that then will be used in the settings screen
  • Simplifies load accounts logic and switching in the settings screen. Uses the new little widget to show the active account by watching the active account provider. Fixes Logged out account still shown in account switcher #623

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

Checklist

  • Run just precommit to ensure that formatting and linting are correct
  • Run just check-flutter-coverage to ensure that flutter coverage rules are passing
  • Updated the CHANGELOG.md file with your changes (if they affect the user experience)

Summary by CodeRabbit

  • New Features

    • Active Account tile in Settings shows your current account with quick access to share your profile (QR icon).
  • Enhancements

    • Unified account loading for faster, consistent profile retrieval and simplified account switching experience.
    • Logout flow updated to prompt account selection when multiple accounts exist; otherwise returns home.
  • UX

    • Consistent loading/error states and a generic "Failed to load accounts" notification on load failures.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 10, 2025

Walkthrough

Consolidates account/profile loading into a unified fetch in GeneralSettingsScreen, replaces per-account provider caching with _loadAccountsProfileData, updates account-switch and logout flows to use profile lists, and adds ActiveAccountTile to render the active account; imports and legacy metadata providers removed.

Changes

Cohort / File(s) Summary
General settings screen overhaul
lib/ui/settings/general_settings_screen.dart
Replaces provider-based per-account caching with unified _loadAccountsProfileData; stores _accounts and _accountsProfileData; simplifies error handling and UI, updates _switchAccount, _showAccountSwitcher, and logout flow to use profile public keys; removes follows/groups/metadata loading and related imports.
Active account widget added
lib/ui/settings/widgets/active_account_tile.dart
Adds ActiveAccountTile (ConsumerWidget) that reads activeAccountProvider and renders a contact-style tile (with QR action) for the active account; handles loading, empty, and error states and navigates to share_profile on tap.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Screen as GeneralSettingsScreen
  participant Accounts as AccountsStore
  participant Profiles as ProfileDataLoader
  participant UI as ActiveAccountTile

  User->>Screen: Open settings
  Screen->>Accounts: getAccounts()
  Accounts-->>Screen: List<Account>
  Screen->>Profiles: loadProfileData concurrently for accounts
  Profiles-->>Screen: List<ContactModel> (_accountsProfileData)
  Screen-->>UI: provide active account context
  UI-->>User: render active account tile
Loading
sequenceDiagram
  autonumber
  actor User
  participant Screen as GeneralSettingsScreen
  participant Switcher as AccountSwitcherSheet
  participant Active as ActiveAccountProvider

  User->>Screen: Tap "Switch Account"
  Screen->>Switcher: _showAccountSwitcher(_accountsProfileData)
  Switcher-->>User: display profiles
  User->>Switcher: select profile
  Switcher-->>Screen: selectedProfile.publicKey
  Screen->>Active: _switchAccount(pubkey)
  Active-->>Screen: active pubkey set
Loading
sequenceDiagram
  autonumber
  actor User
  participant Screen as GeneralSettingsScreen
  participant Auth as AuthService
  participant Switcher as AccountSwitcherSheet

  User->>Screen: Sign out
  Screen->>Auth: signOut()
  alt multiple accounts remain
    Screen->>Switcher: _showAccountSwitcher()
    Switcher-->>Screen: optional selected pubkey
    Screen->>Screen: _loadAccountsProfileData()
  else single/no account
    Screen-->>User: navigate home
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • untreu2
  • erskingardner

Pre-merge checks (5 passed)

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix/account-switch-in-logout" directly references the PR’s primary purpose—fixing account-switch behavior during logout—and therefore is related to the changeset and linked issue. However, it is formatted like a branch name (contains slashes) and is not a concise, human-readable single-sentence title suitable for changelogs. Consider renaming to a clearer sentence before merging.
Linked Issues Check ✅ Passed The PR updates the logout flow to refresh the account list via _loadAccountsProfileData and to show the account switcher when multiple accounts remain, which addresses linked issue #623 that a logged-out account remained visible. The refactor relies on the active account provider to propagate dependent updates instead of manual reloads, which aligns with the stated objectives. Based on the provided summaries, the code changes satisfy the coding objective of removing the logged-out account from the account selector immediately after logout.
Out of Scope Changes Check ✅ Passed The modifications are focused on the settings screen account-loading/switch logic and the new ActiveAccountTile widget, matching the PR objectives and refactor scope; removed imports and simplified state handling are consistent with those changes. There are no indications in the summaries of unrelated feature work or public API/signature changes. Therefore I do not detect out-of-scope changes in the provided summaries.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I hop through settings, tidy and spry,
One fetch for faces—no crumbs to hide.
A shiny tile, a QR wink,
Tap to switch and off I blink.
Logout done—fresh paths to try. 🐇✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73b6401 and 46b26be.

📒 Files selected for processing (2)
  • lib/ui/settings/general_settings_screen.dart (7 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/settings/general_settings_screen.dart
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/settings-account-loading

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.

@josefinalliende josefinalliende force-pushed the refactor/settings-account-loading branch 5 times, most recently from 72a0b9e to 73b6401 Compare September 11, 2025 00:57
@josefinalliende josefinalliende marked this pull request as ready for review September 11, 2025 01:16
Copy link
Contributor

@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: 1

🧹 Nitpick comments (9)
lib/ui/settings/widgets/active_account_tile.dart (5)

25-25: Explicitly type local AsyncValue.

Declare the exact type to match our guidelines.

-    final activeAccountState = ref.watch(activeAccountProvider);
+    final AsyncValue<ActiveAccountState> activeAccountState = ref.watch(activeAccountProvider);

16-21: Avoid silent empty pubkey; assert non-null when used.

This helper is only called when state.account != null, so use a non-null assertion and drop the empty fallback.

-  ContactModel _activeAccountProfileData(ActiveAccountState state) {
-    return ContactModel.fromMetadata(
-      pubkey: state.account?.pubkey ?? '',
-      metadata: state.metadata,
-    );
-  }
+  ContactModel _activeAccountProfileData(ActiveAccountState state) {
+    assert(state.account != null, 'Active account is null when building profile data');
+    return ContactModel.fromMetadata(
+      pubkey: state.account!.pubkey,
+      metadata: state.metadata,
+    );
+  }

40-45: Localize user-facing strings and don’t surface raw errors.

Replace hardcoded text with AppLocalizations and show a friendly message on error.

+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
...
-          return const Center(child: Text('No accounts found'));
+          return Center(child: Text(AppLocalizations.of(context)!.settingsNoAccountsFound));
...
-      error: (error, stack) => Center(child: Text('Error: $error')),
+      error: (error, stack) =>
+          Center(child: Text(AppLocalizations.of(context)!.genericError)),

Note: adjust keys to your l10n ARB.


24-27: Remove blank line inside function.

Our Dart guidelines disallow blank lines within functions.

-    final AsyncValue<ActiveAccountState> activeAccountState = ref.watch(activeAccountProvider);
-
+    final AsyncValue<ActiveAccountState> activeAccountState = ref.watch(activeAccountProvider);

37-37: Prefer a dedicated route constant.

If available, use a named route (e.g., Routes.settingsShareProfile) instead of string concatenation.

lib/ui/settings/general_settings_screen.dart (4)

47-50: Reload only when the active pubkey actually changes.

The current listener reloads profiles on any AsyncData emission, which can be frequent (e.g., metadata changes). Guard by pubkey to avoid redundant work.

-        (previous, next) {
-          if (next is AsyncData) {
-            _loadAccountsProfileData();
-          }
-        },
+        (previous, next) {
+          if (next is AsyncData) {
+            final String? prevKey =
+                (previous is AsyncData) ? previous.value?.account?.pubkey : null;
+            final String? nextKey = next.value?.account?.pubkey;
+            if (prevKey != nextKey) {
+              _loadAccountsProfileData();
+            }
+          }
+        },

77-79: Localize toast message.

Use AppLocalizations instead of hardcoded strings.

-        ref.showErrorToast('Failed to load accounts');
+        ref.showErrorToast(AppLocalizations.of(context)!.settingsAccountsLoadFailed);

Note: import AppLocalizations and use your actual key.


108-127: Return the bottom-sheet Future so callers can truly await it.

_showAccountSwitcher is async but doesn’t await/return the sheet’s Future; await _showAccountSwitcher() will resolve immediately.

   Future<void> _showAccountSwitcher({
     bool isDismissible = true,
     bool showSuccessToast = false,
   }) async {
     if (_accounts.isEmpty) {
       await _loadAccountsProfileData();
     }
 
     if (!mounted) return;
 
-    SwitchProfileBottomSheet.show(
+    return SwitchProfileBottomSheet.show(
       context: context,
       profiles: _accountsProfileData,
       isDismissible: isDismissible,
       showSuccessToast: showSuccessToast,
       onProfileSelected: (selectedProfile) async {
         await _switchAccount(selectedProfile.publicKey);
       },
     );
   }

Also, remove blank lines within this function to match our style guide.


94-101: No-op switch when selecting the current account.

Avoid writing the same pubkey and showing a “switched” toast if the selected account is already active.

   Future<void> _switchAccount(String accountPubkey) async {
     try {
-      await ref.read(activePubkeyProvider.notifier).setActivePubkey(accountPubkey);
+      final String? current = ref.read(activePubkeyProvider);
+      if (current == accountPubkey) {
+        if (mounted) ref.showSuccessToast('This account is already active');
+        return;
+      }
+      await ref.read(activePubkeyProvider.notifier).setActivePubkey(accountPubkey);
 
       if (mounted) {
         ref.showSuccessToast('Account switched successfully');
       }

Note: adjust the read of activePubkeyProvider if its value type differs.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8c495b5 and 73b6401.

⛔ Files ignored due to path filters (1)
  • ios/Podfile.lock is excluded by !**/*.lock
📒 Files selected for processing (2)
  • lib/ui/settings/general_settings_screen.dart (7 hunks)
  • lib/ui/settings/widgets/active_account_tile.dart (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.dart

📄 CodeRabbit inference engine (.cursor/rules/flutter.mdc)

**/*.dart: Always declare the type of each variable and function (parameters and return value). Avoid using 'any'. Create necessary types.
Don't leave blank lines within a function.
One export per file.
Use PascalCase for classes.
Use camelCase for variables, functions, and methods.
Use underscores_case for file and directory names.
Use UPPERCASE for environment variables. Avoid magic numbers and define constants.
Start each function with a verb.
Use verbs for boolean variables. Example: isLoading, hasError, canDelete, etc.
Use complete words instead of abbreviations and correct spelling, except for standard and well-known abbreviations (API, URL, i, j, err, ctx, req, res, next).
Write short functions with a single purpose. Less than 20 instructions.
Name functions with a verb and something else. If it returns a boolean, use isX or hasX, canX, etc. If it doesn't return anything, use executeX or saveX, etc.
Avoid nesting blocks by early checks and returns, or extraction to utility functions.
Use higher-order functions (map, filter, reduce, etc.) to avoid function nesting. Use arrow functions for simple functions (less than 3 instructions). Use named functions for non-simple functions.
Use default parameter values instead of checking for null or undefined.
Reduce function parameters using RO-RO: use an object to pass multiple parameters and to return results. Declare necessary types for input arguments and output.
Use a single level of abstraction in functions.
Don't abuse primitive types and encapsulate data in composite types.
Avoid data validations in functions and use classes with internal validation.
Prefer immutability for data. Use readonly for data that doesn't change. Use 'as const' for literals that don't change.
Declare interfaces to define contracts.
Write small classes with a single purpose. Less than 200 instructions, less than 10 public methods, less than 10 properties.
Use exceptions to handle errors you don't expect. If you catch an exception, it sh...

Files:

  • lib/ui/settings/widgets/active_account_tile.dart
  • lib/ui/settings/general_settings_screen.dart
🧠 Learnings (4)
📚 Learning: 2025-09-07T02:15:31.931Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#594
File: lib/src/rust/api/utils.dart:12-16
Timestamp: 2025-09-07T02:15:31.931Z
Learning: The lingering PublicKey references in lib/config/providers/auth_provider.dart, lib/config/providers/group_provider.dart, and rust_builder/cargokit/build_tool/lib/src/options.dart identified during the utils.dart API cleanup were fixed in PR #597 in the whitenoise_flutter codebase.

Applied to files:

  • lib/ui/settings/general_settings_screen.dart
📚 Learning: 2025-09-07T13:10:16.542Z
Learnt from: josefinalliende
PR: parres-hq/whitenoise_flutter#597
File: lib/config/providers/group_provider.dart:311-314
Timestamp: 2025-09-07T13:10:16.542Z
Learning: In the whitenoise_flutter codebase, the User class used in group_provider.dart (and similar contexts) is presentational only, not the actual user class from the Rust API. There are plans to remove this User class and replace it with UserProfileData, similar to the planned consolidation with ContactModel.

Applied to files:

  • lib/ui/settings/general_settings_screen.dart
📚 Learning: 2025-08-08T13:39:00.500Z
Learnt from: CR
PR: parres-hq/whitenoise_flutter#0
File: .cursor/rules/flutter.mdc:0-0
Timestamp: 2025-08-08T13:39:00.500Z
Learning: Applies to **/*.dart : Use the whitenoise rust crate (via flutter_rust_bridge) as the source of all data and only way to trigger changes in our data model.

Applied to files:

  • lib/ui/settings/general_settings_screen.dart
📚 Learning: 2025-08-23T11:02:28.308Z
Learnt from: Quwaysim
PR: parres-hq/whitenoise_flutter#527
File: lib/ui/core/ui/wn_avatar.dart:1-6
Timestamp: 2025-08-23T11:02:28.308Z
Learning: In the whitenoise_flutter codebase, flutter_screenutil is re-exported through lib/ui/core/themes/src/app_theme.dart, so files that import app_theme.dart do not need to directly import flutter_screenutil to use .w, .h, .sp extensions.

Applied to files:

  • lib/ui/settings/general_settings_screen.dart
🔇 Additional comments (1)
lib/ui/settings/general_settings_screen.dart (1)

195-202: Flow after logout looks good.

Reloading accounts and showing the switcher when more than one remain is consistent with the PR’s intent.

@josefinalliende josefinalliende marked this pull request as draft September 11, 2025 03:51
@josefinalliende josefinalliende force-pushed the refactor/settings-account-loading branch from 4509d49 to f1f17f7 Compare September 11, 2025 14:28
@josefinalliende josefinalliende changed the title Refactor/settings account loading fix/account-switch-in-logout Sep 11, 2025
@josefinalliende josefinalliende force-pushed the refactor/settings-account-loading branch from 612e987 to 46b26be Compare September 12, 2025 05:23
@josefinalliende josefinalliende marked this pull request as ready for review September 12, 2025 05:26
Copy link
Contributor

@Quwaysim Quwaysim left a comment

Choose a reason for hiding this comment

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

LGTM

@Quwaysim Quwaysim merged commit 9e565e4 into master Sep 12, 2025
2 checks passed
@josefinalliende josefinalliende deleted the refactor/settings-account-loading branch September 12, 2025 13:11
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.

Logged out account still shown in account switcher

4 participants