fix: double click to select / unselect options (#4094)

Co-authored-by: Richard Shiue <71320345+richardshiue@users.noreply.github.com>
This commit is contained in:
Lucas.Xu 2023-12-05 20:23:20 +08:00 committed by GitHub
parent 7d55153475
commit 48d6967d3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 79 additions and 50 deletions

View File

@ -1,13 +1,11 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
extension SelectOptionColorExtension on SelectOptionColorPB { extension SelectOptionColorExtension on SelectOptionColorPB {
Color toColor(BuildContext context) { Color toColor(BuildContext context) {
@ -131,33 +129,28 @@ class SelectOptionTagCell extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyHover( return Row(
style: HoverStyle( crossAxisAlignment: CrossAxisAlignment.stretch,
hoverColor: AFThemeExtension.of(context).lightGreyHover, children: [
), Expanded(
child: Row( child: GestureDetector(
crossAxisAlignment: CrossAxisAlignment.stretch, behavior: HitTestBehavior.opaque,
children: [ onTap: onSelected,
Expanded( child: Align(
child: GestureDetector( alignment: AlignmentDirectional.centerStart,
behavior: HitTestBehavior.opaque, child: Padding(
onTap: onSelected, padding: const EdgeInsets.all(5.0),
child: Align( child: SelectOptionTag(
alignment: AlignmentDirectional.centerStart, option: option,
child: Padding( padding:
padding: const EdgeInsets.all(5.0), const EdgeInsets.symmetric(horizontal: 8, vertical: 1),
child: SelectOptionTag(
option: option,
padding:
const EdgeInsets.symmetric(horizontal: 8, vertical: 1),
),
), ),
), ),
), ),
), ),
...children, ),
], ...children,
), ],
); );
} }
} }

View File

@ -6,9 +6,9 @@ import 'package:appflowy/plugins/database_view/application/cell/cell_controller_
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; 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:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:textfield_tags/textfield_tags.dart'; import 'package:textfield_tags/textfield_tags.dart';
@ -340,9 +340,16 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
asBarrier: true, asBarrier: true,
constraints: BoxConstraints.loose(const Size(200, 470)), constraints: BoxConstraints.loose(const Size(200, 470)),
mutex: widget.popoverMutex, mutex: widget.popoverMutex,
clickHandler: PopoverClickHandler.gestureDetector,
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0), padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: child, child: FlowyHover(
resetHoverOnRebuild: false,
style: HoverStyle(
hoverColor: AFThemeExtension.of(context).lightGreyHover,
),
child: child,
),
), ),
popupBuilder: (BuildContext popoverContext) { popupBuilder: (BuildContext popoverContext) {
return SelectOptionTypeOptionEditor( return SelectOptionTypeOptionEditor(

View File

@ -1,10 +1,12 @@
import 'dart:async'; import 'dart:async';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart'; import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/select_option.pb.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/log.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';
import '../../../../application/cell/select_option_cell_service.dart'; import '../../../../application/cell/select_option_cell_service.dart';
part 'select_option_editor_bloc.freezed.dart'; part 'select_option_editor_bloc.freezed.dart';
@ -61,9 +63,27 @@ class SelectOptionCellEditorBloc
}, },
selectOption: (_SelectOption value) async { selectOption: (_SelectOption value) async {
await _selectOptionService.select(optionIds: [value.optionId]); await _selectOptionService.select(optionIds: [value.optionId]);
final selectedOption = [
...state.selectedOptions,
state.options.firstWhere(
(element) => element.id == value.optionId,
),
];
emit(
state.copyWith(
selectedOptions: selectedOption,
),
);
}, },
unSelectOption: (_UnSelectOption value) async { unSelectOption: (_UnSelectOption value) async {
await _selectOptionService.unSelect(optionIds: [value.optionId]); await _selectOptionService.unSelect(optionIds: [value.optionId]);
final selectedOptions = [...state.selectedOptions]
..removeWhere((e) => e.id == value.optionId);
emit(
state.copyWith(
selectedOptions: selectedOptions,
),
);
}, },
trySelectOption: (_TrySelectOption value) { trySelectOption: (_TrySelectOption value) {
_trySelectOption(value.optionName, emit); _trySelectOption(value.optionName, emit);

View File

@ -138,7 +138,7 @@ class _PropertyCellState extends State<_PropertyCell> {
final PopoverController _popoverController = PopoverController(); final PopoverController _popoverController = PopoverController();
final PopoverController _fieldPopoverController = PopoverController(); final PopoverController _fieldPopoverController = PopoverController();
bool _isFieldHover = false; final ValueNotifier<bool> _isFieldHover = ValueNotifier(false);
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -159,15 +159,19 @@ class _PropertyCellState extends State<_PropertyCell> {
triggerActions: PopoverTriggerFlags.none, triggerActions: PopoverTriggerFlags.none,
direction: PopoverDirection.bottomWithLeftAligned, direction: PopoverDirection.bottomWithLeftAligned,
popupBuilder: (popoverContext) => buildFieldEditor(), popupBuilder: (popoverContext) => buildFieldEditor(),
child: _isFieldHover child: ValueListenableBuilder(
? BlockActionButton( valueListenable: _isFieldHover,
onTap: () => _fieldPopoverController.show(), builder: ((context, value, child) {
svg: FlowySvgs.drag_element_s, return value ? child! : const SizedBox.shrink();
richMessage: TextSpan( }),
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(), child: BlockActionButton(
), onTap: () => _fieldPopoverController.show(),
) svg: FlowySvgs.drag_element_s,
: const SizedBox.shrink(), richMessage: TextSpan(
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
),
),
),
), ),
), ),
); );
@ -185,16 +189,21 @@ class _PropertyCellState extends State<_PropertyCell> {
margin: const EdgeInsets.only(bottom: 8), margin: const EdgeInsets.only(bottom: 8),
constraints: const BoxConstraints(minHeight: 30), constraints: const BoxConstraints(minHeight: 30),
child: MouseRegion( child: MouseRegion(
onEnter: (event) => setState(() => _isFieldHover = true), onEnter: (event) => _isFieldHover.value = true,
onExit: (event) => setState(() => _isFieldHover = false), onExit: (event) => _isFieldHover.value = false,
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
ReorderableDragStartListener( ValueListenableBuilder(
index: widget.index, valueListenable: _isFieldHover,
enabled: _isFieldHover, builder: (context, value, _) {
child: dragThumb, return ReorderableDragStartListener(
index: widget.index,
enabled: value,
child: dragThumb,
);
},
), ),
const HSpace(4), const HSpace(4),
AppFlowyPopover( AppFlowyPopover(