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 'package:flutter/widgets.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/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/protobuf/flowy-database2/protobuf.dart';
import 'package:collection/collection.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -109,16 +110,16 @@ class SelectOptionCellEditorBloc
selectOption: (optionId) async {
await _selectOptionService.select(optionIds: [optionId]);
},
unSelectOption: (optionId) async {
await _selectOptionService.unSelect(optionIds: [optionId]);
unselectOption: (optionId) async {
await _selectOptionService.unselect(optionIds: [optionId]);
},
unSelectLastOption: () async {
unselectLastOption: () async {
if (state.selectedOptions.isEmpty) {
return;
}
final lastSelectedOptionId = state.selectedOptions.last.id;
await _selectOptionService
.unSelect(optionIds: [lastSelectedOptionId]);
.unselect(optionIds: [lastSelectedOptionId]);
},
submitTextField: () {
_submitTextFieldValue(emit);
@ -353,10 +354,10 @@ class SelectOptionCellEditorEvent with _$SelectOptionCellEditorEvent {
const factory SelectOptionCellEditorEvent.createOption() = _CreateOption;
const factory SelectOptionCellEditorEvent.selectOption(String optionId) =
_SelectOption;
const factory SelectOptionCellEditorEvent.unSelectOption(String optionId) =
_UnSelectOption;
const factory SelectOptionCellEditorEvent.unSelectLastOption() =
_UnSelectLastOption;
const factory SelectOptionCellEditorEvent.unselectOption(String optionId) =
_UnselectOption;
const factory SelectOptionCellEditorEvent.unselectLastOption() =
_UnselectLastOption;
const factory SelectOptionCellEditorEvent.updateOption(
SelectOptionPB option,
) = _UpdateOption;

View File

@ -70,7 +70,7 @@ class SelectOptionCellBackendService {
return DatabaseEventUpdateSelectOptionCell(payload).send();
}
Future<FlowyResult<void, FlowyError>> unSelect({
Future<FlowyResult<void, FlowyError>> unselect({
required Iterable<String> optionIds,
}) {
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/locale_keys.g.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:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:protobuf/protobuf.dart';
@ -176,7 +177,7 @@ class _MobileSelectOptionEditorState extends State<MobileSelectOptionEditor> {
} else {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.unSelectOption(option.id));
.add(SelectOptionCellEditorEvent.unselectOption(option.id));
}
},
onMoreOptions: (option) {

View File

@ -1,6 +1,10 @@
import 'dart:collection';
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/locale_keys.g.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:flowy_infra/theme_extension.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 '../../grid/presentation/layout/sizes.dart';
import '../../grid/presentation/widgets/common/type_option_separator.dart';
import '../field/type_option_editor/select/select_option_editor.dart';
import 'extension.dart';
import 'select_option_text_field.dart';
@ -73,7 +74,7 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
break;
case LogicalKeyboardKey.backspace when event is KeyUpEvent:
if (!textEditingController.text.isNotEmpty) {
bloc.add(const SelectOptionCellEditorEvent.unSelectLastOption());
bloc.add(const SelectOptionCellEditorEvent.unselectLastOption());
return KeyEventResult.handled;
}
break;
@ -137,8 +138,7 @@ class _OptionList extends StatelessWidget {
Widget build(BuildContext context) {
return BlocConsumer<SelectOptionCellEditorBloc,
SelectOptionCellEditorState>(
listenWhen: (previous, current) =>
previous.clearFilter != current.clearFilter,
listenWhen: (prev, curr) => prev.clearFilter != curr.clearFilter,
listener: (context, state) {
if (state.clearFilter) {
textEditingController.clear();
@ -151,60 +151,66 @@ class _OptionList extends StatelessWidget {
!listEquals(previous.options, current.options) ||
previous.createSelectOptionSuggestion !=
current.createSelectOptionSuggestion,
builder: (context, state) {
return ReorderableListView.builder(
shrinkWrap: true,
proxyDecorator: (child, index, _) => Material(
color: Colors.transparent,
child: Stack(
children: [
BlocProvider.value(
value: context.read<SelectOptionCellEditorBloc>(),
child: child,
),
MouseRegion(
cursor: Platform.isWindows
? SystemMouseCursors.click
: SystemMouseCursors.grabbing,
child: const SizedBox.expand(),
),
],
),
builder: (context, state) => ReorderableListView.builder(
shrinkWrap: true,
proxyDecorator: (child, index, _) => Material(
color: Colors.transparent,
child: Stack(
children: [
BlocProvider.value(
value: context.read<SelectOptionCellEditorBloc>(),
child: child,
),
MouseRegion(
cursor: Platform.isWindows
? SystemMouseCursors.click
: SystemMouseCursors.grabbing,
child: const SizedBox.expand(),
),
],
),
buildDefaultDragHandles: false,
itemCount: state.options.length,
onReorderStart: (_) => popoverMutex.close(),
itemBuilder: (_, int index) {
final option = state.options[index];
return _SelectOptionCell(
key: ValueKey("select_cell_option_list_${option.id}"),
index: index,
option: option,
popoverMutex: popoverMutex,
);
},
onReorder: (oldIndex, newIndex) {
if (oldIndex < newIndex) {
newIndex--;
}
final fromOptionId = state.options[oldIndex].id;
final toOptionId = state.options[newIndex].id;
context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.reorderOption(
fromOptionId,
toOptionId,
),
);
},
header: const _Title(),
footer: state.createSelectOptionSuggestion == null
? null
: _CreateOptionCell(
suggestion: state.createSelectOptionSuggestion!,
),
buildDefaultDragHandles: false,
itemCount: state.options.length,
onReorderStart: (_) => popoverMutex.close(),
itemBuilder: (_, int index) {
final option = state.options[index];
return _SelectOptionCell(
key: ValueKey("select_cell_option_list_${option.id}"),
index: index,
option: option,
popoverMutex: popoverMutex,
);
},
onReorder: (oldIndex, newIndex) {
if (oldIndex < newIndex) {
newIndex--;
}
final fromOptionId = state.options[oldIndex].id;
final toOptionId = state.options[newIndex].id;
context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.reorderOption(
fromOptionId,
toOptionId,
),
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,
textSeparators: const [','],
onClick: () => popoverMutex.close(),
newText: (text) {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.filterOption(text));
},
newText: (text) => context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.filterOption(text)),
onSubmitted: () {
context
.read<SelectOptionCellEditorBloc>()
@ -264,13 +268,12 @@ class _TextField extends StatelessWidget {
),
);
},
onRemove: (optionName) {
context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.unSelectOption(
optionMap[optionName]!.id,
onRemove: (name) =>
context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.unselectOption(
optionMap[name]!.id,
),
),
);
},
),
),
);
@ -286,12 +289,9 @@ class _Title extends StatelessWidget {
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: SizedBox(
height: GridSize.popoverItemHeight,
child: FlowyText.regular(
LocaleKeys.grid_selectOption_panelTitle.tr(),
color: Theme.of(context).hintColor,
),
child: FlowyText.regular(
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)),
mutex: widget.popoverMutex,
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(
padding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 2.0),
child: MouseRegion(
onEnter: (_) {
context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.updateFocusedOption(
widget.option.id,
),
);
},
onEnter: (_) => context.read<SelectOptionCellEditorBloc>().add(
SelectOptionCellEditorEvent.updateFocusedOption(
widget.option.id,
),
),
child: Container(
height: 28,
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() {
widget.popoverMutex.close();
if (context
.read<SelectOptionCellEditorBloc>()
.state
.selectedOptions
.contains(widget.option)) {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.unSelectOption(widget.option.id));
final bloc = context.read<SelectOptionCellEditorBloc>();
if (bloc.state.selectedOptions.contains(widget.option)) {
bloc.add(SelectOptionCellEditorEvent.unselectOption(widget.option.id));
} else {
context
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionCellEditorEvent.selectOption(widget.option.id));
bloc.add(SelectOptionCellEditorEvent.selectOption(widget.option.id));
}
}
}
@ -472,13 +457,14 @@ class SelectOptionTagCell extends StatelessWidget {
child: Align(
alignment: AlignmentDirectional.centerStart,
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: 6.0,
),
padding: const EdgeInsets.symmetric(horizontal: 6.0),
child: SelectOptionTag(
fontSize: 14,
option: option,
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 2,
),
),
),
),
@ -492,16 +478,14 @@ class SelectOptionTagCell extends StatelessWidget {
}
class _CreateOptionCell extends StatelessWidget {
const _CreateOptionCell({
required this.suggestion,
});
const _CreateOptionCell({required this.suggestion});
final CreateSelectOptionSuggestion suggestion;
@override
Widget build(BuildContext context) {
return Container(
height: 28,
height: 32,
margin: const EdgeInsets.symmetric(horizontal: 8.0),
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
@ -537,10 +521,10 @@ class _CreateOptionCell extends StatelessWidget {
child: SelectOptionTag(
name: suggestion.name,
color: suggestion.color.toColor(context),
fontSize: 11,
fontSize: 14,
padding: const EdgeInsets.symmetric(
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:flowy_infra/colorscheme/default_colorscheme.dart';
import 'package:flutter/material.dart';
class AppFlowyPopover extends StatelessWidget {
final Widget child;
@ -152,7 +153,7 @@ extension on BuildContext {
side: BorderSide(
width: 1,
strokeAlign: BorderSide.strokeAlignOutside,
color: borderColor,
color: color != Colors.transparent ? borderColor : color!,
),
borderRadius: borderRadius ?? BorderRadius.circular(10),
),

View File

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