Browse Source

add 12 hour time picker

Liu Yanbo 5 years ago
parent
commit
d75b12d303

+ 2 - 1
CHANGELOG.md

@@ -41,4 +41,5 @@
 ## [1.3.0] - fix many bugs
 ## [1.3.1] - add header color
 ## [1.3.2] - add more languages
-## [1.3.4] - add more languages
+## [1.3.4] - add more languages
+## [1.3.5] - add 12 hour time picker with AM/PM

+ 2 - 1
example/ios/Flutter/flutter_export_environment.sh

@@ -2,9 +2,10 @@
 # This is a generated file; do not edit or check into version control.
 export "FLUTTER_ROOT=/Users/realank/flutter"
 export "FLUTTER_APPLICATION_PATH=/Users/realank/Documents/GitHub/flutter_datetime_picker/example"
-export "FLUTTER_TARGET=lib/main.dart"
+export "FLUTTER_TARGET=/Users/realank/Documents/GitHub/flutter_datetime_picker/example/lib/main.dart"
 export "FLUTTER_BUILD_DIR=build"
 export "SYMROOT=${SOURCE_ROOT}/../build/ios"
 export "FLUTTER_FRAMEWORK_DIR=/Users/realank/flutter/bin/cache/artifacts/engine/ios"
 export "FLUTTER_BUILD_NAME=1.0.0"
 export "FLUTTER_BUILD_NUMBER=1"
+export "TRACK_WIDGET_CREATION=true"

+ 37 - 61
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());
   }
 }
 
@@ -112,14 +101,10 @@ class HomePage extends StatelessWidget {
                           headerColor: Colors.orange,
                           backgroundColor: Colors.blue,
                           itemStyle: TextStyle(
-                              color: Colors.white,
-                              fontWeight: FontWeight.bold,
-                              fontSize: 18),
-                          doneStyle:
-                              TextStyle(color: Colors.white, fontSize: 16)),
+                              color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18),
+                          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);
@@ -130,10 +115,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());
@@ -142,14 +125,25 @@ class HomePage extends StatelessWidget {
                   'show time picker',
                   style: TextStyle(color: Colors.blue),
                 )),
+            FlatButton(
+                onPressed: () {
+                  DatePicker.showTime12hPicker(context, showTitleActions: true, onChanged: (date) {
+                    print('change $date in time zone ' + date.timeZoneOffset.inHours.toString());
+                  }, onConfirm: (date) {
+                    print('confirm $date');
+                  }, currentTime: DateTime.now());
+                },
+                child: Text(
+                  'show 12H time picker with AM/PM',
+                  style: TextStyle(color: Colors.blue),
+                )),
             FlatButton(
                 onPressed: () {
                   DatePicker.showDateTimePicker(context,
                       showTitleActions: true,
                       minTime: DateTime(2020, 5, 5, 20, 50),
                       maxTime: DateTime(2020, 6, 7, 05, 09), 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');
                   }, locale: LocaleType.zh);
@@ -160,10 +154,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));
@@ -174,15 +166,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)',
@@ -190,15 +178,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)',
@@ -206,15 +190,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)',
@@ -222,15 +202,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',

+ 43 - 38
lib/flutter_datetime_picker.dart

@@ -37,13 +37,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)));
   }
 
   ///
@@ -67,12 +63,33 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
             pickerModel: TimePickerModel(
-                currentTime: currentTime,
-                locale: locale,
-                showSecondsColumn: showSecondsColumn)));
+                currentTime: currentTime, locale: locale, showSecondsColumn: showSecondsColumn)));
+  }
+
+  ///
+  /// Display time picker bottom sheet with AM/PM.
+  ///
+  static Future<DateTime> showTime12hPicker(
+    BuildContext context, {
+    bool showTitleActions: true,
+    DateChangedCallback onChanged,
+    DateChangedCallback onConfirm,
+    locale: LocaleType.en,
+    DateTime currentTime,
+    DatePickerTheme theme,
+  }) async {
+    return await Navigator.push(
+        context,
+        new _DatePickerRoute(
+            showTitleActions: showTitleActions,
+            onChanged: onChanged,
+            onConfirm: onConfirm,
+            locale: locale,
+            theme: theme,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            pickerModel: Time12hPickerModel(currentTime: currentTime, locale: locale)));
   }
 
   ///
@@ -97,13 +114,9 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
             pickerModel: DateTimePickerModel(
-                currentTime: currentTime,
-                minTime: minTime,
-                maxTime: maxTime,
-                locale: locale)));
+                currentTime: currentTime, minTime: minTime, maxTime: maxTime, locale: locale)));
   }
 
   ///
@@ -126,8 +139,7 @@ class DatePicker {
             onConfirm: onConfirm,
             locale: locale,
             theme: theme,
-            barrierLabel:
-                MaterialLocalizations.of(context).modalBarrierDismissLabel,
+            barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel,
             pickerModel: pickerModel));
   }
 }
@@ -170,14 +182,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,
@@ -198,11 +209,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;
 
