diff --git a/frontend/app_flowy/lib/startup/deps_resolver.dart b/frontend/app_flowy/lib/startup/deps_resolver.dart index 1bb46f913f..9020101083 100644 --- a/frontend/app_flowy/lib/startup/deps_resolver.dart +++ b/frontend/app_flowy/lib/startup/deps_resolver.dart @@ -165,8 +165,8 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( - (data, _) => GridFieldBloc( + getIt.registerFactoryParam( + (data, _) => FieldActionSheetBloc( field: data.field, service: FieldService(gridId: data.gridId), ), @@ -214,8 +214,8 @@ void _resolveGridDeps(GetIt getIt) { ), ); - getIt.registerFactoryParam( - (context, _) => FieldSwitchBloc(context), + getIt.registerFactoryParam( + (context, _) => FieldSwitcherBloc(context), ); getIt.registerFactoryParam( @@ -233,4 +233,8 @@ void _resolveGridDeps(GetIt getIt) { getIt.registerFactoryParam( (typeOption, _) => NumberTypeOptionBloc(typeOption: typeOption), ); + + getIt.registerFactoryParam>( + (gridId, fields) => GridPropertyBloc(gridId: gridId, fields: fields), + ); } diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_field_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/action_sheet_bloc.dart similarity index 66% rename from frontend/app_flowy/lib/workspace/application/grid/field/grid_field_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/field/action_sheet_bloc.dart index f3ec3b4cbe..5e8cb5a932 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_field_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/action_sheet_bloc.dart @@ -5,14 +5,14 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'field_service.dart'; -part 'grid_field_bloc.freezed.dart'; +part 'action_sheet_bloc.freezed.dart'; -class GridFieldBloc extends Bloc { +class FieldActionSheetBloc extends Bloc { final FieldService service; - GridFieldBloc({required Field field, required this.service}) - : super(GridFieldState.initial(EditFieldContext.create()..gridField = field)) { - on( + FieldActionSheetBloc({required Field field, required this.service}) + : super(ActionSheetState.initial(EditFieldContext.create()..gridField = field)) { + on( (event, emit) async { await event.map( updateFieldName: (_UpdateFieldName value) async { @@ -56,23 +56,23 @@ class GridFieldBloc extends Bloc { } @freezed -class GridFieldEvent with _$GridFieldEvent { - const factory GridFieldEvent.updateFieldName(String name) = _UpdateFieldName; - const factory GridFieldEvent.hideField() = _HideField; - const factory GridFieldEvent.duplicateField() = _DuplicateField; - const factory GridFieldEvent.deleteField() = _DeleteField; - const factory GridFieldEvent.saveField() = _SaveField; +class ActionSheetEvent with _$ActionSheetEvent { + const factory ActionSheetEvent.updateFieldName(String name) = _UpdateFieldName; + const factory ActionSheetEvent.hideField() = _HideField; + const factory ActionSheetEvent.duplicateField() = _DuplicateField; + const factory ActionSheetEvent.deleteField() = _DeleteField; + const factory ActionSheetEvent.saveField() = _SaveField; } @freezed -class GridFieldState with _$GridFieldState { - const factory GridFieldState({ +class ActionSheetState with _$ActionSheetState { + const factory ActionSheetState({ required EditFieldContext editContext, required String errorText, required String fieldName, - }) = _GridFieldState; + }) = _ActionSheetState; - factory GridFieldState.initial(EditFieldContext editContext) => GridFieldState( + factory ActionSheetState.initial(EditFieldContext editContext) => ActionSheetState( editContext: editContext, errorText: '', fieldName: editContext.gridField.name, diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart similarity index 98% rename from frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart index 749cde3420..4556e17d38 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/edit_field_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_editor_bloc.dart @@ -7,7 +7,7 @@ import 'dart:async'; import 'field_service.dart'; import 'package:dartz/dartz.dart'; -part 'edit_field_bloc.freezed.dart'; +part 'field_editor_bloc.freezed.dart'; class FieldEditorBloc extends Bloc { final FieldService service; 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 5bb80a0119..d47dab99d0 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 @@ -98,11 +98,11 @@ class FieldService { } } -class GridFieldData extends Equatable { +class GridFieldCellContext extends Equatable { final String gridId; final Field field; - const GridFieldData({ + const GridFieldCellContext({ required this.gridId, required this.field, }); @@ -132,7 +132,7 @@ class NewFieldContextLoader extends FieldContextLoader { } class FieldContextLoaderAdaptor extends FieldContextLoader { - final GridFieldData data; + final GridFieldCellContext data; FieldContextLoaderAdaptor(this.data); diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/switch_field_type_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart similarity index 90% rename from frontend/app_flowy/lib/workspace/application/grid/field/switch_field_type_bloc.dart rename to frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart index edb0732ddf..802b39d95a 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/switch_field_type_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/field_switch_bloc.dart @@ -7,10 +7,10 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'dart:async'; import 'field_service.dart'; -part 'switch_field_type_bloc.freezed.dart'; +part 'field_switch_bloc.freezed.dart'; -class FieldSwitchBloc extends Bloc { - FieldSwitchBloc(SwitchFieldContext editContext) : super(FieldSwitchState.initial(editContext)) { +class FieldSwitcherBloc extends Bloc { + FieldSwitcherBloc(SwitchFieldContext editContext) : super(FieldSwitchState.initial(editContext)) { on( (event, emit) async { await event.map( diff --git a/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart index d249e9b4c1..ae10505bc7 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/field/grid_header_bloc.dart @@ -27,6 +27,7 @@ class GridHeaderBloc extends Bloc { createField: (_CreateField value) {}, insertField: (_InsertField value) {}, didReceiveFieldUpdate: (_DidReceiveFieldUpdate value) { + value.fields.retainWhere((field) => field.visibility); emit(state.copyWith(fields: value.fields)); }, ); @@ -64,5 +65,8 @@ class GridHeaderEvent with _$GridHeaderEvent { class GridHeaderState with _$GridHeaderState { const factory GridHeaderState({required List fields}) = _GridHeaderState; - factory GridHeaderState.initial(List fields) => GridHeaderState(fields: fields); + factory GridHeaderState.initial(List fields) { + fields.retainWhere((field) => field.visibility); + return GridHeaderState(fields: fields); + } } diff --git a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart index 6c766ee218..f941b01056 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/prelude.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/prelude.dart @@ -7,9 +7,9 @@ export 'data.dart'; // Field export 'field/field_service.dart'; export 'field/grid_header_bloc.dart'; -export 'field/grid_field_bloc.dart'; -export 'field/edit_field_bloc.dart'; -export 'field/switch_field_type_bloc.dart'; +export 'field/action_sheet_bloc.dart'; +export 'field/field_editor_bloc.dart'; +export 'field/field_switch_bloc.dart'; // Field Type Option export 'field/type_option/date_bloc.dart'; @@ -26,3 +26,4 @@ export 'cell_bloc/cell_service.dart'; // Setting export 'setting/setting_bloc.dart'; +export 'setting/property_bloc.dart'; diff --git a/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart new file mode 100644 index 0000000000..a0dd50a633 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/application/grid/setting/property_bloc.dart @@ -0,0 +1,51 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:flowy_sdk/log.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'; +import 'dart:async'; +import 'package:dartz/dartz.dart'; + +part 'property_bloc.freezed.dart'; + +class GridPropertyBloc extends Bloc { + final FieldService _service; + GridPropertyBloc({required String gridId, required List fields}) + : _service = FieldService(gridId: gridId), + super(GridPropertyState.initial(gridId, fields)) { + on( + (event, emit) async { + await event.map(setFieldVisibility: (_SetFieldVisibility value) async { + final result = await _service.updateField(fieldId: value.fieldId, visibility: value.visibility); + result.fold( + (l) => null, + (err) => Log.error(err), + ); + }); + }, + ); + } + + @override + Future close() async { + return super.close(); + } +} + +@freezed +class GridPropertyEvent with _$GridPropertyEvent { + const factory GridPropertyEvent.setFieldVisibility(String fieldId, bool visibility) = _SetFieldVisibility; +} + +@freezed +class GridPropertyState with _$GridPropertyState { + const factory GridPropertyState({ + required String gridId, + required List fields, + }) = _GridPropertyState; + + factory GridPropertyState.initial(String gridId, List fields) => GridPropertyState( + gridId: gridId, + fields: fields, + ); +} 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 1a8b5f4036..c8c5cfd7b2 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 @@ -100,9 +100,9 @@ class _FlowyGridState extends State { physics: StyledScrollPhysics(), controller: _scrollController.verticalController, slivers: [ - SliverToBoxAdapter(child: GridToolbar(gridId: gridId)), - _buildHeader(gridId), - _buildRows(context), + _renderToolbar(gridId), + _renderHeader(gridId), + _renderRows(context), const GridFooter(), ], ), @@ -129,12 +129,27 @@ class _FlowyGridState extends State { ); } - Widget _buildHeader(String gridId) { + Widget _renderToolbar(String gridId) { + return BlocBuilder( + builder: (context, state) { + final toolbarContext = GridToolbarContext( + gridId: gridId, + fields: state.fields, + ); + + return SliverToBoxAdapter( + child: GridToolbar(toolbarContext: toolbarContext), + ); + }, + ); + } + + Widget _renderHeader(String gridId) { return BlocBuilder( buildWhen: (previous, current) => previous.fields.length != current.fields.length, builder: (context, state) { return SliverPersistentHeader( - delegate: GridHeaderDelegate(gridId: gridId, fields: state.fields), + delegate: GridHeaderDelegate(gridId: gridId, fields: List.from(state.fields)), floating: true, pinned: true, ); @@ -142,7 +157,7 @@ class _FlowyGridState extends State { ); } - Widget _buildRows(BuildContext context) { + Widget _renderRows(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) { final rowChanged = previous.rows.length != current.rows.length; diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart index 53c27d62b4..73594de957 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/content/grid_row.dart @@ -124,6 +124,7 @@ class _RowCells extends StatelessWidget { buildWhen: (previous, current) => previous.cellDataMap != current.cellDataMap, builder: (context, state) { final children = state.fields + .where((field) => field.visibility) .map((field) => CellContainer( width: field.width.toDouble(), child: buildGridCell( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart new file mode 100755 index 0000000000..6a2051318e --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart @@ -0,0 +1,55 @@ +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'field_type_extension.dart'; + +import 'field_cell_action_sheet.dart'; +import 'field_editor.dart'; + +class GridFieldCell extends StatelessWidget { + final GridFieldCellContext fieldCellContext; + const GridFieldCell(this.fieldCellContext, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + final field = fieldCellContext.field; + + final button = FlowyButton( + hoverColor: theme.hover, + onTap: () => _showActionSheet(context), + rightIcon: svgWidget("editor/details", color: theme.iconColor), + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + text: FlowyText.medium(field.name, fontSize: 12), + padding: GridSize.cellContentInsets, + ); + + final borderSide = BorderSide(color: theme.shader4, width: 0.4); + final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide)); + + return Container( + width: field.width.toDouble(), + decoration: decoration, + child: button, + ); + } + + void _showActionSheet(BuildContext context) { + GridFieldCellActionSheet( + fieldCellContext: fieldCellContext, + onEdited: () => _showFieldEditor(context), + ).show(context); + } + + void _showFieldEditor(BuildContext context) { + FieldEditor( + gridId: fieldCellContext.gridId, + fieldContextLoader: FieldContextLoaderAdaptor(fieldCellContext), + ).show(context); + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart new file mode 100644 index 0000000000..6cf62bf397 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_cell_action_sheet.dart @@ -0,0 +1,195 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/prelude.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; + +class GridFieldCellActionSheet extends StatelessWidget with FlowyOverlayDelegate { + final GridFieldCellContext fieldCellContext; + final VoidCallback onEdited; + const GridFieldCellActionSheet({required this.fieldCellContext, required this.onEdited, Key? key}) : super(key: key); + + void show(BuildContext overlayContext) { + FlowyOverlay.of(overlayContext).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(240, 200)), + ), + identifier: identifier(), + anchorContext: overlayContext, + anchorDirection: AnchorDirection.bottomWithLeftAligned, + delegate: this, + ); + } + + @override + Widget build(BuildContext context) { + return BlocProvider( + create: (context) => getIt(param1: fieldCellContext), + child: SingleChildScrollView( + child: Column( + children: [ + _EditFieldButton( + onEdited: () { + FlowyOverlay.of(context).remove(identifier()); + onEdited(); + }, + ), + const VSpace(6), + _FieldOperationList(fieldCellContext, () => FlowyOverlay.of(context).remove(identifier())), + ], + ), + ), + ); + } + + String identifier() { + return toString(); + } + + @override + bool asBarrier() { + return true; + } +} + +class _EditFieldButton extends StatelessWidget { + final Function() onEdited; + const _EditFieldButton({required this.onEdited, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return BlocBuilder( + builder: (context, state) { + return SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), + hoverColor: theme.hover, + onTap: onEdited, + ), + ); + }, + ); + } +} + +class _FieldOperationList extends StatelessWidget { + final GridFieldCellContext fieldData; + final VoidCallback onDismissed; + const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + final actions = FieldAction.values + .map( + (action) => FieldActionCell( + fieldId: fieldData.field.id, + action: action, + onTap: onDismissed, + ), + ) + .toList(); + + return FieldOperationList(actions: actions); + } +} + +class FieldOperationList extends StatelessWidget { + final List actions; + const FieldOperationList({required this.actions, Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return GridView( + // https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html + shrinkWrap: true, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 2, + childAspectRatio: 4.0, + mainAxisSpacing: 8, + ), + children: actions, + ); + } +} + +class FieldActionCell extends StatelessWidget { + final String fieldId; + final VoidCallback onTap; + final FieldAction action; + + const FieldActionCell({ + required this.fieldId, + required this.action, + required this.onTap, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + final theme = context.watch(); + return FlowyButton( + text: FlowyText.medium(action.title(), fontSize: 12), + hoverColor: theme.hover, + onTap: () { + action.run(context); + onTap(); + }, + leftIcon: svgWidget(action.iconName(), color: theme.iconColor), + ); + } +} + +enum FieldAction { + hide, + duplicate, + delete, +} + +extension _FieldActionExtension on FieldAction { + String iconName() { + switch (this) { + case FieldAction.hide: + return 'grid/hide'; + case FieldAction.duplicate: + return 'grid/duplicate'; + case FieldAction.delete: + return 'grid/delete'; + } + } + + String title() { + switch (this) { + case FieldAction.hide: + return LocaleKeys.grid_field_hide.tr(); + case FieldAction.duplicate: + return LocaleKeys.grid_field_duplicate.tr(); + case FieldAction.delete: + return LocaleKeys.grid_field_delete.tr(); + } + } + + void run(BuildContext context) { + switch (this) { + case FieldAction.hide: + context.read().add(const ActionSheetEvent.hideField()); + break; + case FieldAction.duplicate: + context.read().add(const ActionSheetEvent.duplicateField()); + break; + case FieldAction.delete: + context.read().add(const ActionSheetEvent.deleteField()); + break; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_editor.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart similarity index 89% rename from frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_editor.dart rename to frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart index 4f349b9347..d568829558 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_editor.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart @@ -1,7 +1,7 @@ import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/workspace/application/grid/field/edit_field_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_editor_bloc.dart'; import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; -import 'package:app_flowy/workspace/application/grid/field/switch_field_type_bloc.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_switch_bloc.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; @@ -22,7 +22,11 @@ class FieldEditor extends FlowyOverlayDelegate { _fieldEditorBloc.add(const FieldEditorEvent.initial()); } - void show(BuildContext context) { + void show( + BuildContext context, { + AnchorDirection anchorDirection = AnchorDirection.bottomWithLeftAligned, + }) { + FlowyOverlay.of(context).remove(identifier()); FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( child: _FieldEditorWidget(_fieldEditorBloc), @@ -30,7 +34,7 @@ class FieldEditor extends FlowyOverlayDelegate { ), identifier: identifier(), anchorContext: context, - anchorDirection: AnchorDirection.bottomWithLeftAligned, + anchorDirection: anchorDirection, style: FlowyOverlayStyle(blur: false), delegate: this, ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart deleted file mode 100644 index 789b4f98bd..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_operation_list.dart +++ /dev/null @@ -1,99 +0,0 @@ -import 'package:app_flowy/workspace/application/grid/field/grid_field_bloc.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flutter/material.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:app_flowy/generated/locale_keys.g.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class FieldOperationList extends StatelessWidget { - final List actions; - const FieldOperationList({required this.actions, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return GridView( - // https://api.flutter.dev/flutter/widgets/AnimatedList/shrinkWrap.html - shrinkWrap: true, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: 2, - childAspectRatio: 4.0, - mainAxisSpacing: 8, - ), - children: actions, - ); - } -} - -class FieldActionCell extends StatelessWidget { - final String fieldId; - final VoidCallback onTap; - final FieldAction action; - - const FieldActionCell({ - required this.fieldId, - required this.action, - required this.onTap, - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch(); - return FlowyButton( - text: FlowyText.medium(action.title(), fontSize: 12), - hoverColor: theme.hover, - onTap: () { - action.run(context); - onTap(); - }, - leftIcon: svgWidget(action.iconName(), color: theme.iconColor), - ); - } -} - -enum FieldAction { - hide, - duplicate, - delete, -} - -extension _FieldActionExtension on FieldAction { - String iconName() { - switch (this) { - case FieldAction.hide: - return 'grid/hide'; - case FieldAction.duplicate: - return 'grid/duplicate'; - case FieldAction.delete: - return 'grid/delete'; - } - } - - String title() { - switch (this) { - case FieldAction.hide: - return LocaleKeys.grid_field_hide.tr(); - case FieldAction.duplicate: - return LocaleKeys.grid_field_duplicate.tr(); - case FieldAction.delete: - return LocaleKeys.grid_field_delete.tr(); - } - } - - void run(BuildContext context) { - switch (this) { - case FieldAction.hide: - context.read().add(const GridFieldEvent.hideField()); - break; - case FieldAction.duplicate: - context.read().add(const GridFieldEvent.duplicateField()); - break; - case FieldAction.delete: - context.read().add(const GridFieldEvent.deleteField()); - break; - } - } -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart index 7c52c29a7e..63816c7d74 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_switcher.dart @@ -15,7 +15,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/startup/startup.dart'; import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_list.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart'; +import 'field_type_extension.dart'; import 'type_option/multi_select.dart'; import 'type_option/number.dart'; @@ -43,8 +44,8 @@ class _FieldSwitcherState extends State { @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => getIt(param1: widget.switchContext), - child: BlocConsumer( + create: (context) => getIt(param1: widget.switchContext), + child: BlocConsumer( listener: (context, state) { widget.onUpdated(state.field, state.typeOptionData); }, @@ -79,7 +80,7 @@ class _FieldSwitcherState extends State { hoverColor: theme.hover, onTap: () { final list = FieldTypeList(onSelectField: (fieldType) { - context.read().add(FieldSwitchEvent.toFieldType(fieldType)); + context.read().add(FieldSwitchEvent.toFieldType(fieldType)); }); _showOverlay(context, list); }, @@ -100,7 +101,7 @@ class _FieldSwitcherState extends State { ); final dataDelegate = TypeOptionDataDelegate(didUpdateTypeOptionData: (data) { - context.read().add(FieldSwitchEvent.didUpdateTypeOptionData(data)); + context.read().add(FieldSwitchEvent.didUpdateTypeOptionData(data)); }); final builder = _makeTypeOptionBuild( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart new file mode 100644 index 0000000000..ce37afe861 --- /dev/null +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart @@ -0,0 +1,44 @@ + +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart'; +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:easy_localization/easy_localization.dart'; + +extension FieldTypeListExtension on FieldType { + String iconName() { + switch (this) { + case FieldType.Checkbox: + return "grid/field/checkbox"; + case FieldType.DateTime: + return "grid/field/date"; + case FieldType.MultiSelect: + return "grid/field/multi_select"; + case FieldType.Number: + return "grid/field/number"; + case FieldType.RichText: + return "grid/field/text"; + case FieldType.SingleSelect: + return "grid/field/single_select"; + default: + throw UnimplementedError; + } + } + + String title() { + switch (this) { + case FieldType.Checkbox: + return LocaleKeys.grid_field_checkboxFieldName.tr(); + case FieldType.DateTime: + return LocaleKeys.grid_field_dateFieldName.tr(); + case FieldType.MultiSelect: + return LocaleKeys.grid_field_multiSelectFieldName.tr(); + case FieldType.Number: + return LocaleKeys.grid_field_numberFieldName.tr(); + case FieldType.RichText: + return LocaleKeys.grid_field_textFieldName.tr(); + case FieldType.SingleSelect: + return LocaleKeys.grid_field_singleSelectFieldName.tr(); + default: + throw UnimplementedError; + } + } +} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_list.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart similarity index 64% rename from frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_list.dart rename to frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart index b83ad267f9..2965556f60 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_list.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/field_type_list.dart @@ -8,8 +8,7 @@ import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/meta.pb.dart'; import 'package:flutter/material.dart'; -import 'package:app_flowy/generated/locale_keys.g.dart'; -import 'package:easy_localization/easy_localization.dart'; +import 'field_type_extension.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; typedef SelectFieldCallback = void Function(FieldType); @@ -76,43 +75,3 @@ class FieldTypeCell extends StatelessWidget { ); } } - -extension FieldTypeListExtension on FieldType { - String iconName() { - switch (this) { - case FieldType.Checkbox: - return "grid/field/checkbox"; - case FieldType.DateTime: - return "grid/field/date"; - case FieldType.MultiSelect: - return "grid/field/multi_select"; - case FieldType.Number: - return "grid/field/number"; - case FieldType.RichText: - return "grid/field/text"; - case FieldType.SingleSelect: - return "grid/field/single_select"; - default: - throw UnimplementedError; - } - } - - String title() { - switch (this) { - case FieldType.Checkbox: - return LocaleKeys.grid_field_checkboxFieldName.tr(); - case FieldType.DateTime: - return LocaleKeys.grid_field_dateFieldName.tr(); - case FieldType.MultiSelect: - return LocaleKeys.grid_field_multiSelectFieldName.tr(); - case FieldType.Number: - return LocaleKeys.grid_field_numberFieldName.tr(); - case FieldType.RichText: - return LocaleKeys.grid_field_textFieldName.tr(); - case FieldType.SingleSelect: - return LocaleKeys.grid_field_singleSelectFieldName.tr(); - default: - throw UnimplementedError; - } - } -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_action_sheet.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_action_sheet.dart deleted file mode 100644 index 79dd083fab..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_field_action_sheet.dart +++ /dev/null @@ -1,105 +0,0 @@ -import 'package:app_flowy/startup/startup.dart'; -import 'package:app_flowy/workspace/application/grid/prelude.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'field_operation_list.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:app_flowy/generated/locale_keys.g.dart'; - -class GridFieldActionSheet extends StatelessWidget with FlowyOverlayDelegate { - final GridFieldData fieldData; - final VoidCallback onEdited; - const GridFieldActionSheet({required this.fieldData, required this.onEdited, Key? key}) : super(key: key); - - void show(BuildContext overlayContext) { - FlowyOverlay.of(overlayContext).insertWithAnchor( - widget: OverlayContainer( - child: this, - constraints: BoxConstraints.loose(const Size(240, 200)), - ), - identifier: identifier(), - anchorContext: overlayContext, - anchorDirection: AnchorDirection.bottomWithLeftAligned, - delegate: this, - ); - } - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => getIt(param1: fieldData), - child: SingleChildScrollView( - child: Column( - children: [ - _EditFieldButton( - onEdited: () { - FlowyOverlay.of(context).remove(identifier()); - onEdited(); - }, - ), - const VSpace(6), - _FieldOperationList(fieldData, () => FlowyOverlay.of(context).remove(identifier())), - ], - ), - ), - ); - } - - String identifier() { - return toString(); - } - - @override - bool asBarrier() { - return true; - } -} - -class _EditFieldButton extends StatelessWidget { - final Function() onEdited; - const _EditFieldButton({required this.onEdited, Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch(); - return BlocBuilder( - builder: (context, state) { - return SizedBox( - height: GridSize.typeOptionItemHeight, - child: FlowyButton( - text: FlowyText.medium(LocaleKeys.grid_field_editProperty.tr(), fontSize: 12), - hoverColor: theme.hover, - onTap: onEdited, - ), - ); - }, - ); - } -} - -class _FieldOperationList extends StatelessWidget { - final GridFieldData fieldData; - final VoidCallback onDismissed; - const _FieldOperationList(this.fieldData, this.onDismissed, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final actions = FieldAction.values - .map( - (action) => FieldActionCell( - fieldId: fieldData.field.id, - action: action, - onTap: onDismissed, - ), - ) - .toList(); - - return FieldOperationList(actions: actions); - } -} 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 faf17e8c13..be025501a0 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 @@ -9,8 +9,8 @@ import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'grid_field_editor.dart'; -import 'grid_header_cell.dart'; +import 'field_editor.dart'; +import 'field_cell.dart'; class GridHeaderDelegate extends SliverPersistentHeaderDelegate { final String gridId; @@ -55,8 +55,8 @@ class GridHeader extends StatelessWidget { child: BlocBuilder( builder: (context, state) { final cells = state.fields.map( - (field) => GridHeaderCell( - GridFieldData(gridId: gridId, field: field), + (field) => GridFieldCell( + GridFieldCellContext(gridId: gridId, field: field), ), ); diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header_cell.dart deleted file mode 100755 index 253f935bbd..0000000000 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/grid_header_cell.dart +++ /dev/null @@ -1,45 +0,0 @@ -import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:flowy_infra/image.dart'; -import 'package:flowy_infra/theme.dart'; -import 'package:flowy_infra_ui/style_widget/button.dart'; -import 'package:flowy_infra_ui/style_widget/text.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'grid_field_editor.dart'; -import 'grid_field_action_sheet.dart'; - -class GridHeaderCell extends StatelessWidget { - final GridFieldData fieldData; - const GridHeaderCell(this.fieldData, {Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = context.watch(); - final button = FlowyButton( - hoverColor: theme.hover, - onTap: () => GridFieldActionSheet( - fieldData: fieldData, - onEdited: () { - FieldEditor( - gridId: fieldData.gridId, - fieldContextLoader: FieldContextLoaderAdaptor(fieldData), - ).show(context); - }, - ).show(context), - rightIcon: svgWidget("editor/details", color: theme.iconColor), - text: Padding(padding: GridSize.cellContentInsets, child: FlowyText.medium(fieldData.field.name, fontSize: 12)), - ); - - final borderSide = BorderSide(color: theme.shader4, width: 0.4); - final decoration = BoxDecoration(border: Border(top: borderSide, right: borderSide, bottom: borderSide)); - - return Container( - width: fieldData.field.width.toDouble(), - decoration: decoration, - padding: GridSize.headerContentInsets, - child: button, - ); - } -} diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart index bae78c02f8..a31d371b09 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/header/type_option/date.dart @@ -109,8 +109,8 @@ class DateFormatList extends StatelessWidget { @override Widget build(BuildContext context) { - final formatItems = DateFormat.values.map((format) { - return DateFormatItem( + final cells = DateFormat.values.map((format) { + return DateFormatCell( dateFormat: format, onSelected: (format) { onSelected(format); @@ -127,9 +127,9 @@ class DateFormatList extends StatelessWidget { separatorBuilder: (context, index) { return VSpace(GridSize.typeOptionSeparatorHeight); }, - itemCount: formatItems.length, + itemCount: cells.length, itemBuilder: (BuildContext context, int index) { - return formatItems[index]; + return cells[index]; }, ), ); @@ -140,11 +140,11 @@ class DateFormatList extends StatelessWidget { } } -class DateFormatItem extends StatelessWidget { +class DateFormatCell extends StatelessWidget { final bool isSelected; final DateFormat dateFormat; final Function(DateFormat format) onSelected; - const DateFormatItem({ + const DateFormatCell({ required this.dateFormat, required this.onSelected, required this.isSelected, @@ -199,8 +199,8 @@ class TimeFormatList extends StatelessWidget { @override Widget build(BuildContext context) { - final formatItems = TimeFormat.values.map((format) { - return TimeFormatItem( + final cells = TimeFormat.values.map((format) { + return TimeFormatCell( isSelected: format == selectedFormat, timeFormat: format, onSelected: (format) { @@ -217,9 +217,9 @@ class TimeFormatList extends StatelessWidget { separatorBuilder: (context, index) { return VSpace(GridSize.typeOptionSeparatorHeight); }, - itemCount: formatItems.length, + itemCount: cells.length, itemBuilder: (BuildContext context, int index) { - return formatItems[index]; + return cells[index]; }, ), ); @@ -230,11 +230,11 @@ class TimeFormatList extends StatelessWidget { } } -class TimeFormatItem extends StatelessWidget { +class TimeFormatCell extends StatelessWidget { final TimeFormat timeFormat; final bool isSelected; final Function(TimeFormat format) onSelected; - const TimeFormatItem({ + const TimeFormatCell({ required this.timeFormat, required this.onSelected, required this.isSelected, diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart index 756b7cdf17..b1c57a1530 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_property.dart @@ -1,19 +1,123 @@ +import 'package:app_flowy/startup/startup.dart'; +import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; +import 'package:app_flowy/workspace/application/grid/setting/property_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_type_extension.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/flowy_infra_ui.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show Field; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:styled_widget/styled_widget.dart'; -class GridPropertyList extends StatelessWidget { - const GridPropertyList({Key? key}) : super(key: key); +class GridPropertyList extends StatelessWidget with FlowyOverlayDelegate { + final String gridId; + final List fields; + const GridPropertyList({ + required this.gridId, + required this.fields, + Key? key, + }) : super(key: key); + + void show(BuildContext context) { + FlowyOverlay.of(context).insertWithAnchor( + widget: OverlayContainer( + child: this, + constraints: BoxConstraints.loose(const Size(260, 400)), + ), + identifier: identifier(), + anchorContext: context, + anchorDirection: AnchorDirection.bottomRight, + style: FlowyOverlayStyle(blur: false), + delegate: this, + ); + } @override Widget build(BuildContext context) { - return Container(); + return BlocProvider( + create: (context) => getIt(param1: gridId, param2: fields), + child: BlocBuilder( + builder: (context, state) { + final cells = state.fields.map((field) { + return _GridPropertyCell(gridId: gridId, field: field); + }).toList(); + + return ListView.separated( + shrinkWrap: true, + controller: ScrollController(), + separatorBuilder: (context, index) { + return VSpace(GridSize.typeOptionSeparatorHeight); + }, + itemCount: cells.length, + itemBuilder: (BuildContext context, int index) { + return cells[index]; + }, + ); + }, + ), + ); } + + String identifier() { + return toString(); + } + + @override + bool asBarrier() => true; } class _GridPropertyCell extends StatelessWidget { - const _GridPropertyCell({Key? key}) : super(key: key); + final Field field; + final String gridId; + const _GridPropertyCell({required this.gridId, required this.field, Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return Container(); + final theme = context.watch(); + + final checkmark = field.visibility + ? svgWidget('home/show', color: theme.iconColor) + : svgWidget('home/hide', color: theme.iconColor); + + return Row( + children: [ + Expanded( + child: SizedBox( + height: GridSize.typeOptionItemHeight, + child: FlowyButton( + text: FlowyText.medium(field.name, fontSize: 12), + hoverColor: theme.hover, + leftIcon: svgWidget(field.fieldType.iconName(), color: theme.iconColor), + onTap: () { + final fieldCellContext = GridFieldCellContext( + gridId: gridId, + field: field, + ); + + FieldEditor( + gridId: gridId, + fieldContextLoader: FieldContextLoaderAdaptor(fieldCellContext), + ).show(context, anchorDirection: AnchorDirection.bottomRight); + }, + ), + ), + ), + FlowyIconButton( + hoverColor: theme.hover, + width: GridSize.typeOptionItemHeight, + onPressed: () { + context.read().add(GridPropertyEvent.setFieldVisibility(field.id, !field.visibility)); + }, + icon: checkmark.padding(all: 6), + ) + ], + ); } } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart index 784fd62bcf..e8a792025d 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_setting.dart @@ -7,34 +7,57 @@ import 'package:flowy_infra_ui/style_widget/button.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; +import 'grid_property.dart'; + class GridSettingContext { final String gridId; + final List fields; + GridSettingContext({ required this.gridId, + required this.fields, }); } -class GridSettingList extends StatelessWidget with FlowyOverlayDelegate { +class GridSettingList extends StatelessWidget { final GridSettingContext settingContext; - const GridSettingList({required this.settingContext, Key? key}) : super(key: key); + final Function(GridSettingAction, GridSettingContext) onAction; + const GridSettingList({required this.settingContext, required this.onAction, Key? key}) : super(key: key); + + static void show(BuildContext context, GridSettingContext settingContext) { + final list = GridSettingList( + settingContext: settingContext, + onAction: (action, settingContext) { + switch (action) { + case GridSettingAction.filter: + // TODO: Handle this case. + break; + case GridSettingAction.sortBy: + // TODO: Handle this case. + break; + case GridSettingAction.properties: + GridPropertyList(gridId: settingContext.gridId, fields: settingContext.fields).show(context); + break; + } + }, + ); - void show(BuildContext context) { FlowyOverlay.of(context).insertWithAnchor( widget: OverlayContainer( - child: this, + child: list, constraints: BoxConstraints.loose(const Size(140, 400)), ), - identifier: identifier(), + identifier: list.identifier(), anchorContext: context, anchorDirection: AnchorDirection.bottomRight, style: FlowyOverlayStyle(blur: false), - delegate: this, ); } @@ -46,17 +69,8 @@ class GridSettingList extends StatelessWidget with FlowyOverlayDelegate { listenWhen: (previous, current) => previous.selectedAction != current.selectedAction, listener: (context, state) { state.selectedAction.foldLeft(null, (_, action) { - switch (action) { - case GridSettingAction.filter: - // TODO: Handle this case. - break; - case GridSettingAction.sortBy: - // TODO: Handle this case. - break; - case GridSettingAction.properties: - // TODO: Handle this case. - break; - } + FlowyOverlay.of(context).remove(identifier()); + onAction(action, settingContext); }); }, child: BlocBuilder( diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart index dd586d9d2f..9569f95225 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/toolbar/grid_toolbar.dart @@ -1,25 +1,40 @@ -import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; -import 'package:flowy_infra_ui/style_widget/extension.dart'; -import 'package:flutter/material.dart'; import 'package:flowy_infra/image.dart'; import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/extension.dart'; import 'package:flowy_infra_ui/style_widget/icon_button.dart'; +import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' hide Row; +import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; + import 'grid_setting.dart'; -class GridToolbar extends StatelessWidget { +class GridToolbarContext { final String gridId; - const GridToolbar({required this.gridId, Key? key}) : super(key: key); + final List fields; + GridToolbarContext({ + required this.gridId, + required this.fields, + }); +} + +class GridToolbar extends StatelessWidget { + final GridToolbarContext toolbarContext; + const GridToolbar({required this.toolbarContext, Key? key}) : super(key: key); @override Widget build(BuildContext context) { + final settingContext = GridSettingContext( + gridId: toolbarContext.gridId, + fields: toolbarContext.fields, + ); return SizedBox( height: 40, child: Row( children: [ SizedBox(width: GridSize.leadingHeaderPadding), - _SettingButton(settingContext: GridSettingContext(gridId: gridId)), + _SettingButton(settingContext: settingContext), const Spacer(), ], ), @@ -37,7 +52,7 @@ class _SettingButton extends StatelessWidget { return FlowyIconButton( hoverColor: theme.hover, width: 22, - onPressed: () => GridSettingList(settingContext: settingContext).show(context), + onPressed: () => GridSettingList.show(context, settingContext), icon: svgWidget("grid/setting/setting").padding(horizontal: 3, vertical: 3), ); } diff --git a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs index 3925f80b24..95c23f489b 100644 --- a/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs +++ b/frontend/rust-lib/flowy-grid/src/services/grid_editor.rs @@ -295,7 +295,7 @@ impl ClientGridEditor { pub async fn get_field_metas(&self, field_orders: Option) -> FlowyResult> { let mut field_metas = self.pad.read().await.get_field_metas(field_orders)?; - field_metas.retain(|field_meta| field_meta.visibility); + // field_metas.retain(|field_meta| field_meta.visibility); Ok(field_metas) }