TextPainter RTL (#11888)
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index a0483e3..7c8fb53 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-ccf68cdcb66f9fe354bf3e8472bb0b47c83e8ac9
+2d7c30033d76fda9779462827ad5322d78e1fb3a
diff --git a/examples/hello_world/README.md b/examples/hello_world/README.md
new file mode 100644
index 0000000..6715517
--- /dev/null
+++ b/examples/hello_world/README.md
@@ -0,0 +1,7 @@
+```
+# To run the Hello World demo:
+flutter run
+
+# To run the Hello World demo showing Arabic:
+flutter run lib/arabic.dart
+```
diff --git a/examples/hello_world/lib/arabic.dart b/examples/hello_world/lib/arabic.dart
new file mode 100644
index 0000000..d26ee5a
--- /dev/null
+++ b/examples/hello_world/lib/arabic.dart
@@ -0,0 +1,7 @@
+// Copyright 2015 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/widgets.dart';
+
+void main() => runApp(const Center(child: const Text('برنامج أهلا بالعالم', textDirection: TextDirection.rtl)));
diff --git a/examples/hello_world/lib/main.dart b/examples/hello_world/lib/main.dart
index 1ad8675..93f7f5b 100644
--- a/examples/hello_world/lib/main.dart
+++ b/examples/hello_world/lib/main.dart
@@ -4,4 +4,4 @@
import 'package:flutter/widgets.dart';
-void main() => runApp(const Center(child: const Text('Hello, world!')));
+void main() => runApp(const Center(child: const Text('Hello, world!', textDirection: TextDirection.ltr)));
diff --git a/examples/layers/lib/main.dart b/examples/layers/lib/main.dart
index 864e8f1..e1e068d 100644
--- a/examples/layers/lib/main.dart
+++ b/examples/layers/lib/main.dart
@@ -4,4 +4,4 @@
import 'package:flutter/widgets.dart';
-void main() => runApp(const Center(child: const Text('flutter run -t xxx/yyy.dart')));
+void main() => runApp(const Center(child: const Text('flutter run -t xxx/yyy.dart', textDirection: TextDirection.ltr)));
diff --git a/examples/layers/raw/hello_world.dart b/examples/layers/raw/hello_world.dart
index b2f67f3..83d3bb5 100644
--- a/examples/layers/raw/hello_world.dart
+++ b/examples/layers/raw/hello_world.dart
@@ -11,7 +11,9 @@
final double devicePixelRatio = ui.window.devicePixelRatio;
final ui.Size logicalSize = ui.window.physicalSize / devicePixelRatio;
- final ui.ParagraphBuilder paragraphBuilder = new ui.ParagraphBuilder(new ui.ParagraphStyle())
+ final ui.ParagraphBuilder paragraphBuilder = new ui.ParagraphBuilder(
+ new ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
+ )
..addText('Hello, world.');
final ui.Paragraph paragraph = paragraphBuilder.build()
..layout(new ui.ParagraphConstraints(width: logicalSize.width));
diff --git a/examples/layers/raw/text.dart b/examples/layers/raw/text.dart
index 3c3e92f..15029c7 100644
--- a/examples/layers/raw/text.dart
+++ b/examples/layers/raw/text.dart
@@ -52,7 +52,13 @@
void main() {
// To create a paragraph of text, we use ParagraphBuilder.
- final ui.ParagraphBuilder builder = new ui.ParagraphBuilder(new ui.ParagraphStyle())
+ final ui.ParagraphBuilder builder = new ui.ParagraphBuilder(
+ // The text below has a primary direction of left-to-right.
+ // The embedded text has other directions.
+ // If this was TextDirection.rtl, the "Hello, world" text would end up on
+ // the other side of the right-to-left text.
+ new ui.ParagraphStyle(textDirection: ui.TextDirection.ltr),
+ )
// We first push a style that turns the text blue.
..pushStyle(new ui.TextStyle(color: const ui.Color(0xFF0000FF)))
..addText('Hello, ')
diff --git a/examples/layers/rendering/flex_layout.dart b/examples/layers/rendering/flex_layout.dart
index dc38d85..0084eba 100644
--- a/examples/layers/rendering/flex_layout.dart
+++ b/examples/layers/rendering/flex_layout.dart
@@ -14,24 +14,36 @@
void addAlignmentRow(CrossAxisAlignment crossAxisAlignment) {
TextStyle style = const TextStyle(color: const Color(0xFF000000));
- final RenderParagraph paragraph = new RenderParagraph(new TextSpan(style: style, text: '$crossAxisAlignment'));
+ final RenderParagraph paragraph = new RenderParagraph(
+ new TextSpan(style: style, text: '$crossAxisAlignment'),
+ textDirection: TextDirection.ltr,
+ );
table.add(new RenderPadding(child: paragraph, padding: const EdgeInsets.only(top: 20.0)));
final RenderFlex row = new RenderFlex(crossAxisAlignment: crossAxisAlignment, textBaseline: TextBaseline.alphabetic);
style = const TextStyle(fontSize: 15.0, color: const Color(0xFF000000));
row.add(new RenderDecoratedBox(
decoration: const BoxDecoration(color: const Color(0x7FFFCCCC)),
- child: new RenderParagraph(new TextSpan(style: style, text: 'foo foo foo'))
+ child: new RenderParagraph(
+ new TextSpan(style: style, text: 'foo foo foo'),
+ textDirection: TextDirection.ltr,
+ ),
));
style = const TextStyle(fontSize: 10.0, color: const Color(0xFF000000));
row.add(new RenderDecoratedBox(
decoration: const BoxDecoration(color: const Color(0x7FCCFFCC)),
- child: new RenderParagraph(new TextSpan(style: style, text: 'foo foo foo'))
+ child: new RenderParagraph(
+ new TextSpan(style: style, text: 'foo foo foo'),
+ textDirection: TextDirection.ltr,
+ ),
));
final RenderFlex subrow = new RenderFlex(crossAxisAlignment: crossAxisAlignment, textBaseline: TextBaseline.alphabetic);
style = const TextStyle(fontSize: 25.0, color: const Color(0xFF000000));
subrow.add(new RenderDecoratedBox(
decoration: const BoxDecoration(color: const Color(0x7FCCCCFF)),
- child: new RenderParagraph(new TextSpan(style: style, text: 'foo foo foo foo'))
+ child: new RenderParagraph(
+ new TextSpan(style: style, text: 'foo foo foo foo'),
+ textDirection: TextDirection.ltr,
+ ),
));
subrow.add(new RenderSolidColorBox(const Color(0x7FCCFFFF), desiredSize: const Size(30.0, 40.0)));
row.add(subrow);
@@ -48,7 +60,10 @@
void addJustificationRow(MainAxisAlignment justify) {
const TextStyle style = const TextStyle(color: const Color(0xFF000000));
- final RenderParagraph paragraph = new RenderParagraph(new TextSpan(style: style, text: '$justify'));
+ final RenderParagraph paragraph = new RenderParagraph(
+ new TextSpan(style: style, text: '$justify'),
+ textDirection: TextDirection.ltr,
+ );
table.add(new RenderPadding(child: paragraph, padding: const EdgeInsets.only(top: 20.0)));
final RenderFlex row = new RenderFlex(direction: Axis.horizontal);
row.add(new RenderSolidColorBox(const Color(0xFFFFCCCC), desiredSize: const Size(80.0, 60.0)));
diff --git a/examples/layers/rendering/hello_world.dart b/examples/layers/rendering/hello_world.dart
index 2c772d1..69a4dc2 100644
--- a/examples/layers/rendering/hello_world.dart
+++ b/examples/layers/rendering/hello_world.dart
@@ -16,7 +16,14 @@
alignment: FractionalOffset.center,
// We use a RenderParagraph to display the text 'Hello, world.' without
// any explicit styling.
- child: new RenderParagraph(const TextSpan(text: 'Hello, world.'))
+ child: new RenderParagraph(
+ const TextSpan(text: 'Hello, world.'),
+ // The text is in English so we specify the text direction as
+ // left-to-right. If the text had been in Hebrew or Arabic, we would
+ // have specified right-to-left. The Flutter framework does not assume a
+ // particular text direction.
+ textDirection: TextDirection.ltr,
+ ),
)
);
}
diff --git a/examples/layers/rendering/touch_input.dart b/examples/layers/rendering/touch_input.dart
index efa793b..891e509 100644
--- a/examples/layers/rendering/touch_input.dart
+++ b/examples/layers/rendering/touch_input.dart
@@ -104,8 +104,9 @@
final RenderParagraph paragraph = new RenderParagraph(
const TextSpan(
style: const TextStyle(color: Colors.black87),
- text: "Touch me!"
- )
+ text: "Touch me!",
+ ),
+ textDirection: TextDirection.ltr,
);
// A stack is a render object that layers its children on top of each other.
// The bottom later is our RenderDots object, and on top of that we show the
@@ -114,7 +115,7 @@
children: <RenderBox>[
new RenderDots(),
paragraph,
- ]
+ ],
);
// The "parentData" field of a render object is controlled by the render
// object's parent render object. Now that we've added the paragraph as a
diff --git a/examples/layers/test/smoketests/lib/main_test.dart b/examples/layers/test/smoketests/lib/main_test.dart
new file mode 100644
index 0000000..b516506
--- /dev/null
+++ b/examples/layers/test/smoketests/lib/main_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../lib/main.dart' as demo;
+
+void main() {
+ test('layers smoketest for lib/main.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/raw/canvas_test.dart b/examples/layers/test/smoketests/raw/canvas_test.dart
new file mode 100644
index 0000000..979180a
--- /dev/null
+++ b/examples/layers/test/smoketests/raw/canvas_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../raw/canvas.dart' as demo;
+
+void main() {
+ test('layers smoketest for raw/canvas.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/raw/hello_world_test.dart b/examples/layers/test/smoketests/raw/hello_world_test.dart
new file mode 100644
index 0000000..c46b114
--- /dev/null
+++ b/examples/layers/test/smoketests/raw/hello_world_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../raw/hello_world.dart' as demo;
+
+void main() {
+ test('layers smoketest for raw/hello_world.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/raw/spinning_square_test.dart b/examples/layers/test/smoketests/raw/spinning_square_test.dart
new file mode 100644
index 0000000..e289f2b
--- /dev/null
+++ b/examples/layers/test/smoketests/raw/spinning_square_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../raw/spinning_square.dart' as demo;
+
+void main() {
+ test('layers smoketest for raw/spinning_square.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/raw/text_test.dart b/examples/layers/test/smoketests/raw/text_test.dart
new file mode 100644
index 0000000..1ba1d38
--- /dev/null
+++ b/examples/layers/test/smoketests/raw/text_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../raw/text.dart' as demo;
+
+void main() {
+ test('layers smoketest for raw/text.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/raw/touch_input_test.dart b/examples/layers/test/smoketests/raw/touch_input_test.dart
new file mode 100644
index 0000000..09065d0
--- /dev/null
+++ b/examples/layers/test/smoketests/raw/touch_input_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../raw/touch_input.dart' as demo;
+
+void main() {
+ test('layers smoketest for raw/touch_input.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/rendering/custom_coordinate_systems_test.dart b/examples/layers/test/smoketests/rendering/custom_coordinate_systems_test.dart
new file mode 100644
index 0000000..c6bcf0a
--- /dev/null
+++ b/examples/layers/test/smoketests/rendering/custom_coordinate_systems_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../rendering/custom_coordinate_systems.dart' as demo;
+
+void main() {
+ test('layers smoketest for rendering/custom_coordinate_systems.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/rendering/flex_layout_test.dart b/examples/layers/test/smoketests/rendering/flex_layout_test.dart
new file mode 100644
index 0000000..1d1f6fe
--- /dev/null
+++ b/examples/layers/test/smoketests/rendering/flex_layout_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../rendering/flex_layout.dart' as demo;
+
+void main() {
+ test('layers smoketest for rendering/flex_layout.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/rendering/hello_world_test.dart b/examples/layers/test/smoketests/rendering/hello_world_test.dart
new file mode 100644
index 0000000..df8932b
--- /dev/null
+++ b/examples/layers/test/smoketests/rendering/hello_world_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../rendering/hello_world.dart' as demo;
+
+void main() {
+ test('layers smoketest for rendering/hello_world.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/rendering/spinning_square_test.dart b/examples/layers/test/smoketests/rendering/spinning_square_test.dart
new file mode 100644
index 0000000..78ceb99
--- /dev/null
+++ b/examples/layers/test/smoketests/rendering/spinning_square_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../rendering/spinning_square.dart' as demo;
+
+void main() {
+ test('layers smoketest for rendering/spinning_square.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/rendering/touch_input_test.dart b/examples/layers/test/smoketests/rendering/touch_input_test.dart
new file mode 100644
index 0000000..dae629f
--- /dev/null
+++ b/examples/layers/test/smoketests/rendering/touch_input_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../rendering/touch_input.dart' as demo;
+
+void main() {
+ test('layers smoketest for rendering/touch_input.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/services/isolate_test.dart b/examples/layers/test/smoketests/services/isolate_test.dart
new file mode 100644
index 0000000..ed5efc1
--- /dev/null
+++ b/examples/layers/test/smoketests/services/isolate_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../services/isolate.dart' as demo;
+
+void main() {
+ test('layers smoketest for services/isolate.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/services/lifecycle_test.dart b/examples/layers/test/smoketests/services/lifecycle_test.dart
new file mode 100644
index 0000000..fa6f4ce
--- /dev/null
+++ b/examples/layers/test/smoketests/services/lifecycle_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../services/lifecycle.dart' as demo;
+
+void main() {
+ test('layers smoketest for services/lifecycle.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/custom_render_box_test.dart b/examples/layers/test/smoketests/widgets/custom_render_box_test.dart
new file mode 100644
index 0000000..2744ebb
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/custom_render_box_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/custom_render_box.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/custom_render_box.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/gestures_test.dart b/examples/layers/test/smoketests/widgets/gestures_test.dart
new file mode 100644
index 0000000..44f8422
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/gestures_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/gestures.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/gestures.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/hello_world_test.dart b/examples/layers/test/smoketests/widgets/hello_world_test.dart
new file mode 100644
index 0000000..0d6cb4e
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/hello_world_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/hello_world.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/hello_world.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/media_query_test.dart b/examples/layers/test/smoketests/widgets/media_query_test.dart
new file mode 100644
index 0000000..f7540f8
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/media_query_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/media_query.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/media_query.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/sectors_test.dart b/examples/layers/test/smoketests/widgets/sectors_test.dart
new file mode 100644
index 0000000..4171497
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/sectors_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/sectors.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/sectors.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/spinning_mixed_test.dart b/examples/layers/test/smoketests/widgets/spinning_mixed_test.dart
new file mode 100644
index 0000000..6cb3bd5
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/spinning_mixed_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/spinning_mixed.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/spinning_mixed.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/spinning_square_test.dart b/examples/layers/test/smoketests/widgets/spinning_square_test.dart
new file mode 100644
index 0000000..e24858d
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/spinning_square_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/spinning_square.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/spinning_square.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/test/smoketests/widgets/styled_text_test.dart b/examples/layers/test/smoketests/widgets/styled_text_test.dart
new file mode 100644
index 0000000..3fc1a05
--- /dev/null
+++ b/examples/layers/test/smoketests/widgets/styled_text_test.dart
@@ -0,0 +1,13 @@
+// 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:test/test.dart';
+
+import '../../../widgets/styled_text.dart' as demo;
+
+void main() {
+ test('layers smoketest for widgets/styled_text.dart', () {
+ demo.main();
+ });
+}
diff --git a/examples/layers/widgets/hello_world.dart b/examples/layers/widgets/hello_world.dart
index 1ad8675..93f7f5b 100644
--- a/examples/layers/widgets/hello_world.dart
+++ b/examples/layers/widgets/hello_world.dart
@@ -4,4 +4,4 @@
import 'package:flutter/widgets.dart';
-void main() => runApp(const Center(child: const Text('Hello, world!')));
+void main() => runApp(const Center(child: const Text('Hello, world!', textDirection: TextDirection.ltr)));
diff --git a/examples/layers/widgets/spinning_mixed.dart b/examples/layers/widgets/spinning_mixed.dart
index 71ba4da..8b2a404 100644
--- a/examples/layers/widgets/spinning_mixed.dart
+++ b/examples/layers/widgets/spinning_mixed.dart
@@ -37,40 +37,43 @@
void attachWidgetTreeToRenderTree(RenderProxyBox container) {
element = new RenderObjectToWidgetAdapter<RenderBox>(
container: container,
- child: new Container(
- height: 300.0,
- child: new Column(
- children: <Widget>[
- const Rectangle(const Color(0xFF00FFFF)),
- new Material(
- child: new Container(
- padding: const EdgeInsets.all(10.0),
- margin: const EdgeInsets.all(10.0),
- child: new Row(
- children: <Widget>[
- new RaisedButton(
- child: new Row(
- children: <Widget>[
- new Image.network('https://flutter.io/images/favicon.png'),
- const Text('PRESS ME'),
- ]
+ child: new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Container(
+ height: 300.0,
+ child: new Column(
+ children: <Widget>[
+ const Rectangle(const Color(0xFF00FFFF)),
+ new Material(
+ child: new Container(
+ padding: const EdgeInsets.all(10.0),
+ margin: const EdgeInsets.all(10.0),
+ child: new Row(
+ children: <Widget>[
+ new RaisedButton(
+ child: new Row(
+ children: <Widget>[
+ new Image.network('https://flutter.io/images/favicon.png'),
+ const Text('PRESS ME'),
+ ],
+ ),
+ onPressed: () {
+ value = value == null ? 0.1 : (value + 0.1) % 1.0;
+ attachWidgetTreeToRenderTree(container);
+ },
),
- onPressed: () {
- value = value == null ? 0.1 : (value + 0.1) % 1.0;
- attachWidgetTreeToRenderTree(container);
- }
- ),
- new CircularProgressIndicator(value: value),
- ],
- mainAxisAlignment: MainAxisAlignment.spaceAround
- )
- )
- ),
- const Rectangle(const Color(0xFFFFFF00)),
- ],
- mainAxisAlignment: MainAxisAlignment.spaceBetween
- )
- )
+ new CircularProgressIndicator(value: value),
+ ],
+ mainAxisAlignment: MainAxisAlignment.spaceAround,
+ ),
+ ),
+ ),
+ const Rectangle(const Color(0xFFFFFF00)),
+ ],
+ mainAxisAlignment: MainAxisAlignment.spaceBetween,
+ ),
+ ),
+ ),
).attachToRenderTree(owner, element);
}
diff --git a/packages/flutter/lib/foundation.dart b/packages/flutter/lib/foundation.dart
index 5d06b77..18c2099 100644
--- a/packages/flutter/lib/foundation.dart
+++ b/packages/flutter/lib/foundation.dart
@@ -46,3 +46,4 @@
export 'src/foundation/profile.dart';
export 'src/foundation/serialization.dart';
export 'src/foundation/synchronous_future.dart';
+export 'src/foundation/unicode.dart';
diff --git a/packages/flutter/lib/src/foundation/unicode.dart b/packages/flutter/lib/src/foundation/unicode.dart
new file mode 100644
index 0000000..a51e907
--- /dev/null
+++ b/packages/flutter/lib/src/foundation/unicode.dart
@@ -0,0 +1,98 @@
+// 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.
+
+/// Constants for useful Unicode characters.
+///
+/// Currently, these characters are all related to bidirectional text.
+///
+/// See also:
+///
+/// * <http://unicode.org/reports/tr9/>, which describes the Unicode
+/// bidirectional text algorithm.
+class Unicode {
+ Unicode._();
+ /// U+202A LEFT-TO-RIGHT EMBEDDING
+ ///
+ /// Treat the following text as embedded left-to-right.
+ ///
+ /// Use [PDF] to end the embedding.
+ static const String LRE = '\u202A';
+
+ /// U+202B RIGHT-TO-LEFT EMBEDDING
+ ///
+ /// Treat the following text as embedded right-to-left.
+ ///
+ /// Use [PDF] to end the embedding.
+ static const String RLE = '\u202B';
+
+ /// U+202C POP DIRECTIONAL FORMATTING
+ ///
+ /// End the scope of the last [LRE], [RLE], [RLO], or [LRO].
+ static const String PDF = '\u202C';
+
+ /// U+202A LEFT-TO-RIGHT OVERRIDE
+ ///
+ /// Force following characters to be treated as strong left-to-right characters.
+ ///
+ /// For example, this causes Hebrew text to render backwards.
+ ///
+ /// Use [PDF] to end the override.
+ static const String LRO = '\u202D';
+
+ /// U+202B RIGHT-TO-LEFT OVERRIDE
+ ///
+ /// Force following characters to be treated as strong right-to-left characters.
+ ///
+ /// For example, this causes English text to render backwards.
+ ///
+ /// Use [PDF] to end the override.
+ static const String RLO = '\u202E';
+
+ /// U+2066 LEFT-TO-RIGHT ISOLATE
+ ///
+ /// Treat the following text as isolated and left-to-right.
+ ///
+ /// Use [PDI] to end the isolated scope.
+ static const String LRI = '\u2066';
+
+ /// U+2067 RIGHT-TO-LEFT ISOLATE
+ ///
+ /// Treat the following text as isolated and right-to-left.
+ ///
+ /// Use [PDI] to end the isolated scope.
+ static const String RLI = '\u2067';
+
+ /// U+2068 FIRST STRONG ISOLATE
+ ///
+ /// Treat the following text as isolated and in the direction of its first
+ /// strong directional character that is not inside a nested isolate.
+ ///
+ /// This essentially "autodetects" the directionality of the text. It is not
+ /// 100% reliable. For example, Arabic text that starts with an English quote
+ /// will be detected as LTR, not RTL, which will lead to the text being in a
+ /// weird order.
+ ///
+ /// Use [PDI] to end the isolated scope.
+ static const String FSI = '\u2068';
+
+ /// U+2069 POP DIRECTIONAL ISOLATE
+ ///
+ /// End the scope of the last [LRI], [RLI], or [FSI].
+ static const String PDI = '\u2069';
+
+ /// U+200E LEFT-TO-RIGHT MARK
+ ///
+ /// Left-to-right zero-width character.
+ static const String LRM = '\u200E';
+
+ /// U+200F RIGHT-TO-LEFT MARK
+ ///
+ /// Right-to-left zero-width non-Arabic character.
+ static const String RLM = '\u200F';
+
+ /// U+061C ARABIC LETTER MARK
+ ///
+ /// Right-to-left zero-width Arabic character.
+ static const String ALM = '\u061C';
+}
diff --git a/packages/flutter/lib/src/material/slider.dart b/packages/flutter/lib/src/material/slider.dart
index db40342..426f9ac 100644
--- a/packages/flutter/lib/src/material/slider.dart
+++ b/packages/flutter/lib/src/material/slider.dart
@@ -295,6 +295,7 @@
@required TextDirection textDirection,
}) : assert(value != null && value >= 0.0 && value <= 1.0),
assert(textDirection != null),
+ _label = label,
_value = value,
_divisions = divisions,
_activeColor = activeColor,
@@ -303,7 +304,7 @@
_textTheme = textTheme,
_onChanged = onChanged,
_textDirection = textDirection {
- this.label = label;
+ _updateLabelPainter();
final GestureArenaTeam team = new GestureArenaTeam();
_drag = new HorizontalDragGestureRecognizer()
..team = team
@@ -356,19 +357,7 @@
if (value == _label)
return;
_label = value;
- if (value != null) {
- // TODO(abarth): Handle textScaleFactor.
- // https://github.com/flutter/flutter/issues/5938
- _labelPainter
- ..text = new TextSpan(
- style: _textTheme.body1.copyWith(fontSize: 10.0),
- text: value
- )
- ..layout();
- } else {
- _labelPainter.text = null;
- }
- markNeedsLayout();
+ _updateLabelPainter();
}
Color get activeColor => _activeColor;
@@ -424,11 +413,29 @@
TextDirection _textDirection;
set textDirection(TextDirection value) {
assert(value != null);
- if (_textDirection == value)
+ if (value == _textDirection)
return;
_textDirection = value;
- // TODO(abarth): Update _labelPainter's text direction.
- markNeedsPaint();
+ _updateLabelPainter();
+ }
+
+ void _updateLabelPainter() {
+ if (label != null) {
+ // TODO(abarth): Handle textScaleFactor. https://github.com/flutter/flutter/issues/5938
+ _labelPainter
+ ..text = new TextSpan(
+ style: _textTheme.body1.copyWith(fontSize: 10.0),
+ text: label,
+ )
+ ..textDirection = textDirection
+ ..layout();
+ } else {
+ _labelPainter.text = null;
+ }
+ // Changing the textDirection can result in the layout changing, because the
+ // bidi algorithm might line up the glyphs differently which can result in
+ // different ligatures, different shapes, etc. So we always markNeedsLayout.
+ markNeedsLayout();
}
double get _trackLength => size.width - 2.0 * _kReactionRadius;
@@ -633,7 +640,6 @@
..lineTo(center.dx + tipAttachment, center.dy + tipAttachment)
..close();
canvas.drawPath(path, primaryPaint);
- _labelPainter.layout();
final Offset labelOffset = new Offset(
center.dx - _labelPainter.width / 2.0,
center.dy - _labelPainter.height / 2.0
diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart
index 0f3e013..528cad1 100644
--- a/packages/flutter/lib/src/material/text_field.dart
+++ b/packages/flutter/lib/src/material/text_field.dart
@@ -69,8 +69,8 @@
/// the number of lines. By default, it is 1, meaning this is a single-line
/// text field. If it is not null, it must be greater than zero.
///
- /// The [keyboardType], [autofocus], [obscureText], and [autocorrect] arguments
- /// must not be null.
+ /// The [keyboardType], [textAlign], [autofocus], [obscureText], and
+ /// [autocorrect] arguments must not be null.
const TextField({
Key key,
this.controller,
@@ -78,7 +78,7 @@
this.decoration: const InputDecoration(),
this.keyboardType: TextInputType.text,
this.style,
- this.textAlign,
+ this.textAlign: TextAlign.start,
this.autofocus: false,
this.obscureText: false,
this.autocorrect: true,
@@ -87,6 +87,7 @@
this.onSubmitted,
this.inputFormatters,
}) : assert(keyboardType != null),
+ assert(textAlign != null),
assert(autofocus != null),
assert(obscureText != null),
assert(autocorrect != null),
@@ -125,6 +126,8 @@
final TextStyle style;
/// How the text being edited should be aligned horizontally.
+ ///
+ /// Defaults to [TextAlign.start].
final TextAlign textAlign;
/// Whether this text field should focus itself if nothing else is already
diff --git a/packages/flutter/lib/src/material/time_picker.dart b/packages/flutter/lib/src/material/time_picker.dart
index cca45f0..f1ce572 100644
--- a/packages/flutter/lib/src/material/time_picker.dart
+++ b/packages/flutter/lib/src/material/time_picker.dart
@@ -356,7 +356,8 @@
// TODO(abarth): Handle textScaleFactor.
// https://github.com/flutter/flutter/issues/5939
painters[i] = new TextPainter(
- text: new TextSpan(style: style, text: label)
+ text: new TextSpan(style: style, text: label),
+ textDirection: TextDirection.ltr,
)..layout();
}
return painters;
diff --git a/packages/flutter/lib/src/painting/flutter_logo.dart b/packages/flutter/lib/src/painting/flutter_logo.dart
index d647613..d8a027b 100644
--- a/packages/flutter/lib/src/painting/flutter_logo.dart
+++ b/packages/flutter/lib/src/painting/flutter_logo.dart
@@ -247,9 +247,10 @@
fontFamily: 'Roboto',
fontSize: 100.0 * 350.0 / 247.0, // 247 is the height of the F when the fontSize is 350, assuming device pixel ratio 1.0
fontWeight: FontWeight.w300,
- textBaseline: TextBaseline.alphabetic
- )
- )
+ textBaseline: TextBaseline.alphabetic,
+ ),
+ ),
+ textDirection: TextDirection.ltr,
);
_textPainter.layout();
final ui.TextBox textSize = _textPainter.getBoxesForSelection(const TextSelection(baseOffset: 0, extentOffset: kLabel.length)).single;
diff --git a/packages/flutter/lib/src/painting/text_painter.dart b/packages/flutter/lib/src/painting/text_painter.dart
index 03a3ca9..3fee2d9 100644
--- a/packages/flutter/lib/src/painting/text_painter.dart
+++ b/packages/flutter/lib/src/painting/text_painter.dart
@@ -33,21 +33,26 @@
class TextPainter {
/// Creates a text painter that paints the given text.
///
- /// The text argument is optional but [text] must be non-null before calling
- /// [layout].
+ /// The `text` and `textDirection` arguments are optional but [text] and
+ /// [textDirection] must be non-null before calling [layout].
+ ///
+ /// The [textAlign] property must not be null.
///
/// The [maxLines] property, if non-null, must be greater than zero.
TextPainter({
TextSpan text,
- TextAlign textAlign,
+ TextAlign textAlign: TextAlign.start,
+ TextDirection textDirection,
double textScaleFactor: 1.0,
int maxLines,
String ellipsis,
}) : assert(text == null || text.debugAssertIsValid()),
+ assert(textAlign != null),
assert(textScaleFactor != null),
assert(maxLines == null || maxLines > 0),
_text = text,
_textAlign = textAlign,
+ _textDirection = textDirection,
_textScaleFactor = textScaleFactor,
_maxLines = maxLines,
_ellipsis = ellipsis;
@@ -58,6 +63,8 @@
/// The (potentially styled) text to paint.
///
/// After this is set, you must call [layout] before the next call to [paint].
+ ///
+ /// This and [textDirection] must be non-null before you call [layout].
TextSpan get text => _text;
TextSpan _text;
set text(TextSpan value) {
@@ -74,9 +81,12 @@
/// How the text should be aligned horizontally.
///
/// After this is set, you must call [layout] before the next call to [paint].
+ ///
+ /// The [textAlign] property must not be null. It defaults to [TextAlign.start].
TextAlign get textAlign => _textAlign;
TextAlign _textAlign;
set textAlign(TextAlign value) {
+ assert(value != null);
if (_textAlign == value)
return;
_textAlign = value;
@@ -84,6 +94,32 @@
_needsLayout = true;
}
+ /// The default directionality of the text.
+ ///
+ /// This controls how the [TextAlign.start], [TextAlign.end], and
+ /// [TextAlign.justify] values of [textAlign] are resolved.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the [text] is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// After this is set, you must call [layout] before the next call to [paint].
+ ///
+ /// This and [text] must be non-null before you call [layout].
+ TextDirection get textDirection => _textDirection;
+ TextDirection _textDirection;
+ set textDirection(TextDirection value) {
+ if (_textDirection == value)
+ return;
+ _textDirection = value;
+ _paragraph = null;
+ _layoutTemplate = null; // Shouldn't really matter, but for strict correctness...
+ _needsLayout = true;
+ }
+
/// The number of font pixels for each logical pixel.
///
/// For example, if the text scale factor is 1.5, text will be 50% larger than
@@ -149,14 +185,20 @@
ui.Paragraph _layoutTemplate;
- ui.ParagraphStyle _createParagraphStyle() {
+ ui.ParagraphStyle _createParagraphStyle([TextDirection defaultTextDirection]) {
+ // The defaultTextDirection argument is used for preferredLineHeight in case
+ // textDirection hasn't yet been set.
+ assert(textAlign != null);
+ assert(textDirection != null || defaultTextDirection != null, 'TextPainter.textDirection must be set to a non-null value before using the TextPainter.');
return _text.style?.getParagraphStyle(
textAlign: textAlign,
+ textDirection: textDirection ?? defaultTextDirection,
textScaleFactor: textScaleFactor,
maxLines: _maxLines,
ellipsis: _ellipsis,
) ?? new ui.ParagraphStyle(
textAlign: textAlign,
+ textDirection: textDirection ?? defaultTextDirection,
maxLines: maxLines,
ellipsis: ellipsis,
);
@@ -169,11 +211,17 @@
/// relative a typical line of text.
///
/// Obtaining this value does not require calling [layout].
+ ///
+ /// The style of the [text] property is used to determine the font settings
+ /// that contribute to the [preferredLineHeight]. If [text] is null or if it
+ /// specifies no styles, the default [TextStyle] values are used (a 10 pixel
+ /// sans-serif font).
double get preferredLineHeight {
- assert(text != null);
if (_layoutTemplate == null) {
- final ui.ParagraphBuilder builder = new ui.ParagraphBuilder(_createParagraphStyle());
- if (text.style != null)
+ final ui.ParagraphBuilder builder = new ui.ParagraphBuilder(
+ _createParagraphStyle(TextDirection.rtl),
+ ); // direction doesn't matter, text is just a zero width space
+ if (text?.style != null)
builder.pushStyle(text.style.getTextStyle(textScaleFactor: textScaleFactor));
builder.addText(_kZeroWidthSpace);
_layoutTemplate = builder.build()
@@ -272,10 +320,14 @@
/// Computes the visual position of the glyphs for painting the text.
///
/// The text will layout with a width that's as close to its max intrinsic
- /// width as possible while still being greater than or equal to minWidth and
- /// less than or equal to maxWidth.
+ /// width as possible while still being greater than or equal to `minWidth` and
+ /// less than or equal to `maxWidth`.
+ ///
+ /// The [text] and [textDirection] properties must be non-null before this is
+ /// called.
void layout({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
- assert(_text != null);
+ assert(text != null, 'TextPainter.text must be set to a non-null value before using the TextPainter.');
+ assert(textDirection != null, 'TextPainter.textDirection must be set to a non-null value before using the TextPainter.');
if (!_needsLayout && minWidth == _lastMinWidth && maxWidth == _lastMaxWidth)
return;
_needsLayout = false;
@@ -352,15 +404,34 @@
}
Offset get _emptyOffset {
- // TODO(abarth): Handle the directionality of the text painter itself.
- switch (textAlign ?? TextAlign.left) {
+ assert(!_needsLayout); // implies textDirection is non-null
+ assert(textAlign != null);
+ switch (textAlign) {
case TextAlign.left:
- case TextAlign.justify:
return Offset.zero;
case TextAlign.right:
return new Offset(width, 0.0);
case TextAlign.center:
return new Offset(width / 2.0, 0.0);
+ case TextAlign.justify:
+ case TextAlign.start:
+ assert(textDirection != null);
+ switch (textDirection) {
+ case TextDirection.rtl:
+ return new Offset(width, 0.0);
+ case TextDirection.ltr:
+ return Offset.zero;
+ }
+ return null;
+ case TextAlign.end:
+ assert(textDirection != null);
+ switch (textDirection) {
+ case TextDirection.rtl:
+ return Offset.zero;
+ case TextDirection.ltr:
+ return new Offset(width, 0.0);
+ }
+ return null;
}
return null;
}
diff --git a/packages/flutter/lib/src/painting/text_style.dart b/packages/flutter/lib/src/painting/text_style.dart
index 2c8cdf2..747307d 100644
--- a/packages/flutter/lib/src/painting/text_style.dart
+++ b/packages/flutter/lib/src/painting/text_style.dart
@@ -369,6 +369,7 @@
/// specified and non-null, must be greater than zero.
ui.ParagraphStyle getParagraphStyle({
TextAlign textAlign,
+ TextDirection textDirection,
double textScaleFactor: 1.0,
String ellipsis,
int maxLines,
@@ -377,6 +378,7 @@
assert(maxLines == null || maxLines > 0);
return new ui.ParagraphStyle(
textAlign: textAlign,
+ textDirection: textDirection,
fontWeight: fontWeight,
fontStyle: fontStyle,
fontFamily: fontFamily,
@@ -418,7 +420,7 @@
bool operator ==(dynamic other) {
if (identical(this, other))
return true;
- if (other is! TextStyle)
+ if (other.runtimeType != runtimeType)
return false;
final TextStyle typedOther = other;
return inherit == typedOther.inherit &&
diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart
index 994e129..3439e01 100644
--- a/packages/flutter/lib/src/rendering/editable.dart
+++ b/packages/flutter/lib/src/rendering/editable.dart
@@ -87,6 +87,10 @@
class RenderEditable extends RenderBox {
/// Creates a render object that implements the visual aspects of a text field.
///
+ /// The [textAlign] argument must not be null. It defaults to [TextAlign.start].
+ ///
+ /// The [textDirection] argument must not be null.
+ ///
/// If [showCursor] is not specified, then it defaults to hiding the cursor.
///
/// The [maxLines] property can be set to null to remove the restriction on
@@ -97,7 +101,8 @@
/// ViewportOffset.zero] if you have no need for scrolling.
RenderEditable({
TextSpan text,
- TextAlign textAlign,
+ @required TextDirection textDirection,
+ TextAlign textAlign: TextAlign.start,
Color cursorColor,
ValueNotifier<bool> showCursor,
int maxLines: 1,
@@ -107,10 +112,17 @@
@required ViewportOffset offset,
this.onSelectionChanged,
this.onCaretChanged,
- }) : assert(maxLines == null || maxLines > 0),
+ }) : assert(textAlign != null),
+ assert(textDirection != null, 'RenderEditable created without a textDirection.'),
+ assert(maxLines == null || maxLines > 0),
assert(textScaleFactor != null),
assert(offset != null),
- _textPainter = new TextPainter(text: text, textAlign: textAlign, textScaleFactor: textScaleFactor),
+ _textPainter = new TextPainter(
+ text: text,
+ textAlign: textAlign,
+ textDirection: textDirection,
+ textScaleFactor: textScaleFactor,
+ ),
_cursorColor = cursorColor,
_showCursor = showCursor ?? new ValueNotifier<bool>(false),
_maxLines = maxLines,
@@ -146,7 +158,7 @@
markNeedsLayout();
}
- /// The text to display
+ /// The text to display.
TextSpan get text => _textPainter.text;
final TextPainter _textPainter;
set text(TextSpan value) {
@@ -157,14 +169,39 @@
}
/// How the text should be aligned horizontally.
+ ///
+ /// This must not be null.
TextAlign get textAlign => _textPainter.textAlign;
set textAlign(TextAlign value) {
+ assert(value != null);
if (_textPainter.textAlign == value)
return;
_textPainter.textAlign = value;
markNeedsPaint();
}
+ /// The directionality of the text.
+ ///
+ /// This decides how the [TextAlign.start], [TextAlign.end], and
+ /// [TextAlign.justify] values of [textAlign] are interpreted.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the [text] is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// This must not be null.
+ TextDirection get textDirection => _textPainter.textDirection;
+ set textDirection(TextDirection value) {
+ assert(value != null);
+ if (_textPainter.textDirection == value)
+ return;
+ _textPainter.textDirection = value;
+ markNeedsTextLayout();
+ }
+
/// The color to use when painting the cursor.
Color get cursorColor => _cursorColor;
Color _cursorColor;
diff --git a/packages/flutter/lib/src/rendering/flex.dart b/packages/flutter/lib/src/rendering/flex.dart
index aa49614..3f93ad1 100644
--- a/packages/flutter/lib/src/rendering/flex.dart
+++ b/packages/flutter/lib/src/rendering/flex.dart
@@ -993,12 +993,13 @@
}
context.canvas.drawRect(markerRect, _debugMarkerPaint);
- _debugMarkerLabel ??= new TextPainter();
- _debugMarkerLabel.text = new TextSpan( // this is a no-op if the label hasn't changed
+ _debugMarkerLabel ??= new TextPainter()
+ ..textDirection = TextDirection.ltr; // This label is in English.
+ _debugMarkerLabel.text = new TextSpan( // This is a no-op if the label hasn't changed.
text: label,
style: _debugMarkerTextStyle,
);
- _debugMarkerLabel.layout(); // this is a no-op if the label hasn't changed
+ _debugMarkerLabel.layout(); // This is a no-op if the label hasn't changed.
// TODO(ianh): RTL support
switch (direction) {
diff --git a/packages/flutter/lib/src/rendering/object.dart b/packages/flutter/lib/src/rendering/object.dart
index 72a68d9..5899eb3 100644
--- a/packages/flutter/lib/src/rendering/object.dart
+++ b/packages/flutter/lib/src/rendering/object.dart
@@ -2867,11 +2867,11 @@
@override
void debugFillProperties(DiagnosticPropertiesBuilder description) {
description.add(new DiagnosticsProperty<dynamic>('creator', debugCreator, defaultValue: null));
- description.add(new DiagnosticsProperty<ParentData>('parentData', parentData, tooltip: _debugCanParentUseSize == true ? "can use size" : null));
- description.add(new DiagnosticsProperty<Constraints>('constraints', constraints));
+ description.add(new DiagnosticsProperty<ParentData>('parentData', parentData, tooltip: _debugCanParentUseSize == true ? 'can use size' : null, ifNull: 'MISSING'));
+ description.add(new DiagnosticsProperty<Constraints>('constraints', constraints, ifNull: 'MISSING'));
// don't access it via the "layer" getter since that's only valid when we don't need paint
description.add(new DiagnosticsProperty<OffsetLayer>('layer', _layer, defaultValue: null));
- description.add(new DiagnosticsProperty<SemanticsNode>('_semantics', _semantics, defaultValue: null));
+ description.add(new DiagnosticsProperty<SemanticsNode>('semantics node', _semantics, defaultValue: null));
description.add(new FlagProperty(
'isBlockingSemanticsOfPreviouslyPaintedNodes',
value: isBlockingSemanticsOfPreviouslyPaintedNodes,
diff --git a/packages/flutter/lib/src/rendering/paragraph.dart b/packages/flutter/lib/src/rendering/paragraph.dart
index 14d9f61..83b1304 100644
--- a/packages/flutter/lib/src/rendering/paragraph.dart
+++ b/packages/flutter/lib/src/rendering/paragraph.dart
@@ -32,19 +32,22 @@
class RenderParagraph extends RenderBox {
/// Creates a paragraph render object.
///
- /// The [text], [overflow], [softWrap], and [textScaleFactor] arguments must
- /// not be null.
+ /// The [text], [textAlign], [textDirection], [overflow], [softWrap], and
+ /// [textScaleFactor] arguments must not be null.
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
RenderParagraph(TextSpan text, {
- TextAlign textAlign,
+ TextAlign textAlign: TextAlign.start,
+ @required TextDirection textDirection,
bool softWrap: true,
TextOverflow overflow: TextOverflow.clip,
double textScaleFactor: 1.0,
int maxLines,
}) : assert(text != null),
assert(text.debugAssertIsValid()),
+ assert(textAlign != null),
+ assert(textDirection != null),
assert(softWrap != null),
assert(overflow != null),
assert(textScaleFactor != null),
@@ -54,6 +57,7 @@
_textPainter = new TextPainter(
text: text,
textAlign: textAlign,
+ textDirection: textDirection,
textScaleFactor: textScaleFactor,
maxLines: maxLines,
ellipsis: overflow == TextOverflow.ellipsis ? _kEllipsis : null,
@@ -84,12 +88,35 @@
/// How the text should be aligned horizontally.
TextAlign get textAlign => _textPainter.textAlign;
set textAlign(TextAlign value) {
+ assert(value != null);
if (_textPainter.textAlign == value)
return;
_textPainter.textAlign = value;
markNeedsPaint();
}
+ /// The directionality of the text.
+ ///
+ /// This decides how the [TextAlign.start], [TextAlign.end], and
+ /// [TextAlign.justify] values of [textAlign] are interpreted.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the [text] is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// This must not be null.
+ TextDirection get textDirection => _textPainter.textDirection;
+ set textDirection(TextDirection value) {
+ assert(value != null);
+ if (_textPainter.textDirection == value)
+ return;
+ _textPainter.textDirection = value;
+ markNeedsLayout();
+ }
+
/// Whether the text should break at soft line breaks.
///
/// If false, the glyphs in the text will be positioned as if there was
@@ -148,10 +175,8 @@
}
void _layoutText({ double minWidth: 0.0, double maxWidth: double.INFINITY }) {
- _textPainter.layout(
- minWidth: minWidth,
- maxWidth: _softWrap || _overflow == TextOverflow.ellipsis ? maxWidth : double.INFINITY
- );
+ final bool widthMatters = softWrap || overflow == TextOverflow.ellipsis;
+ _textPainter.layout(minWidth: minWidth, maxWidth: widthMatters ? maxWidth : double.INFINITY);
}
void _layoutTextWithConstraints(BoxConstraints constraints) {
@@ -245,14 +270,24 @@
_overflowShader = null;
break;
case TextOverflow.fade:
+ assert(textDirection != null);
final TextPainter fadeSizePainter = new TextPainter(
text: new TextSpan(style: _textPainter.text.style, text: '\u2026'),
- textScaleFactor: textScaleFactor
+ textDirection: textDirection,
+ textScaleFactor: textScaleFactor,
)..layout();
if (didOverflowWidth) {
- final double fadeEnd = size.width;
- final double fadeStart = fadeEnd - fadeSizePainter.width;
- // TODO(abarth): This shader has an LTR bias.
+ double fadeEnd, fadeStart;
+ switch (textDirection) {
+ case TextDirection.rtl:
+ fadeEnd = 0.0;
+ fadeStart = fadeSizePainter.width;
+ break;
+ case TextDirection.ltr:
+ fadeEnd = size.width;
+ fadeStart = fadeEnd - fadeSizePainter.width;
+ break;
+ }
_overflowShader = new ui.Gradient.linear(
new Offset(fadeStart, 0.0),
new Offset(fadeEnd, 0.0),
@@ -373,10 +408,22 @@
void _annotate(SemanticsNode node) {
node.label = text.toPlainText();
+ node.textDirection = textDirection;
}
@override
List<DiagnosticsNode> debugDescribeChildren() {
return <DiagnosticsNode>[text.toDiagnosticsNode(name: 'text', style: DiagnosticsTreeStyle.transition)];
}
+
+ @override
+ void debugFillProperties(DiagnosticPropertiesBuilder description) {
+ super.debugFillProperties(description);
+ description.add(new EnumProperty<TextAlign>('textAlign', textAlign));
+ description.add(new EnumProperty<TextDirection>('textDirection', textDirection));
+ description.add(new FlagProperty('softWrap', value: softWrap, ifTrue: 'wrapping at box width', ifFalse: 'no wrapping except at line break characters', showName: true));
+ description.add(new EnumProperty<TextOverflow>('overflow', overflow));
+ description.add(new DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: 1.0));
+ description.add(new IntProperty('maxLines', maxLines, ifNull: 'unlimited'));
+ }
}
diff --git a/packages/flutter/lib/src/rendering/proxy_box.dart b/packages/flutter/lib/src/rendering/proxy_box.dart
index 9b6d0cc..56492c6 100644
--- a/packages/flutter/lib/src/rendering/proxy_box.dart
+++ b/packages/flutter/lib/src/rendering/proxy_box.dart
@@ -3114,17 +3114,21 @@
/// Creates a render object that attaches a semantic annotation.
///
/// The [container] argument must not be null.
+ ///
+ /// If the [label] is not null, the [textDirection] must also not be null.
RenderSemanticsAnnotations({
RenderBox child,
bool container: false,
bool checked,
bool selected,
String label,
+ TextDirection textDirection,
}) : assert(container != null),
_container = container,
_checked = checked,
_selected = selected,
_label = label,
+ _textDirection = textDirection,
super(child);
/// If 'container' is true, this RenderObject will introduce a new
@@ -3182,11 +3186,24 @@
markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
}
+ /// If non-null, sets the [SemanticsNode.textDirection] semantic to the given value.
+ ///
+ /// This must not be null if [label] is not null.
+ TextDirection get textDirection => _textDirection;
+ TextDirection _textDirection;
+ set textDirection(TextDirection value) {
+ if (textDirection == value)
+ return;
+ final bool hadValue = textDirection != null;
+ _textDirection = value;
+ markNeedsSemanticsUpdate(onlyLocalUpdates: (value != null) == hadValue);
+ }
+
@override
bool get isSemanticBoundary => container;
@override
- SemanticsAnnotator get semanticsAnnotator => checked != null || selected != null || label != null ? _annotate : null;
+ SemanticsAnnotator get semanticsAnnotator => checked != null || selected != null || label != null || textDirection != null ? _annotate : null;
void _annotate(SemanticsNode node) {
if (checked != null) {
@@ -3198,6 +3215,8 @@
node.isSelected = selected;
if (label != null)
node.label = label;
+ if (textDirection != null)
+ node.textDirection = textDirection;
}
}
diff --git a/packages/flutter/lib/src/rendering/semantics.dart b/packages/flutter/lib/src/rendering/semantics.dart
index f1c27b6..17e5c52 100644
--- a/packages/flutter/lib/src/rendering/semantics.dart
+++ b/packages/flutter/lib/src/rendering/semantics.dart
@@ -92,16 +92,20 @@
/// Creates a semantics data object.
///
/// The [flags], [actions], [label], and [Rect] arguments must not be null.
+ ///
+ /// If [label] is not empty, then [textDirection] must also not be null.
const SemanticsData({
@required this.flags,
@required this.actions,
@required this.label,
+ @required this.textDirection,
@required this.rect,
@required this.tags,
- this.transform
+ this.transform,
}) : assert(flags != null),
assert(actions != null),
assert(label != null),
+ assert(label == '' || textDirection != null, 'A SemanticsData object with label "$label" had a null textDirection.'),
assert(rect != null),
assert(tags != null);
@@ -112,8 +116,13 @@
final int actions;
/// A textual description of this node.
+ ///
+ /// The text's reading direction is given by [textDirection].
final String label;
+ /// The reading direction for the text in [label].
+ final TextDirection textDirection;
+
/// The bounding box for this node in its coordinate system.
final Rect rect;
@@ -149,6 +158,8 @@
}
if (label.isNotEmpty)
buffer.write('; "$label"');
+ if (textDirection != null)
+ buffer.write('; $textDirection');
buffer.write(')');
return buffer.toString();
}
@@ -161,13 +172,14 @@
return typedOther.flags == flags
&& typedOther.actions == actions
&& typedOther.label == label
+ && typedOther.textDirection == textDirection
&& typedOther.rect == rect
&& setEquals(typedOther.tags, tags)
&& typedOther.transform == transform;
}
@override
- int get hashCode => hashValues(flags, actions, label, rect, tags, transform);
+ int get hashCode => hashValues(flags, actions, label, textDirection, rect, tags, transform);
}
/// A node that represents some semantic data.
@@ -342,6 +354,8 @@
set isSelected(bool value) => _setFlag(SemanticsFlags.isSelected, value);
/// A textual description of this node.
+ ///
+ /// The text's reading direction is given by [textDirection].
String get label => _label;
String _label = '';
set label(String value) {
@@ -352,6 +366,17 @@
}
}
+ /// The reading direction for the text in [label].
+ TextDirection get textDirection => _textDirection;
+ TextDirection _textDirection;
+ set textDirection(TextDirection value) {
+ assert(value != null);
+ if (_textDirection != value) {
+ _textDirection = value;
+ _markDirty();
+ }
+ }
+
final Set<SemanticsTag> _tags = new Set<SemanticsTag>();
/// Tags the [SemanticsNode] with [tag].
@@ -385,6 +410,7 @@
if (hadInheritedMergeAllDescendantsIntoThisNode)
_inheritedMergeAllDescendantsIntoThisNodeValue = true;
_label = '';
+ _textDirection = null;
_tags.clear();
_markDirty();
}
@@ -598,18 +624,31 @@
int flags = _flags;
int actions = _actions;
String label = _label;
+ TextDirection textDirection = _textDirection;
final Set<SemanticsTag> tags = new Set<SemanticsTag>.from(_tags);
if (mergeAllDescendantsIntoThisNode) {
_visitDescendants((SemanticsNode node) {
flags |= node._flags;
actions |= node._actions;
+ textDirection ??= node._textDirection;
tags.addAll(node._tags);
if (node.label.isNotEmpty) {
+ String nestedLabel = node.label;
+ if (textDirection != node.textDirection && node.textDirection != null) {
+ switch (node.textDirection) {
+ case TextDirection.rtl:
+ nestedLabel = '${Unicode.RLE}$nestedLabel${Unicode.PDF}';
+ break;
+ case TextDirection.ltr:
+ nestedLabel = '${Unicode.LRE}$nestedLabel${Unicode.PDF}';
+ break;
+ }
+ }
if (label.isEmpty)
- label = node.label;
+ label = nestedLabel;
else
- label = '$label\n${node.label}';
+ label = '$label\n$nestedLabel';
}
return true;
});
@@ -619,6 +658,7 @@
flags: flags,
actions: actions,
label: label,
+ textDirection: textDirection,
rect: rect,
transform: transform,
tags: tags,
@@ -650,6 +690,7 @@
actions: data.actions,
rect: data.rect,
label: data.label,
+ textDirection: data.textDirection,
transform: data.transform?.storage ?? _kIdentityTransform,
children: children,
);
@@ -696,6 +737,8 @@
buffer.write('; selected');
if (label.isNotEmpty)
buffer.write('; "$label"');
+ if (textDirection != null)
+ buffer.write('; $textDirection');
buffer.write(')');
return buffer.toString();
}
diff --git a/packages/flutter/lib/src/rendering/sliver_grid.dart b/packages/flutter/lib/src/rendering/sliver_grid.dart
index de1f752..037c67c 100644
--- a/packages/flutter/lib/src/rendering/sliver_grid.dart
+++ b/packages/flutter/lib/src/rendering/sliver_grid.dart
@@ -553,7 +553,8 @@
for (int index = indexOf(firstChild) - 1; index >= firstIndex; --index) {
final SliverGridGeometry gridGeometry = layout.getGeometryForChildIndex(index);
final RenderBox child = insertAndLayoutLeadingChild(
- gridGeometry.getBoxConstraints(constraints));
+ gridGeometry.getBoxConstraints(constraints),
+ );
final SliverGridParentData childParentData = child.parentData;
childParentData.layoutOffset = gridGeometry.scrollOffset;
childParentData.crossAxisOffset = gridGeometry.crossAxisOffset;
diff --git a/packages/flutter/lib/src/widgets/banner.dart b/packages/flutter/lib/src/widgets/banner.dart
index 8a75f89..1d8c22c 100644
--- a/packages/flutter/lib/src/widgets/banner.dart
+++ b/packages/flutter/lib/src/widgets/banner.dart
@@ -41,13 +41,15 @@
class BannerPainter extends CustomPainter {
/// Creates a banner painter.
///
- /// The [message] and [location] arguments must not be null.
+ /// The [message], [textDirection], and [location] arguments must not be null.
BannerPainter({
@required this.message,
+ @required this.textDirection,
@required this.location,
this.color: _kColor,
this.textStyle: _kTextStyle,
}) : assert(message != null),
+ assert(textDirection != null),
assert(location != null),
assert(color != null),
assert(textStyle != null);
@@ -55,6 +57,16 @@
/// The message to show in the banner.
final String message;
+ /// The directionality of the text.
+ ///
+ /// This is used to disambiguate how to render bidirectional text. For
+ /// example, if the message is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ final TextDirection textDirection;
+
/// Where to show the banner (e.g., the upper right corder).
final BannerLocation location;
@@ -82,6 +94,7 @@
_textPainter = new TextPainter(
text: new TextSpan(style: textStyle, text: message),
textAlign: TextAlign.center,
+ textDirection: textDirection,
);
_prepared = true;
}
@@ -169,6 +182,7 @@
Key key,
this.child,
@required this.message,
+ this.textDirection,
@required this.location,
this.color: _kColor,
this.textStyle: _kTextStyle,
@@ -184,6 +198,18 @@
/// The message to show in the banner.
final String message;
+ /// The directionality of the text.
+ ///
+ /// This is used to disambiguate how to render bidirectional text. For
+ /// example, if the message is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// Defaults to the ambient [Directionality], if any.
+ final TextDirection textDirection;
+
/// Where to show the banner (e.g., the upper right corder).
final BannerLocation location;
@@ -198,6 +224,7 @@
return new CustomPaint(
foregroundPainter: new BannerPainter(
message: message,
+ textDirection: textDirection ?? Directionality.of(context),
location: location,
color: color,
textStyle: textStyle,
@@ -210,6 +237,7 @@
void debugFillProperties(DiagnosticPropertiesBuilder description) {
super.debugFillProperties(description);
description.add(new StringProperty('message', message, showName: false));
+ description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
description.add(new EnumProperty<BannerLocation>('location', location));
description.add(new DiagnosticsProperty<Color>('color', color, showName: false));
textStyle?.debugFillProperties(description, prefix: 'text ');
@@ -236,7 +264,9 @@
result = new Banner(
child: result,
message: 'SLOW MODE',
- location: BannerLocation.topRight);
+ textDirection: TextDirection.ltr,
+ location: BannerLocation.topRight,
+ );
return true;
});
return result;
diff --git a/packages/flutter/lib/src/widgets/basic.dart b/packages/flutter/lib/src/widgets/basic.dart
index 2090de2..250f4b5 100644
--- a/packages/flutter/lib/src/widgets/basic.dart
+++ b/packages/flutter/lib/src/widgets/basic.dart
@@ -3704,20 +3704,25 @@
class RichText extends LeafRenderObjectWidget {
/// Creates a paragraph of rich text.
///
- /// The [text], [softWrap], [overflow], nad [textScaleFactor] arguments must
- /// not be null.
+ /// The [text], [textAlign], [softWrap], [overflow], nad [textScaleFactor]
+ /// arguments must not be null.
///
/// The [maxLines] property may be null (and indeed defaults to null), but if
/// it is not null, it must be greater than zero.
+ ///
+ /// The [textDirection], if null, defaults to the ambient [Directionality],
+ /// which in that case must not be null.
const RichText({
Key key,
@required this.text,
- this.textAlign,
+ this.textAlign: TextAlign.start,
+ this.textDirection,
this.softWrap: true,
this.overflow: TextOverflow.clip,
this.textScaleFactor: 1.0,
this.maxLines,
}) : assert(text != null),
+ assert(textAlign != null),
assert(softWrap != null),
assert(overflow != null),
assert(textScaleFactor != null),
@@ -3730,6 +3735,22 @@
/// How the text should be aligned horizontally.
final TextAlign textAlign;
+ /// The directionality of the text.
+ ///
+ /// This decides how [textAlign] values like [TextAlign.start] and
+ /// [TextAlign.end] are interpreted.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the [text] is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// Defaults to the ambient [Directionality], if any. If there is no ambient
+ /// [Directionality], then this must not be null.
+ final TextDirection textDirection;
+
/// Whether the text should break at soft line breaks.
///
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
@@ -3754,8 +3775,11 @@
@override
RenderParagraph createRenderObject(BuildContext context) {
+ final TextDirection direction = textDirection ?? Directionality.of(context);
+ assert(direction != null, 'A RichText was created with no textDirection and no ambient Directionality widget.');
return new RenderParagraph(text,
textAlign: textAlign,
+ textDirection: direction,
softWrap: softWrap,
overflow: overflow,
textScaleFactor: textScaleFactor,
@@ -3768,6 +3792,7 @@
renderObject
..text = text
..textAlign = textAlign
+ ..textDirection = textDirection ?? Directionality.of(context)
..softWrap = softWrap
..overflow = overflow
..textScaleFactor = textScaleFactor
@@ -4289,6 +4314,7 @@
this.checked,
this.selected,
this.label,
+ this.textDirection,
}) : assert(container != null),
super(key: key, child: child);
@@ -4317,8 +4343,20 @@
final bool selected;
/// Provides a textual description of the widget.
+ ///
+ /// If a label is provided, there must either by an ambient [Directionality]
+ /// or an explicit [textDirection] should be provided.
final String label;
+ /// The reading direction of the [label].
+ ///
+ /// Defaults to the ambient [Directionality].
+ final TextDirection textDirection;
+
+ TextDirection _getTextDirection(BuildContext context) {
+ return textDirection ?? (label != null ? Directionality.of(context) : null);
+ }
+
@override
RenderSemanticsAnnotations createRenderObject(BuildContext context) {
return new RenderSemanticsAnnotations(
@@ -4326,6 +4364,7 @@
checked: checked,
selected: selected,
label: label,
+ textDirection: _getTextDirection(context),
);
}
@@ -4335,7 +4374,8 @@
..container = container
..checked = checked
..selected = selected
- ..label = label;
+ ..label = label
+ ..textDirection = _getTextDirection(context);
}
@override
@@ -4344,7 +4384,8 @@
description.add(new DiagnosticsProperty<bool>('container', container));
description.add(new DiagnosticsProperty<bool>('checked', checked, defaultValue: null));
description.add(new DiagnosticsProperty<bool>('selected', selected, defaultValue: null));
- description.add(new StringProperty('label', label));
+ description.add(new StringProperty('label', label, defaultValue: ''));
+ description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
}
}
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index 6aba833..aba7051 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -144,8 +144,8 @@
/// the number of lines. By default, it is 1, meaning this is a single-line
/// text field. If it is not null, it must be greater than zero.
///
- /// The [controller], [focusNode], [style], and [cursorColor] arguments must
- /// not be null.
+ /// The [controller], [focusNode], [style], [cursorColor], and [textAlign]
+ /// arguments must not be null.
EditableText({
Key key,
@required this.controller,
@@ -154,7 +154,8 @@
this.autocorrect: true,
@required this.style,
@required this.cursorColor,
- this.textAlign,
+ this.textAlign: TextAlign.start,
+ this.textDirection,
this.textScaleFactor,
this.maxLines: 1,
this.autofocus: false,
@@ -171,6 +172,7 @@
assert(autocorrect != null),
assert(style != null),
assert(cursorColor != null),
+ assert(textAlign != null),
assert(maxLines == null || maxLines > 0),
assert(autofocus != null),
inputFormatters = maxLines == 1
@@ -201,8 +203,25 @@
final TextStyle style;
/// How the text should be aligned horizontally.
+ ///
+ /// Defaults to [TextAlign.start].
final TextAlign textAlign;
+ /// The directionality of the text.
+ ///
+ /// This decides how [textAlign] values like [TextAlign.start] and
+ /// [TextAlign.end] are interpreted.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the text is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// Defaults to the ambient [Directionality], if any.
+ final TextDirection textDirection;
+
/// The number of font pixels for each logical pixel.
///
/// For example, if the text scale factor is 1.5, text will be 50% larger than
@@ -266,6 +285,7 @@
description.add(new DiagnosticsProperty<bool>('autocorrect', autocorrect, defaultValue: true));
style?.debugFillProperties(description);
description.add(new EnumProperty<TextAlign>('textAlign', textAlign, defaultValue: null));
+ description.add(new EnumProperty<TextDirection>('textDirection', textDirection, defaultValue: null));
description.add(new DoubleProperty('textScaleFactor', textScaleFactor, defaultValue: null));
description.add(new IntProperty('maxLines', maxLines, defaultValue: 1));
description.add(new DiagnosticsProperty<bool>('autofocus', autofocus, defaultValue: false));
@@ -575,6 +595,12 @@
updateKeepAlive();
}
+ TextDirection get _textDirection {
+ final TextDirection result = widget.textDirection ?? Directionality.of(context);
+ assert(result != null, '$runtimeType created without a textDirection and with no ambient Directionality.');
+ return result;
+ }
+
@override
Widget build(BuildContext context) {
FocusScope.of(context).reparentIfNeeded(widget.focusNode);
@@ -595,6 +621,7 @@
selectionColor: widget.selectionColor,
textScaleFactor: widget.textScaleFactor ?? MediaQuery.of(context, nullOk: true)?.textScaleFactor ?? 1.0,
textAlign: widget.textAlign,
+ textDirection: _textDirection,
obscureText: widget.obscureText,
obscureShowCharacterAtIndex: _obscureShowCharTicksPending > 0 ? _obscureLatestCharIndex : null,
autocorrect: widget.autocorrect,
@@ -619,13 +646,15 @@
this.selectionColor,
this.textScaleFactor,
this.textAlign,
+ @required this.textDirection,
this.obscureText,
this.obscureShowCharacterAtIndex,
this.autocorrect,
this.offset,
this.onSelectionChanged,
this.onCaretChanged,
- }) : super(key: key);
+ }) : assert(textDirection != null),
+ super(key: key);
final TextEditingValue value;
final TextStyle style;
@@ -635,6 +664,7 @@
final Color selectionColor;
final double textScaleFactor;
final TextAlign textAlign;
+ final TextDirection textDirection;
final bool obscureText;
final int obscureShowCharacterAtIndex;
final bool autocorrect;
@@ -652,6 +682,7 @@
selectionColor: selectionColor,
textScaleFactor: textScaleFactor,
textAlign: textAlign,
+ textDirection: textDirection,
selection: value.selection,
offset: offset,
onSelectionChanged: onSelectionChanged,
@@ -669,6 +700,7 @@
..selectionColor = selectionColor
..textScaleFactor = textScaleFactor
..textAlign = textAlign
+ ..textDirection = textDirection
..selection = value.selection
..offset = offset
..onSelectionChanged = onSelectionChanged
diff --git a/packages/flutter/lib/src/widgets/icon.dart b/packages/flutter/lib/src/widgets/icon.dart
index f92a571..d652c9f 100644
--- a/packages/flutter/lib/src/widgets/icon.dart
+++ b/packages/flutter/lib/src/widgets/icon.dart
@@ -17,6 +17,10 @@
/// Icons are not interactive. For an interactive icon, consider material's
/// [IconButton].
///
+/// There must be an ambient [Directionality] widget when using [Icon].
+/// Typically this is introduced automatically by the [WidgetsApp] or
+/// [MaterialApp].
+///
/// See also:
///
/// * [IconButton], for interactive icons.
@@ -80,6 +84,9 @@
@override
Widget build(BuildContext context) {
+ final TextDirection textDirection = Directionality.of(context);
+ assert(textDirection != null, 'Icon widgets required an ambient Directionality.');
+
final IconThemeData iconTheme = IconTheme.of(context);
final double iconSize = size ?? iconTheme.size;
@@ -98,18 +105,19 @@
height: iconSize,
child: new Center(
child: new RichText(
+ textDirection: textDirection, // Since we already fetched it for the assert...
text: new TextSpan(
text: new String.fromCharCode(icon.codePoint),
style: new TextStyle(
inherit: false,
color: iconColor,
fontSize: iconSize,
- fontFamily: icon.fontFamily
- )
- )
- )
- )
- )
+ fontFamily: icon.fontFamily,
+ ),
+ ),
+ ),
+ ),
+ ),
);
}
diff --git a/packages/flutter/lib/src/widgets/semantics_debugger.dart b/packages/flutter/lib/src/widgets/semantics_debugger.dart
index f6e1c2e..779aeb9 100644
--- a/packages/flutter/lib/src/widgets/semantics_debugger.dart
+++ b/packages/flutter/lib/src/widgets/semantics_debugger.dart
@@ -228,15 +228,29 @@
if (isAdjustable)
annotations.add('adjustable');
+ assert(data.label != null);
String message;
- if (annotations.isEmpty) {
- assert(data.label != null);
- message = data.label;
+ if (data.label.isEmpty) {
+ message = annotations.join('; ');
} else {
- if (data.label.isEmpty) {
- message = annotations.join('; ');
+ String label;
+ if (data.textDirection == null) {
+ label = '${Unicode.FSI}${data.label}${Unicode.PDI}';
+ annotations.insert(0, 'MISSING TEXT DIRECTION');
} else {
- message = '${data.label} (${annotations.join('; ')})';
+ switch (data.textDirection) {
+ case TextDirection.rtl:
+ label = '${Unicode.RLI}${data.label}${Unicode.PDF}';
+ break;
+ case TextDirection.ltr:
+ label = data.label;
+ break;
+ }
+ }
+ if (annotations.isEmpty) {
+ message = label;
+ } else {
+ message = '$label (${annotations.join('; ')})';
}
}
@@ -257,7 +271,11 @@
canvas.save();
canvas.clipRect(rect);
final TextPainter textPainter = new TextPainter()
- ..text = new TextSpan(style: _messageStyle, text: message)
+ ..text = new TextSpan(
+ style: _messageStyle,
+ text: message,
+ )
+ ..textDirection = TextDirection.ltr // _getMessage always returns LTR text, even if node.label is RTL
..textAlign = TextAlign.center
..layout(maxWidth: rect.width);
diff --git a/packages/flutter/lib/src/widgets/text.dart b/packages/flutter/lib/src/widgets/text.dart
index ca2599f..916f148 100644
--- a/packages/flutter/lib/src/widgets/text.dart
+++ b/packages/flutter/lib/src/widgets/text.dart
@@ -200,6 +200,7 @@
Key key,
this.style,
this.textAlign,
+ this.textDirection,
this.softWrap,
this.overflow,
this.textScaleFactor,
@@ -220,6 +221,21 @@
/// How the text should be aligned horizontally.
final TextAlign textAlign;
+ /// The directionality of the text.
+ ///
+ /// This decides how [textAlign] values like [TextAlign.start] and
+ /// [TextAlign.end] are interpreted.
+ ///
+ /// This is also used to disambiguate how to render bidirectional text. For
+ /// example, if the [data] is an English phrase followed by a Hebrew phrase,
+ /// in a [TextDirection.ltr] context the English phrase will be on the left
+ /// and the Hebrew phrase to its right, while in a [TextDirection.rtl]
+ /// context, the English phrase will be on the right and the Hebrow phrase on
+ /// its left.
+ ///
+ /// Defaults to the ambient [Directionality], if any.
+ final TextDirection textDirection;
+
/// Whether the text should break at soft line breaks.
///
/// If false, the glyphs in the text will be positioned as if there was unlimited horizontal space.
@@ -257,7 +273,8 @@
if (style == null || style.inherit)
effectiveTextStyle = defaultTextStyle.style.merge(style);
return new RichText(
- textAlign: textAlign ?? defaultTextStyle.textAlign,
+ textAlign: textAlign ?? defaultTextStyle.textAlign ?? TextAlign.start,
+ textDirection: textDirection, // RichText uses Directionality.of to obtain a default if this is null.
softWrap: softWrap ?? defaultTextStyle.softWrap,
overflow: overflow ?? defaultTextStyle.overflow,
textScaleFactor: textScaleFactor ?? MediaQuery.of(context, nullOk: true)?.textScaleFactor ?? 1.0,
diff --git a/packages/flutter/lib/src/widgets/widget_inspector.dart b/packages/flutter/lib/src/widgets/widget_inspector.dart
index 26a6314..e9bd1f2 100644
--- a/packages/flutter/lib/src/widgets/widget_inspector.dart
+++ b/packages/flutter/lib/src/widgets/widget_inspector.dart
@@ -361,12 +361,14 @@
@required this.selected,
@required this.candidates,
@required this.tooltip,
+ @required this.textDirection,
});
final Rect overlayRect;
final _TransformedRect selected;
final List<_TransformedRect> candidates;
final String tooltip;
+ final TextDirection textDirection;
@override
bool operator ==(dynamic other) {
@@ -447,6 +449,7 @@
overlayRect: overlayRect,
selected: new _TransformedRect(selected),
tooltip: selected.toString(),
+ textDirection: TextDirection.ltr,
candidates: candidates,
);
@@ -497,15 +500,22 @@
final double offsetFromWidget = 9.0;
final double verticalOffset = (targetRect.height) / 2 + offsetFromWidget;
- _paintDescription(canvas, state.tooltip, target, verticalOffset, size, targetRect);
+ _paintDescription(canvas, state.tooltip, state.textDirection, target, verticalOffset, size, targetRect);
// TODO(jacobr): provide an option to perform a debug paint of just the
// selected widget.
return recorder.endRecording();
}
- void _paintDescription(Canvas canvas, String message, Offset target,
- double verticalOffset, Size size, Rect targetRect) {
+ void _paintDescription(
+ Canvas canvas,
+ String message,
+ TextDirection textDirection,
+ Offset target,
+ double verticalOffset,
+ Size size,
+ Rect targetRect,
+ ) {
canvas.save();
final double maxWidth = size.width - 2 * (_kScreenEdgeMargin + _kTooltipPadding);
if (_textPainter == null || _textPainter.text.text != message || _textPainterMaxWidth != maxWidth) {
@@ -514,6 +524,7 @@
..maxLines = _kMaxTooltipLines
..ellipsis = '...'
..text = new TextSpan(style: _messageStyle, text: message)
+ ..textDirection = textDirection
..layout(maxWidth: maxWidth);
}
diff --git a/packages/flutter/test/cupertino/button_test.dart b/packages/flutter/test/cupertino/button_test.dart
index 75f1259..086a248 100644
--- a/packages/flutter/test/cupertino/button_test.dart
+++ b/packages/flutter/test/cupertino/button_test.dart
@@ -14,7 +14,7 @@
void main() {
testWidgets('Default layout minimum size', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(child: const CupertinoButton(
+ boilerplate(child: const CupertinoButton(
child: const Text('X', style: testStyle),
onPressed: null,
))
@@ -30,7 +30,7 @@
testWidgets('Minimum size parameter', (WidgetTester tester) async {
final double minSize = 60.0;
await tester.pumpWidget(
- new Center(child: new CupertinoButton(
+ boilerplate(child: new CupertinoButton(
child: const Text('X', style: testStyle),
onPressed: null,
minSize: minSize,
@@ -46,7 +46,7 @@
testWidgets('Size grows with text', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(child: const CupertinoButton(
+ boilerplate(child: const CupertinoButton(
child: const Text('XXXX', style: testStyle),
onPressed: null,
))
@@ -60,7 +60,7 @@
});
testWidgets('Button with background is wider', (WidgetTester tester) async {
- await tester.pumpWidget(const Center(child: const CupertinoButton(
+ await tester.pumpWidget(boilerplate(child: const CupertinoButton(
child: const Text('X', style: testStyle),
onPressed: null,
color: const Color(0xFFFFFFFF),
@@ -74,7 +74,7 @@
});
testWidgets('Custom padding', (WidgetTester tester) async {
- await tester.pumpWidget(const Center(child: const CupertinoButton(
+ await tester.pumpWidget(boilerplate(child: const CupertinoButton(
child: const Text(' ', style: testStyle),
onPressed: null,
padding: const EdgeInsets.all(100.0),
@@ -91,7 +91,7 @@
await tester.pumpWidget(
new StatefulBuilder(
builder: (BuildContext context, StateSetter setState) {
- return new Center(
+ return boilerplate(
child: new CupertinoButton(
child: const Text('Tap me'),
onPressed: () {
@@ -115,7 +115,7 @@
});
testWidgets('Disabled button doesn\'t animate', (WidgetTester tester) async {
- await tester.pumpWidget(const Center(child: const CupertinoButton(
+ await tester.pumpWidget(boilerplate(child: const CupertinoButton(
child: const Text('Tap me'),
onPressed: null,
)));
@@ -126,7 +126,7 @@
});
testWidgets('pressedOpacity defaults to 0.1', (WidgetTester tester) async {
- await tester.pumpWidget(new Center(child: new CupertinoButton(
+ await tester.pumpWidget(boilerplate(child: new CupertinoButton(
child: const Text('Tap me'),
onPressed: () { },
)));
@@ -146,7 +146,7 @@
testWidgets('pressedOpacity parameter', (WidgetTester tester) async {
final double pressedOpacity = 0.5;
- await tester.pumpWidget(new Center(child: new CupertinoButton(
+ await tester.pumpWidget(boilerplate(child: new CupertinoButton(
pressedOpacity: pressedOpacity,
child: const Text('Tap me'),
onPressed: () { },
@@ -165,3 +165,10 @@
expect(opacity.opacity, pressedOpacity);
});
}
+
+Widget boilerplate({ Widget child }) {
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(child: child),
+ );
+}
\ No newline at end of file
diff --git a/packages/flutter/test/cupertino/dialog_test.dart b/packages/flutter/test/cupertino/dialog_test.dart
index 4cfa288..f7ef03a 100644
--- a/packages/flutter/test/cupertino/dialog_test.dart
+++ b/packages/flutter/test/cupertino/dialog_test.dart
@@ -64,10 +64,10 @@
});
testWidgets('Dialog destructive action styles', (WidgetTester tester) async {
- await tester.pumpWidget(const CupertinoDialogAction(
+ await tester.pumpWidget(boilerplate(const CupertinoDialogAction(
isDestructiveAction: true,
child: const Text('Ok'),
- ));
+ )));
final DefaultTextStyle widget = tester.widget(find.byType(DefaultTextStyle));
@@ -76,10 +76,10 @@
});
testWidgets('Dialog default action styles', (WidgetTester tester) async {
- await tester.pumpWidget(const CupertinoDialogAction(
+ await tester.pumpWidget(boilerplate(const CupertinoDialogAction(
isDefaultAction: true,
child: const Text('Ok'),
- ));
+ )));
final DefaultTextStyle widget = tester.widget(find.byType(DefaultTextStyle));
@@ -87,11 +87,11 @@
});
testWidgets('Default and destructive style', (WidgetTester tester) async {
- await tester.pumpWidget(const CupertinoDialogAction(
+ await tester.pumpWidget(boilerplate(const CupertinoDialogAction(
isDefaultAction: true,
isDestructiveAction: true,
child: const Text('Ok'),
- ));
+ )));
final DefaultTextStyle widget = tester.widget(find.byType(DefaultTextStyle));
@@ -99,3 +99,10 @@
expect(widget.style.color.red, greaterThan(widget.style.color.blue));
});
}
+
+Widget boilerplate(Widget child) {
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: child,
+ );
+}
diff --git a/packages/flutter/test/material/buttons_test.dart b/packages/flutter/test/material/buttons_test.dart
index 180116a..213ad33 100644
--- a/packages/flutter/test/material/buttons_test.dart
+++ b/packages/flutter/test/material/buttons_test.dart
@@ -14,14 +14,17 @@
testWidgets('Does FlatButton contribute semantics', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
- new Material(
- child: new Center(
- child: new FlatButton(
- onPressed: () { },
- child: const Text('ABC')
- )
- )
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Material(
+ child: new Center(
+ child: new FlatButton(
+ onPressed: () { },
+ child: const Text('ABC')
+ ),
+ ),
+ ),
+ ),
);
expect(semantics, hasSemantics(
@@ -58,9 +61,12 @@
);
await tester.pumpWidget(
- new Theme(
- data: new ThemeData(),
- child: buttonWidget,
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Theme(
+ data: new ThemeData(),
+ child: buttonWidget,
+ ),
),
);
@@ -88,12 +94,15 @@
);
await tester.pumpWidget(
- new Theme(
- data: new ThemeData(
- highlightColor: themeHighlightColor1,
- splashColor: themeSplashColor1,
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Theme(
+ data: new ThemeData(
+ highlightColor: themeHighlightColor1,
+ splashColor: themeSplashColor1,
+ ),
+ child: buttonWidget,
),
- child: buttonWidget,
),
);
@@ -108,12 +117,15 @@
final Color themeHighlightColor2 = const Color(0xFF002200);
await tester.pumpWidget(
- new Theme(
- data: new ThemeData(
- highlightColor: themeHighlightColor2,
- splashColor: themeSplashColor2,
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Theme(
+ data: new ThemeData(
+ highlightColor: themeHighlightColor2,
+ splashColor: themeSplashColor2,
+ ),
+ child: buttonWidget, // same widget, so does not get updated because of us
),
- child: buttonWidget, // same widget, so does not get updated because of us
),
);
diff --git a/packages/flutter/test/material/circle_avatar_test.dart b/packages/flutter/test/material/circle_avatar_test.dart
index 1d5466e..05a32f9 100644
--- a/packages/flutter/test/material/circle_avatar_test.dart
+++ b/packages/flutter/test/material/circle_avatar_test.dart
@@ -10,7 +10,7 @@
testWidgets('CircleAvatar with background color', (WidgetTester tester) async {
final Color backgroundColor = Colors.blue.shade400;
await tester.pumpWidget(
- new Center(
+ wrap(
child: new CircleAvatar(
backgroundColor: backgroundColor,
radius: 50.0,
@@ -33,7 +33,7 @@
testWidgets('CircleAvatar with foreground color', (WidgetTester tester) async {
final Color foregroundColor = Colors.red.shade100;
await tester.pumpWidget(
- new Center(
+ wrap(
child: new CircleAvatar(
foregroundColor: foregroundColor,
child: const Text('Z'),
@@ -60,9 +60,9 @@
primaryColorBrightness: Brightness.light,
);
await tester.pumpWidget(
- new Theme(
- data: theme,
- child: const Center(
+ wrap(
+ child: new Theme(
+ data: theme,
child: const CircleAvatar(
child: const Text('Z'),
),
@@ -79,3 +79,10 @@
expect(paragraph.text.style.color, equals(theme.primaryTextTheme.title.color));
});
}
+
+Widget wrap({ Widget child }) {
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(child: child),
+ );
+}
diff --git a/packages/flutter/test/material/expand_icon_test.dart b/packages/flutter/test/material/expand_icon_test.dart
index e4a02b7..94fd279 100644
--- a/packages/flutter/test/material/expand_icon_test.dart
+++ b/packages/flutter/test/material/expand_icon_test.dart
@@ -10,14 +10,12 @@
bool expanded = false;
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new ExpandIcon(
onPressed: (bool isExpanded) {
expanded = !expanded;
}
)
- )
)
);
@@ -31,12 +29,10 @@
testWidgets('ExpandIcon disabled', (WidgetTester tester) async {
await tester.pumpWidget(
- const Material(
- child: const Center(
+ wrap(
child: const ExpandIcon(
onPressed: null
)
- )
)
);
@@ -48,27 +44,23 @@
bool expanded = false;
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new ExpandIcon(
isExpanded: false,
onPressed: (bool isExpanded) {
expanded = !expanded;
}
)
- )
)
);
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new ExpandIcon(
isExpanded: true,
onPressed: (bool isExpanded) {
expanded = !expanded;
}
- )
)
)
);
@@ -76,3 +68,12 @@
expect(expanded, isFalse);
});
}
+
+Widget wrap({ Widget child }) {
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(child: child),
+ ),
+ );
+}
diff --git a/packages/flutter/test/material/feedback_test.dart b/packages/flutter/test/material/feedback_test.dart
index b8676d5..9977316 100644
--- a/packages/flutter/test/material/feedback_test.dart
+++ b/packages/flutter/test/material/feedback_test.dart
@@ -154,7 +154,7 @@
return new GestureDetector(
onTap: tapHandler(context),
onLongPress: longPressHandler(context),
- child: const Text('X'),
+ child: const Text('X', textDirection: TextDirection.ltr),
);
}
}
diff --git a/packages/flutter/test/material/floating_action_button_test.dart b/packages/flutter/test/material/floating_action_button_test.dart
index e4b2b46..c14eac3 100644
--- a/packages/flutter/test/material/floating_action_button_test.dart
+++ b/packages/flutter/test/material/floating_action_button_test.dart
@@ -6,16 +6,18 @@
import 'package:flutter_test/flutter_test.dart';
void main() {
- testWidgets('Floating Action Button control test',
- (WidgetTester tester) async {
+ testWidgets('Floating Action Button control test', (WidgetTester tester) async {
bool didPressButton = false;
await tester.pumpWidget(
- new Center(
- child: new FloatingActionButton(
- onPressed: () {
- didPressButton = true;
- },
- child: const Icon(Icons.add),
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new FloatingActionButton(
+ onPressed: () {
+ didPressButton = true;
+ },
+ child: const Icon(Icons.add),
+ ),
),
),
);
diff --git a/packages/flutter/test/material/grid_title_test.dart b/packages/flutter/test/material/grid_title_test.dart
index 5cf53a6..2bce526 100644
--- a/packages/flutter/test/material/grid_title_test.dart
+++ b/packages/flutter/test/material/grid_title_test.dart
@@ -38,7 +38,12 @@
expect(tester.getBottomLeft(find.byKey(headerKey)).dy,
lessThan(tester.getTopLeft(find.byKey(footerKey)).dy));
- await tester.pumpWidget(const GridTile(child: const Text('Simple')));
+ await tester.pumpWidget(
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const GridTile(child: const Text('Simple')),
+ ),
+ );
expect(find.text('Simple'), findsOneWidget);
});
diff --git a/packages/flutter/test/material/icon_button_test.dart b/packages/flutter/test/material/icon_button_test.dart
index 6d7a2f5..7813094 100644
--- a/packages/flutter/test/material/icon_button_test.dart
+++ b/packages/flutter/test/material/icon_button_test.dart
@@ -24,13 +24,11 @@
testWidgets('test default icon buttons are sized up to 48', (WidgetTester tester) async {
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new IconButton(
onPressed: mockOnPressedFunction,
icon: const Icon(Icons.link),
),
- ),
),
);
@@ -43,14 +41,12 @@
testWidgets('test small icons are sized up to 48dp', (WidgetTester tester) async {
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new IconButton(
iconSize: 10.0,
onPressed: mockOnPressedFunction,
icon: const Icon(Icons.link),
),
- ),
),
);
@@ -60,15 +56,13 @@
testWidgets('test icons can be small when total size is >48dp', (WidgetTester tester) async {
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new IconButton(
iconSize: 10.0,
padding: const EdgeInsets.all(30.0),
onPressed: mockOnPressedFunction,
icon: const Icon(Icons.link),
),
- ),
),
);
@@ -78,15 +72,13 @@
testWidgets('test default icon buttons are constrained', (WidgetTester tester) async {
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new IconButton(
padding: EdgeInsets.zero,
onPressed: mockOnPressedFunction,
icon: const Icon(Icons.ac_unit),
iconSize: 80.0,
),
- ),
),
);
@@ -120,14 +112,12 @@
testWidgets('test default padding', (WidgetTester tester) async {
await tester.pumpWidget(
- new Material(
- child: new Center(
+ wrap(
child: new IconButton(
onPressed: mockOnPressedFunction,
icon: const Icon(Icons.ac_unit),
iconSize: 80.0,
),
- ),
),
);
@@ -203,15 +193,13 @@
final Color directSplashColor = const Color(0xFF00000F);
final Color directHighlightColor = const Color(0xFF0000F0);
- Widget buttonWidget = new Material(
- child: new Center(
+ Widget buttonWidget = wrap(
child: new IconButton(
icon: const Icon(Icons.android),
splashColor: directSplashColor,
highlightColor: directHighlightColor,
onPressed: () { /* enable the button */ },
),
- ),
);
await tester.pumpWidget(
@@ -236,13 +224,11 @@
final Color themeSplashColor1 = const Color(0xFF000F00);
final Color themeHighlightColor1 = const Color(0xFF00FF00);
- buttonWidget = new Material(
- child: new Center(
+ buttonWidget = wrap(
child: new IconButton(
icon: const Icon(Icons.android),
onPressed: () { /* enable the button */ },
),
- ),
);
await tester.pumpWidget(
@@ -285,3 +271,12 @@
await gesture.up();
});
}
+
+Widget wrap({ Widget child }) {
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Material(
+ child: new Center(child: child),
+ ),
+ );
+}
diff --git a/packages/flutter/test/material/refresh_indicator_test.dart b/packages/flutter/test/material/refresh_indicator_test.dart
index b60a67f..e5b784f 100644
--- a/packages/flutter/test/material/refresh_indicator_test.dart
+++ b/packages/flutter/test/material/refresh_indicator_test.dart
@@ -23,9 +23,8 @@
testWidgets('RefreshIndicator', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -51,9 +50,8 @@
testWidgets('RefreshIndicator - bottom', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
reverse: true,
@@ -80,9 +78,8 @@
testWidgets('RefreshIndicator - top - position', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: holdRefresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -107,9 +104,8 @@
testWidgets('RefreshIndicator - bottom - position', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: holdRefresh,
child: new ListView(
reverse: true,
@@ -135,9 +131,8 @@
testWidgets('RefreshIndicator - no movement', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -164,9 +159,8 @@
testWidgets('RefreshIndicator - not enough', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -192,9 +186,8 @@
testWidgets('RefreshIndicator - show - slow', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: holdRefresh, // this one never returns
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -236,9 +229,8 @@
testWidgets('RefreshIndicator - show - fast', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
@@ -281,9 +273,8 @@
testWidgets('RefreshIndicator - show - fast - twice', (WidgetTester tester) async {
refreshCalled = false;
await tester.pumpWidget(
- new Directionality(
- textDirection: TextDirection.ltr,
- child: new RefreshIndicator(
+ new MaterialApp(
+ home: new RefreshIndicator(
onRefresh: refresh,
child: new ListView(
physics: const AlwaysScrollableScrollPhysics(),
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index 2cfa2d0..f2ea7f9 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -1260,7 +1260,7 @@
testWidgets('Cannot enter new lines onto single line TextField', (WidgetTester tester) async {
final TextEditingController textController = new TextEditingController();
- await tester.pumpWidget(new Material(
+ await tester.pumpWidget(boilerplate(
child: new TextField(controller: textController, decoration: null),
));
@@ -1272,7 +1272,7 @@
testWidgets('Injected formatters are chained', (WidgetTester tester) async {
final TextEditingController textController = new TextEditingController();
- await tester.pumpWidget(new Material(
+ await tester.pumpWidget(boilerplate(
child: new TextField(
controller: textController,
decoration: null,
@@ -1293,7 +1293,7 @@
testWidgets('Chained formatters are in sequence', (WidgetTester tester) async {
final TextEditingController textController = new TextEditingController();
- await tester.pumpWidget(new Material(
+ await tester.pumpWidget(boilerplate(
child: new TextField(
controller: textController,
decoration: null,
diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart
index f592e81..0ae17a6 100644
--- a/packages/flutter/test/material/tooltip_test.dart
+++ b/packages/flutter/test/material/tooltip_test.dart
@@ -32,34 +32,37 @@
testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 300.0,
- top: 0.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 20.0,
- padding: const EdgeInsets.all(5.0),
- verticalOffset: 20.0,
- preferBelow: false,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 300.0,
+ top: 0.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 20.0,
+ padding: const EdgeInsets.all(5.0),
+ verticalOffset: 20.0,
+ preferBelow: false,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -85,34 +88,37 @@
testWidgets('Does tooltip end up in the right place - top left', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 0.0,
- top: 0.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 20.0,
- padding: const EdgeInsets.all(5.0),
- verticalOffset: 20.0,
- preferBelow: false,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 0.0,
+ top: 0.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 20.0,
+ padding: const EdgeInsets.all(5.0),
+ verticalOffset: 20.0,
+ preferBelow: false,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -134,34 +140,37 @@
testWidgets('Does tooltip end up in the right place - center prefer above fits', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 400.0,
- top: 300.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 100.0,
- padding: const EdgeInsets.all(0.0),
- verticalOffset: 100.0,
- preferBelow: false,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 400.0,
+ top: 300.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 100.0,
+ padding: const EdgeInsets.all(0.0),
+ verticalOffset: 100.0,
+ preferBelow: false,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -185,34 +194,37 @@
testWidgets('Does tooltip end up in the right place - center prefer above does not fit', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 400.0,
- top: 299.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 190.0,
- padding: const EdgeInsets.all(0.0),
- verticalOffset: 100.0,
- preferBelow: false,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 400.0,
+ top: 299.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 190.0,
+ padding: const EdgeInsets.all(0.0),
+ verticalOffset: 100.0,
+ preferBelow: false,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -247,34 +259,37 @@
testWidgets('Does tooltip end up in the right place - center prefer below fits', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 400.0,
- top: 300.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 190.0,
- padding: const EdgeInsets.all(0.0),
- verticalOffset: 100.0,
- preferBelow: true,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 400.0,
+ top: 300.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 190.0,
+ padding: const EdgeInsets.all(0.0),
+ verticalOffset: 100.0,
+ preferBelow: true,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -297,34 +312,37 @@
testWidgets('Does tooltip end up in the right place - way off to the right', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 1600.0,
- top: 300.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 10.0,
- padding: const EdgeInsets.all(0.0),
- verticalOffset: 10.0,
- preferBelow: true,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 1600.0,
+ top: 300.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 10.0,
+ padding: const EdgeInsets.all(0.0),
+ verticalOffset: 10.0,
+ preferBelow: true,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -349,34 +367,37 @@
testWidgets('Does tooltip end up in the right place - near the edge', (WidgetTester tester) async {
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 780.0,
- top: 300.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- height: 10.0,
- padding: const EdgeInsets.all(0.0),
- verticalOffset: 10.0,
- preferBelow: true,
- child: new Container(
- width: 0.0,
- height: 0.0
- )
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 780.0,
+ top: 300.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ height: 10.0,
+ padding: const EdgeInsets.all(0.0),
+ verticalOffset: 10.0,
+ preferBelow: true,
+ child: new Container(
+ width: 0.0,
+ height: 0.0,
+ ),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
(key.currentState as dynamic).ensureTooltipVisible(); // before using "as dynamic" in your code, see note top of file
await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
@@ -438,27 +459,30 @@
final GlobalKey key = new GlobalKey();
await tester.pumpWidget(
- new Overlay(
- initialEntries: <OverlayEntry>[
- new OverlayEntry(
- builder: (BuildContext context) {
- return new Stack(
- children: <Widget>[
- new Positioned(
- left: 780.0,
- top: 300.0,
- child: new Tooltip(
- key: key,
- message: tooltipText,
- child: new Container(width: 0.0, height: 0.0)
- )
- ),
- ]
- );
- }
- ),
- ]
- )
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Overlay(
+ initialEntries: <OverlayEntry>[
+ new OverlayEntry(
+ builder: (BuildContext context) {
+ return new Stack(
+ children: <Widget>[
+ new Positioned(
+ left: 780.0,
+ top: 300.0,
+ child: new Tooltip(
+ key: key,
+ message: tooltipText,
+ child: new Container(width: 0.0, height: 0.0),
+ ),
+ ),
+ ],
+ );
+ },
+ ),
+ ],
+ ),
+ ),
);
expect(semantics, hasSemantics(new TestSemantics.root(label: tooltipText)));
@@ -504,18 +528,19 @@
testWidgets('Haptic feedback', (WidgetTester tester) async {
final FeedbackTester feedback = new FeedbackTester();
- await tester.pumpWidget(new MaterialApp(
+ await tester.pumpWidget(
+ new MaterialApp(
home: new Center(
- child: new Tooltip(
- message: 'Foo',
- child: new Container(
- width: 100.0,
- height: 100.0,
- color: Colors.green[500],
- )
- )
- )
- )
+ child: new Tooltip(
+ message: 'Foo',
+ child: new Container(
+ width: 100.0,
+ height: 100.0,
+ color: Colors.green[500],
+ ),
+ ),
+ ),
+ ),
);
await tester.longPress(find.byType(Tooltip));
diff --git a/packages/flutter/test/painting/text_painter_test.dart b/packages/flutter/test/painting/text_painter_test.dart
index 3db5ea4..7a86425 100644
--- a/packages/flutter/test/painting/text_painter_test.dart
+++ b/packages/flutter/test/painting/text_painter_test.dart
@@ -2,7 +2,6 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'dart:io' as io;
import 'dart:ui' as ui;
import 'package:flutter/painting.dart';
@@ -10,7 +9,8 @@
void main() {
test('TextPainter caret test', () {
- final TextPainter painter = new TextPainter();
+ final TextPainter painter = new TextPainter()
+ ..textDirection = TextDirection.ltr;
String text = 'A';
painter.text = new TextSpan(text: text);
@@ -27,13 +27,20 @@
painter.layout();
caretOffset = painter.getOffsetForCaret(new ui.TextPosition(offset: text.length), ui.Rect.zero);
expect(caretOffset.dx, painter.width);
- }, skip: io.Platform.isMacOS); // TODO(goderbauer): Disabled because of https://github.com/flutter/flutter/issues/4273
+ });
test('TextPainter error test', () {
- final TextPainter painter = new TextPainter();
+ final TextPainter painter = new TextPainter(textDirection: TextDirection.ltr);
expect(() { painter.paint(null, Offset.zero); }, throwsFlutterError);
});
+ test('TextPainter requires textDirection', () {
+ final TextPainter painter1 = new TextPainter(text: const TextSpan(text: ''));
+ expect(() { painter1.layout(); }, throwsAssertionError);
+ final TextPainter painter2 = new TextPainter(text: const TextSpan(text: ''), textDirection: TextDirection.rtl);
+ expect(() { painter2.layout(); }, isNot(throwsException));
+ });
+
test('TextPainter size test', () {
final TextPainter painter = new TextPainter(
text: const TextSpan(
@@ -44,20 +51,27 @@
fontSize: 123.0,
),
),
+ textDirection: TextDirection.ltr,
);
painter.layout();
expect(painter.size, const Size(123.0, 123.0));
});
test('TextPainter default text height is 14 pixels', () {
- final TextPainter painter = new TextPainter(text: const TextSpan(text: 'x'));
+ final TextPainter painter = new TextPainter(
+ text: const TextSpan(text: 'x'),
+ textDirection: TextDirection.ltr,
+ );
painter.layout();
expect(painter.preferredLineHeight, 14.0);
expect(painter.size, const Size(14.0, 14.0));
});
test('TextPainter sets paragraph size from root', () {
- final TextPainter painter = new TextPainter(text: const TextSpan(text: 'x', style: const TextStyle(fontSize: 100.0)));
+ final TextPainter painter = new TextPainter(
+ text: const TextSpan(text: 'x', style: const TextStyle(fontSize: 100.0)),
+ textDirection: TextDirection.ltr,
+ );
painter.layout();
expect(painter.preferredLineHeight, 100.0);
expect(painter.size, const Size(100.0, 100.0));
diff --git a/packages/flutter/test/painting/text_style_test.dart b/packages/flutter/test/painting/text_style_test.dart
index 29d5a65..438c4f3 100644
--- a/packages/flutter/test/painting/text_style_test.dart
+++ b/packages/flutter/test/painting/text_style_test.dart
@@ -8,7 +8,7 @@
import 'package:test/test.dart';
void main() {
- test("TextStyle control test", () {
+ test('TextStyle control test', () {
expect(
const TextStyle(inherit: false).toString(),
equals('TextStyle(inherit: false, <no style specified>)'),
@@ -117,9 +117,17 @@
final ui.ParagraphStyle ps2 = s2.getParagraphStyle(textAlign: TextAlign.center);
expect(ps2, equals(new ui.ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontSize: 10.0, lineHeight: 100.0)));
- expect(ps2.toString(), 'ParagraphStyle(textAlign: TextAlign.center, fontWeight: FontWeight.w800, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: 10.0, lineHeight: 100.0x, ellipsis: unspecified)');
+ expect(ps2.toString(), 'ParagraphStyle(textAlign: TextAlign.center, textDirection: unspecified, fontWeight: FontWeight.w800, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: 10.0, lineHeight: 100.0x, ellipsis: unspecified)');
final ui.ParagraphStyle ps5 = s5.getParagraphStyle();
expect(ps5, equals(new ui.ParagraphStyle(fontWeight: FontWeight.w700, fontSize: 12.0, lineHeight: 123.0)));
- expect(ps5.toString(), 'ParagraphStyle(textAlign: unspecified, fontWeight: FontWeight.w700, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: 12.0, lineHeight: 123.0x, ellipsis: unspecified)');
+ expect(ps5.toString(), 'ParagraphStyle(textAlign: unspecified, textDirection: unspecified, fontWeight: FontWeight.w700, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: 12.0, lineHeight: 123.0x, ellipsis: unspecified)');
+
+ final ui.ParagraphStyle ps6 = const TextStyle().getParagraphStyle(textDirection: TextDirection.ltr);
+ expect(ps6, equals(new ui.ParagraphStyle(textDirection: TextDirection.ltr)));
+ expect(ps6.toString(), 'ParagraphStyle(textAlign: unspecified, textDirection: TextDirection.ltr, fontWeight: unspecified, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: unspecified, lineHeight: unspecified, ellipsis: unspecified)');
+
+ final ui.ParagraphStyle ps7 = const TextStyle().getParagraphStyle(textDirection: TextDirection.rtl);
+ expect(ps7, equals(new ui.ParagraphStyle(textDirection: TextDirection.rtl)));
+ expect(ps7.toString(), 'ParagraphStyle(textAlign: unspecified, textDirection: TextDirection.rtl, fontWeight: unspecified, fontStyle: unspecified, maxLines: unspecified, fontFamily: unspecified, fontSize: unspecified, lineHeight: unspecified, ellipsis: unspecified)');
});
}
diff --git a/packages/flutter/test/rendering/box_test.dart b/packages/flutter/test/rendering/box_test.dart
index 8b2d556..d6b81c0 100644
--- a/packages/flutter/test/rendering/box_test.dart
+++ b/packages/flutter/test/rendering/box_test.dart
@@ -73,8 +73,8 @@
expect(coloredBox, hasAGoodToStringDeep);
expect(coloredBox.toStringDeep(), equalsIgnoringHashCodes(
'RenderDecoratedBox#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' parentData: null\n'
- ' constraints: null\n'
+ ' parentData: MISSING\n'
+ ' constraints: MISSING\n'
' size: MISSING\n'
' decoration: BoxDecoration:\n'
' <no decorations specified>\n'
diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart
index 9dd3c57..2fd8849 100644
--- a/packages/flutter/test/rendering/editable_test.dart
+++ b/packages/flutter/test/rendering/editable_test.dart
@@ -12,6 +12,8 @@
style: const TextStyle(height: 1.0, fontSize: 10.0, fontFamily: 'Ahem'),
text: '12345',
),
+ textAlign: TextAlign.start,
+ textDirection: TextDirection.ltr,
offset: new ViewportOffset.zero(),
);
expect(editable.getMinIntrinsicWidth(double.INFINITY), 50.0);
@@ -23,8 +25,8 @@
editable.toStringDeep(),
equalsIgnoringHashCodes(
'RenderEditable#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' │ parentData: null\n'
- ' │ constraints: null\n'
+ ' │ parentData: MISSING\n'
+ ' │ constraints: MISSING\n'
' │ size: MISSING\n'
' │ cursorColor: null\n'
' │ showCursor: ValueNotifier<bool>#00000(false)\n'
diff --git a/packages/flutter/test/rendering/flex_test.dart b/packages/flutter/test/rendering/flex_test.dart
index c4423234..89fe515 100644
--- a/packages/flutter/test/rendering/flex_test.dart
+++ b/packages/flutter/test/rendering/flex_test.dart
@@ -91,8 +91,8 @@
flex.toStringDeep(),
equalsIgnoringHashCodes(
'RenderFlex#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' parentData: null\n'
- ' constraints: null\n'
+ ' parentData: MISSING\n'
+ ' constraints: MISSING\n'
' size: MISSING\n'
' direction: horizontal\n'
' mainAxisAlignment: start\n'
diff --git a/packages/flutter/test/rendering/overflow_test.dart b/packages/flutter/test/rendering/overflow_test.dart
index 63e03f0..cd0e947 100644
--- a/packages/flutter/test/rendering/overflow_test.dart
+++ b/packages/flutter/test/rendering/overflow_test.dart
@@ -9,13 +9,16 @@
import 'rendering_tester.dart';
void main() {
- test("overflow should not affect baseline", () {
+ test('overflow should not affect baseline', () {
RenderBox root, child, text;
double baseline1, baseline2, height1, height2;
root = new RenderPositionedBox(
child: new RenderCustomPaint(
- child: child = text = new RenderParagraph(const TextSpan(text: 'Hello World')),
+ child: child = text = new RenderParagraph(
+ const TextSpan(text: 'Hello World'),
+ textDirection: TextDirection.ltr,
+ ),
painter: new TestCallbackPainter(
onPaint: () {
baseline1 = child.getDistanceToBaseline(TextBaseline.alphabetic);
@@ -29,7 +32,10 @@
root = new RenderPositionedBox(
child: new RenderCustomPaint(
child: child = new RenderConstrainedOverflowBox(
- child: text = new RenderParagraph(const TextSpan(text: 'Hello World')),
+ child: text = new RenderParagraph(
+ const TextSpan(text: 'Hello World'),
+ textDirection: TextDirection.ltr,
+ ),
maxHeight: height1 / 2.0,
alignment: const FractionalOffset(0.0, 0.0)
),
diff --git a/packages/flutter/test/rendering/paragraph_intrinsics_test.dart b/packages/flutter/test/rendering/paragraph_intrinsics_test.dart
index cd9c6bb..644d709 100644
--- a/packages/flutter/test/rendering/paragraph_intrinsics_test.dart
+++ b/packages/flutter/test/rendering/paragraph_intrinsics_test.dart
@@ -10,8 +10,9 @@
final RenderParagraph paragraph = new RenderParagraph(
const TextSpan(
style: const TextStyle(height: 1.0),
- text: 'Hello World'
- )
+ text: 'Hello World',
+ ),
+ textDirection: TextDirection.ltr,
);
final RenderListBody testBlock = new RenderListBody(
children: <RenderBox>[
diff --git a/packages/flutter/test/rendering/paragraph_test.dart b/packages/flutter/test/rendering/paragraph_test.dart
index 1b67e88..380fb25 100644
--- a/packages/flutter/test/rendering/paragraph_test.dart
+++ b/packages/flutter/test/rendering/paragraph_test.dart
@@ -14,7 +14,10 @@
void main() {
test('getOffsetForCaret control test', () {
- final RenderParagraph paragraph = new RenderParagraph(const TextSpan(text: _kText));
+ final RenderParagraph paragraph = new RenderParagraph(
+ const TextSpan(text: _kText),
+ textDirection: TextDirection.ltr,
+ );
layout(paragraph);
final Rect caret = new Rect.fromLTWH(0.0, 0.0, 2.0, 20.0);
@@ -30,7 +33,10 @@
});
test('getPositionForOffset control test', () {
- final RenderParagraph paragraph = new RenderParagraph(const TextSpan(text: _kText));
+ final RenderParagraph paragraph = new RenderParagraph(
+ const TextSpan(text: _kText),
+ textDirection: TextDirection.ltr,
+ );
layout(paragraph);
final TextPosition position20 = paragraph.getPositionForOffset(const Offset(20.0, 5.0));
@@ -44,7 +50,10 @@
});
test('getBoxesForSelection control test', () {
- final RenderParagraph paragraph = new RenderParagraph(const TextSpan(text: _kText));
+ final RenderParagraph paragraph = new RenderParagraph(
+ const TextSpan(text: _kText),
+ textDirection: TextDirection.ltr,
+ );
layout(paragraph);
List<ui.TextBox> boxes = paragraph.getBoxesForSelection(
@@ -61,7 +70,10 @@
});
test('getWordBoundary control test', () {
- final RenderParagraph paragraph = new RenderParagraph(const TextSpan(text: _kText));
+ final RenderParagraph paragraph = new RenderParagraph(
+ const TextSpan(text: _kText),
+ textDirection: TextDirection.ltr,
+ );
layout(paragraph);
final TextRange range5 = paragraph.getWordBoundary(const TextPosition(offset: 5));
@@ -81,6 +93,7 @@
'is a wrapping test. It should wrap at manual newlines, and if softWrap is true, also at spaces.',
style: const TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
),
+ textDirection: TextDirection.ltr,
maxLines: 1,
softWrap: true,
);
@@ -157,6 +170,7 @@
// 0 1 2 3 4 5 6 7 8 9 10 11 12
style: const TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
),
+ textDirection: TextDirection.ltr,
);
layout(paragraph, constraints: const BoxConstraints(maxWidth: 100.0));
void layoutAt(int maxLines) {
@@ -183,6 +197,7 @@
text: 'Hello',
style: const TextStyle(color: const Color(0xFF000000)),
),
+ textDirection: TextDirection.ltr,
);
layout(paragraph, constraints: const BoxConstraints(maxWidth: 100.0), phase: EnginePhase.paint);
expect(paragraph.debugNeedsLayout, isFalse);
@@ -210,15 +225,21 @@
test('toStringDeep', () {
final RenderParagraph paragraph = new RenderParagraph(
const TextSpan(text: _kText),
+ textDirection: TextDirection.ltr,
);
expect(paragraph, hasAGoodToStringDeep);
expect(
paragraph.toStringDeep(),
equalsIgnoringHashCodes(
'RenderParagraph#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' │ parentData: null\n'
- ' │ constraints: null\n'
+ ' │ parentData: MISSING\n'
+ ' │ constraints: MISSING\n'
' │ size: MISSING\n'
+ ' │ textAlign: start\n'
+ ' │ textDirection: ltr\n'
+ ' │ softWrap: wrapping at box width\n'
+ ' │ overflow: clip\n'
+ ' │ maxLines: unlimited\n'
' ╘═╦══ text ═══\n'
' ║ TextSpan:\n'
' ║ "I polished up that handle so carefullee\n'
diff --git a/packages/flutter/test/rendering/semantics_and_children_test.dart b/packages/flutter/test/rendering/semantics_and_children_test.dart
index 82ca3bb..90afb11 100644
--- a/packages/flutter/test/rendering/semantics_and_children_test.dart
+++ b/packages/flutter/test/rendering/semantics_and_children_test.dart
@@ -16,7 +16,12 @@
void main() {
test('RenderOpacity and children and semantics', () {
- final RenderOpacity box = new RenderOpacity(child: new RenderParagraph(const TextSpan()));
+ final RenderOpacity box = new RenderOpacity(
+ child: new RenderParagraph(
+ const TextSpan(),
+ textDirection: TextDirection.ltr,
+ ),
+ );
expect(countSemanticsChildren(box), 1);
box.opacity = 0.5;
expect(countSemanticsChildren(box), 1);
diff --git a/packages/flutter/test/rendering/slivers_test.dart b/packages/flutter/test/rendering/slivers_test.dart
index 91b05dc..1525a5a 100644
--- a/packages/flutter/test/rendering/slivers_test.dart
+++ b/packages/flutter/test/rendering/slivers_test.dart
@@ -19,8 +19,8 @@
root.toStringDeep(),
equalsIgnoringHashCodes(
'RenderViewport#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' parentData: null\n'
- ' constraints: null\n'
+ ' parentData: MISSING\n'
+ ' constraints: MISSING\n'
' size: MISSING\n'
' axisDirection: down\n'
' crossAxisDirection: right\n'
diff --git a/packages/flutter/test/rendering/wrap_test.dart b/packages/flutter/test/rendering/wrap_test.dart
index 650b6d3..bc0329d 100644
--- a/packages/flutter/test/rendering/wrap_test.dart
+++ b/packages/flutter/test/rendering/wrap_test.dart
@@ -13,8 +13,8 @@
renderWrap.toStringDeep(),
equalsIgnoringHashCodes(
'RenderWrap#00000 NEEDS-LAYOUT NEEDS-PAINT DETACHED\n'
- ' parentData: null\n'
- ' constraints: null\n'
+ ' parentData: MISSING\n'
+ ' constraints: MISSING\n'
' size: MISSING\n'
' direction: horizontal\n'
' alignment: start\n'
diff --git a/packages/flutter/test/widgets/animated_container_test.dart b/packages/flutter/test/widgets/animated_container_test.dart
index dcd89cd..f0c1c80 100644
--- a/packages/flutter/test/widgets/animated_container_test.dart
+++ b/packages/flutter/test/widgets/animated_container_test.dart
@@ -230,7 +230,7 @@
duration: const Duration(milliseconds: 200),
width: 100.0,
height: 100.0,
- child: const Text('X')
+ child: const Text('X', textDirection: TextDirection.ltr)
)
)
);
@@ -250,7 +250,7 @@
duration: const Duration(milliseconds: 200),
width: 200.0,
height: 200.0,
- child: const Text('X')
+ child: const Text('X', textDirection: TextDirection.ltr)
)
)
);
@@ -274,7 +274,7 @@
duration: const Duration(milliseconds: 200),
width: 200.0,
height: 100.0,
- child: const Text('X')
+ child: const Text('X', textDirection: TextDirection.ltr)
)
)
);
diff --git a/packages/flutter/test/widgets/animated_cross_fade_test.dart b/packages/flutter/test/widgets/animated_cross_fade_test.dart
index ed09f63..7dd7824 100644
--- a/packages/flutter/test/widgets/animated_cross_fade_test.dart
+++ b/packages/flutter/test/widgets/animated_cross_fade_test.dart
@@ -302,16 +302,16 @@
testWidgets('AnimatedCrossFade.layoutBuilder', (WidgetTester tester) async {
await tester.pumpWidget(const AnimatedCrossFade(
- firstChild: const Text('AAA'),
- secondChild: const Text('BBB'),
+ firstChild: const Text('AAA', textDirection: TextDirection.ltr),
+ secondChild: const Text('BBB', textDirection: TextDirection.ltr),
crossFadeState: CrossFadeState.showFirst,
duration: const Duration(milliseconds: 50),
));
expect(find.text('AAA'), findsOneWidget);
expect(find.text('BBB'), findsOneWidget);
await tester.pumpWidget(new AnimatedCrossFade(
- firstChild: const Text('AAA'),
- secondChild: const Text('BBB'),
+ firstChild: const Text('AAA', textDirection: TextDirection.ltr),
+ secondChild: const Text('BBB', textDirection: TextDirection.ltr),
crossFadeState: CrossFadeState.showFirst,
duration: const Duration(milliseconds: 50),
layoutBuilder: (Widget a, Key aKey, Widget b, Key bKey) => a,
@@ -319,8 +319,8 @@
expect(find.text('AAA'), findsOneWidget);
expect(find.text('BBB'), findsNothing);
await tester.pumpWidget(new AnimatedCrossFade(
- firstChild: const Text('AAA'),
- secondChild: const Text('BBB'),
+ firstChild: const Text('AAA', textDirection: TextDirection.ltr),
+ secondChild: const Text('BBB', textDirection: TextDirection.ltr),
crossFadeState: CrossFadeState.showSecond,
duration: const Duration(milliseconds: 50),
layoutBuilder: (Widget a, Key aKey, Widget b, Key bKey) => a,
diff --git a/packages/flutter/test/widgets/animated_list_test.dart b/packages/flutter/test/widgets/animated_list_test.dart
index 54e8167..08bde08 100644
--- a/packages/flutter/test/widgets/animated_list_test.dart
+++ b/packages/flutter/test/widgets/animated_list_test.dart
@@ -121,7 +121,7 @@
child: new SizedBox(
height: 100.0,
child: new Center(
- child: new Text('item $item'),
+ child: new Text('item $item', textDirection: TextDirection.ltr),
),
),
);
diff --git a/packages/flutter/test/widgets/async_test.dart b/packages/flutter/test/widgets/async_test.dart
index ad5bade..ff1a96f 100644
--- a/packages/flutter/test/widgets/async_test.dart
+++ b/packages/flutter/test/widgets/async_test.dart
@@ -9,7 +9,7 @@
void main() {
Widget snapshotText(BuildContext context, AsyncSnapshot<String> snapshot) {
- return new Text(snapshot.toString());
+ return new Text(snapshot.toString(), textDirection: TextDirection.ltr);
}
group('AsyncSnapshot', () {
test('requiring data succeeds if data is present', () {
@@ -280,5 +280,5 @@
List<String> afterDisconnected(List<String> current) => current..add('disc');
@override
- Widget build(BuildContext context, List<String> currentSummary) => new Text(currentSummary.join(', '));
+ Widget build(BuildContext context, List<String> currentSummary) => new Text(currentSummary.join(', '), textDirection: TextDirection.ltr);
}
diff --git a/packages/flutter/test/widgets/banner_test.dart b/packages/flutter/test/widgets/banner_test.dart
index c52e616..0208dda 100644
--- a/packages/flutter/test/widgets/banner_test.dart
+++ b/packages/flutter/test/widgets/banner_test.dart
@@ -19,7 +19,8 @@
void main() {
test('A Banner with a location of topLeft paints in the top left', () {
final BannerPainter bannerPainter = new BannerPainter(
- message:"foo",
+ message: 'foo',
+ textDirection: TextDirection.ltr,
location: BannerLocation.topLeft
);
@@ -45,7 +46,8 @@
test('A Banner with a location of topRight paints in the top right', () {
final BannerPainter bannerPainter = new BannerPainter(
- message:"foo",
+ message: 'foo',
+ textDirection: TextDirection.ltr,
location: BannerLocation.topRight
);
@@ -71,7 +73,8 @@
test('A Banner with a location of bottomLeft paints in the bottom left', () {
final BannerPainter bannerPainter = new BannerPainter(
- message:"foo",
+ message: 'foo',
+ textDirection: TextDirection.ltr,
location: BannerLocation.bottomLeft
);
@@ -97,7 +100,8 @@
test('A Banner with a location of bottomRight paints in the bottom right', () {
final BannerPainter bannerPainter = new BannerPainter(
- message:"foo",
+ message: 'foo',
+ textDirection: TextDirection.ltr,
location: BannerLocation.bottomRight
);
diff --git a/packages/flutter/test/widgets/baseline_test.dart b/packages/flutter/test/widgets/baseline_test.dart
index 23216b0..3dfdbb3 100644
--- a/packages/flutter/test/widgets/baseline_test.dart
+++ b/packages/flutter/test/widgets/baseline_test.dart
@@ -14,7 +14,7 @@
fontFamily: 'Ahem',
fontSize: 100.0,
),
- child: const Text('X'),
+ child: const Text('X', textDirection: TextDirection.ltr),
),
),
);
@@ -32,7 +32,7 @@
fontFamily: 'Ahem',
fontSize: 100.0,
),
- child: const Text('X'),
+ child: const Text('X', textDirection: TextDirection.ltr),
),
),
),
diff --git a/packages/flutter/test/widgets/clamp_overscrolls_test.dart b/packages/flutter/test/widgets/clamp_overscrolls_test.dart
index 6dffdea..c5cc92d 100644
--- a/packages/flutter/test/widgets/clamp_overscrolls_test.dart
+++ b/packages/flutter/test/widgets/clamp_overscrolls_test.dart
@@ -21,9 +21,9 @@
crossAxisAlignment: CrossAxisAlignment.start,
textDirection: TextDirection.ltr,
children: <Widget>[
- const SizedBox(height: 100.0, child: const Text('top')),
+ const SizedBox(height: 100.0, child: const Text('top', textDirection: TextDirection.ltr)),
new Expanded(child: new Container()),
- const SizedBox(height: 100.0, child: const Text('bottom')),
+ const SizedBox(height: 100.0, child: const Text('bottom', textDirection: TextDirection.ltr)),
],
),
),
diff --git a/packages/flutter/test/widgets/default_text_style_test.dart b/packages/flutter/test/widgets/default_text_style_test.dart
index 28da826..e5909c1 100644
--- a/packages/flutter/test/widgets/default_text_style_test.dart
+++ b/packages/flutter/test/widgets/default_text_style_test.dart
@@ -7,7 +7,7 @@
void main() {
testWidgets('DefaultTextStyle changes propagate to Text', (WidgetTester tester) async {
- const Text textWidget = const Text('Hello');
+ const Text textWidget = const Text('Hello', textDirection: TextDirection.ltr);
const TextStyle s1 = const TextStyle(
fontSize: 10.0,
fontWeight: FontWeight.w800,
@@ -16,7 +16,7 @@
await tester.pumpWidget(const DefaultTextStyle(
style: s1,
- child: textWidget
+ child: textWidget,
));
RichText text = tester.firstWidget(find.byType(RichText));
diff --git a/packages/flutter/test/widgets/dismissible_test.dart b/packages/flutter/test/widgets/dismissible_test.dart
index 6ebe430..00b7e0b 100644
--- a/packages/flutter/test/widgets/dismissible_test.dart
+++ b/packages/flutter/test/widgets/dismissible_test.dart
@@ -14,48 +14,51 @@
Widget background;
Widget buildTest({ double startToEndThreshold }) {
- return new StatefulBuilder(
- builder: (BuildContext context, StateSetter setState) {
- Widget buildDismissibleItem(int item) {
- return new Dismissible(
- key: new ValueKey<int>(item),
- direction: dismissDirection,
- onDismissed: (DismissDirection direction) {
- setState(() {
- reportedDismissDirection = direction;
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new StatefulBuilder(
+ builder: (BuildContext context, StateSetter setState) {
+ Widget buildDismissibleItem(int item) {
+ return new Dismissible(
+ key: new ValueKey<int>(item),
+ direction: dismissDirection,
+ onDismissed: (DismissDirection direction) {
+ setState(() {
+ reportedDismissDirection = direction;
+ expect(dismissedItems.contains(item), isFalse);
+ dismissedItems.add(item);
+ });
+ },
+ onResize: () {
expect(dismissedItems.contains(item), isFalse);
- dismissedItems.add(item);
- });
- },
- onResize: () {
- expect(dismissedItems.contains(item), isFalse);
- },
- background: background,
- dismissThresholds: startToEndThreshold == null
- ? <DismissDirection, double>{}
- : <DismissDirection, double>{DismissDirection.startToEnd: startToEndThreshold},
+ },
+ background: background,
+ dismissThresholds: startToEndThreshold == null
+ ? <DismissDirection, double>{}
+ : <DismissDirection, double>{DismissDirection.startToEnd: startToEndThreshold},
+ child: new Container(
+ width: itemExtent,
+ height: itemExtent,
+ child: new Text(item.toString()),
+ ),
+ );
+ }
+
+ return new Directionality(
+ textDirection: TextDirection.ltr,
child: new Container(
- width: itemExtent,
- height: itemExtent,
- child: new Text(item.toString()),
+ padding: const EdgeInsets.all(10.0),
+ child: new ListView(
+ scrollDirection: scrollDirection,
+ itemExtent: itemExtent,
+ children: <int>[0, 1, 2, 3, 4]
+ .where((int i) => !dismissedItems.contains(i))
+ .map(buildDismissibleItem).toList(),
+ ),
),
);
- }
-
- return new Directionality(
- textDirection: TextDirection.ltr,
- child: new Container(
- padding: const EdgeInsets.all(10.0),
- child: new ListView(
- scrollDirection: scrollDirection,
- itemExtent: itemExtent,
- children: <int>[0, 1, 2, 3, 4]
- .where((int i) => !dismissedItems.contains(i))
- .map(buildDismissibleItem).toList(),
- ),
- ),
- );
- },
+ },
+ ),
);
}
@@ -287,18 +290,23 @@
// actually remove the dismissed widget, which is a violation of the
// Dismissible contract. This is not an example of good practice.
testWidgets('dismissing bottom then top (smoketest)', (WidgetTester tester) async {
- await tester.pumpWidget(new Center(
- child: new Container(
- width: 100.0,
- height: 1000.0,
- child: new Column(
- children: <Widget>[
- const Test1215DismissibleWidget('1'),
- const Test1215DismissibleWidget('2'),
- ],
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Container(
+ width: 100.0,
+ height: 1000.0,
+ child: new Column(
+ children: <Widget>[
+ const Test1215DismissibleWidget('1'),
+ const Test1215DismissibleWidget('2'),
+ ],
+ ),
+ ),
),
),
- ));
+ );
expect(find.text('1'), findsOneWidget);
expect(find.text('2'), findsOneWidget);
await dismissElement(tester, find.text('2'), gestureDirection: DismissDirection.startToEnd);
diff --git a/packages/flutter/test/widgets/dispose_ancestor_lookup_test.dart b/packages/flutter/test/widgets/dispose_ancestor_lookup_test.dart
index 08f4a97..bb53504 100644
--- a/packages/flutter/test/widgets/dispose_ancestor_lookup_test.dart
+++ b/packages/flutter/test/widgets/dispose_ancestor_lookup_test.dart
@@ -24,7 +24,7 @@
}
@override
- Widget build(BuildContext context) => const Text('test');
+ Widget build(BuildContext context) => const Text('test', textDirection: TextDirection.ltr);
}
void main() {
diff --git a/packages/flutter/test/widgets/flex_test.dart b/packages/flutter/test/widgets/flex_test.dart
index 126e5ef..f93df04 100644
--- a/packages/flutter/test/widgets/flex_test.dart
+++ b/packages/flutter/test/widgets/flex_test.dart
@@ -28,7 +28,7 @@
width: 100.0,
height: 100.0,
child: const Center(
- child: const Text('X'),
+ child: const Text('X', textDirection: TextDirection.ltr),
),
),
),
@@ -63,8 +63,8 @@
new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- const Expanded(flex: null, child: const Text('one')),
- const Flexible(flex: null, child: const Text('two')),
+ const Expanded(flex: null, child: const Text('one', textDirection: TextDirection.ltr)),
+ const Flexible(flex: null, child: const Text('two', textDirection: TextDirection.ltr)),
],
),
);
diff --git a/packages/flutter/test/widgets/flow_test.dart b/packages/flutter/test/widgets/flow_test.dart
index 237ba63..18991e8 100644
--- a/packages/flutter/test/widgets/flow_test.dart
+++ b/packages/flutter/test/widgets/flow_test.dart
@@ -44,7 +44,7 @@
width: 100.0,
height: 100.0,
color: const Color(0xFF0000FF),
- child: new Text('$i')
+ child: new Text('$i', textDirection: TextDirection.ltr)
)
);
}
diff --git a/packages/flutter/test/widgets/focus_test.dart b/packages/flutter/test/widgets/focus_test.dart
index 282d1f2..874ef90 100644
--- a/packages/flutter/test/widgets/focus_test.dart
+++ b/packages/flutter/test/widgets/focus_test.dart
@@ -47,7 +47,7 @@
child: new AnimatedBuilder(
animation: focusNode,
builder: (BuildContext context, Widget child) {
- return new Text(focusNode.hasFocus ? widget.yes : widget.no);
+ return new Text(focusNode.hasFocus ? widget.yes : widget.no, textDirection: TextDirection.ltr);
},
),
);
diff --git a/packages/flutter/test/widgets/form_test.dart b/packages/flutter/test/widgets/form_test.dart
index 2b83611..4e27812 100644
--- a/packages/flutter/test/widgets/form_test.dart
+++ b/packages/flutter/test/widgets/form_test.dart
@@ -11,12 +11,15 @@
String fieldValue;
Widget builder() {
- return new Center(
- child: new Material(
- child: new Form(
- key: formKey,
- child: new TextFormField(
- onSaved: (String value) { fieldValue = value; },
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(
+ child: new Form(
+ key: formKey,
+ child: new TextFormField(
+ onSaved: (String value) { fieldValue = value; },
+ ),
),
),
),
@@ -42,11 +45,14 @@
String fieldValue;
Widget builder() {
- return new Center(
- child: new Material(
- child: new Form(
- child: new TextField(
- onChanged: (String value) { fieldValue = value; },
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(
+ child: new Form(
+ child: new TextField(
+ onChanged: (String value) { fieldValue = value; },
+ ),
),
),
),
@@ -72,13 +78,16 @@
String errorText(String value) => value + '/error';
Widget builder(bool autovalidate) {
- return new Center(
- child: new Material(
- child: new Form(
- key: formKey,
- autovalidate: autovalidate,
- child: new TextFormField(
- validator: errorText,
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(
+ child: new Form(
+ key: formKey,
+ autovalidate: autovalidate,
+ child: new TextFormField(
+ validator: errorText,
+ ),
),
),
),
@@ -162,12 +171,15 @@
final GlobalKey<FormFieldState<String>> inputKey = new GlobalKey<FormFieldState<String>>();
Widget builder() {
- return new Center(
- child: new Material(
- child: new Form(
- child: new TextFormField(
- key: inputKey,
- controller: controller,
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(
+ child: new Form(
+ child: new TextFormField(
+ key: inputKey,
+ controller: controller,
+ ),
),
),
),
@@ -198,14 +210,17 @@
String fieldValue;
Widget builder(bool remove) {
- return new Center(
- child: new Material(
- child: new Form(
- key: formKey,
- child: remove ? new Container() : new TextFormField(
- autofocus: true,
- onSaved: (String value) { fieldValue = value; },
- validator: (String value) { return value.isEmpty ? null : 'yes'; }
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new Material(
+ child: new Form(
+ key: formKey,
+ child: remove ? new Container() : new TextFormField(
+ autofocus: true,
+ onSaved: (String value) { fieldValue = value; },
+ validator: (String value) { return value.isEmpty ? null : 'yes'; }
+ ),
),
),
),
diff --git a/packages/flutter/test/widgets/global_keys_moving_test.dart b/packages/flutter/test/widgets/global_keys_moving_test.dart
index 2e7346e..12f1276 100644
--- a/packages/flutter/test/widgets/global_keys_moving_test.dart
+++ b/packages/flutter/test/widgets/global_keys_moving_test.dart
@@ -25,7 +25,7 @@
void markNeedsBuild() { setState(() { }); }
@override
- Widget build(BuildContext context) => const Text('leaf');
+ Widget build(BuildContext context) => const Text('leaf', textDirection: TextDirection.ltr);
}
class KeyedWrapper extends StatelessWidget {
diff --git a/packages/flutter/test/widgets/hit_testing_test.dart b/packages/flutter/test/widgets/hit_testing_test.dart
index d069d0b..7afa44d 100644
--- a/packages/flutter/test/widgets/hit_testing_test.dart
+++ b/packages/flutter/test/widgets/hit_testing_test.dart
@@ -8,7 +8,7 @@
void main() {
testWidgets('toString control test', (WidgetTester tester) async {
- await tester.pumpWidget(const Center(child: const Text('Hello')));
+ await tester.pumpWidget(const Center(child: const Text('Hello', textDirection: TextDirection.ltr)));
final HitTestResult result = tester.hitTestOnBinding(Offset.zero);
expect(result, hasOneLineDescription);
expect(result.path.first, hasOneLineDescription);
diff --git a/packages/flutter/test/widgets/hyperlink_test.dart b/packages/flutter/test/widgets/hyperlink_test.dart
index 98b1352..6f6fede 100644
--- a/packages/flutter/test/widgets/hyperlink_test.dart
+++ b/packages/flutter/test/widgets/hyperlink_test.dart
@@ -26,6 +26,7 @@
new Center(
child: new RichText(
key: textKey,
+ textDirection: TextDirection.ltr,
text: new TextSpan(
children: <TextSpan>[
new TextSpan(
diff --git a/packages/flutter/test/widgets/icon_test.dart b/packages/flutter/test/widgets/icon_test.dart
index bfbe94e..3ad61de 100644
--- a/packages/flutter/test/widgets/icon_test.dart
+++ b/packages/flutter/test/widgets/icon_test.dart
@@ -8,13 +8,16 @@
void main() {
testWidgets('Can set opacity for an Icon', (WidgetTester tester) async {
await tester.pumpWidget(
- const IconTheme(
- data: const IconThemeData(
- color: const Color(0xFF666666),
- opacity: 0.5
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const IconTheme(
+ data: const IconThemeData(
+ color: const Color(0xFF666666),
+ opacity: 0.5
+ ),
+ child: const Icon(const IconData(0xd0a0, fontFamily: 'Arial'))
),
- child: const Icon(const IconData(0xd0a0, fontFamily: 'Arial'))
- )
+ ),
);
final RichText text = tester.widget(find.byType(RichText));
expect(text.text.style.color, const Color(0xFF666666).withOpacity(0.5));
@@ -22,8 +25,11 @@
testWidgets('Icon sizing - no theme, default size', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const Icon(null),
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const Icon(null),
+ ),
),
);
@@ -33,10 +39,13 @@
testWidgets('Icon sizing - no theme, explicit size', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const Icon(
- null,
- size: 96.0,
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const Icon(
+ null,
+ size: 96.0,
+ ),
),
),
);
@@ -47,10 +56,13 @@
testWidgets('Icon sizing - sized theme', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const IconTheme(
- data: const IconThemeData(size: 36.0),
- child: const Icon(null),
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const IconTheme(
+ data: const IconThemeData(size: 36.0),
+ child: const Icon(null),
+ ),
),
),
);
@@ -61,12 +73,15 @@
testWidgets('Icon sizing - sized theme, explicit size', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const IconTheme(
- data: const IconThemeData(size: 36.0),
- child: const Icon(
- null,
- size: 48.0,
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const IconTheme(
+ data: const IconThemeData(size: 36.0),
+ child: const Icon(
+ null,
+ size: 48.0,
+ ),
),
),
)
@@ -78,10 +93,13 @@
testWidgets('Icon sizing - sizeless theme, default size', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const IconTheme(
- data: const IconThemeData(),
- child: const Icon(null),
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const IconTheme(
+ data: const IconThemeData(),
+ child: const Icon(null),
+ ),
),
),
);
@@ -93,8 +111,11 @@
testWidgets('Icon with custom font', (WidgetTester tester) async {
await tester.pumpWidget(
- const Center(
- child: const Icon(const IconData(0x41, fontFamily: 'Roboto')),
+ const Directionality(
+ textDirection: TextDirection.ltr,
+ child: const Center(
+ child: const Icon(const IconData(0x41, fontFamily: 'Roboto')),
+ ),
),
);
diff --git a/packages/flutter/test/widgets/independent_widget_layout_test.dart b/packages/flutter/test/widgets/independent_widget_layout_test.dart
index 5ae15a1..b9306d0 100644
--- a/packages/flutter/test/widgets/independent_widget_layout_test.dart
+++ b/packages/flutter/test/widgets/independent_widget_layout_test.dart
@@ -92,7 +92,7 @@
@override
Widget build(BuildContext context) {
widget.counter.count++;
- return new Text("Bang $_count!");
+ return new Text("Bang $_count!", textDirection: TextDirection.ltr);
}
}
diff --git a/packages/flutter/test/widgets/inherited_test.dart b/packages/flutter/test/widgets/inherited_test.dart
index d193104..99cb5c8 100644
--- a/packages/flutter/test/widgets/inherited_test.dart
+++ b/packages/flutter/test/widgets/inherited_test.dart
@@ -129,7 +129,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add('a: ${v.value}');
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
)
)
@@ -146,7 +146,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add('b: ${v.value}');
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
)
)
@@ -204,7 +204,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add('a: ${v.value}');
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
)
)
@@ -222,7 +222,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add('b: ${v.value}');
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
)
)
@@ -265,7 +265,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add(v.value);
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
);
@@ -336,7 +336,7 @@
builder: (BuildContext context) {
final ValueInherited v = context.inheritFromWidgetOfExactType(ValueInherited);
log.add(v.value);
- return const Text('');
+ return const Text('', textDirection: TextDirection.ltr);
}
);
diff --git a/packages/flutter/test/widgets/list_view_builder_test.dart b/packages/flutter/test/widgets/list_view_builder_test.dart
index 3ccfb61..26e7e78 100644
--- a/packages/flutter/test/widgets/list_view_builder_test.dart
+++ b/packages/flutter/test/widgets/list_view_builder_test.dart
@@ -66,7 +66,7 @@
key: new ValueKey<int>(index),
width: 500.0, // this should be ignored
height: 400.0, // should be overridden by itemExtent
- child: new Text('$index')
+ child: new Text('$index', textDirection: TextDirection.ltr)
);
};
@@ -79,7 +79,7 @@
itemExtent: 200.0,
itemBuilder: itemBuilder,
),
- right: const Text('Not Today')
+ right: const Text('Not Today'),
),
);
}
@@ -190,7 +190,7 @@
final IndexedWidgetBuilder itemBuilder = (BuildContext context, int index) {
callbackTracker.add(index);
- return new Text('$index', key: new ValueKey<int>(index));
+ return new Text('$index', key: new ValueKey<int>(index), textDirection: TextDirection.ltr);
};
final Widget testWidget = new Directionality(
diff --git a/packages/flutter/test/widgets/list_view_horizontal_test.dart b/packages/flutter/test/widgets/list_view_horizontal_test.dart
index 1391ba4..9889146 100644
--- a/packages/flutter/test/widgets/list_view_horizontal_test.dart
+++ b/packages/flutter/test/widgets/list_view_horizontal_test.dart
@@ -2,10 +2,10 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
const List<int> items = const <int>[0, 1, 2, 3, 4, 5];
diff --git a/packages/flutter/test/widgets/list_view_misc_test.dart b/packages/flutter/test/widgets/list_view_misc_test.dart
index 298501c..8878ecb 100644
--- a/packages/flutter/test/widgets/list_view_misc_test.dart
+++ b/packages/flutter/test/widgets/list_view_misc_test.dart
@@ -120,7 +120,7 @@
textDirection: TextDirection.ltr,
child: new ListView(
controller: controller,
- children: <Widget>[const Text("A"), const Text("B"), const Text("C")],
+ children: <Widget>[const Text('A'), const Text('B'), const Text('C')],
),
);
}
diff --git a/packages/flutter/test/widgets/list_view_test.dart b/packages/flutter/test/widgets/list_view_test.dart
index 4e13371..7623528 100644
--- a/packages/flutter/test/widgets/list_view_test.dart
+++ b/packages/flutter/test/widgets/list_view_test.dart
@@ -189,7 +189,7 @@
child: new ListView(
padding: const EdgeInsets.all(8.0),
children: <Widget>[
- const Text('padded'),
+ const Text('padded', textDirection: TextDirection.ltr),
],
),
),
@@ -225,7 +225,7 @@
final TestSliverChildListDelegate delegate = new TestSliverChildListDelegate(
new List<Widget>.generate(20, (int i) {
return new Container(
- child: new Text('$i'),
+ child: new Text('$i', textDirection: TextDirection.ltr),
);
})
);
diff --git a/packages/flutter/test/widgets/list_view_viewporting_test.dart b/packages/flutter/test/widgets/list_view_viewporting_test.dart
index b510721..bdf0487 100644
--- a/packages/flutter/test/widgets/list_view_viewporting_test.dart
+++ b/packages/flutter/test/widgets/list_view_viewporting_test.dart
@@ -66,7 +66,7 @@
key: new ValueKey<int>(index),
width: 500.0, // this should be ignored
height: 200.0,
- child: new Text('$index'),
+ child: new Text('$index', textDirection: TextDirection.ltr),
);
};
@@ -118,7 +118,7 @@
key: new ValueKey<int>(index),
height: 500.0, // this should be ignored
width: 200.0,
- child: new Text('$index'),
+ child: new Text('$index', textDirection: TextDirection.ltr),
);
};
@@ -169,7 +169,7 @@
key: new ValueKey<int>(index),
width: 500.0, // this should be ignored
height: 220.0,
- child: new Text('$index')
+ child: new Text('$index', textDirection: TextDirection.ltr)
);
};
@@ -214,7 +214,7 @@
width: 500.0, // this should be ignored
height: 220.0,
color: Theme.of(context).primaryColor,
- child: new Text('$index'),
+ child: new Text('$index', textDirection: TextDirection.ltr),
);
};
@@ -256,7 +256,7 @@
width: 500.0, // this should be ignored
height: 220.0,
color: Colors.green[500],
- child: new Text('$index'),
+ child: new Text('$index', textDirection: TextDirection.ltr),
);
};
diff --git a/packages/flutter/test/widgets/list_view_with_inherited_test.dart b/packages/flutter/test/widgets/list_view_with_inherited_test.dart
index 9523ef2..71d5936 100644
--- a/packages/flutter/test/widgets/list_view_with_inherited_test.dart
+++ b/packages/flutter/test/widgets/list_view_with_inherited_test.dart
@@ -15,7 +15,7 @@
height: 100.0,
child: new DefaultTextStyle(
style: new TextStyle(fontSize: 2.0 + items.length.toDouble()),
- child: new Text('${items[index]}')
+ child: new Text('${items[index]}', textDirection: TextDirection.ltr)
)
);
}
diff --git a/packages/flutter/test/widgets/listener_test.dart b/packages/flutter/test/widgets/listener_test.dart
index 11c7b60..16c7c7d 100644
--- a/packages/flutter/test/widgets/listener_test.dart
+++ b/packages/flutter/test/widgets/listener_test.dart
@@ -24,7 +24,7 @@
onPointerDown: (_) {
log.add('bottom');
},
- child: const Text('X')
+ child: const Text('X', textDirection: TextDirection.ltr)
)
)
)
diff --git a/packages/flutter/test/widgets/localizations_test.dart b/packages/flutter/test/widgets/localizations_test.dart
index 18974fa..90575e0 100644
--- a/packages/flutter/test/widgets/localizations_test.dart
+++ b/packages/flutter/test/widgets/localizations_test.dart
@@ -130,7 +130,7 @@
buildFrame(
buildContent: (BuildContext context) {
pageContext = context;
- return const Text('Hello World');
+ return const Text('Hello World', textDirection: TextDirection.ltr);
}
)
);
diff --git a/packages/flutter/test/widgets/modal_barrier_test.dart b/packages/flutter/test/widgets/modal_barrier_test.dart
index a2e9bdf..b2d628f 100644
--- a/packages/flutter/test/widgets/modal_barrier_test.dart
+++ b/packages/flutter/test/widgets/modal_barrier_test.dart
@@ -23,7 +23,7 @@
child: const SizedBox(
width: 10.0,
height: 10.0,
- child: const Text('target')
+ child: const Text('target', textDirection: TextDirection.ltr)
)
);
});
diff --git a/packages/flutter/test/widgets/overlay_test.dart b/packages/flutter/test/widgets/overlay_test.dart
index 9c1e3df..f7619be 100644
--- a/packages/flutter/test/widgets/overlay_test.dart
+++ b/packages/flutter/test/widgets/overlay_test.dart
@@ -141,7 +141,7 @@
' ╎ │ _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#00000] ←\n'
' ╎ │ TickerMode ← _Theatre ← Overlay-[GlobalKey#00000] ← [root]\n'
' ╎ │ parentData: not positioned; offset=Offset(0.0, 0.0)\n'
- ' ╎ │ constraints: null\n'
+ ' ╎ │ constraints: MISSING\n'
' ╎ │ size: MISSING\n'
' ╎ │ maxWidth: 0.0\n'
' ╎ │ maxHeight: 0.0\n'
@@ -151,7 +151,7 @@
' ╎ _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#00000] ←\n'
' ╎ TickerMode ← _Theatre ← Overlay-[GlobalKey#00000] ← [root]\n'
' ╎ parentData: <none>\n'
- ' ╎ constraints: null\n'
+ ' ╎ constraints: MISSING\n'
' ╎ size: MISSING\n'
' ╎ additionalConstraints: BoxConstraints(biggest)\n'
' ╎\n'
@@ -160,7 +160,7 @@
' │ _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#00000] ←\n'
' │ TickerMode ← _Theatre ← Overlay-[GlobalKey#00000] ← [root]\n'
' │ parentData: not positioned; offset=Offset(0.0, 0.0)\n'
- ' │ constraints: null\n'
+ ' │ constraints: MISSING\n'
' │ size: MISSING\n'
' │ maxWidth: 0.0\n'
' │ maxHeight: 0.0\n'
@@ -170,7 +170,7 @@
' _OverlayEntry-[LabeledGlobalKey<_OverlayEntryState>#00000] ←\n'
' TickerMode ← _Theatre ← Overlay-[GlobalKey#00000] ← [root]\n'
' parentData: <none>\n'
- ' constraints: null\n'
+ ' constraints: MISSING\n'
' size: MISSING\n'
' additionalConstraints: BoxConstraints(biggest)\n'
),
diff --git a/packages/flutter/test/widgets/pageable_list_test.dart b/packages/flutter/test/widgets/pageable_list_test.dart
index de53906..ebf3242 100644
--- a/packages/flutter/test/widgets/pageable_list_test.dart
+++ b/packages/flutter/test/widgets/pageable_list_test.dart
@@ -63,10 +63,14 @@
void main() {
testWidgets('PageView default control', (WidgetTester tester) async {
- await tester.pumpWidget(new Directionality(
- textDirection: TextDirection.ltr,
- child: new Center(child: new PageView())
- ));
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Center(
+ child: new PageView(),
+ ),
+ ),
+ );
});
testWidgets('PageView control test (LTR)', (WidgetTester tester) async {
diff --git a/packages/flutter/test/widgets/reparent_state_harder_test.dart b/packages/flutter/test/widgets/reparent_state_harder_test.dart
index 602b4ef..0c786b5 100644
--- a/packages/flutter/test/widgets/reparent_state_harder_test.dart
+++ b/packages/flutter/test/widgets/reparent_state_harder_test.dart
@@ -52,7 +52,7 @@
class DummyStatefulWidgetState extends State<DummyStatefulWidget> {
@override
- Widget build(BuildContext context) => const Text('LEAF');
+ Widget build(BuildContext context) => const Text('LEAF', textDirection: TextDirection.ltr);
}
class RekeyableDummyStatefulWidgetWrapper extends StatefulWidget {
diff --git a/packages/flutter/test/widgets/run_app_test.dart b/packages/flutter/test/widgets/run_app_test.dart
index 901cfa1..6f9de6d 100644
--- a/packages/flutter/test/widgets/run_app_test.dart
+++ b/packages/flutter/test/widgets/run_app_test.dart
@@ -11,9 +11,9 @@
new Material(
child: new RaisedButton(
onPressed: () {
- runApp(const Center(child: const Text('Done')));
+ runApp(const Center(child: const Text('Done', textDirection: TextDirection.ltr)));
},
- child: const Text('GO')
+ child: const Text('GO', textDirection: TextDirection.ltr)
)
)
);
diff --git a/packages/flutter/test/widgets/scrollable_animations_test.dart b/packages/flutter/test/widgets/scrollable_animations_test.dart
index ffb7581..bbe3d39 100644
--- a/packages/flutter/test/widgets/scrollable_animations_test.dart
+++ b/packages/flutter/test/widgets/scrollable_animations_test.dart
@@ -10,7 +10,7 @@
testWidgets('Does not animate if already at target position', (WidgetTester tester) async {
final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 80; i++)
- textWidgets.add(new Text('$i'));
+ textWidgets.add(new Text('$i', textDirection: TextDirection.ltr));
final ScrollController controller = new ScrollController();
await tester.pumpWidget(
new Directionality(
@@ -33,7 +33,7 @@
testWidgets('Does not animate if already at target position within tolerance', (WidgetTester tester) async {
final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 80; i++)
- textWidgets.add(new Text('$i'));
+ textWidgets.add(new Text('$i', textDirection: TextDirection.ltr));
final ScrollController controller = new ScrollController();
await tester.pumpWidget(
new Directionality(
@@ -59,7 +59,7 @@
testWidgets('Animates if going to a position outside of tolerance', (WidgetTester tester) async {
final List<Widget> textWidgets = <Widget>[];
for (int i = 0; i < 80; i++)
- textWidgets.add(new Text('$i'));
+ textWidgets.add(new Text('$i', textDirection: TextDirection.ltr));
final ScrollController controller = new ScrollController();
await tester.pumpWidget(
new Directionality(
diff --git a/packages/flutter/test/widgets/scrollable_semantics_test.dart b/packages/flutter/test/widgets/scrollable_semantics_test.dart
index f2192c0..6252a60 100644
--- a/packages/flutter/test/widgets/scrollable_semantics_test.dart
+++ b/packages/flutter/test/widgets/scrollable_semantics_test.dart
@@ -47,7 +47,7 @@
for (int i = 0; i < 80; i++)
containers.add(new MergeSemantics(child: new Container(
height: kItemHeight,
- child: new Text('container $i'),
+ child: new Text('container $i', textDirection: TextDirection.ltr),
)));
final ScrollController scrollController = new ScrollController(
diff --git a/packages/flutter/test/widgets/semantics_10_test.dart b/packages/flutter/test/widgets/semantics_10_test.dart
index 7650ef2..5ed047d 100644
--- a/packages/flutter/test/widgets/semantics_10_test.dart
+++ b/packages/flutter/test/widgets/semantics_10_test.dart
@@ -16,22 +16,22 @@
final SemanticsTester semantics = new SemanticsTester(tester);
await tester.pumpWidget(
- buildTestWidgets(
- excludeSemantics: false,
- label: 'label',
- isSemanticsBoundary: true,
- )
+ buildTestWidgets(
+ excludeSemantics: false,
+ label: 'label',
+ isSemanticsBoundary: true,
+ ),
);
callLog.clear();
// The following should not trigger an assert.
await tester.pumpWidget(
- buildTestWidgets(
- excludeSemantics: true,
- label: 'label CHANGED',
- isSemanticsBoundary: false,
- )
+ buildTestWidgets(
+ excludeSemantics: true,
+ label: 'label CHANGED',
+ isSemanticsBoundary: false,
+ ),
);
expect(callLog, <String>['markNeedsSemanticsUpdate(onlyChanges: true)', 'markNeedsSemanticsUpdate(onlyChanges: false)']);
@@ -41,23 +41,26 @@
}
Widget buildTestWidgets({bool excludeSemantics, String label, bool isSemanticsBoundary}) {
- return new Semantics(
- label: 'container',
- container: true,
- child: new ExcludeSemantics(
- excluding: excludeSemantics,
- child: new TestWidget(
- label: label,
- isSemanticBoundary: isSemanticsBoundary,
- child: new Column(
- children: <Widget>[
- const Semantics(
- label: 'child1',
- ),
- const Semantics(
- label: 'child2',
- ),
- ],
+ return new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Semantics(
+ label: 'container',
+ container: true,
+ child: new ExcludeSemantics(
+ excluding: excludeSemantics,
+ child: new TestWidget(
+ label: label,
+ isSemanticBoundary: isSemanticsBoundary,
+ child: new Column(
+ children: <Widget>[
+ const Semantics(
+ label: 'child1',
+ ),
+ const Semantics(
+ label: 'child2',
+ ),
+ ],
+ ),
),
),
),
@@ -96,6 +99,7 @@
void _annotate(SemanticsNode node) {
node.label = _label;
+ node.textDirection = TextDirection.ltr;
}
String _label;
diff --git a/packages/flutter/test/widgets/semantics_11_test.dart b/packages/flutter/test/widgets/semantics_11_test.dart
index bd41d68..7acf3f2 100644
--- a/packages/flutter/test/widgets/semantics_11_test.dart
+++ b/packages/flutter/test/widgets/semantics_11_test.dart
@@ -72,5 +72,6 @@
void _annotate(SemanticsNode node) {
labelWasReset.add(node.label == '');
node.label = "Label ${labelWasReset.length}";
+ node.textDirection = TextDirection.ltr;
}
}
diff --git a/packages/flutter/test/widgets/semantics_1_test.dart b/packages/flutter/test/widgets/semantics_1_test.dart
index 2b1b94c..11e7f9a 100644
--- a/packages/flutter/test/widgets/semantics_1_test.dart
+++ b/packages/flutter/test/widgets/semantics_1_test.dart
@@ -18,6 +18,7 @@
new Container(
child: new Semantics(
label: 'test1',
+ textDirection: TextDirection.ltr,
child: new Container()
)
)
@@ -32,13 +33,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr),
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: true,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr),
)
),
],
@@ -54,13 +55,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr),
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: false,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr),
)
),
],
@@ -92,13 +93,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr)
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: true,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr)
)
),
],
@@ -113,13 +114,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr)
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: false,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr)
)
),
],
diff --git a/packages/flutter/test/widgets/semantics_2_test.dart b/packages/flutter/test/widgets/semantics_2_test.dart
index 5d23495..063d8b7 100644
--- a/packages/flutter/test/widgets/semantics_2_test.dart
+++ b/packages/flutter/test/widgets/semantics_2_test.dart
@@ -23,13 +23,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr)
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: false,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr)
)
),
],
@@ -43,11 +43,13 @@
new TestSemantics.rootChild(
id: 1,
label: 'child1',
+ textDirection: TextDirection.ltr,
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
),
new TestSemantics.rootChild(
id: 2,
label: 'child2',
+ textDirection: TextDirection.ltr,
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
transform: new Matrix4.translationValues(0.0, 10.0, 0.0),
),
@@ -61,13 +63,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr)
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: true,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr)
)
),
],
@@ -83,13 +85,13 @@
children: <Widget>[
new Container(
height: 10.0,
- child: const Semantics(label: 'child1')
+ child: const Semantics(label: 'child1', textDirection: TextDirection.ltr)
),
new Container(
height: 10.0,
child: const IgnorePointer(
ignoring: false,
- child: const Semantics(label: 'child2')
+ child: const Semantics(label: 'child2', textDirection: TextDirection.ltr)
)
),
],
@@ -103,11 +105,13 @@
new TestSemantics.rootChild(
id: 3,
label: 'child1',
+ textDirection: TextDirection.ltr,
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
),
new TestSemantics.rootChild(
id: 2,
label: 'child2',
+ textDirection: TextDirection.ltr,
rect: new Rect.fromLTRB(0.0, 0.0, 800.0, 10.0),
transform: new Matrix4.translationValues(0.0, 10.0, 0.0),
),
diff --git a/packages/flutter/test/widgets/semantics_3_test.dart b/packages/flutter/test/widgets/semantics_3_test.dart
index ad7fc33..7c24528 100644
--- a/packages/flutter/test/widgets/semantics_3_test.dart
+++ b/packages/flutter/test/widgets/semantics_3_test.dart
@@ -19,6 +19,7 @@
new Container(
child: new Semantics(
label: 'test',
+ textDirection: TextDirection.ltr,
child: new Container(
child: const Semantics(
checked: true
@@ -57,7 +58,8 @@
new Container(
child: new Container(
child: const Semantics(
- label: 'test'
+ label: 'test',
+ textDirection: TextDirection.ltr,
)
)
)
@@ -76,7 +78,8 @@
checked: true,
child: new Container(
child: const Semantics(
- label: 'test'
+ label: 'test',
+ textDirection: TextDirection.ltr,
)
)
)
@@ -102,7 +105,8 @@
checked: true,
child: new Container(
child: const Semantics(
- label: 'test'
+ label: 'test',
+ textDirection: TextDirection.ltr,
)
)
)
diff --git a/packages/flutter/test/widgets/semantics_4_test.dart b/packages/flutter/test/widgets/semantics_4_test.dart
index 51cfc22..5902698 100644
--- a/packages/flutter/test/widgets/semantics_4_test.dart
+++ b/packages/flutter/test/widgets/semantics_4_test.dart
@@ -20,8 +20,9 @@
// / \ C=node with checked
// C C* *=node removed next pass
//
- await tester.pumpWidget(
- new Stack(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Stack(
fit: StackFit.expand,
children: <Widget>[
const Semantics(
@@ -43,7 +44,7 @@
),
],
),
- );
+ ));
expect(semantics, hasSemantics(
new TestSemantics.root(
@@ -79,8 +80,9 @@
// L* LC C=node with checked
// *=node removed next pass
//
- await tester.pumpWidget(
- new Stack(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Stack(
fit: StackFit.expand,
children: <Widget>[
const Semantics(
@@ -100,7 +102,7 @@
),
],
),
- );
+ ));
expect(semantics, hasSemantics(
new TestSemantics.root(
@@ -124,8 +126,9 @@
// OLC L=node with label
// C=node with checked
//
- await tester.pumpWidget(
- new Stack(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Stack(
fit: StackFit.expand,
children: <Widget>[
const Semantics(),
@@ -143,7 +146,7 @@
),
],
),
- );
+ ));
expect(semantics, hasSemantics(
new TestSemantics.root(
diff --git a/packages/flutter/test/widgets/semantics_5_test.dart b/packages/flutter/test/widgets/semantics_5_test.dart
index 9732080..7ff598f 100644
--- a/packages/flutter/test/widgets/semantics_5_test.dart
+++ b/packages/flutter/test/widgets/semantics_5_test.dart
@@ -25,6 +25,7 @@
),
const Semantics(
label: 'label', // (force a fork)
+ textDirection: TextDirection.ltr,
),
]
)
diff --git a/packages/flutter/test/widgets/semantics_7_test.dart b/packages/flutter/test/widgets/semantics_7_test.dart
index f9c5b72..e5b8377 100644
--- a/packages/flutter/test/widgets/semantics_7_test.dart
+++ b/packages/flutter/test/widgets/semantics_7_test.dart
@@ -18,34 +18,37 @@
label = '1';
await tester.pumpWidget(
- new Stack(
- fit: StackFit.expand,
- children: <Widget>[
- new MergeSemantics(
- child: new Semantics(
- checked: true,
- container: true,
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Stack(
+ fit: StackFit.expand,
+ children: <Widget>[
+ new MergeSemantics(
child: new Semantics(
+ checked: true,
container: true,
- label: label,
- )
- )
- ),
- new MergeSemantics(
- child: new Stack(
- fit: StackFit.expand,
- children: <Widget>[
- const Semantics(
- checked: true,
- ),
- new Semantics(
+ child: new Semantics(
+ container: true,
label: label,
),
- ]
- )
- ),
- ]
- )
+ ),
+ ),
+ new MergeSemantics(
+ child: new Stack(
+ fit: StackFit.expand,
+ children: <Widget>[
+ const Semantics(
+ checked: true,
+ ),
+ new Semantics(
+ label: label,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
);
expect(semantics, hasSemantics(
@@ -71,34 +74,37 @@
label = '2';
await tester.pumpWidget(
- new Stack(
- fit: StackFit.expand,
- children: <Widget>[
- new MergeSemantics(
- child: new Semantics(
- checked: true,
- container: true,
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Stack(
+ fit: StackFit.expand,
+ children: <Widget>[
+ new MergeSemantics(
child: new Semantics(
+ checked: true,
container: true,
- label: label,
- )
- )
- ),
- new MergeSemantics(
- child: new Stack(
- fit: StackFit.expand,
- children: <Widget>[
- const Semantics(
- checked: true,
- ),
- new Semantics(
+ child: new Semantics(
+ container: true,
label: label,
- )
- ]
- )
- ),
- ]
- )
+ ),
+ ),
+ ),
+ new MergeSemantics(
+ child: new Stack(
+ fit: StackFit.expand,
+ children: <Widget>[
+ const Semantics(
+ checked: true,
+ ),
+ new Semantics(
+ label: label,
+ ),
+ ],
+ ),
+ ),
+ ],
+ ),
+ ),
);
expect(semantics, hasSemantics(
diff --git a/packages/flutter/test/widgets/semantics_8_test.dart b/packages/flutter/test/widgets/semantics_8_test.dart
index 9d9ed4f..f7fa920 100644
--- a/packages/flutter/test/widgets/semantics_8_test.dart
+++ b/packages/flutter/test/widgets/semantics_8_test.dart
@@ -23,10 +23,11 @@
child: new Stack(
children: <Widget>[
const Semantics(
- checked: true
+ checked: true,
),
const Semantics(
- label: 'label'
+ label: 'label',
+ textDirection: TextDirection.ltr,
)
]
)
@@ -39,6 +40,7 @@
new TestSemantics.root(
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: 'label',
+ textDirection: TextDirection.ltr,
)
));
@@ -52,7 +54,8 @@
child: new Stack(
children: <Widget>[
const Semantics(
- label: 'label'
+ label: 'label',
+ textDirection: TextDirection.ltr,
),
const Semantics(
checked: true
@@ -68,6 +71,7 @@
new TestSemantics.root(
flags: SemanticsFlags.hasCheckedState.index | SemanticsFlags.isChecked.index,
label: 'label',
+ textDirection: TextDirection.ltr,
)
));
diff --git a/packages/flutter/test/widgets/semantics_9_test.dart b/packages/flutter/test/widgets/semantics_9_test.dart
index 522b80a..cbe0db7 100644
--- a/packages/flutter/test/widgets/semantics_9_test.dart
+++ b/packages/flutter/test/widgets/semantics_9_test.dart
@@ -18,11 +18,13 @@
children: <Widget>[
new Semantics(
label: 'layer#1',
+ textDirection: TextDirection.ltr,
child: new Container(),
),
const BlockSemantics(),
new Semantics(
label: 'layer#2',
+ textDirection: TextDirection.ltr,
child: new Container(),
),
],
@@ -34,6 +36,7 @@
children: <Widget>[
new Semantics(
label: 'layer#1',
+ textDirection: TextDirection.ltr,
child: new Container(),
),
],
@@ -47,7 +50,7 @@
testWidgets('does not hides semantic nodes of siblings outside the current semantic boundary', (WidgetTester tester) async {
final SemanticsTester semantics = new SemanticsTester(tester);
- await tester.pumpWidget(new Stack(
+ await tester.pumpWidget(new Directionality(textDirection: TextDirection.ltr, child: new Stack(
children: <Widget>[
new Semantics(
label: '#1',
@@ -84,7 +87,7 @@
child: new Container(),
),
],
- ));
+ )));
expect(semantics, includesNodeWith(label: '#1'));
expect(semantics, includesNodeWith(label: '#2'));
@@ -101,7 +104,7 @@
final SemanticsTester semantics = new SemanticsTester(tester);
final GlobalKey stackKey = new GlobalKey();
- await tester.pumpWidget(new Stack(
+ await tester.pumpWidget(new Directionality(textDirection: TextDirection.ltr, child: new Stack(
key: stackKey,
children: <Widget>[
new Semantics(
@@ -119,7 +122,7 @@
child: new Container(),
),
],
- ));
+ )));
expect(semantics, isNot(includesNodeWith(label: 'NOT#1')));
expect(semantics, includesNodeWith(label: '#2.1'));
diff --git a/packages/flutter/test/widgets/semantics_debugger_test.dart b/packages/flutter/test/widgets/semantics_debugger_test.dart
index 67ddbe5..2ee4798 100644
--- a/packages/flutter/test/widgets/semantics_debugger_test.dart
+++ b/packages/flutter/test/widgets/semantics_debugger_test.dart
@@ -4,10 +4,12 @@
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
+import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
testWidgets('SemanticsDebugger smoke test', (WidgetTester tester) async {
+
// This is a smoketest to verify that adding a debugger doesn't crash.
await tester.pumpWidget(
new Stack(
@@ -18,6 +20,7 @@
),
const Semantics(
label: 'label',
+ textDirection: TextDirection.ltr,
),
],
),
@@ -33,6 +36,7 @@
),
const Semantics(
label: 'label',
+ textDirection: TextDirection.ltr,
),
],
),
@@ -50,14 +54,14 @@
new SemanticsDebugger(
child: new Stack(
children: <Widget>[
- const Semantics(label: 'label1'),
+ const Semantics(label: 'label1', textDirection: TextDirection.ltr),
new Positioned(
key: key,
left: 0.0,
top: 0.0,
width: 100.0,
height: 100.0,
- child: const Semantics(label: 'label2'),
+ child: const Semantics(label: 'label2', textDirection: TextDirection.ltr),
),
],
),
@@ -68,7 +72,7 @@
new SemanticsDebugger(
child: new Stack(
children: <Widget>[
- const Semantics(label: 'label1'),
+ const Semantics(label: 'label1', textDirection: TextDirection.ltr),
new Semantics(
container: true,
child: new Stack(
@@ -79,9 +83,9 @@
top: 0.0,
width: 100.0,
height: 100.0,
- child: const Semantics(label: 'label2'),
+ child: const Semantics(label: 'label2', textDirection: TextDirection.ltr),
),
- const Semantics(label: 'label3'),
+ const Semantics(label: 'label3', textDirection: TextDirection.ltr),
],
),
),
@@ -94,7 +98,7 @@
new SemanticsDebugger(
child: new Stack(
children: <Widget>[
- const Semantics(label: 'label1'),
+ const Semantics(label: 'label1', textDirection: TextDirection.ltr),
new Semantics(
container: true,
child: new Stack(
@@ -105,9 +109,9 @@
top: 0.0,
width: 100.0,
height: 100.0,
- child: const Semantics(label: 'label2')),
- const Semantics(label: 'label3'),
- const Semantics(label: 'label4'),
+ child: const Semantics(label: 'label2', textDirection: TextDirection.ltr)),
+ const Semantics(label: 'label3', textDirection: TextDirection.ltr),
+ const Semantics(label: 'label4', textDirection: TextDirection.ltr),
],
),
),
@@ -158,6 +162,47 @@
log.clear();
});
+ testWidgets('SemanticsDebugger interaction test - negative',
+ (WidgetTester tester) async {
+ final List<String> log = <String>[];
+
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new SemanticsDebugger(
+ child: new Material(
+ child: new ListView(
+ children: <Widget>[
+ new RaisedButton(
+ onPressed: () {
+ log.add('top');
+ },
+ child: const Text('TOP', textDirection: TextDirection.ltr),
+ ),
+ new ExcludeSemantics(
+ child: new RaisedButton(
+ onPressed: () {
+ log.add('bottom');
+ },
+ child: const Text('BOTTOM', textDirection: TextDirection.ltr),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ );
+
+ await tester.tap(find.text('TOP'));
+ expect(log, equals(<String>['top']));
+ log.clear();
+
+ await tester.tap(find.text('BOTTOM'));
+ expect(log, equals(<String>[]));
+ log.clear();
+ });
+
testWidgets('SemanticsDebugger scroll test', (WidgetTester tester) async {
final Key childKey = new UniqueKey();
@@ -211,7 +256,7 @@
expect(didLongPress, isFalse);
didLongPress = true;
},
- child: const Text('target'),
+ child: const Text('target', textDirection: TextDirection.ltr),
),
),
);
diff --git a/packages/flutter/test/widgets/semantics_test.dart b/packages/flutter/test/widgets/semantics_test.dart
index e4d25f2..fcadf8a 100644
--- a/packages/flutter/test/widgets/semantics_test.dart
+++ b/packages/flutter/test/widgets/semantics_test.dart
@@ -14,12 +14,14 @@
final TestSemantics expectedSemantics = new TestSemantics.root(
label: 'test1',
+ textDirection: TextDirection.ltr,
);
await tester.pumpWidget(
new Container(
child: new Semantics(
label: 'test1',
+ textDirection: TextDirection.ltr,
child: new Container()
)
)
@@ -43,8 +45,9 @@
final SemanticsTester semantics = new SemanticsTester(tester);
final GlobalKey key = new GlobalKey();
- await tester.pumpWidget(
- new Container(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Container(
child: new Semantics(
label: 'test1',
child: new Semantics(
@@ -55,7 +58,7 @@
)
)
)
- );
+ ));
expect(semantics, hasSemantics(
new TestSemantics.root(
@@ -70,8 +73,9 @@
)
));
- await tester.pumpWidget(
- new Container(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Container(
child: new Semantics(
label: 'test1',
child: new Semantics(
@@ -86,7 +90,7 @@
)
)
)
- );
+ ));
expect(semantics, hasSemantics(
new TestSemantics.root(
@@ -110,4 +114,90 @@
semantics.dispose();
});
+
+ testWidgets('Semantics and Directionality - RTL', (WidgetTester tester) async {
+ final SemanticsTester semantics = new SemanticsTester(tester);
+
+ final TestSemantics expectedSemantics = new TestSemantics.root(
+ label: 'test1',
+ textDirection: TextDirection.rtl,
+ );
+
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.rtl,
+ child: new Semantics(
+ label: 'test1',
+ child: new Container(),
+ ),
+ ),
+ );
+
+ expect(semantics, hasSemantics(expectedSemantics));
+ });
+
+ testWidgets('Semantics and Directionality - LTR', (WidgetTester tester) async {
+ final SemanticsTester semantics = new SemanticsTester(tester);
+
+ final TestSemantics expectedSemantics = new TestSemantics.root(
+ label: 'test1',
+ textDirection: TextDirection.ltr,
+ );
+
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Semantics(
+ label: 'test1',
+ child: new Container(),
+ ),
+ ),
+ );
+
+ expect(semantics, hasSemantics(expectedSemantics));
+ });
+
+ testWidgets('Semantics and Directionality - overriding RTL with LTR', (WidgetTester tester) async {
+ final SemanticsTester semantics = new SemanticsTester(tester);
+
+ final TestSemantics expectedSemantics = new TestSemantics.root(
+ label: 'test1',
+ textDirection: TextDirection.ltr,
+ );
+
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.rtl,
+ child: new Semantics(
+ label: 'test1',
+ textDirection: TextDirection.ltr,
+ child: new Container(),
+ ),
+ ),
+ );
+
+ expect(semantics, hasSemantics(expectedSemantics));
+ });
+
+ testWidgets('Semantics and Directionality - overriding LTR with RTL', (WidgetTester tester) async {
+ final SemanticsTester semantics = new SemanticsTester(tester);
+
+ final TestSemantics expectedSemantics = new TestSemantics.root(
+ label: 'test1',
+ textDirection: TextDirection.rtl,
+ );
+
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Semantics(
+ label: 'test1',
+ textDirection: TextDirection.rtl,
+ child: new Container(),
+ ),
+ ),
+ );
+
+ expect(semantics, hasSemantics(expectedSemantics));
+ });
}
diff --git a/packages/flutter/test/widgets/semantics_tester.dart b/packages/flutter/test/widgets/semantics_tester.dart
index f1bb0ca..f2fb679 100644
--- a/packages/flutter/test/widgets/semantics_tester.dart
+++ b/packages/flutter/test/widgets/semantics_tester.dart
@@ -9,6 +9,8 @@
export 'package:flutter/rendering.dart' show SemanticsData;
+const String _matcherHelp = 'Try dumping the semantics with debugDumpSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest) from the package:flutter/rendering.dart library to see what the semantics tree looks like.';
+
/// Test semantics data that is compared against real semantics tree.
///
/// Useful with [hasSemantics] and [SemanticsTester] to test the contents of the
@@ -33,6 +35,7 @@
this.flags: 0,
this.actions: 0,
this.label: '',
+ this.textDirection,
this.rect,
this.transform,
this.children: const <TestSemantics>[],
@@ -49,6 +52,7 @@
this.flags: 0,
this.actions: 0,
this.label: '',
+ this.textDirection,
this.transform,
this.children: const <TestSemantics>[],
Iterable<SemanticsTag> tags,
@@ -73,6 +77,7 @@
this.flags: 0,
this.actions: 0,
this.label: '',
+ this.textDirection,
this.rect,
Matrix4 transform,
this.children: const <TestSemantics>[],
@@ -98,6 +103,13 @@
/// A textual description of this node.
final String label;
+ /// The reading direction of the [label].
+ ///
+ /// Even if this is not set, the [hasSemantics] matcher will verify that if a
+ /// label is present on the [SemanticsNode], a [SemanticsNode.textDirection]
+ /// is also set.
+ final TextDirection textDirection;
+
/// The bounding box for this node in its coordinate system.
///
/// Convenient values are available:
@@ -142,18 +154,34 @@
bool _matches(SemanticsNode node, Map<dynamic, dynamic> matchState, { bool ignoreRect: false, bool ignoreTransform: false }) {
final SemanticsData nodeData = node.getSemanticsData();
- if (node == null || id != node.id
- || flags != nodeData.flags
- || actions != nodeData.actions
- || label != nodeData.label
- || !setEquals(tags, nodeData.tags)
- || (!ignoreRect && rect != nodeData.rect)
- || (!ignoreTransform && transform != nodeData.transform)
- || children.length != (node.mergeAllDescendantsIntoThisNode ? 0 : node.childrenCount)) {
- matchState[TestSemantics] = this;
- matchState[SemanticsNode] = node;
+
+ bool fail(String message) {
+ matchState[TestSemantics] = 'message\n$_matcherHelp';
return false;
}
+
+ if (node == null)
+ return fail('could not find node with id $id.');
+ if (id != node.id)
+ return fail('expected node id $id but found id ${node.id}.');
+ if (flags != nodeData.flags)
+ return fail('expected node id $id to have flags $flags but found flags ${nodeData.flags}.');
+ if (actions != nodeData.actions)
+ return fail('expected node id $id to have actions $actions but found actions ${nodeData.actions}.');
+ if (label != nodeData.label)
+ return fail('expected node id $id to have label "$label" but found label "${nodeData.label}".');
+ if (textDirection != null && textDirection != nodeData.textDirection)
+ return fail('expected node id $id to have textDirection "$textDirection" but found "${nodeData.textDirection}".');
+ if (nodeData.label != '' && nodeData.textDirection == null)
+ return fail('expected node id $id, which has a label, to have a textDirection, but it did not.');
+ if (!ignoreRect && rect != nodeData.rect)
+ return fail('expected node id $id to have rect $rect but found rect ${nodeData.rect}.');
+ if (!ignoreTransform && transform != nodeData.transform)
+ return fail('expected node id $id to have transform $transform but found transform:\n${nodeData.transform}.');
+ final int childrenCount = node.mergeAllDescendantsIntoThisNode ? 0 : node.childrenCount;
+ if (children.length != childrenCount)
+ return fail('expected node id $id to have ${children.length} child${ children.length == 1 ? "" : "ren" } but found $childrenCount.');
+
if (children.isEmpty)
return true;
bool result = true;
@@ -168,6 +196,11 @@
});
return result;
}
+
+ @override
+ String toString() {
+ return 'node $id, flags=$flags, actions=$actions, label="$label", textDirection=$textDirection, rect=$rect, transform=$transform, ${children.length} child${ children.length == 1 ? "" : "ren" }';
+ }
}
/// Ensures that the given widget tester has a semantics tree to test.
@@ -196,11 +229,9 @@
}
@override
- String toString() => 'SemanticsTester';
+ String toString() => 'SemanticsTester for ${tester.binding.pipelineOwner.semanticsOwner.rootSemanticsNode}';
}
-const String _matcherHelp = 'Try dumping the semantics with debugDumpSemanticsTree(DebugSemanticsDumpOrder.inverseHitTest) from the package:flutter/rendering.dart library to see what the semantics tree looks like.';
-
class _HasSemantics extends Matcher {
const _HasSemantics(this._semantics, { this.ignoreRect: false, this.ignoreTransform: false }) : assert(_semantics != null), assert(ignoreRect != null), assert(ignoreTransform != null);
@@ -215,32 +246,12 @@
@override
Description describe(Description description) {
- return description.add('semantics node id ${_semantics.id}');
+ return description.add('semantics node matching: $_semantics');
}
@override
Description describeMismatch(dynamic item, Description mismatchDescription, Map<dynamic, dynamic> matchState, bool verbose) {
- final TestSemantics testNode = matchState[TestSemantics];
- final SemanticsNode node = matchState[SemanticsNode];
- if (node == null)
- return mismatchDescription.add('could not find node with id ${testNode.id}.\n$_matcherHelp');
- if (testNode.id != node.id)
- return mismatchDescription.add('expected node id ${testNode.id} but found id ${node.id}.\n$_matcherHelp');
- final SemanticsData data = node.getSemanticsData();
- if (testNode.flags != data.flags)
- return mismatchDescription.add('expected node id ${testNode.id} to have flags ${testNode.flags} but found flags ${data.flags}.\n$_matcherHelp');
- if (testNode.actions != data.actions)
- return mismatchDescription.add('expected node id ${testNode.id} to have actions ${testNode.actions} but found actions ${data.actions}.\n$_matcherHelp');
- if (testNode.label != data.label)
- return mismatchDescription.add('expected node id ${testNode.id} to have label "${testNode.label}" but found label "${data.label}".\n$_matcherHelp');
- if (!ignoreRect && testNode.rect != data.rect)
- return mismatchDescription.add('expected node id ${testNode.id} to have rect ${testNode.rect} but found rect ${data.rect}.\n$_matcherHelp');
- if (!ignoreTransform && testNode.transform != data.transform)
- return mismatchDescription.add('expected node id ${testNode.id} to have transform ${testNode.transform} but found transform:.\n${data.transform}.\n$_matcherHelp');
- final int childrenCount = node.mergeAllDescendantsIntoThisNode ? 0 : node.childrenCount;
- if (testNode.children.length != childrenCount)
- return mismatchDescription.add('expected node id ${testNode.id} to have ${testNode.children.length} children but found $childrenCount.\n$_matcherHelp');
- return mismatchDescription;
+ return mismatchDescription.add(matchState[TestSemantics]);
}
}
@@ -253,10 +264,12 @@
class _IncludesNodeWith extends Matcher {
const _IncludesNodeWith({
this.label,
+ this.textDirection,
this.actions,
}) : assert(label != null || actions != null);
final String label;
+ final TextDirection textDirection;
final List<SemanticsAction> actions;
@override
@@ -279,6 +292,8 @@
bool checkNode(SemanticsNode node) {
if (label != null && node.label != label)
return false;
+ if (textDirection != null && node.textDirection != textDirection)
+ return false;
if (actions != null) {
final int expectedActions = actions.fold(0, (int value, SemanticsAction action) => value | action.index);
final int actualActions = node.getSemanticsData().actions;
@@ -302,17 +317,30 @@
String string = '';
if (label != null) {
string += 'label "$label"';
+ if (textDirection != null)
+ string += ' (${describeEnum(textDirection)})';
+ if (actions != null)
+ string += ' and ';
+ } else if (textDirection != null) {
+ string += 'direction ${describeEnum(textDirection)}';
if (actions != null)
string += ' and ';
}
if (actions != null) {
- string += ' actions "${actions.join(', ')}"';
+ string += 'actions "${actions.join(', ')}"';
}
return string;
}
}
-/// Asserts that a node in the semantics tree of [SemanticsTester] has [label] and [actions].
+/// Asserts that a node in the semantics tree of [SemanticsTester] has `label`,
+/// `textDirection`, and `actions`.
///
-/// If `null` is provided for either argument it will match against any value.
-Matcher includesNodeWith({ String label, List<SemanticsAction> actions }) => new _IncludesNodeWith(label: label, actions: actions);
+/// If null is provided for an argument, it will match against any value.
+Matcher includesNodeWith({ String label, TextDirection textDirection, List<SemanticsAction> actions }) {
+ return new _IncludesNodeWith(
+ label: label,
+ textDirection: textDirection,
+ actions: actions,
+ );
+}
diff --git a/packages/flutter/test/widgets/set_state_1_test.dart b/packages/flutter/test/widgets/set_state_1_test.dart
index 5057390..d9ccee4 100644
--- a/packages/flutter/test/widgets/set_state_1_test.dart
+++ b/packages/flutter/test/widgets/set_state_1_test.dart
@@ -15,7 +15,7 @@
Widget build(BuildContext context) {
return new Listener(
onPointerDown: _handlePointerDown,
- child: const Text('INSIDE')
+ child: const Text('INSIDE', textDirection: TextDirection.ltr),
);
}
@@ -38,7 +38,7 @@
Widget build(BuildContext context) {
return new Listener(
onPointerDown: _handlePointerDown,
- child: widget.child
+ child: widget.child,
);
}
diff --git a/packages/flutter/test/widgets/set_state_2_test.dart b/packages/flutter/test/widgets/set_state_2_test.dart
index 608858e..f2570bb 100644
--- a/packages/flutter/test/widgets/set_state_2_test.dart
+++ b/packages/flutter/test/widgets/set_state_2_test.dart
@@ -11,7 +11,7 @@
final Builder inner = new Builder(
builder: (BuildContext context) {
log.add('inner');
- return const Text('inner');
+ return const Text('inner', textDirection: TextDirection.ltr);
}
);
int value = 0;
diff --git a/packages/flutter/test/widgets/set_state_3_test.dart b/packages/flutter/test/widgets/set_state_3_test.dart
index be2bfef..53a2425 100644
--- a/packages/flutter/test/widgets/set_state_3_test.dart
+++ b/packages/flutter/test/widgets/set_state_3_test.dart
@@ -47,7 +47,7 @@
class LeafState extends State<Leaf> {
@override
- Widget build(BuildContext context) => const Text("leaf");
+ Widget build(BuildContext context) => const Text('leaf', textDirection: TextDirection.ltr);
}
void main() {
diff --git a/packages/flutter/test/widgets/set_state_4_test.dart b/packages/flutter/test/widgets/set_state_4_test.dart
index c74afb4..0da0619 100644
--- a/packages/flutter/test/widgets/set_state_4_test.dart
+++ b/packages/flutter/test/widgets/set_state_4_test.dart
@@ -16,7 +16,7 @@
void test2() { setState(() async { }); }
@override
- Widget build(BuildContext context) => const Text('test');
+ Widget build(BuildContext context) => const Text('test', textDirection: TextDirection.ltr);
}
void main() {
diff --git a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart
index a2990b3..a4dd0c9 100644
--- a/packages/flutter/test/widgets/sliver_fill_viewport_test.dart
+++ b/packages/flutter/test/widgets/sliver_fill_viewport_test.dart
@@ -8,7 +8,7 @@
void main() {
testWidgets('SliverFillRemaining control test', (WidgetTester tester) async {
final List<Widget> children = new List<Widget>.generate(20, (int i) {
- return new Container(child: new Text('$i'));
+ return new Container(child: new Text('$i', textDirection: TextDirection.ltr));
});
await tester.pumpWidget(
@@ -107,6 +107,11 @@
' │ parentData: <none> (can use size)\n'
' │ constraints: BoxConstraints(w=800.0, h=600.0)\n'
' │ size: Size(800.0, 600.0)\n'
+ ' │ textAlign: start\n'
+ ' │ textDirection: ltr\n'
+ ' │ softWrap: wrapping at box width\n'
+ ' │ overflow: clip\n'
+ ' │ maxLines: unlimited\n'
' ╘═╦══ text ═══\n'
' ║ TextSpan:\n'
' ║ <all styles inherited>\n'
diff --git a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
index b2bad6a..943ba10 100644
--- a/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
+++ b/packages/flutter/test/widgets/sliver_prototype_item_extent_test.dart
@@ -16,7 +16,7 @@
width: width,
height: height,
alignment: FractionalOffset.center,
- child: new Text('Item $item'),
+ child: new Text('Item $item', textDirection: TextDirection.ltr),
);
}
}
diff --git a/packages/flutter/test/widgets/sliver_semantics_test.dart b/packages/flutter/test/widgets/sliver_semantics_test.dart
index 2057e82..846e53c 100644
--- a/packages/flutter/test/widgets/sliver_semantics_test.dart
+++ b/packages/flutter/test/widgets/sliver_semantics_test.dart
@@ -23,58 +23,60 @@
child: new Text('Item $i'),
);
});
- await tester.pumpWidget(new Directionality(
- textDirection: TextDirection.ltr,
- child: new MediaQuery(
- data: const MediaQueryData(),
- child: new CustomScrollView(
- controller: scrollController,
- slivers: <Widget>[
- const SliverAppBar(
- pinned: true,
- expandedHeight: appBarExpandedHeight,
- title: const Text('Semantics Test with Slivers'),
- ),
- new SliverList(
- delegate: new SliverChildListDelegate(listChildren),
- ),
- ],
+ await tester.pumpWidget(
+ new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new MediaQuery(
+ data: const MediaQueryData(),
+ child: new CustomScrollView(
+ controller: scrollController,
+ slivers: <Widget>[
+ const SliverAppBar(
+ pinned: true,
+ expandedHeight: appBarExpandedHeight,
+ title: const Text('Semantics Test with Slivers'),
+ ),
+ new SliverList(
+ delegate: new SliverChildListDelegate(listChildren),
+ ),
+ ],
+ ),
),
),
- ));
+ );
// AppBar is child of node with semantic scroll actions.
expect(semantics, hasSemantics(
- new TestSemantics.root(
- children: <TestSemantics>[
- new TestSemantics.rootChild(
- id: 1,
- tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
- children: <TestSemantics>[
- new TestSemantics(
- id: 5,
- actions: SemanticsAction.scrollUp.index,
- children: <TestSemantics>[
- new TestSemantics(
- id: 2,
- label: 'Item 0',
- ),
- new TestSemantics(
- id: 3,
- label: 'Item 1',
- ),
- new TestSemantics(
- id: 4,
- label: 'Semantics Test with Slivers',
- ),
- ],
- ),
- ],
- )
- ],
- ),
- ignoreRect: true,
- ignoreTransform: true,
+ new TestSemantics.root(
+ children: <TestSemantics>[
+ new TestSemantics.rootChild(
+ id: 1,
+ tags: <SemanticsTag>[RenderSemanticsGestureHandler.useTwoPaneSemantics],
+ children: <TestSemantics>[
+ new TestSemantics(
+ id: 5,
+ actions: SemanticsAction.scrollUp.index,
+ children: <TestSemantics>[
+ new TestSemantics(
+ id: 2,
+ label: 'Item 0',
+ ),
+ new TestSemantics(
+ id: 3,
+ label: 'Item 1',
+ ),
+ new TestSemantics(
+ id: 4,
+ label: 'Semantics Test with Slivers',
+ ),
+ ],
+ ),
+ ],
+ )
+ ],
+ ),
+ ignoreRect: true,
+ ignoreTransform: true,
));
// Scroll down far enough to reach the pinned state of the app bar.
@@ -177,7 +179,7 @@
return new SliverToBoxAdapter(
child: new Container(
height: containerHeight,
- child: new Text('Item $i'),
+ child: new Text('Item $i', textDirection: TextDirection.ltr),
),
);
});
@@ -210,10 +212,12 @@
new TestSemantics(
id: 10,
label: 'Item 2',
+ textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 11,
label: 'Item 1',
+ textDirection: TextDirection.ltr,
),
],
),
@@ -261,22 +265,27 @@
new TestSemantics(
id: 14,
label: 'Item 4',
+ textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 15,
label: 'Item 3',
+ textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 16,
label: 'Item 2',
+ textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 17,
label: 'Item 1',
+ textDirection: TextDirection.ltr,
),
new TestSemantics(
id: 18,
label: 'Item 0',
+ textDirection: TextDirection.ltr,
),
],
),
@@ -297,7 +306,7 @@
final List<Widget> listChildren = new List<Widget>.generate(10, (int i) {
return new Container(
height: 200.0,
- child: new Text('Item $i'),
+ child: new Text('Item $i', textDirection: TextDirection.ltr),
);
});
final ScrollController controller = new ScrollController(initialScrollOffset: 280.0);
@@ -380,7 +389,7 @@
return new SliverToBoxAdapter(
child: new Container(
height: 200.0,
- child: new Text('Item $i'),
+ child: new Text('Item $i', textDirection: TextDirection.ltr),
),
);
});
@@ -458,7 +467,7 @@
final List<Widget> listChildren = new List<Widget>.generate(10, (int i) {
return new Container(
height: 200.0,
- child: new Text('Item $i'),
+ child: new Text('Item $i', textDirection: TextDirection.ltr),
);
});
final ScrollController controller = new ScrollController(initialScrollOffset: 280.0);
@@ -543,7 +552,7 @@
return new SliverToBoxAdapter(
child: new Container(
height: 200.0,
- child: new Text('Item $i'),
+ child: new Text('Item $i', textDirection: TextDirection.ltr),
),
);
});
@@ -625,13 +634,13 @@
final List<Widget> forwardChildren = new List<Widget>.generate(10, (int i) {
return new Container(
height: 200.0,
- child: new Text('Forward Item $i'),
+ child: new Text('Forward Item $i', textDirection: TextDirection.ltr),
);
});
final List<Widget> backwardChildren = new List<Widget>.generate(10, (int i) {
return new Container(
height: 200.0,
- child: new Text('Backward Item $i'),
+ child: new Text('Backward Item $i', textDirection: TextDirection.ltr),
);
});
await tester.pumpWidget(new Directionality(
@@ -652,7 +661,7 @@
pinned: true,
expandedHeight: 100.0,
flexibleSpace: const FlexibleSpaceBar(
- title: const Text('Backward app bar'),
+ title: const Text('Backward app bar', textDirection: TextDirection.ltr),
),
),
new SliverAppBar(
@@ -660,7 +669,7 @@
key: forwardAppBarKey,
expandedHeight: 100.0,
flexibleSpace: const FlexibleSpaceBar(
- title: const Text('Forward app bar'),
+ title: const Text('Forward app bar', textDirection: TextDirection.ltr),
),
),
new SliverList(
diff --git a/packages/flutter/test/widgets/slivers_block_global_key_test.dart b/packages/flutter/test/widgets/slivers_block_global_key_test.dart
index b1df7cd..696d984 100644
--- a/packages/flutter/test/widgets/slivers_block_global_key_test.dart
+++ b/packages/flutter/test/widgets/slivers_block_global_key_test.dart
@@ -19,7 +19,7 @@
_GenerationTextState() : generation = globalGeneration;
final int generation;
@override
- Widget build(BuildContext context) => new Text('${widget.value}:$generation ');
+ Widget build(BuildContext context) => new Text('${widget.value}:$generation ', textDirection: TextDirection.ltr);
}
Future<Null> test(WidgetTester tester, double offset, List<int> keys) {
diff --git a/packages/flutter/test/widgets/stack_test.dart b/packages/flutter/test/widgets/stack_test.dart
index 76181d3..31c9840 100644
--- a/packages/flutter/test/widgets/stack_test.dart
+++ b/packages/flutter/test/widgets/stack_test.dart
@@ -150,7 +150,7 @@
itemsPainted = <int>[];
final List<Widget> items = new List<Widget>.generate(itemCount, (int i) {
return new CustomPaint(
- child: new Text('$i'),
+ child: new Text('$i', textDirection: TextDirection.ltr),
painter: new TestCallbackPainter(
onPaint: () { itemsPainted.add(i); }
)
@@ -180,7 +180,7 @@
Widget buildFrame(int index) {
itemsTapped = <int>[];
final List<Widget> items = new List<Widget>.generate(itemCount, (int i) {
- return new GestureDetector(child: new Text('$i'), onTap: () { itemsTapped.add(i); });
+ return new GestureDetector(child: new Text('$i', textDirection: TextDirection.ltr), onTap: () { itemsTapped.add(i); });
});
return new Center(child: new IndexedStack(children: items, key: key, index: index));
}
diff --git a/packages/flutter/test/widgets/syncing_test.dart b/packages/flutter/test/widgets/syncing_test.dart
index 13bb2b8..033cc7c 100644
--- a/packages/flutter/test/widgets/syncing_test.dart
+++ b/packages/flutter/test/widgets/syncing_test.dart
@@ -112,8 +112,8 @@
});
testWidgets('swap instances around', (WidgetTester tester) async {
- final Widget a = const TestWidget(persistentState: 0x61, syncedState: 0x41, child: const Text('apple'));
- final Widget b = const TestWidget(persistentState: 0x62, syncedState: 0x42, child: const Text('banana'));
+ final Widget a = const TestWidget(persistentState: 0x61, syncedState: 0x41, child: const Text('apple', textDirection: TextDirection.ltr));
+ final Widget b = const TestWidget(persistentState: 0x62, syncedState: 0x42, child: const Text('banana', textDirection: TextDirection.ltr));
await tester.pumpWidget(new Column());
final GlobalKey keyA = new GlobalKey();
diff --git a/packages/flutter/test/widgets/table_test.dart b/packages/flutter/test/widgets/table_test.dart
index 4662a5c..93ea64e 100644
--- a/packages/flutter/test/widgets/table_test.dart
+++ b/packages/flutter/test/widgets/table_test.dart
@@ -20,8 +20,9 @@
void main() {
testWidgets('Table widget - control test', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -40,7 +41,7 @@
),
]
)
- );
+ ));
final RenderBox boxA = tester.renderObject(find.text('AAAAAA'));
final RenderBox boxD = tester.renderObject(find.text('D'));
final RenderBox boxG = tester.renderObject(find.text('G'));
@@ -51,8 +52,9 @@
});
testWidgets('Table widget - changing table dimensions', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -71,13 +73,14 @@
),
]
)
- );
+ ));
final RenderBox boxA1 = tester.renderObject(find.text('A'));
final RenderBox boxG1 = tester.renderObject(find.text('G'));
expect(boxA1, isNotNull);
expect(boxG1, isNotNull);
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -91,7 +94,7 @@
),
]
)
- );
+ ));
final RenderBox boxA2 = tester.renderObject(find.text('a'));
final RenderBox boxG2 = tester.renderObject(find.text('g'));
expect(boxA2, isNotNull);
@@ -101,8 +104,9 @@
});
testWidgets('Table widget - repump test', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -121,9 +125,10 @@
),
]
)
- );
- await tester.pumpWidget(
- new Table(
+ ));
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -142,7 +147,7 @@
),
]
)
- );
+ ));
final RenderBox boxA = tester.renderObject(find.text('AAA'));
final RenderBox boxD = tester.renderObject(find.text('D'));
final RenderBox boxG = tester.renderObject(find.text('G'));
@@ -153,8 +158,9 @@
});
testWidgets('Table widget - intrinsic sizing test', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: <TableRow>[
new TableRow(
@@ -174,7 +180,7 @@
),
]
)
- );
+ ));
final RenderBox boxA = tester.renderObject(find.text('AAA'));
final RenderBox boxD = tester.renderObject(find.text('D'));
final RenderBox boxG = tester.renderObject(find.text('G'));
@@ -186,8 +192,9 @@
});
testWidgets('Table widget - intrinsic sizing test, resizing', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: <TableRow>[
new TableRow(
@@ -207,9 +214,10 @@
),
]
)
- );
- await tester.pumpWidget(
- new Table(
+ ));
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: <TableRow>[
new TableRow(
@@ -229,7 +237,7 @@
),
]
)
- );
+ ));
final RenderBox boxA = tester.renderObject(find.text('A'));
final RenderBox boxD = tester.renderObject(find.text('D'));
final RenderBox boxG = tester.renderObject(find.text('G'));
@@ -241,8 +249,9 @@
});
testWidgets('Table widget - intrinsic sizing test, changing column widths', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -261,9 +270,10 @@
),
]
)
- );
- await tester.pumpWidget(
- new Table(
+ ));
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
defaultColumnWidth: const IntrinsicColumnWidth(),
children: <TableRow>[
new TableRow(
@@ -283,7 +293,7 @@
),
]
)
- );
+ ));
final RenderBox boxA = tester.renderObject(find.text('AAA'));
final RenderBox boxD = tester.renderObject(find.text('D'));
final RenderBox boxG = tester.renderObject(find.text('G'));
@@ -296,8 +306,9 @@
testWidgets('Table widget - moving test', (WidgetTester tester) async {
final List<BuildContext> contexts = <BuildContext>[];
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
key: const ValueKey<int>(1),
@@ -317,9 +328,10 @@
),
]
)
- );
- await tester.pumpWidget(
- new Table(
+ ));
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
children: <Widget>[
@@ -339,14 +351,15 @@
),
]
)
- );
+ ));
expect(contexts.length, equals(2));
expect(contexts[0], equals(contexts[1]));
});
testWidgets('Table widget - keyed rows', (WidgetTester tester) async {
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
key: const ValueKey<int>(1),
@@ -364,7 +377,7 @@
),
]
)
- );
+ ));
final TestStatefulWidgetState state11 = tester.state(find.byKey(const ValueKey<int>(11)));
final TestStatefulWidgetState state12 = tester.state(find.byKey(const ValueKey<int>(12)));
@@ -376,8 +389,9 @@
expect(state21.mounted, isTrue);
expect(state22.mounted, isTrue);
- await tester.pumpWidget(
- new Table(
+ await tester.pumpWidget(new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
children: <TableRow>[
new TableRow(
key: const ValueKey<int>(2),
@@ -388,7 +402,7 @@
),
]
)
- );
+ ));
expect(state11.mounted, isFalse);
expect(state12.mounted, isFalse);
@@ -499,27 +513,30 @@
testWidgets('Table widget diagnostics', (WidgetTester tester) async {
GlobalKey key0;
- final Table table = new Table(
+ final Widget table = new Directionality(
+ textDirection: TextDirection.ltr,
+ child: new Table(
key: key0 = new GlobalKey(),
defaultColumnWidth: const IntrinsicColumnWidth(),
children: <TableRow>[
new TableRow(
children: <Widget>[
- const Text('A'), const Text('B'), const Text('C')
- ]
+ const Text('A'), const Text('B'), const Text('C'),
+ ],
),
new TableRow(
children: <Widget>[
- const Text('D'), const Text('EEE'), const Text('F')
- ]
+ const Text('D'), const Text('EEE'), const Text('F'),
+ ],
),
new TableRow(
children: <Widget>[
- const Text('G'), const Text('H'), const Text('III')
- ]
+ const Text('G'), const Text('H'), const Text('III'),
+ ],
),
- ]
- );
+ ],
+ ),
+ );
await tester.pumpWidget(table);
final RenderObjectElement element = key0.currentContext;
expect(element, hasAGoodToStringDeep);
diff --git a/packages/flutter/test/widgets/text_test.dart b/packages/flutter/test/widgets/text_test.dart
index a58f79a..89c752a 100644
--- a/packages/flutter/test/widgets/text_test.dart
+++ b/packages/flutter/test/widgets/text_test.dart
@@ -10,7 +10,7 @@
await tester.pumpWidget(const MediaQuery(
data: const MediaQueryData(textScaleFactor: 1.5),
child: const Center(
- child: const Text('Hello')
+ child: const Text('Hello', textDirection: TextDirection.ltr)
)
));
@@ -19,7 +19,7 @@
expect(text.textScaleFactor, 1.5);
await tester.pumpWidget(const Center(
- child: const Text('Hello')
+ child: const Text('Hello', textDirection: TextDirection.ltr)
));
text = tester.firstWidget(find.byType(RichText));
@@ -27,7 +27,7 @@
expect(text.textScaleFactor, 1.0);
await tester.pumpWidget(const Center(
- child: const Text('Hello', textScaleFactor: 3.0)
+ child: const Text('Hello', textScaleFactor: 3.0, textDirection: TextDirection.ltr)
));
text = tester.firstWidget(find.byType(RichText));
diff --git a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart
index 7ebc405..3ff890b 100644
--- a/packages/flutter/test/widgets/tracking_scroll_controller_test.dart
+++ b/packages/flutter/test/widgets/tracking_scroll_controller_test.dart
@@ -17,13 +17,15 @@
child: new PageView.builder(
itemBuilder: (BuildContext context, int index) {
return new ListView(
- controller: controller,
- children: new List<Widget>.generate(
- 10,
- (int i) => new Container(
- height: listItemHeight,
- child: new Text("Page$index-Item$i")),
- ).toList());
+ controller: controller,
+ children: new List<Widget>.generate(
+ 10,
+ (int i) => new Container(
+ height: listItemHeight,
+ child: new Text('Page$index-Item$i'),
+ ),
+ ).toList(),
+ );
},
),
),
@@ -37,8 +39,7 @@
controller.jumpTo(listItemHeight + 10);
await (tester.pumpAndSettle());
- await tester.fling(
- find.text('Page0-Item1'), const Offset(-100.0, 0.0), 10000.0);
+ await tester.fling(find.text('Page0-Item1'), const Offset(-100.0, 0.0), 10000.0);
await (tester.pumpAndSettle());
expect(find.text('Page0-Item1'), findsNothing);
@@ -46,8 +47,7 @@
expect(find.text('Page2-Item0'), findsNothing);
expect(find.text('Page2-Item1'), findsNothing);
- await tester.fling(
- find.text('Page1-Item1'), const Offset(-100.0, 0.0), 10000.0);
+ await tester.fling(find.text('Page1-Item1'), const Offset(-100.0, 0.0), 10000.0);
await (tester.pumpAndSettle());
expect(find.text('Page0-Item1'), findsNothing);
@@ -55,7 +55,7 @@
expect(find.text('Page2-Item0'), findsNothing);
expect(find.text('Page2-Item1'), findsOneWidget);
- await tester.pumpWidget(const Text("Another page"));
+ await tester.pumpWidget(const Text('Another page', textDirection: TextDirection.ltr));
expect(controller.initialScrollOffset, 0.0);
});
diff --git a/packages/flutter/test/widgets/transitions_test.dart b/packages/flutter/test/widgets/transitions_test.dart
index e1e410d..875d562 100644
--- a/packages/flutter/test/widgets/transitions_test.dart
+++ b/packages/flutter/test/widgets/transitions_test.dart
@@ -10,7 +10,7 @@
testWidgets('toString control test', (WidgetTester tester) async {
final Widget widget = const FadeTransition(
opacity: kAlwaysCompleteAnimation,
- child: const Text('Ready'),
+ child: const Text('Ready', textDirection: TextDirection.ltr),
);
expect(widget.toString, isNot(throwsException));
});
@@ -57,7 +57,7 @@
final DecoratedBoxTransition transitionUnderTest =
new DecoratedBoxTransition(
decoration: decorationTween.animate(controller),
- child: const Text("Doesn't matter"),
+ child: const Text('Doesn\'t matter', textDirection: TextDirection.ltr),
);
await tester.pumpWidget(transitionUnderTest);
@@ -109,7 +109,7 @@
new DecoratedBoxTransition(
decoration: curvedDecorationAnimation,
position: DecorationPosition.foreground,
- child: const Text("Doesn't matter"),
+ child: const Text('Doesn\'t matter', textDirection: TextDirection.ltr),
);
await tester.pumpWidget(transitionUnderTest);
diff --git a/packages/flutter/test/widgets/widget_inspector_test.dart b/packages/flutter/test/widgets/widget_inspector_test.dart
index e10deba..830772f 100644
--- a/packages/flutter/test/widgets/widget_inspector_test.dart
+++ b/packages/flutter/test/widgets/widget_inspector_test.dart
@@ -13,9 +13,9 @@
await tester.pumpWidget(
new Stack(
children: <Widget>[
- const Text('a'),
- const Text('b'),
- const Text('c'),
+ const Text('a', textDirection: TextDirection.ltr),
+ const Text('b', textDirection: TextDirection.ltr),
+ const Text('c', textDirection: TextDirection.ltr),
],
),
);
@@ -25,9 +25,9 @@
selectButtonBuilder: null,
child: new Stack(
children: <Widget>[
- const Text('a'),
- const Text('b'),
- const Text('c'),
+ const Text('a', textDirection: TextDirection.ltr),
+ const Text('b', textDirection: TextDirection.ltr),
+ const Text('c', textDirection: TextDirection.ltr),
],
),
),
@@ -179,7 +179,7 @@
expect(didLongPress, isFalse);
didLongPress = true;
},
- child: const Text('target'),
+ child: const Text('target', textDirection: TextDirection.ltr),
),
),
);
@@ -202,9 +202,9 @@
top: 0.0,
width: width,
height: 100.0,
- child: new Text(width.toString()),
+ child: new Text(width.toString(), textDirection: TextDirection.ltr),
),
- ]
+ ],
);
}
await tester.pumpWidget(
diff --git a/packages/flutter/test/widgets/wrap_test.dart b/packages/flutter/test/widgets/wrap_test.dart
index 9440522..fb6ec9f 100644
--- a/packages/flutter/test/widgets/wrap_test.dart
+++ b/packages/flutter/test/widgets/wrap_test.dart
@@ -817,7 +817,7 @@
child: new Wrap(
textDirection: TextDirection.ltr,
children: <Widget>[
- const Text('X'),
+ const Text('X', textDirection: TextDirection.ltr),
],
),
),
diff --git a/packages/flutter_test/lib/src/binding.dart b/packages/flutter_test/lib/src/binding.dart
index f544df7..2f84ec7 100644
--- a/packages/flutter_test/lib/src/binding.dart
+++ b/packages/flutter_test/lib/src/binding.dart
@@ -269,20 +269,22 @@
static const TextStyle _kMessageStyle = const TextStyle(
color: const Color(0xFF917FFF),
- fontSize: 40.0
+ fontSize: 40.0,
);
static final Widget _kPreTestMessage = const Center(
child: const Text(
'Test starting...',
- style: _kMessageStyle
+ style: _kMessageStyle,
+ textDirection: TextDirection.ltr,
)
);
static final Widget _kPostTestMessage = const Center(
child: const Text(
'Test finished.',
- style: _kMessageStyle
+ style: _kMessageStyle,
+ textDirection: TextDirection.ltr,
)
);
@@ -1019,7 +1021,8 @@
_label = null;
return;
}
- _label ??= new TextPainter(textAlign: TextAlign.left);
+ // TODO(ianh): Figure out if the test name is actually RTL.
+ _label ??= new TextPainter(textAlign: TextAlign.left, textDirection: TextDirection.ltr);
_label.text = new TextSpan(text: value, style: _labelStyle);
_label.layout();
if (onNeedPaint != null)
diff --git a/packages/flutter_test/test/widget_tester_test.dart b/packages/flutter_test/test/widget_tester_test.dart
index e900de8..c9970d3 100644
--- a/packages/flutter_test/test/widget_tester_test.dart
+++ b/packages/flutter_test/test/widget_tester_test.dart
@@ -5,10 +5,15 @@
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
+const List<Widget> fooBarTexts = const <Text>[
+ const Text('foo', textDirection: TextDirection.ltr),
+ const Text('bar', textDirection: TextDirection.ltr),
+];
+
void main() {
group('findsOneWidget', () {
testWidgets('finds exactly one widget', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
expect(find.text('foo'), findsOneWidget);
});
@@ -34,7 +39,7 @@
});
testWidgets('fails with a descriptive message', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
TestFailure failure;
try {
@@ -52,7 +57,7 @@
});
testWidgets('fails with a descriptive message when skipping', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
TestFailure failure;
try {
@@ -70,7 +75,7 @@
});
testWidgets('pumping', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
int count;
final AnimationController test = new AnimationController(
@@ -106,7 +111,7 @@
group('find.byElementPredicate', () {
testWidgets('fails with a custom description in the message', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
final String customDescription = 'custom description';
TestFailure failure;
@@ -123,7 +128,7 @@
group('find.byWidgetPredicate', () {
testWidgets('fails with a custom description in the message', (WidgetTester tester) async {
- await tester.pumpWidget(const Text('foo'));
+ await tester.pumpWidget(const Text('foo', textDirection: TextDirection.ltr));
final String customDescription = 'custom description';
TestFailure failure;
@@ -143,7 +148,7 @@
await tester.pumpWidget(new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- new Column(children: <Text>[const Text('foo'), const Text('bar')]),
+ new Column(children: fooBarTexts),
],
));
@@ -157,8 +162,8 @@
await tester.pumpWidget(new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- new Column(children: <Text>[const Text('foo'), const Text('bar')]),
- new Column(children: <Text>[const Text('foo'), const Text('bar')]),
+ new Column(children: fooBarTexts),
+ new Column(children: fooBarTexts),
],
));
@@ -172,8 +177,8 @@
await tester.pumpWidget(new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- new Column(children: <Text>[const Text('foo')]),
- const Text('bar'),
+ new Column(children: <Text>[const Text('foo', textDirection: TextDirection.ltr)]),
+ const Text('bar', textDirection: TextDirection.ltr),
],
));
@@ -198,7 +203,7 @@
await tester.pumpWidget(new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- new Column(children: <Text>[const Text('foo'), const Text('bar')]),
+ new Column(children: fooBarTexts),
],
));
@@ -212,7 +217,7 @@
await tester.pumpWidget(new Row(
textDirection: TextDirection.ltr,
children: <Widget>[
- new Column(children: <Text>[const Text('foo'), const Text('bar')]),
+ new Column(children: fooBarTexts),
],
));