Browse Source

chore: fixed grid toolbar

appflowy 3 năm trước cách đây
mục cha
commit
b0e07c952e

+ 9 - 2
frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart

@@ -2,7 +2,7 @@ import 'package:app_flowy/workspace/application/grid/cell_bloc/cell_listener.dar
 import 'package:app_flowy/workspace/application/grid/field/field_listener.dart';
 import 'package:app_flowy/workspace/application/grid/row/row_service.dart';
 import 'package:flowy_sdk/log.dart';
-import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell;
+import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Cell, Field;
 import 'package:flutter_bloc/flutter_bloc.dart';
 import 'package:freezed_annotation/freezed_annotation.dart';
 import 'dart:async';
@@ -35,6 +35,10 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
               content: value.cell.content,
             ));
           },
+          didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) {
+            emit(state.copyWith(field: value.field));
+            _loadCellData();
+          },
         );
       },
     );
@@ -58,7 +62,7 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
 
     _fieldListener.updateFieldNotifier.addPublishListener((result) {
       result.fold(
-        (field) => _loadCellData(),
+        (field) => add(DateCellEvent.didReceiveFieldUpdate(field)),
         (err) => Log.error(err),
       );
     });
@@ -97,6 +101,7 @@ class DateCellEvent with _$DateCellEvent {
   const factory DateCellEvent.initial() = _InitialCell;
   const factory DateCellEvent.selectDay(DateTime day) = _SelectDay;
   const factory DateCellEvent.didReceiveCellUpdate(Cell cell) = _DidReceiveCellUpdate;
+  const factory DateCellEvent.didReceiveFieldUpdate(Field field) = _DidReceiveFieldUpdate;
 }
 
 @freezed
@@ -104,11 +109,13 @@ class DateCellState with _$DateCellState {
   const factory DateCellState({
     required CellData cellData,
     required String content,
+    required Field field,
     DateTime? selectedDay,
   }) = _DateCellState;
 
   factory DateCellState.initial(CellData cellData) => DateCellState(
         cellData: cellData,
+        field: cellData.field,
         content: cellData.cell?.content ?? "",
       );
 }

+ 9 - 0
frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart

@@ -20,6 +20,15 @@ class FieldService {
     return GridEventSwitchToField(payload).send();
   }
 
