Bladeren bron

add min/max time for date time picker

Liu Yanbo 6 jaren geleden
bovenliggende
commit
353482e188
5 gewijzigde bestanden met toevoegingen van 184 en 135 verwijderingen
  1. 2 1
      CHANGELOG.md
  2. 30 65
      example/lib/main.dart
  3. 25 39
      lib/flutter_datetime_picker.dart
  4. 126 29
      lib/src/date_model.dart
  5. 1 1
      pubspec.yaml

+ 2 - 1
CHANGELOG.md

@@ -35,4 +35,5 @@
 ## [1.2.3] - fix confirm pop issue
 ## [1.2.4] - fix format
 ## [1.2.5] - add more languages
-## [1.2.6] - add more languages
+## [1.2.6] - add more languages
+## [1.2.7] - add max/min time for date time picker

+ 30 - 65
example/lib/main.dart

@@ -8,8 +8,7 @@ class CustomPicker extends CommonPickerModel {
     return '$value'.padLeft(length, "0");
   }
 
-  CustomPicker({DateTime currentTime, LocaleType locale})
-      : super(locale: locale) {
+  CustomPicker({DateTime currentTime, LocaleType locale}) : super(locale: locale) {
     this.currentTime = currentTime ?? DateTime.now();
     this.setLeftIndex(this.currentTime.hour);
     this.setMiddleIndex(this.currentTime.minute);
@@ -61,20 +60,10 @@ class CustomPicker extends CommonPickerModel {
   @override
   DateTime finalTime() {
     return currentTime.isUtc
-        ? DateTime.utc(
-            currentTime.year,
-            currentTime.month,
-            currentTime.day,
-            this.currentLeftIndex(),
-            this.currentMiddleIndex(),
-            this.currentRightIndex())
-        : DateTime(
-            currentTime.year,
-            currentTime.month,
-            currentTime.day,
-            this.currentLeftIndex(),
-            this.currentMiddleIndex(),
-            this.currentRightIndex());
+        ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day,
+            this.currentLeftIndex(), this.currentMiddleIndex(), this.currentRightIndex())
+        : DateTime(currentTime.year, currentTime.month, currentTime.day, this.currentLeftIndex(),
+            this.currentMiddleIndex(), this.currentRightIndex());
   }
 }
 
@@ -110,13 +99,10 @@ class HomePage extends StatelessWidget {
                       maxTime: DateTime(2019, 6, 7),
                       theme: DatePickerTheme(
                           backgroundColor: Colors.blue,
-                          itemStyle: TextStyle(
-                              color: Colors.white, fontWeight: FontWeight.bold),
-                          doneStyle:
-                              TextStyle(color: Colors.white, fontSize: 16)),
+                          itemStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
+                          doneStyle: TextStyle(color: Colors.white, fontSize: 16)),
                       onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
                   }, currentTime: DateTime.now(), locale: LocaleType.en);
@@ -127,10 +113,8 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showTimePicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
                   }, currentTime: DateTime.now());
@@ -141,15 +125,14 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showDateTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showDateTimePicker(context,
+                      showTitleActions: true,
+                      minTime: DateTime(2018, 5, 5, 20, 50),
+                      maxTime: DateTime(2018, 6, 7, 05, 09), onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
-                  },
-                      currentTime: DateTime(2008, 12, 31, 23, 12, 34),
-                      locale: LocaleType.zh);
+                  }, currentTime: DateTime(2018, 5, 31, 23, 12, 34), locale: LocaleType.zh);
                 },
                 child: Text(
                   'show date time picker (Chinese)',
@@ -157,10 +140,8 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showDateTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
                   }, currentTime: DateTime(2008, 12, 31, 23, 12, 34));
