chore: fixed grid toolbar

This commit is contained in:
appflowy 2022-04-13 10:47:07 +08:00
parent a707410548
commit b0e07c952e
6 changed files with 135 additions and 119 deletions

View file

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

View file

@ -20,6 +20,15 @@ class FieldService {
return GridEventSwitchToField(payload).send(); 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({ Future<Either<Unit, FlowyError>> updateField({
required String fieldId, required String fieldId,
String? name, String? name,

View file

@ -40,7 +40,7 @@ class _GridPageState extends State<GridPage> {
return state.loadingState.map( return state.loadingState.map(
loading: (_) => const Center(child: CircularProgressIndicator.adaptive()), loading: (_) => const Center(child: CircularProgressIndicator.adaptive()),
finish: (result) => result.successOrFail.fold( finish: (result) => result.successOrFail.fold(
(_) => const FlowyGrid(), (_) => FlowyGrid(),
(err) => FlowyErrorPage(err.toString()), (err) => FlowyErrorPage(err.toString()),
), ),
); );
@ -65,64 +65,61 @@ class _GridPageState extends State<GridPage> {
} }
} }
class FlowyGrid extends StatefulWidget { class FlowyGrid extends StatelessWidget {
const FlowyGrid({Key? key}) : super(key: key);
@override
_FlowyGridState createState() => _FlowyGridState();
}
class _FlowyGridState extends State<FlowyGrid> {
final _scrollController = GridScrollController(); final _scrollController = GridScrollController();
final _key = GlobalKey<SliverAnimatedListState>(); FlowyGrid({Key? key}) : super(key: key);
@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) {
if (state.fields.isEmpty) { final child = _wrapScrollView(
return const Center(child: CircularProgressIndicator.adaptive()); state.fields,
} [
_GridHeader(gridId: state.gridId, fields: List.from(state.fields)),
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(), _GridRows(),
const SliverToBoxAdapter(child: GridFooter()), 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( return ScrollbarListStack(
axis: Axis.vertical, axis: Axis.vertical,
controller: _scrollController.verticalController, controller: _scrollController.verticalController,
barSize: GridSize.scrollBarSize, barSize: GridSize.scrollBarSize,
child: StyledSingleChildScrollView( child: horizontalScrollView,
controller: _scrollController.horizontalController,
axis: Axis.horizontal,
child: child,
),
); );
} }
} }
@ -140,14 +137,27 @@ class _GridToolbarAdaptor extends StatelessWidget {
); );
}, },
builder: (context, toolbarContext) { builder: (context, toolbarContext) {
return SliverToBoxAdapter( return GridToolbar(toolbarContext: toolbarContext);
child: 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 { class _GridRows extends StatelessWidget {
final _key = GlobalKey<SliverAnimatedListState>(); final _key = GlobalKey<SliverAnimatedListState>();
_GridRows({Key? key}) : super(key: key); _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()),
],
),
),
),
),
);
}
}

View file

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

View file

@ -7,28 +7,8 @@ import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class GridFooter extends StatelessWidget { class GridAddRowButton extends StatelessWidget {
const GridFooter({Key? key}) : super(key: key); const GridAddRowButton({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);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View file

@ -12,30 +12,32 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'field_editor.dart'; import 'field_editor.dart';
import 'field_cell.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 String gridId;
final List<Field> fields; final List<Field> fields;
_GridHeaderDelegate({required this.gridId, required this.fields}); GridHeaderSliverAdaptor({required this.gridId, required this.fields});
@override @override
Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) { 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 @override
@ -46,40 +48,13 @@ class _GridHeaderDelegate extends SliverPersistentHeaderDelegate {
@override @override
bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) { bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
if (oldDelegate is _GridHeaderDelegate) { if (oldDelegate is GridHeaderSliverAdaptor) {
return fields.length != oldDelegate.fields.length; return fields.length != oldDelegate.fields.length;
} }
return true; 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 { class _CellLeading extends StatelessWidget {
const _CellLeading({Key? key}) : super(key: key); const _CellLeading({Key? key}) : super(key: key);