ソースを参照

chore: save app order

appflowy 3 年 前
コミット
e8bb6f0a7f

+ 0 - 1
frontend/app_flowy/lib/startup/deps_resolver.dart

@@ -99,7 +99,6 @@ void _resolveFolderDeps(GetIt getIt) {
   getIt.registerFactoryParam<MenuBloc, UserProfile, String>(
     (user, workspaceId) => MenuBloc(
       workspaceId: workspaceId,
-      service: WorkspaceService(),
       listener: getIt<WorkspaceListener>(param1: user, param2: workspaceId),
     ),
   );

+ 23 - 14
frontend/app_flowy/lib/workspace/application/menu/menu_bloc.dart

@@ -12,11 +12,13 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 part 'menu_bloc.freezed.dart';
 
 class MenuBloc extends Bloc<MenuEvent, MenuState> {
-  final WorkspaceService service;
+  final WorkspaceService _workspaceService;
   final WorkspaceListener listener;
   final String workspaceId;
 
-  MenuBloc({required this.workspaceId, required this.service, required this.listener}) : super(MenuState.initial()) {
+  MenuBloc({required this.workspaceId, required this.listener})
+      : _workspaceService = WorkspaceService(workspaceId: workspaceId),
+        super(MenuState.initial()) {
     on<MenuEvent>((event, emit) async {
       await event.map(
         initial: (e) async {
@@ -30,15 +32,21 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
         openPage: (e) async {
           emit(state.copyWith(plugin: e.plugin));
         },
-        createApp: (CreateApp event) async {
+        createApp: (_CreateApp event) async {
           await _performActionOnCreateApp(event, emit);
         },
         didReceiveApps: (e) async {
           emit(e.appsOrFail.fold(
-            (apps) => state.copyWith(apps: some(apps), successOrFailure: left(unit)),
+            (apps) => state.copyWith(apps: apps, successOrFailure: left(unit)),
             (err) => state.copyWith(successOrFailure: right(err)),
           ));
         },
+        moveApp: (_MoveApp value) {
+          if (state.apps.length > value.fromIndex) {
+            final app = state.apps[value.fromIndex];
+            _workspaceService.moveApp(appId: app.id, fromIndex: value.fromIndex, toIndex: value.toIndex);
+          }
+        },
       );
     });
   }
@@ -49,8 +57,8 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
     return super.close();
   }
 
-  Future<void> _performActionOnCreateApp(CreateApp event, Emitter<MenuState> emit) async {
-    final result = await service.createApp(workspaceId: workspaceId, name: event.name, desc: event.desc ?? "");
+  Future<void> _performActionOnCreateApp(_CreateApp event, Emitter<MenuState> emit) async {
+    final result = await _workspaceService.createApp(name: event.name, desc: event.desc ?? "");
     result.fold(
       (app) => {},
       (error) {
@@ -62,9 +70,9 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
 
   // ignore: unused_element
   Future<void> _fetchApps(Emitter<MenuState> emit) async {
-    final appsOrFail = await service.getApps(workspaceId: workspaceId);
+    final appsOrFail = await _workspaceService.getApps();
     emit(appsOrFail.fold(
-      (apps) => state.copyWith(apps: some(apps)),
+      (apps) => state.copyWith(apps: apps),
       (error) {
         Log.error(error);
         return state.copyWith(successOrFailure: right(error));
@@ -83,24 +91,25 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
 @freezed
 class MenuEvent with _$MenuEvent {
   const factory MenuEvent.initial() = _Initial;
-  const factory MenuEvent.collapse() = Collapse;
-  const factory MenuEvent.openPage(Plugin plugin) = OpenPage;
-  const factory MenuEvent.createApp(String name, {String? desc}) = CreateApp;
-  const factory MenuEvent.didReceiveApps(Either<List<App>, FlowyError> appsOrFail) = ReceiveApps;
+  const factory MenuEvent.collapse() = _Collapse;
+  const factory MenuEvent.openPage(Plugin plugin) = _OpenPage;
+  const factory MenuEvent.createApp(String name, {String? desc}) = _CreateApp;
+  const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
+  const factory MenuEvent.didReceiveApps(Either<List<App>, FlowyError> appsOrFail) = _ReceiveApps;
 }
 
 @freezed
 class MenuState with _$MenuState {
   const factory MenuState({
     required bool isCollapse,
-    required Option<List<App>> apps,
+    required List<App> apps,
     required Either<Unit, FlowyError> successOrFailure,
     required Plugin plugin,
   }) = _MenuState;
 
   factory MenuState.initial() => MenuState(
         isCollapse: false,
-        apps: none(),
+        apps: [],
         successOrFailure: left(unit),
         plugin: makePlugin(pluginType: DefaultPlugin.blank.type()),
       );

ファイルの差分が大きいため隠しています
+ 367 - 154
frontend/app_flowy/lib/workspace/application/menu/menu_bloc.freezed.dart


+ 12 - 6
frontend/app_flowy/lib/workspace/application/workspace/workspace_service.dart

@@ -1,15 +1,21 @@
 import 'dart:async';
+
 import 'package:dartz/dartz.dart';
 import 'package:easy_localization/easy_localization.dart';
 import 'package:flowy_sdk/dispatch/dispatch.dart';
+import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart' show MoveFolderItemPayload, MoveItemType;
+import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart' show MoveFolderItemPayload, MoveFolderItemType;
 import 'package:flowy_sdk/protobuf/flowy-folder-data-model/workspace.pb.dart';
-import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
+
 import 'package:app_flowy/generated/locale_keys.g.dart';
 
 class WorkspaceService {
-  Future<Either<App, FlowyError>> createApp({required String workspaceId, required String name, required String desc}) {
+  final String workspaceId;
+  WorkspaceService({
+    required this.workspaceId,
+  });
+  Future<Either<App, FlowyError>> createApp({required String name, required String desc}) {
     final payload = CreateAppPayload.create()
       ..name = name
       ..workspaceId = workspaceId
@@ -17,7 +23,7 @@ class WorkspaceService {
     return FolderEventCreateApp(payload).send();
   }
 
-  Future<Either<Workspace, FlowyError>> getWorkspace({required String workspaceId}) {
+  Future<Either<Workspace, FlowyError>> getWorkspace() {
     final payload = WorkspaceId.create()..value = workspaceId;
     return FolderEventReadWorkspaces(payload).send().then((result) {
       return result.fold(
@@ -35,7 +41,7 @@ class WorkspaceService {
     });
   }
 
-  Future<Either<List<App>, FlowyError>> getApps({required String workspaceId}) {
+  Future<Either<List<App>, FlowyError>> getApps() {
     final payload = WorkspaceId.create()..value = workspaceId;
     return FolderEventReadWorkspaceApps(payload).send().then((result) {
       return result.fold(
@@ -54,7 +60,7 @@ class WorkspaceService {
       ..itemId = appId
       ..from = fromIndex
       ..to = toIndex
-      ..ty = MoveItemType.MoveApp;
+      ..ty = MoveFolderItemType.MoveApp;
 
     return FolderEventMoveItem(payload).send();
   }

+ 7 - 58
frontend/app_flowy/lib/workspace/presentation/home/menu/menu.dart

@@ -26,7 +26,7 @@ import 'app/menu_app.dart';
 import 'app/create_button.dart';
 import 'menu_user.dart';
 
-class HomeMenu extends StatefulWidget {
+class HomeMenu extends StatelessWidget {
   final PublishNotifier<bool> _collapsedNotifier;
   final UserProfile user;
   final CurrentWorkspaceSetting workspaceSetting;
@@ -39,22 +39,13 @@ class HomeMenu extends StatefulWidget {
   })  : _collapsedNotifier = collapsedNotifier,
         super(key: key);
 
-  @override
-  State<HomeMenu> createState() => _HomeMenuState();
-}
-
-class _HomeMenuState extends State<HomeMenu> {
-  /// Maps the hashmap of the menu items to their index in reorderable list view.
-  //TODO @gaganyadav80: Retain this map to persist on app restarts.
-  final Map<int, int> _menuItemIndex = <int, int>{};
-
   @override
   Widget build(BuildContext context) {
     return MultiBlocProvider(
       providers: [
         BlocProvider<MenuBloc>(
           create: (context) {
-            final menuBloc = getIt<MenuBloc>(param1: widget.user, param2: widget.workspaceSetting.workspace.id);
+            final menuBloc = getIt<MenuBloc>(param1: user, param2: workspaceSetting.workspace.id);
             menuBloc.add(const MenuEvent.initial());
             return menuBloc;
           },
@@ -71,7 +62,7 @@ class _HomeMenuState extends State<HomeMenu> {
           BlocListener<MenuBloc, MenuState>(
             listenWhen: (p, c) => p.isCollapse != c.isCollapse,
             listener: (context, state) {
-              widget._collapsedNotifier.value = state.isCollapse;
+              _collapsedNotifier.value = state.isCollapse;
             },
           )
         ],
@@ -101,7 +92,7 @@ class _HomeMenuState extends State<HomeMenu> {
             ).padding(horizontal: Insets.l),
           ),
           const VSpace(20),
-          _renderTrash(context).padding(horizontal: Insets.l),
+          const MenuTrash().padding(horizontal: Insets.l),
           const VSpace(20),
           _renderNewAppButton(context),
         ],
@@ -116,56 +107,18 @@ class _HomeMenuState extends State<HomeMenu> {
         child: ScrollConfiguration(
           behavior: const ScrollBehavior().copyWith(scrollbars: false),
           child: BlocSelector<MenuBloc, MenuState, List<Widget>>(
-            selector: (state) {
-              List<Widget> menuItems = [];
-              // menuItems.add(MenuUser(user));
-              List<MenuApp> appWidgets =
-                  state.apps.foldRight([], (apps, _) => apps.map((app) => MenuApp(app)).toList());
-              // menuItems.addAll(appWidgets);
-              for (int i = 0; i < appWidgets.length; i++) {
-                if (_menuItemIndex[appWidgets[i].key.hashCode] == null) {
-                  _menuItemIndex[appWidgets[i].key.hashCode] = i;
-                }
-
-                menuItems.insert(_menuItemIndex[appWidgets[i].key.hashCode]!, appWidgets[i]);
-              }
-
-              return menuItems;
-            },
+            selector: (state) => state.apps.map((app) => MenuApp(app)).toList(),
             builder: (context, menuItems) {
               return ReorderableListView.builder(
                 itemCount: menuItems.length,
                 buildDefaultDragHandles: false,
                 header: Padding(
                   padding: EdgeInsets.only(bottom: 20.0 - MenuAppSizes.appVPadding),
-                  child: MenuUser(widget.user),
+                  child: MenuUser(user),
                 ),
-                onReorder: (oldIndex, newIndex) {
-                  int index = newIndex > oldIndex ? newIndex - 1 : newIndex;
-
-                  Widget menu = menuItems.removeAt(oldIndex);
-                  menuItems.insert(index, menu);
-
-                  final menuBloc = context.read<MenuBloc>();
-                  menuBloc.state.apps.forEach((a) {
-                    var app = a.removeAt(oldIndex);
-                    a.insert(index, app);
-                  });
-
-                  _menuItemIndex[menu.key.hashCode] = index;
-                },
+                onReorder: (oldIndex, newIndex) => context.read<MenuBloc>().add(MenuEvent.moveApp(oldIndex, newIndex)),
                 physics: StyledScrollPhysics(),
                 itemBuilder: (BuildContext context, int index) {
-                  //? @gaganyadav80: To mimic the ListView.separated behavior, we need to add a padding.
-                  // EdgeInsets padding = EdgeInsets.zero;
-                  // if (index == 0) {
-                  //   padding = EdgeInsets.only(bottom: MenuAppSizes.appVPadding / 2);
-                  // } else if (index == menuItems.length - 1) {
-                  //   padding = EdgeInsets.only(top: MenuAppSizes.appVPadding / 2);
-                  // } else {
-                  //   padding = EdgeInsets.symmetric(vertical: MenuAppSizes.appVPadding / 2);
-                  // }
-
                   return ReorderableDragStartListener(
                     key: ValueKey(menuItems[index].hashCode),
                     index: index,
@@ -183,10 +136,6 @@ class _HomeMenuState extends State<HomeMenu> {
     );
   }
 
-  Widget _renderTrash(BuildContext context) {
-    return const MenuTrash();
-  }
-
   Widget _renderNewAppButton(BuildContext context) {
     return NewAppButton(
       press: (appName) => context.read<MenuBloc>().add(MenuEvent.createApp(appName, desc: "")),

+ 15 - 0
shared-lib/flowy-sync/src/client_folder/folder_pad.rs

@@ -169,6 +169,21 @@ 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>> {
+        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(()))
+                }
+            }
+        })
+    }
+
     #[tracing::instrument(level = "trace", skip(self), fields(view_name=%view.name), err)]
     pub fn create_view(&mut self, view: View) -> CollaborateResult<Option<FolderChange>> {
         let app_id = view.belong_to_id.clone();

この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません