소스 검색

chore: repalce sliver header with single scroll view

appflowy 3 년 전
부모
커밋
6dbb708991

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

@@ -1,3 +1,4 @@
+import 'package:app_flowy/workspace/application/grid/field/field_service.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
@@ -7,13 +8,14 @@ import 'grid_service.dart';
 part 'grid_header_bloc.freezed.dart';
 
 class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
-  // final FieldService _fieldService;
+  final FieldService _fieldService;
   final GridFieldCache fieldCache;
 
   GridHeaderBloc({
     required String gridId,
     required this.fieldCache,
-  }) : super(GridHeaderState.initial(fieldCache.clonedFields)) {
+  })  : _fieldService = FieldService(gridId: gridId),
+        super(GridHeaderState.initial(fieldCache.clonedFields)) {
     on<GridHeaderEvent>(
       (event, emit) async {
         await event.map(
@@ -23,6 +25,7 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
           didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
             emit(state.copyWith(fields: value.fields));
           },
+          moveField: (_MoveField value) {},
         );
       },
     );
@@ -46,6 +49,7 @@ class GridHeaderBloc extends Bloc<GridHeaderEvent, GridHeaderState> {
 class GridHeaderEvent with _$GridHeaderEvent {
   const factory GridHeaderEvent.initial() = _InitialHeader;
   const factory GridHeaderEvent.didReceiveFieldUpdate(List<Field> fields) = _DidReceiveFieldUpdate;
+  const factory GridHeaderEvent.moveField(int fromIndex, int toIndex) = _MoveField;
 }
 
 @freezed

+ 17 - 10
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/controller/grid_scroll.dart

@@ -1,21 +1,28 @@
 import 'package:flutter/material.dart';
+import 'package:linked_scroll_controller/linked_scroll_controller.dart';
 
 class GridScrollController {
-  final ScrollController _verticalController = ScrollController();
-  final ScrollController _horizontalController = ScrollController();
+  final LinkedScrollControllerGroup _scrollGroupContorller;
+  final ScrollController verticalController;
+  final ScrollController horizontalController;
 
-  ScrollController get verticalController => _verticalController;
-  ScrollController get horizontalController => _horizontalController;
+  final List<ScrollController> _linkHorizontalControllers = [];
 
-  GridScrollController();
+  GridScrollController({required LinkedScrollControllerGroup scrollGroupContorller})
+      : _scrollGroupContorller = scrollGroupContorller,
+        verticalController = ScrollController(),
+        horizontalController = scrollGroupContorller.addAndGet();
 
-  // final SelectionChangeCallback? onSelectionChanged;
-
-  // final ShouldApplySelection? shouldApplySelection;
-
-  // final ScrollCallback? onScroll;
+  ScrollController linkHorizontalController() {
+    final controller = _scrollGroupContorller.addAndGet();
+    _linkHorizontalControllers.add(controller);
+    return controller;
+  }
 
   void dispose() {
+    for (final controller in _linkHorizontalControllers) {
+      controller.dispose();
+    }
     verticalController.dispose();
     horizontalController.dispose();
   }

+ 26 - 17
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart

@@ -9,6 +9,7 @@ import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
 import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field;
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:flutter/material.dart';
+import 'package:linked_scroll_controller/linked_scroll_controller.dart';
 import 'controller/grid_scroll.dart';
 import 'layout/layout.dart';
 import 'layout/sizes.dart';
@@ -73,17 +74,23 @@ class FlowyGrid extends StatefulWidget {
 }
 
 class _FlowyGridState extends State<FlowyGrid> {
-  final _scrollController = GridScrollController();
+  final _scrollController = GridScrollController(scrollGroupContorller: LinkedScrollControllerGroup());
+
+  @override
+  void dispose() {
+    _scrollController.dispose();
+    super.dispose();
+  }
 
   @override
   Widget build(BuildContext context) {
     return BlocBuilder<GridBloc, GridState>(
       buildWhen: (previous, current) => previous.fields.length != current.fields.length,
       builder: (context, state) {
+        final contentWidth = GridLayout.headerWidth(state.fields);
         final child = _wrapScrollView(
-          state.fields,
+          contentWidth,
           [
-            _GridHeader(gridId: state.gridId, fields: state.fields),
             const _GridRows(),
             const _GridFooter(),
           ],
@@ -91,6 +98,7 @@ class _FlowyGridState extends State<FlowyGrid> {
 
         return Column(children: [
           const _GridToolbarAdaptor(),
+          _gridHeader(context, state.gridId, contentWidth),
           Flexible(child: child),
         ]);
       },
@@ -98,7 +106,7 @@ class _FlowyGridState extends State<FlowyGrid> {
   }
 
   Widget _wrapScrollView(
-    List<Field> fields,
+    double contentWidth,
     List<Widget> slivers,
   ) {
     final verticalScrollView = ScrollConfiguration(
@@ -111,7 +119,7 @@ class _FlowyGridState extends State<FlowyGrid> {
     );
 
     final sizedVerticalScrollView = SizedBox(
-      width: GridLayout.headerWidth(fields),
+      width: contentWidth,
       child: verticalScrollView,
     );
 
@@ -128,6 +136,19 @@ class _FlowyGridState extends State<FlowyGrid> {
       child: horizontalScrollView,
     );
   }
+
+  Widget _gridHeader(BuildContext context, String gridId, double contentWidth) {
+    final fieldCache = context.read<GridBloc>().fieldCache;
+
+    return SizedBox(
+      width: contentWidth,
+      child: GridHeaderSliverAdaptor(
+        gridId: gridId,
+        fieldCache: fieldCache,
+        anchorScrollController: _scrollController.linkHorizontalController(),
+      ),
+    );
+  }
 }
 
 class _GridToolbarAdaptor extends StatelessWidget {
@@ -149,18 +170,6 @@ class _GridToolbarAdaptor extends StatelessWidget {
   }
 }
 
-class _GridHeader extends StatelessWidget {
-  final String gridId;
-  final List<Field> fields;
-  const _GridHeader({Key? key, required this.gridId, required this.fields}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    final fieldCache = context.read<GridBloc>().fieldCache;
-    return GridHeaderSliverAdaptor(gridId: gridId, fieldCache: fieldCache);
-  }
-}
-
 class _GridRows extends StatefulWidget {
   const _GridRows({Key? key}) : super(key: key);
 

+ 36 - 24
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart

@@ -13,25 +13,41 @@ import 'package:reorderables/reorderables.dart';
 import 'field_editor.dart';
 import 'field_cell.dart';
 
-class GridHeaderSliverAdaptor extends StatelessWidget {
+class GridHeaderSliverAdaptor extends StatefulWidget {
   final String gridId;
   final GridFieldCache fieldCache;
+  final ScrollController anchorScrollController;
+  const GridHeaderSliverAdaptor({
+    required this.gridId,
+    required this.fieldCache,
+    required this.anchorScrollController,
+    Key? key,
+  }) : super(key: key);
 
-  const GridHeaderSliverAdaptor({required this.gridId, required this.fieldCache, Key? key}) : super(key: key);
+  @override
+  State<GridHeaderSliverAdaptor> createState() => _GridHeaderSliverAdaptorState();
+}
 
+class _GridHeaderSliverAdaptorState extends State<GridHeaderSliverAdaptor> {
   @override
   Widget build(BuildContext context) {
     return BlocProvider(
       create: (context) =>
-          getIt<GridHeaderBloc>(param1: gridId, param2: fieldCache)..add(const GridHeaderEvent.initial()),
+          getIt<GridHeaderBloc>(param1: widget.gridId, param2: widget.fieldCache)..add(const GridHeaderEvent.initial()),
       child: BlocBuilder<GridHeaderBloc, GridHeaderState>(
         buildWhen: (previous, current) => previous.fields.length != current.fields.length,
         builder: (context, state) {
-          return SliverPersistentHeader(
-            delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields),
-            floating: true,
-            pinned: true,
+          return SingleChildScrollView(
+            scrollDirection: Axis.horizontal,
+            controller: widget.anchorScrollController,
+            child: SizedBox(height: GridSize.headerHeight, child: _GridHeader(gridId: widget.gridId)),
           );
+
+          // return SliverPersistentHeader(
+          //   delegate: SliverHeaderDelegateImplementation(gridId: gridId, fields: state.fields),
+          //   floating: true,
+          //   pinned: true,
+          // );
         },
       ),
     );
@@ -46,7 +62,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate
 
   @override
   Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
-    return _GridHeader(gridId: gridId, fields: fields);
+    return _GridHeader(gridId: gridId);
   }
 
   @override
@@ -66,13 +82,7 @@ class SliverHeaderDelegateImplementation extends SliverPersistentHeaderDelegate
 
 class _GridHeader extends StatefulWidget {
   final String gridId;
-  final List<Field> fields;
-
-  const _GridHeader({
-    Key? key,
-    required this.gridId,
-    required this.fields,
-  }) : super(key: key);
+  const _GridHeader({Key? key, required this.gridId}) : super(key: key);
 
   @override
   State<_GridHeader> createState() => _GridHeaderState();
@@ -93,15 +103,17 @@ class _GridHeaderState extends State<_GridHeader> {
 
         return Container(
           color: theme.surface,
-          child: ReorderableRow(
-            crossAxisAlignment: CrossAxisAlignment.stretch,
-            scrollController: ScrollController(),
-            header: const _CellLeading(),
-            footer: _CellTrailing(gridId: widget.gridId),
-            onReorder: (int oldIndex, int newIndex) {
-              Log.info("from $oldIndex to $newIndex");
-            },
-            children: cells,
+          child: RepaintBoundary(
+            child: ReorderableRow(
+              crossAxisAlignment: CrossAxisAlignment.stretch,
+              scrollController: ScrollController(),
+              header: const _CellLeading(),
+              footer: _CellTrailing(gridId: widget.gridId),
+              onReorder: (int oldIndex, int newIndex) {
+                Log.info("from $oldIndex to $newIndex");
+              },
+              children: cells,
+            ),
           ),
         );
       },

+ 7 - 0
frontend/app_flowy/pubspec.lock

@@ -653,6 +653,13 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "4.4.0"
+  linked_scroll_controller:
+    dependency: "direct main"
+    description:
+      name: linked_scroll_controller
+      url: "https://pub.dartlang.org"
+    source: hosted
+    version: "0.2.0"
   lint:
     dependency: transitive
     description:

+ 1 - 0
frontend/app_flowy/pubspec.yaml

@@ -75,6 +75,7 @@ dependencies:
   fluttertoast: ^8.0.8
   table_calendar: ^3.0.5
   reorderables:
+  linked_scroll_controller: ^0.2.0
 
 dev_dependencies:
   flutter_lints: ^1.0.0