mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: focus traversal in checklist popover (#4843)
* fix: focus traversal in checklist popover * fix: dont trim input * chore: remove redundant state var * chore: remove late from controller
This commit is contained in:
parent
677617dcf2
commit
cd245b5f0a
@ -1,11 +1,12 @@
|
||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/plugins/database/application/cell/bloc/checklist_cell_bloc.dart';
|
||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
|
||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../editable_cell_skeleton/checklist.dart';
|
||||
@ -25,6 +26,7 @@ class DesktopGridChecklistCellSkin extends IEditableChecklistCellSkin {
|
||||
constraints: BoxConstraints.loose(const Size(360, 400)),
|
||||
direction: PopoverDirection.bottomWithLeftAligned,
|
||||
triggerActions: PopoverTriggerFlags.none,
|
||||
skipTraversal: true,
|
||||
popupBuilder: (BuildContext popoverContext) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
cellContainerNotifier.isFocus = true;
|
||||
|
@ -1,6 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
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/cell_controller_builder.dart';
|
||||
@ -11,11 +14,10 @@ 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';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
|
||||
import '../../application/cell/bloc/checklist_cell_bloc.dart';
|
||||
|
||||
import 'checklist_progress_bar.dart';
|
||||
|
||||
class ChecklistCellEditor extends StatefulWidget {
|
||||
@ -345,12 +347,11 @@ class NewTaskItem extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _NewTaskItemState extends State<NewTaskItem> {
|
||||
late final TextEditingController _textEditingController;
|
||||
final _textEditingController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_textEditingController = TextEditingController();
|
||||
if (widget.focusNode.canRequestFocus) {
|
||||
widget.focusNode.requestFocus();
|
||||
}
|
||||
@ -385,15 +386,13 @@ class _NewTaskItemState extends State<NewTaskItem> {
|
||||
hintText: LocaleKeys.grid_checklist_addNew.tr(),
|
||||
),
|
||||
onSubmitted: (taskDescription) {
|
||||
if (taskDescription.trim().isNotEmpty) {
|
||||
context.read<ChecklistCellBloc>().add(
|
||||
ChecklistCellEvent.createNewTask(
|
||||
taskDescription.trim(),
|
||||
),
|
||||
);
|
||||
if (taskDescription.isNotEmpty) {
|
||||
context
|
||||
.read<ChecklistCellBloc>()
|
||||
.add(ChecklistCellEvent.createNewTask(taskDescription));
|
||||
_textEditingController.clear();
|
||||
}
|
||||
widget.focusNode.requestFocus();
|
||||
_textEditingController.clear();
|
||||
},
|
||||
onChanged: (value) => setState(() {}),
|
||||
),
|
||||
@ -409,16 +408,17 @@ class _NewTaskItemState extends State<NewTaskItem> {
|
||||
: Theme.of(context).colorScheme.primaryContainer,
|
||||
fontColor: Theme.of(context).colorScheme.onPrimary,
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
onPressed: () {
|
||||
final text = _textEditingController.text.trim();
|
||||
if (text.isNotEmpty) {
|
||||
context.read<ChecklistCellBloc>().add(
|
||||
ChecklistCellEvent.createNewTask(text),
|
||||
);
|
||||
}
|
||||
widget.focusNode.requestFocus();
|
||||
_textEditingController.clear();
|
||||
},
|
||||
onPressed: _textEditingController.text.isEmpty
|
||||
? null
|
||||
: () {
|
||||
context.read<ChecklistCellBloc>().add(
|
||||
ChecklistCellEvent.createNewTask(
|
||||
_textEditingController.text,
|
||||
),
|
||||
);
|
||||
widget.focusNode.requestFocus();
|
||||
_textEditingController.clear();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:appflowy_popover/src/layout.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy_popover/src/layout.dart';
|
||||
|
||||
import 'mask.dart';
|
||||
import 'mutex.dart';
|
||||
|
||||
@ -90,6 +91,8 @@ class Popover extends StatefulWidget {
|
||||
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
||||
final PopoverClickHandler clickHandler;
|
||||
|
||||
final bool skipTraversal;
|
||||
|
||||
/// The content area of the popover.
|
||||
final Widget child;
|
||||
|
||||
@ -110,6 +113,7 @@ class Popover extends StatefulWidget {
|
||||
this.canClose,
|
||||
this.asBarrier = false,
|
||||
this.clickHandler = PopoverClickHandler.listener,
|
||||
this.skipTraversal = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -158,6 +162,7 @@ class PopoverState extends State<Popover> {
|
||||
popupBuilder: widget.popupBuilder,
|
||||
onClose: () => close(),
|
||||
onCloseAll: () => _removeRootOverlay(),
|
||||
skipTraversal: widget.skipTraversal,
|
||||
),
|
||||
);
|
||||
|
||||
@ -263,6 +268,7 @@ class PopoverContainer extends StatefulWidget {
|
||||
final EdgeInsets windowPadding;
|
||||
final void Function() onClose;
|
||||
final void Function() onCloseAll;
|
||||
final bool skipTraversal;
|
||||
|
||||
const PopoverContainer({
|
||||
super.key,
|
||||
@ -273,6 +279,7 @@ class PopoverContainer extends StatefulWidget {
|
||||
required this.windowPadding,
|
||||
required this.onClose,
|
||||
required this.onCloseAll,
|
||||
required this.skipTraversal,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -293,6 +300,7 @@ class PopoverContainerState extends State<PopoverContainer> {
|
||||
Widget build(BuildContext context) {
|
||||
return Focus(
|
||||
autofocus: true,
|
||||
skipTraversal: widget.skipTraversal,
|
||||
child: CustomSingleChildLayout(
|
||||
delegate: PopoverLayoutDelegate(
|
||||
direction: widget.direction,
|
||||
|
@ -26,6 +26,10 @@ class AppFlowyPopover extends StatelessWidget {
|
||||
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
||||
final PopoverClickHandler clickHandler;
|
||||
|
||||
/// If true the popover will not participate in focus traversal.
|
||||
///
|
||||
final bool skipTraversal;
|
||||
|
||||
const AppFlowyPopover({
|
||||
super.key,
|
||||
required this.child,
|
||||
@ -43,6 +47,7 @@ class AppFlowyPopover extends StatelessWidget {
|
||||
this.windowPadding = const EdgeInsets.all(8.0),
|
||||
this.decoration,
|
||||
this.clickHandler = PopoverClickHandler.listener,
|
||||
this.skipTraversal = false,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -58,6 +63,7 @@ class AppFlowyPopover extends StatelessWidget {
|
||||
windowPadding: windowPadding,
|
||||
offset: offset,
|
||||
clickHandler: clickHandler,
|
||||
skipTraversal: skipTraversal,
|
||||
popupBuilder: (context) {
|
||||
return _PopoverContainer(
|
||||
constraints: constraints,
|
||||
|
@ -1,12 +1,13 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||
import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowyButton extends StatelessWidget {
|
||||
final Widget text;
|
||||
@ -213,6 +214,7 @@ class FlowyTextButton extends StatelessWidget {
|
||||
);
|
||||
|
||||
child = RawMaterialButton(
|
||||
focusNode: FocusNode(skipTraversal: onPressed == null),
|
||||
hoverElevation: 0,
|
||||
highlightElevation: 0,
|
||||
shape: RoundedRectangleBorder(borderRadius: radius ?? Corners.s6Border),
|
||||
@ -237,6 +239,10 @@ class FlowyTextButton extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
if (onPressed == null) {
|
||||
child = ExcludeFocus(child: child);
|
||||
}
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user