| 
 | 1 | +// Copyright 2014 The Flutter Authors. All rights reserved.  | 
 | 2 | +// Use of this source code is governed by a BSD-style license that can be  | 
 | 3 | +// found in the LICENSE file.  | 
 | 4 | + | 
 | 5 | +import 'template.dart';  | 
 | 6 | + | 
 | 7 | +class TimePickerTemplate extends TokenTemplate {  | 
 | 8 | +  const TimePickerTemplate(super.blockName, super.fileName, super.tokens, {  | 
 | 9 | +    super.colorSchemePrefix = '_colors.',  | 
 | 10 | +    super.textThemePrefix = '_textTheme.'  | 
 | 11 | +  });  | 
 | 12 | + | 
 | 13 | +  static const String tokenGroup = 'md.comp.time-picker';  | 
 | 14 | +  static const String hourMinuteComponent = '$tokenGroup.time-selector';  | 
 | 15 | +  static const String dayPeriodComponent = '$tokenGroup.period-selector';  | 
 | 16 | +  static const String dialComponent = '$tokenGroup.clock-dial';  | 
 | 17 | +  static const String variant = '';  | 
 | 18 | + | 
 | 19 | +  @override  | 
 | 20 | +  String generate() => '''  | 
 | 21 | +// Generated version ${tokens["version"]}  | 
 | 22 | +class _${blockName}DefaultsM3 extends _TimePickerDefaults {  | 
 | 23 | +  _${blockName}DefaultsM3(this.context);  | 
 | 24 | +
  | 
 | 25 | +  final BuildContext context;  | 
 | 26 | +
  | 
 | 27 | +  late final ColorScheme _colors = Theme.of(context).colorScheme;  | 
 | 28 | +  late final TextTheme _textTheme = Theme.of(context).textTheme;  | 
 | 29 | +
  | 
 | 30 | +  @override  | 
 | 31 | +  Color get backgroundColor {  | 
 | 32 | +    return ${componentColor("$tokenGroup.container")};  | 
 | 33 | +  }  | 
 | 34 | +
  | 
 | 35 | +  @override  | 
 | 36 | +  ButtonStyle get cancelButtonStyle {  | 
 | 37 | +    return TextButton.styleFrom();  | 
 | 38 | +  }  | 
 | 39 | +
  | 
 | 40 | +  @override  | 
 | 41 | +  ButtonStyle get confirmButtonStyle {  | 
 | 42 | +    return TextButton.styleFrom();  | 
 | 43 | +  }  | 
 | 44 | +
  | 
 | 45 | +  @override  | 
 | 46 | +  BorderSide get dayPeriodBorderSide {  | 
 | 47 | +    return ${border('$dayPeriodComponent.outline')};  | 
 | 48 | +  }  | 
 | 49 | +
  | 
 | 50 | +  @override  | 
 | 51 | +  Color get dayPeriodColor {  | 
 | 52 | +    return MaterialStateColor.resolveWith((Set<MaterialState> states) {  | 
 | 53 | +      if (states.contains(MaterialState.selected)) {  | 
 | 54 | +        return ${componentColor("$dayPeriodComponent.selected.container")};  | 
 | 55 | +      }  | 
 | 56 | +      // The unselected day period should match the overall picker dialog color.  | 
 | 57 | +      // Making it transparent enables that without being redundant and allows  | 
 | 58 | +      // the optional elevation overlay for dark mode to be visible.  | 
 | 59 | +      return Colors.transparent;  | 
 | 60 | +    });  | 
 | 61 | +  }  | 
 | 62 | +
  | 
 | 63 | +  @override  | 
 | 64 | +  OutlinedBorder get dayPeriodShape {  | 
 | 65 | +    return ${shape("$dayPeriodComponent.container")}.copyWith(side: dayPeriodBorderSide);  | 
 | 66 | +  }  | 
 | 67 | +
  | 
 | 68 | +  @override  | 
 | 69 | +  Size get dayPeriodPortraitSize {  | 
 | 70 | +    return ${size('$dayPeriodComponent.vertical.container')};  | 
 | 71 | +  }  | 
 | 72 | +
  | 
 | 73 | +  @override  | 
 | 74 | +  Size get dayPeriodLandscapeSize {  | 
 | 75 | +    return ${size('$dayPeriodComponent.horizontal.container')};  | 
 | 76 | +  }  | 
 | 77 | +
  | 
 | 78 | +  @override  | 
 | 79 | +  Size get dayPeriodInputSize {  | 
 | 80 | +    // Input size is eight pixels smaller than the portrait size in the spec,  | 
 | 81 | +    // but there's not token for it yet.  | 
 | 82 | +    return Size(dayPeriodPortraitSize.width, dayPeriodPortraitSize.height - 8);  | 
 | 83 | +  }  | 
 | 84 | +
  | 
 | 85 | +  @override  | 
 | 86 | +  Color get dayPeriodTextColor {  | 
 | 87 | +    return MaterialStateColor.resolveWith((Set<MaterialState> states) {  | 
 | 88 | +      return _dayPeriodForegroundColor.resolve(states);  | 
 | 89 | +    });  | 
 | 90 | +  }  | 
 | 91 | +
  | 
 | 92 | +  MaterialStateProperty<Color> get _dayPeriodForegroundColor {  | 
 | 93 | +    return MaterialStateProperty.resolveWith((Set<MaterialState> states) {  | 
 | 94 | +      Color? textColor;  | 
 | 95 | +      if (states.contains(MaterialState.selected)) {  | 
 | 96 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 97 | +          textColor = ${componentColor("$dayPeriodComponent.selected.pressed.label-text")};  | 
 | 98 | +        } else {  | 
 | 99 | +          // not pressed  | 
 | 100 | +          if (states.contains(MaterialState.focused)) {  | 
 | 101 | +            textColor = ${componentColor("$dayPeriodComponent.selected.focus.label-text")};  | 
 | 102 | +          } else {  | 
 | 103 | +            // not focused  | 
 | 104 | +            if (states.contains(MaterialState.hovered)) {  | 
 | 105 | +              textColor = ${componentColor("$dayPeriodComponent.selected.hover.label-text")};  | 
 | 106 | +            }  | 
 | 107 | +          }  | 
 | 108 | +        }  | 
 | 109 | +      } else {  | 
 | 110 | +        // unselected  | 
 | 111 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 112 | +          textColor = ${componentColor("$dayPeriodComponent.unselected.pressed.label-text")};  | 
 | 113 | +        } else {  | 
 | 114 | +          // not pressed  | 
 | 115 | +          if (states.contains(MaterialState.focused)) {  | 
 | 116 | +            textColor = ${componentColor("$dayPeriodComponent.unselected.focus.label-text")};  | 
 | 117 | +          } else {  | 
 | 118 | +            // not focused  | 
 | 119 | +            if (states.contains(MaterialState.hovered)) {  | 
 | 120 | +              textColor = ${componentColor("$dayPeriodComponent.unselected.hover.label-text")};  | 
 | 121 | +            }  | 
 | 122 | +          }  | 
 | 123 | +        }  | 
 | 124 | +      }  | 
 | 125 | +      return textColor ?? ${componentColor("$dayPeriodComponent.selected.label-text")};  | 
 | 126 | +    });  | 
 | 127 | +  }  | 
 | 128 | +
  | 
 | 129 | +  @override  | 
 | 130 | +  TextStyle get dayPeriodTextStyle {  | 
 | 131 | +    return ${textStyle("$dayPeriodComponent.label-text")}!.copyWith(color: dayPeriodTextColor);  | 
 | 132 | +  }  | 
 | 133 | +
  | 
 | 134 | +  @override  | 
 | 135 | +  Color get dialBackgroundColor {  | 
 | 136 | +    return ${componentColor(dialComponent)}.withOpacity(_colors.brightness == Brightness.dark ? 0.12 : 0.08);  | 
 | 137 | +  }  | 
 | 138 | +
  | 
 | 139 | +  @override  | 
 | 140 | +  Color get dialHandColor {  | 
 | 141 | +    return ${componentColor('$dialComponent.selector.handle.container')};  | 
 | 142 | +  }  | 
 | 143 | +
  | 
 | 144 | +  @override  | 
 | 145 | +  Size get dialSize {  | 
 | 146 | +    return ${size("$dialComponent.container")};  | 
 | 147 | +  }  | 
 | 148 | +
  | 
 | 149 | +  @override  | 
 | 150 | +  double get handWidth {  | 
 | 151 | +    return ${size("$dialComponent.selector.track.container")}.width;  | 
 | 152 | +  }  | 
 | 153 | +
  | 
 | 154 | +  @override  | 
 | 155 | +  double get dotRadius {  | 
 | 156 | +    return ${size("$dialComponent.selector.handle.container")}.width / 2;  | 
 | 157 | +  }  | 
 | 158 | +
  | 
 | 159 | +  @override  | 
 | 160 | +  double get centerRadius {  | 
 | 161 | +    return ${size("$dialComponent.selector.center.container")}.width / 2;  | 
 | 162 | +  }  | 
 | 163 | +
  | 
 | 164 | +  @override  | 
 | 165 | +  Color get dialTextColor {  | 
 | 166 | +    return MaterialStateColor.resolveWith((Set<MaterialState> states) {  | 
 | 167 | +      if (states.contains(MaterialState.selected)) {  | 
 | 168 | +        return ${componentColor('$dialComponent.selected.label-text')};  | 
 | 169 | +      }  | 
 | 170 | +      return ${componentColor('$dialComponent.unselected.label-text')};  | 
 | 171 | +    });  | 
 | 172 | +  }  | 
 | 173 | +
  | 
 | 174 | +  @override  | 
 | 175 | +  TextStyle get dialTextStyle {  | 
 | 176 | +    return ${textStyle('$dialComponent.label-text')}!;  | 
 | 177 | +  }  | 
 | 178 | +
  | 
 | 179 | +  @override  | 
 | 180 | +  double get elevation {  | 
 | 181 | +    return ${elevation("$tokenGroup.container")};  | 
 | 182 | +  }  | 
 | 183 | +
  | 
 | 184 | +  @override  | 
 | 185 | +  Color get entryModeIconColor {  | 
 | 186 | +    return _colors.onSurface;  | 
 | 187 | +  }  | 
 | 188 | +
  | 
 | 189 | +  @override  | 
 | 190 | +  TextStyle get helpTextStyle {  | 
 | 191 | +    return MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {  | 
 | 192 | +      final TextStyle textStyle = ${textStyle('$tokenGroup.headline')}!;  | 
 | 193 | +      return textStyle.copyWith(color: ${componentColor('$tokenGroup.headline')});  | 
 | 194 | +    });  | 
 | 195 | +  }  | 
 | 196 | +
  | 
 | 197 | +  @override  | 
 | 198 | +  EdgeInsetsGeometry get padding {  | 
 | 199 | +    return const EdgeInsets.all(24);  | 
 | 200 | +  }  | 
 | 201 | +
  | 
 | 202 | +  @override  | 
 | 203 | +  Color get hourMinuteColor {  | 
 | 204 | +    return MaterialStateColor.resolveWith((Set<MaterialState> states) {  | 
 | 205 | +      if (states.contains(MaterialState.selected)) {  | 
 | 206 | +        Color overlayColor = ${componentColor('$hourMinuteComponent.selected.container')};  | 
 | 207 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 208 | +          overlayColor = ${componentColor('$hourMinuteComponent.selected.pressed.state-layer')};  | 
 | 209 | +        } else if (states.contains(MaterialState.focused)) {  | 
 | 210 | +          const double focusOpacity = ${opacity('$hourMinuteComponent.focus.state-layer.opacity')};  | 
 | 211 | +          overlayColor = ${componentColor('$hourMinuteComponent.selected.focus.state-layer')}.withOpacity(focusOpacity);  | 
 | 212 | +        } else if (states.contains(MaterialState.hovered)) {  | 
 | 213 | +          const double hoverOpacity = ${opacity('$hourMinuteComponent.hover.state-layer.opacity')};  | 
 | 214 | +          overlayColor = ${componentColor('$hourMinuteComponent.selected.hover.state-layer')}.withOpacity(hoverOpacity);  | 
 | 215 | +        }  | 
 | 216 | +        return Color.alphaBlend(overlayColor, ${componentColor('$hourMinuteComponent.selected.container')});  | 
 | 217 | +      } else {  | 
 | 218 | +        Color overlayColor = ${componentColor('$hourMinuteComponent.unselected.container')};  | 
 | 219 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 220 | +          overlayColor = ${componentColor('$hourMinuteComponent.unselected.pressed.state-layer')};  | 
 | 221 | +        } else if (states.contains(MaterialState.focused)) {  | 
 | 222 | +          const double focusOpacity = ${opacity('$hourMinuteComponent.focus.state-layer.opacity')};  | 
 | 223 | +          overlayColor = ${componentColor('$hourMinuteComponent.unselected.focus.state-layer')}.withOpacity(focusOpacity);  | 
 | 224 | +        } else if (states.contains(MaterialState.hovered)) {  | 
 | 225 | +          const double hoverOpacity = ${opacity('$hourMinuteComponent.hover.state-layer.opacity')};  | 
 | 226 | +          overlayColor = ${componentColor('$hourMinuteComponent.unselected.hover.state-layer')}.withOpacity(hoverOpacity);  | 
 | 227 | +        }  | 
 | 228 | +        return Color.alphaBlend(overlayColor, ${componentColor('$hourMinuteComponent.unselected.container')});  | 
 | 229 | +      }  | 
 | 230 | +    });  | 
 | 231 | +  }  | 
 | 232 | +
  | 
 | 233 | +  @override  | 
 | 234 | +  ShapeBorder get hourMinuteShape {  | 
 | 235 | +    return ${shape('$hourMinuteComponent.container')};  | 
 | 236 | +  }  | 
 | 237 | +
  | 
 | 238 | +  @override  | 
 | 239 | +  Size get hourMinuteSize {  | 
 | 240 | +    return ${size('$hourMinuteComponent.container')};  | 
 | 241 | +  }  | 
 | 242 | +
  | 
 | 243 | +  @override  | 
 | 244 | +  Size get hourMinuteSize24Hour {  | 
 | 245 | +    return Size(${size('$hourMinuteComponent.24h-vertical.container')}.width, hourMinuteSize.height);  | 
 | 246 | +  }  | 
 | 247 | +
  | 
 | 248 | +  @override  | 
 | 249 | +  Size get hourMinuteInputSize {  | 
 | 250 | +    // Input size is eight pixels smaller than the regular size in the spec, but  | 
 | 251 | +    // there's not token for it yet.  | 
 | 252 | +    return Size(hourMinuteSize.width, hourMinuteSize.height - 8);  | 
 | 253 | +  }  | 
 | 254 | +
  | 
 | 255 | +  @override  | 
 | 256 | +  Size get hourMinuteInputSize24Hour {  | 
 | 257 | +    // Input size is eight pixels smaller than the regular size in the spec, but  | 
 | 258 | +    // there's not token for it yet.  | 
 | 259 | +    return Size(hourMinuteSize24Hour.width, hourMinuteSize24Hour.height - 8);  | 
 | 260 | +  }  | 
 | 261 | +
  | 
 | 262 | +  @override  | 
 | 263 | +  Color get hourMinuteTextColor {  | 
 | 264 | +    return MaterialStateColor.resolveWith((Set<MaterialState> states) {  | 
 | 265 | +      return _hourMinuteTextColor.resolve(states);  | 
 | 266 | +    });  | 
 | 267 | +  }  | 
 | 268 | +
  | 
 | 269 | +  MaterialStateProperty<Color> get _hourMinuteTextColor {  | 
 | 270 | +    return MaterialStateProperty.resolveWith((Set<MaterialState> states) {  | 
 | 271 | +      if (states.contains(MaterialState.selected)) {  | 
 | 272 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 273 | +          return ${componentColor("$hourMinuteComponent.selected.pressed.label-text")};  | 
 | 274 | +        }  | 
 | 275 | +        if (states.contains(MaterialState.focused)) {  | 
 | 276 | +          return ${componentColor("$hourMinuteComponent.selected.focus.label-text")};  | 
 | 277 | +        }  | 
 | 278 | +        if (states.contains(MaterialState.hovered)) {  | 
 | 279 | +          return ${componentColor("$hourMinuteComponent.selected.hover.label-text")};  | 
 | 280 | +        }  | 
 | 281 | +        return ${componentColor("$hourMinuteComponent.selected.label-text")};  | 
 | 282 | +      } else {  | 
 | 283 | +        // unselected  | 
 | 284 | +        if (states.contains(MaterialState.pressed)) {  | 
 | 285 | +          return ${componentColor("$hourMinuteComponent.unselected.pressed.label-text")};  | 
 | 286 | +        }  | 
 | 287 | +        if (states.contains(MaterialState.focused)) {  | 
 | 288 | +          return ${componentColor("$hourMinuteComponent.unselected.focus.label-text")};  | 
 | 289 | +        }  | 
 | 290 | +        if (states.contains(MaterialState.hovered)) {  | 
 | 291 | +          return ${componentColor("$hourMinuteComponent.unselected.hover.label-text")};  | 
 | 292 | +        }  | 
 | 293 | +        return ${componentColor("$hourMinuteComponent.unselected.label-text")};  | 
 | 294 | +      }  | 
 | 295 | +    });  | 
 | 296 | +  }  | 
 | 297 | +
  | 
 | 298 | +  @override  | 
 | 299 | +  TextStyle get hourMinuteTextStyle {  | 
 | 300 | +    return MaterialStateTextStyle.resolveWith((Set<MaterialState> states) {  | 
 | 301 | +      return ${textStyle('$hourMinuteComponent.label-text')}!.copyWith(color: _hourMinuteTextColor.resolve(states));  | 
 | 302 | +    });  | 
 | 303 | +  }  | 
 | 304 | +
  | 
 | 305 | +  @override  | 
 | 306 | +  InputDecorationTheme get inputDecorationTheme {  | 
 | 307 | +    // This is NOT correct, but there's no token for  | 
 | 308 | +    // 'time-input.container.shape', so this is using the radius from the shape  | 
 | 309 | +    // for the hour/minute selector.  | 
 | 310 | +    final BorderRadiusGeometry selectorRadius = ${shape('$hourMinuteComponent.container')}.borderRadius;  | 
 | 311 | +    return InputDecorationTheme(  | 
 | 312 | +      contentPadding: EdgeInsets.zero,  | 
 | 313 | +      filled: true,  | 
 | 314 | +      // This should be derived from a token, but there isn't one for 'time-input'.  | 
 | 315 | +      fillColor: hourMinuteColor,  | 
 | 316 | +      // This should be derived from a token, but there isn't one for 'time-input'.  | 
 | 317 | +      focusColor: _colors.primaryContainer,  | 
 | 318 | +      enabledBorder: OutlineInputBorder(  | 
 | 319 | +        borderRadius: selectorRadius,  | 
 | 320 | +        borderSide: const BorderSide(color: Colors.transparent),  | 
 | 321 | +      ),  | 
 | 322 | +      errorBorder: OutlineInputBorder(  | 
 | 323 | +        borderRadius: selectorRadius,  | 
 | 324 | +        borderSide: BorderSide(color: _colors.error, width: 2),  | 
 | 325 | +      ),  | 
 | 326 | +      focusedBorder: OutlineInputBorder(  | 
 | 327 | +        borderRadius: selectorRadius,  | 
 | 328 | +        borderSide: BorderSide(color: _colors.primary, width: 2),  | 
 | 329 | +      ),  | 
 | 330 | +      focusedErrorBorder: OutlineInputBorder(  | 
 | 331 | +        borderRadius: selectorRadius,  | 
 | 332 | +        borderSide: BorderSide(color: _colors.error, width: 2),  | 
 | 333 | +      ),  | 
 | 334 | +      hintStyle: hourMinuteTextStyle.copyWith(color: _colors.onSurface.withOpacity(0.36)),  | 
 | 335 | +      // Prevent the error text from appearing.  | 
 | 336 | +      // TODO(rami-a): Remove this workaround once  | 
 | 337 | +      // https://github.com/flutter/flutter/issues/54104  | 
 | 338 | +      // is fixed.  | 
 | 339 | +      errorStyle: const TextStyle(fontSize: 0, height: 0),  | 
 | 340 | +    );  | 
 | 341 | +  }  | 
 | 342 | +
  | 
 | 343 | +  @override  | 
 | 344 | +  ShapeBorder get shape {  | 
 | 345 | +    return ${shape("$tokenGroup.container")};  | 
 | 346 | +  }  | 
 | 347 | +}  | 
 | 348 | +''';  | 
 | 349 | +}  | 
0 commit comments