Skip to content

chore(flutter): modernize deprecations, async guards, and list assertions - #8984

Open
YadneshTeli wants to merge 4 commits into
AppFlowy-IO:mainfrom
YadneshTeli:chore/flutter-deprecations-and-safety
Open

YadneshTeli wants to merge 4 commits into
AppFlowy-IO:mainfrom
YadneshTeli:chore/flutter-deprecations-and-safety

Conversation

@YadneshTeli

@YadneshTeli YadneshTeli commented Aug 31, 2026

Copy link
Copy Markdown

Description

This PR addresses several high-value TODOs, modernizes deprecated Flutter APIs to current stable patterns, and adds async context safety guards across the workspace:

  1. Flutter Modernization (onReorder -> onReorderItem):

    • Replaced deprecated ReorderableListView.onReorder callbacks with modern onReorderItem across 12 UI files (grid_page.dart, mobile_grid_page.dart, checklist_cell_editor.dart, mobile_checklist_cell_editor.dart, desktop_row_detail_checklist_cell.dart, media_cell_editor.dart, select_option_cell_editor.dart, select_option.dart, row_property.dart, setting_property_list.dart, database_field_list.dart, database_sort_bottom_sheet.dart, favorite_folder.dart, mobile_hidden_groups_column.dart, board_hidden_groups.dart, mobile_grid_header.dart, sort_editor.dart).
    • Removed manual offset adjustments (if (fromIndex < toIndex) toIndex--;) in corresponding BLoCs (SortEditorBloc, ChecklistCellBloc, PropertyBloc, RowDetailBloc, FavoriteBloc), eliminating indexing bugs when moving items downwards.
  2. Modernized Theme & Widget Deprecations:

    • desktop_appearance.dart & mobile_appearance.dart: Replaced deprecated dialogBackgroundColor and indicatorColor with dialogTheme: DialogThemeData(...) and tabBarTheme: TabBarThemeData(...).
    • notifications_setting_group.dart: Replaced deprecated activeColor with activeTrackColor: theme.colorScheme.primary.
    • interactive_image_viewer.dart: Migrated deprecated Matrix4.translate / Matrix4.scale to translateByDouble / scaleByDouble.
  3. Async Context Guards & Invariant Assertions:

    • file_util.dart: Added if (!context.mounted) return; and if (context.mounted) safety guards before asynchronous showSnackBarMessage calls after file uploads.
    • animated_chat_list.dart & animated_chat_list_reversed.dart: Added runtime assertions in initState ensuring message IDs are unique, preventing AnimatedList key collision errors.

Type of Change

  • Refactoring / Code Quality (chore)
  • Bug fix (non-breaking change which fixes indexing and async context race conditions)

Verification

  • Ran flutter analyze ensuring 0 compilation errors.
  • Verified BLoC and widget reordering behaviors across grid, board, checklist, media, and favorites.

Summary by Sourcery

Modernize deprecated Flutter APIs and strengthen list reordering, asynchronous context safety, and chat-list invariants across the workspace.

Bug Fixes:

  • Correct item movement behavior across database, checklist, favorites, and other reorderable lists by adopting the current reorder callback semantics.
  • Prevent async file-upload error notifications from using an unmounted widget context.
  • Detect duplicate chat message IDs to avoid animated-list key collisions.

Enhancements:

  • Modernize Flutter widget, theme, matrix transformation, and dropdown APIs for current stable versions.
  • Add message-list identity validation and stable keys for animated chat lists.

Build:

  • Broaden analyzer, intl, and leak_tracker dependency compatibility and update related dependency overrides.

Chores:

  • Update the Flutter workspace and UI examples to use current package APIs and imports.

@sourcery-ai

sourcery-ai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Modernizes deprecated Flutter APIs across the workspace, updates reorder callbacks and destination-index handling, adds mounted and unique-ID safety checks, and broadens dependency constraints with coordinated overrides.

Sequence diagram for safe asynchronous file upload feedback

sequenceDiagram
    participant Caller
    participant insertLocalFile
    participant BuildContext
    participant showSnackBarMessage

    Caller->>insertLocalFile: insertLocalFile(...)
    insertLocalFile->>BuildContext: mounted
    alt context is unmounted
        insertLocalFile-->>Caller: return
    else context is mounted
        insertLocalFile->>showSnackBarMessage: showSnackBarMessage(context, errorMsg)
        showSnackBarMessage-->>Caller: display upload error
    end
Loading

Flow diagram for reorder destination handling

flowchart LR
    UI[ReorderableListView.onReorderItem] -->|fromIndex, toIndex| Bloc[Reorder BLoC]
    Bloc --> IDs[Resolve source and destination IDs]
    IDs --> Move[Apply reorder without manual downward offset]
    Move --> State[Update reordered state]
Loading

File-Level Changes

Change Details Files
Migrated reorderable lists to Flutter’s item-based callback API and aligned handlers and BLoCs with its destination-index semantics.
  • Replaced deprecated onReorder callbacks throughout grid, board, checklist, media, select-option, settings, and favorites UI.
  • Removed manual downward-move index decrements from reorder handlers and related BLoCs.
  • Preserved necessary index translations for lists with non-data header offsets.
frontend/appflowy_flutter/lib/mobile/presentation/database/board/widgets/mobile_hidden_groups_column.dart
frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_field_list.dart
frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_sort_bottom_sheet.dart
frontend/appflowy_flutter/lib/plugins/database/application/cell/bloc/checklist_cell_bloc.dart
frontend/appflowy_flutter/lib/plugins/database/application/setting/property_bloc.dart
frontend/appflowy_flutter/lib/plugins/database/board/presentation/widgets/board_hidden_groups.dart
frontend/appflowy_flutter/lib/plugins/database/grid/application/row/row_detail_bloc.dart
frontend/appflowy_flutter/lib/plugins/database/grid/application/sort/sort_editor_bloc.dart
frontend/appflowy_flutter/lib/plugins/database/grid/presentation/grid_page.dart
frontend/appflowy_flutter/lib/plugins/database/grid/presentation/mobile_grid_page.dart
frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/header/mobile_grid_header.dart
frontend/appflowy_flutter/lib/plugins/database/grid/presentation/widgets/sort/sort_editor.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/cell/desktop_row_detail/desktop_row_detail_checklist_cell.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/checklist_cell_editor.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/media_cell_editor.dart
frontend/appflowy_flutter/lib/mobile/presentation/database/widgets/mobile_hidden_groups_column.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/mobile_checklist_cell_editor.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/cell_editor/select_option_cell_editor.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/field/type_option_editor/select/select_option.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/row/row_property.dart
frontend/appflowy_flutter/lib/plugins/database/widgets/setting/setting_property_list.dart
frontend/appflowy_flutter/lib/workspace/application/favorite/favorite_bloc.dart
frontend/appflowy_flutter/lib/workspace/presentation/home/menu/sidebar/favorites/favorite_folder.dart
Updated Flutter APIs and theme configuration to current stable type and property names.
  • Changed dropdown theme types to InputDecorationThemeData.
  • Moved dialog and tab indicator colors into DialogThemeData and TabBarThemeData.
  • Replaced Switch activeColor with activeTrackColor.
  • Migrated Matrix4 transformations to translateByDouble and scaleByDouble.
  • Corrected the flutter_svg import in the UI example.
frontend/appflowy_flutter/lib/flutter/af_dropdown_menu.dart
frontend/appflowy_flutter/lib/workspace/presentation/settings/shared/settings_dropdown.dart
frontend/appflowy_flutter/lib/workspace/application/settings/appearance/desktop_appearance.dart
frontend/appflowy_flutter/lib/workspace/application/settings/appearance/mobile_appearance.dart
frontend/appflowy_flutter/lib/mobile/presentation/setting/notifications_setting_group.dart
frontend/appflowy_flutter/lib/workspace/presentation/widgets/image_viewer/interactive_image_viewer.dart
frontend/appflowy_flutter/packages/appflowy_ui/example/lib/src/menu/menu_page.dart
Added runtime safety checks for asynchronous UI updates and animated-list data invariants.
  • Guarded post-upload snackbar calls with BuildContext.mounted.
  • Asserted unique chat message IDs during animated-list initialization to prevent key collisions.
frontend/appflowy_flutter/lib/plugins/document/presentation/editor_plugins/file/file_util.dart
frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/animated_chat_list.dart
frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/animated_chat_list_reversed.dart
Relaxed and coordinated package version constraints to support the updated Dart/Flutter dependency set.
  • Broadened analyzer, intl, and leak_tracker constraints.
  • Added dependency overrides for analyzer, code-generation packages, and related tooling.
  • Regenerated the application lockfile.
frontend/appflowy_flutter/packages/flowy_infra/pubspec.yaml
frontend/appflowy_flutter/packages/flowy_infra_ui/pubspec.yaml
frontend/appflowy_flutter/pubspec.yaml
frontend/appflowy_flutter/pubspec.lock

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 1 issue

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="frontend/appflowy_flutter/lib/plugins/ai_chat/presentation/animated_chat_list.dart" line_range="87-91" />
<code_context>
     super.initState();

-    // TODO: Add assert for messages having same id
+    assert(
+      chatController.messages.map((m) => m.id).toSet().length ==
+          chatController.messages.length,
+      'Messages must have unique IDs.',
+    );
     oldList = List.from(chatController.messages);
     operationsSubscription = chatController.operationsStream.listen((event) {
</code_context>
<issue_to_address>
**issue (broader_impact):** The unique-ID check runs only during `initState` and Dart `assert` statements are removed in release builds, so duplicate message IDs introduced by later chat operations—or present in production—still reach `AnimatedList` and cause key collisions.

**Triggers:** When messages are updated after initialization or the application runs in a release build.

**Suggested fix:** Validate IDs whenever the controller message list changes and use an active runtime guard or collision-safe key strategy if duplicates must be prevented in production.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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