1// Copyright 2017 The Chromium 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. 4import 'package:flutter/cupertino.dart'; 5import 'package:intl/intl.dart'; 6 7import '../../gallery/demo.dart'; 8import 'cupertino_navigation_demo.dart' show coolColorNames; 9 10const double _kPickerSheetHeight = 216.0; 11const double _kPickerItemHeight = 32.0; 12 13class CupertinoPickerDemo extends StatefulWidget { 14 static const String routeName = '/cupertino/picker'; 15 16 @override 17 _CupertinoPickerDemoState createState() => _CupertinoPickerDemoState(); 18} 19 20class _CupertinoPickerDemoState extends State<CupertinoPickerDemo> { 21 int _selectedColorIndex = 0; 22 23 Duration timer = const Duration(); 24 25 // Value that is shown in the date picker in date mode. 26 DateTime date = DateTime.now(); 27 28 // Value that is shown in the date picker in time mode. 29 DateTime time = DateTime.now(); 30 31 // Value that is shown in the date picker in dateAndTime mode. 32 DateTime dateTime = DateTime.now(); 33 34 Widget _buildMenu(List<Widget> children) { 35 return Container( 36 decoration: BoxDecoration( 37 color: CupertinoTheme.of(context).scaffoldBackgroundColor, 38 border: const Border( 39 top: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), 40 bottom: BorderSide(color: Color(0xFFBCBBC1), width: 0.0), 41 ), 42 ), 43 height: 44.0, 44 child: Padding( 45 padding: const EdgeInsets.symmetric(horizontal: 16.0), 46 child: SafeArea( 47 top: false, 48 bottom: false, 49 child: Row( 50 mainAxisAlignment: MainAxisAlignment.spaceBetween, 51 children: children, 52 ), 53 ), 54 ), 55 ); 56 } 57 58 Widget _buildBottomPicker(Widget picker) { 59 return Container( 60 height: _kPickerSheetHeight, 61 padding: const EdgeInsets.only(top: 6.0), 62 color: CupertinoColors.white, 63 child: DefaultTextStyle( 64 style: const TextStyle( 65 color: CupertinoColors.black, 66 fontSize: 22.0, 67 ), 68 child: GestureDetector( 69 // Blocks taps from propagating to the modal sheet and popping. 70 onTap: () { }, 71 child: SafeArea( 72 top: false, 73 child: picker, 74 ), 75 ), 76 ), 77 ); 78 } 79 80 Widget _buildColorPicker(BuildContext context) { 81 final FixedExtentScrollController scrollController = 82 FixedExtentScrollController(initialItem: _selectedColorIndex); 83 84 return GestureDetector( 85 onTap: () async { 86 await showCupertinoModalPopup<void>( 87 context: context, 88 builder: (BuildContext context) { 89 return _buildBottomPicker( 90 CupertinoPicker( 91 scrollController: scrollController, 92 itemExtent: _kPickerItemHeight, 93 backgroundColor: CupertinoColors.white, 94 onSelectedItemChanged: (int index) { 95 setState(() => _selectedColorIndex = index); 96 }, 97 children: List<Widget>.generate(coolColorNames.length, (int index) { 98 return Center( 99 child: Text(coolColorNames[index]), 100 ); 101 }), 102 ), 103 ); 104 }, 105 ); 106 }, 107 child: _buildMenu( 108 <Widget>[ 109 const Text('Favorite Color'), 110 Text( 111 coolColorNames[_selectedColorIndex], 112 style: const TextStyle( 113 color: CupertinoColors.inactiveGray 114 ), 115 ), 116 ], 117 ), 118 ); 119 } 120 121 Widget _buildCountdownTimerPicker(BuildContext context) { 122 return GestureDetector( 123 onTap: () { 124 showCupertinoModalPopup<void>( 125 context: context, 126 builder: (BuildContext context) { 127 return _buildBottomPicker( 128 CupertinoTimerPicker( 129 initialTimerDuration: timer, 130 onTimerDurationChanged: (Duration newTimer) { 131 setState(() => timer = newTimer); 132 }, 133 ), 134 ); 135 }, 136 ); 137 }, 138 child: _buildMenu( 139 <Widget>[ 140 const Text('Countdown Timer'), 141 Text( 142 '${timer.inHours}:' 143 '${(timer.inMinutes % 60).toString().padLeft(2,'0')}:' 144 '${(timer.inSeconds % 60).toString().padLeft(2,'0')}', 145 style: const TextStyle(color: CupertinoColors.inactiveGray), 146 ), 147 ], 148 ), 149 ); 150 } 151 152 Widget _buildDatePicker(BuildContext context) { 153 return GestureDetector( 154 onTap: () { 155 showCupertinoModalPopup<void>( 156 context: context, 157 builder: (BuildContext context) { 158 return _buildBottomPicker( 159 CupertinoDatePicker( 160 mode: CupertinoDatePickerMode.date, 161 initialDateTime: date, 162 onDateTimeChanged: (DateTime newDateTime) { 163 setState(() => date = newDateTime); 164 }, 165 ), 166 ); 167 }, 168 ); 169 }, 170 child: _buildMenu( 171 <Widget>[ 172 const Text('Date'), 173 Text( 174 DateFormat.yMMMMd().format(date), 175 style: const TextStyle(color: CupertinoColors.inactiveGray), 176 ), 177 ] 178 ), 179 ); 180 } 181 182 Widget _buildTimePicker(BuildContext context) { 183 return GestureDetector( 184 onTap: () { 185 showCupertinoModalPopup<void>( 186 context: context, 187 builder: (BuildContext context) { 188 return _buildBottomPicker( 189 CupertinoDatePicker( 190 mode: CupertinoDatePickerMode.time, 191 initialDateTime: time, 192 onDateTimeChanged: (DateTime newDateTime) { 193 setState(() => time = newDateTime); 194 }, 195 ), 196 ); 197 }, 198 ); 199 }, 200 child: _buildMenu( 201 <Widget>[ 202 const Text('Time'), 203 Text( 204 DateFormat.jm().format(time), 205 style: const TextStyle(color: CupertinoColors.inactiveGray), 206 ), 207 ], 208 ), 209 ); 210 } 211 212 Widget _buildDateAndTimePicker(BuildContext context) { 213 return GestureDetector( 214 onTap: () { 215 showCupertinoModalPopup<void>( 216 context: context, 217 builder: (BuildContext context) { 218 return _buildBottomPicker( 219 CupertinoDatePicker( 220 mode: CupertinoDatePickerMode.dateAndTime, 221 initialDateTime: dateTime, 222 onDateTimeChanged: (DateTime newDateTime) { 223 setState(() => dateTime = newDateTime); 224 }, 225 ), 226 ); 227 }, 228 ); 229 }, 230 child: _buildMenu( 231 <Widget>[ 232 const Text('Date and Time'), 233 Text( 234 DateFormat.yMMMd().add_jm().format(dateTime), 235 style: const TextStyle(color: CupertinoColors.inactiveGray), 236 ), 237 ], 238 ), 239 ); 240 } 241 242 @override 243 Widget build(BuildContext context) { 244 return CupertinoPageScaffold( 245 navigationBar: CupertinoNavigationBar( 246 middle: const Text('Picker'), 247 // We're specifying a back label here because the previous page is a 248 // Material page. CupertinoPageRoutes could auto-populate these back 249 // labels. 250 previousPageTitle: 'Cupertino', 251 trailing: CupertinoDemoDocumentationButton(CupertinoPickerDemo.routeName), 252 ), 253 child: DefaultTextStyle( 254 style: CupertinoTheme.of(context).textTheme.textStyle, 255 child: DecoratedBox( 256 decoration: BoxDecoration( 257 color: CupertinoTheme.of(context).brightness == Brightness.light 258 ? CupertinoColors.extraLightBackgroundGray 259 : CupertinoColors.darkBackgroundGray, 260 ), 261 child: ListView( 262 children: <Widget>[ 263 const Padding(padding: EdgeInsets.only(top: 32.0)), 264 _buildColorPicker(context), 265 _buildCountdownTimerPicker(context), 266 _buildDatePicker(context), 267 _buildTimePicker(context), 268 _buildDateAndTimePicker(context), 269 ], 270 ), 271 ), 272 ), 273 ); 274 } 275} 276