diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart index 2cbbf9e23c..8f6965a8ef 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/checklist_cell/checklist_prograss_bar.dart @@ -56,6 +56,7 @@ class _SliverChecklistPrograssBarDelegate children: [ FlowyTextField( autoClearWhenDone: true, + submitOnLeave: true, hintText: LocaleKeys.grid_checklist_panelTitle.tr(), onChanged: (text) { context diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart index f6a9a72ca9..504a02b3b6 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/cell/select_option_cell/select_option_editor.dart @@ -17,7 +17,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import 'package:textfield_tags/textfield_tags.dart'; import '../../../layout/sizes.dart'; -import '../../common/text_field.dart'; +import '../../common/type_option_separator.dart'; import '../../header/type_option/select_option_editor.dart'; import 'extension.dart'; import 'text_field.dart'; diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart deleted file mode 100644 index 8714427303..0000000000 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/text_field.dart +++ /dev/null @@ -1,108 +0,0 @@ -import 'package:flowy_infra_ui/widget/rounded_input_field.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; - -class InputTextField extends StatefulWidget { - final void Function(String)? onDone; - final void Function(String)? onChanged; - final void Function() onCanceled; - final bool autoClearWhenDone; - final String text; - final int? maxLength; - final FocusNode? focusNode; - - const InputTextField({ - required this.text, - this.onDone, - required this.onCanceled, - this.onChanged, - this.autoClearWhenDone = false, - this.maxLength, - this.focusNode, - Key? key, - }) : super(key: key); - - @override - State createState() => _InputTextFieldState(); -} - -class _InputTextFieldState extends State { - late FocusNode _focusNode; - var isEdited = false; - late TextEditingController _controller; - - @override - void initState() { - _focusNode = widget.focusNode ?? FocusNode(); - _controller = TextEditingController(text: widget.text); - SchedulerBinding.instance.addPostFrameCallback((Duration _) { - _focusNode.requestFocus(); - }); - - _focusNode.addListener(notifyDidEndEditing); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return RoundedInputField( - controller: _controller, - focusNode: _focusNode, - autoFocus: true, - height: 36.0, - maxLength: widget.maxLength, - style: Theme.of(context).textTheme.bodyMedium, - onChanged: (text) { - if (widget.onChanged != null) { - widget.onChanged!(text); - } - }, - onEditingComplete: (_) { - if (widget.onDone != null) { - widget.onDone!(_controller.text); - } - - if (widget.autoClearWhenDone) { - _controller.text = ""; - } - }, - ); - } - - @override - void dispose() { - _focusNode.removeListener(notifyDidEndEditing); - // only dispose the focusNode if it was created in this widget's initState - if (widget.focusNode == null) { - _focusNode.dispose(); - } - super.dispose(); - } - - void notifyDidEndEditing() { - if (!_focusNode.hasFocus) { - if (_controller.text.isEmpty) { - widget.onCanceled(); - } else { - if (widget.onDone != null) { - widget.onDone!(_controller.text); - } - } - } - } -} - -class TypeOptionSeparator extends StatelessWidget { - const TypeOptionSeparator({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.symmetric(vertical: 6), - child: Container( - color: Theme.of(context).dividerColor, - height: 1.0, - ), - ); - } -} diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/type_option_separator.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/type_option_separator.dart new file mode 100644 index 0000000000..f00c1c30f4 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/common/type_option_separator.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; + +class TypeOptionSeparator extends StatelessWidget { + const TypeOptionSeparator({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 6), + child: Container( + color: Theme.of(context).dividerColor, + height: 1.0, + ), + ); + } +} diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart index 92ab58e11b..359c9b1c90 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/date.dart @@ -13,7 +13,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import '../../../layout/sizes.dart'; -import '../../common/text_field.dart'; +import '../../common/type_option_separator.dart'; import '../field_type_option_editor.dart'; import 'builder.dart'; diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart index 00be72ee50..ef3df6ba71 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/number.dart @@ -13,7 +13,7 @@ import 'package:easy_localization/easy_localization.dart' hide NumberFormat; import 'package:app_flowy/generated/locale_keys.g.dart'; import '../../../layout/sizes.dart'; -import '../../common/text_field.dart'; +import '../../common/type_option_separator.dart'; import '../field_type_option_editor.dart'; import 'builder.dart'; @@ -182,12 +182,10 @@ class _FilterTextField extends StatelessWidget { const _FilterTextField({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - return InputTextField( - text: "", - onCanceled: () {}, - onChanged: (text) { - context.read().add(NumberFormatEvent.setFilter(text)); - }, + return FlowyTextField( + onChanged: (text) => context + .read() + .add(NumberFormatEvent.setFilter(text)), ); } } diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart index f78a3bc5a4..97c94f0b87 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option.dart @@ -12,7 +12,7 @@ import 'package:app_flowy/generated/locale_keys.g.dart'; import '../../../layout/sizes.dart'; import '../../cell/select_option_cell/extension.dart'; -import '../../common/text_field.dart'; +import '../../common/type_option_separator.dart'; import 'select_option_editor.dart'; class SelectOptionTypeOptionWidget extends StatelessWidget { @@ -282,7 +282,7 @@ class _CreateOptionTextFieldState extends State<_CreateOptionTextField> { return BlocBuilder( builder: (context, state) { final text = state.newOptionName.foldRight("", (a, previous) => a); - return InputTextField( + return FlowyTextField( autoClearWhenDone: true, maxLength: 30, text: text, @@ -292,7 +292,8 @@ class _CreateOptionTextFieldState extends State<_CreateOptionTextField> { .read() .add(const SelectOptionTypeOptionEvent.endAddingOption()); }, - onDone: (optionName) { + onEditingComplete: () {}, + onSubmitted: (optionName) { context .read() .add(SelectOptionTypeOptionEvent.createOption(optionName)); diff --git a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart index 9db22f8d88..2c1ce69d3e 100644 --- a/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart +++ b/frontend/app_flowy/lib/plugins/grid/presentation/widgets/header/type_option/select_option_editor.dart @@ -13,7 +13,7 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:app_flowy/generated/locale_keys.g.dart'; import '../../../layout/sizes.dart'; -import '../../common/text_field.dart'; +import '../../common/type_option_separator.dart'; class SelectOptionTypeOptionEditor extends StatelessWidget { final SelectOptionPB option; @@ -126,6 +126,7 @@ class _OptionNameTextField extends StatelessWidget { autoFocus: autoFocus, text: name, maxLength: 30, + submitOnLeave: true, onSubmitted: (newName) { if (name != newName) { context diff --git a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart index bea515fb46..b34864064e 100644 --- a/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart +++ b/frontend/app_flowy/packages/flowy_infra_ui/lib/style_widget/text_field.dart @@ -9,24 +9,30 @@ class FlowyTextField extends StatefulWidget { final String hintText; final String text; final void Function(String)? onChanged; + final void Function()? onEditingComplete; final void Function(String)? onSubmitted; final void Function()? onCanceled; + final FocusNode? focusNode; final bool autoFocus; final int? maxLength; final TextEditingController? controller; final bool autoClearWhenDone; + final bool submitOnLeave; final Duration? debounceDuration; const FlowyTextField({ this.hintText = "", this.text = "", this.onChanged, + this.onEditingComplete, this.onSubmitted, this.onCanceled, + this.focusNode, this.autoFocus = true, this.maxLength, this.controller, this.autoClearWhenDone = false, + this.submitOnLeave = false, this.debounceDuration, Key? key, }) : super(key: key); @@ -42,7 +48,7 @@ class FlowyTextFieldState extends State { @override void initState() { - focusNode = FocusNode(); + focusNode = widget.focusNode ?? FocusNode(); focusNode.addListener(notifyDidEndEditing); if (widget.controller != null) { @@ -77,6 +83,7 @@ class FlowyTextFieldState extends State { widget.onSubmitted?.call(text); if (widget.autoClearWhenDone) { controller.text = ""; + setState(() {}); } } @@ -93,6 +100,7 @@ class FlowyTextFieldState extends State { } }, onSubmitted: (text) => _onSubmitted(text), + onEditingComplete: widget.onEditingComplete, maxLines: 1, maxLength: widget.maxLength, maxLengthEnforcement: MaxLengthEnforcement.truncateAfterCompositionEnds, @@ -102,7 +110,7 @@ class FlowyTextFieldState extends State { const EdgeInsets.symmetric(horizontal: 10, vertical: 13), enabledBorder: OutlineInputBorder( borderSide: BorderSide( - color: Theme.of(context).colorScheme.primary, + color: Theme.of(context).colorScheme.outline, width: 1.0, ), borderRadius: Corners.s10Border, @@ -135,10 +143,10 @@ class FlowyTextFieldState extends State { void notifyDidEndEditing() { if (!focusNode.hasFocus) { - if (controller.text.isEmpty) { - widget.onCanceled?.call(); - } else { + if (controller.text.isNotEmpty && widget.submitOnLeave) { widget.onSubmitted?.call(controller.text); + } else { + widget.onCanceled?.call(); } } }