Merge pull request #2757 from apwilson/banner
Refactor CheckedModeBanner into something more reusable.
This commit is contained in:
@@ -9,9 +9,9 @@ import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'asset_vendor.dart';
|
||||
import 'banner.dart';
|
||||
import 'basic.dart';
|
||||
import 'binding.dart';
|
||||
import 'checked_mode_banner.dart';
|
||||
import 'framework.dart';
|
||||
import 'locale_query.dart';
|
||||
import 'media_query.dart';
|
||||
|
||||
143
packages/flutter/lib/src/widgets/banner.dart
Normal file
143
packages/flutter/lib/src/widgets/banner.dart
Normal file
@@ -0,0 +1,143 @@
|
||||
// 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 'dart:math' as math;
|
||||
|
||||
import 'basic.dart';
|
||||
import 'framework.dart';
|
||||
|
||||
enum BannerLocation { topRight, topLeft, bottomRight, bottomLeft }
|
||||
|
||||
class BannerPainter extends CustomPainter {
|
||||
const BannerPainter({
|
||||
this.message,
|
||||
this.location
|
||||
});
|
||||
|
||||
final String message;
|
||||
final BannerLocation location;
|
||||
|
||||
static const Color kColor = const Color(0xA0B71C1C);
|
||||
static const double kOffset = 40.0; // distance to bottom of banner, at a 45 degree angle inwards
|
||||
static const double kHeight = 12.0; // height of banner
|
||||
static const double kBottomOffset = kOffset + 0.707 * kHeight; // offset plus sqrt(2)/2 * banner height
|
||||
static const Offset kTextAlign = const Offset(0.0, -3.0); // offset to move text up
|
||||
static const double kFontSize = kHeight * 0.85;
|
||||
static const double kShadowBlur = 4.0; // shadow blur sigma
|
||||
static final Rect kRect = new Rect.fromLTWH(-kOffset, kOffset - kHeight, kOffset * 2.0, kHeight);
|
||||
static const TextStyle kTextStyles = const TextStyle(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
fontSize: kFontSize,
|
||||
fontWeight: FontWeight.w900,
|
||||
textAlign: TextAlign.center
|
||||
);
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint paintShadow = new Paint()
|
||||
..color = const Color(0x7F000000)
|
||||
..maskFilter = new MaskFilter.blur(BlurStyle.normal, kShadowBlur);
|
||||
final Paint paintBanner = new Paint()
|
||||
..color = kColor;
|
||||
canvas
|
||||
..translate(_translationX(size.width), _translationY(size.height))
|
||||
..rotate(_rotation)
|
||||
..drawRect(kRect, paintShadow)
|
||||
..drawRect(kRect, paintBanner);
|
||||
|
||||
final TextPainter textPainter = new TextPainter()
|
||||
..text = new TextSpan(style: kTextStyles, text: message)
|
||||
..maxWidth = kOffset * 2.0
|
||||
..maxHeight = kHeight
|
||||
..layout();
|
||||
|
||||
textPainter.paint(canvas, kRect.topLeft.toOffset() + kTextAlign);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(BannerPainter oldPainter) => false;
|
||||
|
||||
@override
|
||||
bool hitTest(Point position) => false;
|
||||
|
||||
double _translationX(double width) {
|
||||
switch (location) {
|
||||
case BannerLocation.bottomRight:
|
||||
return width - kBottomOffset;
|
||||
case BannerLocation.topRight:
|
||||
return width;
|
||||
case BannerLocation.bottomLeft:
|
||||
return kBottomOffset;
|
||||
case BannerLocation.topLeft:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
double _translationY(double height) {
|
||||
switch (location) {
|
||||
case BannerLocation.bottomRight:
|
||||
case BannerLocation.bottomLeft:
|
||||
return height - kBottomOffset;
|
||||
case BannerLocation.topRight:
|
||||
case BannerLocation.topLeft:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
double get _rotation {
|
||||
switch (location) {
|
||||
case BannerLocation.bottomLeft:
|
||||
case BannerLocation.topRight:
|
||||
return math.PI / 4.0;
|
||||
case BannerLocation.bottomRight:
|
||||
case BannerLocation.topLeft:
|
||||
return -math.PI / 4.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Banner extends StatelessWidget {
|
||||
Banner({
|
||||
Key key,
|
||||
this.child,
|
||||
this.message,
|
||||
this.location
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
final String message;
|
||||
final BannerLocation location;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return new CustomPaint(
|
||||
foregroundPainter: new BannerPainter(message: message, location: location),
|
||||
child: child
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Displays a banner saying "SLOW MODE" when running in checked mode.
|
||||
/// Does nothing in release mode.
|
||||
class CheckedModeBanner extends StatelessWidget {
|
||||
CheckedModeBanner({
|
||||
Key key,
|
||||
this.child
|
||||
}) : super(key: key);
|
||||
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget result = child;
|
||||
assert(() {
|
||||
result = new Banner(
|
||||
child: result,
|
||||
message: 'SLOW MODE',
|
||||
location: BannerLocation.topRight);
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// 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 'dart:math' as math;
|
||||
|
||||
import 'basic.dart';
|
||||
import 'framework.dart';
|
||||
|
||||
class _CheckedModeBannerPainter extends CustomPainter {
|
||||
const _CheckedModeBannerPainter();
|
||||
|
||||
static const Color kColor = const Color(0xA0B71C1C);
|
||||
static const double kOffset = 40.0; // distance to bottom of banner, at a 45 degree angle inwards from the top right corner
|
||||
static const double kHeight = 12.0; // height of banner
|
||||
static const Offset kTextAlign = const Offset(0.0, -3.0); // offset to move text up
|
||||
static const double kFontSize = kHeight * 0.85;
|
||||
static const double kShadowBlur = 4.0; // shadow blur sigma
|
||||
static final Rect kRect = new Rect.fromLTWH(-kOffset, kOffset-kHeight, kOffset * 2.0, kHeight);
|
||||
static const TextStyle kTextStyles = const TextStyle(
|
||||
color: const Color(0xFFFFFFFF),
|
||||
fontSize: kFontSize,
|
||||
fontWeight: FontWeight.w900,
|
||||
textAlign: TextAlign.center
|
||||
);
|
||||
|
||||
static final TextPainter textPainter = new TextPainter()
|
||||
..text = new TextSpan(style: kTextStyles, text: 'SLOW MODE')
|
||||
..maxWidth = kOffset * 2.0
|
||||
..maxHeight = kHeight
|
||||
..layout();
|
||||
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
final Paint paintShadow = new Paint()
|
||||
..color = const Color(0x7F000000)
|
||||
..maskFilter = new MaskFilter.blur(BlurStyle.normal, kShadowBlur);
|
||||
final Paint paintBanner = new Paint()
|
||||
..color = kColor;
|
||||
canvas
|
||||
..translate(size.width, 0.0)
|
||||
..rotate(math.PI/4)
|
||||
..drawRect(kRect, paintShadow)
|
||||
..drawRect(kRect, paintBanner);
|
||||
textPainter.paint(canvas, kRect.topLeft.toOffset() + kTextAlign);
|
||||
}
|
||||
|
||||
@override
|
||||
bool shouldRepaint(_CheckedModeBannerPainter oldPainter) => false;
|
||||
|
||||
@override
|
||||
bool hitTest(Point position) => false;
|
||||
}
|
||||
|
||||
/// Displays a banner saying "CHECKED" when running in checked mode.
|
||||
/// Does nothing in release mode.
|
||||
class CheckedModeBanner extends StatelessWidget {
|
||||
CheckedModeBanner({
|
||||
Key key,
|
||||
this.child
|
||||
}) : super(key: key);
|
||||
|
||||
/// The widget below this widget in the tree.
|
||||
final Widget child;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Widget result = child;
|
||||
assert(() {
|
||||
result = new CustomPaint(
|
||||
foregroundPainter: const _CheckedModeBannerPainter(),
|
||||
child: result
|
||||
);
|
||||
return true;
|
||||
});
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -8,9 +8,9 @@ library widgets;
|
||||
export 'src/widgets/app.dart';
|
||||
export 'src/widgets/asset_vendor.dart';
|
||||
export 'src/widgets/auto_layout.dart';
|
||||
export 'src/widgets/banner.dart';
|
||||
export 'src/widgets/basic.dart';
|
||||
export 'src/widgets/binding.dart';
|
||||
export 'src/widgets/checked_mode_banner.dart';
|
||||
export 'src/widgets/child_view.dart';
|
||||
export 'src/widgets/dismissable.dart';
|
||||
export 'src/widgets/drag_target.dart';
|
||||
|
||||
123
packages/flutter/test/widget/banner_test.dart
Normal file
123
packages/flutter/test/widget/banner_test.dart
Normal file
@@ -0,0 +1,123 @@
|
||||
// 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 'dart:math' as math;
|
||||
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
class TestCanvas implements Canvas {
|
||||
final List<Invocation> invocations = <Invocation>[];
|
||||
|
||||
@override
|
||||
void noSuchMethod(Invocation invocation) {
|
||||
invocations.add(invocation);
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
test('A Banner with a location of topLeft paints in the top left', () {
|
||||
BannerPainter bannerPainter = new BannerPainter(
|
||||
message:"foo",
|
||||
location: BannerLocation.topLeft
|
||||
);
|
||||
|
||||
TestCanvas canvas = new TestCanvas();
|
||||
|
||||
bannerPainter.paint(canvas, new Size(1000.0, 1000.0));
|
||||
|
||||
Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #translate;
|
||||
});
|
||||
|
||||
expect(translateCommand, isNotNull);
|
||||
expect(translateCommand.positionalArguments[0], lessThan(100.0));
|
||||
expect(translateCommand.positionalArguments[1], lessThan(100.0));
|
||||
|
||||
Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #rotate;
|
||||
});
|
||||
|
||||
expect(rotateCommand, isNotNull);
|
||||
expect(rotateCommand.positionalArguments[0], equals(-math.PI / 4.0));
|
||||
});
|
||||
|
||||
test('A Banner with a location of topRight paints in the top right', () {
|
||||
BannerPainter bannerPainter = new BannerPainter(
|
||||
message:"foo",
|
||||
location: BannerLocation.topRight
|
||||
);
|
||||
|
||||
TestCanvas canvas = new TestCanvas();
|
||||
|
||||
bannerPainter.paint(canvas, new Size(1000.0, 1000.0));
|
||||
|
||||
Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #translate;
|
||||
});
|
||||
|
||||
expect(translateCommand, isNotNull);
|
||||
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
|
||||
expect(translateCommand.positionalArguments[1], lessThan(100.0));
|
||||
|
||||
Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #rotate;
|
||||
});
|
||||
|
||||
expect(rotateCommand, isNotNull);
|
||||
expect(rotateCommand.positionalArguments[0], equals(math.PI / 4.0));
|
||||
});
|
||||
|
||||
test('A Banner with a location of bottomLeft paints in the bottom left', () {
|
||||
BannerPainter bannerPainter = new BannerPainter(
|
||||
message:"foo",
|
||||
location: BannerLocation.bottomLeft
|
||||
);
|
||||
|
||||
TestCanvas canvas = new TestCanvas();
|
||||
|
||||
bannerPainter.paint(canvas, new Size(1000.0, 1000.0));
|
||||
|
||||
Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #translate;
|
||||
});
|
||||
|
||||
expect(translateCommand, isNotNull);
|
||||
expect(translateCommand.positionalArguments[0], lessThan(100.0));
|
||||
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
|
||||
|
||||
Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #rotate;
|
||||
});
|
||||
|
||||
expect(rotateCommand, isNotNull);
|
||||
expect(rotateCommand.positionalArguments[0], equals(math.PI / 4.0));
|
||||
});
|
||||
|
||||
test('A Banner with a location of bottomRight paints in the bottom right', () {
|
||||
BannerPainter bannerPainter = new BannerPainter(
|
||||
message:"foo",
|
||||
location: BannerLocation.bottomRight
|
||||
);
|
||||
|
||||
TestCanvas canvas = new TestCanvas();
|
||||
|
||||
bannerPainter.paint(canvas, new Size(1000.0, 1000.0));
|
||||
|
||||
Invocation translateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #translate;
|
||||
});
|
||||
|
||||
expect(translateCommand, isNotNull);
|
||||
expect(translateCommand.positionalArguments[0], greaterThan(900.0));
|
||||
expect(translateCommand.positionalArguments[1], greaterThan(900.0));
|
||||
|
||||
Invocation rotateCommand = canvas.invocations.firstWhere((Invocation invocation) {
|
||||
return invocation.memberName == #rotate;
|
||||
});
|
||||
|
||||
expect(rotateCommand, isNotNull);
|
||||
expect(rotateCommand.positionalArguments[0], equals(-math.PI / 4.0));
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user