Skip to content

Commit 79c4169

Browse files
authored
merge: pull request #630 from hm21/dev
feat(text-editor): replace `EditableText` with `TextField` to enhance text selection and overall input handling
2 parents da04ee5 + 9a19208 commit 79c4169

File tree

4 files changed

+49
-152
lines changed

4 files changed

+49
-152
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## 11.3.0
4+
- **FEAT**(text-editor): Replace `EditableText` with `TextField` to enhance text selection and overall input handling.
5+
36
## 11.2.3
47
- **FIX**(multiselect): Resolve issue where layers could still be selected even when `enableSelection` for the layer was set to `false`. This resolves issue [#628](https://github.com/hm21/pro_image_editor/issues/628).
58

lib/features/text_editor/widgets/rounded_background_text/rounded_background_text_field.dart

Lines changed: 44 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import 'package:flutter/cupertino.dart';
21
import 'package:flutter/material.dart';
32

43
import '/core/models/editor_configs/pro_image_editor_configs.dart';
@@ -27,8 +26,6 @@ class RoundedBackgroundTextField extends StatefulWidget {
2726
this.hint,
2827
this.hintStyle,
2928
this.autofocus = false,
30-
this.showSelectionHandles = false,
31-
this.onSelectionChanged,
3229
this.onChanged,
3330
this.onEditingComplete,
3431
this.onSubmitted,
@@ -62,9 +59,6 @@ class RoundedBackgroundTextField extends StatefulWidget {
6259
/// {@macro flutter.widgets.editableText.autofocus}
6360
final bool autofocus;
6461

65-
/// Whether to show selection handles.
66-
final bool showSelectionHandles;
67-
6862
/// {@macro flutter.widgets.editableText.cursorWidth}
6963
final double cursorWidth;
7064

@@ -87,9 +81,6 @@ class RoundedBackgroundTextField extends StatefulWidget {
8781
/// {@macro flutter.widgets.editableText.onSubmitted}
8882
final ValueChanged<String>? onSubmitted;
8983

90-
/// {@macro flutter.widgets.editableText.onSelectionChanged}
91-
final SelectionChangedCallback? onSelectionChanged;
92-
9384
@override
9485
State<RoundedBackgroundTextField> createState() =>
9586
_RoundedBackgroundTextFieldState();
@@ -100,8 +91,6 @@ class _RoundedBackgroundTextFieldState
10091
late final _textController = widget.controller;
10192
final _scrollCtrl = ScrollController();
10293

103-
final _padding = const EdgeInsets.all(6.0);
104-
10594
@override
10695
void initState() {
10796
super.initState();
@@ -141,10 +130,7 @@ class _RoundedBackgroundTextFieldState
141130
TextAlign.center || _ => Alignment.topCenter,
142131
},
143132
children: [
144-
if (_textController.text.isNotEmpty)
145-
_buildBackgroundText()
146-
else if (widget.hint != null)
147-
_buildHint(fontSize: fontSize),
133+
if (_textController.text.isNotEmpty) _buildBackgroundText(),
148134
_buildEditableText(fontSize: fontSize),
149135
],
150136
);
@@ -177,131 +163,53 @@ class _RoundedBackgroundTextFieldState
177163
}
178164

179165
Widget _buildEditableText({required double fontSize}) {
180-
final theme = Theme.of(context);
181-
final selectionTheme = TextSelectionTheme.of(context);
182-
TextSelectionControls? textSelectionControls;
183-
final bool paintCursorAboveText;
184-
final bool cursorOpacityAnimates;
185-
Offset? cursorOffset;
186-
final Color selectionColor;
187-
Color? autocorrectionTextRectColor;
188-
Radius? cursorRadius = widget.cursorRadius;
189-
190-
switch (theme.platform) {
191-
case TargetPlatform.iOS:
192-
final cupertinoTheme = CupertinoTheme.of(context);
193-
textSelectionControls ??= cupertinoTextSelectionControls;
194-
paintCursorAboveText = true;
195-
cursorOpacityAnimates = true;
196-
selectionColor = selectionTheme.selectionColor ??
197-
cupertinoTheme.primaryColor.withValues(alpha: 0.40);
198-
cursorRadius ??= const Radius.circular(2.0);
199-
cursorOffset = Offset(
200-
iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0);
201-
autocorrectionTextRectColor = selectionColor;
202-
break;
203-
204-
case TargetPlatform.macOS:
205-
final cupertinoTheme = CupertinoTheme.of(context);
206-
textSelectionControls ??= cupertinoDesktopTextSelectionControls;
207-
paintCursorAboveText = true;
208-
cursorOpacityAnimates = true;
209-
selectionColor = selectionTheme.selectionColor ??
210-
cupertinoTheme.primaryColor.withValues(alpha: 0.40);
211-
cursorRadius ??= const Radius.circular(2.0);
212-
cursorOffset = Offset(
213-
iOSHorizontalOffset / MediaQuery.devicePixelRatioOf(context), 0);
214-
break;
215-
216-
case TargetPlatform.android:
217-
case TargetPlatform.fuchsia:
218-
textSelectionControls ??= materialTextSelectionControls;
219-
paintCursorAboveText = false;
220-
cursorOpacityAnimates = false;
221-
selectionColor = selectionTheme.selectionColor ??
222-
theme.colorScheme.primary.withValues(alpha: 0.40);
223-
break;
224-
225-
case TargetPlatform.linux:
226-
case TargetPlatform.windows:
227-
textSelectionControls ??= desktopTextSelectionControls;
228-
paintCursorAboveText = false;
229-
cursorOpacityAnimates = false;
230-
selectionColor = selectionTheme.selectionColor ??
231-
theme.colorScheme.primary.withValues(alpha: 0.40);
232-
break;
233-
}
234-
235-
return Padding(
236-
padding: EdgeInsets.zero,
237-
child: Listener(
238-
behavior: HitTestBehavior.translucent,
239-
onPointerDown: _textController.text.isEmpty
240-
? (_) {
241-
if (View.of(context).viewInsets.bottom <= 0) {
242-
FocusManager.instance.primaryFocus?.unfocus();
243-
widget.focusNode.requestFocus();
244-
}
166+
return Material(
167+
type: MaterialType.transparency,
168+
child: TextField(
169+
onTap: _textController.text.isEmpty &&
170+
View.of(context).viewInsets.bottom <= 0
171+
? () {
172+
FocusManager.instance.primaryFocus?.unfocus();
173+
widget.focusNode.requestFocus();
245174
}
246175
: null,
247-
child: EditableText(
248-
autofocus: widget.autofocus,
249-
controller: _textController,
250-
focusNode: widget.focusNode,
251-
scrollPhysics: const NeverScrollableScrollPhysics(),
252-
scrollController: _scrollCtrl,
253-
scrollPadding: EdgeInsets.zero,
254-
style: widget.style.copyWith(
255-
fontSize: fontSize,
256-
leadingDistribution: TextLeadingDistribution.proportional,
257-
),
258-
textAlign: widget.textAlign,
259-
maxLines: null,
260-
keyboardType: TextInputType.multiline,
261-
backgroundCursorColor: CupertinoColors.inactiveGray,
262-
cursorColor: widget.configs.style.inputCursorColor,
263-
cursorWidth: widget.cursorWidth,
264-
cursorHeight: widget.cursorHeight,
265-
cursorRadius: widget.cursorRadius,
266-
paintCursorAboveText: paintCursorAboveText,
267-
cursorOpacityAnimates: cursorOpacityAnimates,
268-
cursorOffset: cursorOffset,
269-
autocorrectionTextRectColor: autocorrectionTextRectColor,
270-
textCapitalization: TextCapitalization.sentences,
271-
enableInteractiveSelection: true,
272-
selectionColor: selectionColor,
273-
selectionControls: textSelectionControls,
274-
showSelectionHandles: widget.showSelectionHandles,
275-
showCursor: true,
276-
autocorrect: widget.configs.enableAutocorrect,
277-
smartDashesType: SmartDashesType.enabled,
278-
smartQuotesType: SmartQuotesType.enabled,
279-
enableSuggestions: widget.configs.enableSuggestions,
280-
clipBehavior: Clip.hardEdge,
281-
textInputAction: TextInputAction.newline,
282-
onSelectionChanged: widget.onSelectionChanged,
283-
magnifierConfiguration: const TextMagnifierConfiguration(),
284-
onChanged: widget.onChanged,
285-
onEditingComplete: widget.onEditingComplete,
286-
onSubmitted: widget.onSubmitted,
176+
autofocus: widget.autofocus,
177+
controller: _textController,
178+
focusNode: widget.focusNode,
179+
scrollPhysics: const NeverScrollableScrollPhysics(),
180+
scrollController: _scrollCtrl,
181+
scrollPadding: EdgeInsets.zero,
182+
style: widget.style.copyWith(
183+
fontSize: fontSize,
184+
leadingDistribution: TextLeadingDistribution.proportional,
185+
height: 0.0,
287186
),
288-
),
289-
);
290-
}
291-
292-
Widget _buildHint({required double fontSize}) {
293-
final style =
294-
(widget.hintStyle ?? TextStyle(color: Theme.of(context).hintColor))
295-
.copyWith(fontSize: fontSize);
296-
297-
return Positioned(
298-
child: Padding(
299-
padding: _padding,
300-
child: Text(
301-
widget.hint!,
302-
style: style,
303-
textAlign: widget.textAlign,
187+
decoration: InputDecoration.collapsed(
188+
hintText: _textController.text.isEmpty ? widget.hint : '',
189+
hintStyle: (widget.hintStyle ??
190+
TextStyle(color: Theme.of(context).hintColor))
191+
.copyWith(fontSize: fontSize),
192+
maintainHintSize: false,
304193
),
194+
textAlign: widget.textAlign,
195+
maxLines: null,
196+
keyboardType: TextInputType.multiline,
197+
textCapitalization: TextCapitalization.sentences,
198+
textInputAction: TextInputAction.newline,
199+
cursorColor: widget.configs.style.inputCursorColor,
200+
cursorWidth: widget.cursorWidth,
201+
cursorHeight: widget.cursorHeight,
202+
cursorRadius: widget.cursorRadius,
203+
enableInteractiveSelection: true,
204+
showCursor: true,
205+
autocorrect: widget.configs.enableAutocorrect,
206+
smartDashesType: SmartDashesType.enabled,
207+
smartQuotesType: SmartQuotesType.enabled,
208+
enableSuggestions: widget.configs.enableSuggestions,
209+
clipBehavior: Clip.hardEdge,
210+
onChanged: widget.onChanged,
211+
onEditingComplete: widget.onEditingComplete,
212+
onSubmitted: widget.onSubmitted,
305213
),
306214
);
307215
}

lib/features/text_editor/widgets/text_editor_input.dart

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,6 @@ class TextEditorInput extends StatefulWidget {
9393
}
9494

9595
class _TextEditorInputState extends State<TextEditorInput> {
96-
bool _isTextSelected = false;
97-
9896
Widget _flightShuttleBuilder(
9997
BuildContext flightContext,
10098
Animation<double> animation,
@@ -141,6 +139,7 @@ class _TextEditorInputState extends State<TextEditorInput> {
141139
padding: widget.configs.style.textFieldMargin,
142140
child: IntrinsicWidth(
143141
child: SingleChildScrollView(
142+
clipBehavior: Clip.none,
144143
padding: widget.configs.enableAutoOverflow
145144
? null
146145
: const EdgeInsets.symmetric(horizontal: 16.0),
@@ -171,7 +170,6 @@ class _TextEditorInputState extends State<TextEditorInput> {
171170
},
172171
onEditingComplete: widget.callbacks?.handleEditingComplete,
173172
onSubmitted: widget.callbacks?.handleSubmitted,
174-
onSelectionChanged: _handleSelectionChanged,
175173
textAlign:
176174
widget.textCtrl.text.isEmpty ? TextAlign.center : widget.align,
177175
configs: widget.configs,
@@ -191,7 +189,6 @@ class _TextEditorInputState extends State<TextEditorInput> {
191189
decoration: TextDecoration.none,
192190
shadows: [],
193191
),
194-
showSelectionHandles: _isTextSelected,
195192

196193
/// If we edit an layer we focus to the textfield after the
197194
/// hero animation is done
@@ -200,15 +197,4 @@ class _TextEditorInputState extends State<TextEditorInput> {
200197
),
201198
);
202199
}
203-
204-
/// Handles the toggling off or on of the selection Handles based
205-
/// On whether the text is selected or not.
206-
void _handleSelectionChanged(
207-
TextSelection selection,
208-
SelectionChangedCause? cause,
209-
) {
210-
setState(() {
211-
_isTextSelected = selection.isValid && selection.start != selection.end;
212-
});
213-
}
214200
}

pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: pro_image_editor
22
description: "A Flutter image editor: Seamlessly enhance your images with user-friendly editing features."
3-
version: 11.2.3
3+
version: 11.3.0
44
homepage: https://github.com/hm21/pro_image_editor/
55
repository: https://github.com/hm21/pro_image_editor/
66
documentation: https://github.com/hm21/pro_image_editor/

0 commit comments

Comments
 (0)