fix: select option chip size (#5859)

This commit is contained in:
Mathias Mogensen 2024-08-01 23:28:05 +02:00 committed by GitHub
parent 73421e0d58
commit c2e8a12427
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 126 additions and 139 deletions

View File

@ -1,5 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/widgets.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart'; import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart';
import 'package:appflowy/plugins/database/application/field/type_option/select_type_option_actions.dart'; import 'package:appflowy/plugins/database/application/field/type_option/select_type_option_actions.dart';
@ -9,7 +11,6 @@ import 'package:appflowy/plugins/database/domain/select_option_cell_service.dart
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
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';
@ -109,16 +110,16 @@ class SelectOptionCellEditorBloc
selectOption: (optionId) async { selectOption: (optionId) async {
await _selectOptionService.select(optionIds: [optionId]); await _selectOptionService.select(optionIds: [optionId]);
}, },
unSelectOption: (optionId) async { unselectOption: (optionId) async {
await _selectOptionService.unSelect(optionIds: [optionId]); await _selectOptionService.unselect(optionIds: [optionId]);
}, },
unSelectLastOption: () async { unselectLastOption: () async {
if (state.selectedOptions.isEmpty) { if (state.selectedOptions.isEmpty) {
return; return;
} }
final lastSelectedOptionId = state.selectedOptions.last.id; final lastSelectedOptionId = state.selectedOptions.last.id;
await _selectOptionService await _selectOptionService
.unSelect(optionIds: [lastSelectedOptionId]); .unselect(optionIds: [lastSelectedOptionId]);
}, },
submitTextField: () { submitTextField: () {
_submitTextFieldValue(emit); _submitTextFieldValue(emit);
@ -353,10 +354,10 @@ class SelectOptionCellEditorEvent with _$SelectOptionCellEditorEvent {
const factory SelectOptionCellEditorEvent.createOption() = _CreateOption; const factory SelectOptionCellEditorEvent.createOption() = _CreateOption;
const factory SelectOptionCellEditorEvent.selectOption(String optionId) = const factory SelectOptionCellEditorEvent.selectOption(String optionId) =
_SelectOption; _SelectOption;
const factory SelectOptionCellEditorEvent.unSelectOption(String optionId) = const factory SelectOptionCellEditorEvent.unselectOption(String optionId) =
_UnSelectOption; _UnselectOption;
const factory SelectOptionCellEditorEvent.unSelectLastOption() = const factory SelectOptionCellEditorEvent.unselectLastOption() =
_UnSelectLastOption; _UnselectLastOption;
const factory SelectOptionCellEditorEvent.updateOption( const factory SelectOptionCellEditorEvent.updateOption(
SelectOptionPB option, SelectOptionPB option,
) = _UpdateOption; ) = _UpdateOption;

View File

@ -70,7 +70,7 @@ class SelectOptionCellBackendService {
return DatabaseEventUpdateSelectOptionCell(payload).send(); return DatabaseEventUpdateSelectOptionCell(payload).send();
} }
Future<FlowyResult<void, FlowyError>> unSelect({ Future<FlowyResult<void, FlowyError>> unselect({
required Iterable<String> optionIds, required Iterable<String> optionIds,
}) { }) {
final payload = SelectOptionCellChangesetPB() final payload = SelectOptionCellChangesetPB()

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar_actions.dart'; import 'package:appflowy/mobile/presentation/base/app_bar/app_bar_actions.dart';
@ -12,7 +14,6 @@ import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pbenum.
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/select_option_entities.pb.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import 'package:protobuf/protobuf.dart'; import 'package:protobuf/protobuf.dart';
@ -176,7 +177,7 @@ class _MobileSelectOptionEditorState extends State<MobileSelectOptionEditor> {
} else { } else {
context context
.read<SelectOptionCellEditorBloc>() .read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.unSelectOption(option.id)); .add(SelectOptionCellEditorEvent.unselectOption(option.id));
} }
}, },
onMoreOptions: (option) { onMoreOptions: (option) {

View File

@ -1,6 +1,10 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart'; import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart';
@ -10,14 +14,11 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../grid/presentation/layout/sizes.dart';
import '../../grid/presentation/widgets/common/type_option_separator.dart'; import '../../grid/presentation/widgets/common/type_option_separator.dart';
import '../field/type_option_editor/select/select_option_editor.dart'; import '../field/type_option_editor/select/select_option_editor.dart';
import 'extension.dart'; import 'extension.dart';
import 'select_option_text_field.dart'; import 'select_option_text_field.dart';
@ -73,7 +74,7 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
break; break;
case LogicalKeyboardKey.backspace when event is KeyUpEvent: case LogicalKeyboardKey.backspace when event is KeyUpEvent:
if (!textEditingController.text.isNotEmpty) { if (!textEditingController.text.isNotEmpty) {
bloc.add(const SelectOptionCellEditorEvent.unSelectLastOption()); bloc.add(const SelectOptionCellEditorEvent.unselectLastOption());
return KeyEventResult.handled; return KeyEventResult.handled;
} }
break; break;
@ -137,8 +138,7 @@ class _OptionList extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocConsumer<SelectOptionCellEditorBloc, return BlocConsumer<SelectOptionCellEditorBloc,
SelectOptionCellEditorState>( SelectOptionCellEditorState>(
listenWhen: (previous, current) => listenWhen: (prev, curr) => prev.clearFilter != curr.clearFilter,
previous.clearFilter != current.clearFilter,
listener: (context, state) { listener: (context, state) {
if (state.clearFilter) { if (state.clearFilter) {
textEditingController.clear(); textEditingController.clear();
@ -151,60 +151,66 @@ class _OptionList extends StatelessWidget {
!listEquals(previous.options, current.options) || !listEquals(previous.options, current.options) ||
previous.createSelectOptionSuggestion != previous.createSelectOptionSuggestion !=
current.createSelectOptionSuggestion, current.createSelectOptionSuggestion,
builder: (context, state) { builder: (context, state) => ReorderableListView.builder(
return ReorderableListView.builder( shrinkWrap: true,
shrinkWrap: true, proxyDecorator: (child, index, _) => Material(
proxyDecorator: (child, index, _) => Material( color: Colors.transparent,
color: Colors.transparent, child: Stack(
child: Stack( children: [
children: [ BlocProvider.value(
BlocProvider.value( value: context.read<SelectOptionCellEditorBloc>(),
value: context.read<SelectOptionCellEditorBloc>(), child: child,
child: child, ),
), MouseRegion(
MouseRegion( cursor: Platform.isWindows
cursor: Platform.isWindows ? SystemMouseCursors.click
? SystemMouseCursors.click : SystemMouseCursors.grabbing,
: SystemMouseCursors.grabbing, child: const SizedBox.expand(),
child: const SizedBox.expand(), ),
), ],
],
),
), ),
buildDefaultDragHandles: false, ),
itemCount: state.options.length, buildDefaultDragHandles: false,
onReorderStart: (_) => popoverMutex.close(), itemCount: state.options.length,
itemBuilder: (_, int index) { onReorderStart: (_) => popoverMutex.close(),
final option = state.options[index]; itemBuilder: (_, int index) {
return _SelectOptionCell( final option = state.options[index];
key: ValueKey("select_cell_option_list_${option.id}"), return _SelectOptionCell(
index: index, key: ValueKey("select_cell_option_list_${option.id}"),
option: option, index: index,
popoverMutex: popoverMutex, option: option,
); popoverMutex: popoverMutex,
}, );
onReorder: (oldIndex, newIndex) { },
if (oldIndex < newIndex) { onReorder: (oldIndex, newIndex) {
newIndex--; if (oldIndex < newIndex) {
} newIndex--;
final fromOptionId = state.options[oldIndex].id; }
final toOptionId = state.options[newIndex].id; final fromOptionId = state.options[oldIndex].id;
context.read<SelectOptionCellEditorBloc>().add( final toOptionId = state.options[newIndex].id;
SelectOptionCellEditorEvent.reorderOption( context.read<SelectOptionCellEditorBloc>().add(
fromOptionId, SelectOptionCellEditorEvent.reorderOption(
toOptionId, fromOptionId,
), toOptionId,
);
},
header: const _Title(),
footer: state.createSelectOptionSuggestion == null
? null
: _CreateOptionCell(
suggestion: state.createSelectOptionSuggestion!,
), ),
padding: const EdgeInsets.symmetric(vertical: 8.0), );
); },
}, header: Padding(
padding: EdgeInsets.only(
bottom: state.createSelectOptionSuggestion != null ||
state.options.isNotEmpty
? 12
: 0,
),
child: const _Title(),
),
footer: state.createSelectOptionSuggestion != null
? _CreateOptionCell(
suggestion: state.createSelectOptionSuggestion!,
)
: null,
padding: const EdgeInsets.symmetric(vertical: 8),
),
); );
} }
} }
@ -245,11 +251,9 @@ class _TextField extends StatelessWidget {
scrollController: scrollController, scrollController: scrollController,
textSeparators: const [','], textSeparators: const [','],
onClick: () => popoverMutex.close(), onClick: () => popoverMutex.close(),
newText: (text) { newText: (text) => context
context .read<SelectOptionCellEditorBloc>()
.read<SelectOptionCellEditorBloc>() .add(SelectOptionCellEditorEvent.filterOption(text)),
.add(SelectOptionCellEditorEvent.filterOption(text));
},
onSubmitted: () { onSubmitted: () {
context context
.read<SelectOptionCellEditorBloc>() .read<SelectOptionCellEditorBloc>()
@ -264,13 +268,12 @@ class _TextField extends StatelessWidget {
), ),
); );
}, },
onRemove: (optionName) { onRemove: (name) =>
context.read<SelectOptionCellEditorBloc>().add( context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.unSelectOption( SelectOptionCellEditorEvent.unselectOption(
optionMap[optionName]!.id, optionMap[name]!.id,
),
), ),
);
},
), ),
), ),
); );
@ -286,12 +289,9 @@ class _Title extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0), padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SizedBox( child: FlowyText.regular(
height: GridSize.popoverItemHeight, LocaleKeys.grid_selectOption_panelTitle.tr(),
child: FlowyText.regular( color: Theme.of(context).hintColor,
LocaleKeys.grid_selectOption_panelTitle.tr(),
color: Theme.of(context).hintColor,
),
), ),
); );
} }
@ -326,16 +326,27 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
constraints: BoxConstraints.loose(const Size(200, 470)), constraints: BoxConstraints.loose(const Size(200, 470)),
mutex: widget.popoverMutex, mutex: widget.popoverMutex,
clickHandler: PopoverClickHandler.gestureDetector, clickHandler: PopoverClickHandler.gestureDetector,
popupBuilder: (popoverContext) => SelectOptionEditor(
key: ValueKey(widget.option.id),
option: widget.option,
onDeleted: () {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.deleteOption(widget.option));
PopoverContainer.of(popoverContext).close();
},
onUpdated: (updatedOption) => context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.updateOption(updatedOption)),
),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0), padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: MouseRegion( child: MouseRegion(
onEnter: (_) { onEnter: (_) => context.read<SelectOptionCellEditorBloc>().add(
context.read<SelectOptionCellEditorBloc>().add( SelectOptionCellEditorEvent.updateFocusedOption(
SelectOptionCellEditorEvent.updateFocusedOption( widget.option.id,
widget.option.id, ),
), ),
);
},
child: Container( child: Container(
height: 28, height: 28,
decoration: BoxDecoration( decoration: BoxDecoration(
@ -382,42 +393,16 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
), ),
), ),
), ),
popupBuilder: (BuildContext popoverContext) {
return SelectOptionEditor(
option: widget.option,
onDeleted: () {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.deleteOption(widget.option));
PopoverContainer.of(popoverContext).close();
},
onUpdated: (updatedOption) {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.updateOption(updatedOption));
},
key: ValueKey(
widget.option.id,
), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
);
},
); );
} }
void _onTap() { void _onTap() {
widget.popoverMutex.close(); widget.popoverMutex.close();
if (context final bloc = context.read<SelectOptionCellEditorBloc>();
.read<SelectOptionCellEditorBloc>() if (bloc.state.selectedOptions.contains(widget.option)) {
.state bloc.add(SelectOptionCellEditorEvent.unselectOption(widget.option.id));
.selectedOptions
.contains(widget.option)) {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.unSelectOption(widget.option.id));
} else { } else {
context bloc.add(SelectOptionCellEditorEvent.selectOption(widget.option.id));
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.selectOption(widget.option.id));
} }
} }
} }
@ -472,13 +457,14 @@ class SelectOptionTagCell extends StatelessWidget {
child: Align( child: Align(
alignment: AlignmentDirectional.centerStart, alignment: AlignmentDirectional.centerStart,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 6.0),
horizontal: 6.0,
),
child: SelectOptionTag( child: SelectOptionTag(
fontSize: 14,
option: option, option: option,
padding: padding: const EdgeInsets.symmetric(
const EdgeInsets.symmetric(horizontal: 8, vertical: 4), horizontal: 8,
vertical: 2,
),
), ),
), ),
), ),
@ -492,16 +478,14 @@ class SelectOptionTagCell extends StatelessWidget {
} }
class _CreateOptionCell extends StatelessWidget { class _CreateOptionCell extends StatelessWidget {
const _CreateOptionCell({ const _CreateOptionCell({required this.suggestion});
required this.suggestion,
});
final CreateSelectOptionSuggestion suggestion; final CreateSelectOptionSuggestion suggestion;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Container( return Container(
height: 28, height: 32,
margin: const EdgeInsets.symmetric(horizontal: 8.0), margin: const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration( decoration: BoxDecoration(
@ -537,10 +521,10 @@ class _CreateOptionCell extends StatelessWidget {
child: SelectOptionTag( child: SelectOptionTag(
name: suggestion.name, name: suggestion.name,
color: suggestion.color.toColor(context), color: suggestion.color.toColor(context),
fontSize: 11, fontSize: 14,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
horizontal: 8, horizontal: 8,
vertical: 1, vertical: 2,
), ),
), ),
), ),

View File

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra/colorscheme/default_colorscheme.dart'; import 'package:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart';
class AppFlowyPopover extends StatelessWidget { class AppFlowyPopover extends StatelessWidget {
final Widget child; final Widget child;
@ -152,7 +153,7 @@ extension on BuildContext {
side: BorderSide( side: BorderSide(
width: 1, width: 1,
strokeAlign: BorderSide.strokeAlignOutside, strokeAlign: BorderSide.strokeAlignOutside,
color: borderColor, color: color != Colors.transparent ? borderColor : color!,
), ),
borderRadius: borderRadius ?? BorderRadius.circular(10), borderRadius: borderRadius ?? BorderRadius.circular(10),
), ),

View File

@ -123,7 +123,7 @@ void main() {
await gridResponseFuture(); await gridResponseFuture();
final optionId = bloc.state.options[0].id; final optionId = bloc.state.options[0].id;
bloc.add(SelectOptionCellEditorEvent.unSelectOption(optionId)); bloc.add(SelectOptionCellEditorEvent.unselectOption(optionId));
await gridResponseFuture(); await gridResponseFuture();
assert(bloc.state.selectedOptions.isEmpty); assert(bloc.state.selectedOptions.isEmpty);