Commit 963fb413 authored by Jason Simmons's avatar Jason Simmons

Merge pull request #1245 from jason-simmons/editable_text_initial_blink

Ensure that EditableText always shows a cursor
parents 9b84e6b8 58b421aa
...@@ -156,6 +156,13 @@ class EditableText extends StatefulComponent { ...@@ -156,6 +156,13 @@ class EditableText extends StatefulComponent {
Timer _cursorTimer; Timer _cursorTimer;
bool _showCursor = false; bool _showCursor = false;
/// Whether the blinking cursor is visible (exposed for testing).
bool get test_showCursor => _showCursor;
/// The cursor blink interval (exposed for testing).
Duration get test_cursorBlinkPeriod =>
new Duration(milliseconds: _kCursorBlinkPeriod);
void _cursorTick(Timer timer) { void _cursorTick(Timer timer) {
setState(() { setState(() {
_showCursor = !_showCursor; _showCursor = !_showCursor;
...@@ -184,11 +191,12 @@ class EditableText extends StatefulComponent { ...@@ -184,11 +191,12 @@ class EditableText extends StatefulComponent {
if (!_showCursor) if (!_showCursor)
return; return;
double cursorHeight = style.fontSize + 2.0 * _kCursorHeightOffset;
Rect cursorRect = new Rect.fromLTWH( Rect cursorRect = new Rect.fromLTWH(
_kCursorGap, _kCursorGap,
-_kCursorHeightOffset, (size.height - cursorHeight) / 2.0,
_kCursorWidth, _kCursorWidth,
style.fontSize + 2 * _kCursorHeightOffset cursorHeight
); );
canvas.drawRect(cursorRect, new Paint()..color = cursorColor); canvas.drawRect(cursorRect, new Paint()..color = cursorColor);
} }
...@@ -203,21 +211,22 @@ class EditableText extends StatefulComponent { ...@@ -203,21 +211,22 @@ class EditableText extends StatefulComponent {
else if (!focused && _cursorTimer != null) else if (!focused && _cursorTimer != null)
_stopCursorTimer(); _stopCursorTimer();
if (!value.composing.isValid) { Widget text;
if (value.composing.isValid) {
TextStyle composingStyle = style.merge(const TextStyle(decoration: underline));
text = new StyledText(elements: [
style,
value.textBefore(value.composing),
[composingStyle, value.textInside(value.composing)],
value.textAfter(value.composing)
]);
} else {
// TODO(eseidel): This is the wrong height if empty! // TODO(eseidel): This is the wrong height if empty!
return new Row([new Text(value.text, style: style)]); text = new Text(value.text, style: style);
} }
TextStyle composingStyle = style.merge(const TextStyle(decoration: underline));
StyledText text = new StyledText(elements: [
style,
value.textBefore(value.composing),
[composingStyle, value.textInside(value.composing)],
value.textAfter(value.composing)
]);
Widget cursor = new Container( Widget cursor = new Container(
height: style.fontSize, height: style.fontSize * style.height,
width: _kCursorGap + _kCursorWidth, width: _kCursorGap + _kCursorWidth,
child: new CustomPaint(callback: _paintCursor, token: _showCursor) child: new CustomPaint(callback: _paintCursor, token: _showCursor)
); );
......
import 'package:mojo_services/keyboard/keyboard.mojom.dart'; import 'package:mojo_services/keyboard/keyboard.mojom.dart';
import 'package:quiver/testing/async.dart';
import 'package:sky/rendering.dart'; import 'package:sky/rendering.dart';
import 'package:sky/services.dart'; import 'package:sky/services.dart';
import 'package:sky/widgets.dart'; import 'package:sky/widgets.dart';
...@@ -20,12 +21,12 @@ class MockKeyboard implements KeyboardService { ...@@ -20,12 +21,12 @@ class MockKeyboard implements KeyboardService {
} }
void main() { void main() {
MockKeyboard mockKeyboard = new MockKeyboard();
serviceMocker.registerMockService(KeyboardServiceName, mockKeyboard);
test('Editable text has consistent width', () { test('Editable text has consistent width', () {
WidgetTester tester = new WidgetTester(); WidgetTester tester = new WidgetTester();
MockKeyboard mockKeyboard = new MockKeyboard();
serviceMocker.registerMockService(KeyboardServiceName, mockKeyboard);
GlobalKey inputKey = new GlobalKey(); GlobalKey inputKey = new GlobalKey();
String inputValue; String inputValue;
...@@ -57,4 +58,41 @@ void main() { ...@@ -57,4 +58,41 @@ void main() {
// Check that the Input with text has the same size as the empty Input. // Check that the Input with text has the same size as the empty Input.
expect((input.renderObject as RenderBox).size, equals(emptyInputSize)); expect((input.renderObject as RenderBox).size, equals(emptyInputSize));
}); });
test('Cursor blinks', () {
WidgetTester tester = new WidgetTester();
GlobalKey inputKey = new GlobalKey();
Widget builder() {
return new Center(
child: new Input(
key: inputKey,
placeholder: 'Placeholder'
)
);
}
new FakeAsync().run((async) {
tester.pumpFrame(builder);
EditableText editableText = tester.findWidget(
(Widget widget) => widget is EditableText);
// Check that the cursor visibility toggles after each blink interval.
void checkCursorToggle() {
bool initialShowCursor = editableText.test_showCursor;
async.elapse(editableText.test_cursorBlinkPeriod);
expect(editableText.test_showCursor, equals(!initialShowCursor));
async.elapse(editableText.test_cursorBlinkPeriod);
expect(editableText.test_showCursor, equals(initialShowCursor));
}
checkCursorToggle();
// Try the test again with a nonempty EditableText.
mockKeyboard.client.setComposingText('X', 1);
checkCursorToggle();
});
});
} }
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