+  Future<Either<EditFieldContext, FlowyError>> getEditFieldContext(String fieldId, FieldType fieldType) {
+    final payload = GetEditFieldContextPayload.create()
+      ..gridId = gridId
+      ..fieldId = fieldId
+      ..fieldType = fieldType;
+
+    return GridEventGetEditFieldContext(payload).send();
+  }
+
   Future<Either<Unit, FlowyError>> updateField({
     required String fieldId,
     String? name,

+ 80 - 45
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart

@@ -40,7 +40,7 @@ class _GridPageState extends State<GridPage> {
           return state.loadingState.map(
             loading: (_) => const Center(child: CircularProgressIndicator.adaptive()),
             finish: (result) => result.successOrFail.fold(
-              (_) => const FlowyGrid(),
+              (_) => FlowyGrid(),
               (err) => FlowyErrorPage(err.toString()),
             ),
           );
@@ -65,64 +65,61 @@ class _GridPageState extends State<GridPage> {
   }
 }
 
-class FlowyGrid extends StatefulWidget {
-  const FlowyGrid({Key? key}) : super(key: key);
-
-  @override
-  _FlowyGridState createState() => _FlowyGridState();
-}
-
-class _FlowyGridState extends State<FlowyGrid> {
+class FlowyGrid extends StatelessWidget {
   final _scrollController = GridScrollController();
-  final _key = GlobalKey<SliverAnimatedListState>();
-
-  @override
-  void dispose() {
-    _scrollController.dispose();
-    super.dispose();
-  }
+  FlowyGrid({Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {
     return BlocBuilder<GridBloc, GridState>(
       buildWhen: (previous, current) => previous.fields.length != current.fields.length,
       builder: (context, state) {
-        if (state.fields.isEmpty) {
-          return const Center(child: CircularProgressIndicator.adaptive());
-        }
-
-        final child = SizedBox(
-          width: GridLayout.headerWidth(state.fields),
-          child: ScrollConfiguration(
-            behavior: const ScrollBehavior().copyWith(scrollbars: false),
-            child: CustomScrollView(
-              physics: StyledScrollPhysics(),
-              controller: _scrollController.verticalController,
-              slivers: [
-                const _GridToolbarAdaptor(),
-                GridHeader(gridId: state.gridId, fields: List.from(state.fields)),
-                _GridRows(),
-                const SliverToBoxAdapter(child: GridFooter()),
-              ],
-            ),
-          ),
+        final child = _wrapScrollView(
+          state.fields,
+          [
+            _GridHeader(gridId: state.gridId, fields: List.from(state.fields)),
+            _GridRows(),
+            const _GridFooter(),
+          ],
         );
 
-        return _wrapScrollbar(child);
+        return Column(children: [
+          const _GridToolbarAdaptor(),
+          Flexible(child: child),
+        ]);
       },
     );
   }
 
-  Widget _wrapScrollbar(Widget child) {
+  Widget _wrapScrollView(
+    List<Field> fields,
+    List<Widget> slivers,
+  ) {
+    final verticalScrollView = ScrollConfiguration(
+      behavior: const ScrollBehavior().copyWith(scrollbars: false),
+      child: CustomScrollView(
+        physics: StyledScrollPhysics(),
+        controller: _scrollController.verticalController,
+        slivers: slivers,
+      ),
+    );
+
+    final sizedVerticalScrollView = SizedBox(
+      width: GridLayout.headerWidth(fields),
+      child: verticalScrollView,
+    );
+
+    final horizontalScrollView = StyledSingleChildScrollView(
+      controller: _scrollController.horizontalController,
+      axis: Axis.horizontal,
+      child: sizedVerticalScrollView,
+    );
+
     return ScrollbarListStack(
       axis: Axis.vertical,
       controller: _scrollController.verticalController,
       barSize: GridSize.scrollBarSize,
-      child: StyledSingleChildScrollView(
-        controller: _scrollController.horizontalController,
-        axis: Axis.horizontal,
-        child: child,
-      ),
+      child: horizontalScrollView,
     );
   }
 }
@@ -140,14 +137,27 @@ class _GridToolbarAdaptor extends StatelessWidget {
         );
       },
       builder: (context, toolbarContext) {
-        return SliverToBoxAdapter(
-          child: GridToolbar(toolbarContext: toolbarContext),
-        );
+        return GridToolbar(toolbarContext: toolbarContext);
       },
     );
   }
 }
 
+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) {
+    return SliverPersistentHeader(
+      delegate: GridHeaderSliverAdaptor(gridId: gridId, fields: List.from(fields)),
+      floating: true,
+      pinned: true,
+    );
+  }
+}
+
 class _GridRows extends StatelessWidget {
   final _key = GlobalKey<SliverAnimatedListState>();
   _GridRows({Key? key}) : super(key: key);
@@ -191,3 +201,28 @@ class _GridRows extends StatelessWidget {
     );
   }
 }
+
+class _GridFooter extends StatelessWidget {
+  const _GridFooter({Key? key}) : super(key: key);
+
+  @override
+  Widget build(BuildContext context) {
+    return SliverPadding(
+      padding: const EdgeInsets.only(bottom: 200),
+      sliver: SliverToBoxAdapter(
+        child: SizedBox(
+          height: GridSize.footerHeight,
+          child: Padding(
+            padding: GridSize.headerContentInsets,
+            child: Row(
+              children: [
+                SizedBox(width: GridSize.leadingHeaderPadding),
+                const SizedBox(width: 120, child: GridAddRowButton()),
+              ],
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}

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

@@ -74,7 +74,13 @@ final kLastDay = DateTime(kToday.year, kToday.month + 3, kToday.day);
 class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate {
   final void Function(DateTime) onSelected;
   final VoidCallback onDismissed;
-  const _CellCalendar({required this.onSelected, required this.onDismissed, Key? key}) : super(key: key);
+  final bool includeTime;
+  const _CellCalendar({
+    required this.onSelected,
+    required this.onDismissed,
+    required this.includeTime,
+    Key? key,
+  }) : super(key: key);
 
   @override
   State<_CellCalendar> createState() => _CellCalendarState();
@@ -86,7 +92,11 @@ class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate {
   }) async {
     _CellCalendar.remove(context);
 
-    final calendar = _CellCalendar(onSelected: onSelected, onDismissed: onDismissed);
+    final calendar = _CellCalendar(
+      onSelected: onSelected,
+      onDismissed: onDismissed,
+      includeTime: false,
+    );
     // const size = Size(460, 400);
     // final window = await getWindowInfo();
     // FlowyOverlay.of(context).insertWithRect(
@@ -105,11 +115,11 @@ class _CellCalendar extends StatefulWidget with FlowyOverlayDelegate {
     FlowyOverlay.of(context).insertWithAnchor(
       widget: OverlayContainer(
         child: calendar,
-        constraints: BoxConstraints.loose(const Size(300, 320)),
+        constraints: BoxConstraints.tight(const Size(320, 320)),
       ),
       identifier: _CellCalendar.identifier(),
       anchorContext: context,
-      anchorDirection: AnchorDirection.bottomWithCenterAligned,
+      anchorDirection: AnchorDirection.leftWithCenterAligned,
       style: FlowyOverlayStyle(blur: false),
       delegate: calendar,
     );

+ 2 - 22
frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart

@@ -7,28 +7,8 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_bloc/flutter_bloc.dart';
 
-class GridFooter extends StatelessWidget {
-  const GridFooter({Key? key}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    return SizedBox(
-      height: GridSize.footerHeight,
-      child: Padding(
-        padding: GridSize.headerContentInsets,
-        child: Row(
-          children: [
-            SizedBox(width: GridSize.leadingHeaderPadding),
-            const SizedBox(width: 120, child: _AddRowButton()),
-          ],
-        ),
-      ),
-    );
-  }
-}
-
-class _AddRowButton extends StatelessWidget {
-  const _AddRowButton({Key? key}) : super(key: key);
+class GridAddRowButton extends StatelessWidget {
+  const GridAddRowButton({Key? key}) : super(key: key);
 
   @override
   Widget build(BuildContext context) {

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

@@ -12,30 +12,32 @@ import 'package:flutter_bloc/flutter_bloc.dart';
 import 'field_editor.dart';
 import 'field_cell.dart';
 
-class GridHeader extends StatelessWidget {
+class GridHeaderSliverAdaptor extends SliverPersistentHeaderDelegate {
   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) {
-    return SliverPersistentHeader(
-      delegate: _GridHeaderDelegate(gridId: gridId, fields: List.from(fields)),
-      floating: true,
-      pinned: true,
-    );
-  }
-}
-
-class _GridHeaderDelegate extends SliverPersistentHeaderDelegate {
-  final String gridId;
-  final List<Field> fields;
-
-  _GridHeaderDelegate({required this.gridId, required this.fields});
+  GridHeaderSliverAdaptor({required this.gridId, required this.fields});
 
   @override
   Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
-    return _GridHeaderWidget(gridId: gridId, fields: fields, key: ObjectKey(fields));
+    final cells = fields.map(
+      (field) => GridFieldCell(
+        GridFieldCellContext(gridId: gridId, field: field),
+      ),
+    );
+
+    return Container(
+      color: Colors.white,
+      child: Row(
+        crossAxisAlignment: CrossAxisAlignment.stretch,
+        children: [
+          const _CellLeading(),
+          ...cells,
+          _CellTrailing(gridId: gridId),
+        ],
+        key: ObjectKey(fields),
+      ),
+    );
   }
 
   @override
@@ -46,40 +48,13 @@ class _GridHeaderDelegate extends SliverPersistentHeaderDelegate {
 
   @override
   bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
-    if (oldDelegate is _GridHeaderDelegate) {
+    if (oldDelegate is GridHeaderSliverAdaptor) {
       return fields.length != oldDelegate.fields.length;
     }
     return true;
   }
 }
 
-class _GridHeaderWidget extends StatelessWidget {
-  final String gridId;
-  final List<Field> fields;
-
-  const _GridHeaderWidget({required this.gridId, required this.fields, Key? key}) : super(key: key);
-
-  @override
-  Widget build(BuildContext context) {
-    final cells = fields.map(
-      (field) => GridFieldCell(
-        GridFieldCellContext(gridId: gridId, field: field),
-      ),
-    );
-
-    return Row(
-      crossAxisAlignment: CrossAxisAlignment.stretch,
-      children: [
-        const _CellLeading(),
-        ...cells,
-        _CellTrailing(gridId: gridId),
-      ],
-    );
-
-    // return Container(height: GridSize.headerHeight, color: theme.surface, child: row);
-  }
-}
-
 class _CellLeading extends StatelessWidget {
   const _CellLeading({Key? key}) : super(key: key);