From e42bfe0b1eedc8530d1fbb931c40990f13efda75 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 29 Aug 2022 14:37:38 +0800 Subject: [PATCH 1/4] chore: ignore dragtarget event when performing insert animation --- .../lib/src/widgets/reorder_flex/reorder_flex.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart index b0f511f641..63bd9638b4 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart @@ -82,6 +82,8 @@ class ReorderFlex extends StatefulWidget { final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage; + final bool reorderable; + ReorderFlex({ Key? key, this.scrollController, @@ -89,6 +91,7 @@ class ReorderFlex extends StatefulWidget { required this.children, required this.config, required this.onReorder, + this.reorderable = true, this.dragStateStorage, this.dragTargetIndexKeyStorage, this.onDragStarted, @@ -385,7 +388,7 @@ class ReorderFlexState extends State }, onWillAccept: (FlexDragTargetData dragTargetData) { // Do not receive any events if the Insert item is animating. - if (_animation.deleteController.isAnimating) { + if (_animation.insertController.isAnimating) { return false; } @@ -421,6 +424,7 @@ class ReorderFlexState extends State deleteAnimationController: _animation.deleteController, draggableTargetBuilder: widget.interceptor?.draggableTargetBuilder, useMoveAnimation: widget.config.useMoveAnimation, + draggable: widget.reorderable, child: child, ); } From 4e8308b8342565dcb343752ba87f5c221f06798c Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 29 Aug 2022 15:42:08 +0800 Subject: [PATCH 2/4] chore: disable moving column --- .../card/board_text_cell_bloc.dart | 8 ++ .../card/board_select_option_cell.dart | 41 +++++++++-- .../presentation/card/board_text_cell.dart | 41 +++++++---- .../plugins/board/presentation/card/card.dart | 24 ++++-- .../flutter/generated_plugin_registrant.cc | 4 + .../linux/flutter/generated_plugins.cmake | 1 + .../Flutter/GeneratedPluginRegistrant.swift | 2 + .../example/lib/multi_board_list_example.dart | 73 ++++++++++++------- .../appflowy_board/lib/src/utils/log.dart | 4 +- .../appflowy_board/lib/src/widgets/board.dart | 13 +++- .../widgets/board_column/board_column.dart | 4 +- .../src/widgets/reorder_flex/drag_target.dart | 5 ++ .../reorder_flex/drag_target_interceptor.dart | 3 +- .../reorder_phantom/phantom_controller.dart | 35 +++++---- .../reorder_phantom/phantom_state.dart | 2 +- 15 files changed, 183 insertions(+), 77 deletions(-) diff --git a/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart index e11d7b5ac6..3df8b029f8 100644 --- a/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/card/board_text_cell_bloc.dart @@ -1,4 +1,5 @@ import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; @@ -20,6 +21,12 @@ class BoardTextCellBloc extends Bloc { didReceiveCellUpdate: (content) { emit(state.copyWith(content: content)); }, + updateText: (text) { + if (text != state.content) { + cellController.saveCellData(text); + emit(state.copyWith(content: text)); + } + }, ); }, ); @@ -49,6 +56,7 @@ class BoardTextCellBloc extends Bloc { @freezed class BoardTextCellEvent with _$BoardTextCellEvent { const factory BoardTextCellEvent.initial() = _InitialCell; + const factory BoardTextCellEvent.updateText(String text) = _UpdateContent; const factory BoardTextCellEvent.didReceiveCellUpdate(String cellContent) = _DidReceiveCellUpdate; } diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart index b2383bd937..e0607db306 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_select_option_cell.dart @@ -1,6 +1,7 @@ import 'package:app_flowy/plugins/board/application/card/board_select_option_cell_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/extension.dart'; +import 'package:app_flowy/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -40,8 +41,9 @@ class _BoardSelectOptionCellState extends State { }, builder: (context, state) { if (state.selectedOptions - .where((element) => element.id == widget.groupId) - .isNotEmpty) { + .where((element) => element.id == widget.groupId) + .isNotEmpty || + state.selectedOptions.isEmpty) { return const SizedBox(); } else { final children = state.selectedOptions @@ -52,10 +54,17 @@ class _BoardSelectOptionCellState extends State { ), ) .toList(); - return Align( - alignment: Alignment.centerLeft, - child: AbsorbPointer( - child: Wrap(children: children, spacing: 4, runSpacing: 2), + + return IntrinsicHeight( + child: Stack( + alignment: AlignmentDirectional.center, + fit: StackFit.expand, + children: [ + Wrap(children: children, spacing: 4, runSpacing: 2), + _SelectOptionDialog( + controller: widget.cellControllerBuilder.build(), + ), + ], ), ); } @@ -70,3 +79,23 @@ class _BoardSelectOptionCellState extends State { super.dispose(); } } + +class _SelectOptionDialog extends StatelessWidget { + final GridSelectOptionCellController _controller; + const _SelectOptionDialog({ + Key? key, + required IGridCellController controller, + }) : _controller = controller as GridSelectOptionCellController, + super(key: key); + + @override + Widget build(BuildContext context) { + return InkWell(onTap: () { + SelectOptionCellEditor.show( + context, + _controller, + () {}, + ); + }); + } +} diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart index deea60e793..ed683005f9 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart @@ -1,5 +1,6 @@ import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; +import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -19,14 +20,16 @@ class BoardTextCell extends StatefulWidget { class _BoardTextCellState extends State { late BoardTextCellBloc _cellBloc; + late TextEditingController _controller; + SingleListenerFocusNode focusNode = SingleListenerFocusNode(); @override void initState() { final cellController = widget.cellControllerBuilder.build() as GridCellController; - _cellBloc = BoardTextCellBloc(cellController: cellController) ..add(const BoardTextCellEvent.initial()); + _controller = TextEditingController(text: _cellBloc.state.content); super.initState(); } @@ -34,28 +37,38 @@ class _BoardTextCellState extends State { Widget build(BuildContext context) { return BlocProvider.value( value: _cellBloc, - child: BlocBuilder( - buildWhen: (previous, current) => previous.content != current.content, - builder: (context, state) { - if (state.content.isEmpty) { - return const SizedBox(); - } else { - return Align( - alignment: Alignment.centerLeft, - child: ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 120), - child: FlowyText.medium(state.content, fontSize: 14), - ), - ); + child: BlocListener( + listener: (context, state) { + if (_controller.text != state.content) { + _controller.text = state.content; } }, + child: TextField( + controller: _controller, + focusNode: focusNode, + onChanged: (value) => focusChanged(), + onEditingComplete: () => focusNode.unfocus(), + maxLines: 1, + style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500), + decoration: const InputDecoration( + contentPadding: EdgeInsets.symmetric(vertical: 6), + border: InputBorder.none, + isDense: true, + ), + ), ), ); } + Future focusChanged() async { + _cellBloc.add(BoardTextCellEvent.updateText(_controller.text)); + } + @override Future dispose() async { _cellBloc.close(); + _controller.dispose(); + focusNode.dispose(); super.dispose(); } } diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart index dfb8149c9e..9f919f2dd1 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart @@ -68,6 +68,7 @@ class _BoardCardState extends State { widget.openCard(context); }, child: Column( + mainAxisSize: MainAxisSize.min, children: _makeCells( context, state.cells.map((cell) => cell.identifier).toList(), @@ -83,15 +84,24 @@ class _BoardCardState extends State { BuildContext context, List cells, ) { - return cells.map( - (GridCellIdentifier cellId) { + final List children = []; + cells.asMap().forEach( + (int index, GridCellIdentifier cellId) { final child = widget.cellBuilder.buildCell(widget.groupId, cellId); - return Padding( - padding: const EdgeInsets.only(left: 4, right: 4, top: 6), - child: child, - ); + if (index != 0) { + children.add(Padding( + padding: const EdgeInsets.only(left: 4, right: 4, top: 8), + child: child, + )); + } else { + children.add(Padding( + padding: const EdgeInsets.only(left: 4, right: 4), + child: child, + )); + } }, - ).toList(); + ); + return children; } @override diff --git a/frontend/app_flowy/linux/flutter/generated_plugin_registrant.cc b/frontend/app_flowy/linux/flutter/generated_plugin_registrant.cc index ae6ec7ed89..f05fb593f4 100644 --- a/frontend/app_flowy/linux/flutter/generated_plugin_registrant.cc +++ b/frontend/app_flowy/linux/flutter/generated_plugin_registrant.cc @@ -7,6 +7,7 @@ #include "generated_plugin_registrant.h" #include +#include #include #include #include @@ -15,6 +16,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flowy_infra_ui_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlowyInfraUIPlugin"); flowy_infra_u_i_plugin_register_with_registrar(flowy_infra_ui_registrar); + g_autoptr(FlPluginRegistrar) hotkey_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "HotkeyManagerPlugin"); + hotkey_manager_plugin_register_with_registrar(hotkey_manager_registrar); g_autoptr(FlPluginRegistrar) rich_clipboard_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "RichClipboardPlugin"); rich_clipboard_plugin_register_with_registrar(rich_clipboard_linux_registrar); diff --git a/frontend/app_flowy/linux/flutter/generated_plugins.cmake b/frontend/app_flowy/linux/flutter/generated_plugins.cmake index 3e0d068b6a..ce38abcac0 100644 --- a/frontend/app_flowy/linux/flutter/generated_plugins.cmake +++ b/frontend/app_flowy/linux/flutter/generated_plugins.cmake @@ -4,6 +4,7 @@ list(APPEND FLUTTER_PLUGIN_LIST flowy_infra_ui + hotkey_manager rich_clipboard_linux url_launcher_linux window_size diff --git a/frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift b/frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift index 60d2b8c792..2f24aad58b 100644 --- a/frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/frontend/app_flowy/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import connectivity_plus_macos import device_info_plus_macos import flowy_infra_ui import flowy_sdk +import hotkey_manager import package_info_plus_macos import path_provider_macos import rich_clipboard_macos @@ -21,6 +22,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) FlowyInfraUIPlugin.register(with: registry.registrar(forPlugin: "FlowyInfraUIPlugin")) FlowySdkPlugin.register(with: registry.registrar(forPlugin: "FlowySdkPlugin")) + HotkeyManagerPlugin.register(with: registry.registrar(forPlugin: "HotkeyManagerPlugin")) FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) RichClipboardPlugin.register(with: registry.registrar(forPlugin: "RichClipboardPlugin")) diff --git a/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart b/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart index 170738b2e4..7b9a84b6d2 100644 --- a/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart +++ b/frontend/app_flowy/packages/appflowy_board/example/lib/multi_board_list_example.dart @@ -11,13 +11,13 @@ class MultiBoardListExample extends StatefulWidget { class _MultiBoardListExampleState extends State { final AFBoardDataController boardDataController = AFBoardDataController( onMoveColumn: (fromColumnId, fromIndex, toColumnId, toIndex) { - debugPrint('Move column from $fromIndex to $toIndex'); + // debugPrint('Move column from $fromIndex to $toIndex'); }, onMoveColumnItem: (columnId, fromIndex, toIndex) { - debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex'); + // debugPrint('Move $columnId:$fromIndex to $columnId:$toIndex'); }, onMoveColumnItemToColumn: (fromColumnId, fromIndex, toColumnId, toIndex) { - debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex'); + // debugPrint('Move $fromColumnId:$fromIndex to $toColumnId:$toIndex'); }, ); @@ -96,7 +96,7 @@ class _MultiBoardListExampleState extends State { }, cardBuilder: (context, column, columnItem) { return AppFlowyColumnItemCard( - key: ObjectKey(columnItem), + key: ValueKey(columnItem.id), child: _buildCard(columnItem), ); }, @@ -121,33 +121,56 @@ class _MultiBoardListExampleState extends State { } if (item is RichTextItem) { - return Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - item.title, - style: const TextStyle(fontSize: 14), - textAlign: TextAlign.left, - ), - const SizedBox(height: 10), - Text( - item.subtitle, - style: const TextStyle(fontSize: 12, color: Colors.grey), - ) - ], - ), - ), - ); + return RichTextCard(item: item); } throw UnimplementedError(); } } +class RichTextCard extends StatefulWidget { + final RichTextItem item; + const RichTextCard({ + required this.item, + Key? key, + }) : super(key: key); + + @override + State createState() => _RichTextCardState(); +} + +class _RichTextCardState extends State { + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 20), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.item.title, + style: const TextStyle(fontSize: 14), + textAlign: TextAlign.left, + ), + const SizedBox(height: 10), + Text( + widget.item.subtitle, + style: const TextStyle(fontSize: 12, color: Colors.grey), + ) + ], + ), + ), + ); + } +} + class TextItem extends AFColumnItem { final String s; diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart index 9c23060b26..bd2f39e926 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/utils/log.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; const DART_LOG = "Dart_LOG"; class Log { - static const enableLog = false; + static const enableLog = true; static void info(String? message) { if (enableLog) { @@ -26,7 +26,7 @@ class Log { static void trace(String? message) { if (enableLog) { - debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); + // debugPrint('❗️[Trace] - ${DateTime.now().second}=> $message'); } } } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart index 67d8111aec..3360325e8e 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board.dart @@ -64,7 +64,7 @@ class AFBoard extends StatelessWidget { final BoxConstraints columnConstraints; /// - final BoardPhantomController phantomController; + late final BoardPhantomController phantomController; final ScrollController? scrollController; @@ -85,8 +85,12 @@ class AFBoard extends StatelessWidget { this.columnConstraints = const BoxConstraints(maxWidth: 200), this.config = const AFBoardConfig(), Key? key, - }) : phantomController = BoardPhantomController(delegate: dataController), - super(key: key); + }) : super(key: key) { + phantomController = BoardPhantomController( + delegate: dataController, + columnsState: _columnState, + ); + } @override Widget build(BuildContext context) { @@ -194,6 +198,7 @@ class _AFBoardContentState extends State { dataSource: widget.dataController, direction: Axis.horizontal, interceptor: interceptor, + reorderable: false, children: _buildColumns(), ); @@ -244,7 +249,7 @@ class _AFBoardContentState extends State { child: Consumer( builder: (context, value, child) { final boardColumn = AFBoardColumnWidget( - key: PageStorageKey(columnData.id), + // key: PageStorageKey(columnData.id), // key: GlobalObjectKey(columnData.id), margin: _marginFromIndex(columnIndex), itemMargin: widget.config.columnItemPadding, diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart index a89ef269cb..ee1b501e8f 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/board_column/board_column.dart @@ -92,7 +92,7 @@ class AFBoardColumnWidget extends StatefulWidget { final ReorderDragTargetIndexKeyStorage? dragTargetIndexKeyStorage; - final GlobalKey globalKey; + final GlobalObjectKey globalKey; AFBoardColumnWidget({ Key? key, @@ -111,7 +111,7 @@ class AFBoardColumnWidget extends StatefulWidget { this.itemMargin = EdgeInsets.zero, this.cornerRadius = 0.0, this.backgroundColor = Colors.transparent, - }) : globalKey = GlobalKey(), + }) : globalKey = GlobalObjectKey(dataSource.columnData.id), config = const ReorderFlexConfig(), super(key: key); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart index 92b71cd1f3..9da9e393ad 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target.dart @@ -75,6 +75,7 @@ class ReorderDragTarget extends StatefulWidget { final AnimationController deleteAnimationController; final bool useMoveAnimation; + final bool draggable; const ReorderDragTarget({ Key? key, @@ -88,6 +89,7 @@ class ReorderDragTarget extends StatefulWidget { required this.insertAnimationController, required this.deleteAnimationController, required this.useMoveAnimation, + required this.draggable, this.onAccept, this.onLeave, this.draggableTargetBuilder, @@ -132,6 +134,9 @@ class _ReorderDragTargetState List acceptedCandidates, List rejectedCandidates, ) { + if (!widget.draggable) { + return widget.child; + } Widget feedbackBuilder = Builder(builder: (BuildContext context) { BoxConstraints contentSizeConstraints = BoxConstraints.loose(_draggingFeedbackSize!); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart index a2d2cf9c6c..20f66c0921 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/drag_target_interceptor.dart @@ -131,6 +131,7 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor { final String reorderFlexId; final List acceptedReorderFlexIds; final CrossReorderFlexDragTargetDelegate delegate; + @override final ReorderFlexDraggableTargetBuilder? draggableTargetBuilder; @@ -188,7 +189,7 @@ class CrossReorderFlexDragTargetInterceptor extends DragTargetInterceptor { ); Log.debug( - '[$CrossReorderFlexDragTargetInterceptor] dargTargetIndex: $dragTargetIndex, reorderFlexId: $reorderFlexId'); + '[$CrossReorderFlexDragTargetInterceptor] isNewDragTarget: $isNewDragTarget, dargTargetIndex: $dragTargetIndex, reorderFlexId: $reorderFlexId'); if (isNewDragTarget == false) { delegate.updateDragTargetData(reorderFlexId, dragTargetIndex); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart index 14b525d67d..a3e0f5fb6e 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart @@ -1,3 +1,4 @@ +import 'package:appflowy_board/appflowy_board.dart'; import 'package:flutter/widgets.dart'; import '../../utils/log.dart'; @@ -39,8 +40,12 @@ class BoardPhantomController extends OverlapDragTargetDelegate with CrossReorderFlexDragTargetDelegate { PhantomRecord? phantomRecord; final BoardPhantomControllerDelegate delegate; - final columnsState = ColumnPhantomStateController(); - BoardPhantomController({required this.delegate}); + final BoardColumnsState columnsState; + final phantomState = ColumnPhantomState(); + BoardPhantomController({ + required this.delegate, + required this.columnsState, + }); bool isFromColumn(String columnId) { if (phantomRecord != null) { @@ -59,19 +64,19 @@ class BoardPhantomController extends OverlapDragTargetDelegate } void columnStartDragging(String columnId) { - columnsState.setColumnIsDragging(columnId, true); + phantomState.setColumnIsDragging(columnId, true); } /// Remove the phantom in the column when the column is end dragging. void columnEndDragging(String columnId) { - columnsState.setColumnIsDragging(columnId, false); + phantomState.setColumnIsDragging(columnId, false); if (phantomRecord == null) return; final fromColumnId = phantomRecord!.fromColumnId; final toColumnId = phantomRecord!.toColumnId; if (fromColumnId == columnId) { - columnsState.notifyDidRemovePhantom(toColumnId); + phantomState.notifyDidRemovePhantom(toColumnId); } if (phantomRecord!.toColumnId == columnId) { @@ -82,8 +87,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate phantomRecord!.toColumnIndex, ); - Log.debug( - "[$BoardPhantomController] did move ${phantomRecord.toString()}"); + // Log.debug( + // "[$BoardPhantomController] did move ${phantomRecord.toString()}"); phantomRecord = null; } } @@ -91,8 +96,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate /// Remove the phantom in the column if it contains phantom void _removePhantom(String columnId) { if (delegate.removePhantom(columnId)) { - columnsState.notifyDidRemovePhantom(columnId); - columnsState.removeColumnListener(columnId); + phantomState.notifyDidRemovePhantom(columnId); + phantomState.removeColumnListener(columnId); } } @@ -105,7 +110,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate index: phantomIndex, dragTargetData: dragTargetData, ); - columnsState.addColumnListener(toColumnId, phantomContext); + phantomState.addColumnListener(toColumnId, phantomContext); delegate.insertPhantom( toColumnId, @@ -113,7 +118,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate PhantomColumnItem(phantomContext), ); - columnsState.notifyDidInsertPhantom(toColumnId, phantomIndex); + phantomState.notifyDidInsertPhantom(toColumnId, phantomIndex); } /// Reset or initial the [PhantomRecord] @@ -150,7 +155,8 @@ class BoardPhantomController extends OverlapDragTargetDelegate if (phantomRecord == null) { _resetPhantomRecord(reorderFlexId, dragTargetData, dragTargetIndex); _insertPhantom(reorderFlexId, dragTargetData, dragTargetIndex); - return false; + + return true; } final isNewDragTarget = phantomRecord!.toColumnId != reorderFlexId; @@ -204,7 +210,7 @@ class BoardPhantomController extends OverlapDragTargetDelegate @override int getInsertedIndex(String dragTargetId) { - if (columnsState.isDragging(dragTargetId)) { + if (phantomState.isDragging(dragTargetId)) { return -1; } @@ -243,8 +249,7 @@ class PhantomRecord { if (fromColumnIndex == index) { return; } - Log.debug( - '[$PhantomRecord] Update Column:[$fromColumnId] remove position to $index'); + fromColumnIndex = index; } diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart index 443d7fb936..c550ee3bca 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_state.dart @@ -1,7 +1,7 @@ import 'phantom_controller.dart'; import 'package:flutter/material.dart'; -class ColumnPhantomStateController { +class ColumnPhantomState { final _states = {}; void setColumnIsDragging(String columnId, bool isDragging) { From af3bfebb64c7ae6c189a1512524f99ae0c4e39c8 Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 29 Aug 2022 16:32:20 +0800 Subject: [PATCH 3/4] chore: become editing when creating a new card --- .../plugins/board/application/board_bloc.dart | 19 +++++++++++---- .../board/application/group_controller.dart | 7 +++++- .../board/presentation/board_page.dart | 9 ++------ .../board/presentation/card/board_cell.dart | 3 +++ .../presentation/card/board_text_cell.dart | 9 +++++++- .../plugins/board/presentation/card/card.dart | 23 +++++++++++-------- .../presentation/card/card_cell_builder.dart | 7 +++++- .../packages/appflowy_board/CHANGELOG.md | 4 ++++ .../widgets/reorder_flex/reorder_flex.dart | 1 - .../reorder_phantom/phantom_controller.dart | 1 - .../packages/appflowy_board/pubspec.yaml | 2 +- .../flowy-grid/src/entities/block_entities.rs | 15 ++++++++++-- .../flowy-grid/src/services/block_manager.rs | 1 + .../src/services/grid_view_editor.rs | 1 + 14 files changed, 73 insertions(+), 29 deletions(-) create mode 100644 frontend/app_flowy/lib/plugins/board/presentation/card/board_cell.dart diff --git a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart index dcac0a47bb..53038c8d42 100644 --- a/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart +++ b/frontend/app_flowy/lib/plugins/board/application/board_bloc.dart @@ -142,7 +142,7 @@ class BoardBloc extends Bloc { for (final group in groups) { final delegate = GroupControllerDelegateImpl( controller: boardController, - didAddColumnItem: (groupId, row) { + onNewColumnItem: (groupId, row) { add(BoardEvent.didCreateRow(groupId, row)); }, ); @@ -313,11 +313,11 @@ class BoardColumnItem extends AFColumnItem { class GroupControllerDelegateImpl extends GroupControllerDelegate { final AFBoardDataController controller; - final void Function(String, RowPB) didAddColumnItem; + final void Function(String, RowPB) onNewColumnItem; GroupControllerDelegateImpl({ required this.controller, - required this.didAddColumnItem, + required this.onNewColumnItem, }); @override @@ -329,10 +329,8 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate { final item = BoardColumnItem( row: row, fieldId: group.fieldId, - requestFocus: true, ); controller.addColumnItem(group.groupId, item); - didAddColumnItem(group.groupId, row); } } @@ -351,6 +349,17 @@ class GroupControllerDelegateImpl extends GroupControllerDelegate { ), ); } + + @override + void addNewRow(GroupPB group, RowPB row) { + final item = BoardColumnItem( + row: row, + fieldId: group.fieldId, + requestFocus: true, + ); + controller.addColumnItem(group.groupId, item); + onNewColumnItem(group.groupId, row); + } } class BoardEditingRow { diff --git a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart index 812dbc76d3..9407ae360b 100644 --- a/frontend/app_flowy/lib/plugins/board/application/group_controller.dart +++ b/frontend/app_flowy/lib/plugins/board/application/group_controller.dart @@ -9,6 +9,7 @@ abstract class GroupControllerDelegate { void removeRow(GroupPB group, String rowId); void insertRow(GroupPB group, RowPB row, int? index); void updateRow(GroupPB group, RowPB row); + void addNewRow(GroupPB group, RowPB row); } class GroupController { @@ -48,7 +49,11 @@ class GroupController { group.rows.add(insertedRow.row); } - delegate.insertRow(group, insertedRow.row, index); + if (insertedRow.isNew) { + delegate.addNewRow(group, insertedRow.row); + } else { + delegate.insertRow(group, insertedRow.row, index); + } } for (final updatedRow in changeset.updatedRows) { diff --git a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart index d0884e4efc..f6bfd609c3 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/board_page.dart @@ -196,10 +196,8 @@ class _BoardContentState extends State { ); final cellBuilder = BoardCellBuilder(cardController); - final isEditing = context.read().state.editingRow.fold( - () => false, - (editingRow) => editingRow.row.id == rowPB.id, - ); + + final isEditing = context.read().state.editingRow.isSome(); return AppFlowyColumnItemCard( key: ValueKey(columnItem.id), @@ -212,9 +210,6 @@ class _BoardContentState extends State { isEditing: isEditing, cellBuilder: cellBuilder, dataController: cardController, - onEditEditing: (rowId) { - context.read().add(BoardEvent.endEditRow(rowId)); - }, openCard: (context) => _openCard( gridId, fieldCache, diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_cell.dart new file mode 100644 index 0000000000..3c0c0298e9 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_cell.dart @@ -0,0 +1,3 @@ +abstract class FocusableBoardCell { + set becomeFocus(bool isFocus); +} diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart index ed683005f9..20b1a07085 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/board_text_cell.dart @@ -1,16 +1,19 @@ import 'package:app_flowy/plugins/board/application/card/board_text_cell_bloc.dart'; import 'package:app_flowy/plugins/grid/application/cell/cell_service/cell_service.dart'; import 'package:app_flowy/plugins/grid/presentation/widgets/cell/cell_builder.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; class BoardTextCell extends StatefulWidget { final String groupId; + final bool isFocus; + final GridCellControllerBuilder cellControllerBuilder; + const BoardTextCell({ required this.groupId, required this.cellControllerBuilder, + this.isFocus = false, Key? key, }) : super(key: key); @@ -30,6 +33,10 @@ class _BoardTextCellState extends State { _cellBloc = BoardTextCellBloc(cellController: cellController) ..add(const BoardTextCellEvent.initial()); _controller = TextEditingController(text: _cellBloc.state.content); + + if (widget.isFocus) { + focusNode.requestFocus(); + } super.initState(); } diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart index 9f919f2dd1..08331f6021 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/card.dart @@ -10,8 +10,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'card_cell_builder.dart'; import 'card_container.dart'; -typedef OnEndEditing = void Function(String rowId); - class BoardCard extends StatefulWidget { final String gridId; final String groupId; @@ -19,7 +17,6 @@ class BoardCard extends StatefulWidget { final bool isEditing; final CardDataController dataController; final BoardCellBuilder cellBuilder; - final OnEndEditing onEditEditing; final void Function(BuildContext) openCard; const BoardCard({ @@ -29,7 +26,6 @@ class BoardCard extends StatefulWidget { required this.isEditing, required this.dataController, required this.cellBuilder, - required this.onEditEditing, required this.openCard, Key? key, }) : super(key: key); @@ -87,18 +83,27 @@ class _BoardCardState extends State { final List children = []; cells.asMap().forEach( (int index, GridCellIdentifier cellId) { - final child = widget.cellBuilder.buildCell(widget.groupId, cellId); + Widget child = widget.cellBuilder.buildCell( + widget.groupId, + cellId, + widget.isEditing, + ); + if (index != 0) { - children.add(Padding( + child = Padding( + key: cellId.key(), padding: const EdgeInsets.only(left: 4, right: 4, top: 8), child: child, - )); + ); } else { - children.add(Padding( + child = Padding( + key: UniqueKey(), padding: const EdgeInsets.only(left: 4, right: 4), child: child, - )); + ); } + + children.add(child); }, ); return children; diff --git a/frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart b/frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart index 83dbf584e8..b292457193 100644 --- a/frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart +++ b/frontend/app_flowy/lib/plugins/board/presentation/card/card_cell_builder.dart @@ -19,7 +19,11 @@ class BoardCellBuilder { BoardCellBuilder(this.delegate); - Widget buildCell(String groupId, GridCellIdentifier cellId) { + Widget buildCell( + String groupId, + GridCellIdentifier cellId, + bool isEditing, + ) { final cellControllerBuilder = GridCellControllerBuilder( delegate: delegate, cellId: cellId, @@ -62,6 +66,7 @@ class BoardCellBuilder { return BoardTextCell( groupId: groupId, cellControllerBuilder: cellControllerBuilder, + isFocus: isEditing, key: key, ); case FieldType.URL: diff --git a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md index c4c6495533..d8eceeefee 100644 --- a/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md +++ b/frontend/app_flowy/packages/appflowy_board/CHANGELOG.md @@ -1,3 +1,7 @@ +# 0.0.6 +* Support scroll to bottom +* Fix some bugs + # 0.0.5 * Optimize insert card animation * Enable insert card at the end of the column diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart index 63bd9638b4..90556440b4 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_flex/reorder_flex.dart @@ -381,7 +381,6 @@ class ReorderFlexState extends State dragState.currentIndex, ); } - dragState.endDragging(); widget.onDragEnded?.call(); }); diff --git a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart index a3e0f5fb6e..0f63266e51 100644 --- a/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart +++ b/frontend/app_flowy/packages/appflowy_board/lib/src/widgets/reorder_phantom/phantom_controller.dart @@ -2,7 +2,6 @@ import 'package:appflowy_board/appflowy_board.dart'; import 'package:flutter/widgets.dart'; import '../../utils/log.dart'; -import '../board_column/board_column_data.dart'; import '../reorder_flex/drag_state.dart'; import '../reorder_flex/drag_target.dart'; import '../reorder_flex/drag_target_interceptor.dart'; diff --git a/frontend/app_flowy/packages/appflowy_board/pubspec.yaml b/frontend/app_flowy/packages/appflowy_board/pubspec.yaml index 6bb2feabfe..a9adf5007a 100644 --- a/frontend/app_flowy/packages/appflowy_board/pubspec.yaml +++ b/frontend/app_flowy/packages/appflowy_board/pubspec.yaml @@ -1,6 +1,6 @@ name: appflowy_board description: AppFlowy board implementation. -version: 0.0.5 +version: 0.0.6 homepage: https://github.com/AppFlowy-IO/AppFlowy repository: https://github.com/AppFlowy-IO/AppFlowy/tree/main/frontend/app_flowy/packages/appflowy_board diff --git a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs index e691ed1830..6e271a0fb2 100644 --- a/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs +++ b/frontend/rust-lib/flowy-grid/src/entities/block_entities.rs @@ -120,17 +120,28 @@ pub struct InsertedRowPB { #[pb(index = 2, one_of)] pub index: Option, + + #[pb(index = 3)] + pub is_new: bool, } impl InsertedRowPB { pub fn new(row: RowPB) -> Self { - Self { row, index: None } + Self { + row, + index: None, + is_new: false, + } } } impl std::convert::From for InsertedRowPB { fn from(row: RowPB) -> Self { - Self { row, index: None } + Self { + row, + index: None, + is_new: false, + } } } diff --git a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs index 1bc9b9dc42..9619bf52ab 100644 --- a/frontend/rust-lib/flowy-grid/src/services/block_manager.rs +++ b/frontend/rust-lib/flowy-grid/src/services/block_manager.rs @@ -164,6 +164,7 @@ impl GridBlockManager { let insert_row = InsertedRowPB { index: Some(to as i32), row: make_row_from_row_rev(row_rev), + is_new: false, }; let notified_changeset = GridBlockChangesetPB { diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs index 8b89aa72ae..013f59cd42 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_view_editor.rs @@ -98,6 +98,7 @@ impl GridViewRevisionEditor { let inserted_row = InsertedRowPB { row: row_pb.clone(), index: None, + is_new: true, }; let changeset = GroupChangesetPB::insert(group_id.clone(), vec![inserted_row]); self.notify_did_update_group(changeset).await; From 32a1bbb6b949a232bcda0205cae52fee3993b3ce Mon Sep 17 00:00:00 2001 From: appflowy Date: Mon, 29 Aug 2022 18:15:17 +0800 Subject: [PATCH 4/4] chore: optimize cell cache --- .../lib/plugins/grid/application/cell/cell_listener.dart | 6 ++++-- .../grid/application/cell/cell_service/cell_cache.dart | 9 ++++++++- .../application/cell/cell_service/context_builder.dart | 2 +- .../lib/plugins/grid/application/row/row_cache.dart | 3 ++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart index 5da5fce86d..4805ad8b7a 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_listener.dart @@ -11,13 +11,15 @@ typedef UpdateFieldNotifiedValue = Either; class CellListener { final String rowId; final String fieldId; - PublishNotifier? _updateCellNotifier = PublishNotifier(); + PublishNotifier? _updateCellNotifier = + PublishNotifier(); GridNotificationListener? _listener; CellListener({required this.rowId, required this.fieldId}); void start({required void Function(UpdateFieldNotifiedValue) onCellChanged}) { _updateCellNotifier?.addPublishListener(onCellChanged); - _listener = GridNotificationListener(objectId: "$rowId:$fieldId", handler: _handler); + _listener = GridNotificationListener( + objectId: "$rowId:$fieldId", handler: _handler); } void _handler(GridNotification ty, Either result) { diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_cache.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_cache.dart index 1f14c7c54a..3d816b21d1 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_cache.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/cell_cache.dart @@ -33,10 +33,17 @@ class GridCellCache { required this.gridId, }); - void remove(String fieldId) { + void removeCellWithFieldId(String fieldId) { _cellDataByFieldId.remove(fieldId); } + void remove(GridCellCacheKey key) { + var map = _cellDataByFieldId[key.fieldId]; + if (map != null) { + map.remove(key.rowId); + } + } + void insert(GridCellCacheKey key, T value) { var map = _cellDataByFieldId[key.fieldId]; if (map == null) { diff --git a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/context_builder.dart b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/context_builder.dart index 8ab486a48c..d716133d05 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/context_builder.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/cell/cell_service/context_builder.dart @@ -191,7 +191,7 @@ class IGridCellController extends Equatable { _cellListener?.start(onCellChanged: (result) { result.fold( (_) { - _cellsCache.remove(fieldId); + _cellsCache.remove(_cacheKey); _loadData(); }, (err) => Log.error(err), diff --git a/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart b/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart index 68c8b6f519..d6cd387e74 100644 --- a/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart +++ b/frontend/app_flowy/lib/plugins/grid/application/row/row_cache.dart @@ -52,7 +52,8 @@ class GridRowCache { // notifier.onRowFieldsChanged(() => _rowChangeReasonNotifier .receive(const RowsChangedReason.fieldDidChange())); - notifier.onRowFieldChanged((field) => _cellCache.remove(field.id)); + notifier.onRowFieldChanged( + (field) => _cellCache.removeCellWithFieldId(field.id)); _rowInfos = block.rows.map((rowPB) => buildGridRow(rowPB)).toList(); }