Skip to content

Commit

Permalink
feature: enanble custom TextSelectionControls (#398)
Browse files Browse the repository at this point in the history
  • Loading branch information
kfdykme authored Aug 11, 2024
1 parent e7c7a9a commit fff4b87
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 33 deletions.
72 changes: 39 additions & 33 deletions packages/fleather/lib/src/widgets/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -286,35 +286,37 @@ class FleatherEditor extends StatefulWidget {

final GlobalKey<EditorState>? editorKey;

const FleatherEditor({
super.key,
required this.controller,
this.editorKey,
this.focusNode,
this.scrollController,
this.scrollable = true,
this.padding = EdgeInsets.zero,
this.autofocus = false,
this.showCursor = true,
this.readOnly = false,
this.autocorrect = true,
this.enableSuggestions = true,
this.enableInteractiveSelection = true,
this.minHeight,
this.maxHeight,
this.maxContentWidth,
this.expands = false,
this.textCapitalization = TextCapitalization.sentences,
this.keyboardAppearance,
this.scrollPhysics,
this.onLaunchUrl,
this.spellCheckConfiguration,
this.clipboardManager = const PlainTextClipboardManager(),
this.clipboardStatus,
this.contextMenuBuilder = defaultContextMenuBuilder,
this.embedBuilder = defaultFleatherEmbedBuilder,
this.linkActionPickerDelegate = defaultLinkActionPickerDelegate,
});
final TextSelectionControls? textSelectionControls;

const FleatherEditor(
{super.key,
required this.controller,
this.editorKey,
this.focusNode,
this.scrollController,
this.scrollable = true,
this.padding = EdgeInsets.zero,
this.autofocus = false,
this.showCursor = true,
this.readOnly = false,
this.autocorrect = true,
this.enableSuggestions = true,
this.enableInteractiveSelection = true,
this.minHeight,
this.maxHeight,
this.maxContentWidth,
this.expands = false,
this.textCapitalization = TextCapitalization.sentences,
this.keyboardAppearance,
this.scrollPhysics,
this.onLaunchUrl,
this.spellCheckConfiguration,
this.clipboardManager = const PlainTextClipboardManager(),
this.clipboardStatus,
this.contextMenuBuilder = defaultContextMenuBuilder,
this.embedBuilder = defaultFleatherEmbedBuilder,
this.linkActionPickerDelegate = defaultLinkActionPickerDelegate,
this.textSelectionControls});

@override
State<FleatherEditor> createState() => _FleatherEditorState();
Expand Down Expand Up @@ -415,7 +417,8 @@ class _FleatherEditorState extends State<FleatherEditor>
switch (theme.platform) {
case TargetPlatform.iOS:
final cupertinoTheme = CupertinoTheme.of(context);
textSelectionControls = cupertinoTextSelectionControls;
textSelectionControls =
widget.textSelectionControls ?? cupertinoTextSelectionControls;
paintCursorAboveText = true;
cursorOpacityAnimates = true;
cursorColor = selectionTheme.cursorColor ?? cupertinoTheme.primaryColor;
Expand All @@ -428,7 +431,8 @@ class _FleatherEditorState extends State<FleatherEditor>

case TargetPlatform.macOS:
final CupertinoThemeData cupertinoTheme = CupertinoTheme.of(context);
textSelectionControls = cupertinoDesktopTextSelectionControls;
textSelectionControls = widget.textSelectionControls ??
cupertinoDesktopTextSelectionControls;
paintCursorAboveText = true;
cursorOpacityAnimates = false;
cursorColor = selectionTheme.cursorColor ?? cupertinoTheme.primaryColor;
Expand All @@ -441,7 +445,8 @@ class _FleatherEditorState extends State<FleatherEditor>

case TargetPlatform.android:
case TargetPlatform.fuchsia:
textSelectionControls = materialTextSelectionControls;
textSelectionControls =
widget.textSelectionControls ?? materialTextSelectionControls;
paintCursorAboveText = false;
cursorOpacityAnimates = false;
cursorColor = selectionTheme.cursorColor ?? theme.colorScheme.primary;
Expand All @@ -451,7 +456,8 @@ class _FleatherEditorState extends State<FleatherEditor>

case TargetPlatform.linux:
case TargetPlatform.windows:
textSelectionControls = desktopTextSelectionControls;
textSelectionControls =
widget.textSelectionControls ?? desktopTextSelectionControls;
paintCursorAboveText = false;
cursorOpacityAnimates = false;
cursorColor = selectionTheme.cursorColor ?? theme.colorScheme.primary;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import 'dart:math' as math;

import 'package:fleather/fleather.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';

class MyTextSelectionHandle extends StatefulWidget {
final Size size;
const MyTextSelectionHandle({super.key, required this.size});

@override
State<StatefulWidget> createState() {
return MyTextSelectionHandleState();
}
}

class MyTextSelectionHandleState extends State<MyTextSelectionHandle> {
@override
Widget build(BuildContext context) {
return Container(
width: widget.size.width,
height: widget.size.height,
color: Colors.red,
);
}
}

class MyTextSelectionControllers extends MaterialTextSelectionControls {
final Size size;
MyTextSelectionControllers(this.size);

@override
Widget buildHandle(
BuildContext context, TextSelectionHandleType type, double textHeight,
[VoidCallback? onTap]) {
final Widget handle = MyTextSelectionHandle(
size: size,
);

return switch (type) {
TextSelectionHandleType.left => Transform.rotate(
angle: math.pi / 2.0, child: handle), // points up-right
TextSelectionHandleType.right => handle, // points up-left
TextSelectionHandleType.collapsed =>
Transform.rotate(angle: math.pi / 4.0, child: handle), // points up
};
}
}

void main() {
group('CustomTextSelectionControllers', () {
testWidgets('set customTextSelectionControllers', (tester) async {
final document = ParchmentDocument.fromJson([
{'insert': 'some text\n'}
]);
FleatherController controller = FleatherController(document: document);
FocusNode focusNode = FocusNode();
const Size testSize = Size(230, 5);
final editor = MaterialApp(
home: FleatherEditor(
controller: controller,
focusNode: focusNode,
textSelectionControls: MyTextSelectionControllers(testSize)),
);
await tester.pumpWidget(editor);
await tester.tap(find.byType(RawEditor).first);
await tester.pumpAndSettle();
expect(focusNode.hasFocus, isTrue);
tester.binding.scheduleWarmUpFrame();
final handleState = tester.state(find.byType(MyTextSelectionHandle))
as MyTextSelectionHandleState;
expect(handleState.context.size, testSize);
});
});
}

0 comments on commit fff4b87

Please sign in to comment.