fix: kanban board card text input inconsistency (#5307)

This commit is contained in:
Richard Shiue 2024-05-10 11:25:22 +08:00 committed by GitHub
parent c732438f8a
commit f47c88b022
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -55,18 +55,26 @@ class _TextCellState extends State<TextCardCell> {
widget.cellContext, widget.cellContext,
).as(), ).as(),
); );
late final TextEditingController _textEditingController = late final TextEditingController _textEditingController;
TextEditingController(text: cellBloc.state.content);
final focusNode = SingleListenerFocusNode(); final focusNode = SingleListenerFocusNode();
bool focusWhenInit = false;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
focusWhenInit = widget.editableNotifier?.isCellEditing.value ?? false;
if (focusWhenInit) { _textEditingController = TextEditingController(text: cellBloc.state.content)
..addListener(() {
if (_textEditingController.value.composing.isCollapsed) {
cellBloc
.add(TextCellEvent.updateText(_textEditingController.value.text));
}
});
if (widget.editableNotifier?.isCellEditing.value ?? false) {
WidgetsBinding.instance.addPostFrameCallback((_) {
focusNode.requestFocus(); focusNode.requestFocus();
cellBloc.add(const TextCellEvent.enableEdit(true));
});
} }
// If the focusNode lost its focus, the widget's editableNotifier will // If the focusNode lost its focus, the widget's editableNotifier will
@ -74,7 +82,6 @@ class _TextCellState extends State<TextCardCell> {
// end edit event. // end edit event.
focusNode.addListener(() { focusNode.addListener(() {
if (!focusNode.hasFocus) { if (!focusNode.hasFocus) {
focusWhenInit = false;
widget.editableNotifier?.isCellEditing.value = false; widget.editableNotifier?.isCellEditing.value = false;
cellBloc.add(const TextCellEvent.enableEdit(false)); cellBloc.add(const TextCellEvent.enableEdit(false));
} }
@ -100,45 +107,25 @@ class _TextCellState extends State<TextCardCell> {
@override @override
void didUpdateWidget(covariant oldWidget) { void didUpdateWidget(covariant oldWidget) {
if (oldWidget.editableNotifier != widget.editableNotifier) {
_bindEditableNotifier(); _bindEditableNotifier();
}
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isTitle = cellBloc.cellController.fieldInfo.isPrimary;
return BlocProvider.value( return BlocProvider.value(
value: cellBloc, value: cellBloc,
child: BlocConsumer<TextCellBloc, TextCellState>( child: BlocListener<TextCellBloc, TextCellState>(
listenWhen: (previous, current) => previous.content != current.content, listenWhen: (previous, current) => previous.content != current.content,
listener: (context, state) { listener: (context, state) {
if (!state.enableEdit) { if (!state.enableEdit) {
_textEditingController.text = state.content; _textEditingController.text = state.content;
} }
}, },
builder: (context, state) { child: isTitle ? _buildTitle() : _buildText(),
final isTitle = cellBloc.cellController.fieldInfo.isPrimary;
if (state.content.isEmpty &&
state.enableEdit == false &&
focusWhenInit == false &&
!isTitle) {
return const SizedBox.shrink();
}
final icon = isTitle ? _buildIcon(state) : null;
final child = isTitle
? _buildTextField(state.enableEdit || focusWhenInit)
: _buildText(state.content);
return Row(
children: [
if (icon != null) ...[
icon,
const HSpace(4.0),
],
Expanded(child: child),
],
);
},
), ),
); );
} }
@ -146,6 +133,8 @@ class _TextCellState extends State<TextCardCell> {
@override @override
void dispose() { void dispose() {
_textEditingController.dispose(); _textEditingController.dispose();
widget.editableNotifier?.isCellEditing
.removeListener(_bindEditableNotifier);
focusNode.dispose(); focusNode.dispose();
cellBloc.close(); cellBloc.close();
super.dispose(); super.dispose();
@ -170,9 +159,13 @@ class _TextCellState extends State<TextCardCell> {
return null; return null;
} }
Widget _buildText(String content) { Widget _buildText() {
final text = return BlocBuilder<TextCellBloc, TextCellState>(
content.isEmpty ? LocaleKeys.grid_row_textPlaceholder.tr() : content; builder: (context, state) {
final content = state.content;
final text = content.isEmpty
? LocaleKeys.grid_row_textPlaceholder.tr()
: content;
final color = content.isEmpty ? Theme.of(context).hintColor : null; final color = content.isEmpty ? Theme.of(context).hintColor : null;
return Padding( return Padding(
@ -183,11 +176,32 @@ class _TextCellState extends State<TextCardCell> {
maxLines: widget.style.maxLines, maxLines: widget.style.maxLines,
), ),
); );
},
);
} }
Widget _buildTextField(bool isEditing) { Widget _buildTitle() {
final padding = final textField = _buildTextField();
widget.style.padding.add(const EdgeInsets.symmetric(vertical: 4.0)); return BlocBuilder<TextCellBloc, TextCellState>(
builder: (context, state) {
final icon = _buildIcon(state);
return Row(
children: [
if (icon != null) ...[
icon,
const HSpace(4.0),
],
Expanded(child: textField),
],
);
},
);
}
Widget _buildTextField() {
return BlocSelector<TextCellBloc, TextCellState, bool>(
selector: (state) => state.enableEdit,
builder: (context, isEditing) {
return IgnorePointer( return IgnorePointer(
ignoring: !isEditing, ignoring: !isEditing,
child: CallbackShortcuts( child: CallbackShortcuts(
@ -198,12 +212,6 @@ class _TextCellState extends State<TextCardCell> {
child: TextField( child: TextField(
controller: _textEditingController, controller: _textEditingController,
focusNode: focusNode, focusNode: focusNode,
onChanged: (_) {
if (_textEditingController.value.composing.isCollapsed) {
cellBloc
.add(TextCellEvent.updateText(_textEditingController.text));
}
},
onEditingComplete: () => focusNode.unfocus(), onEditingComplete: () => focusNode.unfocus(),
maxLines: isEditing ? null : 2, maxLines: isEditing ? null : 2,
minLines: 1, minLines: 1,
@ -212,7 +220,8 @@ class _TextCellState extends State<TextCardCell> {
enableInteractiveSelection: isEditing, enableInteractiveSelection: isEditing,
style: widget.style.titleTextStyle, style: widget.style.titleTextStyle,
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: padding, contentPadding: widget.style.padding
.add(const EdgeInsets.symmetric(vertical: 4.0)),
border: InputBorder.none, border: InputBorder.none,
enabledBorder: InputBorder.none, enabledBorder: InputBorder.none,
isDense: true, isDense: true,
@ -226,5 +235,7 @@ class _TextCellState extends State<TextCardCell> {
), ),
), ),
); );
},
);
} }
} }