Update Cupertino desktop text selection toolbar (#121829)
Visual fidelity of the right-click context menu on MacOS.
This commit is contained in:
parent
8a815c1d1d
commit
f86b9220a3
@ -182,7 +182,6 @@ class _CupertinoDesktopTextSelectionControlsToolbarState extends State<_Cupertin
|
|||||||
}
|
}
|
||||||
|
|
||||||
items.add(CupertinoDesktopTextSelectionToolbarButton.text(
|
items.add(CupertinoDesktopTextSelectionToolbarButton.text(
|
||||||
context: context,
|
|
||||||
onPressed: onPressed,
|
onPressed: onPressed,
|
||||||
text: text,
|
text: text,
|
||||||
));
|
));
|
||||||
|
@ -2,6 +2,9 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
import 'colors.dart';
|
import 'colors.dart';
|
||||||
@ -10,23 +13,33 @@ import 'colors.dart';
|
|||||||
// the screen.
|
// the screen.
|
||||||
const double _kToolbarScreenPadding = 8.0;
|
const double _kToolbarScreenPadding = 8.0;
|
||||||
|
|
||||||
// These values were measured from a screenshot of TextEdit on macOS 10.15.7 on
|
// These values were measured from a screenshot of the native context menu on
|
||||||
// a Macbook Pro.
|
// macOS 13.2 on a Macbook Pro.
|
||||||
|
const double _kToolbarSaturationBoost = 3;
|
||||||
|
const double _kToolbarBlurSigma = 20;
|
||||||
const double _kToolbarWidth = 222.0;
|
const double _kToolbarWidth = 222.0;
|
||||||
const Radius _kToolbarBorderRadius = Radius.circular(4.0);
|
const Radius _kToolbarBorderRadius = Radius.circular(8.0);
|
||||||
const EdgeInsets _kToolbarPadding = EdgeInsets.symmetric(
|
const EdgeInsets _kToolbarPadding = EdgeInsets.all(6.0);
|
||||||
vertical: 3.0,
|
const List<BoxShadow> _kToolbarShadow = <BoxShadow>[
|
||||||
);
|
BoxShadow(
|
||||||
|
color: Color.fromARGB(60, 0, 0, 0),
|
||||||
|
blurRadius: 10.0,
|
||||||
|
spreadRadius: 0.5,
|
||||||
|
offset: Offset(0.0, 4.0),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
// These values were measured from a screenshot of TextEdit on macOS 10.16 on a
|
// These values were measured from a screenshot of the native context menu on
|
||||||
// Macbook Pro.
|
// macOS 13.2 on a Macbook Pro.
|
||||||
const CupertinoDynamicColor _kToolbarBorderColor = CupertinoDynamicColor.withBrightness(
|
const CupertinoDynamicColor _kToolbarBorderColor =
|
||||||
color: Color(0xFFBBBBBB),
|
CupertinoDynamicColor.withBrightness(
|
||||||
darkColor: Color(0xFF505152),
|
color: Color(0xFFB8B8B8),
|
||||||
|
darkColor: Color(0xFF5B5B5B),
|
||||||
);
|
);
|
||||||
const CupertinoDynamicColor _kToolbarBackgroundColor = CupertinoDynamicColor.withBrightness(
|
const CupertinoDynamicColor _kToolbarBackgroundColor =
|
||||||
color: Color(0xffECE8E6),
|
CupertinoDynamicColor.withBrightness(
|
||||||
darkColor: Color(0xff302928),
|
color: Color(0xB2FFFFFF),
|
||||||
|
darkColor: Color(0xB2303030),
|
||||||
);
|
);
|
||||||
|
|
||||||
/// A macOS-style text selection toolbar.
|
/// A macOS-style text selection toolbar.
|
||||||
@ -53,6 +66,23 @@ class CupertinoDesktopTextSelectionToolbar extends StatelessWidget {
|
|||||||
required this.children,
|
required this.children,
|
||||||
}) : assert(children.length > 0);
|
}) : assert(children.length > 0);
|
||||||
|
|
||||||
|
/// Creates a 5x5 matrix that increases saturation when used with [ColorFilter.matrix].
|
||||||
|
///
|
||||||
|
/// The numbers were taken from this comment:
|
||||||
|
/// [Cupertino blurs should boost saturation](https://github.com/flutter/flutter/issues/29483#issuecomment-477334981).
|
||||||
|
static List<double> _matrixWithSaturation(double saturation) {
|
||||||
|
final double r = 0.213 * (1 - saturation);
|
||||||
|
final double g = 0.715 * (1 - saturation);
|
||||||
|
final double b = 0.072 * (1 - saturation);
|
||||||
|
|
||||||
|
return <double>[
|
||||||
|
r + saturation, g, b, 0, 0, //
|
||||||
|
r, g + saturation, b, 0, 0, //
|
||||||
|
r, g, b + saturation, 0, 0, //
|
||||||
|
0, 0, 0, 1, 0, //
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/// {@macro flutter.material.DesktopTextSelectionToolbar.anchor}
|
/// {@macro flutter.material.DesktopTextSelectionToolbar.anchor}
|
||||||
final Offset anchor;
|
final Offset anchor;
|
||||||
|
|
||||||
@ -68,16 +98,41 @@ class CupertinoDesktopTextSelectionToolbar extends StatelessWidget {
|
|||||||
static Widget _defaultToolbarBuilder(BuildContext context, Widget child) {
|
static Widget _defaultToolbarBuilder(BuildContext context, Widget child) {
|
||||||
return Container(
|
return Container(
|
||||||
width: _kToolbarWidth,
|
width: _kToolbarWidth,
|
||||||
decoration: BoxDecoration(
|
clipBehavior: Clip.hardEdge,
|
||||||
color: _kToolbarBackgroundColor.resolveFrom(context),
|
decoration: const BoxDecoration(
|
||||||
border: Border.all(
|
boxShadow: _kToolbarShadow,
|
||||||
color: _kToolbarBorderColor.resolveFrom(context),
|
borderRadius: BorderRadius.all(_kToolbarBorderRadius),
|
||||||
),
|
|
||||||
borderRadius: const BorderRadius.all(_kToolbarBorderRadius),
|
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: BackdropFilter(
|
||||||
padding: _kToolbarPadding,
|
// Flutter web doesn't support ImageFilter.compose on CanvasKit yet
|
||||||
child: child,
|
// (https://github.com/flutter/flutter/issues/120123).
|
||||||
|
filter: kIsWeb
|
||||||
|
? ImageFilter.blur(
|
||||||
|
sigmaX: _kToolbarBlurSigma,
|
||||||
|
sigmaY: _kToolbarBlurSigma,
|
||||||
|
)
|
||||||
|
: ImageFilter.compose(
|
||||||
|
outer: ColorFilter.matrix(
|
||||||
|
_matrixWithSaturation(_kToolbarSaturationBoost),
|
||||||
|
),
|
||||||
|
inner: ImageFilter.blur(
|
||||||
|
sigmaX: _kToolbarBlurSigma,
|
||||||
|
sigmaY: _kToolbarBlurSigma,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: _kToolbarBackgroundColor.resolveFrom(context),
|
||||||
|
border: Border.all(
|
||||||
|
color: _kToolbarBorderColor.resolveFrom(context),
|
||||||
|
),
|
||||||
|
borderRadius: const BorderRadius.all(_kToolbarBorderRadius),
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: _kToolbarPadding,
|
||||||
|
child: child,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -86,7 +141,8 @@ class CupertinoDesktopTextSelectionToolbar extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
assert(debugCheckHasMediaQuery(context));
|
assert(debugCheckHasMediaQuery(context));
|
||||||
|
|
||||||
final double paddingAbove = MediaQuery.paddingOf(context).top + _kToolbarScreenPadding;
|
final double paddingAbove =
|
||||||
|
MediaQuery.paddingOf(context).top + _kToolbarScreenPadding;
|
||||||
final Offset localAdjustment = Offset(_kToolbarScreenPadding, paddingAbove);
|
final Offset localAdjustment = Offset(_kToolbarScreenPadding, paddingAbove);
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
|
@ -10,8 +10,8 @@ import 'colors.dart';
|
|||||||
import 'text_selection_toolbar_button.dart';
|
import 'text_selection_toolbar_button.dart';
|
||||||
import 'theme.dart';
|
import 'theme.dart';
|
||||||
|
|
||||||
// These values were measured from a screenshot of TextEdit on MacOS 10.15.7 on
|
// These values were measured from a screenshot of the native context menu on
|
||||||
// a Macbook Pro.
|
// macOS 13.2 on a Macbook Pro.
|
||||||
const TextStyle _kToolbarButtonFontStyle = TextStyle(
|
const TextStyle _kToolbarButtonFontStyle = TextStyle(
|
||||||
inherit: false,
|
inherit: false,
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
@ -19,13 +19,13 @@ const TextStyle _kToolbarButtonFontStyle = TextStyle(
|
|||||||
fontWeight: FontWeight.w400,
|
fontWeight: FontWeight.w400,
|
||||||
);
|
);
|
||||||
|
|
||||||
// This value was measured from a screenshot of TextEdit on MacOS 10.15.7 on a
|
// This value was measured from a screenshot of the native context menu on
|
||||||
// Macbook Pro.
|
// macOS 13.2 on a Macbook Pro.
|
||||||
const EdgeInsets _kToolbarButtonPadding = EdgeInsets.fromLTRB(
|
const EdgeInsets _kToolbarButtonPadding = EdgeInsets.fromLTRB(
|
||||||
20.0,
|
8.0,
|
||||||
0.0,
|
2.0,
|
||||||
20.0,
|
8.0,
|
||||||
3.0,
|
5.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
/// A button in the style of the Mac context menu buttons.
|
/// A button in the style of the Mac context menu buttons.
|
||||||
@ -37,26 +37,17 @@ class CupertinoDesktopTextSelectionToolbarButton extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
required Widget this.child,
|
required Widget this.child,
|
||||||
}) : buttonItem = null;
|
}) : buttonItem = null,
|
||||||
|
text = null;
|
||||||
|
|
||||||
/// Create an instance of [CupertinoDesktopTextSelectionToolbarButton] whose child is
|
/// Create an instance of [CupertinoDesktopTextSelectionToolbarButton] whose child is
|
||||||
/// a [Text] widget styled like the default Mac context menu button.
|
/// a [Text] widget styled like the default Mac context menu button.
|
||||||
CupertinoDesktopTextSelectionToolbarButton.text({
|
const CupertinoDesktopTextSelectionToolbarButton.text({
|
||||||
super.key,
|
super.key,
|
||||||
required BuildContext context,
|
|
||||||
required this.onPressed,
|
required this.onPressed,
|
||||||
required String text,
|
required this.text,
|
||||||
}) : buttonItem = null,
|
}) : buttonItem = null,
|
||||||
child = Text(
|
child = null;
|
||||||
text,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: _kToolbarButtonFontStyle.copyWith(
|
|
||||||
color: const CupertinoDynamicColor.withBrightness(
|
|
||||||
color: CupertinoColors.black,
|
|
||||||
darkColor: CupertinoColors.white,
|
|
||||||
).resolveFrom(context),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
/// Create an instance of [CupertinoDesktopTextSelectionToolbarButton] from
|
/// Create an instance of [CupertinoDesktopTextSelectionToolbarButton] from
|
||||||
/// the given [ContextMenuButtonItem].
|
/// the given [ContextMenuButtonItem].
|
||||||
@ -65,8 +56,9 @@ class CupertinoDesktopTextSelectionToolbarButton extends StatefulWidget {
|
|||||||
CupertinoDesktopTextSelectionToolbarButton.buttonItem({
|
CupertinoDesktopTextSelectionToolbarButton.buttonItem({
|
||||||
super.key,
|
super.key,
|
||||||
required ContextMenuButtonItem this.buttonItem,
|
required ContextMenuButtonItem this.buttonItem,
|
||||||
}) : onPressed = buttonItem.onPressed,
|
}) : onPressed = buttonItem.onPressed,
|
||||||
child = null;
|
text = null,
|
||||||
|
child = null;
|
||||||
|
|
||||||
/// {@macro flutter.cupertino.CupertinoTextSelectionToolbarButton.onPressed}
|
/// {@macro flutter.cupertino.CupertinoTextSelectionToolbarButton.onPressed}
|
||||||
final VoidCallback? onPressed;
|
final VoidCallback? onPressed;
|
||||||
@ -77,11 +69,16 @@ class CupertinoDesktopTextSelectionToolbarButton extends StatefulWidget {
|
|||||||
/// {@macro flutter.cupertino.CupertinoTextSelectionToolbarButton.onPressed}
|
/// {@macro flutter.cupertino.CupertinoTextSelectionToolbarButton.onPressed}
|
||||||
final ContextMenuButtonItem? buttonItem;
|
final ContextMenuButtonItem? buttonItem;
|
||||||
|
|
||||||
|
/// {@macro flutter.cupertino.CupertinoTextSelectionToolbarButton.text}
|
||||||
|
final String? text;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CupertinoDesktopTextSelectionToolbarButton> createState() => _CupertinoDesktopTextSelectionToolbarButtonState();
|
State<CupertinoDesktopTextSelectionToolbarButton> createState() =>
|
||||||
|
_CupertinoDesktopTextSelectionToolbarButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _CupertinoDesktopTextSelectionToolbarButtonState extends State<CupertinoDesktopTextSelectionToolbarButton> {
|
class _CupertinoDesktopTextSelectionToolbarButtonState
|
||||||
|
extends State<CupertinoDesktopTextSelectionToolbarButton> {
|
||||||
bool _isHovered = false;
|
bool _isHovered = false;
|
||||||
|
|
||||||
void _onEnter(PointerEnterEvent event) {
|
void _onEnter(PointerEnterEvent event) {
|
||||||
@ -98,16 +95,24 @@ class _CupertinoDesktopTextSelectionToolbarButtonState extends State<CupertinoDe
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final Widget child = widget.child ?? Text(
|
final Widget child = widget.child ??
|
||||||
CupertinoTextSelectionToolbarButton.getButtonLabel(context, widget.buttonItem!),
|
Text(
|
||||||
overflow: TextOverflow.ellipsis,
|
widget.text ??
|
||||||
style: _kToolbarButtonFontStyle.copyWith(
|
CupertinoTextSelectionToolbarButton.getButtonLabel(
|
||||||
color: const CupertinoDynamicColor.withBrightness(
|
context,
|
||||||
color: CupertinoColors.black,
|
widget.buttonItem!,
|
||||||
darkColor: CupertinoColors.white,
|
),
|
||||||
).resolveFrom(context),
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
style: _kToolbarButtonFontStyle.copyWith(
|
||||||
);
|
color: _isHovered
|
||||||
|
? CupertinoTheme.of(context).primaryContrastingColor
|
||||||
|
: const CupertinoDynamicColor.withBrightness(
|
||||||
|
color: CupertinoColors.black,
|
||||||
|
darkColor: CupertinoColors.white,
|
||||||
|
).resolveFrom(context),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
@ -115,7 +120,7 @@ class _CupertinoDesktopTextSelectionToolbarButtonState extends State<CupertinoDe
|
|||||||
onExit: _onExit,
|
onExit: _onExit,
|
||||||
child: CupertinoButton(
|
child: CupertinoButton(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
borderRadius: null,
|
borderRadius: const BorderRadius.all(Radius.circular(4.0)),
|
||||||
color: _isHovered ? CupertinoTheme.of(context).primaryColor : null,
|
color: _isHovered ? CupertinoTheme.of(context).primaryColor : null,
|
||||||
minSize: 0.0,
|
minSize: 0.0,
|
||||||
onPressed: widget.onPressed,
|
onPressed: widget.onPressed,
|
||||||
|
@ -83,8 +83,10 @@ class CupertinoTextSelectionToolbarButton extends StatelessWidget {
|
|||||||
/// {@endtemplate}
|
/// {@endtemplate}
|
||||||
final ContextMenuButtonItem? buttonItem;
|
final ContextMenuButtonItem? buttonItem;
|
||||||
|
|
||||||
|
/// {@template flutter.cupertino.CupertinoTextSelectionToolbarButton.text}
|
||||||
/// The text used in the button's label when using
|
/// The text used in the button's label when using
|
||||||
/// [CupertinoTextSelectionToolbarButton.text].
|
/// [CupertinoTextSelectionToolbarButton.text].
|
||||||
|
/// {@endtemplate}
|
||||||
final String? text;
|
final String? text;
|
||||||
|
|
||||||
/// Returns the default button label String for the button of the given
|
/// Returns the default button label String for the button of the given
|
||||||
|
@ -271,7 +271,6 @@ class AdaptiveTextSelectionToolbar extends StatelessWidget {
|
|||||||
case TargetPlatform.macOS:
|
case TargetPlatform.macOS:
|
||||||
return buttonItems.map((ContextMenuButtonItem buttonItem) {
|
return buttonItems.map((ContextMenuButtonItem buttonItem) {
|
||||||
return CupertinoDesktopTextSelectionToolbarButton.text(
|
return CupertinoDesktopTextSelectionToolbarButton.text(
|
||||||
context: context,
|
|
||||||
onPressed: buttonItem.onPressed,
|
onPressed: buttonItem.onPressed,
|
||||||
text: getButtonLabel(context, buttonItem),
|
text: getButtonLabel(context, buttonItem),
|
||||||
);
|
);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
@ -29,6 +30,46 @@ void main() {
|
|||||||
expect(pressed, true);
|
expect(pressed, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('keeps contrast with background on hover',
|
||||||
|
(WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoDesktopTextSelectionToolbarButton.text(
|
||||||
|
text: 'Tap me',
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final BuildContext context =
|
||||||
|
tester.element(find.byType(CupertinoDesktopTextSelectionToolbarButton));
|
||||||
|
|
||||||
|
// The Text color is a CupertinoDynamicColor so we have to compare the color
|
||||||
|
// values instead of just comparing the colors themselves.
|
||||||
|
expect(
|
||||||
|
(tester.firstWidget(find.text('Tap me')) as Text).style!.color!.value,
|
||||||
|
CupertinoColors.black.value,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Hover gesture
|
||||||
|
final TestGesture gesture =
|
||||||
|
await tester.createGesture(kind: PointerDeviceKind.mouse);
|
||||||
|
await gesture.addPointer(location: Offset.zero);
|
||||||
|
addTearDown(gesture.removePointer);
|
||||||
|
await tester.pump();
|
||||||
|
await gesture.moveTo(tester
|
||||||
|
.getCenter(find.byType(CupertinoDesktopTextSelectionToolbarButton)));
|
||||||
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
// The color here should be a standard Color, there's no need to use value.
|
||||||
|
expect(
|
||||||
|
(tester.firstWidget(find.text('Tap me')) as Text).style!.color,
|
||||||
|
CupertinoTheme.of(context).primaryContrastingColor,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('pressedOpacity defaults to 0.1', (WidgetTester tester) async {
|
testWidgets('pressedOpacity defaults to 0.1', (WidgetTester tester) async {
|
||||||
await tester.pumpWidget(
|
await tester.pumpWidget(
|
||||||
CupertinoApp(
|
CupertinoApp(
|
||||||
@ -49,7 +90,8 @@ void main() {
|
|||||||
expect(opacity.opacity.value, 1.0);
|
expect(opacity.opacity.value, 1.0);
|
||||||
|
|
||||||
// Make a "down" gesture on the button.
|
// Make a "down" gesture on the button.
|
||||||
final Offset center = tester.getCenter(find.byType(CupertinoDesktopTextSelectionToolbarButton));
|
final Offset center = tester
|
||||||
|
.getCenter(find.byType(CupertinoDesktopTextSelectionToolbarButton));
|
||||||
final TestGesture gesture = await tester.startGesture(center);
|
final TestGesture gesture = await tester.startGesture(center);
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|
||||||
|
@ -2,12 +2,120 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
import 'package:flutter_test/flutter_test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
TestWidgetsFlutterBinding.ensureInitialized();
|
TestWidgetsFlutterBinding.ensureInitialized();
|
||||||
|
|
||||||
|
testWidgets('has correct backdrop filters', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoDesktopTextSelectionToolbar(
|
||||||
|
anchor: Offset.zero,
|
||||||
|
children: <Widget>[
|
||||||
|
CupertinoDesktopTextSelectionToolbarButton(
|
||||||
|
child: const Text('Tap me'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final BackdropFilter toolbarFilter = tester.firstWidget<BackdropFilter>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(CupertinoDesktopTextSelectionToolbar),
|
||||||
|
matching: find.byType(BackdropFilter),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
toolbarFilter.filter.runtimeType,
|
||||||
|
// _ComposeImageFilter is internal so we can't test if its filters are
|
||||||
|
// for blur and saturation, but checking if it's a _ComposeImageFilter
|
||||||
|
// should be enough. Outer and inner parameters don't matter, we just need
|
||||||
|
// a new _ComposeImageFilter to get its runtimeType.
|
||||||
|
//
|
||||||
|
// As web doesn't support ImageFilter.compose, we use just blur when
|
||||||
|
// kIsWeb.
|
||||||
|
kIsWeb
|
||||||
|
? ImageFilter.blur().runtimeType
|
||||||
|
: ImageFilter.compose(
|
||||||
|
outer: ImageFilter.blur(),
|
||||||
|
inner: ImageFilter.blur(),
|
||||||
|
).runtimeType,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('has shadow', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoDesktopTextSelectionToolbar(
|
||||||
|
anchor: Offset.zero,
|
||||||
|
children: <Widget>[
|
||||||
|
CupertinoDesktopTextSelectionToolbarButton(
|
||||||
|
child: const Text('Tap me'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final DecoratedBox decoratedBox = tester.firstWidget<DecoratedBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(CupertinoDesktopTextSelectionToolbar),
|
||||||
|
matching: find.byType(DecoratedBox),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(decoratedBox.decoration as BoxDecoration).boxShadow,
|
||||||
|
isNotNull,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('is translucent', (WidgetTester tester) async {
|
||||||
|
await tester.pumpWidget(
|
||||||
|
CupertinoApp(
|
||||||
|
home: Center(
|
||||||
|
child: CupertinoDesktopTextSelectionToolbar(
|
||||||
|
anchor: Offset.zero,
|
||||||
|
children: <Widget>[
|
||||||
|
CupertinoDesktopTextSelectionToolbarButton(
|
||||||
|
child: const Text('Tap me'),
|
||||||
|
onPressed: () {},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final DecoratedBox decoratedBox = tester
|
||||||
|
.widgetList<DecoratedBox>(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(CupertinoDesktopTextSelectionToolbar),
|
||||||
|
matching: find.byType(DecoratedBox),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
// The second DecoratedBox should be the one with color.
|
||||||
|
.elementAt(1);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
(decoratedBox.decoration as BoxDecoration).color!.opacity,
|
||||||
|
lessThan(1.0),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('positions itself at the anchor', (WidgetTester tester) async {
|
testWidgets('positions itself at the anchor', (WidgetTester tester) async {
|
||||||
// An arbitrary point on the screen to position at.
|
// An arbitrary point on the screen to position at.
|
||||||
const Offset anchor = Offset(30.0, 40.0);
|
const Offset anchor = Offset(30.0, 40.0);
|
||||||
@ -29,7 +137,8 @@ void main() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
tester.getTopLeft(find.byType(CupertinoDesktopTextSelectionToolbarButton)),
|
tester
|
||||||
|
.getTopLeft(find.byType(CupertinoDesktopTextSelectionToolbarButton)),
|
||||||
// Greater than due to padding internal to the toolbar.
|
// Greater than due to padding internal to the toolbar.
|
||||||
greaterThan(anchor),
|
greaterThan(anchor),
|
||||||
);
|
);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user