Skip to content

Commit

Permalink
Cannot make toolbar appear on empty document (immediately after gaini…
Browse files Browse the repository at this point in the history
…ng focus) (#28)
  • Loading branch information
amantoux authored Aug 31, 2022
1 parent a996fae commit e5446f6
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 18 deletions.
25 changes: 13 additions & 12 deletions packages/fleather/lib/src/rendering/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,7 @@ class RenderEditor extends RenderEditableContainerBox
}

double? _maxContentWidth;

set maxContentWidth(double? value) {
if (_maxContentWidth == value) return;
_maxContentWidth = value;
Expand Down Expand Up @@ -601,20 +602,13 @@ class RenderEditor extends RenderEditableContainerBox
TextSelection nextSelection,
SelectionChangedCause cause,
) {
final bool selectionChanged = selection != nextSelection;
// Changes made by the keyboard can sometimes be "out of band" for listening
// components, so always send those events, even if we didn't think it
// changed. Also, focusing an empty field is sent as a selection change even
// if the selection offset didn't change.
final focusingEmpty = nextSelection.baseOffset == 0 &&
nextSelection.extentOffset == 0 &&
!hasFocus;
if (nextSelection == selection &&
cause != SelectionChangedCause.keyboard &&
!focusingEmpty) {
return;
}
if (onSelectionChanged != null) {
onSelectionChanged!(nextSelection, cause);
// changed. Also, the user long pressing should always send a selection change
// as well.
if (selectionChanged || cause.forcesSelectionChanged) {
onSelectionChanged?.call(nextSelection, cause);
}
}

Expand Down Expand Up @@ -1025,3 +1019,10 @@ class FleatherVerticalCaretMovementRun
return true;
}
}

extension on SelectionChangedCause {
bool get forcesSelectionChanged =>
this == SelectionChangedCause.longPress ||
this == SelectionChangedCause.keyboard ||
this == SelectionChangedCause.doubleTap;
}
6 changes: 5 additions & 1 deletion packages/fleather/lib/src/widgets/editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -901,7 +901,11 @@ class RawEditorState extends EditorState
_replaceText(
ReplaceTextIntent(textEditingValue, data.text!, selection, cause));
if (cause == SelectionChangedCause.toolbar) {
bringIntoView(textEditingValue.selection.extent);
SchedulerBinding.instance.addPostFrameCallback((_) {
if (mounted) {
bringIntoView(textEditingValue.selection.extent);
}
});
hideToolbar();
}
}
Expand Down
2 changes: 1 addition & 1 deletion packages/fleather/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ class EditorTextSelectionGestureDetectorBuilder {
@protected
void onDoubleTapDown(TapDownDetails details) {
if (delegate.selectionEnabled) {
renderEditor!.selectWord(cause: SelectionChangedCause.tap);
renderEditor!.selectWord(cause: SelectionChangedCause.doubleTap);
if (shouldShowSelectionToolbar) editor!.showToolbar();
}
}
Expand Down
60 changes: 56 additions & 4 deletions packages/fleather/test/widgets/editor_test.dart
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
// Copyright (c) 2018, the Zefyr project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:fleather/fleather.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:quill_delta/quill_delta.dart';
import 'package:fleather/fleather.dart';

import '../testing.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('$RawEditor', () {
testWidgets('allows merging attribute theme data', (tester) async {
var delta = Delta()
Expand Down Expand Up @@ -47,5 +46,58 @@ void main() {
final widget = tester.widget(find.byType(FleatherField)) as FleatherField;
expect(widget.readOnly, true);
});

testWidgets('ability to paste upon long press on an empty document',
(tester) async {
// if Clipboard not initialize (status 'unknown'), an shrunken toolbar appears
prepareClipboard();

final editor = EditorSandBox(
tester: tester, document: ParchmentDocument(), autofocus: true);
await editor.pump();

expect(find.text('Paste'), findsNothing);
await tester.longPress(find.byType(FleatherEditor));
await tester.pump();
// Given current toolbar implementation in Flutter no other choice
// than to search for "Paste" text
final finder = find.text('Paste');
expect(finder, findsOneWidget);
await tester.tap(finder);
await tester.pumpAndSettle();
expect(editor.document.toPlainText(), '$clipboardText\n');
});

testWidgets('ability to paste upon double-tap on an empty document',
(tester) async {
// if Clipboard not initialize (status 'unknown'), an shrunken toolbar appears
prepareClipboard();
final editor = EditorSandBox(
tester: tester, document: ParchmentDocument(), autofocus: true);
await editor.pump();
expect(find.text('Paste'), findsNothing);
await tester.tap(find.byType(FleatherEditor));
await tester.tap(find.byType(FleatherEditor));
await tester.pump();
final finder = find.text('Paste');
expect(finder, findsOneWidget);
await tester.tap(finder);
await tester.pumpAndSettle();
expect(editor.document.toPlainText(), '$clipboardText\n');
});
});
}

const clipboardText = 'copied text';

void prepareClipboard() {
TestDefaultBinaryMessengerBinding.instance?.defaultBinaryMessenger
.setMockMethodCallHandler(SystemChannels.platform, (message) {
if (message.method == 'Clipboard.getData') {
return Future.value(<String, dynamic>{'text': clipboardText});
}
if (message.method == 'Clipboard.hasStrings') {
return Future.value(<String, dynamic>{'value': true});
}
});
}

0 comments on commit e5446f6

Please sign in to comment.