您最多选择25个主题 主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

1617 行
64 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using uiwidgets;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.async;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Canvas = Unity.UIWidgets.ui.Canvas;
using Color = Unity.UIWidgets.ui.Color;
using Rect = Unity.UIWidgets.ui.Rect;
using TextStyle = Unity.UIWidgets.painting.TextStyle;
namespace Unity.UIWidgets.material {
public static class TimePickerUtils {
public static readonly TimeSpan _kDialAnimateDuration = new TimeSpan(0, 0, 0, 0, 200);
public const float _kTwoPi = 2 * Mathf.PI;
public static readonly TimeSpan _kVibrateCommitDelay = new TimeSpan(0, 0, 0, 0, milliseconds: 100);
public const float _kTimePickerHeaderPortraitHeight = 96.0f;
public const float _kTimePickerHeaderLandscapeWidth = 168.0f;
public const float _kTimePickerWidthPortrait = 328.0f;
public const float _kTimePickerWidthLandscape = 512.0f;
public const float _kTimePickerHeightPortrait = 496.0f;
public const float _kTimePickerHeightLandscape = 316.0f;
public const float _kTimePickerHeightPortraitCollapsed = 484.0f;
public const float _kTimePickerHeightLandscapeCollapsed = 304.0f;
public static readonly BoxConstraints _kMinTappableRegion = new BoxConstraints(minWidth: 48, minHeight: 48);
public static _TimePickerHeaderFormat _buildHeaderFormat(
TimeOfDayFormat timeOfDayFormat,
_TimePickerFragmentContext context,
Orientation orientation
) {
_TimePickerHeaderFragment hour() {
return new _TimePickerHeaderFragment(
layoutId: _TimePickerHeaderId.hour,
widget: new _HourControl(fragmentContext: context)
);
}
_TimePickerHeaderFragment minute() {
return new _TimePickerHeaderFragment(
layoutId: _TimePickerHeaderId.minute,
widget: new _MinuteControl(fragmentContext: context)
);
}
_TimePickerHeaderFragment getString(_TimePickerHeaderId layoutId, string value) {
return new _TimePickerHeaderFragment(
layoutId: layoutId,
widget: new _StringFragment(
fragmentContext: context,
value: value
)
);
}
_TimePickerHeaderFragment dayPeriod() {
return new _TimePickerHeaderFragment(
layoutId: _TimePickerHeaderId.period,
widget: new _DayPeriodControl(fragmentContext: context, orientation: orientation)
);
}
_TimePickerHeaderFormat format(
_TimePickerHeaderPiece piece1,
_TimePickerHeaderPiece piece2 = null
) {
List<_TimePickerHeaderPiece> pieces = new List<_TimePickerHeaderPiece>();
switch (context.textDirection) {
case TextDirection.ltr:
pieces.Add(piece1);
if (piece2 != null) {
pieces.Add(piece2);
}
break;
case TextDirection.rtl:
if (piece2 != null) {
pieces.Add(piece2);
}
pieces.Add(piece1);
break;
}
int? centerpieceIndex = null;
for (int i = 0; i < pieces.Count; i += 1) {
if (pieces[i].pivotIndex >= 0) {
centerpieceIndex = i;
}
}
D.assert(centerpieceIndex != null);
return new _TimePickerHeaderFormat(centerpieceIndex.Value, pieces);
}
_TimePickerHeaderPiece piece(
int pivotIndex = -1,
float bottomMargin = 0.0f,
_TimePickerHeaderFragment fragment1 = null,
_TimePickerHeaderFragment fragment2 = null,
_TimePickerHeaderFragment fragment3 = null
) {
List<_TimePickerHeaderFragment> fragments = new List<_TimePickerHeaderFragment> {fragment1};
if (fragment2 != null) {
fragments.Add(fragment2);
if (fragment3 != null) {
fragments.Add(fragment3);
}
}
return new _TimePickerHeaderPiece(pivotIndex, fragments, bottomMargin: bottomMargin);
}
switch (timeOfDayFormat) {
case TimeOfDayFormat.h_colon_mm_space_a:
return format(
piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.colon, ":"),
fragment3: minute()
),
piece(
fragment1: dayPeriod()
)
);
case TimeOfDayFormat.H_colon_mm:
return format(piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.colon, ":"),
fragment3: minute()
));
case TimeOfDayFormat.HH_dot_mm:
return format(piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.dot, "."),
fragment3: minute()
));
case TimeOfDayFormat.a_space_h_colon_mm:
return format(
piece(
fragment1: dayPeriod()
),
piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.colon, ":"),
fragment3: minute()
)
);
case TimeOfDayFormat.frenchCanadian:
return format(piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.hString, "h"),
fragment3: minute()
));
case TimeOfDayFormat.HH_colon_mm:
return format(piece(
pivotIndex: 1,
fragment1: hour(),
fragment2: getString(_TimePickerHeaderId.colon, ":"),
fragment3: minute()
));
}
return null;
}
public static Future<TimeOfDay> showTimePicker(
BuildContext context,
TimeOfDay initialTime,
TransitionBuilder builder = null,
bool useRootNavigator = true,
RouteSettings routeSettings = null
) {
D.assert(context != null);
D.assert(initialTime != null);
D.assert(material_.debugCheckHasMaterialLocalizations(context));
Widget dialog = new _TimePickerDialog(initialTime: initialTime);
return material_.showDialog<TimeOfDay>(
context: context,
useRootNavigator: useRootNavigator,
builder: (BuildContext subContext) => {
return builder == null ? dialog : builder(subContext, dialog);
},
routeSettings: routeSettings
);
}
}
public enum _TimePickerMode {
hour,
minute
}
public enum _TimePickerHeaderId {
hour,
colon,
minute,
period, // AM/PM picker
dot,
hString, // French Canadian "h" literal
}
public class _TimePickerFragmentContext {
public _TimePickerFragmentContext(
TextTheme headerTextTheme = null,
TextDirection? textDirection = null,
TimeOfDay selectedTime = null,
_TimePickerMode? mode = null,
Color activeColor = null,
TextStyle activeStyle = null,
Color inactiveColor = null,
TextStyle inactiveStyle = null,
ValueChanged<TimeOfDay> onTimeChange = null,
ValueChanged<_TimePickerMode> onModeChange = null,
RuntimePlatform? targetPlatform = null,
bool? use24HourDials = null
) {
D.assert(headerTextTheme != null);
D.assert(textDirection != null);
D.assert(selectedTime != null);
D.assert(mode != null);
D.assert(activeColor != null);
D.assert(activeStyle != null);
D.assert(inactiveColor != null);
D.assert(inactiveStyle != null);
D.assert(onTimeChange != null);
D.assert(onModeChange != null);
D.assert(targetPlatform != null);
D.assert(use24HourDials != null);
this.headerTextTheme = headerTextTheme;
this.textDirection = textDirection.Value;
this.selectedTime = selectedTime;
this.mode = mode.Value;
this.activeColor = activeColor;
this.activeStyle = activeStyle;
this.inactiveColor = inactiveColor;
this.inactiveStyle = inactiveStyle;
this.onTimeChange = onTimeChange;
this.onModeChange = onModeChange;
this.targetPlatform = targetPlatform.Value;
this.use24HourDials = use24HourDials.Value;
}
public readonly TextTheme headerTextTheme;
public readonly TextDirection textDirection;
public readonly TimeOfDay selectedTime;
public readonly _TimePickerMode mode;
public readonly Color activeColor;
public readonly TextStyle activeStyle;
public readonly Color inactiveColor;
public readonly TextStyle inactiveStyle;
public readonly ValueChanged<TimeOfDay> onTimeChange;
public readonly ValueChanged<_TimePickerMode> onModeChange;
public readonly RuntimePlatform targetPlatform;
public readonly bool use24HourDials;
}
public class _TimePickerHeaderFragment {
public _TimePickerHeaderFragment(
_TimePickerHeaderId? layoutId = null,
Widget widget = null,
float startMargin = 0.0f
) {
D.assert(layoutId != null);
D.assert(widget != null);
this.layoutId = layoutId.Value;
this.widget = widget;
this.startMargin = startMargin;
}
public readonly _TimePickerHeaderId layoutId;
public readonly Widget widget;
public readonly float startMargin;
}
public class _TimePickerHeaderPiece {
public _TimePickerHeaderPiece(int pivotIndex, List<_TimePickerHeaderFragment> fragments,
float bottomMargin = 0.0f) {
D.assert(fragments != null);
this.pivotIndex = pivotIndex;
this.fragments = fragments;
this.bottomMargin = bottomMargin;
}
public readonly int pivotIndex;
public readonly List<_TimePickerHeaderFragment> fragments;
public readonly float bottomMargin;
}
public class _TimePickerHeaderFormat {
public _TimePickerHeaderFormat(int centerpieceIndex, List<_TimePickerHeaderPiece> pieces) {
D.assert(pieces != null);
this.centerpieceIndex = centerpieceIndex;
this.pieces = pieces;
}
public readonly int centerpieceIndex;
public readonly List<_TimePickerHeaderPiece> pieces;
}
class _DayPeriodControl : StatelessWidget {
public _DayPeriodControl(
_TimePickerFragmentContext fragmentContext,
Orientation orientation
) {
this.fragmentContext = fragmentContext;
this.orientation = orientation;
}
public readonly _TimePickerFragmentContext fragmentContext;
public readonly Orientation orientation;
void _togglePeriod() {
int newHour = (fragmentContext.selectedTime.hour + TimeOfDay.hoursPerPeriod) % TimeOfDay.hoursPerDay;
TimeOfDay newTime = fragmentContext.selectedTime.replacing(hour: newHour);
fragmentContext.onTimeChange(newTime);
}
void _setAm(BuildContext context) {
if (fragmentContext.selectedTime.period == DayPeriod.am) {
return;
}
_togglePeriod();
}
void _setPm(BuildContext context) {
if (fragmentContext.selectedTime.period == DayPeriod.pm) {
return;
}
_togglePeriod();
}
public override Widget build(BuildContext context) {
MaterialLocalizations materialLocalizations = MaterialLocalizations.of(context);
TextTheme headerTextTheme = fragmentContext.headerTextTheme;
TimeOfDay selectedTime = fragmentContext.selectedTime;
Color activeColor = fragmentContext.activeColor;
Color inactiveColor = fragmentContext.inactiveColor;
bool amSelected = selectedTime.period == DayPeriod.am;
TextStyle amStyle = headerTextTheme.subtitle1.copyWith(
color: amSelected ? activeColor : inactiveColor
);
TextStyle pmStyle = headerTextTheme.subtitle1.copyWith(
color: !amSelected ? activeColor : inactiveColor
);
bool layoutPortrait = orientation == Orientation.portrait;
float buttonTextScaleFactor = Mathf.Min(MediaQuery.of(context).textScaleFactor, 2.0f);
Widget amButton = new ConstrainedBox(
constraints: TimePickerUtils._kMinTappableRegion,
child: new Material(
type: MaterialType.transparency,
child: new InkWell(
onTap: Feedback.wrapForTap(() => _setAm(context), context),
child: new Padding(
padding: layoutPortrait ? EdgeInsets.only(bottom: 2.0f) : EdgeInsets.only(right: 4.0f),
child: new Align(
alignment: layoutPortrait ? Alignment.bottomCenter : Alignment.centerRight,
widthFactor: 1,
heightFactor: 1,
child: new Text(
materialLocalizations.anteMeridiemAbbreviation,
style: amStyle,
textScaleFactor: buttonTextScaleFactor
)
)
)
)
)
);
Widget pmButton = new ConstrainedBox(
constraints: TimePickerUtils._kMinTappableRegion,
child: new Material(
type: MaterialType.transparency,
textStyle: pmStyle,
child: new InkWell(
onTap: Feedback.wrapForTap(() => _setPm(context), context),
child: new Padding(
padding: layoutPortrait ? EdgeInsets.only(top: 2.0f) : EdgeInsets.only(left: 4.0f),
child: new Align(
alignment: orientation == Orientation.portrait
? Alignment.topCenter
: Alignment.centerLeft,
widthFactor: 1,
heightFactor: 1,
child: new Text(
materialLocalizations.postMeridiemAbbreviation,
style: pmStyle,
textScaleFactor: buttonTextScaleFactor
)
)
)
)
)
);
switch (orientation) {
case Orientation.portrait:
return new Column(
mainAxisSize: MainAxisSize.min,
children: new List<Widget> {
amButton,
pmButton
}
);
case Orientation.landscape:
return new Row(
mainAxisSize: MainAxisSize.min,
children: new List<Widget> {
amButton,
pmButton
}
);
}
return null;
}
}
class _HourControl : StatelessWidget {
public _HourControl(
_TimePickerFragmentContext fragmentContext
) {
this.fragmentContext = fragmentContext;
}
public readonly _TimePickerFragmentContext fragmentContext;
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
bool alwaysUse24HourFormat = MediaQuery.of(context).alwaysUse24HourFormat;
MaterialLocalizations localizations = MaterialLocalizations.of(context);
TextStyle hourStyle = fragmentContext.mode == _TimePickerMode.hour
? fragmentContext.activeStyle
: fragmentContext.inactiveStyle;
string formattedHour = localizations.formatHour(
fragmentContext.selectedTime,
alwaysUse24HourFormat: alwaysUse24HourFormat
);
TimeOfDay hoursFromSelected(int hoursToAdd) {
if (fragmentContext.use24HourDials) {
int selectedHour = fragmentContext.selectedTime.hour;
return fragmentContext.selectedTime.replacing(
hour: (selectedHour + hoursToAdd) % TimeOfDay.hoursPerDay
);
}
else {
int periodOffset = fragmentContext.selectedTime.periodOffset;
int hours = fragmentContext.selectedTime.hourOfPeriod;
return fragmentContext.selectedTime.replacing(
hour: periodOffset + (hours + hoursToAdd) % TimeOfDay.hoursPerPeriod
);
}
}
TimeOfDay nextHour = hoursFromSelected(1);
string formattedNextHour = localizations.formatHour(
nextHour,
alwaysUse24HourFormat: alwaysUse24HourFormat
);
TimeOfDay previousHour = hoursFromSelected(-1);
string formattedPreviousHour = localizations.formatHour(
previousHour,
alwaysUse24HourFormat: alwaysUse24HourFormat
);
return new ConstrainedBox(
constraints: TimePickerUtils._kMinTappableRegion,
child: new Material(
type: MaterialType.transparency,
child: new InkWell(
onTap: Feedback.wrapForTap(() => fragmentContext.onModeChange(_TimePickerMode.hour), context),
child: new Text(
formattedHour,
style: hourStyle,
textAlign: TextAlign.end,
textScaleFactor: 1.0f
)
)
)
);
}
}
class _StringFragment : StatelessWidget {
public _StringFragment(
_TimePickerFragmentContext fragmentContext,
string value
) {
this.fragmentContext = fragmentContext;
this.value = value;
}
public readonly _TimePickerFragmentContext fragmentContext;
public readonly string value;
public override Widget build(BuildContext context) {
return new Text(value, style: fragmentContext.inactiveStyle, textScaleFactor: 1.0f);
}
}
class _MinuteControl : StatelessWidget {
public _MinuteControl(
_TimePickerFragmentContext fragmentContext
) {
this.fragmentContext = fragmentContext;
}
public readonly _TimePickerFragmentContext fragmentContext;
public override Widget build(BuildContext context) {
MaterialLocalizations localizations = MaterialLocalizations.of(context);
TextStyle minuteStyle = fragmentContext.mode == _TimePickerMode.minute
? fragmentContext.activeStyle
: fragmentContext.inactiveStyle;
string formattedMinute = localizations.formatMinute(fragmentContext.selectedTime);
TimeOfDay nextMinute = fragmentContext.selectedTime.replacing(
minute: (fragmentContext.selectedTime.minute + 1) % TimeOfDay.minutesPerHour
);
string formattedNextMinute = localizations.formatMinute(nextMinute);
TimeOfDay previousMinute = fragmentContext.selectedTime.replacing(
minute: (fragmentContext.selectedTime.minute - 1 + TimeOfDay.minutesPerHour) % TimeOfDay.minutesPerHour
);
string formattedPreviousMinute = localizations.formatMinute(previousMinute);
return new ConstrainedBox(
constraints: TimePickerUtils._kMinTappableRegion,
child: new Material(
type: MaterialType.transparency,
child: new InkWell(
onTap: Feedback.wrapForTap(() => fragmentContext.onModeChange(_TimePickerMode.minute), context),
child: new Text(formattedMinute, style: minuteStyle, textAlign: TextAlign.start,
textScaleFactor: 1.0f)
)
)
);
}
}
class _TimePickerHeaderLayout : MultiChildLayoutDelegate {
public _TimePickerHeaderLayout(
Orientation orientation,
_TimePickerHeaderFormat format) {
this.orientation = orientation;
this.format = format;
}
public readonly Orientation orientation;
public readonly _TimePickerHeaderFormat format;
public override void performLayout(Size size) {
BoxConstraints constraints = BoxConstraints.loose(size);
switch (orientation) {
case Orientation.portrait:
_layoutHorizontally(size, constraints);
break;
case Orientation.landscape:
_layoutVertically(size, constraints);
break;
}
}
void _layoutHorizontally(Size size, BoxConstraints constraints) {
List<_TimePickerHeaderFragment> fragmentsFlattened = new List<_TimePickerHeaderFragment>();
Dictionary<_TimePickerHeaderId, Size> childSizes = new Dictionary<_TimePickerHeaderId, Size>();
int pivotIndex = 0;
for (int pieceIndex = 0; pieceIndex < format.pieces.Count; pieceIndex += 1) {
_TimePickerHeaderPiece piece = format.pieces[pieceIndex];
foreach (_TimePickerHeaderFragment fragment in piece.fragments) {
childSizes[fragment.layoutId] = layoutChild(fragment.layoutId, constraints);
fragmentsFlattened.Add(fragment);
}
if (pieceIndex == format.centerpieceIndex) {
pivotIndex += format.pieces[format.centerpieceIndex].pivotIndex;
}
else if (pieceIndex < format.centerpieceIndex) {
pivotIndex += piece.fragments.Count;
}
}
_positionPivoted(size.width, size.height / 2.0f, childSizes, fragmentsFlattened, pivotIndex);
}
void _layoutVertically(Size size, BoxConstraints constraints) {
Dictionary<_TimePickerHeaderId, Size> childSizes = new Dictionary<_TimePickerHeaderId, Size>();
List<float> pieceHeights = new List<float>();
float height = 0.0f;
float margin = 0.0f;
foreach (_TimePickerHeaderPiece piece in format.pieces) {
float pieceHeight = 0.0f;
foreach (_TimePickerHeaderFragment fragment in piece.fragments) {
Size childSize = childSizes[fragment.layoutId] = layoutChild(fragment.layoutId, constraints);
pieceHeight = Mathf.Max(pieceHeight, childSize.height);
}
pieceHeights.Add(pieceHeight);
height += pieceHeight + margin;
margin = piece.bottomMargin;
}
_TimePickerHeaderPiece centerpiece = format.pieces[format.centerpieceIndex];
float y = (size.height - height) / 2.0f;
for (int pieceIndex = 0; pieceIndex < format.pieces.Count; pieceIndex += 1) {
float pieceVerticalCenter = y + pieceHeights[pieceIndex] / 2.0f;
if (pieceIndex != format.centerpieceIndex) {
_positionPiece(size.width, pieceVerticalCenter, childSizes, format.pieces[pieceIndex].fragments);
}
else {
_positionPivoted(size.width, pieceVerticalCenter, childSizes, centerpiece.fragments,
centerpiece.pivotIndex);
}
y += pieceHeights[pieceIndex] + format.pieces[pieceIndex].bottomMargin;
}
}
void _positionPivoted(float width, float y, Dictionary<_TimePickerHeaderId, Size> childSizes,
List<_TimePickerHeaderFragment> fragments, int pivotIndex) {
float tailWidth = childSizes[fragments[pivotIndex].layoutId].width / 2.0f;
foreach (_TimePickerHeaderFragment fragment in fragments.Skip(pivotIndex + 1)) {
tailWidth += childSizes[fragment.layoutId].width + fragment.startMargin;
}
float x = width / 2.0f + tailWidth;
x = Mathf.Min(x, width);
for (int i = fragments.Count - 1; i >= 0; i -= 1) {
_TimePickerHeaderFragment fragment = fragments[i];
Size childSize = childSizes[fragment.layoutId];
x -= childSize.width;
positionChild(fragment.layoutId, new Offset(x, y - childSize.height / 2.0f));
x -= fragment.startMargin;
}
}
void _positionPiece(float width, float centeredAroundY, Dictionary<_TimePickerHeaderId, Size> childSizes,
List<_TimePickerHeaderFragment> fragments) {
float pieceWidth = 0.0f;
float nextMargin = 0.0f;
foreach (_TimePickerHeaderFragment fragment in fragments) {
Size childSize = childSizes[fragment.layoutId];
pieceWidth += childSize.width + nextMargin;
nextMargin = fragment.startMargin;
}
float x = (width + pieceWidth) / 2.0f;
for (int i = fragments.Count - 1; i >= 0; i -= 1) {
_TimePickerHeaderFragment fragment = fragments[i];
Size childSize = childSizes[fragment.layoutId];
x -= childSize.width;
positionChild(fragment.layoutId, new Offset(x, centeredAroundY - childSize.height / 2.0f));
x -= fragment.startMargin;
}
}
public override bool shouldRelayout(MultiChildLayoutDelegate oldDelegate) {
var _oldDelegate = (_TimePickerHeaderLayout) oldDelegate;
return orientation != _oldDelegate.orientation || format != _oldDelegate.format;
}
}
class _TimePickerHeader : StatelessWidget {
public _TimePickerHeader(
TimeOfDay selectedTime,
_TimePickerMode mode,
Orientation orientation,
ValueChanged<_TimePickerMode> onModeChanged,
ValueChanged<TimeOfDay> onChanged,
bool use24HourDials
) {
D.assert(selectedTime != null);
this.selectedTime = selectedTime;
this.mode = mode;
this.orientation = orientation;
this.onModeChanged = onModeChanged;
this.onChanged = onChanged;
this.use24HourDials = use24HourDials;
}
public readonly TimeOfDay selectedTime;
public readonly _TimePickerMode mode;
public readonly Orientation orientation;
public readonly ValueChanged<_TimePickerMode> onModeChanged;
public readonly ValueChanged<TimeOfDay> onChanged;
public readonly bool use24HourDials;
void _handleChangeMode(_TimePickerMode value) {
if (value != mode) {
onModeChanged(value);
}
}
TextStyle _getBaseHeaderStyle(TextTheme headerTextTheme) {
switch (orientation) {
case Orientation.portrait:
return headerTextTheme.headline2.copyWith(fontSize: 60.0f);
case Orientation.landscape:
return headerTextTheme.headline3.copyWith(fontSize: 50.0f);
}
return null;
}
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
ThemeData themeData = Theme.of(context);
MediaQueryData media = MediaQuery.of(context);
TimeOfDayFormat timeOfDayFormat = MaterialLocalizations.of(context)
.timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat);
EdgeInsets padding = null;
float height = 0f;
float width = 0f;
switch (orientation) {
case Orientation.portrait:
height = TimePickerUtils._kTimePickerHeaderPortraitHeight;
padding = EdgeInsets.symmetric(horizontal: 24.0f);
break;
case Orientation.landscape:
width = TimePickerUtils._kTimePickerHeaderLandscapeWidth;
padding = EdgeInsets.symmetric(horizontal: 16.0f);
break;
}
Color backgroundColor = null;
switch (themeData.brightness) {
case Brightness.light:
backgroundColor = themeData.primaryColor;
break;
case Brightness.dark:
backgroundColor = themeData.backgroundColor;
break;
}
Color activeColor = null;
Color inactiveColor = null;
switch (themeData.primaryColorBrightness) {
case Brightness.light:
activeColor = Colors.black87;
inactiveColor = Colors.black54;
break;
case Brightness.dark:
activeColor = Colors.white;
inactiveColor = Colors.white70;
break;
}
TextTheme headerTextTheme = themeData.primaryTextTheme;
TextStyle baseHeaderStyle = _getBaseHeaderStyle(headerTextTheme);
_TimePickerFragmentContext fragmentContext = new _TimePickerFragmentContext(
headerTextTheme: headerTextTheme,
textDirection: Directionality.of(context),
selectedTime: selectedTime,
mode: mode,
activeColor: activeColor,
activeStyle: baseHeaderStyle.copyWith(color: activeColor),
inactiveColor: inactiveColor,
inactiveStyle: baseHeaderStyle.copyWith(color: inactiveColor),
onTimeChange: onChanged,
onModeChange: _handleChangeMode,
targetPlatform: themeData.platform,
use24HourDials: use24HourDials
);
_TimePickerHeaderFormat format =
TimePickerUtils._buildHeaderFormat(timeOfDayFormat, fragmentContext, orientation);
var childrenPieces = new List<_TimePickerHeaderFragment>();
foreach (var piece in format.pieces) {
childrenPieces.AddRange(piece.fragments);
}
var children = childrenPieces.Select<_TimePickerHeaderFragment, Widget>(
(_TimePickerHeaderFragment fragment) => {
return new LayoutId(
id: fragment.layoutId,
child: fragment.widget
);
});
return new Container(
width: width,
height: height,
padding: padding,
color: backgroundColor,
child: new CustomMultiChildLayout(
layoutDelegate: new _TimePickerHeaderLayout(orientation, format),
children: children.ToList()
)
);
}
}
enum _DialRing {
outer,
inner,
}
class _TappableLabel {
public _TappableLabel(
int value,
TextPainter painter,
VoidCallback onTap
) {
this.value = value;
this.painter = painter;
this.onTap = onTap;
}
public readonly int value;
public readonly TextPainter painter;
public readonly VoidCallback onTap;
}
class _DialPainter : AbstractCustomPainter {
public _DialPainter(
List<_TappableLabel> primaryOuterLabels,
List<_TappableLabel> primaryInnerLabels,
List<_TappableLabel> secondaryOuterLabels,
List<_TappableLabel> secondaryInnerLabels,
Color backgroundColor,
Color accentColor,
float theta,
_DialRing activeRing,
TextDirection textDirection,
int selectedValue
) : base(repaint: PaintingBinding.instance.systemFonts) {
this.primaryOuterLabels = primaryOuterLabels;
this.primaryInnerLabels = primaryInnerLabels;
this.secondaryOuterLabels = secondaryOuterLabels;
this.secondaryInnerLabels = secondaryInnerLabels;
this.backgroundColor = backgroundColor;
this.accentColor = accentColor;
this.theta = theta;
this.activeRing = activeRing;
this.textDirection = textDirection;
this.selectedValue = selectedValue;
}
public readonly List<_TappableLabel> primaryOuterLabels;
public readonly List<_TappableLabel> primaryInnerLabels;
public readonly List<_TappableLabel> secondaryOuterLabels;
public readonly List<_TappableLabel> secondaryInnerLabels;
public readonly Color backgroundColor;
public readonly Color accentColor;
public readonly float theta;
public readonly _DialRing activeRing;
public readonly TextDirection textDirection;
public readonly int selectedValue;
public override void paint(Canvas canvas, Size size) {
float radius = size.shortestSide / 2.0f;
Offset center = new Offset(size.width / 2.0f, size.height / 2.0f);
Offset centerPoint = center;
canvas.drawCircle(centerPoint, radius, new Paint {color = backgroundColor});
float labelPadding = 24.0f;
float outerLabelRadius = radius - labelPadding;
float innerLabelRadius = radius - labelPadding * 2.5f;
Offset getOffsetForTheta(float theta, _DialRing ring) {
float labelRadius = 0f;
switch (ring) {
case _DialRing.outer:
labelRadius = outerLabelRadius;
break;
case _DialRing.inner:
labelRadius = innerLabelRadius;
break;
}
return center + new Offset(labelRadius * Mathf.Cos(theta),
-labelRadius * Mathf.Sin(theta));
}
void paintLabels(List<_TappableLabel> labels, _DialRing ring) {
if (labels == null) {
return;
}
float labelThetaIncrement = -TimePickerUtils._kTwoPi / labels.Count;
float labelTheta = Mathf.PI / 2.0f;
foreach (_TappableLabel label in labels) {
TextPainter labelPainter = label.painter;
Offset labelOffset = new Offset(-labelPainter.width / 2.0f, -labelPainter.height / 2.0f);
labelPainter.paint(canvas, getOffsetForTheta(labelTheta, ring) + labelOffset);
labelTheta += labelThetaIncrement;
}
}
paintLabels(primaryOuterLabels, _DialRing.outer);
paintLabels(primaryInnerLabels, _DialRing.inner);
Paint selectorPaint = new Paint {color = accentColor};
Offset focusedPoint = getOffsetForTheta(theta, activeRing);
float focusedRadius = labelPadding - 4.0f;
canvas.drawCircle(centerPoint, 4.0f, selectorPaint);
canvas.drawCircle(focusedPoint, focusedRadius, selectorPaint);
selectorPaint.strokeWidth = 2.0f;
canvas.drawLine(centerPoint, focusedPoint, selectorPaint);
Rect focusedRect = Rect.fromCircle(
center: focusedPoint, radius: focusedRadius
);
canvas.save();
var path = new Path();
path.addOval(focusedRect);
canvas.clipPath(path);
paintLabels(secondaryOuterLabels, _DialRing.outer);
paintLabels(secondaryInnerLabels, _DialRing.inner);
canvas.restore();
}
public override bool shouldRepaint(CustomPainter oldPainter) {
var _oldPainter = (_DialPainter) oldPainter;
return _oldPainter.primaryOuterLabels != primaryOuterLabels
|| _oldPainter.primaryInnerLabels != primaryInnerLabels
|| _oldPainter.secondaryOuterLabels != secondaryOuterLabels
|| _oldPainter.secondaryInnerLabels != secondaryInnerLabels
|| _oldPainter.backgroundColor != backgroundColor
|| _oldPainter.accentColor != accentColor
|| _oldPainter.theta != theta
|| _oldPainter.activeRing != activeRing;
}
}
class _Dial : StatefulWidget {
public _Dial(
TimeOfDay selectedTime,
_TimePickerMode mode,
bool use24HourDials,
ValueChanged<TimeOfDay> onChanged,
VoidCallback onHourSelected
) {
D.assert(selectedTime != null);
this.selectedTime = selectedTime;
this.mode = mode;
this.use24HourDials = use24HourDials;
this.onChanged = onChanged;
this.onHourSelected = onHourSelected;
}
public readonly TimeOfDay selectedTime;
public readonly _TimePickerMode mode;
public readonly bool use24HourDials;
public readonly ValueChanged<TimeOfDay> onChanged;
public readonly VoidCallback onHourSelected;
public override State createState() {
return new _DialState();
}
}
class _DialState : SingleTickerProviderStateMixin<_Dial> {
public override void initState() {
base.initState();
_updateDialRingFromWidget();
_thetaController = new AnimationController(
duration: TimePickerUtils._kDialAnimateDuration,
vsync: this
);
//the end will be set to be valid value later, we just make it 1f by default here
_thetaTween = new FloatTween(begin: _getThetaForTime(widget.selectedTime), end: 1f);
_theta = _thetaController
.drive(new CurveTween(curve: Curves.fastOutSlowIn))
.drive(_thetaTween);
_theta.addListener(() => setState(() => {
}));
}
ThemeData themeData;
MaterialLocalizations localizations;
MediaQueryData media;
public override void didChangeDependencies() {
base.didChangeDependencies();
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
themeData = Theme.of(context);
localizations = MaterialLocalizations.of(context);
media = MediaQuery.of(context);
}
public override void didUpdateWidget(StatefulWidget oldWidget) {
var _oldWidget = (_Dial) oldWidget;
base.didUpdateWidget(oldWidget);
_updateDialRingFromWidget();
if (widget.mode != _oldWidget.mode || widget.selectedTime != _oldWidget.selectedTime) {
if (!_dragging) {
_animateTo(_getThetaForTime(widget.selectedTime));
}
}
}
void _updateDialRingFromWidget() {
if (widget.mode == _TimePickerMode.hour && widget.use24HourDials) {
_activeRing = widget.selectedTime.hour >= 1 && widget.selectedTime.hour <= 12
? _DialRing.inner
: _DialRing.outer;
}
else {
_activeRing = _DialRing.outer;
}
}
public override void dispose() {
_thetaController.dispose();
base.dispose();
}
Tween<float> _thetaTween;
Animation<float> _theta;
AnimationController _thetaController;
bool _dragging = false;
static float _nearest(float target, float a, float b) {
return ((target - a).abs() < (target - b).abs()) ? a : b;
}
void _animateTo(float targetTheta) {
float currentTheta = _theta.value;
float beginTheta = _nearest(targetTheta, currentTheta, currentTheta + TimePickerUtils._kTwoPi);
beginTheta = _nearest(targetTheta, beginTheta, currentTheta - TimePickerUtils._kTwoPi);
_thetaTween.begin = beginTheta;
_thetaTween.end = targetTheta;
_thetaController.setValue(0.0f);
_thetaController.forward();
}
float _getThetaForTime(TimeOfDay time) {
float fraction = widget.mode == _TimePickerMode.hour
? (time.hour / TimeOfDay.hoursPerPeriod) % TimeOfDay.hoursPerPeriod
: (time.minute / TimeOfDay.minutesPerHour) % TimeOfDay.minutesPerHour;
return (Mathf.PI / 2.0f - fraction * TimePickerUtils._kTwoPi) % TimePickerUtils._kTwoPi;
}
TimeOfDay _getTimeForTheta(float theta) {
float fraction = (0.25f - (theta % TimePickerUtils._kTwoPi) / TimePickerUtils._kTwoPi) % 1.0f;
if (widget.mode == _TimePickerMode.hour) {
int newHour = (fraction * TimeOfDay.hoursPerPeriod).round() % TimeOfDay.hoursPerPeriod;
if (widget.use24HourDials) {
if (_activeRing == _DialRing.outer) {
if (newHour != 0) {
newHour = (newHour + TimeOfDay.hoursPerPeriod) % TimeOfDay.hoursPerDay;
}
}
else if (newHour == 0) {
newHour = TimeOfDay.hoursPerPeriod;
}
}
else {
newHour = newHour + widget.selectedTime.periodOffset;
}
return widget.selectedTime.replacing(hour: newHour);
}
else {
return widget.selectedTime.replacing(
minute: (fraction * TimeOfDay.minutesPerHour).round() % TimeOfDay.minutesPerHour
);
}
}
TimeOfDay _notifyOnChangedIfNeeded() {
TimeOfDay current = _getTimeForTheta(_theta.value);
if (widget.onChanged == null) {
return current;
}
if (current != widget.selectedTime) {
widget.onChanged(current);
}
return current;
}
void _updateThetaForPan() {
setState(() => {
Offset offset = _position - _center;
float angle = (Mathf.Atan2(offset.dx, offset.dy) - Mathf.PI / 2.0f) % TimePickerUtils._kTwoPi;
_thetaTween.begin = angle;
_thetaTween.end = angle;
RenderBox box = context.findRenderObject() as RenderBox;
float radius = box.size.shortestSide / 2.0f;
if (widget.mode == _TimePickerMode.hour && widget.use24HourDials) {
if (offset.distance * 1.5f < radius) {
_activeRing = _DialRing.inner;
}
else {
_activeRing = _DialRing.outer;
}
}
});
}
Offset _position;
Offset _center;
_DialRing _activeRing = _DialRing.outer;
void _handlePanStart(DragStartDetails details) {
D.assert(!_dragging);
_dragging = true;
RenderBox box = context.findRenderObject() as RenderBox;
_position = box.globalToLocal(details.globalPosition);
_center = box.size.center(Offset.zero);
_updateThetaForPan();
_notifyOnChangedIfNeeded();
}
void _handlePanUpdate(DragUpdateDetails details) {
_position += details.delta;
_updateThetaForPan();
_notifyOnChangedIfNeeded();
}
void _handlePanEnd(DragEndDetails details) {
D.assert(_dragging);
_dragging = false;
_position = null;
_center = null;
_animateTo(_getThetaForTime(widget.selectedTime));
if (widget.mode == _TimePickerMode.hour) {
if (widget.onHourSelected != null) {
widget.onHourSelected();
}
}
}
void _handleTapUp(TapUpDetails details) {
RenderBox box = context.findRenderObject() as RenderBox;
_position = box.globalToLocal(details.globalPosition);
_center = box.size.center(Offset.zero);
_updateThetaForPan();
TimeOfDay newTime = _notifyOnChangedIfNeeded();
if (widget.mode == _TimePickerMode.hour) {
if (widget.onHourSelected != null) {
widget.onHourSelected();
}
}
_animateTo(_getThetaForTime(_getTimeForTheta(_theta.value)));
_dragging = false;
_position = null;
_center = null;
}
void _selectHour(int hour) {
TimeOfDay time;
if (widget.mode == _TimePickerMode.hour && widget.use24HourDials) {
_activeRing = hour >= 1 && hour <= 12
? _DialRing.inner
: _DialRing.outer;
time = new TimeOfDay(hour: hour, minute: widget.selectedTime.minute);
}
else {
_activeRing = _DialRing.outer;
if (widget.selectedTime.period == DayPeriod.am) {
time = new TimeOfDay(hour: hour, minute: widget.selectedTime.minute);
}
else {
time = new TimeOfDay(hour: hour + TimeOfDay.hoursPerPeriod, minute: widget.selectedTime.minute);
}
}
float angle = _getThetaForTime(time);
_thetaTween.begin = angle;
_thetaTween.end = angle;
_notifyOnChangedIfNeeded();
}
void _selectMinute(int minute) {
TimeOfDay time = new TimeOfDay(
hour: widget.selectedTime.hour,
minute: minute
);
float angle = _getThetaForTime(time);
_thetaTween.begin = angle;
_thetaTween.end = angle;
_notifyOnChangedIfNeeded();
}
static readonly List<TimeOfDay> _amHours = new List<TimeOfDay> {
new TimeOfDay(hour: 12, minute: 0),
new TimeOfDay(hour: 1, minute: 0),
new TimeOfDay(hour: 2, minute: 0),
new TimeOfDay(hour: 3, minute: 0),
new TimeOfDay(hour: 4, minute: 0),
new TimeOfDay(hour: 5, minute: 0),
new TimeOfDay(hour: 6, minute: 0),
new TimeOfDay(hour: 7, minute: 0),
new TimeOfDay(hour: 8, minute: 0),
new TimeOfDay(hour: 9, minute: 0),
new TimeOfDay(hour: 10, minute: 0),
new TimeOfDay(hour: 11, minute: 0)
};
static readonly List<TimeOfDay> _pmHours = new List<TimeOfDay> {
new TimeOfDay(hour: 0, minute: 0),
new TimeOfDay(hour: 13, minute: 0),
new TimeOfDay(hour: 14, minute: 0),
new TimeOfDay(hour: 15, minute: 0),
new TimeOfDay(hour: 16, minute: 0),
new TimeOfDay(hour: 17, minute: 0),
new TimeOfDay(hour: 18, minute: 0),
new TimeOfDay(hour: 19, minute: 0),
new TimeOfDay(hour: 20, minute: 0),
new TimeOfDay(hour: 21, minute: 0),
new TimeOfDay(hour: 22, minute: 0),
new TimeOfDay(hour: 23, minute: 0)
};
_TappableLabel _buildTappableLabel(TextTheme textTheme, int value, string label, VoidCallback onTap) {
TextStyle style = textTheme.subtitle1;
float labelScaleFactor = Mathf.Min(MediaQuery.of(context).textScaleFactor, 2.0f);
var painter = new TextPainter(
text: new TextSpan(style: style, text: label),
textDirection: TextDirection.ltr,
textScaleFactor: labelScaleFactor
);
painter.layout();
return new _TappableLabel(
value: value,
painter: painter,
onTap: onTap
);
}
List<_TappableLabel> _build24HourInnerRing(TextTheme textTheme) {
var labels = new List<_TappableLabel>();
foreach (TimeOfDay timeOfDay in _amHours) {
labels.Add(_buildTappableLabel(
textTheme,
timeOfDay.hour,
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
() => { _selectHour(timeOfDay.hour); }
));
}
return labels;
}
List<_TappableLabel> _build24HourOuterRing(TextTheme textTheme) {
var labels = new List<_TappableLabel>();
foreach (TimeOfDay timeOfDay in _pmHours) {
labels.Add(_buildTappableLabel(
textTheme,
timeOfDay.hour,
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
() => { _selectHour(timeOfDay.hour); }
));
}
return labels;
}
List<_TappableLabel> _build12HourOuterRing(TextTheme textTheme) {
var labels = new List<_TappableLabel>();
foreach (TimeOfDay timeOfDay in _amHours) {
labels.Add(_buildTappableLabel(
textTheme,
timeOfDay.hour,
localizations.formatHour(timeOfDay, alwaysUse24HourFormat: media.alwaysUse24HourFormat),
() => { _selectHour(timeOfDay.hour); }
));
}
return labels;
}
static readonly List<TimeOfDay> _minuteMarkerValues = new List<TimeOfDay> {
new TimeOfDay(hour: 0, minute: 0),
new TimeOfDay(hour: 0, minute: 5),
new TimeOfDay(hour: 0, minute: 10),
new TimeOfDay(hour: 0, minute: 15),
new TimeOfDay(hour: 0, minute: 20),
new TimeOfDay(hour: 0, minute: 25),
new TimeOfDay(hour: 0, minute: 30),
new TimeOfDay(hour: 0, minute: 35),
new TimeOfDay(hour: 0, minute: 40),
new TimeOfDay(hour: 0, minute: 45),
new TimeOfDay(hour: 0, minute: 50),
new TimeOfDay(hour: 0, minute: 55)
};
List<_TappableLabel> _buildMinutes(TextTheme textTheme) {
var labels = new List<_TappableLabel>();
foreach (TimeOfDay timeOfDay in _minuteMarkerValues) {
labels.Add(_buildTappableLabel(
textTheme,
timeOfDay.minute,
localizations.formatMinute(timeOfDay),
() => { _selectMinute(timeOfDay.minute); }
));
}
return labels;
}
public override Widget build(BuildContext context) {
Color backgroundColor = null;
switch (themeData.brightness) {
case Brightness.light:
backgroundColor = Colors.grey[200];
break;
case Brightness.dark:
backgroundColor = themeData.backgroundColor;
break;
}
ThemeData theme = Theme.of(context);
List<_TappableLabel> primaryOuterLabels = null;
List<_TappableLabel> primaryInnerLabels = null;
List<_TappableLabel> secondaryOuterLabels = null;
List<_TappableLabel> secondaryInnerLabels = null;
int selectedDialValue = 0;
switch (widget.mode) {
case _TimePickerMode.hour:
if (widget.use24HourDials) {
selectedDialValue = widget.selectedTime.hour;
primaryOuterLabels = _build24HourOuterRing(theme.textTheme);
secondaryOuterLabels = _build24HourOuterRing(theme.accentTextTheme);
primaryInnerLabels = _build24HourInnerRing(theme.textTheme);
secondaryInnerLabels = _build24HourInnerRing(theme.accentTextTheme);
}
else {
selectedDialValue = widget.selectedTime.hourOfPeriod;
primaryOuterLabels = _build12HourOuterRing(theme.textTheme);
secondaryOuterLabels = _build12HourOuterRing(theme.accentTextTheme);
}
break;
case _TimePickerMode.minute:
selectedDialValue = widget.selectedTime.minute;
primaryOuterLabels = _buildMinutes(theme.textTheme);
primaryInnerLabels = null;
secondaryOuterLabels = _buildMinutes(theme.accentTextTheme);
secondaryInnerLabels = null;
break;
}
return new GestureDetector(
onPanStart: _handlePanStart,
onPanUpdate: _handlePanUpdate,
onPanEnd: _handlePanEnd,
onTapUp: _handleTapUp,
child: new CustomPaint(
key: new ValueKey<string>("time-picker-dial"),
painter: new _DialPainter(
selectedValue: selectedDialValue,
primaryOuterLabels: primaryOuterLabels,
primaryInnerLabels: primaryInnerLabels,
secondaryOuterLabels: secondaryOuterLabels,
secondaryInnerLabels: secondaryInnerLabels,
backgroundColor: backgroundColor,
accentColor: themeData.accentColor,
theta: _theta.value,
activeRing: _activeRing,
textDirection: Directionality.of(context)
)
)
);
}
}
class _TimePickerDialog : StatefulWidget {
public _TimePickerDialog(
Key key = null,
TimeOfDay initialTime = null) : base(key: key) {
D.assert(initialTime != null);
this.initialTime = initialTime;
}
public readonly TimeOfDay initialTime;
public override State createState() {
return new _TimePickerDialogState();
}
}
class _TimePickerDialogState : State<_TimePickerDialog> {
public override void initState() {
base.initState();
_selectedTime = widget.initialTime;
}
public override void didChangeDependencies() {
base.didChangeDependencies();
localizations = MaterialLocalizations.of(context);
_announceInitialTimeOnce();
_announceModeOnce();
}
_TimePickerMode _mode = _TimePickerMode.hour;
_TimePickerMode _lastModeAnnounced;
TimeOfDay selectedTime {
get { return _selectedTime; }
}
TimeOfDay _selectedTime;
Timer _vibrateTimer;
MaterialLocalizations localizations;
void _vibrate() {
}
void _handleModeChanged(_TimePickerMode mode) {
_vibrate();
setState(() => {
_mode = mode;
_announceModeOnce();
});
}
void _announceModeOnce() {
if (_lastModeAnnounced == _mode) {
return;
}
_lastModeAnnounced = _mode;
}
bool _announcedInitialTime = false;
void _announceInitialTimeOnce() {
if (_announcedInitialTime) {
return;
}
MediaQueryData media = MediaQuery.of(context);
MaterialLocalizations localizations = MaterialLocalizations.of(context);
_announcedInitialTime = true;
}
void _handleTimeChanged(TimeOfDay value) {
_vibrate();
setState(() => { _selectedTime = value; });
}
void _handleHourSelected() {
setState(() => { _mode = _TimePickerMode.minute; });
}
void _handleCancel() {
Navigator.pop<object>(context);
}
void _handleOk() {
Navigator.pop(context, _selectedTime);
}
public override Widget build(BuildContext context) {
D.assert(WidgetsD.debugCheckHasMediaQuery(context));
MediaQueryData media = MediaQuery.of(context);
TimeOfDayFormat timeOfDayFormat =
localizations.timeOfDayFormat(alwaysUse24HourFormat: media.alwaysUse24HourFormat);
bool use24HourDials = HourFormatUtils.hourFormat(of: timeOfDayFormat) != HourFormat.h;
ThemeData theme = Theme.of(context);
Widget picker = new Padding(
padding: EdgeInsets.all(16.0f),
child: new AspectRatio(
aspectRatio: 1.0f,
child: new _Dial(
mode: _mode,
use24HourDials: use24HourDials,
selectedTime: _selectedTime,
onChanged: _handleTimeChanged,
onHourSelected: _handleHourSelected
)
)
);
Widget actions = new ButtonBar(
children: new List<Widget> {
new FlatButton(
child: new Text(localizations.cancelButtonLabel),
onPressed: _handleCancel
),
new FlatButton(
child: new Text(localizations.okButtonLabel),
onPressed: _handleOk
),
}
);
Dialog dialog = new Dialog(
child: new OrientationBuilder(
builder: (BuildContext subContext, Orientation subOrientation) => {
Widget header = new _TimePickerHeader(
selectedTime: _selectedTime,
mode: _mode,
orientation: subOrientation,
onModeChanged: _handleModeChanged,
onChanged: _handleTimeChanged,
use24HourDials: use24HourDials
);
Widget pickerAndActions = new Container(
color: theme.dialogBackgroundColor,
child: new Column(
mainAxisSize: MainAxisSize.min,
children: new List<Widget> {
new Expanded(child: picker), // picker grows and shrinks with the available space
actions,
}
)
);
float timePickerHeightPortrait = 0f;
float timePickerHeightLandscape = 0f;
switch (theme.materialTapTargetSize) {
case MaterialTapTargetSize.padded:
timePickerHeightPortrait = TimePickerUtils._kTimePickerHeightPortrait;
timePickerHeightLandscape = TimePickerUtils._kTimePickerHeightLandscape;
break;
case MaterialTapTargetSize.shrinkWrap:
timePickerHeightPortrait = TimePickerUtils._kTimePickerHeightPortraitCollapsed;
timePickerHeightLandscape = TimePickerUtils._kTimePickerHeightLandscapeCollapsed;
break;
}
switch (subOrientation) {
case Orientation.portrait:
return new SizedBox(
width: TimePickerUtils._kTimePickerWidthPortrait,
height: timePickerHeightPortrait,
child: new Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: new List<Widget> {
header,
new Expanded(
child: pickerAndActions
),
}
)
);
case Orientation.landscape:
return new SizedBox(
width: TimePickerUtils._kTimePickerWidthLandscape,
height: timePickerHeightLandscape,
child: new Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: new List<Widget> {
header,
new Flexible(
child: pickerAndActions
),
}
)
);
}
return null;
}
)
);
return new Theme(
data: theme.copyWith(
dialogBackgroundColor: Colors.transparent
),
child: dialog
);
}
public override void dispose() {
_vibrateTimer?.cancel();
_vibrateTimer = null;
base.dispose();
}
}
}