@@ -171,15 +152,11 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showDateTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
-                  },
-                      currentTime: DateTime(2008, 12, 31, 23, 12, 34),
-                      locale: LocaleType.nl);
+                  }, currentTime: DateTime(2008, 12, 31, 23, 12, 34), locale: LocaleType.nl);
                 },
                 child: Text(
                   'show date time picker (Dutch)',
@@ -187,15 +164,11 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showDateTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
-                  },
-                      currentTime: DateTime(2008, 12, 31, 23, 12, 34),
-                      locale: LocaleType.ru);
+                  }, currentTime: DateTime(2008, 12, 31, 23, 12, 34), locale: LocaleType.ru);
                 },
                 child: Text(
                   'show date time picker (Russian)',
@@ -203,15 +176,11 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showDateTimePicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
-                  },
-                      currentTime: DateTime.utc(2019, 12, 31, 23, 12, 34),
-                      locale: LocaleType.de);
+                  }, currentTime: DateTime.utc(2019, 12, 31, 23, 12, 34), locale: LocaleType.de);
                 },
                 child: Text(
                   'show date time picker in UTC (German)',
@@ -219,15 +188,11 @@ class HomePage extends StatelessWidget {
                 )),
             FlatButton(
                 onPressed: () {
-                  DatePicker.showPicker(context, showTitleActions: true,
-                      onChanged: (date) {
-                    print('change $date in time zone ' +
-                        date.timeZoneOffset.inHours.toString());
+                  DatePicker.showPicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
                   }, onConfirm: (date) {
                     print('confirm $date');
-                  },
-                      pickerModel: CustomPicker(currentTime: DateTime.now()),
-                      locale: LocaleType.en);
+                  }, pickerModel: CustomPicker(currentTime: DateTime.now()), locale: LocaleType.en);
                 },
                 child: Text(
                   'show custom time picker,\nyou can custom picker model like this',

+ 25 - 39
lib/flutter_datetime_picker.dart

@@ -36,13 +36,9 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
             pickerModel: DatePickerModel(
-                currentTime: currentTime,
-                maxTime: maxTime,
-                minTime: minTime,
-                locale: locale)));
+                currentTime: currentTime, maxTime: maxTime, minTime: minTime, locale: locale)));
   }
 
   ///
@@ -65,10 +61,8 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
-            pickerModel:
-                TimePickerModel(currentTime: currentTime, locale: locale)));
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            pickerModel: TimePickerModel(currentTime: currentTime, locale: locale)));
   }
 
   ///
@@ -77,6 +71,8 @@ class DatePicker {
   static Future showDateTimePicker(
     BuildContext context, {
     bool showTitleActions: true,
+    DateTime minTime,
+    DateTime maxTime,
     DateChangedCallback onChanged,
     DateChangedCallback onConfirm,
     locale: LocaleType.en,
@@ -91,10 +87,9 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
-            pickerModel:
-                DateTimePickerModel(currentTime: currentTime, locale: locale)));
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            pickerModel: DateTimePickerModel(
+                currentTime: currentTime, minTime: minTime, maxTime: maxTime, locale: locale)));
   }
 
   ///
@@ -117,8 +112,7 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
             pickerModel: pickerModel));
   }
 }
@@ -161,14 +155,13 @@ class _DatePickerRoute<T> extends PopupRoute<T> {
   @override
   AnimationController createAnimationController() {
     assert(_animationController == null);
-    _animationController =
-        BottomSheet.createAnimationController(navigator.overlay);
+    _animationController = BottomSheet.createAnimationController(navigator.overlay);
     return _animationController;
   }
 
   @override
-  Widget buildPage(BuildContext context, Animation<double> animation,
-      Animation<double> secondaryAnimation) {
+  Widget buildPage(
+      BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
     Widget bottomSheet = new MediaQuery.removePadding(
       context: context,
       removeTop: true,
@@ -189,11 +182,7 @@ class _DatePickerRoute<T> extends PopupRoute<T> {
 
 class _DatePickerComponent extends StatefulWidget {
   _DatePickerComponent(
-      {Key key,
-      @required this.route,
-      this.onChanged,
-      this.locale,
-      this.pickerModel});
+      {Key key, @required this.route, this.onChanged, this.locale, this.pickerModel});
 
   final DateChangedCallback onChanged;
 
@@ -219,12 +208,12 @@ class _DatePickerState extends State<_DatePickerComponent> {
   }
 
   void refreshScrollOffset() {
-    leftScrollCtrl = new FixedExtentScrollController(
-        initialItem: widget.pickerModel.currentLeftIndex());
-    middleScrollCtrl = new FixedExtentScrollController(
-        initialItem: widget.pickerModel.currentMiddleIndex());
-    rightScrollCtrl = new FixedExtentScrollController(
-        initialItem: widget.pickerModel.currentRightIndex());
+    leftScrollCtrl =
+        new FixedExtentScrollController(initialItem: widget.pickerModel.currentLeftIndex());
+    middleScrollCtrl =
+        new FixedExtentScrollController(initialItem: widget.pickerModel.currentMiddleIndex());
+    rightScrollCtrl =
+        new FixedExtentScrollController(initialItem: widget.pickerModel.currentRightIndex());
   }
 
   @override
@@ -236,8 +225,7 @@ class _DatePickerState extends State<_DatePickerComponent> {
         builder: (BuildContext context, Widget child) {
           return new ClipRect(
             child: new CustomSingleChildLayout(
-              delegate: new _BottomPickerLayout(
-                  widget.route.animation.value, theme,
+              delegate: new _BottomPickerLayout(widget.route.animation.value, theme,
                   showTitleActions: widget.route.showTitleActions),
               child: new GestureDetector(
                 child: Material(
@@ -284,8 +272,7 @@ class _DatePickerState extends State<_DatePickerComponent> {
       child: Container(
           padding: EdgeInsets.all(8.0),
           height: theme.containerHeight,
-          decoration:
-              BoxDecoration(color: theme.backgroundColor ?? Colors.white),
+          decoration: BoxDecoration(color: theme.backgroundColor ?? Colors.white),
           child: NotificationListener(
               onNotification: (ScrollNotification notification) {
                 if (notification.depth == 0 &&
@@ -366,8 +353,8 @@ class _DatePickerState extends State<_DatePickerComponent> {
             style: theme.itemStyle,
           ),
           _renderColumnView(
-              ValueKey(widget.pickerModel.currentMiddleIndex() +
-                  widget.pickerModel.currentLeftIndex()),
+              ValueKey(
+                  widget.pickerModel.currentMiddleIndex() + widget.pickerModel.currentLeftIndex()),
               theme,
               widget.pickerModel.rightStringAtIndex,
               rightScrollCtrl,
@@ -435,8 +422,7 @@ class _DatePickerState extends State<_DatePickerComponent> {
 }
 
 class _BottomPickerLayout extends SingleChildLayoutDelegate {
-  _BottomPickerLayout(this.progress, this.theme,
-      {this.itemCount, this.showTitleActions});
+  _BottomPickerLayout(this.progress, this.theme, {this.itemCount, this.showTitleActions});
 
   final double progress;
   final int itemCount;

+ 126 - 29
lib/src/date_model.dart

@@ -1,6 +1,7 @@
 import 'package:flutter_datetime_picker/src/date_format.dart';
 import 'package:flutter_datetime_picker/src/i18n_model.dart';
 import 'datetime_util.dart';
+import 'dart:math';
 
 //interface for picker data model
 abstract class BasePickerModel {
@@ -44,8 +45,7 @@ class CommonPickerModel extends BasePickerModel {
 
   LocaleType locale;
 
-  CommonPickerModel({this.currentTime, locale})
-      : this.locale = locale ?? LocaleType.en;
+  CommonPickerModel({this.currentTime, locale}) : this.locale = locale ?? LocaleType.en;
 
   @override
   String leftStringAtIndex(int index) {
@@ -118,11 +118,7 @@ class DatePickerModel extends CommonPickerModel {
   DateTime maxTime;
   DateTime minTime;
 
-  DatePickerModel(
-      {DateTime currentTime,
-      DateTime maxTime,
-      DateTime minTime,
-      LocaleType locale})
+  DatePickerModel({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale})
       : super(locale: locale) {
     this.maxTime = maxTime ?? DateTime(2049, 12, 31);
     this.minTime = minTime ?? DateTime(1970, 1, 1);
@@ -164,17 +160,13 @@ class DatePickerModel extends CommonPickerModel {
 
   int _maxDayOfCurrentMonth() {
     int dayCount = calcDateCount(currentTime.year, currentTime.month);
-    return currentTime.year == maxTime.year &&
-            currentTime.month == maxTime.month
+    return currentTime.year == maxTime.year && currentTime.month == maxTime.month
         ? maxTime.day
         : dayCount;
   }
 
   int _minDayOfCurrentMonth() {
-    return currentTime.year == minTime.year &&
-            currentTime.month == minTime.month
-        ? minTime.day
-        : 1;
+    return currentTime.year == minTime.year && currentTime.month == minTime.month ? minTime.day : 1;
   }
 
   void _fillMiddleLists() {
@@ -361,8 +353,7 @@ class DatePickerModel extends CommonPickerModel {
 
 //a time picker model
 class TimePickerModel extends CommonPickerModel {
-  TimePickerModel({DateTime currentTime, LocaleType locale})
-      : super(locale: locale) {
+  TimePickerModel({DateTime currentTime, LocaleType locale}) : super(locale: locale) {
     this.currentTime = currentTime ?? DateTime.now();
 
     _currentLeftIndex = this.currentTime.hour;
@@ -410,55 +401,161 @@ class TimePickerModel extends CommonPickerModel {
   @override
   DateTime finalTime() {
     return currentTime.isUtc
-        ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day,
-            _currentLeftIndex, _currentMiddleIndex, _currentRightIndex)
-        : DateTime(currentTime.year, currentTime.month, currentTime.day,
-            _currentLeftIndex, _currentMiddleIndex, _currentRightIndex);
+        ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day, _currentLeftIndex,
+            _currentMiddleIndex, _currentRightIndex)
+        : DateTime(currentTime.year, currentTime.month, currentTime.day, _currentLeftIndex,
+            _currentMiddleIndex, _currentRightIndex);
   }
 }
 
 //a date&time picker model
 class DateTimePickerModel extends CommonPickerModel {
-  DateTimePickerModel({DateTime currentTime, LocaleType locale})
+  DateTime maxTime;
+  DateTime minTime;
+  DateTimePickerModel({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale})
       : super(locale: locale) {
-    this.currentTime = currentTime ?? DateTime.now();
+    if (currentTime != null) {
+      this.currentTime = currentTime;
+      if (currentTime.isBefore(maxTime)) {
+        this.maxTime = maxTime;
+      }
+      if (currentTime.isAfter(minTime)) {
+        this.minTime = minTime;
+      }
+    } else {
+      var now = DateTime.now();
+      if (this.minTime != null && this.minTime.isAfter(now)) {
+        this.currentTime = this.minTime;
+      } else if (this.maxTime != null && this.maxTime.isBefore(now)) {
+        this.currentTime = this.maxTime;
+      } else {
+        this.currentTime = now;
+      }
+    }
+
+    if (this.minTime != null && this.maxTime != null && this.maxTime.isBefore(this.minTime)) {
+      // invalid
+      this.minTime = null;
+      this.maxTime = null;
+    }
+
     _currentLeftIndex = 0;
     _currentMiddleIndex = this.currentTime.hour;
     _currentRightIndex = this.currentTime.minute;
   }
 
+  bool isAtSameDay(DateTime day1, DateTime day2) {
+    return day1 != null &&
+        day2 != null &&
+        day1.difference(day2).inDays == 0 &&
+        day1.day == day2.day;
+  }
+
+  @override
+  void setLeftIndex(int index) {
+    // TODO: implement setLeftIndex
+    super.setLeftIndex(index);
+
+    DateTime time = currentTime.add(Duration(days: index));
+    if (isAtSameDay(minTime, time)) {
+      var index = min(24 - minTime.hour - 1, _currentMiddleIndex);
+      this.setMiddleIndex(index);
+    } else if (isAtSameDay(maxTime, time)) {
+      var index = min(maxTime.hour, _currentMiddleIndex);
+      this.setMiddleIndex(index);
+    }
+  }
+
+  @override
+  void setMiddleIndex(int index) {
+    // TODO: implement setMiddleIndex
+    super.setMiddleIndex(index);
+    DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
+    if (isAtSameDay(minTime, time) && index == 0) {
+      var maxIndex = 60 - minTime.minute - 1;
+      if (_currentRightIndex > maxIndex) {
+        _currentRightIndex = maxIndex;
+      }
+    } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex == maxTime.hour) {
+      var maxIndex = maxTime.minute;
+      if (_currentRightIndex > maxIndex) {
+        _currentRightIndex = maxIndex;
+      }
+    }
+  }
+
   @override
   String leftStringAtIndex(int index) {
     DateTime time = currentTime.add(Duration(days: index));
+    if (minTime != null && time.isBefore(minTime) && !isAtSameDay(minTime, time)) {
+      return null;
+    } else if (maxTime != null && time.isAfter(maxTime) && !isAtSameDay(maxTime, time)) {
+      return null;
+    }
     return formatDate(time, [ymdw], locale);
   }
 
   @override
   String middleStringAtIndex(int index) {
     if (index >= 0 && index < 24) {
+      DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
+      if (isAtSameDay(minTime, time)) {
+        if (index >= 0 && index < 24 - minTime.hour) {
+          return digits(minTime.hour + index, 2);
+        } else {
+          return null;
+        }
+      } else if (isAtSameDay(maxTime, time)) {
+        if (index >= 0 && index <= maxTime.hour) {
+          return digits(index, 2);
+        } else {
+          return null;
+        }
+      }
       return digits(index, 2);
-    } else {
-      return null;
     }
+
+    return null;
   }
 
   @override
   String rightStringAtIndex(int index) {
     if (index >= 0 && index < 60) {
+      DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
+      if (isAtSameDay(minTime, time) && _currentMiddleIndex == 0) {
+        if (index >= 0 && index < 60 - minTime.minute) {
+          return digits(minTime.minute + index, 2);
+        } else {
+          return null;
+        }
+      } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex >= maxTime.hour) {
+        if (index >= 0 && index <= maxTime.minute) {
+          return digits(index, 2);
+        } else {
+          return null;
+        }
+      }
       return digits(index, 2);
-    } else {
-      return null;
     }
+
+    return null;
   }
 
   @override
   DateTime finalTime() {
     DateTime time = currentTime.add(Duration(days: _currentLeftIndex));
+    var hour = _currentMiddleIndex;
+    var minute = _currentRightIndex;
+    if (isAtSameDay(minTime, time)) {
+      hour += minTime.hour;
+      if (minTime.hour == hour) {
+        minute += minTime.minute;
+      }
+    }
+
     return currentTime.isUtc
-        ? DateTime.utc(time.year, time.month, time.day, _currentMiddleIndex,
-            _currentRightIndex)
-        : DateTime(time.year, time.month, time.day, _currentMiddleIndex,
-            _currentRightIndex);
+        ? DateTime.utc(time.year, time.month, time.day, hour, minute)
+        : DateTime(time.year, time.month, time.day, hour, minute);
   }
 
   @override

+ 1 - 1
pubspec.yaml

@@ -1,6 +1,6 @@
 name: flutter_datetime_picker
 description: A date time picker for flutter, you can choose date / time / date&time in English Dutch and Chinese, and you can also custom your own picker content
-version: 1.2.6
+version: 1.2.7
 author: Realank <realank@126.com>
 homepage: https://github.com/Realank/flutter_datetime_picker