chore: repalce sliver header with single scroll view

This commit is contained in:
appflowy 2022-04-15 15:41:55 +08:00
parent d71e0de8c3
commit 6dbb708991
6 changed files with 93 additions and 53 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -653,6 +653,13 @@ packages:
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "4.4.0" 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: lint:
dependency: transitive dependency: transitive
description: description:

View File

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