Unverified Commit 4cd87705 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Revert "Adds support for floating cursor (#24761)" (#25352)

This reverts commit 46878d84.
parent 46878d84
......@@ -672,7 +672,6 @@ class _CupertinoTextFieldState extends State<CupertinoTextField> with AutomaticK
cursorWidth: widget.cursorWidth,
cursorRadius: widget.cursorRadius,
cursorColor: widget.cursorColor,
backgroundCursorColor: CupertinoColors.inactiveGray,
scrollPadding: widget.scrollPadding,
keyboardAppearance: keyboardAppearance,
),
......
......@@ -613,7 +613,6 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
cursorWidth: widget.cursorWidth,
cursorRadius: widget.cursorRadius,
cursorColor: widget.cursorColor ?? Theme.of(context).cursorColor,
backgroundCursorColor: CupertinoColors.inactiveGray,
scrollPadding: widget.scrollPadding,
keyboardAppearance: keyboardAppearance,
enableInteractiveSelection: widget.enableInteractiveSelection,
......
......@@ -4,7 +4,7 @@
import 'dart:async';
import 'dart:io' show Platform;
import 'dart:ui' show TextAffinity, hashValues, Offset;
import 'dart:ui' show TextAffinity, hashValues;
import 'package:flutter/foundation.dart';
......@@ -439,40 +439,6 @@ TextAffinity _toTextAffinity(String affinity) {
return null;
}
/// A floating cursor state the user has induced by force pressing an iOS
/// keyboard.
enum FloatingCursorDragState {
/// A user has just activated a floating cursor.
Start,
/// A user is dragging a floating cursor.
Update,
/// A user has lifted their finger off the screen after using a floating
/// cursor.
End,
}
/// The current state and position of the floating cursor.
class RawFloatingCursorPoint {
/// Creates information for setting the position and state of a floating
/// cursor.
///
/// [state] must not be null and [offset] must not be null if the state is
/// [FloatingCursorDragState.Update].
RawFloatingCursorPoint({
this.offset,
@required this.state,
}) : assert(state != null),
assert(state == FloatingCursorDragState.Update ? offset != null : true);
/// The raw position of the floating cursor as determined by the iOS sdk.
final Offset offset;
/// The state of the floating cursor.
final FloatingCursorDragState state;
}
/// The current text, selection, and composing state for editing a run of text.
@immutable
class TextEditingValue {
......@@ -600,9 +566,6 @@ abstract class TextInputClient {
/// Requests that this client perform the given action.
void performAction(TextInputAction action);
/// Updates the floating cursor position and state.
void updateFloatingCursor(RawFloatingCursorPoint point);
}
/// An interface for interacting with a text input control.
......@@ -685,26 +648,6 @@ TextInputAction _toTextInputAction(String action) {
throw FlutterError('Unknown text input action: $action');
}
FloatingCursorDragState _toTextCursorAction(String state) {
switch (state) {
case 'FloatingCursorDragState.start':
return FloatingCursorDragState.Start;
case 'FloatingCursorDragState.update':
return FloatingCursorDragState.Update;
case 'FloatingCursorDragState.end':
return FloatingCursorDragState.End;
}
throw FlutterError('Unknown text cursor action: $state');
}
RawFloatingCursorPoint _toTextPoint(FloatingCursorDragState state, Map<String, dynamic> encoded) {
assert(state != null, 'You must provide a state to set a new editing point.');
assert(encoded['X'] != null, 'You must provide a value for the horizontal location of the floating cursor.');
assert(encoded['Y'] != null, 'You must provide a value for the vertical location of the floating cursor.');
final Offset offset = state == FloatingCursorDragState.Update ? Offset(encoded['X'], encoded['Y']) : const Offset(0, 0);
return RawFloatingCursorPoint(offset: offset, state: state);
}
class _TextInputClientHandler {
_TextInputClientHandler() {
SystemChannels.textInput.setMethodCallHandler(_handleTextInputInvocation);
......@@ -728,9 +671,6 @@ class _TextInputClientHandler {
case 'TextInputClient.performAction':
_currentConnection._client.performAction(_toTextInputAction(args[1]));
break;
case 'TextInputClient.updateFloatingCursor':
_currentConnection._client.updateFloatingCursor(_toTextPoint(_toTextCursorAction(args[1]), args[2]));
break;
default:
throw MissingPluginException();
}
......
......@@ -21,7 +21,6 @@ import 'scroll_controller.dart';
import 'scroll_physics.dart';
import 'scrollable.dart';
import 'text_selection.dart';
import 'ticker_provider.dart';
export 'package:flutter/services.dart' show TextEditingValue, TextSelection, TextInputType;
export 'package:flutter/rendering.dart' show SelectionChangedCause;
......@@ -183,9 +182,9 @@ class EditableText extends StatefulWidget {
/// [TextInputType.text] unless [maxLines] is greater than one, when it will
/// default to [TextInputType.multiline].
///
/// The [controller], [focusNode], [style], [cursorColor], [backgroundCursorColor],
/// [textAlign], [rendererIgnoresPointer], and [enableInteractiveSelection]
/// arguments must not be null.
/// The [controller], [focusNode], [style], [cursorColor], [textAlign],
/// [rendererIgnoresPointer], and [enableInteractiveSelection] arguments must
/// not be null.
EditableText({
Key key,
@required this.controller,
......@@ -194,7 +193,6 @@ class EditableText extends StatefulWidget {
this.autocorrect = true,
@required this.style,
@required this.cursorColor,
@required this.backgroundCursorColor,
this.textAlign = TextAlign.start,
this.textDirection,
this.locale,
......@@ -223,7 +221,6 @@ class EditableText extends StatefulWidget {
assert(autocorrect != null),
assert(style != null),
assert(cursorColor != null),
assert(backgroundCursorColor != null),
assert(textAlign != null),
assert(maxLines == null || maxLines > 0),
assert(autofocus != null),
......@@ -327,13 +324,6 @@ class EditableText extends StatefulWidget {
/// Cannot be null.
final Color cursorColor;
/// The color to use when painting the background cursor aligned with the text
/// while rendering the floating cursor.
///
/// Cannot be null. By default it is the disabled grey color from
/// CupertinoColors.
final Color backgroundCursorColor;
/// {@template flutter.widgets.editableText.maxLines}
/// The maximum number of lines for the text to span, wrapping if necessary.
///
......@@ -501,7 +491,7 @@ class EditableText extends StatefulWidget {
}
/// State for a [EditableText].
class EditableTextState extends State<EditableText> with AutomaticKeepAliveClientMixin<EditableText>, WidgetsBindingObserver, TickerProviderStateMixin<EditableText> implements TextInputClient, TextSelectionDelegate {
class EditableTextState extends State<EditableText> with AutomaticKeepAliveClientMixin<EditableText>, WidgetsBindingObserver implements TextInputClient, TextSelectionDelegate {
Timer _cursorTimer;
final ValueNotifier<bool> _showCursor = ValueNotifier<bool>(false);
final GlobalKey _editableKey = GlobalKey();
......@@ -513,12 +503,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
final LayerLink _layerLink = LayerLink();
bool _didAutoFocus = false;
// The time it takes for the floating cursor to snap to the text aligned
// cursor position after the user has finished placing it.
static const Duration _floatingCursorResetTime = Duration(milliseconds: 125);
AnimationController _floatingCursorResetController;
@override
bool get wantKeepAlive => widget.focusNode.hasFocus;
......@@ -530,8 +514,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
widget.controller.addListener(_didChangeTextEditingValue);
widget.focusNode.addListener(_handleFocusChanged);
_scrollController.addListener(() { _selectionOverlay?.updateForScroll(); });
_floatingCursorResetController = AnimationController(vsync: this);
_floatingCursorResetController.addListener(_onFloatingCursorResetTick);
}
@override
......@@ -613,72 +595,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
}
}
// The original position of the caret on FloatingCursorDragState.start.
Rect _startCaretRect;
// The most recent text position as determined by the location of the floating
// cursor.
TextPosition _lastTextPosition;
// The offset of the floating cursor as determined from the first update call.
Offset _pointOffsetOrigin;
// The most recent position of the floating cursor.
Offset _lastBoundedOffset;
// Because the center of the cursor is preferredLineHeight / 2 below the touch
// origin, but the touch origin is used to determine which line the cursor is
// on, we need this offset to correctly render and move the cursor.
Offset get _floatingCursorOffset => Offset(0, renderEditable.preferredLineHeight / 2);
@override
void updateFloatingCursor(RawFloatingCursorPoint point) {
switch(point.state){
case FloatingCursorDragState.Start:
final TextPosition currentTextPosition = TextPosition(offset: renderEditable.selection.baseOffset);
_startCaretRect = renderEditable.getLocalRectForCaret(currentTextPosition);
renderEditable.setFloatingCursor(point.state, _startCaretRect.center - _floatingCursorOffset, currentTextPosition);
break;
case FloatingCursorDragState.Update:
// We want to send in points that are centered around a (0,0) origin, so we cache the
// position on the first update call.
if (_pointOffsetOrigin != null) {
final Offset centeredPoint = point.offset - _pointOffsetOrigin;
final Offset rawCursorOffset = _startCaretRect.center + centeredPoint - _floatingCursorOffset;
_lastBoundedOffset = renderEditable.calculateBoundedFloatingCursorOffset(rawCursorOffset);
_lastTextPosition = renderEditable.getPositionForPoint(renderEditable.localToGlobal(_lastBoundedOffset + _floatingCursorOffset));
renderEditable.setFloatingCursor(point.state, _lastBoundedOffset, _lastTextPosition);
} else {
_pointOffsetOrigin = point.offset;
}
break;
case FloatingCursorDragState.End:
_floatingCursorResetController.value = 0.0;
_floatingCursorResetController.animateTo(1.0, duration: _floatingCursorResetTime, curve: Curves.decelerate);
break;
}
}
void _onFloatingCursorResetTick() {
final Offset finalPosition = renderEditable.getLocalRectForCaret(_lastTextPosition).center - _floatingCursorOffset;
if (_floatingCursorResetController.isCompleted) {
renderEditable.setFloatingCursor(FloatingCursorDragState.End, finalPosition, _lastTextPosition);
if (_lastTextPosition.offset != renderEditable.selection.baseOffset)
// The cause is technically the force cursor, but the cause is listed as tap as the desired functionality is the same.
_handleSelectionChanged(TextSelection.collapsed(offset: _lastTextPosition.offset), renderEditable, SelectionChangedCause.tap);
_startCaretRect = null;
_lastTextPosition = null;
_pointOffsetOrigin = null;
_lastBoundedOffset = null;
} else {
final double lerpValue = _floatingCursorResetController.value;
final double lerpX = ui.lerpDouble(_lastBoundedOffset.dx, finalPosition.dx, lerpValue);
final double lerpY = ui.lerpDouble(_lastBoundedOffset.dy, finalPosition.dy, lerpValue);
renderEditable.setFloatingCursor(FloatingCursorDragState.Update, Offset(lerpX, lerpY), _lastTextPosition, resetLerpValue: lerpValue);
}
}
void _finalizeEditing(bool shouldUnfocus) {
// Take any actions necessary now that the user has completed editing.
if (widget.onEditingComplete != null) {
......@@ -1053,7 +969,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
textSpan: buildTextSpan(),
value: _value,
cursorColor: widget.cursorColor,
backgroundCursorColor: widget.backgroundCursorColor,
showCursor: EditableText.debugDeterministicCursor ? ValueNotifier<bool>(true) : _showCursor,
hasFocus: _hasFocus,
maxLines: widget.maxLines,
......@@ -1119,7 +1034,6 @@ class _Editable extends LeafRenderObjectWidget {
this.textSpan,
this.value,
this.cursorColor,
this.backgroundCursorColor,
this.showCursor,
this.hasFocus,
this.maxLines,
......@@ -1146,7 +1060,6 @@ class _Editable extends LeafRenderObjectWidget {
final TextSpan textSpan;
final TextEditingValue value;
final Color cursorColor;
final Color backgroundCursorColor;
final ValueNotifier<bool> showCursor;
final bool hasFocus;
final int maxLines;
......@@ -1171,7 +1084,6 @@ class _Editable extends LeafRenderObjectWidget {
return RenderEditable(
text: textSpan,
cursorColor: cursorColor,
backgroundCursorColor: backgroundCursorColor,
showCursor: showCursor,
hasFocus: hasFocus,
maxLines: maxLines,
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Copyright 2017 The Chromium Authors. 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:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/services.dart';
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import '../rendering/mock_canvas.dart';
import '../rendering/recording_canvas.dart';
......@@ -26,10 +24,6 @@ class FakeEditableTextState extends TextSelectionDelegate {
}
void main() {
final TextEditingController controller = TextEditingController();
const TextStyle textStyle = TextStyle();
test('editable intrinsics', () {
final TextSelectionDelegate delegate = FakeEditableTextState();
final RenderEditable editable = RenderEditable(
......@@ -97,68 +91,4 @@ void main() {
paints..clipRect(rect: Rect.fromLTRB(0.0, 0.0, 1000.0, 10.0))
);
});
RenderEditable findRenderEditable(WidgetTester tester) {
final RenderObject root = tester.renderObject(find.byType(EditableText));
expect(root, isNotNull);
RenderEditable renderEditable;
void recursiveFinder(RenderObject child) {
if (child is RenderEditable) {
renderEditable = child;
return;
}
child.visitChildren(recursiveFinder);
}
root.visitChildren(recursiveFinder);
expect(renderEditable, isNotNull);
return renderEditable;
}
testWidgets('Floating cursor is painted', (WidgetTester tester) async {
debugDefaultTargetPlatformOverride = TargetPlatform.iOS;
const String text = 'hello world this is fun and cool and awesome!';
controller.text = text;
final FocusNode focusNode = FocusNode();
await tester.pumpWidget(
MaterialApp(
home: Material(
child: TextField(
controller: controller,
focusNode: focusNode,
style: textStyle,
),
),
),
);
await tester.tap(find.byType(EditableText));
final RenderEditable editable = findRenderEditable(tester);
editable.selection = const TextSelection(baseOffset: 29, extentOffset: 29);
final EditableTextState editableTextState = tester.firstState(find.byType(EditableText));
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.Start));
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.Update,
offset: const Offset(20, 20)));
await tester.pump();
expect(find.byType(EditableText), paints..rrect(
rrect: RRect.fromRectAndRadius(Rect.fromLTRB(406.5, 0, 409.5, 14.0), const Radius.circular(1.0)), color: const Color(0xff4285f4))
);
// Moves the cursor right a few characters.
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.Update,
offset: const Offset(-250, 20)));
expect(find.byType(EditableText), paints..rrect(
rrect: RRect.fromRectAndRadius(Rect.fromLTRB(136.5, 0, 139.5, 14.0), const Radius.circular(1.0)), color: const Color(0xff4285f4))
);
editableTextState.updateFloatingCursor(RawFloatingCursorPoint(state: FloatingCursorDragState.End));
await tester.pumpAndSettle();
debugDefaultTargetPlatformOverride = null;
});
}
......@@ -1024,49 +1024,16 @@ class _RectPaintPredicate extends _OneParameterPaintPredicate<Rect> {
);
}
class _RRectPaintPredicate extends _DrawCommandPaintPredicate {
_RRectPaintPredicate({ this.rrect, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
class _RRectPaintPredicate extends _OneParameterPaintPredicate<RRect> {
_RRectPaintPredicate({ RRect rrect, Color color, double strokeWidth, bool hasMaskFilter, PaintingStyle style }) : super(
#drawRRect,
'a rounded rectangle',
2,
1,
expected: rrect,
color: color,
strokeWidth: strokeWidth,
hasMaskFilter: hasMaskFilter,
style: style
style: style,
);
final RRect rrect;
@override
void verifyArguments(List<dynamic> arguments) {
super.verifyArguments(arguments);
const double eps = .0001;
final RRect actual = arguments[0];
if (rrect != null &&
((actual.left - rrect.left).abs() > eps ||
(actual.right - rrect.right).abs() > eps ||
(actual.top - rrect.top).abs() > eps ||
(actual.bottom - rrect.bottom).abs() > eps ||
(actual.blRadiusX - rrect.blRadiusX).abs() > eps ||
(actual.blRadiusY - rrect.blRadiusY).abs() > eps ||
(actual.brRadiusX - rrect.brRadiusX).abs() > eps ||
(actual.brRadiusY - rrect.brRadiusY).abs() > eps ||
(actual.tlRadiusX - rrect.tlRadiusX).abs() > eps ||
(actual.tlRadiusY - rrect.tlRadiusY).abs() > eps ||
(actual.trRadiusX - rrect.trRadiusX).abs() > eps ||
(actual.trRadiusY - rrect.trRadiusY).abs() > eps)) {
throw 'It called $methodName with RRect, $actual, which was not exactly the expected RRect ($rrect).';
}
}
@override
void debugFillDescription(List<String> description) {
super.debugFillDescription(description);
if (rrect != null) {
description.add('RRect: $rrect');
}
}
}
class _DRRectPaintPredicate extends _TwoParameterPaintPredicate<RRect, RRect> {
......
......@@ -26,7 +26,6 @@ void main() {
controller: scrollController,
children: <Widget>[
EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
style: textStyle,
......@@ -68,7 +67,6 @@ void main() {
height: 200.0,
),
EditableText(
backgroundCursorColor: Colors.grey,
scrollPadding: const EdgeInsets.all(50.0),
controller: controller,
focusNode: focusNode,
......@@ -114,7 +112,6 @@ void main() {
height: 350.0,
),
EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
style: textStyle,
......@@ -164,7 +161,6 @@ void main() {
height: 350.0,
),
EditableText(
backgroundCursorColor: Colors.grey,
controller: controller,
focusNode: focusNode,
style: textStyle,
......@@ -251,7 +247,6 @@ void main() {
controller: scrollController,
children: <Widget>[
EditableText(
backgroundCursorColor: Colors.grey,
maxLines: null, // multi-line
controller: controller,
focusNode: focusNode,
......@@ -307,7 +302,6 @@ void main() {
height: 200.0,
),
EditableText(
backgroundCursorColor: Colors.grey,
scrollPadding: const EdgeInsets.only(bottom: 300.0),
controller: controller,
focusNode: focusNode,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment