1
1
import 'dart:async' ;
2
- import 'dart:io' ;
3
2
4
- import 'package:flutter/foundation.dart' ;
5
3
import 'package:flutter/material.dart' ;
6
4
import 'package:flutter/services.dart' ;
7
- import 'package:flutter_keyboard_visibility/flutter_keyboard_visibility.dart' ;
8
5
import 'package:intl/intl.dart' hide TextDirection;
9
6
import 'package:vsc_datetime_field/datetime_parser.dart' ;
10
7
11
- final _kbdSupportedPlatform = (kIsWeb || Platform .isAndroid || Platform .isIOS);
12
-
13
- // Unfortunately stolen from flutter/lib/src/material/calendar_date_picker.dart
14
- const double _dayPickerRowHeight = 42.0 ;
15
- const int _maxDayPickerRowCount = 6 ; // A 31 day month that starts on Saturday.
16
- // One extra row for the day-of-week header.
17
- const double _maxDayPickerHeight =
18
- _dayPickerRowHeight * (_maxDayPickerRowCount + 1 );
19
- // Value is from flutter/lib/src/material/date_picker.dart:
20
- const _pickerWidth = 330.0 ;
21
-
22
8
final _yearSuffixRegexp = RegExp (r'[-/]y+' );
23
9
24
10
const _timePatterns24h = [
@@ -41,16 +27,6 @@ const _timePatternsAmPm = [
41
27
42
28
enum VscDatetimeFieldType { date, datetime, time }
43
29
44
- /*
45
- * TODO
46
- * - Sometimes there's just not enough room with the kbd open on mobile. Don't show any picker in this case.
47
- * But if the mobile kbd closes, recalculate available size
48
- * - Sometimes on mobile the screen doesn't scroll with the kbd up, even though the example has a scroll widget,
49
- * it doesn't have enough height to perform scrolling.
50
- * - Maybe on mobile if there is not enough height, don't show the picker but if the calendar icon is tapped,
51
- * show the dialog instead.
52
- */
53
-
54
30
class VscDatetimeField extends StatefulWidget {
55
31
/// Type of field desired.
56
32
final VscDatetimeFieldType type;
@@ -245,11 +221,6 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
245
221
widget.textFieldConfiguration.focusNode ?? _focusNode;
246
222
late VoidCallback _focusNodeListener;
247
223
248
- // Keyboard detection
249
- final Stream <bool >? _keyboardVisibility =
250
- (_kbdSupportedPlatform) ? KeyboardVisibilityController ().onChange : null ;
251
- late StreamSubscription <bool >? _keyboardVisibilitySubscription;
252
-
253
224
final _textFieldGlobalKey = GlobalKey ();
254
225
255
226
DateTime ? _value;
@@ -278,7 +249,6 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
278
249
279
250
@override
280
251
void dispose () {
281
- _keyboardVisibilitySubscription? .cancel ();
282
252
_effectiveFocusNode.removeListener (_focusNodeListener);
283
253
_focusNode.dispose ();
284
254
_textEditingController.dispose ();
@@ -364,18 +334,11 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
364
334
Future <void > _openPicker () async {
365
335
switch (widget.type) {
366
336
case VscDatetimeFieldType .date:
367
- case VscDatetimeFieldType .datetime:
368
- final selected = await showDatePicker (
369
- context: context,
370
- initialDate: _value ?? DateTime .now (),
371
- firstDate: widget.minValue,
372
- lastDate: widget.maxValue,
373
- );
374
-
337
+ final selected = await _showCustomizedDatePicker ();
375
338
_effectiveFocusNode.requestFocus ();
376
339
377
340
if (selected != null ) {
378
- // Modify the field's DateTime, sans the time component.
341
+ // Modify the field's DateTime date component.
379
342
final currValue = _value ?? testableNow ();
380
343
_setValue (
381
344
DateTime (
@@ -391,30 +354,39 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
391
354
setTextAndMoveCursorToEnd: true ,
392
355
);
393
356
}
394
-
395
357
break ;
358
+ case VscDatetimeFieldType .datetime:
359
+ final selectedDate = await _showCustomizedDatePicker ();
360
+ if (selectedDate == null ) break ;
396
361
397
- case VscDatetimeFieldType .time:
398
- final selected = await showTimePicker (
399
- context: context,
400
- initialTime: TimeOfDay .now (),
401
- // TODO
402
- // initialDate: _value ?? DateTime.now(),
403
- // firstDate: widget.minValue,
404
- // lastDate: widget.maxValue,
405
- builder: (context, Widget ? child) {
406
- return MediaQuery (
407
- data:
408
- MediaQuery .of (context).copyWith (alwaysUse24HourFormat: false ),
409
- child: child! ,
410
- );
411
- },
362
+ var selectedTime = await _showCustomizedTimePicker ();
363
+ _effectiveFocusNode.requestFocus ();
364
+
365
+ selectedTime ?? = _value == null
366
+ ? const TimeOfDay (hour: 0 , minute: 0 )
367
+ : TimeOfDay .fromDateTime (_value! );
368
+
369
+ _setValue (
370
+ DateTime (
371
+ selectedDate.year,
372
+ selectedDate.month,
373
+ selectedDate.day,
374
+ selectedTime.hour,
375
+ selectedTime.minute,
376
+ 0 ,
377
+ 0 ,
378
+ 0 ,
379
+ ),
380
+ setTextAndMoveCursorToEnd: true ,
412
381
);
382
+ break ;
413
383
384
+ case VscDatetimeFieldType .time:
385
+ final selected = await _showCustomizedTimePicker ();
414
386
_effectiveFocusNode.requestFocus ();
415
387
416
388
if (selected != null ) {
417
- // Modify the field's DateTime, sans the date component.
389
+ // Modify the field's DateTime time component.
418
390
final currValue = _value ?? testableNow ();
419
391
_setValue (
420
392
DateTime (
@@ -434,6 +406,32 @@ class VscDatetimeFieldState extends State<VscDatetimeField> {
434
406
}
435
407
}
436
408
409
+ Future <TimeOfDay ?> _showCustomizedTimePicker () async {
410
+ final selected = await showTimePicker (
411
+ context: context,
412
+ initialTime: _value == null
413
+ ? const TimeOfDay (hour: 0 , minute: 0 )
414
+ : TimeOfDay .fromDateTime (_value! ),
415
+ builder: (context, Widget ? child) {
416
+ return MediaQuery (
417
+ data: MediaQuery .of (context).copyWith (alwaysUse24HourFormat: false ),
418
+ child: child! ,
419
+ );
420
+ },
421
+ );
422
+ return selected;
423
+ }
424
+
425
+ Future <DateTime ?> _showCustomizedDatePicker () async {
426
+ final selected = await showDatePicker (
427
+ context: context,
428
+ initialDate: _value ?? testableNow (),
429
+ firstDate: widget.minValue,
430
+ lastDate: widget.maxValue,
431
+ );
432
+ return selected;
433
+ }
434
+
437
435
void _setValue (
438
436
DateTime ? newValue, {
439
437
bool setText = false ,
0 commit comments