diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart index 8d46b7e659..ff8d7d012e 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell_bloc/date_cell_bloc.dart +++ b/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 { content: value.cell.content, )); }, + didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + emit(state.copyWith(field: value.field)); + _loadCellData(); + }, ); }, ); @@ -58,7 +62,7 @@ class DateCellBloc extends Bloc { _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 ?? "", ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart index 743a441c7d..e1bed697c8 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_service.dart @@ -20,6 +20,15 @@ class FieldService { return GridEventSwitchToField(payload).send(); } + Future> getEditFieldContext(String fieldId, FieldType fieldType) { + final payload = GetEditFieldContextPayload.create() + ..gridId = gridId + ..fieldId = fieldId + ..fieldType = fieldType; + + return GridEventGetEditFieldContext(payload).send(); + } + Future> updateField({ required String fieldId, String? name, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart index 40b282e717..804ffff685 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/grid_page.dart @@ -40,7 +40,7 @@ class _GridPageState extends State { 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 { } } -class FlowyGrid extends StatefulWidget { - const FlowyGrid({Key? key}) : super(key: key); - - @override - _FlowyGridState createState() => _FlowyGridState(); -} - -class _FlowyGridState extends State { +class FlowyGrid extends StatelessWidget { final _scrollController = GridScrollController(); - final _key = GlobalKey(); - - @override - void dispose() { - _scrollController.dispose(); - super.dispose(); - } + FlowyGrid({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( 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 fields, + List 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 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(); _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()), + ], + ), + ), + ), + ), + ); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart index c5100df969..b913a09e4e 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/date_cell.dart +++ b/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, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart index 35d9ee1378..a99e87f5fa 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/footer/grid_footer.dart +++ b/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) { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart index 44730f703d..c387ecd4e2 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header.dart +++ b/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 { - final String gridId; - final List 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 { +class GridHeaderSliverAdaptor extends SliverPersistentHeaderDelegate { final String gridId; final List 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 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);