@@ -229,12 +236,12 @@ class _DatePickerState extends State<_DatePickerComponent> {
 
   void refreshScrollOffset() {
 //    print('refreshScrollOffset ${widget.pickerModel.currentRightIndex()}');
-    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
@@ -248,8 +255,7 @@ class _DatePickerState extends State<_DatePickerComponent> {
           return ClipRect(
             child: CustomSingleChildLayout(
               delegate: _BottomPickerLayout(widget.route.animation.value, theme,
-                  showTitleActions: widget.route.showTitleActions,
-                  bottomPadding: bottomPadding),
+                  showTitleActions: widget.route.showTitleActions, bottomPadding: bottomPadding),
               child: GestureDetector(
                 child: Material(
                   color: theme.backgroundColor ?? Colors.white,
@@ -295,8 +301,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 &&

+ 86 - 41
lib/src/date_model.dart

@@ -45,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) {
@@ -119,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);
@@ -165,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() {
@@ -364,8 +355,7 @@ class DatePickerModel extends CommonPickerModel {
 class TimePickerModel extends CommonPickerModel {
   bool showSecondsColumn;
 
-  TimePickerModel(
-      {DateTime currentTime, LocaleType locale, this.showSecondsColumn: true})
+  TimePickerModel({DateTime currentTime, LocaleType locale, this.showSecondsColumn: true})
       : super(locale: locale) {
     this.currentTime = currentTime ?? DateTime.now();
 
@@ -425,10 +415,79 @@ 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 time picker model
+class Time12hPickerModel extends CommonPickerModel {
+  Time12hPickerModel({DateTime currentTime, LocaleType locale}) : super(locale: locale) {
+    this.currentTime = currentTime ?? DateTime.now();
+
+    _currentLeftIndex = this.currentTime.hour % 12;
+    _currentMiddleIndex = this.currentTime.minute;
+    _currentRightIndex = this.currentTime.hour < 12 ? 0 : 1;
+  }
+
+  @override
+  String leftStringAtIndex(int index) {
+    if (index >= 0 && index < 12) {
+      if (index == 0) {
+        return digits(12, 2);
+      } else {
+        return digits(index, 2);
+      }
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  String middleStringAtIndex(int index) {
+    if (index >= 0 && index < 60) {
+      return digits(index, 2);
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  String rightStringAtIndex(int index) {
+    if (index == 0) {
+      return "AM";
+    } else if (index == 1) {
+      return "PM";
+    } else {
+      return null;
+    }
+  }
+
+  @override
+  String leftDivider() {
+    return ":";
+  }
+
+  @override
+  String rightDivider() {
+    return ":";
+  }
+
+  @override
+  List<int> layoutProportions() {
+    return [1, 1, 1];
+  }
+
+  @override
+  DateTime finalTime() {
+    int hour = _currentLeftIndex + 12 * _currentRightIndex;
+    return currentTime.isUtc
+        ? DateTime.utc(
+            currentTime.year, currentTime.month, currentTime.day, hour, _currentMiddleIndex, 0)
+        : DateTime(
+            currentTime.year, currentTime.month, currentTime.day, hour, _currentMiddleIndex, 0);
   }
 }
 
@@ -436,22 +495,16 @@ class TimePickerModel extends CommonPickerModel {
 class DateTimePickerModel extends CommonPickerModel {
   DateTime maxTime;
   DateTime minTime;
-  DateTimePickerModel(
-      {DateTime currentTime,
-      DateTime maxTime,
-      DateTime minTime,
-      LocaleType locale})
+  DateTimePickerModel({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale})
       : super(locale: locale) {
     if (currentTime != null) {
       this.currentTime = currentTime;
       if (maxTime != null &&
-          (currentTime.isBefore(maxTime) ||
-              currentTime.isAtSameMomentAs(maxTime))) {
+          (currentTime.isBefore(maxTime) || currentTime.isAtSameMomentAs(maxTime))) {
         this.maxTime = maxTime;
       }
       if (minTime != null &&
-          (currentTime.isAfter(minTime) ||
-              currentTime.isAtSameMomentAs(minTime))) {
+          (currentTime.isAfter(minTime) || currentTime.isAtSameMomentAs(minTime))) {
         this.minTime = minTime;
       }
     } else {
@@ -467,9 +520,7 @@ class DateTimePickerModel extends CommonPickerModel {
       }
     }
 
-    if (this.minTime != null &&
-        this.maxTime != null &&
-        this.maxTime.isBefore(this.minTime)) {
+    if (this.minTime != null && this.maxTime != null && this.maxTime.isBefore(this.minTime)) {
       // invalid
       this.minTime = null;
       this.maxTime = null;
@@ -518,8 +569,7 @@ class DateTimePickerModel extends CommonPickerModel {
       if (_currentRightIndex > maxIndex) {
         _currentRightIndex = maxIndex;
       }
-    } else if (isAtSameDay(maxTime, time) &&
-        _currentMiddleIndex == maxTime.hour) {
+    } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex == maxTime.hour) {
       var maxIndex = maxTime.minute;
       if (_currentRightIndex > maxIndex) {
         _currentRightIndex = maxIndex;
@@ -530,13 +580,9 @@ class DateTimePickerModel extends CommonPickerModel {
   @override
   String leftStringAtIndex(int index) {
     DateTime time = currentTime.add(Duration(days: index));
-    if (minTime != null &&
-        time.isBefore(minTime) &&
-        !isAtSameDay(minTime, time)) {
+    if (minTime != null && time.isBefore(minTime) && !isAtSameDay(minTime, time)) {
       return null;
-    } else if (maxTime != null &&
-        time.isAfter(maxTime) &&
-        !isAtSameDay(maxTime, time)) {
+    } else if (maxTime != null && time.isAfter(maxTime) && !isAtSameDay(maxTime, time)) {
       return null;
     }
     return formatDate(time, [ymdw], locale);
@@ -575,8 +621,7 @@ class DateTimePickerModel extends CommonPickerModel {
         } else {
           return null;
         }
-      } else if (isAtSameDay(maxTime, time) &&
-          _currentMiddleIndex >= maxTime.hour) {
+      } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex >= maxTime.hour) {
         if (index >= 0 && index <= maxTime.minute) {
           return digits(index, 2);
         } else {

+ 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.3.4
+version: 1.3.5
 homepage: https://github.com/Realank/flutter_datetime_picker
 
 environment: