Browse Source

Merge pull request #467 from AppFlowy-IO/fix_reorder_animation

Fix: reorder animation
Nathan.fooo 3 years ago
parent
commit
f2cd3846f1
22 changed files with 276 additions and 1372 deletions
  1. 10 1
      frontend/app_flowy/lib/workspace/application/app/app_bloc.dart
  2. 42 1
      frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart
  3. 14 2
      frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart
  4. 3 0
      frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart
  5. 0 1251
      frontend/app_flowy/lib/workspace/application/menu/menu_bloc.freezed.dart
  6. 6 2
      frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart
  7. 6 1
      frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart
  8. 10 3
      frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart
  9. 17 36
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart
  10. 14 6
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart
  11. 17 4
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart
  12. 4 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart
  13. 24 3
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart
  14. 16 14
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart
  15. 26 4
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart
  16. 7 6
      frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart
  17. 1 1
      frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs
  18. 1 1
      frontend/rust-lib/flowy-net/src/local_server/server.rs
  19. 10 16
      shared-lib/flowy-sync/src/client_folder/folder_pad.rs
  20. 15 12
      shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs
  21. 1 5
      shared-lib/lib-infra/src/lib.rs
  22. 32 0
      shared-lib/lib-infra/src/util.rs

+ 10 - 1
frontend/app_flowy/lib/workspace/application/app/app_bloc.dart

@@ -161,11 +161,12 @@ class AppViewDataContext extends ChangeNotifier {
   final String appId;
   final ValueNotifier<List<View>> _viewsNotifier = ValueNotifier([]);
   final ValueNotifier<View?> _selectedViewNotifier = ValueNotifier(null);
+  VoidCallback? _menuSharedStateListener;
   ExpandableController expandController = ExpandableController(initialExpanded: false);
 
   AppViewDataContext({required this.appId}) {
     _setLatestView(getIt<MenuSharedState>().latestOpenView);
-    getIt<MenuSharedState>().addLatestViewListener((view) {
+    _menuSharedStateListener = getIt<MenuSharedState>().addLatestViewListener((view) {
       _setLatestView(view);
     });
   }
@@ -234,4 +235,12 @@ class AppViewDataContext extends ChangeNotifier {
       });
     }
   }
+
+  @override
+  void dispose() {
+    if (_menuSharedStateListener != null) {
+      getIt<MenuSharedState>().removeLatestViewListener(_menuSharedStateListener!);
+    }
+    super.dispose();
+  }
 }

+ 42 - 1
frontend/app_flowy/lib/workspace/application/grid/cell/cell_service.dart

@@ -1,7 +1,9 @@
 import 'dart:async';
 import 'dart:collection';
 
+import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
 import 'package:dartz/dartz.dart';
+import 'package:equatable/equatable.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
 import 'package:flowy_sdk/log.dart';
 import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
@@ -10,13 +12,52 @@ import 'package:flowy_sdk/protobuf/flowy-grid/cell_entities.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid/selection_type_option.pb.dart';
 import 'package:flutter/foundation.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
+
 import 'package:app_flowy/workspace/application/grid/cell/cell_listener.dart';
-import 'package:equatable/equatable.dart';
+
 part 'cell_service.freezed.dart';
 
 typedef GridDefaultCellContext = GridCellContext<Cell>;
 typedef GridSelectOptionCellContext = GridCellContext<SelectOptionContext>;
 
+class GridCellContextBuilder {
+  final GridCellCache _cellCache;
+  final GridCell _gridCell;
+  GridCellContextBuilder({
+    required GridCellCache cellCache,
+    required GridCell gridCell,
+  })  : _cellCache = cellCache,
+        _gridCell = gridCell;
+
+  GridCellContext build() {
+    switch (_gridCell.field.fieldType) {
+      case FieldType.Checkbox:
+      case FieldType.DateTime:
+      case FieldType.Number:
+        return GridDefaultCellContext(
+          gridCell: _gridCell,
+          cellCache: _cellCache,
+          cellDataLoader: DefaultCellDataLoader(gridCell: _gridCell, reloadOnCellChanged: true),
+        );
+      case FieldType.RichText:
+        return GridDefaultCellContext(
+          gridCell: _gridCell,
+          cellCache: _cellCache,
+          cellDataLoader: DefaultCellDataLoader(gridCell: _gridCell),
+        );
+      case FieldType.MultiSelect:
+      case FieldType.SingleSelect:
+        return GridSelectOptionCellContext(
+          gridCell: _gridCell,
+          cellCache: _cellCache,
+          cellDataLoader: SelectOptionCellDataLoader(gridCell: _gridCell),
+        );
+      default:
+        throw UnimplementedError;
+    }
+  }
+}
+
 // ignore: must_be_immutable
 class GridCellContext<T> extends Equatable {
   final GridCell gridCell;

+ 14 - 2
frontend/app_flowy/lib/workspace/application/grid/grid_header_bloc.dart

@@ -27,14 +27,26 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
             emit(state.copyWith(fields: value.fields));
           },
           moveField: (_MoveField value) async {
-            final result = await _fieldService.moveField(value.field.id, value.fromIndex, value.toIndex);
-            result.fold((l) {}, (err) => Log.error(err));
+            await _moveField(value, emit);
           },
         );
       },
     );
   }
 
+  Future<void> _moveField(_MoveField value, Emitter<GridHeaderState> emit) async {
+    final fields = List<Field>.from(state.fields);
+    fields.insert(value.toIndex, fields.removeAt(value.fromIndex));
+    emit(state.copyWith(fields: fields));
+
+    final result = await _fieldService.moveField(
+      value.field.id,
+      value.fromIndex,
+      value.toIndex,
+    );
+    result.fold((l) {}, (err) => Log.error(err));
+  }
+
   Future<void> _startListening() async {
     fieldCache.addListener(
       onChanged: (fields) => add(GridHeaderEvent.didReceiveFieldUpdate(fields)),

+ 3 - 0
frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart

@@ -45,6 +45,9 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
           if (state.apps.length > value.fromIndex) {
             final app = state.apps[value.fromIndex];
             _workspaceService.moveApp(appId: app.id, fromIndex: value.fromIndex, toIndex: value.toIndex);
+            final apps = List<App>.from(state.apps);
+            apps.insert(value.toIndex, apps.removeAt(value.fromIndex));
+            emit(state.copyWith(apps: apps));
           }
         },
       );

+ 0 - 1251
frontend/app_flowy/lib/workspace/application/menu/menu_bloc.freezed.dart

@@ -1,1251 +0,0 @@
-// coverage:ignore-file
-// GENERATED CODE - DO NOT MODIFY BY HAND
-// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
-
-part of 'menu_bloc.dart';
-
-// **************************************************************************
-// FreezedGenerator
-// **************************************************************************
-
-T _$identity<T>(T value) => value;
-
-final _privateConstructorUsedError = UnsupportedError(
-    'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
-
-/// @nodoc
-class _$MenuEventTearOff {
-  const _$MenuEventTearOff();
-
-  _Initial initial() {
-    return const _Initial();
-  }
-
-  _Collapse collapse() {
-    return const _Collapse();
-  }
-
-  _OpenPage openPage(Plugin plugin) {
-    return _OpenPage(
-      plugin,
-    );
-  }
-
-  _CreateApp createApp(String name, {String? desc}) {
-    return _CreateApp(
-      name,
-      desc: desc,
-    );
-  }
-
-  _MoveApp moveApp(int fromIndex, int toIndex) {
-    return _MoveApp(
-      fromIndex,
-      toIndex,
-    );
-  }
-
-  _ReceiveApps didReceiveApps(Either<List<App>, FlowyError> appsOrFail) {
-    return _ReceiveApps(
-      appsOrFail,
-    );
-  }
-}
-
-/// @nodoc
-const $MenuEvent = _$MenuEventTearOff();
-
-/// @nodoc
-mixin _$MenuEvent {
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) =>
-      throw _privateConstructorUsedError;
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class $MenuEventCopyWith<$Res> {
-  factory $MenuEventCopyWith(MenuEvent value, $Res Function(MenuEvent) then) =
-      _$MenuEventCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class _$MenuEventCopyWithImpl<$Res> implements $MenuEventCopyWith<$Res> {
-  _$MenuEventCopyWithImpl(this._value, this._then);
-
-  final MenuEvent _value;
-  // ignore: unused_field
-  final $Res Function(MenuEvent) _then;
-}
-
-/// @nodoc
-abstract class _$InitialCopyWith<$Res> {
-  factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
-      __$InitialCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class __$InitialCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$InitialCopyWith<$Res> {
-  __$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
-      : super(_value, (v) => _then(v as _Initial));
-
-  @override
-  _Initial get _value => super._value as _Initial;
-}
-
-/// @nodoc
-
-class _$_Initial implements _Initial {
-  const _$_Initial();
-
-  @override
-  String toString() {
-    return 'MenuEvent.initial()';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) || (other is _Initial);
-  }
-
-  @override
-  int get hashCode => runtimeType.hashCode;
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return initial();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return initial?.call();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (initial != null) {
-      return initial();
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return initial(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return initial?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (initial != null) {
-      return initial(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Initial implements MenuEvent {
-  const factory _Initial() = _$_Initial;
-}
-
-/// @nodoc
-abstract class _$CollapseCopyWith<$Res> {
-  factory _$CollapseCopyWith(_Collapse value, $Res Function(_Collapse) then) =
-      __$CollapseCopyWithImpl<$Res>;
-}
-
-/// @nodoc
-class __$CollapseCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$CollapseCopyWith<$Res> {
-  __$CollapseCopyWithImpl(_Collapse _value, $Res Function(_Collapse) _then)
-      : super(_value, (v) => _then(v as _Collapse));
-
-  @override
-  _Collapse get _value => super._value as _Collapse;
-}
-
-/// @nodoc
-
-class _$_Collapse implements _Collapse {
-  const _$_Collapse();
-
-  @override
-  String toString() {
-    return 'MenuEvent.collapse()';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) || (other is _Collapse);
-  }
-
-  @override
-  int get hashCode => runtimeType.hashCode;
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return collapse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return collapse?.call();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (collapse != null) {
-      return collapse();
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return collapse(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return collapse?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (collapse != null) {
-      return collapse(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _Collapse implements MenuEvent {
-  const factory _Collapse() = _$_Collapse;
-}
-
-/// @nodoc
-abstract class _$OpenPageCopyWith<$Res> {
-  factory _$OpenPageCopyWith(_OpenPage value, $Res Function(_OpenPage) then) =
-      __$OpenPageCopyWithImpl<$Res>;
-  $Res call({Plugin plugin});
-}
-
-/// @nodoc
-class __$OpenPageCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$OpenPageCopyWith<$Res> {
-  __$OpenPageCopyWithImpl(_OpenPage _value, $Res Function(_OpenPage) _then)
-      : super(_value, (v) => _then(v as _OpenPage));
-
-  @override
-  _OpenPage get _value => super._value as _OpenPage;
-
-  @override
-  $Res call({
-    Object? plugin = freezed,
-  }) {
-    return _then(_OpenPage(
-      plugin == freezed
-          ? _value.plugin
-          : plugin // ignore: cast_nullable_to_non_nullable
-              as Plugin,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_OpenPage implements _OpenPage {
-  const _$_OpenPage(this.plugin);
-
-  @override
-  final Plugin plugin;
-
-  @override
-  String toString() {
-    return 'MenuEvent.openPage(plugin: $plugin)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _OpenPage &&
-            (identical(other.plugin, plugin) ||
-                const DeepCollectionEquality().equals(other.plugin, plugin)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(plugin);
-
-  @JsonKey(ignore: true)
-  @override
-  _$OpenPageCopyWith<_OpenPage> get copyWith =>
-      __$OpenPageCopyWithImpl<_OpenPage>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return openPage(plugin);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return openPage?.call(plugin);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (openPage != null) {
-      return openPage(plugin);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return openPage(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return openPage?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (openPage != null) {
-      return openPage(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _OpenPage implements MenuEvent {
-  const factory _OpenPage(Plugin plugin) = _$_OpenPage;
-
-  Plugin get plugin => throw _privateConstructorUsedError;
-  @JsonKey(ignore: true)
-  _$OpenPageCopyWith<_OpenPage> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class _$CreateAppCopyWith<$Res> {
-  factory _$CreateAppCopyWith(
-          _CreateApp value, $Res Function(_CreateApp) then) =
-      __$CreateAppCopyWithImpl<$Res>;
-  $Res call({String name, String? desc});
-}
-
-/// @nodoc
-class __$CreateAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$CreateAppCopyWith<$Res> {
-  __$CreateAppCopyWithImpl(_CreateApp _value, $Res Function(_CreateApp) _then)
-      : super(_value, (v) => _then(v as _CreateApp));
-
-  @override
-  _CreateApp get _value => super._value as _CreateApp;
-
-  @override
-  $Res call({
-    Object? name = freezed,
-    Object? desc = freezed,
-  }) {
-    return _then(_CreateApp(
-      name == freezed
-          ? _value.name
-          : name // ignore: cast_nullable_to_non_nullable
-              as String,
-      desc: desc == freezed
-          ? _value.desc
-          : desc // ignore: cast_nullable_to_non_nullable
-              as String?,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_CreateApp implements _CreateApp {
-  const _$_CreateApp(this.name, {this.desc});
-
-  @override
-  final String name;
-  @override
-  final String? desc;
-
-  @override
-  String toString() {
-    return 'MenuEvent.createApp(name: $name, desc: $desc)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _CreateApp &&
-            (identical(other.name, name) ||
-                const DeepCollectionEquality().equals(other.name, name)) &&
-            (identical(other.desc, desc) ||
-                const DeepCollectionEquality().equals(other.desc, desc)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^
-      const DeepCollectionEquality().hash(name) ^
-      const DeepCollectionEquality().hash(desc);
-
-  @JsonKey(ignore: true)
-  @override
-  _$CreateAppCopyWith<_CreateApp> get copyWith =>
-      __$CreateAppCopyWithImpl<_CreateApp>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return createApp(name, desc);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return createApp?.call(name, desc);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (createApp != null) {
-      return createApp(name, desc);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return createApp(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return createApp?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (createApp != null) {
-      return createApp(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _CreateApp implements MenuEvent {
-  const factory _CreateApp(String name, {String? desc}) = _$_CreateApp;
-
-  String get name => throw _privateConstructorUsedError;
-  String? get desc => throw _privateConstructorUsedError;
-  @JsonKey(ignore: true)
-  _$CreateAppCopyWith<_CreateApp> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class _$MoveAppCopyWith<$Res> {
-  factory _$MoveAppCopyWith(_MoveApp value, $Res Function(_MoveApp) then) =
-      __$MoveAppCopyWithImpl<$Res>;
-  $Res call({int fromIndex, int toIndex});
-}
-
-/// @nodoc
-class __$MoveAppCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$MoveAppCopyWith<$Res> {
-  __$MoveAppCopyWithImpl(_MoveApp _value, $Res Function(_MoveApp) _then)
-      : super(_value, (v) => _then(v as _MoveApp));
-
-  @override
-  _MoveApp get _value => super._value as _MoveApp;
-
-  @override
-  $Res call({
-    Object? fromIndex = freezed,
-    Object? toIndex = freezed,
-  }) {
-    return _then(_MoveApp(
-      fromIndex == freezed
-          ? _value.fromIndex
-          : fromIndex // ignore: cast_nullable_to_non_nullable
-              as int,
-      toIndex == freezed
-          ? _value.toIndex
-          : toIndex // ignore: cast_nullable_to_non_nullable
-              as int,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_MoveApp implements _MoveApp {
-  const _$_MoveApp(this.fromIndex, this.toIndex);
-
-  @override
-  final int fromIndex;
-  @override
-  final int toIndex;
-
-  @override
-  String toString() {
-    return 'MenuEvent.moveApp(fromIndex: $fromIndex, toIndex: $toIndex)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _MoveApp &&
-            (identical(other.fromIndex, fromIndex) ||
-                const DeepCollectionEquality()
-                    .equals(other.fromIndex, fromIndex)) &&
-            (identical(other.toIndex, toIndex) ||
-                const DeepCollectionEquality().equals(other.toIndex, toIndex)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^
-      const DeepCollectionEquality().hash(fromIndex) ^
-      const DeepCollectionEquality().hash(toIndex);
-
-  @JsonKey(ignore: true)
-  @override
-  _$MoveAppCopyWith<_MoveApp> get copyWith =>
-      __$MoveAppCopyWithImpl<_MoveApp>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return moveApp(fromIndex, toIndex);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return moveApp?.call(fromIndex, toIndex);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (moveApp != null) {
-      return moveApp(fromIndex, toIndex);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return moveApp(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return moveApp?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (moveApp != null) {
-      return moveApp(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _MoveApp implements MenuEvent {
-  const factory _MoveApp(int fromIndex, int toIndex) = _$_MoveApp;
-
-  int get fromIndex => throw _privateConstructorUsedError;
-  int get toIndex => throw _privateConstructorUsedError;
-  @JsonKey(ignore: true)
-  _$MoveAppCopyWith<_MoveApp> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class _$ReceiveAppsCopyWith<$Res> {
-  factory _$ReceiveAppsCopyWith(
-          _ReceiveApps value, $Res Function(_ReceiveApps) then) =
-      __$ReceiveAppsCopyWithImpl<$Res>;
-  $Res call({Either<List<App>, FlowyError> appsOrFail});
-}
-
-/// @nodoc
-class __$ReceiveAppsCopyWithImpl<$Res> extends _$MenuEventCopyWithImpl<$Res>
-    implements _$ReceiveAppsCopyWith<$Res> {
-  __$ReceiveAppsCopyWithImpl(
-      _ReceiveApps _value, $Res Function(_ReceiveApps) _then)
-      : super(_value, (v) => _then(v as _ReceiveApps));
-
-  @override
-  _ReceiveApps get _value => super._value as _ReceiveApps;
-
-  @override
-  $Res call({
-    Object? appsOrFail = freezed,
-  }) {
-    return _then(_ReceiveApps(
-      appsOrFail == freezed
-          ? _value.appsOrFail
-          : appsOrFail // ignore: cast_nullable_to_non_nullable
-              as Either<List<App>, FlowyError>,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_ReceiveApps implements _ReceiveApps {
-  const _$_ReceiveApps(this.appsOrFail);
-
-  @override
-  final Either<List<App>, FlowyError> appsOrFail;
-
-  @override
-  String toString() {
-    return 'MenuEvent.didReceiveApps(appsOrFail: $appsOrFail)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _ReceiveApps &&
-            (identical(other.appsOrFail, appsOrFail) ||
-                const DeepCollectionEquality()
-                    .equals(other.appsOrFail, appsOrFail)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^ const DeepCollectionEquality().hash(appsOrFail);
-
-  @JsonKey(ignore: true)
-  @override
-  _$ReceiveAppsCopyWith<_ReceiveApps> get copyWith =>
-      __$ReceiveAppsCopyWithImpl<_ReceiveApps>(this, _$identity);
-
-  @override
-  @optionalTypeArgs
-  TResult when<TResult extends Object?>({
-    required TResult Function() initial,
-    required TResult Function() collapse,
-    required TResult Function(Plugin plugin) openPage,
-    required TResult Function(String name, String? desc) createApp,
-    required TResult Function(int fromIndex, int toIndex) moveApp,
-    required TResult Function(Either<List<App>, FlowyError> appsOrFail)
-        didReceiveApps,
-  }) {
-    return didReceiveApps(appsOrFail);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? whenOrNull<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-  }) {
-    return didReceiveApps?.call(appsOrFail);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeWhen<TResult extends Object?>({
-    TResult Function()? initial,
-    TResult Function()? collapse,
-    TResult Function(Plugin plugin)? openPage,
-    TResult Function(String name, String? desc)? createApp,
-    TResult Function(int fromIndex, int toIndex)? moveApp,
-    TResult Function(Either<List<App>, FlowyError> appsOrFail)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (didReceiveApps != null) {
-      return didReceiveApps(appsOrFail);
-    }
-    return orElse();
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult map<TResult extends Object?>({
-    required TResult Function(_Initial value) initial,
-    required TResult Function(_Collapse value) collapse,
-    required TResult Function(_OpenPage value) openPage,
-    required TResult Function(_CreateApp value) createApp,
-    required TResult Function(_MoveApp value) moveApp,
-    required TResult Function(_ReceiveApps value) didReceiveApps,
-  }) {
-    return didReceiveApps(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult? mapOrNull<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-  }) {
-    return didReceiveApps?.call(this);
-  }
-
-  @override
-  @optionalTypeArgs
-  TResult maybeMap<TResult extends Object?>({
-    TResult Function(_Initial value)? initial,
-    TResult Function(_Collapse value)? collapse,
-    TResult Function(_OpenPage value)? openPage,
-    TResult Function(_CreateApp value)? createApp,
-    TResult Function(_MoveApp value)? moveApp,
-    TResult Function(_ReceiveApps value)? didReceiveApps,
-    required TResult orElse(),
-  }) {
-    if (didReceiveApps != null) {
-      return didReceiveApps(this);
-    }
-    return orElse();
-  }
-}
-
-abstract class _ReceiveApps implements MenuEvent {
-  const factory _ReceiveApps(Either<List<App>, FlowyError> appsOrFail) =
-      _$_ReceiveApps;
-
-  Either<List<App>, FlowyError> get appsOrFail =>
-      throw _privateConstructorUsedError;
-  @JsonKey(ignore: true)
-  _$ReceiveAppsCopyWith<_ReceiveApps> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-class _$MenuStateTearOff {
-  const _$MenuStateTearOff();
-
-  _MenuState call(
-      {required bool isCollapse,
-      required List<App> apps,
-      required Either<Unit, FlowyError> successOrFailure,
-      required Plugin plugin}) {
-    return _MenuState(
-      isCollapse: isCollapse,
-      apps: apps,
-      successOrFailure: successOrFailure,
-      plugin: plugin,
-    );
-  }
-}
-
-/// @nodoc
-const $MenuState = _$MenuStateTearOff();
-
-/// @nodoc
-mixin _$MenuState {
-  bool get isCollapse => throw _privateConstructorUsedError;
-  List<App> get apps => throw _privateConstructorUsedError;
-  Either<Unit, FlowyError> get successOrFailure =>
-      throw _privateConstructorUsedError;
-  Plugin get plugin => throw _privateConstructorUsedError;
-
-  @JsonKey(ignore: true)
-  $MenuStateCopyWith<MenuState> get copyWith =>
-      throw _privateConstructorUsedError;
-}
-
-/// @nodoc
-abstract class $MenuStateCopyWith<$Res> {
-  factory $MenuStateCopyWith(MenuState value, $Res Function(MenuState) then) =
-      _$MenuStateCopyWithImpl<$Res>;
-  $Res call(
-      {bool isCollapse,
-      List<App> apps,
-      Either<Unit, FlowyError> successOrFailure,
-      Plugin plugin});
-}
-
-/// @nodoc
-class _$MenuStateCopyWithImpl<$Res> implements $MenuStateCopyWith<$Res> {
-  _$MenuStateCopyWithImpl(this._value, this._then);
-
-  final MenuState _value;
-  // ignore: unused_field
-  final $Res Function(MenuState) _then;
-
-  @override
-  $Res call({
-    Object? isCollapse = freezed,
-    Object? apps = freezed,
-    Object? successOrFailure = freezed,
-    Object? plugin = freezed,
-  }) {
-    return _then(_value.copyWith(
-      isCollapse: isCollapse == freezed
-          ? _value.isCollapse
-          : isCollapse // ignore: cast_nullable_to_non_nullable
-              as bool,
-      apps: apps == freezed
-          ? _value.apps
-          : apps // ignore: cast_nullable_to_non_nullable
-              as List<App>,
-      successOrFailure: successOrFailure == freezed
-          ? _value.successOrFailure
-          : successOrFailure // ignore: cast_nullable_to_non_nullable
-              as Either<Unit, FlowyError>,
-      plugin: plugin == freezed
-          ? _value.plugin
-          : plugin // ignore: cast_nullable_to_non_nullable
-              as Plugin,
-    ));
-  }
-}
-
-/// @nodoc
-abstract class _$MenuStateCopyWith<$Res> implements $MenuStateCopyWith<$Res> {
-  factory _$MenuStateCopyWith(
-          _MenuState value, $Res Function(_MenuState) then) =
-      __$MenuStateCopyWithImpl<$Res>;
-  @override
-  $Res call(
-      {bool isCollapse,
-      List<App> apps,
-      Either<Unit, FlowyError> successOrFailure,
-      Plugin plugin});
-}
-
-/// @nodoc
-class __$MenuStateCopyWithImpl<$Res> extends _$MenuStateCopyWithImpl<$Res>
-    implements _$MenuStateCopyWith<$Res> {
-  __$MenuStateCopyWithImpl(_MenuState _value, $Res Function(_MenuState) _then)
-      : super(_value, (v) => _then(v as _MenuState));
-
-  @override
-  _MenuState get _value => super._value as _MenuState;
-
-  @override
-  $Res call({
-    Object? isCollapse = freezed,
-    Object? apps = freezed,
-    Object? successOrFailure = freezed,
-    Object? plugin = freezed,
-  }) {
-    return _then(_MenuState(
-      isCollapse: isCollapse == freezed
-          ? _value.isCollapse
-          : isCollapse // ignore: cast_nullable_to_non_nullable
-              as bool,
-      apps: apps == freezed
-          ? _value.apps
-          : apps // ignore: cast_nullable_to_non_nullable
-              as List<App>,
-      successOrFailure: successOrFailure == freezed
-          ? _value.successOrFailure
-          : successOrFailure // ignore: cast_nullable_to_non_nullable
-              as Either<Unit, FlowyError>,
-      plugin: plugin == freezed
-          ? _value.plugin
-          : plugin // ignore: cast_nullable_to_non_nullable
-              as Plugin,
-    ));
-  }
-}
-
-/// @nodoc
-
-class _$_MenuState implements _MenuState {
-  const _$_MenuState(
-      {required this.isCollapse,
-      required this.apps,
-      required this.successOrFailure,
-      required this.plugin});
-
-  @override
-  final bool isCollapse;
-  @override
-  final List<App> apps;
-  @override
-  final Either<Unit, FlowyError> successOrFailure;
-  @override
-  final Plugin plugin;
-
-  @override
-  String toString() {
-    return 'MenuState(isCollapse: $isCollapse, apps: $apps, successOrFailure: $successOrFailure, plugin: $plugin)';
-  }
-
-  @override
-  bool operator ==(dynamic other) {
-    return identical(this, other) ||
-        (other is _MenuState &&
-            (identical(other.isCollapse, isCollapse) ||
-                const DeepCollectionEquality()
-                    .equals(other.isCollapse, isCollapse)) &&
-            (identical(other.apps, apps) ||
-                const DeepCollectionEquality().equals(other.apps, apps)) &&
-            (identical(other.successOrFailure, successOrFailure) ||
-                const DeepCollectionEquality()
-                    .equals(other.successOrFailure, successOrFailure)) &&
-            (identical(other.plugin, plugin) ||
-                const DeepCollectionEquality().equals(other.plugin, plugin)));
-  }
-
-  @override
-  int get hashCode =>
-      runtimeType.hashCode ^
-      const DeepCollectionEquality().hash(isCollapse) ^
-      const DeepCollectionEquality().hash(apps) ^
-      const DeepCollectionEquality().hash(successOrFailure) ^
-      const DeepCollectionEquality().hash(plugin);
-
-  @JsonKey(ignore: true)
-  @override
-  _$MenuStateCopyWith<_MenuState> get copyWith =>
-      __$MenuStateCopyWithImpl<_MenuState>(this, _$identity);
-}
-
-abstract class _MenuState implements MenuState {
-  const factory _MenuState(
-      {required bool isCollapse,
-      required List<App> apps,
-      required Either<Unit, FlowyError> successOrFailure,
-      required Plugin plugin}) = _$_MenuState;
-
-  @override
-  bool get isCollapse => throw _privateConstructorUsedError;
-  @override
-  List<App> get apps => throw _privateConstructorUsedError;
-  @override
-  Either<Unit, FlowyError> get successOrFailure =>
-      throw _privateConstructorUsedError;
-  @override
-  Plugin get plugin => throw _privateConstructorUsedError;
-  @override
-  @JsonKey(ignore: true)
-  _$MenuStateCopyWith<_MenuState> get copyWith =>
-      throw _privateConstructorUsedError;
-}

+ 6 - 2
frontend/app_flowy/lib/workspace/application/menu/menu_view_section_bloc.dart

@@ -32,7 +32,7 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
           emit(state.copyWith(views: value.views));
         },
         moveView: (_MoveView value) async {
-          await _moveView(value);
+          _moveView(value, emit);
         },
       );
     });
@@ -59,9 +59,13 @@ class ViewSectionBloc extends Bloc<ViewSectionEvent, ViewSectionState> {
     }
   }
 
-  Future<void> _moveView(_MoveView value) async {
+  Future<void> _moveView(_MoveView value, Emitter<ViewSectionState> emit) async {
     if (value.fromIndex < state.views.length) {
       final viewId = state.views[value.fromIndex].id;
+      final views = List<View>.from(state.views);
+      views.insert(value.toIndex, views.removeAt(value.fromIndex));
+      emit(state.copyWith(views: views));
+
       final result = await _appService.moveView(
         viewId: viewId,
         fromIndex: value.fromIndex,

+ 6 - 1
frontend/app_flowy/lib/workspace/presentation/home/menu/app/menu_app.dart

@@ -11,7 +11,7 @@ import 'section/section.dart';
 
 class MenuApp extends StatefulWidget {
   final App app;
-  MenuApp(this.app, {Key? key}) : super(key: ValueKey(app.hashCode));
+  const MenuApp(this.app, {Key? key}) : super(key: key);
 
   @override
   State<MenuApp> createState() => _MenuAppState();
@@ -95,6 +95,11 @@ class _MenuAppState extends State<MenuApp> {
     );
   }
 
+  @override
+  void didUpdateWidget(covariant MenuApp oldWidget) {
+    super.didUpdateWidget(oldWidget);
+  }
+
   @override
   void dispose() {
     viewDataContext.dispose();

+ 10 - 3
frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart

@@ -107,7 +107,7 @@ class HomeMenu extends StatelessWidget {
         child: ScrollConfiguration(
           behavior: const ScrollBehavior().copyWith(scrollbars: false),
           child: BlocSelector<MenuBloc, MenuState, List<Widget>>(
-            selector: (state) => state.apps.map((app) => MenuApp(app)).toList(),
+            selector: (state) => state.apps.map((app) => MenuApp(app, key: ValueKey(app.id))).toList(),
             builder: (context, menuItems) {
               return ReorderableListView.builder(
                 itemCount: menuItems.length,
@@ -116,11 +116,18 @@ class HomeMenu extends StatelessWidget {
                   padding: EdgeInsets.only(bottom: 20.0 - MenuAppSizes.appVPadding),
                   child: MenuUser(user),
                 ),
-                onReorder: (oldIndex, newIndex) => context.read<MenuBloc>().add(MenuEvent.moveApp(oldIndex, newIndex)),
+                onReorder: (oldIndex, newIndex) {
+                  // Moving item1 from index 0 to index 1
+                  //  expect:   oldIndex: 0, newIndex: 1
+                  //  receive:  oldIndex: 0, newIndex: 2
+                  //  Workaround: if newIndex > oldIndex, we just minus one
+                  int index = newIndex > oldIndex ? newIndex - 1 : newIndex;
+                  context.read<MenuBloc>().add(MenuEvent.moveApp(oldIndex, index));
+                },
                 physics: StyledScrollPhysics(),
                 itemBuilder: (BuildContext context, int index) {
                   return ReorderableDragStartListener(
-                    key: ValueKey(menuItems[index].hashCode),
+                    key: ValueKey(menuItems[index].key),
                     index: index,
                     child: Padding(
                       padding: EdgeInsets.symmetric(vertical: MenuAppSizes.appVPadding / 2),

+ 17 - 36
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart

@@ -1,5 +1,4 @@
 import 'package:app_flowy/workspace/application/grid/cell/cell_service.dart';
-import 'package:app_flowy/workspace/application/grid/cell/select_option_service.dart';
 import 'package:flowy_infra_ui/style_widget/hover.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType;
 import 'package:flutter/widgets.dart';
@@ -12,49 +11,22 @@ import 'text_cell.dart';
 GridCellWidget buildGridCellWidget(GridCell gridCell, GridCellCache cellCache, {GridCellStyle? style}) {
   final key = ValueKey(gridCell.rowId + gridCell.field.id);
 
-  final cellContext = makeCellContext(gridCell, cellCache);
+  final cellContextBuilder = GridCellContextBuilder(gridCell: gridCell, cellCache: cellCache);
 
   switch (gridCell.field.fieldType) {
     case FieldType.Checkbox:
-      return CheckboxCell(cellContext: cellContext, key: key);
+      return CheckboxCell(cellContextBuilder: cellContextBuilder, key: key);
     case FieldType.DateTime:
-      return DateCell(cellContext: cellContext, key: key);
+      return DateCell(cellContextBuilder: cellContextBuilder, key: key);
+    case FieldType.SingleSelect:
+      return SingleSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
     case FieldType.MultiSelect:
-      return MultiSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key);
+      return MultiSelectCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
     case FieldType.Number:
-      return NumberCell(cellContext: cellContext, key: key);
+      return NumberCell(cellContextBuilder: cellContextBuilder, key: key);
     case FieldType.RichText:
-      return GridTextCell(cellContext: cellContext, style: style, key: key);
-    case FieldType.SingleSelect:
-      return SingleSelectCell(cellContext: cellContext as GridSelectOptionCellContext, style: style, key: key);
-    default:
-      throw UnimplementedError;
-  }
-}
+      return GridTextCell(cellContextBuilder: cellContextBuilder, style: style, key: key);
 
-GridCellContext makeCellContext(GridCell gridCell, GridCellCache cellCache) {
-  switch (gridCell.field.fieldType) {
-    case FieldType.Checkbox:
-    case FieldType.DateTime:
-    case FieldType.Number:
-      return GridDefaultCellContext(
-        gridCell: gridCell,
-        cellCache: cellCache,
-        cellDataLoader: DefaultCellDataLoader(gridCell: gridCell, reloadOnCellChanged: true),
-      );
-    case FieldType.RichText:
-      return GridDefaultCellContext(
-        gridCell: gridCell,
-        cellCache: cellCache,
-        cellDataLoader: DefaultCellDataLoader(gridCell: gridCell),
-      );
-    case FieldType.MultiSelect:
-    case FieldType.SingleSelect:
-      return GridSelectOptionCellContext(
-        gridCell: gridCell,
-        cellCache: cellCache,
-        cellDataLoader: SelectOptionCellDataLoader(gridCell: gridCell),
-      );
     default:
       throw UnimplementedError;
   }
@@ -72,7 +44,16 @@ class BlankCell extends StatelessWidget {
 abstract class GridCellWidget extends HoverWidget {
   @override
   final ValueNotifier<bool> onFocus = ValueNotifier<bool>(false);
+
+  final GridCellRequestFocusNotifier requestFocus = GridCellRequestFocusNotifier();
+
   GridCellWidget({Key? key}) : super(key: key);
 }
 
+class GridCellRequestFocusNotifier extends ChangeNotifier {
+  void notify() {
+    notifyListeners();
+  }
+}
+
 abstract class GridCellStyle {}

+ 14 - 6
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_container.dart

@@ -1,3 +1,4 @@
+import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart';
 import 'package:flowy_infra/theme.dart';
 import 'package:flutter/material.dart';
 import 'package:provider/provider.dart';
@@ -31,17 +32,20 @@ class CellContainer extends StatelessWidget {
   final GridCellWidget child;
   final Widget? expander;
   final double width;
+  final RegionStateNotifier rowStateNotifier;
   const CellContainer({
     Key? key,
     required this.child,
     required this.width,
+    required this.rowStateNotifier,
     this.expander,
   }) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
-    return ChangeNotifierProvider(
+    return ChangeNotifierProxyProvider<RegionStateNotifier, CellStateNotifier>(
       create: (_) => CellStateNotifier(),
+      update: (_, row, cell) => cell!..onEnter = row.onEnter,
       child: Selector<CellStateNotifier, bool>(
         selector: (context, notifier) => notifier.isFocus,
         builder: (context, isFocus, _) {
@@ -54,11 +58,15 @@ class CellContainer extends StatelessWidget {
             container = _CellEnterRegion(child: container, expander: expander!);
           }
 
-          return Container(
-            constraints: BoxConstraints(maxWidth: width),
-            decoration: _makeBoxDecoration(context, isFocus),
-            padding: GridSize.cellContentInsets,
-            child: container,
+          return GestureDetector(
+            behavior: HitTestBehavior.translucent,
+            onTap: () => child.requestFocus.notify(),
+            child: Container(
+              constraints: BoxConstraints(maxWidth: width),
+              decoration: _makeBoxDecoration(context, isFocus),
+              padding: GridSize.cellContentInsets,
+              child: container,
+            ),
           );
         },
       ),

+ 17 - 4
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/checkbox_cell.dart

@@ -7,10 +7,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'cell_builder.dart';
 
 class CheckboxCell extends GridCellWidget {
-  final GridCellContext cellContext;
-
+  final GridCellContextBuilder cellContextBuilder;
   CheckboxCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     Key? key,
   }) : super(key: key);
 
@@ -23,7 +22,9 @@ class _CheckboxCellState extends State<CheckboxCell> {
 
   @override
   void initState() {
-    _cellBloc = getIt<CheckboxCellBloc>(param1: widget.cellContext)..add(const CheckboxCellEvent.initial());
+    final cellContext = widget.cellContextBuilder.build();
+    _cellBloc = getIt<CheckboxCellBloc>(param1: cellContext)..add(const CheckboxCellEvent.initial());
+    _listenCellRequestFocus();
     super.initState();
   }
 
@@ -48,9 +49,21 @@ class _CheckboxCellState extends State<CheckboxCell> {
     );
   }
 
+  @override
+  void didUpdateWidget(covariant CheckboxCell oldWidget) {
+    _listenCellRequestFocus();
+    super.didUpdateWidget(oldWidget);
+  }
+
   @override
   Future<void> dispose() async {
     _cellBloc.close();
     super.dispose();
   }
+
+  void _listenCellRequestFocus() {
+    widget.requestFocus.addListener(() {
+      _cellBloc.add(const CheckboxCellEvent.select());
+    });
+  }
 }

+ 4 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart

@@ -14,10 +14,10 @@ abstract class GridCellDelegate {
 }
 
 class DateCell extends GridCellWidget {
-  final GridCellContext cellContext;
+  final GridCellContextBuilder cellContextBuilder;
 
   DateCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     Key? key,
   }) : super(key: key);
 
@@ -30,7 +30,8 @@ class _DateCellState extends State<DateCell> {
 
   @override
   void initState() {
-    _cellBloc = getIt<DateCellBloc>(param1: widget.cellContext)..add(const DateCellEvent.initial());
+    final cellContext = widget.cellContextBuilder.build();
+    _cellBloc = getIt<DateCellBloc>(param1: cellContext)..add(const DateCellEvent.initial());
     super.initState();
   }
 

+ 24 - 3
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/number_cell.dart

@@ -8,10 +8,10 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'cell_builder.dart';
 
 class NumberCell extends GridCellWidget {
-  final GridCellContext cellContext;
+  final GridCellContextBuilder cellContextBuilder;
 
   NumberCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     Key? key,
   }) : super(key: key);
 
@@ -23,11 +23,13 @@ class _NumberCellState extends State<NumberCell> {
   late NumberCellBloc _cellBloc;
   late TextEditingController _controller;
   late FocusNode _focusNode;
+  VoidCallback? _focusListener;
   Timer? _delayOperation;
 
   @override
   void initState() {
-    _cellBloc = getIt<NumberCellBloc>(param1: widget.cellContext)..add(const NumberCellEvent.initial());
+    final cellContext = widget.cellContextBuilder.build();
+    _cellBloc = getIt<NumberCellBloc>(param1: cellContext)..add(const NumberCellEvent.initial());
     _controller = TextEditingController(text: _cellBloc.state.content);
     _focusNode = FocusNode();
     _focusNode.addListener(() {
@@ -39,6 +41,7 @@ class _NumberCellState extends State<NumberCell> {
 
   @override
   Widget build(BuildContext context) {
+    _listenCellRequestFocus(context);
     return BlocProvider.value(
       value: _cellBloc,
       child: BlocConsumer<NumberCellBloc, NumberCellState>(
@@ -67,6 +70,9 @@ class _NumberCellState extends State<NumberCell> {
 
   @override
   Future<void> dispose() async {
+    if (_focusListener != null) {
+      widget.requestFocus.removeListener(_focusListener!);
+    }
     _delayOperation?.cancel();
     _cellBloc.close();
     _focusNode.dispose();
@@ -88,4 +94,19 @@ class _NumberCellState extends State<NumberCell> {
       });
     }
   }
+
+  void _listenCellRequestFocus(BuildContext context) {
+    if (_focusListener != null) {
+      widget.requestFocus.removeListener(_focusListener!);
+    }
+
+    focusListener() {
+      if (_focusNode.hasFocus == false && _focusNode.canRequestFocus) {
+        FocusScope.of(context).requestFocus(_focusNode);
+      }
+    }
+
+    _focusListener = focusListener;
+    widget.requestFocus.addListener(focusListener);
+  }
 }

+ 16 - 14
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart

@@ -20,11 +20,11 @@ class SelectOptionCellStyle extends GridCellStyle {
 }
 
 class SingleSelectCell extends GridCellWidget {
-  final GridSelectOptionCellContext cellContext;
+  final GridCellContextBuilder cellContextBuilder;
   late final SelectOptionCellStyle? cellStyle;
 
   SingleSelectCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     GridCellStyle? style,
     Key? key,
   }) : super(key: key) {
@@ -45,7 +45,8 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
   @override
   void initState() {
     // Log.trace("init widget $hashCode");
-    _cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext)..add(const SelectionCellEvent.initial());
+    final cellContext = _buildCellContext();
+    _cellBloc = getIt<SelectionCellBloc>(param1: cellContext)..add(const SelectionCellEvent.initial());
     super.initState();
   }
 
@@ -69,7 +70,7 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
                 widget.onFocus.value = true;
                 SelectOptionCellEditor.show(
                   context,
-                  widget.cellContext.clone(),
+                  _buildCellContext(),
                   () => widget.onFocus.value = false,
                 );
               },
@@ -81,12 +82,8 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
     );
   }
 
-  @override
-  void didUpdateWidget(covariant SingleSelectCell oldWidget) {
-    if (oldWidget.cellContext != widget.cellContext) {
-      // Log.trace("did update widget $hashCode");
-    }
-    super.didUpdateWidget(oldWidget);
+  GridSelectOptionCellContext _buildCellContext() {
+    return widget.cellContextBuilder.build() as GridSelectOptionCellContext;
   }
 
   @override
@@ -99,11 +96,11 @@ class _SingleSelectCellState extends State<SingleSelectCell> {
 
 //----------------------------------------------------------------
 class MultiSelectCell extends GridCellWidget {
-  final GridSelectOptionCellContext cellContext;
+  final GridCellContextBuilder cellContextBuilder;
   late final SelectOptionCellStyle? cellStyle;
 
   MultiSelectCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     GridCellStyle? style,
     Key? key,
   }) : super(key: key) {
@@ -123,7 +120,8 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
 
   @override
   void initState() {
-    _cellBloc = getIt<SelectionCellBloc>(param1: widget.cellContext)..add(const SelectionCellEvent.initial());
+    final cellContext = _buildCellContext();
+    _cellBloc = getIt<SelectionCellBloc>(param1: cellContext)..add(const SelectionCellEvent.initial());
     super.initState();
   }
 
@@ -145,7 +143,7 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
                 widget.onFocus.value = true;
                 SelectOptionCellEditor.show(
                   context,
-                  widget.cellContext,
+                  _buildCellContext(),
                   () => widget.onFocus.value = false,
                 );
               },
@@ -162,4 +160,8 @@ class _MultiSelectCellState extends State<MultiSelectCell> {
     _cellBloc.close();
     super.dispose();
   }
+
+  GridSelectOptionCellContext _buildCellContext() {
+    return widget.cellContextBuilder.build() as GridSelectOptionCellContext;
+  }
 }

+ 26 - 4
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/text_cell.dart

@@ -14,10 +14,10 @@ class GridTextCellStyle extends GridCellStyle {
 }
 
 class GridTextCell extends GridCellWidget {
-  final GridCellContext cellContext;
+  final GridCellContextBuilder cellContextBuilder;
   late final GridTextCellStyle? cellStyle;
   GridTextCell({
-    required this.cellContext,
+    required this.cellContextBuilder,
     GridCellStyle? style,
     Key? key,
   }) : super(key: key) {
@@ -36,12 +36,13 @@ class _GridTextCellState extends State<GridTextCell> {
   late TextCellBloc _cellBloc;
   late TextEditingController _controller;
   late FocusNode _focusNode;
-
+  VoidCallback? _focusListener;
   Timer? _delayOperation;
 
   @override
   void initState() {
-    _cellBloc = getIt<TextCellBloc>(param1: widget.cellContext);
+    final cellContext = widget.cellContextBuilder.build();
+    _cellBloc = getIt<TextCellBloc>(param1: cellContext);
     _cellBloc.add(const TextCellEvent.initial());
     _controller = TextEditingController(text: _cellBloc.state.content);
     _focusNode = FocusNode();
@@ -49,11 +50,14 @@ class _GridTextCellState extends State<GridTextCell> {
       widget.onFocus.value = _focusNode.hasFocus;
       focusChanged();
     });
+
     super.initState();
   }
 
   @override
   Widget build(BuildContext context) {
+    _listenCellRequestFocus(context);
+
     return BlocProvider.value(
       value: _cellBloc,
       child: BlocConsumer<TextCellBloc, TextCellState>(
@@ -83,8 +87,26 @@ class _GridTextCellState extends State<GridTextCell> {
     );
   }
 
+  void _listenCellRequestFocus(BuildContext context) {
+    if (_focusListener != null) {
+      widget.requestFocus.removeListener(_focusListener!);
+    }
+
+    focusListener() {
+      if (_focusNode.hasFocus == false && _focusNode.canRequestFocus) {
+        FocusScope.of(context).requestFocus(_focusNode);
+      }
+    }
+
+    _focusListener = focusListener;
+    widget.requestFocus.addListener(focusListener);
+  }
+
   @override
   Future<void> dispose() async {
+    if (_focusListener != null) {
+      widget.requestFocus.removeListener(_focusListener!);
+    }
     _delayOperation?.cancel();
     _cellBloc.close();
     _focusNode.dispose();

+ 7 - 6
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/grid_row.dart

@@ -88,7 +88,7 @@ class _RowLeading extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    return Consumer<_RegionStateNotifier>(
+    return Consumer<RegionStateNotifier>(
       builder: (context, state, _) {
         return SizedBox(width: GridSize.leadingHeaderPadding, child: state.onEnter ? _activeWidget() : null);
       },
@@ -164,13 +164,13 @@ class _RowCells extends StatelessWidget {
         return Row(
           mainAxisSize: MainAxisSize.min,
           mainAxisAlignment: MainAxisAlignment.center,
-          children: _makeCells(state.cellDataMap),
+          children: _makeCells(context, state.cellDataMap),
         );
       },
     );
   }
 
-  List<Widget> _makeCells(GridCellMap gridCellMap) {
+  List<Widget> _makeCells(BuildContext context, GridCellMap gridCellMap) {
     return gridCellMap.values.map(
       (gridCell) {
         Widget? expander;
@@ -181,6 +181,7 @@ class _RowCells extends StatelessWidget {
         return CellContainer(
           width: gridCell.field.width.toDouble(),
           child: buildGridCellWidget(gridCell, cellCache),
+          rowStateNotifier: Provider.of<RegionStateNotifier>(context, listen: false),
           expander: expander,
         );
       },
@@ -188,7 +189,7 @@ class _RowCells extends StatelessWidget {
   }
 }
 
-class _RegionStateNotifier extends ChangeNotifier {
+class RegionStateNotifier extends ChangeNotifier {
   bool _onEnter = false;
 
   set onEnter(bool value) {
@@ -226,11 +227,11 @@ class _RowEnterRegion extends StatefulWidget {
 }
 
 class _RowEnterRegionState extends State<_RowEnterRegion> {
-  late _RegionStateNotifier _rowStateNotifier;
+  late RegionStateNotifier _rowStateNotifier;
 
   @override
   void initState() {
-    _rowStateNotifier = _RegionStateNotifier();
+    _rowStateNotifier = RegionStateNotifier();
     super.initState();
   }
 

+ 1 - 1
frontend/rust-lib/flowy-folder/src/services/persistence/version_1/view_sql.rs

@@ -12,7 +12,7 @@ use flowy_database::{
     schema::{view_table, view_table::dsl},
     SqliteConnection,
 };
-use lib_infra::timestamp;
+use lib_infra::util::timestamp;
 
 pub struct ViewTableSql();
 impl ViewTableSql {

+ 1 - 1
frontend/rust-lib/flowy-net/src/local_server/server.rs

@@ -265,7 +265,7 @@ use flowy_user::event_map::UserCloudService;
 use flowy_user_data_model::entities::{
     SignInParams, SignInResponse, SignUpParams, SignUpResponse, UpdateUserParams, UserProfile,
 };
-use lib_infra::{future::FutureResult, timestamp};
+use lib_infra::{future::FutureResult, util::timestamp};
 
 impl FolderCouldServiceV1 for LocalServer {
     fn init(&self) {}

+ 10 - 16
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -10,6 +10,8 @@ use crate::{
 use flowy_folder_data_model::entities::{app::App, trash::Trash, view::View, workspace::Workspace};
 use lib_ot::core::*;
 
+use crate::errors::internal_error;
+use lib_infra::util::move_vec_element;
 use serde::{Deserialize, Serialize};
 use std::sync::Arc;
 
@@ -170,16 +172,12 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn move_app(&mut self, app_id: &str, _from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
+    pub fn move_app(&mut self, app_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
         let app = self.read_app(app_id)?;
         self.with_workspace(&app.workspace_id, |workspace| {
-            match workspace.apps.iter().position(|app| app.id == app_id) {
-                None => Ok(None),
-                Some(index) => {
-                    let app = workspace.apps.remove(index);
-                    workspace.apps.insert(to, app);
-                    Ok(Some(()))
-                }
+            match move_vec_element(&mut workspace.apps, |app| app.id == app_id, from, to).map_err(internal_error)? {
+                true => Ok(Some(())),
+                false => Ok(None),
             }
         })
     }
@@ -251,16 +249,12 @@ impl FolderPad {
     }
 
     #[tracing::instrument(level = "trace", skip(self), err)]
-    pub fn move_view(&mut self, view_id: &str, _from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
+    pub fn move_view(&mut self, view_id: &str, from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
         let view = self.read_view(view_id)?;
         self.with_app(&view.belong_to_id, |app| {
-            match app.belongings.iter().position(|view| view.id == view_id) {
-                None => Ok(None),
-                Some(index) => {
-                    let view = app.belongings.remove(index);
-                    app.belongings.insert(to, view);
-                    Ok(Some(()))
-                }
+            match move_vec_element(&mut app.belongings, |view| view.id == view_id, from, to).map_err(internal_error)? {
+                true => Ok(Some(())),
+                false => Ok(None),
             }
         })
     }

+ 15 - 12
shared-lib/flowy-sync/src/client_grid/grid_meta_pad.rs

@@ -6,6 +6,7 @@ use flowy_grid_data_model::entities::{
     gen_grid_id, FieldChangesetParams, FieldMeta, FieldOrder, FieldType, GridBlockMeta, GridBlockMetaChangeset,
     GridMeta,
 };
+use lib_infra::util::move_vec_element;
 use lib_ot::core::{OperationTransformable, PlainTextAttributes, PlainTextDelta, PlainTextDeltaBuilder};
 use std::collections::HashMap;
 use std::sync::Arc;
@@ -208,20 +209,22 @@ impl GridMetaPad {
     pub fn move_field(
         &mut self,
         field_id: &str,
-        _from_index: usize,
+        from_index: usize,
         to_index: usize,
     ) -> CollaborateResult<Option<GridChangeset>> {
-        self.modify_grid(
-            |grid_meta| match grid_meta.fields.iter().position(|field| field.id == field_id) {
-                None => Ok(None),
-                Some(index) => {
-                    // debug_assert_eq!(index, from_index);
-                    let field_meta = grid_meta.fields.remove(index);
-                    grid_meta.fields.insert(to_index, field_meta);
-                    Ok(Some(()))
-                }
-            },
-        )
+        self.modify_grid(|grid_meta| {
+            match move_vec_element(
+                &mut grid_meta.fields,
+                |field| field.id == field_id,
+                from_index,
+                to_index,
+            )
+            .map_err(internal_error)?
+            {
+                true => Ok(Some(())),
+                false => Ok(None),
+            }
+        })
     }
 
     pub fn contain_field(&self, field_id: &str) -> bool {

+ 1 - 5
shared-lib/lib-infra/src/lib.rs

@@ -1,8 +1,4 @@
 pub mod code_gen;
 pub mod future;
 pub mod retry;
-
-#[allow(dead_code)]
-pub fn timestamp() -> i64 {
-    chrono::Utc::now().timestamp()
-}
+pub mod util;

+ 32 - 0
shared-lib/lib-infra/src/util.rs

@@ -0,0 +1,32 @@
+pub fn move_vec_element<T, F>(
+    vec: &mut Vec<T>,
+    filter: F,
+    _from_index: usize,
+    mut to_index: usize,
+) -> Result<bool, String>
+where
+    F: FnMut(&T) -> bool,
+{
+    match vec.iter().position(filter) {
+        None => Ok(false),
+        Some(index) => {
+            if vec.len() > to_index {
+                let removed_element = vec.remove(index);
+                vec.insert(to_index, removed_element);
+                Ok(true)
+            } else {
+                let msg = format!(
+                    "Move element to invalid index: {}, current len: {}",
+                    to_index,
+                    vec.len()
+                );
+                Err(msg)
+            }
+        }
+    }
+}
+
+#[allow(dead_code)]
+pub fn timestamp() -> i64 {
+    chrono::Utc::now().timestamp()
+}