diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart index c76f06adc9..41c496c373 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/select_option_service.dart @@ -94,7 +94,7 @@ class SelectOptionService { return GridEventUpdateCellSelectOption(payload).send(); } - Future> remove({ + Future> unSelect({ required String gridId, required String fieldId, required String rowId, diff --git a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart index 92676a0c12..1860e40ef3 100644 --- a/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart +++ b/frontend/app_flowy/lib/workspace/application/grid/cell/selection_editor_bloc.dart @@ -51,7 +51,7 @@ class SelectOptionEditorBloc extends Bloc null, (err) => Log.error(err)); } - void _makeOptionAsSelected(String optionId) { - _selectOptionService.select( - gridId: state.gridId, - fieldId: state.field.id, - rowId: state.rowId, - optionId: optionId, - ); + void _onSelectOption(String optionId) { + final hasSelected = state.selectedOptions.firstWhereOrNull((option) => option.id == optionId); + if (hasSelected != null) { + _selectOptionService.unSelect( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + optionId: optionId, + ); + } else { + _selectOptionService.select( + gridId: state.gridId, + fieldId: state.field.id, + rowId: state.rowId, + optionId: optionId, + ); + } } void _loadOptions() async { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart index 015fea1c32..4b52cae908 100755 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/cell_builder.dart @@ -16,13 +16,13 @@ GridCellWidget buildGridCell(GridCell cellData, {GridCellStyle? style}) { case FieldType.DateTime: return DateCell(cellData: cellData, key: key); case FieldType.MultiSelect: - return MultiSelectCell(cellData: cellData, key: key); + return MultiSelectCell(cellData: cellData, style: style, key: key); case FieldType.Number: return NumberCell(cellData: cellData, key: key); case FieldType.RichText: - return GridTextCell(cellData: cellData, key: key, style: style); + return GridTextCell(cellData: cellData, style: style, key: key); case FieldType.SingleSelect: - return SingleSelectCell(cellData: cellData, key: key); + return SingleSelectCell(cellData: cellData, style: style, key: key); default: throw UnimplementedError; } diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart index 05dd66e224..f3b42621a9 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/cell/selection_cell/selection_cell.dart @@ -1,19 +1,37 @@ 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/cell/cell_builder.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'extension.dart'; import 'selection_editor.dart'; +class SelectOptionCellStyle extends GridCellStyle { + String placeholder; + + SelectOptionCellStyle({ + required this.placeholder, + }); +} + class SingleSelectCell extends GridCellWidget { final GridCell cellData; + late final SelectOptionCellStyle? cellStyle; SingleSelectCell({ required this.cellData, + GridCellStyle? style, Key? key, - }) : super(key: key); + }) : super(key: key) { + if (style != null) { + cellStyle = (style as SelectOptionCellStyle); + } else { + cellStyle = null; + } + } @override State createState() => _SingleSelectCellState(); @@ -30,11 +48,18 @@ class _SingleSelectCellState extends State { @override Widget build(BuildContext context) { + final theme = context.watch(); + return BlocProvider.value( value: _cellBloc, child: BlocBuilder( builder: (context, state) { - final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + List children = []; + children.addAll(state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList()); + + if (children.isEmpty && widget.cellStyle != null) { + children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14, color: theme.shader3)); + } return SizedBox.expand( child: InkWell( onTap: () { @@ -65,11 +90,19 @@ class _SingleSelectCellState extends State { //---------------------------------------------------------------- class MultiSelectCell extends GridCellWidget { final GridCell cellData; + late final SelectOptionCellStyle? cellStyle; MultiSelectCell({ required this.cellData, + GridCellStyle? style, Key? key, - }) : super(key: key); + }) : super(key: key) { + if (style != null) { + cellStyle = (style as SelectOptionCellStyle); + } else { + cellStyle = null; + } + } @override State createState() => _MultiSelectCellState(); @@ -90,7 +123,12 @@ class _MultiSelectCellState extends State { value: _cellBloc, child: BlocBuilder( builder: (context, state) { - final children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + List children = state.selectedOptions.map((option) => SelectOptionTag(option: option)).toList(); + + if (children.isEmpty && widget.cellStyle != null) { + children.add(FlowyText.medium(widget.cellStyle!.placeholder, fontSize: 14)); + } + return SizedBox.expand( child: InkWell( onTap: () { diff --git a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart index 4ba31f783b..28ea259b88 100644 --- a/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart +++ b/frontend/app_flowy/lib/workspace/presentation/plugins/grid/src/widgets/row/row_detail.dart @@ -1,12 +1,14 @@ import 'package:app_flowy/workspace/application/grid/field/field_service.dart'; import 'package:app_flowy/workspace/application/grid/row/row_detail_bloc.dart'; import 'package:app_flowy/workspace/application/grid/row/row_service.dart'; +import 'package:app_flowy/workspace/presentation/plugins/grid/src/layout/sizes.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/cell/prelude.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_cell.dart'; import 'package:app_flowy/workspace/presentation/plugins/grid/src/widgets/header/field_editor.dart'; import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_sdk/protobuf/flowy-grid-data-model/grid.pb.dart' show FieldType; import 'package:easy_localization/easy_localization.dart'; @@ -59,8 +61,8 @@ class _RowDetailPageState extends State { bloc.add(const RowDetailEvent.initial()); return bloc; }, - child: const Padding( - padding: EdgeInsets.symmetric(horizontal: 80, vertical: 40), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 80, vertical: 40), child: _PropertyList(), ), ); @@ -68,23 +70,31 @@ class _RowDetailPageState extends State { } class _PropertyList extends StatelessWidget { - const _PropertyList({ + final ScrollController _scrollController; + _PropertyList({ Key? key, - }) : super(key: key); + }) : _scrollController = ScrollController(), + super(key: key); @override Widget build(BuildContext context) { return BlocBuilder( buildWhen: (previous, current) => previous.cellDatas != current.cellDatas, builder: (context, state) { - return ListView.separated( - itemCount: state.cellDatas.length, - itemBuilder: (BuildContext context, int index) { - return _RowDetailCell(cellData: state.cellDatas[index]); - }, - separatorBuilder: (BuildContext context, int index) { - return const VSpace(2); - }, + return ScrollbarListStack( + axis: Axis.vertical, + controller: _scrollController, + barSize: GridSize.scrollBarSize, + child: ListView.separated( + controller: _scrollController, + itemCount: state.cellDatas.length, + itemBuilder: (BuildContext context, int index) { + return _RowDetailCell(cellData: state.cellDatas[index]); + }, + separatorBuilder: (BuildContext context, int index) { + return const VSpace(2); + }, + ), ); }, ); @@ -142,7 +152,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) { case FieldType.DateTime: return null; case FieldType.MultiSelect: - return null; + return SelectOptionCellStyle( + placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), + ); case FieldType.Number: return null; case FieldType.RichText: @@ -150,7 +162,9 @@ GridCellStyle? _buildCellStyle(AppTheme theme, FieldType fieldType) { placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), ); case FieldType.SingleSelect: - return null; + return SelectOptionCellStyle( + placeholder: LocaleKeys.grid_row_textPlaceholder.tr(), + ); default: return null; } diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart index 55f29eba93..74cf7e4c31 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text.dart @@ -46,7 +46,7 @@ class FlowyText extends StatelessWidget { style: TextStyle( color: color ?? theme.textColor, fontWeight: fontWeight, - fontSize: fontSize + 2, + fontSize: fontSize, fontFamily: 'Mulish', )); }