Unverified Commit da151c95 authored by LongCatIsLooong's avatar LongCatIsLooong Committed by GitHub

CupertinoAlertDialog dark mode & CupertinoActionSheet fidelity (#40007)

parent 609a78fd
...@@ -30,23 +30,6 @@ const TextStyle _kActionSheetContentStyle = TextStyle( ...@@ -30,23 +30,6 @@ const TextStyle _kActionSheetContentStyle = TextStyle(
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
); );
// This decoration is applied to the blurred backdrop to lighten the blurred
// image. Brightening is done to counteract the dark modal barrier that
// appears behind the alert. The overlay blend mode does the brightening.
// The white color doesn't paint any white, it's a placeholder and is going to be
// replaced by the resolved color of _kAlertBlurOverlayColor.
const BoxDecoration _kAlertBlurOverlayDecoration = BoxDecoration(
color: CupertinoColors.white,
backgroundBlendMode: BlendMode.overlay,
);
// Color of the overlay.
// Extracted from https://developer.apple.com/design/resources/.
const Color _kAlertBlurOverlayColor = CupertinoDynamicColor.withBrightness(
color: Color(0x66000000),
darkColor: Color(0x99000000),
);
// Translucent, very light gray that is painted on top of the blurred backdrop // Translucent, very light gray that is painted on top of the blurred backdrop
// as the action sheet's background color. // as the action sheet's background color.
// TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/39272. Use // TODO(LongCatIsLooong): https://github.com/flutter/flutter/issues/39272. Use
...@@ -224,13 +207,9 @@ class CupertinoActionSheet extends StatelessWidget { ...@@ -224,13 +207,9 @@ class CupertinoActionSheet extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<Widget> children = <Widget>[ final List<Widget> children = <Widget>[
Flexible(child: ClipRRect( Flexible(child: ClipRRect(
borderRadius: BorderRadius.circular(12.0), borderRadius: BorderRadius.circular(12.0),
child: BackdropFilter( child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: _kBlurAmount, sigmaY: _kBlurAmount), filter: ImageFilter.blur(sigmaX: _kBlurAmount, sigmaY: _kBlurAmount),
child: Container(
decoration: _kAlertBlurOverlayDecoration.copyWith(
color: CupertinoDynamicColor.resolve(_kAlertBlurOverlayColor, context),
),
child: _CupertinoAlertRenderWidget( child: _CupertinoAlertRenderWidget(
contentSection: Builder(builder: _buildContent), contentSection: Builder(builder: _buildContent),
actionsSection: _buildActions(), actionsSection: _buildActions(),
...@@ -238,15 +217,9 @@ class CupertinoActionSheet extends StatelessWidget { ...@@ -238,15 +217,9 @@ class CupertinoActionSheet extends StatelessWidget {
), ),
), ),
), ),
), if (cancelButton != null) _buildCancelButton(),
]; ];
if (cancelButton != null) {
children.add(
_buildCancelButton(),
);
}
final Orientation orientation = MediaQuery.of(context).orientation; final Orientation orientation = MediaQuery.of(context).orientation;
double actionSheetWidth; double actionSheetWidth;
if (orientation == Orientation.portrait) { if (orientation == Orientation.portrait) {
...@@ -420,14 +393,14 @@ class _CupertinoAlertRenderWidget extends RenderObjectWidget { ...@@ -420,14 +393,14 @@ class _CupertinoAlertRenderWidget extends RenderObjectWidget {
RenderObject createRenderObject(BuildContext context) { RenderObject createRenderObject(BuildContext context) {
return _RenderCupertinoAlert( return _RenderCupertinoAlert(
dividerThickness: _kDividerThickness / MediaQuery.of(context).devicePixelRatio, dividerThickness: _kDividerThickness / MediaQuery.of(context).devicePixelRatio,
dividerColor: _kButtonDividerColor, dividerColor: CupertinoDynamicColor.resolve(_kButtonDividerColor, context),
); );
} }
@override @override
void updateRenderObject(BuildContext context, _RenderCupertinoAlert renderObject) { void updateRenderObject(BuildContext context, _RenderCupertinoAlert renderObject) {
super.updateRenderObject(context, renderObject); super.updateRenderObject(context, renderObject);
renderObject.dividerColor = _kButtonDividerColor; renderObject.dividerColor = CupertinoDynamicColor.resolve(_kButtonDividerColor, context);
} }
@override @override
...@@ -1034,7 +1007,7 @@ class _CupertinoAlertActionsRenderWidget extends MultiChildRenderObjectWidget { ...@@ -1034,7 +1007,7 @@ class _CupertinoAlertActionsRenderWidget extends MultiChildRenderObjectWidget {
RenderObject createRenderObject(BuildContext context) { RenderObject createRenderObject(BuildContext context) {
return _RenderCupertinoAlertActions( return _RenderCupertinoAlertActions(
dividerThickness: _dividerThickness, dividerThickness: _dividerThickness,
dividerColor: _kButtonDividerColor, dividerColor: CupertinoDynamicColor.resolve(_kButtonDividerColor, context),
hasCancelButton: _hasCancelButton, hasCancelButton: _hasCancelButton,
backgroundColor: CupertinoDynamicColor.resolve(_kBackgroundColor, context), backgroundColor: CupertinoDynamicColor.resolve(_kBackgroundColor, context),
pressedColor: CupertinoDynamicColor.resolve(_kPressedColor, context), pressedColor: CupertinoDynamicColor.resolve(_kPressedColor, context),
...@@ -1045,7 +1018,7 @@ class _CupertinoAlertActionsRenderWidget extends MultiChildRenderObjectWidget { ...@@ -1045,7 +1018,7 @@ class _CupertinoAlertActionsRenderWidget extends MultiChildRenderObjectWidget {
void updateRenderObject(BuildContext context, _RenderCupertinoAlertActions renderObject) { void updateRenderObject(BuildContext context, _RenderCupertinoAlertActions renderObject) {
renderObject renderObject
..dividerThickness = _dividerThickness ..dividerThickness = _dividerThickness
..dividerColor = _kButtonDividerColor ..dividerColor = CupertinoDynamicColor.resolve(_kButtonDividerColor, context)
..hasCancelButton = _hasCancelButton ..hasCancelButton = _hasCancelButton
..backgroundColor = CupertinoDynamicColor.resolve(_kBackgroundColor, context) ..backgroundColor = CupertinoDynamicColor.resolve(_kBackgroundColor, context)
..pressedColor = CupertinoDynamicColor.resolve(_kPressedColor, context); ..pressedColor = CupertinoDynamicColor.resolve(_kPressedColor, context);
......
...@@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart'; ...@@ -10,6 +10,7 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'colors.dart'; import 'colors.dart';
import 'interface_level.dart';
import 'localizations.dart'; import 'localizations.dart';
import 'scrollbar.dart'; import 'scrollbar.dart';
...@@ -20,7 +21,6 @@ const TextStyle _kCupertinoDialogTitleStyle = TextStyle( ...@@ -20,7 +21,6 @@ const TextStyle _kCupertinoDialogTitleStyle = TextStyle(
inherit: false, inherit: false,
fontSize: 18.0, fontSize: 18.0,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: CupertinoColors.black,
letterSpacing: 0.48, letterSpacing: 0.48,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
); );
...@@ -30,7 +30,6 @@ const TextStyle _kCupertinoDialogContentStyle = TextStyle( ...@@ -30,7 +30,6 @@ const TextStyle _kCupertinoDialogContentStyle = TextStyle(
inherit: false, inherit: false,
fontSize: 13.4, fontSize: 13.4,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: CupertinoColors.black,
height: 1.036, height: 1.036,
letterSpacing: -0.25, letterSpacing: -0.25,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
...@@ -41,7 +40,6 @@ const TextStyle _kCupertinoDialogActionStyle = TextStyle( ...@@ -41,7 +40,6 @@ const TextStyle _kCupertinoDialogActionStyle = TextStyle(
inherit: false, inherit: false,
fontSize: 16.8, fontSize: 16.8,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: CupertinoColors.activeBlue,
textBaseline: TextBaseline.alphabetic, textBaseline: TextBaseline.alphabetic,
); );
...@@ -51,35 +49,28 @@ const TextStyle _kCupertinoDialogActionStyle = TextStyle( ...@@ -51,35 +49,28 @@ const TextStyle _kCupertinoDialogActionStyle = TextStyle(
const double _kCupertinoDialogWidth = 270.0; const double _kCupertinoDialogWidth = 270.0;
const double _kAccessibilityCupertinoDialogWidth = 310.0; const double _kAccessibilityCupertinoDialogWidth = 310.0;
// _kCupertinoDialogBlurOverlayDecoration is applied to the blurred backdrop to
// lighten the blurred image. Brightening is done to counteract the dark modal
// barrier that appears behind the dialog. The overlay blend mode does the
// brightening. The white color doesn't paint any white, it's just the basis
// for the overlay blend mode.
const BoxDecoration _kCupertinoDialogBlurOverlayDecoration = BoxDecoration(
color: CupertinoColors.white,
backgroundBlendMode: BlendMode.overlay,
);
const double _kBlurAmount = 20.0; const double _kBlurAmount = 20.0;
const double _kEdgePadding = 20.0; const double _kEdgePadding = 20.0;
const double _kMinButtonHeight = 45.0; const double _kMinButtonHeight = 45.0;
const double _kMinButtonFontSize = 10.0; const double _kMinButtonFontSize = 10.0;
const double _kDialogCornerRadius = 12.0; const double _kDialogCornerRadius = 14.0;
const double _kDividerThickness = 1.0; const double _kDividerThickness = 1.0;
// Translucent white that is painted on top of the blurred backdrop as the // A translucent color that is painted on top of the blurred backdrop as the
// dialog's background color. // dialog's background color
const Color _kDialogColor = Color(0xC0FFFFFF); // Extracted from https://developer.apple.com/design/resources/.
const Color _kDialogColor = CupertinoDynamicColor.withBrightness(
color: Color(0xCCF2F2F2),
darkColor: Color(0xBF1E1E1E),
);
// Translucent white that is painted on top of the blurred backdrop as the // Translucent light gray that is painted on top of the blurred backdrop as the
// background color of a pressed button. // background color of a pressed button.
const Color _kDialogPressedColor = Color(0x90FFFFFF); // Eyeballed from iOS 13 beta simulator.
const Color _kDialogPressedColor = CupertinoDynamicColor.withBrightness(
// Translucent white that is painted on top of the blurred backdrop in the color: Color(0xFFE1E1E1),
// gap areas between the content section and actions section, as well as between darkColor: Color(0xFF2E2E2E),
// buttons. );
const Color _kButtonDividerColor = Color(0x40FFFFFF);
// The alert dialog layout policy changes depending on whether the user is using // The alert dialog layout policy changes depending on whether the user is using
// a "regular" font size vs a "large" font size. This is a spectrum. There are // a "regular" font size vs a "large" font size. This is a spectrum. There are
...@@ -182,7 +173,7 @@ class CupertinoAlertDialog extends StatelessWidget { ...@@ -182,7 +173,7 @@ class CupertinoAlertDialog extends StatelessWidget {
/// section when it is long. /// section when it is long.
final ScrollController actionScrollController; final ScrollController actionScrollController;
Widget _buildContent() { Widget _buildContent(BuildContext context) {
final List<Widget> children = <Widget>[]; final List<Widget> children = <Widget>[];
if (title != null || content != null) { if (title != null || content != null) {
...@@ -195,7 +186,7 @@ class CupertinoAlertDialog extends StatelessWidget { ...@@ -195,7 +186,7 @@ class CupertinoAlertDialog extends StatelessWidget {
} }
return Container( return Container(
color: _kDialogColor, color: CupertinoDynamicColor.resolve(_kDialogColor, context),
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
...@@ -223,35 +214,38 @@ class CupertinoAlertDialog extends StatelessWidget { ...@@ -223,35 +214,38 @@ class CupertinoAlertDialog extends StatelessWidget {
final CupertinoLocalizations localizations = CupertinoLocalizations.of(context); final CupertinoLocalizations localizations = CupertinoLocalizations.of(context);
final bool isInAccessibilityMode = _isInAccessibilityMode(context); final bool isInAccessibilityMode = _isInAccessibilityMode(context);
final double textScaleFactor = MediaQuery.of(context).textScaleFactor; final double textScaleFactor = MediaQuery.of(context).textScaleFactor;
return MediaQuery( return CupertinoUserInterfaceLevel(
data: MediaQuery.of(context).copyWith( data: CupertinoUserInterfaceLevelData.elevated,
// iOS does not shrink dialog content below a 1.0 scale factor child: MediaQuery(
textScaleFactor: math.max(textScaleFactor, 1.0), data: MediaQuery.of(context).copyWith(
), // iOS does not shrink dialog content below a 1.0 scale factor
child: LayoutBuilder( textScaleFactor: math.max(textScaleFactor, 1.0),
builder: (BuildContext context, BoxConstraints constraints) { ),
return Center( child: LayoutBuilder(
child: Container( builder: (BuildContext context, BoxConstraints constraints) {
margin: const EdgeInsets.symmetric(vertical: _kEdgePadding), return Center(
width: isInAccessibilityMode child: Container(
margin: const EdgeInsets.symmetric(vertical: _kEdgePadding),
width: isInAccessibilityMode
? _kAccessibilityCupertinoDialogWidth ? _kAccessibilityCupertinoDialogWidth
: _kCupertinoDialogWidth, : _kCupertinoDialogWidth,
child: CupertinoPopupSurface( child: CupertinoPopupSurface(
isSurfacePainted: false, isSurfacePainted: false,
child: Semantics( child: Semantics(
namesRoute: true, namesRoute: true,
scopesRoute: true, scopesRoute: true,
explicitChildNodes: true, explicitChildNodes: true,
label: localizations.alertDialogLabel, label: localizations.alertDialogLabel,
child: _CupertinoDialogRenderWidget( child: _CupertinoDialogRenderWidget(
contentSection: _buildContent(), contentSection: _buildContent(context),
actionsSection: _buildActions(), actionsSection: _buildActions(),
),
), ),
), ),
), ),
), );
); },
}, ),
), ),
); );
} }
...@@ -338,11 +332,8 @@ class CupertinoPopupSurface extends StatelessWidget { ...@@ -338,11 +332,8 @@ class CupertinoPopupSurface extends StatelessWidget {
child: BackdropFilter( child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: _kBlurAmount, sigmaY: _kBlurAmount), filter: ImageFilter.blur(sigmaX: _kBlurAmount, sigmaY: _kBlurAmount),
child: Container( child: Container(
decoration: _kCupertinoDialogBlurOverlayDecoration, color: isSurfacePainted ? CupertinoDynamicColor.resolve(_kDialogColor, context) : null,
child: Container( child: child,
color: isSurfacePainted ? _kDialogColor : null,
child: child,
),
), ),
), ),
); );
...@@ -368,12 +359,15 @@ class _CupertinoDialogRenderWidget extends RenderObjectWidget { ...@@ -368,12 +359,15 @@ class _CupertinoDialogRenderWidget extends RenderObjectWidget {
return _RenderCupertinoDialog( return _RenderCupertinoDialog(
dividerThickness: _kDividerThickness / MediaQuery.of(context).devicePixelRatio, dividerThickness: _kDividerThickness / MediaQuery.of(context).devicePixelRatio,
isInAccessibilityMode: _isInAccessibilityMode(context), isInAccessibilityMode: _isInAccessibilityMode(context),
dividerColor: CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).separator, context),
); );
} }
@override @override
void updateRenderObject(BuildContext context, _RenderCupertinoDialog renderObject) { void updateRenderObject(BuildContext context, _RenderCupertinoDialog renderObject) {
renderObject.isInAccessibilityMode = _isInAccessibilityMode(context); renderObject
..isInAccessibilityMode = _isInAccessibilityMode(context)
..dividerColor = CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).separator, context);
} }
@override @override
...@@ -489,10 +483,15 @@ class _RenderCupertinoDialog extends RenderBox { ...@@ -489,10 +483,15 @@ class _RenderCupertinoDialog extends RenderBox {
RenderBox actionsSection, RenderBox actionsSection,
double dividerThickness = 0.0, double dividerThickness = 0.0,
bool isInAccessibilityMode = false, bool isInAccessibilityMode = false,
Color dividerColor,
}) : _contentSection = contentSection, }) : _contentSection = contentSection,
_actionsSection = actionsSection, _actionsSection = actionsSection,
_dividerThickness = dividerThickness, _dividerThickness = dividerThickness,
_isInAccessibilityMode = isInAccessibilityMode; _isInAccessibilityMode = isInAccessibilityMode,
_dividerPaint = Paint()
..color = dividerColor
..style = PaintingStyle.fill;
RenderBox get contentSection => _contentSection; RenderBox get contentSection => _contentSection;
RenderBox _contentSection; RenderBox _contentSection;
...@@ -536,10 +535,17 @@ class _RenderCupertinoDialog extends RenderBox { ...@@ -536,10 +535,17 @@ class _RenderCupertinoDialog extends RenderBox {
: _kCupertinoDialogWidth; : _kCupertinoDialogWidth;
final double _dividerThickness; final double _dividerThickness;
final Paint _dividerPaint;
Color get dividerColor => _dividerPaint.color;
set dividerColor(Color newValue) {
if (dividerColor == newValue) {
return;
}
final Paint _dividerPaint = Paint() _dividerPaint.color = newValue;
..color = _kButtonDividerColor markNeedsPaint();
..style = PaintingStyle.fill; }
@override @override
void attach(PipelineOwner owner) { void attach(PipelineOwner owner) {
...@@ -838,26 +844,32 @@ class _CupertinoAlertContentSection extends StatelessWidget { ...@@ -838,26 +844,32 @@ class _CupertinoAlertContentSection extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final double textScaleFactor = MediaQuery.of(context).textScaleFactor; if (title == null && content == null) {
final List<Widget> titleContentGroup = <Widget>[]; return SingleChildScrollView(
if (title != null) { controller: scrollController,
titleContentGroup.add(Padding( child: Container(width: 0.0, height: 0.0),
padding: EdgeInsets.only( );
left: _kEdgePadding,
right: _kEdgePadding,
bottom: content == null ? _kEdgePadding : 1.0,
top: _kEdgePadding * textScaleFactor,
),
child: DefaultTextStyle(
style: _kCupertinoDialogTitleStyle,
textAlign: TextAlign.center,
child: title,
),
));
} }
if (content != null) { final double textScaleFactor = MediaQuery.of(context).textScaleFactor;
titleContentGroup.add( final List<Widget> titleContentGroup = <Widget>[
if (title != null)
Padding(
padding: EdgeInsets.only(
left: _kEdgePadding,
right: _kEdgePadding,
bottom: content == null ? _kEdgePadding : 1.0,
top: _kEdgePadding * textScaleFactor,
),
child: DefaultTextStyle(
style: _kCupertinoDialogTitleStyle.copyWith(
color: CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).label, context),
),
textAlign: TextAlign.center,
child: title,
),
),
if (content != null)
Padding( Padding(
padding: EdgeInsets.only( padding: EdgeInsets.only(
left: _kEdgePadding, left: _kEdgePadding,
...@@ -866,20 +878,14 @@ class _CupertinoAlertContentSection extends StatelessWidget { ...@@ -866,20 +878,14 @@ class _CupertinoAlertContentSection extends StatelessWidget {
top: title == null ? _kEdgePadding : 1.0, top: title == null ? _kEdgePadding : 1.0,
), ),
child: DefaultTextStyle( child: DefaultTextStyle(
style: _kCupertinoDialogContentStyle, style: _kCupertinoDialogContentStyle.copyWith(
color: CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).label, context),
),
textAlign: TextAlign.center, textAlign: TextAlign.center,
child: content, child: content,
), ),
), ),
); ];
}
if (titleContentGroup.isEmpty) {
return SingleChildScrollView(
controller: scrollController,
child: Container(width: 0.0, height: 0.0),
);
}
return CupertinoScrollbar( return CupertinoScrollbar(
child: SingleChildScrollView( child: SingleChildScrollView(
...@@ -1155,17 +1161,18 @@ class CupertinoDialogAction extends StatelessWidget { ...@@ -1155,17 +1161,18 @@ class CupertinoDialogAction extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
TextStyle style = _kCupertinoDialogActionStyle; TextStyle style = _kCupertinoDialogActionStyle.copyWith(
color: CupertinoDynamicColor.resolve(
isDestructiveAction ? CupertinoSystemColors.of(context).systemRed : CupertinoSystemColors.of(context).systemBlue,
context
),
);
style = style.merge(textStyle); style = style.merge(textStyle);
if (isDefaultAction) { if (isDefaultAction) {
style = style.copyWith(fontWeight: FontWeight.w600); style = style.copyWith(fontWeight: FontWeight.w600);
} }
if (isDestructiveAction) {
style = style.copyWith(color: CupertinoColors.destructiveRed);
}
if (!enabled) { if (!enabled) {
style = style.copyWith(color: style.color.withOpacity(0.5)); style = style.copyWith(color: style.color.withOpacity(0.5));
} }
...@@ -1229,15 +1236,22 @@ class _CupertinoDialogActionsRenderWidget extends MultiChildRenderObjectWidget { ...@@ -1229,15 +1236,22 @@ class _CupertinoDialogActionsRenderWidget extends MultiChildRenderObjectWidget {
? _kAccessibilityCupertinoDialogWidth ? _kAccessibilityCupertinoDialogWidth
: _kCupertinoDialogWidth, : _kCupertinoDialogWidth,
dividerThickness: _dividerThickness, dividerThickness: _dividerThickness,
dialogColor: CupertinoDynamicColor.resolve(_kDialogColor, context),
dialogPressedColor: CupertinoDynamicColor.resolve(_kDialogPressedColor, context),
dividerColor: CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).separator, context),
); );
} }
@override @override
void updateRenderObject(BuildContext context, _RenderCupertinoDialogActions renderObject) { void updateRenderObject(BuildContext context, _RenderCupertinoDialogActions renderObject) {
renderObject.dialogWidth = _isInAccessibilityMode(context) renderObject
? _kAccessibilityCupertinoDialogWidth ..dialogWidth = _isInAccessibilityMode(context)
: _kCupertinoDialogWidth; ? _kAccessibilityCupertinoDialogWidth
renderObject.dividerThickness = _dividerThickness; : _kCupertinoDialogWidth
..dividerThickness = _dividerThickness
..dialogColor = CupertinoDynamicColor.resolve(_kDialogColor, context)
..dialogPressedColor = CupertinoDynamicColor.resolve(_kDialogPressedColor, context)
..dividerColor = CupertinoDynamicColor.resolve(CupertinoSystemColors.of(context).separator, context);
} }
} }
...@@ -1282,7 +1296,19 @@ class _RenderCupertinoDialogActions extends RenderBox ...@@ -1282,7 +1296,19 @@ class _RenderCupertinoDialogActions extends RenderBox
List<RenderBox> children, List<RenderBox> children,
@required double dialogWidth, @required double dialogWidth,
double dividerThickness = 0.0, double dividerThickness = 0.0,
@required Color dialogColor,
@required Color dialogPressedColor,
@required Color dividerColor,
}) : _dialogWidth = dialogWidth, }) : _dialogWidth = dialogWidth,
_buttonBackgroundPaint = Paint()
..color = dialogColor
..style = PaintingStyle.fill,
_pressedButtonBackgroundPaint = Paint()
..color = dialogPressedColor
..style = PaintingStyle.fill,
_dividerPaint = Paint()
..color = dividerColor
..style = PaintingStyle.fill,
_dividerThickness = dividerThickness { _dividerThickness = dividerThickness {
addAll(children); addAll(children);
} }
...@@ -1306,17 +1332,32 @@ class _RenderCupertinoDialogActions extends RenderBox ...@@ -1306,17 +1332,32 @@ class _RenderCupertinoDialogActions extends RenderBox
} }
} }
final Paint _buttonBackgroundPaint = Paint() final Paint _buttonBackgroundPaint;
..color = _kDialogColor set dialogColor(Color value) {
..style = PaintingStyle.fill; if (value == _buttonBackgroundPaint.color)
return;
_buttonBackgroundPaint.color = value;
markNeedsPaint();
}
final Paint _pressedButtonBackgroundPaint = Paint() final Paint _pressedButtonBackgroundPaint;
..color = _kDialogPressedColor set dialogPressedColor(Color value) {
..style = PaintingStyle.fill; if (value == _pressedButtonBackgroundPaint.color)
return;
final Paint _dividerPaint = Paint() _pressedButtonBackgroundPaint.color = value;
..color = _kButtonDividerColor markNeedsPaint();
..style = PaintingStyle.fill; }
final Paint _dividerPaint;
set dividerColor(Color value) {
if (value == _dividerPaint.color)
return;
_dividerPaint.color = value;
markNeedsPaint();
}
Iterable<RenderBox> get _pressedButtons sync* { Iterable<RenderBox> get _pressedButtons sync* {
RenderBox currentChild = firstChild; RenderBox currentChild = firstChild;
......
...@@ -12,6 +12,8 @@ import 'package:flutter/rendering.dart'; ...@@ -12,6 +12,8 @@ import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
import 'package:flutter/animation.dart' show Curves; import 'package:flutter/animation.dart' show Curves;
import 'colors.dart';
const double _kBackGestureWidth = 20.0; const double _kBackGestureWidth = 20.0;
const double _kMinFlingVelocity = 1.0; // Screen widths per second. const double _kMinFlingVelocity = 1.0; // Screen widths per second.
...@@ -24,7 +26,11 @@ const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds. ...@@ -24,7 +26,11 @@ const int _kMaxDroppedSwipePageForwardAnimationTime = 800; // Milliseconds.
const int _kMaxPageBackAnimationTime = 300; // Milliseconds. const int _kMaxPageBackAnimationTime = 300; // Milliseconds.
// Barrier color for a Cupertino modal barrier. // Barrier color for a Cupertino modal barrier.
const Color _kModalBarrierColor = Color(0x6604040F); // Extracted from https://developer.apple.com/design/resources/.
const Color _kModalBarrierColor = CupertinoDynamicColor.withBrightness(
color: Color(0x33000000),
darkColor: Color(0x7A000000),
);
// The duration of the transition used when a modal popup is shown. // The duration of the transition used when a modal popup is shown.
const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335); const Duration _kModalPopupTransitionDuration = Duration(milliseconds: 335);
...@@ -788,6 +794,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> { ...@@ -788,6 +794,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
_CupertinoModalPopupRoute({ _CupertinoModalPopupRoute({
this.builder, this.builder,
this.barrierLabel, this.barrierLabel,
this.barrierColor,
RouteSettings settings, RouteSettings settings,
}) : super(settings: settings); }) : super(settings: settings);
...@@ -797,7 +804,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> { ...@@ -797,7 +804,7 @@ class _CupertinoModalPopupRoute<T> extends PopupRoute<T> {
final String barrierLabel; final String barrierLabel;
@override @override
Color get barrierColor => _kModalBarrierColor; final Color barrierColor;
@override @override
bool get barrierDismissible => true; bool get barrierDismissible => true;
...@@ -879,6 +886,7 @@ Future<T> showCupertinoModalPopup<T>({ ...@@ -879,6 +886,7 @@ Future<T> showCupertinoModalPopup<T>({
_CupertinoModalPopupRoute<T>( _CupertinoModalPopupRoute<T>(
builder: builder, builder: builder,
barrierLabel: 'Dismiss', barrierLabel: 'Dismiss',
barrierColor: CupertinoDynamicColor.resolve(_kModalBarrierColor, context),
), ),
); );
} }
...@@ -947,7 +955,7 @@ Future<T> showCupertinoDialog<T>({ ...@@ -947,7 +955,7 @@ Future<T> showCupertinoDialog<T>({
return showGeneralDialog( return showGeneralDialog(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
barrierColor: _kModalBarrierColor, barrierColor: CupertinoDynamicColor.resolve(_kModalBarrierColor, context),
// This transition duration was eyeballed comparing with iOS // This transition duration was eyeballed comparing with iOS
transitionDuration: const Duration(milliseconds: 250), transitionDuration: const Duration(milliseconds: 250),
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
......
...@@ -7,7 +7,6 @@ import 'package:flutter/widgets.dart'; ...@@ -7,7 +7,6 @@ import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import '../rendering/mock_canvas.dart';
import '../widgets/semantics_tester.dart'; import '../widgets/semantics_tester.dart';
void main() { void main() {
...@@ -113,8 +112,6 @@ void main() { ...@@ -113,8 +112,6 @@ void main() {
await tester.tap(find.text('Go')); await tester.tap(find.text('Go'));
await tester.pump(); await tester.pump();
// Draw the overlay using the light variant.
expect(find.byType(CupertinoActionSheet), paints..rect(color: const Color(0x66000000)));
expect( expect(
actionTextStyle('action').color.value, actionTextStyle('action').color.value,
const Color.fromARGB(255, 0, 122, 255).value, const Color.fromARGB(255, 0, 122, 255).value,
...@@ -123,8 +120,6 @@ void main() { ...@@ -123,8 +120,6 @@ void main() {
stateSetter(() { brightness = Brightness.dark; }); stateSetter(() { brightness = Brightness.dark; });
await tester.pump(); await tester.pump();
// Draw the overlay using the dark variant.
expect(find.byType(CupertinoActionSheet), paints..rect(color: const Color(0x99000000)));
expect( expect(
actionTextStyle('action').color.value, actionTextStyle('action').color.value,
const Color.fromARGB(255, 10, 132, 255).value, const Color.fromARGB(255, 10, 132, 255).value,
......
...@@ -63,6 +63,38 @@ void main() { ...@@ -63,6 +63,38 @@ void main() {
expect(widget.style.color.withAlpha(255), CupertinoColors.destructiveRed); expect(widget.style.color.withAlpha(255), CupertinoColors.destructiveRed);
}); });
testWidgets('Dialog dark theme', (WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: MediaQuery(
data: const MediaQueryData(platformBrightness: Brightness.dark),
child: CupertinoAlertDialog(
title: const Text('The Title'),
content: const Text('Content'),
actions: <Widget>[
CupertinoDialogAction(child: const Text('Cancel'), isDefaultAction: true, onPressed: () {}),
const CupertinoDialogAction(child: Text('OK')),
],
),
),
),
);
final RichText cancelText = tester.widget<RichText>(
find.descendant(of: find.text('Cancel'), matching: find.byType(RichText)),
);
expect(
cancelText.text.style.color.value,
0xFF0A84FF, // dark elevated color of systemBlue.
);
expect(
find.byType(CupertinoAlertDialog),
paints..rect(color: const Color(0xBF1E1E1E)),
);
});
testWidgets('Has semantic annotations', (WidgetTester tester) async { testWidgets('Has semantic annotations', (WidgetTester tester) async {
final SemanticsTester semantics = SemanticsTester(tester); final SemanticsTester semantics = SemanticsTester(tester);
await tester.pumpWidget(const MaterialApp(home: Material( await tester.pumpWidget(const MaterialApp(home: Material(
...@@ -739,8 +771,8 @@ void main() { ...@@ -739,8 +771,8 @@ void main() {
await tester.tap(find.text('Go')); await tester.tap(find.text('Go'));
await tester.pump(); await tester.pump();
const Color normalButtonBackgroundColor = Color(0xc0ffffff); const Color normalButtonBackgroundColor = Color(0xCCF2F2F2);
const Color pressedButtonBackgroundColor = Color(0x90ffffff); const Color pressedButtonBackgroundColor = Color(0xFFE1E1E1);
final RenderBox firstButtonBox = findActionButtonRenderBoxByTitle(tester, 'Option 1'); final RenderBox firstButtonBox = findActionButtonRenderBoxByTitle(tester, 'Option 1');
final RenderBox secondButtonBox = findActionButtonRenderBoxByTitle(tester, 'Option 2'); final RenderBox secondButtonBox = findActionButtonRenderBoxByTitle(tester, 'Option 2');
final RenderBox actionsSectionBox = findScrollableActionsSectionRenderBox(tester); final RenderBox actionsSectionBox = findScrollableActionsSectionRenderBox(tester);
......
...@@ -743,6 +743,79 @@ void main() { ...@@ -743,6 +743,79 @@ void main() {
false, false,
); );
}); });
testWidgets('ModalPopup overlay dark mode', (WidgetTester tester) async {
StateSetter stateSetter;
Brightness brightness = Brightness.light;
await tester.pumpWidget(
StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
stateSetter = setter;
return CupertinoApp(
theme: CupertinoThemeData(brightness: brightness),
home: CupertinoPageScaffold(
child: Builder(builder: (BuildContext context) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
}),
),
);
},
),
);
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(
tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color.value,
0x33000000,
);
stateSetter(() { brightness = Brightness.dark; });
await tester.pump();
// TODO(LongCatIsLooong): The background overlay SHOULD switch to dark color.
expect(
tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color.value,
0x33000000,
);
await tester.pumpWidget(
CupertinoApp(
theme: const CupertinoThemeData(brightness: Brightness.dark),
home: CupertinoPageScaffold(
child: Builder(builder: (BuildContext context) {
return GestureDetector(
onTap: () async {
await showCupertinoModalPopup<void>(
context: context,
builder: (BuildContext context) => const SizedBox(),
);
},
child: const Text('tap'),
);
}),
),
),
);
await tester.tap(find.text('tap'));
await tester.pumpAndSettle();
expect(
tester.widget<ModalBarrier>(find.byType(ModalBarrier).last).color.value,
0x7A000000,
);
});
} }
class MockNavigatorObserver extends Mock implements NavigatorObserver {} class MockNavigatorObserver extends Mock implements NavigatorObserver {}
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