Commit cedc7450 authored by Ian Hickson's avatar Ian Hickson Committed by GitHub

Add a flag that shows a banner for old Scrollables (#7819)

Also, tweak Banner a bit so you can set the color and text style.
Also, cache the text painter between paints.
parent 5928d221
...@@ -13,7 +13,9 @@ const double _kOffset = 40.0; // distance to bottom of banner, at a 45 degree an ...@@ -13,7 +13,9 @@ const double _kOffset = 40.0; // distance to bottom of banner, at a 45 degree an
const double _kHeight = 12.0; // height of banner const double _kHeight = 12.0; // height of banner
const double _kBottomOffset = _kOffset + 0.707 * _kHeight; // offset plus sqrt(2)/2 * banner height const double _kBottomOffset = _kOffset + 0.707 * _kHeight; // offset plus sqrt(2)/2 * banner height
final Rect _kRect = new Rect.fromLTWH(-_kOffset, _kOffset - _kHeight, _kOffset * 2.0, _kHeight); final Rect _kRect = new Rect.fromLTWH(-_kOffset, _kOffset - _kHeight, _kOffset * 2.0, _kHeight);
const TextStyle _kTextStyles = const TextStyle(
const Color _kColor = const Color(0xA0B71C1C);
const TextStyle _kTextStyle = const TextStyle(
color: const Color(0xFFFFFFFF), color: const Color(0xFFFFFFFF),
fontSize: _kHeight * 0.85, fontSize: _kHeight * 0.85,
fontWeight: FontWeight.w900, fontWeight: FontWeight.w900,
...@@ -40,10 +42,17 @@ class BannerPainter extends CustomPainter { ...@@ -40,10 +42,17 @@ class BannerPainter extends CustomPainter {
/// Creates a banner painter. /// Creates a banner painter.
/// ///
/// The [message] and [location] arguments must not be null. /// The [message] and [location] arguments must not be null.
const BannerPainter({ BannerPainter({
@required this.message, @required this.message,
@required this.location @required this.location,
}); this.color: _kColor,
this.textStyle: _kTextStyle,
}) {
assert(message != null);
assert(location != null);
assert(color != null);
assert(textStyle != null);
}
/// The message to show in the banner. /// The message to show in the banner.
final String message; final String message;
...@@ -51,35 +60,55 @@ class BannerPainter extends CustomPainter { ...@@ -51,35 +60,55 @@ class BannerPainter extends CustomPainter {
/// Where to show the banner (e.g., the upper right corder). /// Where to show the banner (e.g., the upper right corder).
final BannerLocation location; final BannerLocation location;
@override final Color color;
void paint(Canvas canvas, Size size) {
final Paint paintShadow = new Paint() final TextStyle textStyle;
bool _prepared = false;
TextPainter _textPainter;
Paint _paintShadow;
Paint _paintBanner;
void _prepare() {
_paintShadow = new Paint()
..color = const Color(0x7F000000) ..color = const Color(0x7F000000)
..maskFilter = new MaskFilter.blur(BlurStyle.normal, 4.0); ..maskFilter = new MaskFilter.blur(BlurStyle.normal, 4.0);
final Paint paintBanner = new Paint() _paintBanner = new Paint()
..color = const Color(0xA0B71C1C); ..color = color;
_textPainter = new TextPainter(
text: new TextSpan(style: textStyle, text: message),
textAlign: TextAlign.center,
);
_prepared = true;
}
@override
void paint(Canvas canvas, Size size) {
if (!_prepared)
_prepare();
canvas canvas
..translate(_translationX(size.width), _translationY(size.height)) ..translate(_translationX(size.width), _translationY(size.height))
..rotate(_rotation) ..rotate(_rotation)
..drawRect(_kRect, paintShadow) ..drawRect(_kRect, _paintShadow)
..drawRect(_kRect, paintBanner); ..drawRect(_kRect, _paintBanner);
final double width = _kOffset * 2.0; final double width = _kOffset * 2.0;
final TextPainter textPainter = new TextPainter( _textPainter.layout(minWidth: width, maxWidth: width);
text: new TextSpan(style: _kTextStyles, text: message), _textPainter.paint(canvas, _kRect.topLeft.toOffset() + new Offset(0.0, (_kRect.height - _textPainter.height) / 2.0));
textAlign: TextAlign.center
)..layout(minWidth: width, maxWidth: width);
textPainter.paint(canvas, _kRect.topLeft.toOffset() + new Offset(0.0, (_kRect.height - textPainter.height) / 2.0));
} }
@override @override
bool shouldRepaint(BannerPainter oldPainter) => false; bool shouldRepaint(BannerPainter oldPainter) {
return message != oldPainter.message
|| location != oldPainter.location
|| color != oldPainter.color
|| textStyle != oldPainter.textStyle;
}
@override @override
bool hitTest(Point position) => false; bool hitTest(Point position) => false;
double _translationX(double width) { double _translationX(double width) {
assert(location != null);
switch (location) { switch (location) {
case BannerLocation.bottomRight: case BannerLocation.bottomRight:
return width - _kBottomOffset; return width - _kBottomOffset;
...@@ -90,11 +119,11 @@ class BannerPainter extends CustomPainter { ...@@ -90,11 +119,11 @@ class BannerPainter extends CustomPainter {
case BannerLocation.topLeft: case BannerLocation.topLeft:
return 0.0; return 0.0;
} }
assert(location != null);
return null; return null;
} }
double _translationY(double height) { double _translationY(double height) {
assert(location != null);
switch (location) { switch (location) {
case BannerLocation.bottomRight: case BannerLocation.bottomRight:
case BannerLocation.bottomLeft: case BannerLocation.bottomLeft:
...@@ -103,11 +132,11 @@ class BannerPainter extends CustomPainter { ...@@ -103,11 +132,11 @@ class BannerPainter extends CustomPainter {
case BannerLocation.topLeft: case BannerLocation.topLeft:
return 0.0; return 0.0;
} }
assert(location != null);
return null; return null;
} }
double get _rotation { double get _rotation {
assert(location != null);
switch (location) { switch (location) {
case BannerLocation.bottomLeft: case BannerLocation.bottomLeft:
case BannerLocation.topRight: case BannerLocation.topRight:
...@@ -116,7 +145,6 @@ class BannerPainter extends CustomPainter { ...@@ -116,7 +145,6 @@ class BannerPainter extends CustomPainter {
case BannerLocation.topLeft: case BannerLocation.topLeft:
return -math.PI / 4.0; return -math.PI / 4.0;
} }
assert(location != null);
return null; return null;
} }
} }
...@@ -136,11 +164,15 @@ class Banner extends StatelessWidget { ...@@ -136,11 +164,15 @@ class Banner extends StatelessWidget {
Banner({ Banner({
Key key, Key key,
this.child, this.child,
this.message, @required this.message,
this.location @required this.location,
this.color: _kColor,
this.textStyle: _kTextStyle,
}) : super(key: key) { }) : super(key: key) {
assert(message != null); assert(message != null);
assert(location != null); assert(location != null);
assert(color != null);
assert(textStyle != null);
} }
/// The widget to show behind the banner. /// The widget to show behind the banner.
...@@ -152,11 +184,22 @@ class Banner extends StatelessWidget { ...@@ -152,11 +184,22 @@ class Banner extends StatelessWidget {
/// Where to show the banner (e.g., the upper right corder). /// Where to show the banner (e.g., the upper right corder).
final BannerLocation location; final BannerLocation location;
/// The color of the banner.
final Color color;
/// The style of the text shown on the banner.
final TextStyle textStyle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new CustomPaint( return new CustomPaint(
foregroundPainter: new BannerPainter(message: message, location: location), foregroundPainter: new BannerPainter(
child: child message: message,
location: location,
color: color,
textStyle: textStyle,
),
child: child,
); );
} }
} }
......
...@@ -57,6 +57,9 @@ bool debugPrintGlobalKeyedWidgetLifecycle = false; ...@@ -57,6 +57,9 @@ bool debugPrintGlobalKeyedWidgetLifecycle = false;
/// optimize your app, see https://fuchsia.googlesource.com/sysui/+/master/docs/performance.md /// optimize your app, see https://fuchsia.googlesource.com/sysui/+/master/docs/performance.md
bool debugProfileBuildsEnabled = false; bool debugProfileBuildsEnabled = false;
/// Show banners for deprecated widgets.
bool debugHighlightDeprecatedWidgets = false;
Key _firstNonUniqueKey(Iterable<Widget> widgets) { Key _firstNonUniqueKey(Iterable<Widget> widgets) {
Set<Key> keySet = new HashSet<Key>(); Set<Key> keySet = new HashSet<Key>();
for (Widget widget in widgets) { for (Widget widget in widgets) {
...@@ -184,7 +187,8 @@ bool debugAssertAllWidgetVarsUnset(String reason) { ...@@ -184,7 +187,8 @@ bool debugAssertAllWidgetVarsUnset(String reason) {
debugPrintBuildScope || debugPrintBuildScope ||
debugPrintScheduleBuildForStacks || debugPrintScheduleBuildForStacks ||
debugPrintGlobalKeyedWidgetLifecycle || debugPrintGlobalKeyedWidgetLifecycle ||
debugProfileBuildsEnabled) { debugProfileBuildsEnabled ||
debugHighlightDeprecatedWidgets) {
throw new FlutterError(reason); throw new FlutterError(reason);
} }
return true; return true;
......
...@@ -12,8 +12,10 @@ import 'package:flutter/physics.dart'; ...@@ -12,8 +12,10 @@ import 'package:flutter/physics.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'banner.dart';
import 'basic.dart'; import 'basic.dart';
import 'clamp_overscrolls.dart'; import 'clamp_overscrolls.dart';
import 'debug.dart';
import 'framework.dart'; import 'framework.dart';
import 'gesture_detector.dart'; import 'gesture_detector.dart';
import 'notification_listener.dart'; import 'notification_listener.dart';
...@@ -1386,15 +1388,24 @@ class ScrollableState<T extends Scrollable> extends State<T> with SingleTickerPr ...@@ -1386,15 +1388,24 @@ class ScrollableState<T extends Scrollable> extends State<T> with SingleTickerPr
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return new RawGestureDetector( Widget result = new RawGestureDetector(
key: _gestureDetectorKey, key: _gestureDetectorKey,
gestures: buildGestureDetectors(), gestures: buildGestureDetectors(),
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
child: new IgnorePointer( child: new IgnorePointer(
ignoring: _scrollUnderway, ignoring: _scrollUnderway,
child: buildContent(context) child: buildContent(context),
) ),
); );
if (debugHighlightDeprecatedWidgets) {
result = new Banner(
message: 'OLD',
color: const Color(0xFF009000),
location: BannerLocation.bottomRight,
child: result,
);
}
return result;
} }
/// Fixes up the gesture detector to listen to the appropriate /// Fixes up the gesture detector to listen to the appropriate
......
...@@ -18,7 +18,7 @@ class TestCanvas implements Canvas { ...@@ -18,7 +18,7 @@ class TestCanvas implements Canvas {
void main() { void main() {
test('A Banner with a location of topLeft paints in the top left', () { test('A Banner with a location of topLeft paints in the top left', () {
BannerPainter bannerPainter = const BannerPainter( BannerPainter bannerPainter = new BannerPainter(
message:"foo", message:"foo",
location: BannerLocation.topLeft location: BannerLocation.topLeft
); );
...@@ -44,7 +44,7 @@ void main() { ...@@ -44,7 +44,7 @@ void main() {
}); });
test('A Banner with a location of topRight paints in the top right', () { test('A Banner with a location of topRight paints in the top right', () {
BannerPainter bannerPainter = const BannerPainter( BannerPainter bannerPainter = new BannerPainter(
message:"foo", message:"foo",
location: BannerLocation.topRight location: BannerLocation.topRight
); );
...@@ -70,7 +70,7 @@ void main() { ...@@ -70,7 +70,7 @@ void main() {
}); });
test('A Banner with a location of bottomLeft paints in the bottom left', () { test('A Banner with a location of bottomLeft paints in the bottom left', () {
BannerPainter bannerPainter = const BannerPainter( BannerPainter bannerPainter = new BannerPainter(
message:"foo", message:"foo",
location: BannerLocation.bottomLeft location: BannerLocation.bottomLeft
); );
...@@ -96,7 +96,7 @@ void main() { ...@@ -96,7 +96,7 @@ void main() {
}); });
test('A Banner with a location of bottomRight paints in the bottom right', () { test('A Banner with a location of bottomRight paints in the bottom right', () {
BannerPainter bannerPainter = const BannerPainter( BannerPainter bannerPainter = new BannerPainter(
message:"foo", message:"foo",
location: BannerLocation.bottomRight location: BannerLocation.bottomRight
); );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment