├── res └── values │ └── strings_en.arb ├── example ├── ios │ ├── Flutter │ │ ├── Debug.xcconfig │ │ ├── Release.xcconfig │ │ ├── flutter_export_environment.sh │ │ ├── Flutter.podspec │ │ └── AppFrameworkInfo.plist │ ├── Runner │ │ ├── AppDelegate.h │ │ ├── Assets.xcassets │ │ │ ├── LaunchImage.imageset │ │ │ │ ├── LaunchImage.png │ │ │ │ ├── LaunchImage@2x.png │ │ │ │ ├── LaunchImage@3x.png │ │ │ │ ├── README.md │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ ├── Icon-App-20x20@1x.png │ │ │ │ ├── Icon-App-20x20@2x.png │ │ │ │ ├── Icon-App-20x20@3x.png │ │ │ │ ├── Icon-App-29x29@1x.png │ │ │ │ ├── Icon-App-29x29@2x.png │ │ │ │ ├── Icon-App-29x29@3x.png │ │ │ │ ├── Icon-App-40x40@1x.png │ │ │ │ ├── Icon-App-40x40@2x.png │ │ │ │ ├── Icon-App-40x40@3x.png │ │ │ │ ├── Icon-App-60x60@2x.png │ │ │ │ ├── Icon-App-60x60@3x.png │ │ │ │ ├── Icon-App-76x76@1x.png │ │ │ │ ├── Icon-App-76x76@2x.png │ │ │ │ ├── Icon-App-1024x1024@1x.png │ │ │ │ ├── Icon-App-83.5x83.5@2x.png │ │ │ │ └── Contents.json │ │ ├── main.m │ │ ├── AppDelegate.m │ │ ├── Info.plist │ │ └── Base.lproj │ │ │ ├── Main.storyboard │ │ │ └── LaunchScreen.storyboard │ ├── Runner.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── WorkspaceSettings.xcsettings │ ├── Runner.xcodeproj │ │ ├── project.xcworkspace │ │ │ └── contents.xcworkspacedata │ │ ├── xcshareddata │ │ │ └── xcschemes │ │ │ │ └── Runner.xcscheme │ │ └── project.pbxproj │ └── .gitignore ├── android │ ├── .settings │ │ └── org.eclipse.buildship.core.prefs │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── app │ │ ├── src │ │ │ └── main │ │ │ │ ├── res │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ └── ic_launcher.png │ │ │ │ ├── values │ │ │ │ │ └── styles.xml │ │ │ │ └── drawable │ │ │ │ │ └── launch_background.xml │ │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── realank │ │ │ │ │ └── example │ │ │ │ │ └── MainActivity.java │ │ │ │ └── AndroidManifest.xml │ │ └── build.gradle │ ├── .gitignore │ ├── .project │ ├── settings.gradle │ ├── build.gradle │ ├── gradlew.bat │ └── gradlew ├── .gitignore ├── .idea │ ├── markdown-navigator │ │ └── profiles_settings.xml │ ├── libraries │ │ ├── Flutter_Plugins.xml │ │ ├── Flutter_for_Android.xml │ │ ├── Dart_SDK.xml │ │ └── Dart_Packages.xml │ ├── runConfigurations │ │ └── main_dart.xml │ ├── modules.xml │ ├── misc.xml │ ├── codeStyles │ │ └── Project.xml │ ├── markdown-navigator.xml │ └── workspace.xml ├── README.md ├── .metadata ├── test │ └── widget_test.dart ├── example.iml ├── example_android.iml ├── pubspec.yaml └── lib │ └── main.dart ├── .gitattributes ├── main_page.png ├── screen_date.png ├── screen_time.png ├── screen_datetime_dutch.png ├── screen_datetime_chinese.png ├── screen_datetime_english.png ├── screen_datetime_russian.png ├── test └── flutter_datetime_picker_test.dart ├── lib ├── src │ ├── datetime_util.dart │ ├── datetime_picker_theme.dart │ ├── date_format.dart │ ├── date_model.dart │ └── i18n_model.dart └── flutter_datetime_picker.dart ├── LICENSE ├── .gitignore ├── CHANGELOG.md ├── pubspec.yaml └── README.md /res/values/strings_en.arb: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example/ios/Flutter/Debug.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /example/ios/Flutter/Release.xcconfig: -------------------------------------------------------------------------------- 1 | #include "Generated.xcconfig" 2 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /main_page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/main_page.png -------------------------------------------------------------------------------- /screen_date.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_date.png -------------------------------------------------------------------------------- /screen_time.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_time.png -------------------------------------------------------------------------------- /example/android/.settings/org.eclipse.buildship.core.prefs: -------------------------------------------------------------------------------- 1 | connection.project.dir= 2 | eclipse.preferences.version=1 3 | -------------------------------------------------------------------------------- /screen_datetime_dutch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_datetime_dutch.png -------------------------------------------------------------------------------- /screen_datetime_chinese.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_datetime_chinese.png -------------------------------------------------------------------------------- /screen_datetime_english.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_datetime_english.png -------------------------------------------------------------------------------- /screen_datetime_russian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/screen_datetime_russian.png -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .dart_tool/ 3 | 4 | .packages 5 | .pub/ 6 | 7 | build/ 8 | 9 | .flutter-plugins 10 | -------------------------------------------------------------------------------- /example/android/gradle.properties: -------------------------------------------------------------------------------- 1 | org.gradle.jvmargs=-Xmx1536M 2 | android.enableR8=true 3 | android.useAndroidX=true 4 | android.enableJetifier=true 5 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | 4 | @interface AppDelegate : FlutterAppDelegate 5 | 6 | @end 7 | -------------------------------------------------------------------------------- /example/.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /example/README.md: -------------------------------------------------------------------------------- 1 | # example 2 | 3 | A demo for flutter_datetime_picker 4 | 5 | ## Getting Started 6 | 7 | For help getting started with Flutter, view our online 8 | [documentation](https://flutter.io/). 9 | -------------------------------------------------------------------------------- /example/android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | *.class 3 | .gradle 4 | /local.properties 5 | /.idea/workspace.xml 6 | /.idea/libraries 7 | .DS_Store 8 | /build 9 | /captures 10 | GeneratedPluginRegistrant.java 11 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hamaluik/flutter_datetime_picker/master/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/flutter_datetime_picker_test.dart: -------------------------------------------------------------------------------- 1 | //import 'package:test/test.dart'; 2 | //import 'package:flutter_datetime_picker/flutter_datetime_picker.dart'; 3 | // 4 | //void main() { 5 | // test('adds one to input values', () {}); 6 | //} 7 | -------------------------------------------------------------------------------- /example/.idea/libraries/Flutter_Plugins.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /example/ios/Runner/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "AppDelegate.h" 4 | 5 | int main(int argc, char* argv[]) { 6 | @autoreleasepool { 7 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /example/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Nov 21 17:00:56 IST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip 7 | -------------------------------------------------------------------------------- /example/.idea/runConfigurations/main_dart.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /example/.metadata: -------------------------------------------------------------------------------- 1 | # This file tracks properties of this Flutter project. 2 | # Used by Flutter tool to assess capabilities and perform upgrades etc. 3 | # 4 | # This file should be version controlled and should not be manually edited. 5 | 6 | version: 7 | revision: 5cd97f0004707872e5e12bdb83b62fbc855b80c8 8 | channel: master 9 | -------------------------------------------------------------------------------- /example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildSystemType 6 | Original 7 | 8 | 9 | -------------------------------------------------------------------------------- /example/.idea/libraries/Flutter_for_Android.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /lib/src/datetime_util.dart: -------------------------------------------------------------------------------- 1 | List _leapYearMonths = const [1, 3, 5, 7, 8, 10, 12]; 2 | 3 | int calcDateCount(int year, int month) { 4 | if (_leapYearMonths.contains(month)) { 5 | return 31; 6 | } else if (month == 2) { 7 | if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { 8 | return 29; 9 | } 10 | return 28; 11 | } 12 | return 30; 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md: -------------------------------------------------------------------------------- 1 | # Launch Screen Assets 2 | 3 | You can customize the launch screen with your own desired assets by replacing the image files in this directory. 4 | 5 | You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. -------------------------------------------------------------------------------- /example/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | -------------------------------------------------------------------------------- /example/android/app/src/main/java/com/realank/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.realank.example; 2 | 3 | import android.os.Bundle; 4 | import io.flutter.app.FlutterActivity; 5 | import io.flutter.plugins.GeneratedPluginRegistrant; 6 | 7 | public class MainActivity extends FlutterActivity { 8 | @Override 9 | protected void onCreate(Bundle savedInstanceState) { 10 | super.onCreate(savedInstanceState); 11 | GeneratedPluginRegistrant.registerWith(this); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /example/ios/Runner/AppDelegate.m: -------------------------------------------------------------------------------- 1 | #include "AppDelegate.h" 2 | #include "GeneratedPluginRegistrant.h" 3 | 4 | @implementation AppDelegate 5 | 6 | - (BOOL)application:(UIApplication *)application 7 | didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 8 | [GeneratedPluginRegistrant registerWithRegistry:self]; 9 | // Override point for customization after application launch. 10 | return [super application:application didFinishLaunchingWithOptions:launchOptions]; 11 | } 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /example/android/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | android 4 | Project android created by Buildship. 5 | 6 | 7 | 8 | 9 | org.eclipse.buildship.core.gradleprojectbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.buildship.core.gradleprojectnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /example/android/app/src/main/res/drawable/launch_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "LaunchImage.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "LaunchImage@2x.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "filename" : "LaunchImage@3x.png", 16 | "scale" : "3x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /example/android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | 3 | def flutterProjectRoot = rootProject.projectDir.parentFile.toPath() 4 | 5 | def plugins = new Properties() 6 | def pluginsFile = new File(flutterProjectRoot.toFile(), '.flutter-plugins') 7 | if (pluginsFile.exists()) { 8 | pluginsFile.withReader('UTF-8') { reader -> plugins.load(reader) } 9 | } 10 | 11 | plugins.each { name, path -> 12 | def pluginDirectory = flutterProjectRoot.resolve(path).resolve('android').toFile() 13 | include ":$name" 14 | project(":$name").projectDir = pluginDirectory 15 | } 16 | -------------------------------------------------------------------------------- /example/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | jcenter() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:3.5.2' 9 | } 10 | } 11 | 12 | allprojects { 13 | repositories { 14 | google() 15 | jcenter() 16 | } 17 | } 18 | 19 | rootProject.buildDir = '../build' 20 | subprojects { 21 | project.buildDir = "${rootProject.buildDir}/${project.name}" 22 | } 23 | subprojects { 24 | project.evaluationDependsOn(':app') 25 | } 26 | 27 | task clean(type: Delete) { 28 | delete rootProject.buildDir 29 | } 30 | -------------------------------------------------------------------------------- /example/ios/Flutter/flutter_export_environment.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # This is a generated file; do not edit or check into version control. 3 | export "FLUTTER_ROOT=/Users/realank/flutter" 4 | export "FLUTTER_APPLICATION_PATH=/Users/realank/Documents/GitHub/flutter_datetime_picker/example" 5 | export "FLUTTER_TARGET=/Users/realank/Documents/GitHub/flutter_datetime_picker/example/lib/main.dart" 6 | export "FLUTTER_BUILD_DIR=build" 7 | export "SYMROOT=${SOURCE_ROOT}/../build/ios" 8 | export "FLUTTER_FRAMEWORK_DIR=/Users/realank/flutter/bin/cache/artifacts/engine/ios" 9 | export "FLUTTER_BUILD_NAME=1.0.0" 10 | export "FLUTTER_BUILD_NUMBER=1" 11 | export "TRACK_WIDGET_CREATION=true" 12 | -------------------------------------------------------------------------------- /example/test/widget_test.dart: -------------------------------------------------------------------------------- 1 | //// This is a basic Flutter widget test. 2 | //// To perform an interaction with a widget in your test, use the WidgetTester utility that Flutter 3 | //// provides. For example, you can send tap and scroll gestures. You can also use WidgetTester to 4 | //// find child widgets in the widget tree, read text, and verify that the values of widget properties 5 | //// are correct. 6 | // 7 | //import 'package:flutter/material.dart'; 8 | //import 'package:flutter_test/flutter_test.dart'; 9 | // 10 | //import 'package:example/main.dart'; 11 | // 12 | //void main() { 13 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {}); 14 | //} 15 | -------------------------------------------------------------------------------- /example/ios/.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vagrant/ 3 | .sconsign.dblite 4 | .svn/ 5 | 6 | .DS_Store 7 | *.swp 8 | profile 9 | 10 | DerivedData/ 11 | build/ 12 | GeneratedPluginRegistrant.h 13 | GeneratedPluginRegistrant.m 14 | 15 | .generated/ 16 | 17 | *.pbxuser 18 | *.mode1v3 19 | *.mode2v3 20 | *.perspectivev3 21 | 22 | !default.pbxuser 23 | !default.mode1v3 24 | !default.mode2v3 25 | !default.perspectivev3 26 | 27 | xcuserdata 28 | 29 | *.moved-aside 30 | 31 | *.pyc 32 | *sync/ 33 | Icon? 34 | .tags* 35 | 36 | /Flutter/app.flx 37 | /Flutter/app.zip 38 | /Flutter/flutter_assets/ 39 | /Flutter/App.framework 40 | /Flutter/Flutter.framework 41 | /Flutter/Generated.xcconfig 42 | /ServiceDefinitions.json 43 | 44 | Pods/ 45 | .symlinks/ 46 | -------------------------------------------------------------------------------- /example/ios/Flutter/Flutter.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # NOTE: This podspec is NOT to be published. It is only used as a local source! 3 | # 4 | 5 | Pod::Spec.new do |s| 6 | s.name = 'Flutter' 7 | s.version = '1.0.0' 8 | s.summary = 'High-performance, high-fidelity mobile apps.' 9 | s.description = <<-DESC 10 | Flutter provides an easy and productive way to build and deploy high-performance mobile apps for Android and iOS. 11 | DESC 12 | s.homepage = 'https://flutter.io' 13 | s.license = { :type => 'MIT' } 14 | s.author = { 'Flutter Dev Team' => 'flutter-dev@googlegroups.com' } 15 | s.source = { :git => 'https://github.com/flutter/engine', :tag => s.version.to_s } 16 | s.ios.deployment_target = '8.0' 17 | s.vendored_frameworks = 'Flutter.framework' 18 | end 19 | -------------------------------------------------------------------------------- /example/ios/Flutter/AppFrameworkInfo.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | App 9 | CFBundleIdentifier 10 | io.flutter.flutter.app 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | App 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1.0 23 | MinimumOSVersion 24 | 8.0 25 | 26 | 27 | -------------------------------------------------------------------------------- /example/example.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /lib/src/datetime_picker_theme.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/foundation.dart'; 2 | import 'package:flutter/material.dart'; 3 | 4 | // Migrate DiagnosticableMixin to Diagnosticable until 5 | // https://github.com/flutter/flutter/pull/51495 makes it into stable (v1.15.21) 6 | class DatePickerTheme with DiagnosticableMixin { 7 | final TextStyle cancelStyle; 8 | final TextStyle doneStyle; 9 | final TextStyle itemStyle; 10 | final Color backgroundColor; 11 | final Color headerColor; 12 | 13 | final double containerHeight; 14 | final double titleHeight; 15 | final double itemHeight; 16 | 17 | const DatePickerTheme({ 18 | this.cancelStyle = const TextStyle(color: Colors.black54, fontSize: 16), 19 | this.doneStyle = const TextStyle(color: Colors.blue, fontSize: 16), 20 | this.itemStyle = const TextStyle(color: Color(0xFF000046), fontSize: 18), 21 | this.backgroundColor = Colors.white, 22 | this.headerColor, 23 | this.containerHeight = 210.0, 24 | this.titleHeight = 44.0, 25 | this.itemHeight = 36.0, 26 | }); 27 | } 28 | -------------------------------------------------------------------------------- /example/.idea/libraries/Dart_SDK.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Liu Yanbo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /example/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 27 | 28 | -------------------------------------------------------------------------------- /example/example_android.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Miscellaneous 2 | *.class 3 | *.lock 4 | *.log 5 | *.pyc 6 | *.swp 7 | .DS_Store 8 | .atom/ 9 | .buildlog/ 10 | .history 11 | .svn/ 12 | 13 | # IntelliJ related 14 | *.iml 15 | *.ipr 16 | *.iws 17 | .idea/ 18 | 19 | # Visual Studio Code related 20 | .vscode/ 21 | 22 | # Flutter/Dart/Pub related 23 | **/doc/api/ 24 | .dart_tool/ 25 | .flutter-plugins 26 | .packages 27 | .pub-cache/ 28 | .pub/ 29 | build/ 30 | 31 | # Android related 32 | pubspec.lock 33 | **/android/**/gradle-wrapper.jar 34 | **/android/.gradle 35 | **/android/captures/ 36 | **/android/gradlew 37 | **/android/gradlew.bat 38 | **/android/local.properties 39 | **/android/**/GeneratedPluginRegistrant.java 40 | 41 | # iOS/XCode related 42 | **/ios/**/*.mode1v3 43 | **/ios/**/*.mode2v3 44 | **/ios/**/*.moved-aside 45 | **/ios/**/*.pbxuser 46 | **/ios/**/*.perspectivev3 47 | **/ios/**/*sync/ 48 | **/ios/**/.sconsign.dblite 49 | **/ios/**/.tags* 50 | **/ios/**/.vagrant/ 51 | **/ios/**/DerivedData/ 52 | **/ios/**/Icon? 53 | **/ios/**/Pods/ 54 | **/ios/**/.symlinks/ 55 | **/ios/**/profile 56 | **/ios/**/xcuserdata 57 | **/ios/.generated/ 58 | **/ios/Flutter/App.framework 59 | **/ios/Flutter/Flutter.framework 60 | **/ios/Flutter/Generated.xcconfig 61 | **/ios/Flutter/app.flx 62 | **/ios/Flutter/app.zip 63 | **/ios/Flutter/flutter_assets/ 64 | **/ios/ServiceDefinitions.json 65 | **/ios/Runner/GeneratedPluginRegistrant.* 66 | 67 | # Exceptions to above rules. 68 | !**/ios/**/default.mode1v3 69 | !**/ios/**/default.mode2v3 70 | !**/ios/**/default.pbxuser 71 | !**/ios/**/default.perspectivev3 72 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages 73 | -------------------------------------------------------------------------------- /example/ios/Runner/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | example 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | $(FLUTTER_BUILD_NAME) 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(FLUTTER_BUILD_NUMBER) 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UISupportedInterfaceOrientations 30 | 31 | UIInterfaceOrientationPortrait 32 | UIInterfaceOrientationLandscapeLeft 33 | UIInterfaceOrientationLandscapeRight 34 | 35 | UISupportedInterfaceOrientations~ipad 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationPortraitUpsideDown 39 | UIInterfaceOrientationLandscapeLeft 40 | UIInterfaceOrientationLandscapeRight 41 | 42 | UIViewControllerBasedStatusBarAppearance 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [0.1.0] - initial submit 2 | ## [0.1.1] - add time picker and date time picker, add i18n 3 | ## [0.1.2] - fix bugs 4 | ## [0.1.3] - fix bugs 5 | ## [0.1.4] - change screenshot path 6 | ## [0.1.5] - change screenshot path 7 | ## [0.1.6] - sync 8 | ## [0.1.7] - pub.dartlang.org bug, re-submit 9 | ## [0.1.8] - update description 10 | ## [0.1.9] - update description 11 | ## [0.1.10] - update description 12 | ## [1.0.0] - release stable version 13 | ## [1.0.1] - fix day bug when changing month 14 | ## [1.0.2] - add Dutch support 15 | ## [1.0.3] - add Dutch in demo 16 | ## [1.0.4] - add Dutch in readme 17 | ## [1.0.5] - add max/min time limit for Date Picker, add theme 18 | ## [1.0.6] - add comments 19 | ## [1.0.7] - fix max/min time for datetime type picker 20 | ## [1.0.8] - add Russian 21 | ## [1.0.9] - fix readme 22 | ## [1.1.0] - fix readme 23 | ## [1.1.1] - add 3 more languages 24 | ## [1.1.2] - add Portuguese 25 | ## [1.1.3] - update date picker format 26 | ## [1.1.4] - add 2 more languages 27 | ## [1.1.5] - add Japanese 28 | ## [1.1.6] - update something 29 | ## [1.1.7] - update something 30 | ## [1.1.8] - update something 31 | ## [1.1.9] - add German 32 | ## [1.2.0] - add support for time zone 33 | ## [1.2.1] - add more languages 34 | ## [1.2.2] - add customize example 35 | ## [1.2.3] - fix confirm pop issue 36 | ## [1.2.4] - fix format 37 | ## [1.2.5] - add more languages 38 | ## [1.2.6] - add more languages 39 | ## [1.2.7] - add max/min time for date time picker 40 | ## [1.2.8] - fix bug 41 | ## [1.3.0] - fix many bugs 42 | ## [1.3.1] - add header color 43 | ## [1.3.2] - add more languages 44 | ## [1.3.4] - add more languages 45 | ## [1.3.5] - add 12 hour time picker with AM/PM 46 | ## [1.3.6] - fix error with Diagnosticable in newer Flutter versions -------------------------------------------------------------------------------- /example/.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: flutter_datetime_picker 2 | 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 3 | version: 1.3.6 4 | homepage: https://github.com/Realank/flutter_datetime_picker 5 | 6 | environment: 7 | sdk: ">=2.0.0 <3.0.0" 8 | 9 | dependencies: 10 | flutter: 11 | sdk: flutter 12 | 13 | dev_dependencies: 14 | flutter_test: 15 | sdk: flutter 16 | 17 | # For information on the generic Dart part of this file, see the 18 | # following page: https://www.dartlang.org/tools/pub/pubspec 19 | 20 | # The following section is specific to Flutter. 21 | flutter: 22 | 23 | # To add assets to your package, add an assets section, like this: 24 | # assets: 25 | # - images/a_dot_burr.jpeg 26 | # - images/a_dot_ham.jpeg 27 | # 28 | # For details regarding assets in packages, see 29 | # https://flutter.io/assets-and-images/#from-packages 30 | # 31 | # An image asset can refer to one or more resolution-specific "variants", see 32 | # https://flutter.io/assets-and-images/#resolution-aware. 33 | 34 | # To add custom fonts to your package, add a fonts section here, 35 | # in this "flutter" section. Each entry in this list should have a 36 | # "family" key with the font family name, and a "fonts" key with a 37 | # list giving the asset and other descriptors for the font. For 38 | # example: 39 | # fonts: 40 | # - family: Schyler 41 | # fonts: 42 | # - asset: fonts/Schyler-Regular.ttf 43 | # - asset: fonts/Schyler-Italic.ttf 44 | # style: italic 45 | # - family: Trajan Pro 46 | # fonts: 47 | # - asset: fonts/TrajanPro.ttf 48 | # - asset: fonts/TrajanPro_Bold.ttf 49 | # weight: 700 50 | # 51 | # For details regarding fonts in packages, see 52 | # https://flutter.io/custom-fonts/#from-packages 53 | -------------------------------------------------------------------------------- /example/android/app/build.gradle: -------------------------------------------------------------------------------- 1 | def localProperties = new Properties() 2 | def localPropertiesFile = rootProject.file('local.properties') 3 | if (localPropertiesFile.exists()) { 4 | localPropertiesFile.withReader('UTF-8') { reader -> 5 | localProperties.load(reader) 6 | } 7 | } 8 | 9 | def flutterRoot = localProperties.getProperty('flutter.sdk') 10 | if (flutterRoot == null) { 11 | throw new GradleException("Flutter SDK not found. Define location with flutter.sdk in the local.properties file.") 12 | } 13 | 14 | def flutterVersionCode = localProperties.getProperty('flutter.versionCode') 15 | if (flutterVersionCode == null) { 16 | flutterVersionCode = '1' 17 | } 18 | 19 | def flutterVersionName = localProperties.getProperty('flutter.versionName') 20 | if (flutterVersionName == null) { 21 | flutterVersionName = '1.0' 22 | } 23 | 24 | apply plugin: 'com.android.application' 25 | apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" 26 | 27 | android { 28 | compileSdkVersion 28 29 | 30 | lintOptions { 31 | disable 'InvalidPackage' 32 | } 33 | 34 | defaultConfig { 35 | // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). 36 | applicationId "com.realank.example" 37 | minSdkVersion 16 38 | targetSdkVersion 28 39 | versionCode flutterVersionCode.toInteger() 40 | versionName flutterVersionName 41 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 42 | } 43 | 44 | buildTypes { 45 | release { 46 | // TODO: Add your own signing config for the release build. 47 | // Signing with the debug keys for now, so `flutter run --release` works. 48 | signingConfig signingConfigs.debug 49 | } 50 | } 51 | } 52 | 53 | flutter { 54 | source '../..' 55 | } 56 | 57 | dependencies { 58 | testImplementation 'junit:junit:4.12' 59 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 60 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0' 61 | } 62 | -------------------------------------------------------------------------------- /example/android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 8 | 9 | 10 | 15 | 19 | 26 | 30 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /example/ios/Runner/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /example/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: example 2 | description: A new Flutter application. 3 | 4 | # The following defines the version and build number for your application. 5 | # A version number is three numbers separated by dots, like 1.2.43 6 | # followed by an optional build number separated by a +. 7 | # Both the version and the builder number may be overridden in flutter 8 | # build by specifying --build-name and --build-number, respectively. 9 | # Read more about versioning at semver.org. 10 | version: 1.0.0+1 11 | 12 | environment: 13 | sdk: ">=2.0.0-dev.68.0 <3.0.0" 14 | 15 | dependencies: 16 | flutter: 17 | sdk: flutter 18 | 19 | # The following adds the Cupertino Icons font to your application. 20 | # Use with the CupertinoIcons class for iOS style icons. 21 | cupertino_icons: ^0.1.2 22 | flutter_datetime_picker: 23 | path: ../ 24 | 25 | dev_dependencies: 26 | flutter_test: 27 | sdk: flutter 28 | 29 | 30 | # For information on the generic Dart part of this file, see the 31 | # following page: https://www.dartlang.org/tools/pub/pubspec 32 | 33 | # The following section is specific to Flutter. 34 | flutter: 35 | 36 | # The following line ensures that the Material Icons font is 37 | # included with your application, so that you can use the icons in 38 | # the material Icons class. 39 | uses-material-design: true 40 | 41 | # To add assets to your application, add an assets section, like this: 42 | # assets: 43 | # - images/a_dot_burr.jpeg 44 | # - images/a_dot_ham.jpeg 45 | 46 | # An image asset can refer to one or more resolution-specific "variants", see 47 | # https://flutter.io/assets-and-images/#resolution-aware. 48 | 49 | # For details regarding adding assets from package dependencies, see 50 | # https://flutter.io/assets-and-images/#from-packages 51 | 52 | # To add custom fonts to your application, add a fonts section here, 53 | # in this "flutter" section. Each entry in this list should have a 54 | # "family" key with the font family name, and a "fonts" key with a 55 | # list giving the asset and other descriptors for the font. For 56 | # example: 57 | # fonts: 58 | # - family: Schyler 59 | # fonts: 60 | # - asset: fonts/Schyler-Regular.ttf 61 | # - asset: fonts/Schyler-Italic.ttf 62 | # style: italic 63 | # - family: Trajan Pro 64 | # fonts: 65 | # - asset: fonts/TrajanPro.ttf 66 | # - asset: fonts/TrajanPro_Bold.ttf 67 | # weight: 700 68 | # 69 | # For details regarding fonts from package dependencies, 70 | # see https://flutter.io/custom-fonts/#from-packages 71 | -------------------------------------------------------------------------------- /example/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "20x20", 5 | "idiom" : "iphone", 6 | "filename" : "Icon-App-20x20@2x.png", 7 | "scale" : "2x" 8 | }, 9 | { 10 | "size" : "20x20", 11 | "idiom" : "iphone", 12 | "filename" : "Icon-App-20x20@3x.png", 13 | "scale" : "3x" 14 | }, 15 | { 16 | "size" : "29x29", 17 | "idiom" : "iphone", 18 | "filename" : "Icon-App-29x29@1x.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "29x29", 23 | "idiom" : "iphone", 24 | "filename" : "Icon-App-29x29@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "29x29", 29 | "idiom" : "iphone", 30 | "filename" : "Icon-App-29x29@3x.png", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "size" : "40x40", 35 | "idiom" : "iphone", 36 | "filename" : "Icon-App-40x40@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "40x40", 41 | "idiom" : "iphone", 42 | "filename" : "Icon-App-40x40@3x.png", 43 | "scale" : "3x" 44 | }, 45 | { 46 | "size" : "60x60", 47 | "idiom" : "iphone", 48 | "filename" : "Icon-App-60x60@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "60x60", 53 | "idiom" : "iphone", 54 | "filename" : "Icon-App-60x60@3x.png", 55 | "scale" : "3x" 56 | }, 57 | { 58 | "size" : "20x20", 59 | "idiom" : "ipad", 60 | "filename" : "Icon-App-20x20@1x.png", 61 | "scale" : "1x" 62 | }, 63 | { 64 | "size" : "20x20", 65 | "idiom" : "ipad", 66 | "filename" : "Icon-App-20x20@2x.png", 67 | "scale" : "2x" 68 | }, 69 | { 70 | "size" : "29x29", 71 | "idiom" : "ipad", 72 | "filename" : "Icon-App-29x29@1x.png", 73 | "scale" : "1x" 74 | }, 75 | { 76 | "size" : "29x29", 77 | "idiom" : "ipad", 78 | "filename" : "Icon-App-29x29@2x.png", 79 | "scale" : "2x" 80 | }, 81 | { 82 | "size" : "40x40", 83 | "idiom" : "ipad", 84 | "filename" : "Icon-App-40x40@1x.png", 85 | "scale" : "1x" 86 | }, 87 | { 88 | "size" : "40x40", 89 | "idiom" : "ipad", 90 | "filename" : "Icon-App-40x40@2x.png", 91 | "scale" : "2x" 92 | }, 93 | { 94 | "size" : "76x76", 95 | "idiom" : "ipad", 96 | "filename" : "Icon-App-76x76@1x.png", 97 | "scale" : "1x" 98 | }, 99 | { 100 | "size" : "76x76", 101 | "idiom" : "ipad", 102 | "filename" : "Icon-App-76x76@2x.png", 103 | "scale" : "2x" 104 | }, 105 | { 106 | "size" : "83.5x83.5", 107 | "idiom" : "ipad", 108 | "filename" : "Icon-App-83.5x83.5@2x.png", 109 | "scale" : "2x" 110 | }, 111 | { 112 | "size" : "1024x1024", 113 | "idiom" : "ios-marketing", 114 | "filename" : "Icon-App-1024x1024@1x.png", 115 | "scale" : "1x" 116 | } 117 | ], 118 | "info" : { 119 | "version" : 1, 120 | "author" : "xcode" 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 40 | 41 | 42 | 43 | 44 | 45 | 56 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | 75 | 77 | 83 | 84 | 85 | 86 | 88 | 89 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /example/.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flutter Datetime Picker 2 | 3 | [(Pub) flutter_datetime_picker](https://pub.dev/packages/flutter_datetime_picker) 4 | 5 | A flutter date time picker inspired by [flutter-cupertino-date-picker](https://github.com/wuzhendev/flutter-cupertino-date-picker) 6 | 7 | you can choose date / time / date&time in multiple languages: 8 | 9 | - Arabic(ar) 10 | - Armenian(hy) 11 | - Azerbaijan(az) 12 | - Basque(eu) 13 | - Bengali(bn) 14 | - Bulgarian(bg) 15 | - Catalan(cat) 16 | - Chinese(zh) 17 | - Danish(da) 18 | - Dutch(nl) 19 | - English(en) 20 | - French(fr) 21 | - German(de) 22 | - Indonesian(id) 23 | - Italian(it) 24 | - Japanese(jp) 25 | - Kazakh(kk) 26 | - Korean(ko) 27 | - Persian(fa) 28 | - Polish (pl) 29 | - Portuguese(pt) 30 | - Russian(ru) 31 | - Spanish(es) 32 | - Thai(th) 33 | - Turkish(tr) 34 | - Vietnamese(vi) 35 | 36 | 37 | and you can also custom your own picker content 38 | 39 | | Date picker | Time picker | Date Time picker | 40 | | -------------------- | -------------------- | -------------------------------- | 41 | | ![](screen_date.png) | ![](screen_time.png) | ![](screen_datetime_chinese.png) | 42 | 43 | International: 44 | 45 | | Date Time picker (Chinese) | Date Time picker (America) | Date Time picker (Dutch) | Date Time picker (Russian) | 46 | | -------------------------------- | -------------------------------- | ------------------------------ | -------------------------------- | 47 | | ![](screen_datetime_chinese.png) | ![](screen_datetime_english.png) | ![](screen_datetime_dutch.png) | ![](screen_datetime_russian.png) | 48 | 49 | 50 | ## Demo App 51 | 52 | ![main page](main_page.png) 53 | 54 | ## Usage 55 | 56 | ``` 57 | FlatButton( 58 | onPressed: () { 59 | DatePicker.showDatePicker(context, 60 | showTitleActions: true, 61 | minTime: DateTime(2018, 3, 5), 62 | maxTime: DateTime(2019, 6, 7), onChanged: (date) { 63 | print('change $date'); 64 | }, onConfirm: (date) { 65 | print('confirm $date'); 66 | }, currentTime: DateTime.now(), locale: LocaleType.zh); 67 | }, 68 | child: Text( 69 | 'show date time picker (Chinese)', 70 | style: TextStyle(color: Colors.blue), 71 | )); 72 | ``` 73 | 74 | ## Customize 75 | 76 | If you want to customize your own style of date time picker, there is a class called CommonPickerModel, every type of date time picker is extended from this class, you can refer to other picker model (eg. DatePickerModel), and write your custom one, then pass this model to showPicker method, so that your own date time picker will appear, it’s easy, and will perfectly meet your demand 77 | 78 | How to customize your own picker model: 79 | 80 | ``` 81 | class CustomPicker extends CommonPickerModel { 82 | String digits(int value, int length) { 83 | return '$value'.padLeft(length, "0"); 84 | } 85 | 86 | CustomPicker({DateTime currentTime, LocaleType locale}) : super(locale: locale) { 87 | this.currentTime = currentTime ?? DateTime.now(); 88 | this.setLeftIndex(this.currentTime.hour); 89 | this.setMiddleIndex(this.currentTime.minute); 90 | this.setRightIndex(this.currentTime.second); 91 | } 92 | 93 | @override 94 | String leftStringAtIndex(int index) { 95 | if (index >= 0 && index < 24) { 96 | return this.digits(index, 2); 97 | } else { 98 | return null; 99 | } 100 | } 101 | 102 | @override 103 | String middleStringAtIndex(int index) { 104 | if (index >= 0 && index < 60) { 105 | return this.digits(index, 2); 106 | } else { 107 | return null; 108 | } 109 | } 110 | 111 | @override 112 | String rightStringAtIndex(int index) { 113 | if (index >= 0 && index < 60) { 114 | return this.digits(index, 2); 115 | } else { 116 | return null; 117 | } 118 | } 119 | 120 | @override 121 | String leftDivider() { 122 | return "|"; 123 | } 124 | 125 | @override 126 | String rightDivider() { 127 | return "|"; 128 | } 129 | 130 | @override 131 | List layoutProportions() { 132 | return [1, 2, 1]; 133 | } 134 | 135 | @override 136 | DateTime finalTime() { 137 | return currentTime.isUtc 138 | ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day, 139 | this.currentLeftIndex(), this.currentMiddleIndex(), this.currentRightIndex()) 140 | : DateTime(currentTime.year, currentTime.month, currentTime.day, this.currentLeftIndex(), 141 | this.currentMiddleIndex(), this.currentRightIndex()); 142 | } 143 | } 144 | ``` 145 | 146 | 147 | ## Getting Started 148 | 149 | For help getting started with Flutter, view our online [documentation](https://flutter.io/). 150 | 151 | For help on editing package code, view the [documentation](https://flutter.io/developing-packages/). 152 | -------------------------------------------------------------------------------- /example/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /example/lib/main.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter/material.dart'; 2 | import 'package:flutter_datetime_picker/flutter_datetime_picker.dart'; 3 | 4 | void main() => runApp(new MyApp()); 5 | 6 | class CustomPicker extends CommonPickerModel { 7 | String digits(int value, int length) { 8 | return '$value'.padLeft(length, "0"); 9 | } 10 | 11 | CustomPicker({DateTime currentTime, LocaleType locale}) : super(locale: locale) { 12 | this.currentTime = currentTime ?? DateTime.now(); 13 | this.setLeftIndex(this.currentTime.hour); 14 | this.setMiddleIndex(this.currentTime.minute); 15 | this.setRightIndex(this.currentTime.second); 16 | } 17 | 18 | @override 19 | String leftStringAtIndex(int index) { 20 | if (index >= 0 && index < 24) { 21 | return this.digits(index, 2); 22 | } else { 23 | return null; 24 | } 25 | } 26 | 27 | @override 28 | String middleStringAtIndex(int index) { 29 | if (index >= 0 && index < 60) { 30 | return this.digits(index, 2); 31 | } else { 32 | return null; 33 | } 34 | } 35 | 36 | @override 37 | String rightStringAtIndex(int index) { 38 | if (index >= 0 && index < 60) { 39 | return this.digits(index, 2); 40 | } else { 41 | return null; 42 | } 43 | } 44 | 45 | @override 46 | String leftDivider() { 47 | return "|"; 48 | } 49 | 50 | @override 51 | String rightDivider() { 52 | return "|"; 53 | } 54 | 55 | @override 56 | List layoutProportions() { 57 | return [1, 2, 1]; 58 | } 59 | 60 | @override 61 | DateTime finalTime() { 62 | return currentTime.isUtc 63 | ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day, 64 | this.currentLeftIndex(), this.currentMiddleIndex(), this.currentRightIndex()) 65 | : DateTime(currentTime.year, currentTime.month, currentTime.day, this.currentLeftIndex(), 66 | this.currentMiddleIndex(), this.currentRightIndex()); 67 | } 68 | } 69 | 70 | class MyApp extends StatelessWidget { 71 | // This widget is the root of your application. 72 | @override 73 | Widget build(BuildContext context) { 74 | return new MaterialApp( 75 | title: 'Flutter Demo', 76 | theme: new ThemeData( 77 | primarySwatch: Colors.blue, 78 | ), 79 | home: new HomePage(), 80 | ); 81 | } 82 | } 83 | 84 | class HomePage extends StatelessWidget { 85 | @override 86 | Widget build(BuildContext context) { 87 | return Scaffold( 88 | appBar: AppBar( 89 | title: Text('Datetime Picker'), 90 | ), 91 | body: Center( 92 | child: Column( 93 | children: [ 94 | FlatButton( 95 | onPressed: () { 96 | DatePicker.showDatePicker(context, 97 | showTitleActions: true, 98 | minTime: DateTime(2018, 3, 5), 99 | maxTime: DateTime(2019, 6, 7), 100 | theme: DatePickerTheme( 101 | headerColor: Colors.orange, 102 | backgroundColor: Colors.blue, 103 | itemStyle: TextStyle( 104 | color: Colors.white, fontWeight: FontWeight.bold, fontSize: 18), 105 | doneStyle: TextStyle(color: Colors.white, fontSize: 16)), 106 | onChanged: (date) { 107 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 108 | }, onConfirm: (date) { 109 | print('confirm $date'); 110 | }, currentTime: DateTime.now(), locale: LocaleType.en); 111 | }, 112 | child: Text( 113 | 'show date picker(custom theme &date time range)', 114 | style: TextStyle(color: Colors.blue), 115 | )), 116 | FlatButton( 117 | onPressed: () { 118 | DatePicker.showTimePicker(context, showTitleActions: true, onChanged: (date) { 119 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 120 | }, onConfirm: (date) { 121 | print('confirm $date'); 122 | }, currentTime: DateTime.now()); 123 | }, 124 | child: Text( 125 | 'show time picker', 126 | style: TextStyle(color: Colors.blue), 127 | )), 128 | FlatButton( 129 | onPressed: () { 130 | DatePicker.showTime12hPicker(context, showTitleActions: true, onChanged: (date) { 131 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 132 | }, onConfirm: (date) { 133 | print('confirm $date'); 134 | }, currentTime: DateTime.now()); 135 | }, 136 | child: Text( 137 | 'show 12H time picker with AM/PM', 138 | style: TextStyle(color: Colors.blue), 139 | )), 140 | FlatButton( 141 | onPressed: () { 142 | DatePicker.showDateTimePicker(context, 143 | showTitleActions: true, 144 | minTime: DateTime(2020, 5, 5, 20, 50), 145 | maxTime: DateTime(2020, 6, 7, 05, 09), onChanged: (date) { 146 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 147 | }, onConfirm: (date) { 148 | print('confirm $date'); 149 | }, locale: LocaleType.zh); 150 | }, 151 | child: Text( 152 | 'show date time picker (Chinese)', 153 | style: TextStyle(color: Colors.blue), 154 | )), 155 | FlatButton( 156 | onPressed: () { 157 | DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) { 158 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 159 | }, onConfirm: (date) { 160 | print('confirm $date'); 161 | }, currentTime: DateTime(2008, 12, 31, 23, 12, 34)); 162 | }, 163 | child: Text( 164 | 'show date time picker (English-America)', 165 | style: TextStyle(color: Colors.blue), 166 | )), 167 | FlatButton( 168 | onPressed: () { 169 | DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) { 170 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 171 | }, onConfirm: (date) { 172 | print('confirm $date'); 173 | }, currentTime: DateTime(2008, 12, 31, 23, 12, 34), locale: LocaleType.nl); 174 | }, 175 | child: Text( 176 | 'show date time picker (Dutch)', 177 | style: TextStyle(color: Colors.blue), 178 | )), 179 | FlatButton( 180 | onPressed: () { 181 | DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) { 182 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 183 | }, onConfirm: (date) { 184 | print('confirm $date'); 185 | }, currentTime: DateTime(2008, 12, 31, 23, 12, 34), locale: LocaleType.ru); 186 | }, 187 | child: Text( 188 | 'show date time picker (Russian)', 189 | style: TextStyle(color: Colors.blue), 190 | )), 191 | FlatButton( 192 | onPressed: () { 193 | DatePicker.showDateTimePicker(context, showTitleActions: true, onChanged: (date) { 194 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 195 | }, onConfirm: (date) { 196 | print('confirm $date'); 197 | }, currentTime: DateTime.utc(2019, 12, 31, 23, 12, 34), locale: LocaleType.de); 198 | }, 199 | child: Text( 200 | 'show date time picker in UTC (German)', 201 | style: TextStyle(color: Colors.blue), 202 | )), 203 | FlatButton( 204 | onPressed: () { 205 | DatePicker.showPicker(context, showTitleActions: true, onChanged: (date) { 206 | print('change $date in time zone ' + date.timeZoneOffset.inHours.toString()); 207 | }, onConfirm: (date) { 208 | print('confirm $date'); 209 | }, pickerModel: CustomPicker(currentTime: DateTime.now()), locale: LocaleType.en); 210 | }, 211 | child: Text( 212 | 'show custom time picker,\nyou can custom picker model like this', 213 | style: TextStyle(color: Colors.blue), 214 | )), 215 | ], 216 | ), 217 | ), 218 | ); 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /lib/src/date_format.dart: -------------------------------------------------------------------------------- 1 | import 'i18n_model.dart'; 2 | 3 | /// Outputs year as four digits 4 | /// 5 | /// Example: 6 | /// formatDate(new DateTime(2018,8,31), [ymdw]); 7 | /// // => Today 8 | const String ymdw = 'ymdw'; 9 | 10 | /// 11 | /// Example: 12 | /// formatDate(new DateTime(1989), [yyyy]); 13 | /// // => 1989 14 | const String yyyy = 'yyyy'; 15 | 16 | /// Outputs year as two digits 17 | /// 18 | /// Example: 19 | /// formatDate(new DateTime(1989), [yy]); 20 | /// // => 89 21 | const String yy = 'yy'; 22 | 23 | /// Outputs month as two digits 24 | /// 25 | /// Example: 26 | /// formatDate(new DateTime(1989, 11), [mm]); 27 | /// // => 11 28 | /// formatDate(new DateTime(1989, 5), [mm]); 29 | /// // => 05 30 | const String mm = 'mm'; 31 | 32 | /// Outputs month compactly 33 | /// 34 | /// Example: 35 | /// formatDate(new DateTime(1989, 11), [mm]); 36 | /// // => 11 37 | /// formatDate(new DateTime(1989, 5), [m]); 38 | /// // => 5 39 | const String m = 'm'; 40 | 41 | /// Outputs month as long name 42 | /// 43 | /// Example: 44 | /// formatDate(new DateTime(1989, 2), [MM]); 45 | /// // => february 46 | const String MM = 'MM'; 47 | 48 | /// Outputs month as short name 49 | /// 50 | /// Example: 51 | /// formatDate(new DateTime(1989, 2), [M]); 52 | /// // => feb 53 | const String M = 'M'; 54 | 55 | /// Outputs day as two digits 56 | /// 57 | /// Example: 58 | /// formatDate(new DateTime(1989, 2, 21), [dd]); 59 | /// // => 21 60 | /// formatDate(new DateTime(1989, 2, 5), [dd]); 61 | /// // => 05 62 | const String dd = 'dd'; 63 | 64 | /// Outputs day compactly 65 | /// 66 | /// Example: 67 | /// formatDate(new DateTime(1989, 2, 21), [d]); 68 | /// // => 21 69 | /// formatDate(new DateTime(1989, 2, 5), [d]); 70 | /// // => 5 71 | const String d = 'd'; 72 | 73 | /// Outputs week in month 74 | /// 75 | /// Example: 76 | /// formatDate(new DateTime(1989, 2, 21), [w]); 77 | /// // => 4 78 | const String w = 'w'; 79 | 80 | /// Outputs week in year as two digits 81 | /// 82 | /// Example: 83 | /// formatDate(new DateTime(1989, 12, 31), [W]); 84 | /// // => 53 85 | /// formatDate(new DateTime(1989, 2, 21), [W]); 86 | /// // => 08 87 | const String WW = 'WW'; 88 | 89 | /// Outputs week in year compactly 90 | /// 91 | /// Example: 92 | /// formatDate(new DateTime(1989, 2, 21), [W]); 93 | /// // => 8 94 | const String W = 'W'; 95 | 96 | /// Outputs week day as long name 97 | /// 98 | /// Example: 99 | /// formatDate(new DateTime(2018, 1, 14), [D]); 100 | /// // => sun 101 | const String D = 'D'; 102 | 103 | /// Outputs hour (0 - 11) as two digits 104 | /// 105 | /// Example: 106 | /// formatDate(new DateTime(1989, 02, 1, 15), [hh]); 107 | /// // => 03 108 | const String hh = 'hh'; 109 | 110 | /// Outputs hour (0 - 11) compactly 111 | /// 112 | /// Example: 113 | /// formatDate(new DateTime(1989, 02, 1, 15), [h]); 114 | /// // => 3 115 | const String h = 'h'; 116 | 117 | /// Outputs hour (0 to 23) as two digits 118 | /// 119 | /// Example: 120 | /// formatDate(new DateTime(1989, 02, 1, 15), [HH]); 121 | /// // => 15 122 | const String HH = 'HH'; 123 | 124 | /// Outputs hour (0 to 23) compactly 125 | /// 126 | /// Example: 127 | /// formatDate(new DateTime(1989, 02, 1, 5), [H]); 128 | /// // => 5 129 | const String H = 'H'; 130 | 131 | /// Outputs minute as two digits 132 | /// 133 | /// Example: 134 | /// formatDate(new DateTime(1989, 02, 1, 15, 40), [nn]); 135 | /// // => 40 136 | /// formatDate(new DateTime(1989, 02, 1, 15, 4), [nn]); 137 | /// // => 04 138 | const String nn = 'nn'; 139 | 140 | /// Outputs minute compactly 141 | /// 142 | /// Example: 143 | /// formatDate(new DateTime(1989, 02, 1, 15, 4), [n]); 144 | /// // => 4 145 | const String n = 'n'; 146 | 147 | /// Outputs second as two digits 148 | /// 149 | /// Example: 150 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10), [ss]); 151 | /// // => 10 152 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 5), [ss]); 153 | /// // => 05 154 | const String ss = 'ss'; 155 | 156 | /// Outputs second compactly 157 | /// 158 | /// Example: 159 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 5), [s]); 160 | /// // => 5 161 | const String s = 's'; 162 | 163 | /// Outputs millisecond as three digits 164 | /// 165 | /// Example: 166 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 999), [SSS]); 167 | /// // => 999 168 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 99), [SS]); 169 | /// // => 099 170 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0), [SS]); 171 | /// // => 009 172 | const String SSS = 'SSS'; 173 | 174 | /// Outputs millisecond compactly 175 | /// 176 | /// Example: 177 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 999), [SSS]); 178 | /// // => 999 179 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 99), [SS]); 180 | /// // => 99 181 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 9), [SS]); 182 | /// // => 9 183 | const String S = 'S'; 184 | 185 | /// Outputs microsecond as three digits 186 | /// 187 | /// Example: 188 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 999), [uuu]); 189 | /// // => 999 190 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 99), [uuu]); 191 | /// // => 099 192 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 9), [uuu]); 193 | /// // => 009 194 | const String uuu = 'uuu'; 195 | 196 | /// Outputs millisecond compactly 197 | /// 198 | /// Example: 199 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 999), [u]); 200 | /// // => 999 201 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 99), [u]); 202 | /// // => 99 203 | /// formatDate(new DateTime(1989, 02, 1, 15, 40, 10, 0, 9), [u]); 204 | /// // => 9 205 | const String u = 'u'; 206 | 207 | /// Outputs if hour is AM or PM 208 | /// 209 | /// Example: 210 | /// print(formatDate(new DateTime(1989, 02, 1, 5), [am])); 211 | /// // => AM 212 | /// print(formatDate(new DateTime(1989, 02, 1, 15), [am])); 213 | /// // => PM 214 | const String am = 'am'; 215 | 216 | /// Outputs timezone as time offset 217 | /// 218 | /// Example: 219 | /// 220 | const String z = 'z'; 221 | const String Z = 'Z'; 222 | 223 | String formatDate(DateTime date, List formats, LocaleType locale) { 224 | if (formats.first == ymdw) { 225 | final now = DateTime.now(); 226 | if (date.year == now.year && 227 | date.month == now.month && 228 | date.day == now.day) { 229 | //today 230 | return i18nObjInLocale(locale)['today']; 231 | } else if (date.year == now.year) { 232 | if (locale == LocaleType.zh) { 233 | return formatDate(date, [mm, '月', dd, '日 ', D], locale); 234 | } else if (locale == LocaleType.nl) { 235 | return formatDate(date, [D, ' ', dd, ' ', M], locale); 236 | } else if (locale == LocaleType.ko) { 237 | return formatDate(date, [mm, '월', dd, '일 ', D], locale); 238 | } else if (locale == LocaleType.de) { 239 | return formatDate(date, [D, ', ', dd, '. ', M], locale); 240 | } else if (locale == LocaleType.id) { 241 | return formatDate(date, [D, ', ', dd, ' ', M], locale); 242 | } else if (locale == LocaleType.jp) { 243 | return formatDate(date, [mm, '月', dd, '日', D], locale); 244 | } else if (locale == LocaleType.si) { 245 | return formatDate(date, [D, ', ', dd, '. ', M, '.'], locale); 246 | } else { 247 | return formatDate(date, [D, ' ', M, ' ', dd], locale); 248 | } 249 | } else { 250 | if (locale == LocaleType.zh) { 251 | return formatDate(date, [yyyy, '年', mm, '月', dd, '日 ', D], locale); 252 | } else if (locale == LocaleType.nl) { 253 | return formatDate(date, [D, ' ', dd, ' ', M, ' ', yyyy], locale); 254 | } else if (locale == LocaleType.ko) { 255 | return formatDate(date, [yyyy, '년', mm, '월', dd, '일 ', D], locale); 256 | } else if (locale == LocaleType.de) { 257 | return formatDate(date, [D, ', ', dd, '. ', M, ' ', yyyy], locale); 258 | } else if (locale == LocaleType.id) { 259 | return formatDate(date, [D, ', ', dd, ' ', M, ' ', yyyy], locale); 260 | } else if (locale == LocaleType.jp) { 261 | return formatDate(date, [yyyy, '年', mm, '月', dd, '日', D], locale); 262 | } else if (locale == LocaleType.si) { 263 | return formatDate(date, [D, ', ', dd, '. ', M, '. ', yyyy], locale); 264 | } else { 265 | return formatDate(date, [D, ' ', M, ' ', dd, ', ', yyyy], locale); 266 | } 267 | } 268 | } 269 | 270 | final sb = new StringBuffer(); 271 | 272 | for (String format in formats) { 273 | if (format == yyyy) { 274 | sb.write(digits(date.year, 4)); 275 | } else if (format == yy) { 276 | sb.write(digits(date.year % 100, 2)); 277 | } else if (format == mm) { 278 | sb.write(digits(date.month, 2)); 279 | } else if (format == m) { 280 | sb.write(date.month); 281 | } else if (format == MM) { 282 | String monthLong = i18nObjInLocale(locale)['monthLong'][date.month - 1]; 283 | sb.write(monthLong); 284 | } else if (format == M) { 285 | String monthShort = i18nObjInLocale(locale)['monthShort'][date.month - 1]; 286 | sb.write(monthShort); 287 | } else if (format == dd) { 288 | sb.write(digits(date.day, 2)); 289 | } else if (format == d) { 290 | sb.write(date.day); 291 | } else if (format == w) { 292 | sb.write((date.day + 7) ~/ 7); 293 | } else if (format == W) { 294 | sb.write((dayInYear(date) + 7) ~/ 7); 295 | } else if (format == WW) { 296 | sb.write(digits((dayInYear(date) + 7) ~/ 7, 2)); 297 | } else if (format == D) { 298 | String day = i18nObjInLocale(locale)['day'][date.weekday - 1]; 299 | if (locale == LocaleType.ko) { 300 | day = "($day)"; 301 | } 302 | sb.write(day); 303 | } else if (format == HH) { 304 | sb.write(digits(date.hour, 2)); 305 | } else if (format == H) { 306 | sb.write(date.hour); 307 | } else if (format == hh) { 308 | sb.write(digits(date.hour % 12, 2)); 309 | } else if (format == h) { 310 | sb.write(date.hour % 12); 311 | } else if (format == am) { 312 | sb.write(date.hour < 12 313 | ? i18nObjInLocale(locale)['am'] 314 | : i18nObjInLocale(locale)['pm']); 315 | } else if (format == nn) { 316 | sb.write(digits(date.minute, 2)); 317 | } else if (format == n) { 318 | sb.write(date.minute); 319 | } else if (format == ss) { 320 | sb.write(digits(date.second, 2)); 321 | } else if (format == s) { 322 | sb.write(date.second); 323 | } else if (format == SSS) { 324 | sb.write(digits(date.millisecond, 3)); 325 | } else if (format == S) { 326 | sb.write(date.second); 327 | } else if (format == uuu) { 328 | sb.write(digits(date.microsecond, 2)); 329 | } else if (format == u) { 330 | sb.write(date.microsecond); 331 | } else if (format == z) { 332 | if (date.timeZoneOffset.inMinutes == 0) { 333 | sb.write('Z'); 334 | } else { 335 | if (date.timeZoneOffset.isNegative) { 336 | sb.write('-'); 337 | sb.write(digits((-date.timeZoneOffset.inHours) % 24, 2)); 338 | sb.write(digits((-date.timeZoneOffset.inMinutes) % 60, 2)); 339 | } else { 340 | sb.write('+'); 341 | sb.write(digits(date.timeZoneOffset.inHours % 24, 2)); 342 | sb.write(digits(date.timeZoneOffset.inMinutes % 60, 2)); 343 | } 344 | } 345 | } else if (format == Z) { 346 | sb.write(date.timeZoneName); 347 | } else { 348 | sb.write(format); 349 | } 350 | } 351 | 352 | return sb.toString(); 353 | } 354 | 355 | String digits(int value, int length) { 356 | return '$value'.padLeft(length, "0"); 357 | } 358 | 359 | int dayInYear(DateTime date) => 360 | date.difference(new DateTime(date.year, 1, 1)).inDays; 361 | -------------------------------------------------------------------------------- /example/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 36 | 37 | 38 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 89 | 90 | 91 | 92 | 93 | 94 | 108 | 109 | 110 | 111 | 112 | 113 | 125 | 126 | 132 | 133 | 134 | 135 | 153 | 159 | 160 | 168 | 169 | 174 | 175 | 177 | 178 | 179 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 1535618656482 188 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | -------------------------------------------------------------------------------- /lib/flutter_datetime_picker.dart: -------------------------------------------------------------------------------- 1 | library flutter_datetime_picker; 2 | 3 | import 'package:flutter/cupertino.dart'; 4 | import 'package:flutter/material.dart'; 5 | import 'dart:async'; 6 | import 'package:flutter_datetime_picker/src/datetime_picker_theme.dart'; 7 | import 'package:flutter_datetime_picker/src/date_model.dart'; 8 | import 'package:flutter_datetime_picker/src/i18n_model.dart'; 9 | 10 | export 'package:flutter_datetime_picker/src/datetime_picker_theme.dart'; 11 | export 'package:flutter_datetime_picker/src/date_model.dart'; 12 | export 'package:flutter_datetime_picker/src/i18n_model.dart'; 13 | 14 | typedef DateChangedCallback(DateTime time); 15 | typedef String StringAtIndexCallBack(int index); 16 | 17 | class DatePicker { 18 | /// 19 | /// Display date picker bottom sheet. 20 | /// 21 | static Future showDatePicker( 22 | BuildContext context, { 23 | bool showTitleActions: true, 24 | DateTime minTime, 25 | DateTime maxTime, 26 | DateChangedCallback onChanged, 27 | DateChangedCallback onConfirm, 28 | locale: LocaleType.en, 29 | DateTime currentTime, 30 | DatePickerTheme theme, 31 | }) async { 32 | return await Navigator.push( 33 | context, 34 | new _DatePickerRoute( 35 | showTitleActions: showTitleActions, 36 | onChanged: onChanged, 37 | onConfirm: onConfirm, 38 | locale: locale, 39 | theme: theme, 40 | barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, 41 | pickerModel: DatePickerModel( 42 | currentTime: currentTime, maxTime: maxTime, minTime: minTime, locale: locale))); 43 | } 44 | 45 | /// 46 | /// Display time picker bottom sheet. 47 | /// 48 | static Future showTimePicker( 49 | BuildContext context, { 50 | bool showTitleActions: true, 51 | bool showSecondsColumn: true, 52 | DateChangedCallback onChanged, 53 | DateChangedCallback onConfirm, 54 | locale: LocaleType.en, 55 | DateTime currentTime, 56 | DatePickerTheme theme, 57 | }) async { 58 | return await Navigator.push( 59 | context, 60 | new _DatePickerRoute( 61 | showTitleActions: showTitleActions, 62 | onChanged: onChanged, 63 | onConfirm: onConfirm, 64 | locale: locale, 65 | theme: theme, 66 | barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, 67 | pickerModel: TimePickerModel( 68 | currentTime: currentTime, locale: locale, showSecondsColumn: showSecondsColumn))); 69 | } 70 | 71 | /// 72 | /// Display time picker bottom sheet with AM/PM. 73 | /// 74 | static Future showTime12hPicker( 75 | BuildContext context, { 76 | bool showTitleActions: true, 77 | DateChangedCallback onChanged, 78 | DateChangedCallback onConfirm, 79 | locale: LocaleType.en, 80 | DateTime currentTime, 81 | DatePickerTheme theme, 82 | }) async { 83 | return await Navigator.push( 84 | context, 85 | new _DatePickerRoute( 86 | showTitleActions: showTitleActions, 87 | onChanged: onChanged, 88 | onConfirm: onConfirm, 89 | locale: locale, 90 | theme: theme, 91 | barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, 92 | pickerModel: Time12hPickerModel(currentTime: currentTime, locale: locale))); 93 | } 94 | 95 | /// 96 | /// Display date&time picker bottom sheet. 97 | /// 98 | static Future showDateTimePicker( 99 | BuildContext context, { 100 | bool showTitleActions: true, 101 | DateTime minTime, 102 | DateTime maxTime, 103 | DateChangedCallback onChanged, 104 | DateChangedCallback onConfirm, 105 | locale: LocaleType.en, 106 | DateTime currentTime, 107 | DatePickerTheme theme, 108 | }) async { 109 | return await Navigator.push( 110 | context, 111 | new _DatePickerRoute( 112 | showTitleActions: showTitleActions, 113 | onChanged: onChanged, 114 | onConfirm: onConfirm, 115 | locale: locale, 116 | theme: theme, 117 | barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, 118 | pickerModel: DateTimePickerModel( 119 | currentTime: currentTime, minTime: minTime, maxTime: maxTime, locale: locale))); 120 | } 121 | 122 | /// 123 | /// Display date picker bottom sheet witch custom picker model. 124 | /// 125 | static Future showPicker( 126 | BuildContext context, { 127 | bool showTitleActions: true, 128 | DateChangedCallback onChanged, 129 | DateChangedCallback onConfirm, 130 | locale: LocaleType.en, 131 | BasePickerModel pickerModel, 132 | DatePickerTheme theme, 133 | }) async { 134 | return await Navigator.push( 135 | context, 136 | new _DatePickerRoute( 137 | showTitleActions: showTitleActions, 138 | onChanged: onChanged, 139 | onConfirm: onConfirm, 140 | locale: locale, 141 | theme: theme, 142 | barrierLabel: MaterialLocalizations.of(context).modalBarrierDismissLabel, 143 | pickerModel: pickerModel)); 144 | } 145 | } 146 | 147 | class _DatePickerRoute extends PopupRoute { 148 | _DatePickerRoute({ 149 | this.showTitleActions, 150 | this.onChanged, 151 | this.onConfirm, 152 | theme, 153 | this.barrierLabel, 154 | this.locale, 155 | RouteSettings settings, 156 | pickerModel, 157 | }) : this.pickerModel = pickerModel ?? DatePickerModel(), 158 | this.theme = theme ?? DatePickerTheme(), 159 | super(settings: settings); 160 | 161 | final bool showTitleActions; 162 | final DateChangedCallback onChanged; 163 | final DateChangedCallback onConfirm; 164 | final DatePickerTheme theme; 165 | final LocaleType locale; 166 | final BasePickerModel pickerModel; 167 | 168 | @override 169 | Duration get transitionDuration => const Duration(milliseconds: 200); 170 | 171 | @override 172 | bool get barrierDismissible => true; 173 | 174 | @override 175 | final String barrierLabel; 176 | 177 | @override 178 | Color get barrierColor => Colors.black54; 179 | 180 | AnimationController _animationController; 181 | 182 | @override 183 | AnimationController createAnimationController() { 184 | assert(_animationController == null); 185 | _animationController = BottomSheet.createAnimationController(navigator.overlay); 186 | return _animationController; 187 | } 188 | 189 | @override 190 | Widget buildPage( 191 | BuildContext context, Animation animation, Animation secondaryAnimation) { 192 | Widget bottomSheet = new MediaQuery.removePadding( 193 | context: context, 194 | removeTop: true, 195 | child: _DatePickerComponent( 196 | onChanged: onChanged, 197 | locale: this.locale, 198 | route: this, 199 | pickerModel: pickerModel, 200 | ), 201 | ); 202 | ThemeData inheritTheme = Theme.of(context, shadowThemeOnly: true); 203 | if (inheritTheme != null) { 204 | bottomSheet = new Theme(data: inheritTheme, child: bottomSheet); 205 | } 206 | return bottomSheet; 207 | } 208 | } 209 | 210 | class _DatePickerComponent extends StatefulWidget { 211 | _DatePickerComponent( 212 | {Key key, @required this.route, this.onChanged, this.locale, this.pickerModel}); 213 | 214 | final DateChangedCallback onChanged; 215 | 216 | final _DatePickerRoute route; 217 | 218 | final LocaleType locale; 219 | 220 | final BasePickerModel pickerModel; 221 | 222 | @override 223 | State createState() { 224 | return _DatePickerState(); 225 | } 226 | } 227 | 228 | class _DatePickerState extends State<_DatePickerComponent> { 229 | FixedExtentScrollController leftScrollCtrl, middleScrollCtrl, rightScrollCtrl; 230 | 231 | @override 232 | void initState() { 233 | super.initState(); 234 | refreshScrollOffset(); 235 | } 236 | 237 | void refreshScrollOffset() { 238 | // print('refreshScrollOffset ${widget.pickerModel.currentRightIndex()}'); 239 | leftScrollCtrl = 240 | new FixedExtentScrollController(initialItem: widget.pickerModel.currentLeftIndex()); 241 | middleScrollCtrl = 242 | new FixedExtentScrollController(initialItem: widget.pickerModel.currentMiddleIndex()); 243 | rightScrollCtrl = 244 | new FixedExtentScrollController(initialItem: widget.pickerModel.currentRightIndex()); 245 | } 246 | 247 | @override 248 | Widget build(BuildContext context) { 249 | DatePickerTheme theme = widget.route.theme; 250 | return GestureDetector( 251 | child: AnimatedBuilder( 252 | animation: widget.route.animation, 253 | builder: (BuildContext context, Widget child) { 254 | final double bottomPadding = MediaQuery.of(context).padding.bottom; 255 | return ClipRect( 256 | child: CustomSingleChildLayout( 257 | delegate: _BottomPickerLayout(widget.route.animation.value, theme, 258 | showTitleActions: widget.route.showTitleActions, bottomPadding: bottomPadding), 259 | child: GestureDetector( 260 | child: Material( 261 | color: theme.backgroundColor ?? Colors.white, 262 | child: _renderPickerView(theme), 263 | ), 264 | ), 265 | ), 266 | ); 267 | }, 268 | ), 269 | ); 270 | } 271 | 272 | void _notifyDateChanged() { 273 | if (widget.onChanged != null) { 274 | widget.onChanged(widget.pickerModel.finalTime()); 275 | } 276 | } 277 | 278 | Widget _renderPickerView(DatePickerTheme theme) { 279 | Widget itemView = _renderItemView(theme); 280 | if (widget.route.showTitleActions) { 281 | return Column( 282 | children: [ 283 | _renderTitleActionsView(theme), 284 | itemView, 285 | ], 286 | ); 287 | } 288 | return itemView; 289 | } 290 | 291 | Widget _renderColumnView( 292 | ValueKey key, 293 | DatePickerTheme theme, 294 | StringAtIndexCallBack stringAtIndexCB, 295 | ScrollController scrollController, 296 | int layoutProportion, 297 | ValueChanged selectedChangedWhenScrolling, 298 | ValueChanged selectedChangedWhenScrollEnd) { 299 | return Expanded( 300 | flex: layoutProportion, 301 | child: Container( 302 | padding: EdgeInsets.all(8.0), 303 | height: theme.containerHeight, 304 | decoration: BoxDecoration(color: theme.backgroundColor ?? Colors.white), 305 | child: NotificationListener( 306 | onNotification: (ScrollNotification notification) { 307 | if (notification.depth == 0 && 308 | selectedChangedWhenScrollEnd != null && 309 | notification is ScrollEndNotification && 310 | notification.metrics is FixedExtentMetrics) { 311 | final FixedExtentMetrics metrics = notification.metrics; 312 | final int currentItemIndex = metrics.itemIndex; 313 | selectedChangedWhenScrollEnd(currentItemIndex); 314 | } 315 | return false; 316 | }, 317 | child: CupertinoPicker.builder( 318 | key: key, 319 | backgroundColor: theme.backgroundColor ?? Colors.white, 320 | scrollController: scrollController, 321 | itemExtent: theme.itemHeight, 322 | onSelectedItemChanged: (int index) { 323 | selectedChangedWhenScrolling(index); 324 | }, 325 | useMagnifier: true, 326 | itemBuilder: (BuildContext context, int index) { 327 | final content = stringAtIndexCB(index); 328 | if (content == null) { 329 | return null; 330 | } 331 | return Container( 332 | height: theme.itemHeight, 333 | alignment: Alignment.center, 334 | child: Text( 335 | content, 336 | style: theme.itemStyle, 337 | textAlign: TextAlign.start, 338 | ), 339 | ); 340 | }))), 341 | ); 342 | } 343 | 344 | Widget _renderItemView(DatePickerTheme theme) { 345 | return Container( 346 | color: theme.backgroundColor ?? Colors.white, 347 | child: Row( 348 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 349 | children: [ 350 | Container( 351 | child: widget.pickerModel.layoutProportions()[0] > 0 352 | ? _renderColumnView( 353 | ValueKey(widget.pickerModel.currentLeftIndex()), 354 | theme, 355 | widget.pickerModel.leftStringAtIndex, 356 | leftScrollCtrl, 357 | widget.pickerModel.layoutProportions()[0], (index) { 358 | widget.pickerModel.setLeftIndex(index); 359 | }, (index) { 360 | setState(() { 361 | refreshScrollOffset(); 362 | _notifyDateChanged(); 363 | }); 364 | }) 365 | : null, 366 | ), 367 | Text( 368 | widget.pickerModel.leftDivider(), 369 | style: theme.itemStyle, 370 | ), 371 | Container( 372 | child: widget.pickerModel.layoutProportions()[1] > 0 373 | ? _renderColumnView( 374 | ValueKey(widget.pickerModel.currentLeftIndex()), 375 | theme, 376 | widget.pickerModel.middleStringAtIndex, 377 | middleScrollCtrl, 378 | widget.pickerModel.layoutProportions()[1], (index) { 379 | widget.pickerModel.setMiddleIndex(index); 380 | }, (index) { 381 | setState(() { 382 | refreshScrollOffset(); 383 | _notifyDateChanged(); 384 | }); 385 | }) 386 | : null, 387 | ), 388 | Text( 389 | widget.pickerModel.rightDivider(), 390 | style: theme.itemStyle, 391 | ), 392 | Container( 393 | child: widget.pickerModel.layoutProportions()[2] > 0 394 | ? _renderColumnView( 395 | ValueKey(widget.pickerModel.currentMiddleIndex() * 100 + 396 | widget.pickerModel.currentLeftIndex()), 397 | theme, 398 | widget.pickerModel.rightStringAtIndex, 399 | rightScrollCtrl, 400 | widget.pickerModel.layoutProportions()[2], (index) { 401 | widget.pickerModel.setRightIndex(index); 402 | _notifyDateChanged(); 403 | }, null) 404 | : null, 405 | ), 406 | ], 407 | ), 408 | ); 409 | } 410 | 411 | // Title View 412 | Widget _renderTitleActionsView(DatePickerTheme theme) { 413 | String done = _localeDone(); 414 | String cancel = _localeCancel(); 415 | 416 | return Container( 417 | height: theme.titleHeight, 418 | decoration: BoxDecoration( 419 | color: theme.headerColor ?? theme.backgroundColor ?? Colors.white, 420 | ), 421 | child: Row( 422 | mainAxisAlignment: MainAxisAlignment.spaceBetween, 423 | children: [ 424 | Container( 425 | height: theme.titleHeight, 426 | child: CupertinoButton( 427 | pressedOpacity: 0.3, 428 | padding: EdgeInsets.only(left: 16, top: 0), 429 | child: Text( 430 | '$cancel', 431 | style: theme.cancelStyle, 432 | ), 433 | onPressed: () => Navigator.pop(context), 434 | ), 435 | ), 436 | Container( 437 | height: theme.titleHeight, 438 | child: CupertinoButton( 439 | pressedOpacity: 0.3, 440 | padding: EdgeInsets.only(right: 16, top: 0), 441 | child: Text( 442 | '$done', 443 | style: theme.doneStyle, 444 | ), 445 | onPressed: () { 446 | Navigator.pop(context, widget.pickerModel.finalTime()); 447 | if (widget.route.onConfirm != null) { 448 | widget.route.onConfirm(widget.pickerModel.finalTime()); 449 | } 450 | }, 451 | ), 452 | ), 453 | ], 454 | ), 455 | ); 456 | } 457 | 458 | String _localeDone() { 459 | return i18nObjInLocale(widget.locale)['done']; 460 | } 461 | 462 | String _localeCancel() { 463 | return i18nObjInLocale(widget.locale)['cancel']; 464 | } 465 | } 466 | 467 | class _BottomPickerLayout extends SingleChildLayoutDelegate { 468 | _BottomPickerLayout(this.progress, this.theme, 469 | {this.itemCount, this.showTitleActions, this.bottomPadding = 0}); 470 | 471 | final double progress; 472 | final int itemCount; 473 | final bool showTitleActions; 474 | final DatePickerTheme theme; 475 | final double bottomPadding; 476 | 477 | @override 478 | BoxConstraints getConstraintsForChild(BoxConstraints constraints) { 479 | double maxHeight = theme.containerHeight; 480 | if (showTitleActions) { 481 | maxHeight += theme.titleHeight; 482 | } 483 | 484 | return new BoxConstraints( 485 | minWidth: constraints.maxWidth, 486 | maxWidth: constraints.maxWidth, 487 | minHeight: 0.0, 488 | maxHeight: maxHeight + bottomPadding); 489 | } 490 | 491 | @override 492 | Offset getPositionForChild(Size size, Size childSize) { 493 | double height = size.height - childSize.height * progress; 494 | return new Offset(0.0, height); 495 | } 496 | 497 | @override 498 | bool shouldRelayout(_BottomPickerLayout oldDelegate) { 499 | return progress != oldDelegate.progress; 500 | } 501 | } 502 | -------------------------------------------------------------------------------- /example/ios/Runner.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; 11 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 12 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; }; 13 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 14 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; }; 15 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; }; 17 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 18 | 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 19 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 20 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 21 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXCopyFilesBuildPhase section */ 25 | 9705A1C41CF9048500538489 /* Embed Frameworks */ = { 26 | isa = PBXCopyFilesBuildPhase; 27 | buildActionMask = 2147483647; 28 | dstPath = ""; 29 | dstSubfolderSpec = 10; 30 | files = ( 31 | 3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */, 32 | 9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */, 33 | ); 34 | name = "Embed Frameworks"; 35 | runOnlyForDeploymentPostprocessing = 0; 36 | }; 37 | /* End PBXCopyFilesBuildPhase section */ 38 | 39 | /* Begin PBXFileReference section */ 40 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 41 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 42 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; 43 | 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 44 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 45 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 46 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 47 | 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 48 | 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 49 | 9740EEBA1CF902C7004384FC /* Flutter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Flutter.framework; path = Flutter/Flutter.framework; sourceTree = ""; }; 50 | 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 51 | 97C146F21CF9000F007C117D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 52 | 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 53 | 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 54 | 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 55 | 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 56 | /* End PBXFileReference section */ 57 | 58 | /* Begin PBXFrameworksBuildPhase section */ 59 | 97C146EB1CF9000F007C117D /* Frameworks */ = { 60 | isa = PBXFrameworksBuildPhase; 61 | buildActionMask = 2147483647; 62 | files = ( 63 | 9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */, 64 | 3B80C3941E831B6300D905FE /* App.framework in Frameworks */, 65 | ); 66 | runOnlyForDeploymentPostprocessing = 0; 67 | }; 68 | /* End PBXFrameworksBuildPhase section */ 69 | 70 | /* Begin PBXGroup section */ 71 | 9740EEB11CF90186004384FC /* Flutter */ = { 72 | isa = PBXGroup; 73 | children = ( 74 | 3B80C3931E831B6300D905FE /* App.framework */, 75 | 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, 76 | 9740EEBA1CF902C7004384FC /* Flutter.framework */, 77 | 9740EEB21CF90195004384FC /* Debug.xcconfig */, 78 | 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, 79 | 9740EEB31CF90195004384FC /* Generated.xcconfig */, 80 | ); 81 | name = Flutter; 82 | sourceTree = ""; 83 | }; 84 | 97C146E51CF9000F007C117D = { 85 | isa = PBXGroup; 86 | children = ( 87 | 9740EEB11CF90186004384FC /* Flutter */, 88 | 97C146F01CF9000F007C117D /* Runner */, 89 | 97C146EF1CF9000F007C117D /* Products */, 90 | CF3B75C9A7D2FA2A4C99F110 /* Frameworks */, 91 | ); 92 | sourceTree = ""; 93 | }; 94 | 97C146EF1CF9000F007C117D /* Products */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 97C146EE1CF9000F007C117D /* Runner.app */, 98 | ); 99 | name = Products; 100 | sourceTree = ""; 101 | }; 102 | 97C146F01CF9000F007C117D /* Runner */ = { 103 | isa = PBXGroup; 104 | children = ( 105 | 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */, 106 | 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */, 107 | 97C146FA1CF9000F007C117D /* Main.storyboard */, 108 | 97C146FD1CF9000F007C117D /* Assets.xcassets */, 109 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, 110 | 97C147021CF9000F007C117D /* Info.plist */, 111 | 97C146F11CF9000F007C117D /* Supporting Files */, 112 | 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 113 | 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 114 | ); 115 | path = Runner; 116 | sourceTree = ""; 117 | }; 118 | 97C146F11CF9000F007C117D /* Supporting Files */ = { 119 | isa = PBXGroup; 120 | children = ( 121 | 97C146F21CF9000F007C117D /* main.m */, 122 | ); 123 | name = "Supporting Files"; 124 | sourceTree = ""; 125 | }; 126 | /* End PBXGroup section */ 127 | 128 | /* Begin PBXNativeTarget section */ 129 | 97C146ED1CF9000F007C117D /* Runner */ = { 130 | isa = PBXNativeTarget; 131 | buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; 132 | buildPhases = ( 133 | 9740EEB61CF901F6004384FC /* Run Script */, 134 | 97C146EA1CF9000F007C117D /* Sources */, 135 | 97C146EB1CF9000F007C117D /* Frameworks */, 136 | 97C146EC1CF9000F007C117D /* Resources */, 137 | 9705A1C41CF9048500538489 /* Embed Frameworks */, 138 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */, 139 | ); 140 | buildRules = ( 141 | ); 142 | dependencies = ( 143 | ); 144 | name = Runner; 145 | productName = Runner; 146 | productReference = 97C146EE1CF9000F007C117D /* Runner.app */; 147 | productType = "com.apple.product-type.application"; 148 | }; 149 | /* End PBXNativeTarget section */ 150 | 151 | /* Begin PBXProject section */ 152 | 97C146E61CF9000F007C117D /* Project object */ = { 153 | isa = PBXProject; 154 | attributes = { 155 | LastUpgradeCheck = 0910; 156 | ORGANIZATIONNAME = "The Chromium Authors"; 157 | TargetAttributes = { 158 | 97C146ED1CF9000F007C117D = { 159 | CreatedOnToolsVersion = 7.3.1; 160 | }; 161 | }; 162 | }; 163 | buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; 164 | compatibilityVersion = "Xcode 3.2"; 165 | developmentRegion = English; 166 | hasScannedForEncodings = 0; 167 | knownRegions = ( 168 | en, 169 | Base, 170 | ); 171 | mainGroup = 97C146E51CF9000F007C117D; 172 | productRefGroup = 97C146EF1CF9000F007C117D /* Products */; 173 | projectDirPath = ""; 174 | projectRoot = ""; 175 | targets = ( 176 | 97C146ED1CF9000F007C117D /* Runner */, 177 | ); 178 | }; 179 | /* End PBXProject section */ 180 | 181 | /* Begin PBXResourcesBuildPhase section */ 182 | 97C146EC1CF9000F007C117D /* Resources */ = { 183 | isa = PBXResourcesBuildPhase; 184 | buildActionMask = 2147483647; 185 | files = ( 186 | 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, 187 | 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 188 | 9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */, 189 | 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, 190 | 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, 191 | ); 192 | runOnlyForDeploymentPostprocessing = 0; 193 | }; 194 | /* End PBXResourcesBuildPhase section */ 195 | 196 | /* Begin PBXShellScriptBuildPhase section */ 197 | 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { 198 | isa = PBXShellScriptBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | ); 202 | inputPaths = ( 203 | ); 204 | name = "Thin Binary"; 205 | outputPaths = ( 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | shellPath = /bin/sh; 209 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" thin"; 210 | }; 211 | 9740EEB61CF901F6004384FC /* Run Script */ = { 212 | isa = PBXShellScriptBuildPhase; 213 | buildActionMask = 2147483647; 214 | files = ( 215 | ); 216 | inputPaths = ( 217 | ); 218 | name = "Run Script"; 219 | outputPaths = ( 220 | ); 221 | runOnlyForDeploymentPostprocessing = 0; 222 | shellPath = /bin/sh; 223 | shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; 224 | }; 225 | /* End PBXShellScriptBuildPhase section */ 226 | 227 | /* Begin PBXSourcesBuildPhase section */ 228 | 97C146EA1CF9000F007C117D /* Sources */ = { 229 | isa = PBXSourcesBuildPhase; 230 | buildActionMask = 2147483647; 231 | files = ( 232 | 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */, 233 | 97C146F31CF9000F007C117D /* main.m in Sources */, 234 | 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 235 | ); 236 | runOnlyForDeploymentPostprocessing = 0; 237 | }; 238 | /* End PBXSourcesBuildPhase section */ 239 | 240 | /* Begin PBXVariantGroup section */ 241 | 97C146FA1CF9000F007C117D /* Main.storyboard */ = { 242 | isa = PBXVariantGroup; 243 | children = ( 244 | 97C146FB1CF9000F007C117D /* Base */, 245 | ); 246 | name = Main.storyboard; 247 | sourceTree = ""; 248 | }; 249 | 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { 250 | isa = PBXVariantGroup; 251 | children = ( 252 | 97C147001CF9000F007C117D /* Base */, 253 | ); 254 | name = LaunchScreen.storyboard; 255 | sourceTree = ""; 256 | }; 257 | /* End PBXVariantGroup section */ 258 | 259 | /* Begin XCBuildConfiguration section */ 260 | 97C147031CF9000F007C117D /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 263 | buildSettings = { 264 | ALWAYS_SEARCH_USER_PATHS = NO; 265 | CLANG_ANALYZER_NONNULL = YES; 266 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 267 | CLANG_CXX_LIBRARY = "libc++"; 268 | CLANG_ENABLE_MODULES = YES; 269 | CLANG_ENABLE_OBJC_ARC = YES; 270 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 271 | CLANG_WARN_BOOL_CONVERSION = YES; 272 | CLANG_WARN_COMMA = YES; 273 | CLANG_WARN_CONSTANT_CONVERSION = YES; 274 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 275 | CLANG_WARN_EMPTY_BODY = YES; 276 | CLANG_WARN_ENUM_CONVERSION = YES; 277 | CLANG_WARN_INFINITE_RECURSION = YES; 278 | CLANG_WARN_INT_CONVERSION = YES; 279 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 280 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 281 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 282 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 283 | CLANG_WARN_STRICT_PROTOTYPES = YES; 284 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 285 | CLANG_WARN_UNREACHABLE_CODE = YES; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | DEBUG_INFORMATION_FORMAT = dwarf; 290 | ENABLE_STRICT_OBJC_MSGSEND = YES; 291 | ENABLE_TESTABILITY = YES; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_DYNAMIC_NO_PIC = NO; 294 | GCC_NO_COMMON_BLOCKS = YES; 295 | GCC_OPTIMIZATION_LEVEL = 0; 296 | GCC_PREPROCESSOR_DEFINITIONS = ( 297 | "DEBUG=1", 298 | "$(inherited)", 299 | ); 300 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 301 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 302 | GCC_WARN_UNDECLARED_SELECTOR = YES; 303 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 304 | GCC_WARN_UNUSED_FUNCTION = YES; 305 | GCC_WARN_UNUSED_VARIABLE = YES; 306 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 307 | MTL_ENABLE_DEBUG_INFO = YES; 308 | ONLY_ACTIVE_ARCH = YES; 309 | SDKROOT = iphoneos; 310 | TARGETED_DEVICE_FAMILY = "1,2"; 311 | }; 312 | name = Debug; 313 | }; 314 | 97C147041CF9000F007C117D /* Release */ = { 315 | isa = XCBuildConfiguration; 316 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 317 | buildSettings = { 318 | ALWAYS_SEARCH_USER_PATHS = NO; 319 | CLANG_ANALYZER_NONNULL = YES; 320 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 321 | CLANG_CXX_LIBRARY = "libc++"; 322 | CLANG_ENABLE_MODULES = YES; 323 | CLANG_ENABLE_OBJC_ARC = YES; 324 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 325 | CLANG_WARN_BOOL_CONVERSION = YES; 326 | CLANG_WARN_COMMA = YES; 327 | CLANG_WARN_CONSTANT_CONVERSION = YES; 328 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 329 | CLANG_WARN_EMPTY_BODY = YES; 330 | CLANG_WARN_ENUM_CONVERSION = YES; 331 | CLANG_WARN_INFINITE_RECURSION = YES; 332 | CLANG_WARN_INT_CONVERSION = YES; 333 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 334 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 335 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 336 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 337 | CLANG_WARN_STRICT_PROTOTYPES = YES; 338 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 339 | CLANG_WARN_UNREACHABLE_CODE = YES; 340 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 341 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 342 | COPY_PHASE_STRIP = NO; 343 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 344 | ENABLE_NS_ASSERTIONS = NO; 345 | ENABLE_STRICT_OBJC_MSGSEND = YES; 346 | GCC_C_LANGUAGE_STANDARD = gnu99; 347 | GCC_NO_COMMON_BLOCKS = YES; 348 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 350 | GCC_WARN_UNDECLARED_SELECTOR = YES; 351 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 352 | GCC_WARN_UNUSED_FUNCTION = YES; 353 | GCC_WARN_UNUSED_VARIABLE = YES; 354 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 355 | MTL_ENABLE_DEBUG_INFO = NO; 356 | SDKROOT = iphoneos; 357 | TARGETED_DEVICE_FAMILY = "1,2"; 358 | VALIDATE_PRODUCT = YES; 359 | }; 360 | name = Release; 361 | }; 362 | 97C147061CF9000F007C117D /* Debug */ = { 363 | isa = XCBuildConfiguration; 364 | baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; 365 | buildSettings = { 366 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 367 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 368 | ENABLE_BITCODE = NO; 369 | FRAMEWORK_SEARCH_PATHS = ( 370 | "$(inherited)", 371 | "$(PROJECT_DIR)/Flutter", 372 | ); 373 | INFOPLIST_FILE = Runner/Info.plist; 374 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 375 | LIBRARY_SEARCH_PATHS = ( 376 | "$(inherited)", 377 | "$(PROJECT_DIR)/Flutter", 378 | ); 379 | PRODUCT_BUNDLE_IDENTIFIER = com.realank.example; 380 | PRODUCT_NAME = "$(TARGET_NAME)"; 381 | VERSIONING_SYSTEM = "apple-generic"; 382 | }; 383 | name = Debug; 384 | }; 385 | 97C147071CF9000F007C117D /* Release */ = { 386 | isa = XCBuildConfiguration; 387 | baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; 388 | buildSettings = { 389 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 390 | CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; 391 | ENABLE_BITCODE = NO; 392 | FRAMEWORK_SEARCH_PATHS = ( 393 | "$(inherited)", 394 | "$(PROJECT_DIR)/Flutter", 395 | ); 396 | INFOPLIST_FILE = Runner/Info.plist; 397 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 398 | LIBRARY_SEARCH_PATHS = ( 399 | "$(inherited)", 400 | "$(PROJECT_DIR)/Flutter", 401 | ); 402 | PRODUCT_BUNDLE_IDENTIFIER = com.realank.example; 403 | PRODUCT_NAME = "$(TARGET_NAME)"; 404 | VERSIONING_SYSTEM = "apple-generic"; 405 | }; 406 | name = Release; 407 | }; 408 | /* End XCBuildConfiguration section */ 409 | 410 | /* Begin XCConfigurationList section */ 411 | 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { 412 | isa = XCConfigurationList; 413 | buildConfigurations = ( 414 | 97C147031CF9000F007C117D /* Debug */, 415 | 97C147041CF9000F007C117D /* Release */, 416 | ); 417 | defaultConfigurationIsVisible = 0; 418 | defaultConfigurationName = Release; 419 | }; 420 | 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { 421 | isa = XCConfigurationList; 422 | buildConfigurations = ( 423 | 97C147061CF9000F007C117D /* Debug */, 424 | 97C147071CF9000F007C117D /* Release */, 425 | ); 426 | defaultConfigurationIsVisible = 0; 427 | defaultConfigurationName = Release; 428 | }; 429 | /* End XCConfigurationList section */ 430 | }; 431 | rootObject = 97C146E61CF9000F007C117D /* Project object */; 432 | } 433 | -------------------------------------------------------------------------------- /example/.idea/libraries/Dart_Packages.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | -------------------------------------------------------------------------------- /lib/src/date_model.dart: -------------------------------------------------------------------------------- 1 | import 'package:flutter_datetime_picker/src/date_format.dart'; 2 | import 'package:flutter_datetime_picker/src/i18n_model.dart'; 3 | import 'datetime_util.dart'; 4 | import 'dart:math'; 5 | 6 | //interface for picker data model 7 | abstract class BasePickerModel { 8 | //a getter method for left column data, return null to end list 9 | String leftStringAtIndex(int index); 10 | //a getter method for middle column data, return null to end list 11 | String middleStringAtIndex(int index); 12 | //a getter method for right column data, return null to end list 13 | String rightStringAtIndex(int index); 14 | //set selected left index 15 | void setLeftIndex(int index); 16 | //set selected middle index 17 | void setMiddleIndex(int index); 18 | //set selected right index 19 | void setRightIndex(int index); 20 | //return current left index 21 | int currentLeftIndex(); 22 | //return current middle index 23 | int currentMiddleIndex(); 24 | //return current right index 25 | int currentRightIndex(); 26 | //return final time 27 | DateTime finalTime(); 28 | //return left divider string 29 | String leftDivider(); 30 | //return right divider string 31 | String rightDivider(); 32 | //layout proportions for 3 columns 33 | List layoutProportions(); 34 | } 35 | 36 | //a base class for picker data model 37 | class CommonPickerModel extends BasePickerModel { 38 | List leftList; 39 | List middleList; 40 | List rightList; 41 | DateTime currentTime; 42 | int _currentLeftIndex; 43 | int _currentMiddleIndex; 44 | int _currentRightIndex; 45 | 46 | LocaleType locale; 47 | 48 | CommonPickerModel({this.currentTime, locale}) : this.locale = locale ?? LocaleType.en; 49 | 50 | @override 51 | String leftStringAtIndex(int index) { 52 | return null; 53 | } 54 | 55 | @override 56 | String middleStringAtIndex(int index) { 57 | return null; 58 | } 59 | 60 | @override 61 | String rightStringAtIndex(int index) { 62 | return null; 63 | } 64 | 65 | @override 66 | int currentLeftIndex() { 67 | return _currentLeftIndex; 68 | } 69 | 70 | @override 71 | int currentMiddleIndex() { 72 | return _currentMiddleIndex; 73 | } 74 | 75 | @override 76 | int currentRightIndex() { 77 | return _currentRightIndex; 78 | } 79 | 80 | @override 81 | void setLeftIndex(int index) { 82 | _currentLeftIndex = index; 83 | } 84 | 85 | @override 86 | void setMiddleIndex(int index) { 87 | _currentMiddleIndex = index; 88 | } 89 | 90 | @override 91 | void setRightIndex(int index) { 92 | _currentRightIndex = index; 93 | } 94 | 95 | @override 96 | String leftDivider() { 97 | return ""; 98 | } 99 | 100 | @override 101 | String rightDivider() { 102 | return ""; 103 | } 104 | 105 | @override 106 | List layoutProportions() { 107 | return [1, 1, 1]; 108 | } 109 | 110 | @override 111 | DateTime finalTime() { 112 | return null; 113 | } 114 | } 115 | 116 | //a date picker model 117 | class DatePickerModel extends CommonPickerModel { 118 | DateTime maxTime; 119 | DateTime minTime; 120 | 121 | DatePickerModel({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale}) 122 | : super(locale: locale) { 123 | this.maxTime = maxTime ?? DateTime(2049, 12, 31); 124 | this.minTime = minTime ?? DateTime(1970, 1, 1); 125 | 126 | currentTime = currentTime ?? DateTime.now(); 127 | if (currentTime != null) { 128 | if (currentTime.compareTo(this.maxTime) > 0) { 129 | currentTime = this.maxTime; 130 | } else if (currentTime.compareTo(this.minTime) < 0) { 131 | currentTime = this.minTime; 132 | } 133 | } 134 | this.currentTime = currentTime; 135 | 136 | _fillLeftLists(); 137 | _fillMiddleLists(); 138 | _fillRightLists(); 139 | int minMonth = _minMonthOfCurrentYear(); 140 | int minDay = _minDayOfCurrentMonth(); 141 | _currentLeftIndex = this.currentTime.year - this.minTime.year; 142 | _currentMiddleIndex = this.currentTime.month - minMonth; 143 | _currentRightIndex = this.currentTime.day - minDay; 144 | } 145 | 146 | void _fillLeftLists() { 147 | this.leftList = List.generate(maxTime.year - minTime.year + 1, (int index) { 148 | // print('LEFT LIST... ${minTime.year + index}${_localeYear()}'); 149 | return '${minTime.year + index}${_localeYear()}'; 150 | }); 151 | } 152 | 153 | int _maxMonthOfCurrentYear() { 154 | return currentTime.year == maxTime.year ? maxTime.month : 12; 155 | } 156 | 157 | int _minMonthOfCurrentYear() { 158 | return currentTime.year == minTime.year ? minTime.month : 1; 159 | } 160 | 161 | int _maxDayOfCurrentMonth() { 162 | int dayCount = calcDateCount(currentTime.year, currentTime.month); 163 | return currentTime.year == maxTime.year && currentTime.month == maxTime.month 164 | ? maxTime.day 165 | : dayCount; 166 | } 167 | 168 | int _minDayOfCurrentMonth() { 169 | return currentTime.year == minTime.year && currentTime.month == minTime.month ? minTime.day : 1; 170 | } 171 | 172 | void _fillMiddleLists() { 173 | int minMonth = _minMonthOfCurrentYear(); 174 | int maxMonth = _maxMonthOfCurrentYear(); 175 | 176 | this.middleList = List.generate(maxMonth - minMonth + 1, (int index) { 177 | return '${_localeMonth(minMonth + index)}'; 178 | }); 179 | } 180 | 181 | void _fillRightLists() { 182 | int maxDay = _maxDayOfCurrentMonth(); 183 | int minDay = _minDayOfCurrentMonth(); 184 | this.rightList = List.generate(maxDay - minDay + 1, (int index) { 185 | return '${minDay + index}${_localeDay()}'; 186 | }); 187 | } 188 | 189 | @override 190 | void setLeftIndex(int index) { 191 | super.setLeftIndex(index); 192 | //adjust middle 193 | int destYear = index + minTime.year; 194 | int minMonth = _minMonthOfCurrentYear(); 195 | DateTime newTime; 196 | //change date time 197 | if (currentTime.month == 2 && currentTime.day == 29) { 198 | newTime = currentTime.isUtc 199 | ? DateTime.utc( 200 | destYear, 201 | currentTime.month, 202 | calcDateCount(destYear, 2), 203 | ) 204 | : DateTime( 205 | destYear, 206 | currentTime.month, 207 | calcDateCount(destYear, 2), 208 | ); 209 | } else { 210 | newTime = currentTime.isUtc 211 | ? DateTime.utc( 212 | destYear, 213 | currentTime.month, 214 | currentTime.day, 215 | ) 216 | : DateTime( 217 | destYear, 218 | currentTime.month, 219 | currentTime.day, 220 | ); 221 | } 222 | //min/max check 223 | if (newTime.isAfter(maxTime)) { 224 | currentTime = maxTime; 225 | } else if (newTime.isBefore(minTime)) { 226 | currentTime = minTime; 227 | } else { 228 | currentTime = newTime; 229 | } 230 | 231 | _fillMiddleLists(); 232 | _fillRightLists(); 233 | minMonth = _minMonthOfCurrentYear(); 234 | int minDay = _minDayOfCurrentMonth(); 235 | _currentMiddleIndex = currentTime.month - minMonth; 236 | _currentRightIndex = currentTime.day - minDay; 237 | } 238 | 239 | @override 240 | void setMiddleIndex(int index) { 241 | super.setMiddleIndex(index); 242 | //adjust right 243 | int minMonth = _minMonthOfCurrentYear(); 244 | int destMonth = minMonth + index; 245 | DateTime newTime; 246 | //change date time 247 | int dayCount = calcDateCount(currentTime.year, destMonth); 248 | newTime = currentTime.isUtc 249 | ? DateTime.utc( 250 | currentTime.year, 251 | destMonth, 252 | currentTime.day <= dayCount ? currentTime.day : dayCount, 253 | ) 254 | : DateTime( 255 | currentTime.year, 256 | destMonth, 257 | currentTime.day <= dayCount ? currentTime.day : dayCount, 258 | ); 259 | //min/max check 260 | if (newTime.isAfter(maxTime)) { 261 | currentTime = maxTime; 262 | } else if (newTime.isBefore(minTime)) { 263 | currentTime = minTime; 264 | } else { 265 | currentTime = newTime; 266 | } 267 | 268 | _fillRightLists(); 269 | int minDay = _minDayOfCurrentMonth(); 270 | _currentRightIndex = currentTime.day - minDay; 271 | } 272 | 273 | @override 274 | void setRightIndex(int index) { 275 | super.setRightIndex(index); 276 | int minDay = _minDayOfCurrentMonth(); 277 | currentTime = currentTime.isUtc 278 | ? DateTime.utc( 279 | currentTime.year, 280 | currentTime.month, 281 | minDay + index, 282 | ) 283 | : DateTime( 284 | currentTime.year, 285 | currentTime.month, 286 | minDay + index, 287 | ); 288 | } 289 | 290 | @override 291 | String leftStringAtIndex(int index) { 292 | if (index >= 0 && index < leftList.length) { 293 | return leftList[index]; 294 | } else { 295 | return null; 296 | } 297 | } 298 | 299 | @override 300 | String middleStringAtIndex(int index) { 301 | if (index >= 0 && index < middleList.length) { 302 | return middleList[index]; 303 | } else { 304 | return null; 305 | } 306 | } 307 | 308 | @override 309 | String rightStringAtIndex(int index) { 310 | if (index >= 0 && index < rightList.length) { 311 | return rightList[index]; 312 | } else { 313 | return null; 314 | } 315 | } 316 | 317 | String _localeYear() { 318 | if (locale == LocaleType.zh || locale == LocaleType.jp) { 319 | return '年'; 320 | } else if (locale == LocaleType.ko) { 321 | return '년'; 322 | } else { 323 | return ''; 324 | } 325 | } 326 | 327 | String _localeMonth(int month) { 328 | if (locale == LocaleType.zh || locale == LocaleType.jp) { 329 | return '$month月'; 330 | } else if (locale == LocaleType.ko) { 331 | return '$month월'; 332 | } else { 333 | List monthStrings = i18nObjInLocale(locale)['monthLong']; 334 | return monthStrings[month - 1]; 335 | } 336 | } 337 | 338 | String _localeDay() { 339 | if (locale == LocaleType.zh || locale == LocaleType.jp) { 340 | return '日'; 341 | } else if (locale == LocaleType.ko) { 342 | return '일'; 343 | } else { 344 | return ''; 345 | } 346 | } 347 | 348 | @override 349 | DateTime finalTime() { 350 | return currentTime; 351 | } 352 | } 353 | 354 | //a time picker model 355 | class TimePickerModel extends CommonPickerModel { 356 | bool showSecondsColumn; 357 | 358 | TimePickerModel({DateTime currentTime, LocaleType locale, this.showSecondsColumn: true}) 359 | : super(locale: locale) { 360 | this.currentTime = currentTime ?? DateTime.now(); 361 | 362 | _currentLeftIndex = this.currentTime.hour; 363 | _currentMiddleIndex = this.currentTime.minute; 364 | _currentRightIndex = this.currentTime.second; 365 | } 366 | 367 | @override 368 | String leftStringAtIndex(int index) { 369 | if (index >= 0 && index < 24) { 370 | return digits(index, 2); 371 | } else { 372 | return null; 373 | } 374 | } 375 | 376 | @override 377 | String middleStringAtIndex(int index) { 378 | if (index >= 0 && index < 60) { 379 | return digits(index, 2); 380 | } else { 381 | return null; 382 | } 383 | } 384 | 385 | @override 386 | String rightStringAtIndex(int index) { 387 | if (index >= 0 && index < 60) { 388 | return digits(index, 2); 389 | } else { 390 | return null; 391 | } 392 | } 393 | 394 | @override 395 | String leftDivider() { 396 | return ":"; 397 | } 398 | 399 | @override 400 | String rightDivider() { 401 | if (showSecondsColumn) 402 | return ":"; 403 | else 404 | return ""; 405 | } 406 | 407 | @override 408 | List layoutProportions() { 409 | if (showSecondsColumn) 410 | return [1, 1, 1]; 411 | else 412 | return [1, 1, 0]; 413 | } 414 | 415 | @override 416 | DateTime finalTime() { 417 | return currentTime.isUtc 418 | ? DateTime.utc(currentTime.year, currentTime.month, currentTime.day, _currentLeftIndex, 419 | _currentMiddleIndex, _currentRightIndex) 420 | : DateTime(currentTime.year, currentTime.month, currentTime.day, _currentLeftIndex, 421 | _currentMiddleIndex, _currentRightIndex); 422 | } 423 | } 424 | 425 | //a time picker model 426 | class Time12hPickerModel extends CommonPickerModel { 427 | Time12hPickerModel({DateTime currentTime, LocaleType locale}) : super(locale: locale) { 428 | this.currentTime = currentTime ?? DateTime.now(); 429 | 430 | _currentLeftIndex = this.currentTime.hour % 12; 431 | _currentMiddleIndex = this.currentTime.minute; 432 | _currentRightIndex = this.currentTime.hour < 12 ? 0 : 1; 433 | } 434 | 435 | @override 436 | String leftStringAtIndex(int index) { 437 | if (index >= 0 && index < 12) { 438 | if (index == 0) { 439 | return digits(12, 2); 440 | } else { 441 | return digits(index, 2); 442 | } 443 | } else { 444 | return null; 445 | } 446 | } 447 | 448 | @override 449 | String middleStringAtIndex(int index) { 450 | if (index >= 0 && index < 60) { 451 | return digits(index, 2); 452 | } else { 453 | return null; 454 | } 455 | } 456 | 457 | @override 458 | String rightStringAtIndex(int index) { 459 | if (index == 0) { 460 | return "AM"; 461 | } else if (index == 1) { 462 | return "PM"; 463 | } else { 464 | return null; 465 | } 466 | } 467 | 468 | @override 469 | String leftDivider() { 470 | return ":"; 471 | } 472 | 473 | @override 474 | String rightDivider() { 475 | return ":"; 476 | } 477 | 478 | @override 479 | List layoutProportions() { 480 | return [1, 1, 1]; 481 | } 482 | 483 | @override 484 | DateTime finalTime() { 485 | int hour = _currentLeftIndex + 12 * _currentRightIndex; 486 | return currentTime.isUtc 487 | ? DateTime.utc( 488 | currentTime.year, currentTime.month, currentTime.day, hour, _currentMiddleIndex, 0) 489 | : DateTime( 490 | currentTime.year, currentTime.month, currentTime.day, hour, _currentMiddleIndex, 0); 491 | } 492 | } 493 | 494 | // a date&time picker model 495 | class DateTimePickerModel extends CommonPickerModel { 496 | DateTime maxTime; 497 | DateTime minTime; 498 | DateTimePickerModel({DateTime currentTime, DateTime maxTime, DateTime minTime, LocaleType locale}) 499 | : super(locale: locale) { 500 | if (currentTime != null) { 501 | this.currentTime = currentTime; 502 | if (maxTime != null && 503 | (currentTime.isBefore(maxTime) || currentTime.isAtSameMomentAs(maxTime))) { 504 | this.maxTime = maxTime; 505 | } 506 | if (minTime != null && 507 | (currentTime.isAfter(minTime) || currentTime.isAtSameMomentAs(minTime))) { 508 | this.minTime = minTime; 509 | } 510 | } else { 511 | this.maxTime = maxTime; 512 | this.minTime = minTime; 513 | var now = DateTime.now(); 514 | if (this.minTime != null && this.minTime.isAfter(now)) { 515 | this.currentTime = this.minTime; 516 | } else if (this.maxTime != null && this.maxTime.isBefore(now)) { 517 | this.currentTime = this.maxTime; 518 | } else { 519 | this.currentTime = now; 520 | } 521 | } 522 | 523 | if (this.minTime != null && this.maxTime != null && this.maxTime.isBefore(this.minTime)) { 524 | // invalid 525 | this.minTime = null; 526 | this.maxTime = null; 527 | } 528 | 529 | _currentLeftIndex = 0; 530 | _currentMiddleIndex = this.currentTime.hour; 531 | _currentRightIndex = this.currentTime.minute; 532 | if (this.minTime != null && isAtSameDay(this.minTime, this.currentTime)) { 533 | _currentMiddleIndex = this.currentTime.hour - this.minTime.hour; 534 | if (_currentMiddleIndex == 0) { 535 | _currentRightIndex = this.currentTime.minute - this.minTime.minute; 536 | } 537 | } 538 | } 539 | 540 | bool isAtSameDay(DateTime day1, DateTime day2) { 541 | return day1 != null && 542 | day2 != null && 543 | day1.difference(day2).inDays == 0 && 544 | day1.day == day2.day; 545 | } 546 | 547 | @override 548 | void setLeftIndex(int index) { 549 | // TODO: implement setLeftIndex 550 | super.setLeftIndex(index); 551 | 552 | DateTime time = currentTime.add(Duration(days: index)); 553 | if (isAtSameDay(minTime, time)) { 554 | var index = min(24 - minTime.hour - 1, _currentMiddleIndex); 555 | this.setMiddleIndex(index); 556 | } else if (isAtSameDay(maxTime, time)) { 557 | var index = min(maxTime.hour, _currentMiddleIndex); 558 | this.setMiddleIndex(index); 559 | } 560 | } 561 | 562 | @override 563 | void setMiddleIndex(int index) { 564 | // TODO: implement setMiddleIndex 565 | super.setMiddleIndex(index); 566 | DateTime time = currentTime.add(Duration(days: _currentLeftIndex)); 567 | if (isAtSameDay(minTime, time) && index == 0) { 568 | var maxIndex = 60 - minTime.minute - 1; 569 | if (_currentRightIndex > maxIndex) { 570 | _currentRightIndex = maxIndex; 571 | } 572 | } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex == maxTime.hour) { 573 | var maxIndex = maxTime.minute; 574 | if (_currentRightIndex > maxIndex) { 575 | _currentRightIndex = maxIndex; 576 | } 577 | } 578 | } 579 | 580 | @override 581 | String leftStringAtIndex(int index) { 582 | DateTime time = currentTime.add(Duration(days: index)); 583 | if (minTime != null && time.isBefore(minTime) && !isAtSameDay(minTime, time)) { 584 | return null; 585 | } else if (maxTime != null && time.isAfter(maxTime) && !isAtSameDay(maxTime, time)) { 586 | return null; 587 | } 588 | return formatDate(time, [ymdw], locale); 589 | } 590 | 591 | @override 592 | String middleStringAtIndex(int index) { 593 | if (index >= 0 && index < 24) { 594 | DateTime time = currentTime.add(Duration(days: _currentLeftIndex)); 595 | if (isAtSameDay(minTime, time)) { 596 | if (index >= 0 && index < 24 - minTime.hour) { 597 | return digits(minTime.hour + index, 2); 598 | } else { 599 | return null; 600 | } 601 | } else if (isAtSameDay(maxTime, time)) { 602 | if (index >= 0 && index <= maxTime.hour) { 603 | return digits(index, 2); 604 | } else { 605 | return null; 606 | } 607 | } 608 | return digits(index, 2); 609 | } 610 | 611 | return null; 612 | } 613 | 614 | @override 615 | String rightStringAtIndex(int index) { 616 | if (index >= 0 && index < 60) { 617 | DateTime time = currentTime.add(Duration(days: _currentLeftIndex)); 618 | if (isAtSameDay(minTime, time) && _currentMiddleIndex == 0) { 619 | if (index >= 0 && index < 60 - minTime.minute) { 620 | return digits(minTime.minute + index, 2); 621 | } else { 622 | return null; 623 | } 624 | } else if (isAtSameDay(maxTime, time) && _currentMiddleIndex >= maxTime.hour) { 625 | if (index >= 0 && index <= maxTime.minute) { 626 | return digits(index, 2); 627 | } else { 628 | return null; 629 | } 630 | } 631 | return digits(index, 2); 632 | } 633 | 634 | return null; 635 | } 636 | 637 | @override 638 | DateTime finalTime() { 639 | DateTime time = currentTime.add(Duration(days: _currentLeftIndex)); 640 | var hour = _currentMiddleIndex; 641 | var minute = _currentRightIndex; 642 | if (isAtSameDay(minTime, time)) { 643 | hour += minTime.hour; 644 | if (minTime.hour == hour) { 645 | minute += minTime.minute; 646 | } 647 | } 648 | 649 | return currentTime.isUtc 650 | ? DateTime.utc(time.year, time.month, time.day, hour, minute) 651 | : DateTime(time.year, time.month, time.day, hour, minute); 652 | } 653 | 654 | @override 655 | List layoutProportions() { 656 | return [4, 1, 1]; 657 | } 658 | 659 | @override 660 | String rightDivider() { 661 | return ':'; 662 | } 663 | } 664 | -------------------------------------------------------------------------------- /lib/src/i18n_model.dart: -------------------------------------------------------------------------------- 1 | enum LocaleType { 2 | en, 3 | fa, 4 | zh, 5 | nl, 6 | ru, 7 | it, 8 | fr, 9 | es, 10 | pl, 11 | pt, 12 | ko, 13 | kk, 14 | ar, 15 | tr, 16 | az, 17 | jp, 18 | de, 19 | da, 20 | mn, 21 | bn, 22 | vi, 23 | hy, 24 | id, 25 | bg, 26 | eu, 27 | cat, 28 | th, 29 | si, 30 | no 31 | } 32 | 33 | final _i18nModel = { 34 | 'en': { 35 | 'cancel': 'Cancel', 36 | 'done': 'Done', 37 | 'today': 'Today', 38 | 'monthShort': [ 39 | 'Jan', 40 | 'Feb', 41 | 'Mar', 42 | 'Apr', 43 | 'May', 44 | 'Jun', 45 | 'Jul', 46 | 'Aug', 47 | 'Sep', 48 | 'Oct', 49 | 'Nov', 50 | 'Dec' 51 | ], 52 | 'monthLong': [ 53 | 'January', 54 | 'February', 55 | 'March', 56 | 'April', 57 | 'May', 58 | 'June', 59 | 'July', 60 | 'August', 61 | 'September', 62 | 'October', 63 | 'November', 64 | 'December' 65 | ], 66 | 'day': ['Mon', 'Tue', 'Wed', 'Thur', 'Fri', 'Sat', 'Sun'], 67 | 'am': 'AM', 68 | 'pm': 'PM' 69 | }, 70 | 'mn': { 71 | 'cancel': 'Гарах', 72 | 'done': 'Дуусгах', 73 | 'today': 'Өнөөдөр', 74 | 'monthShort': [ 75 | '1-р сар', 76 | '2-р сар', 77 | '3-р сар', 78 | '4-р сар', 79 | '5-р сар', 80 | '6-р сар', 81 | '7-р сар', 82 | '8-р сар', 83 | '9-р сар', 84 | '10-р сар', 85 | '11-р сар', 86 | '12-р сар' 87 | ], 88 | 'monthLong': [ 89 | '1-р сарын ', 90 | '2-р сарын ', 91 | '3-р сарын ', 92 | '4-р сарын ', 93 | '5-р сарын ', 94 | '6-р сарын ', 95 | '7-р сарын ', 96 | '8-р сарын ', 97 | '9-р сарын ', 98 | '10-р сарын ', 99 | '11-р сарын ', 100 | '12-р сарын ' 101 | ], 102 | 'day': ['Дав', 'Мяг', 'Лха', 'Пүр', 'Баа', 'Бям', 'Ням'], 103 | 'am': 'AM', 104 | 'pm': 'PM' 105 | }, 106 | 'fa': { 107 | 'cancel': 'لغو', 108 | 'done': 'تایید', 109 | 'today': 'امروز', 110 | 'monthShort': [ 111 | 'فروردین', 112 | 'اردیبهشت', 113 | 'خرداد', 114 | 'تیر', 115 | 'مرداد', 116 | 'شهریور', 117 | 'مهر', 118 | 'آبان', 119 | 'آذر', 120 | 'دی', 121 | 'بهمن', 122 | 'اسفند' 123 | ], 124 | 'monthLong': [ 125 | 'فروردین', 126 | 'اردیبهشت', 127 | 'خرداد', 128 | 'تیر', 129 | 'مرداد', 130 | 'شهریور', 131 | 'مهر', 132 | 'آبان', 133 | 'آذر', 134 | 'دی', 135 | 'بهمن', 136 | 'اسفند' 137 | ], 138 | 'day': ['دوشنبه', 'سه شنبه', 'چهارشنبه', 'پنج شنبه', 'جمعه', 'شنبه', 'یکشنبه'], 139 | 'am': 'صبح', 140 | 'pm': 'عصر' 141 | }, 142 | 'zh': { 143 | //Chinese 144 | 'cancel': '取消', 145 | 'done': '确定', 146 | 'today': '今天', 147 | 'monthShort': ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], 148 | 'monthLong': ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], 149 | 'day': ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期日'], 150 | 'am': '上午', 151 | 'pm': '下午' 152 | }, 153 | 'nl': { 154 | //Dutch 155 | 'cancel': 'Annuleer', 156 | 'done': 'Klaar', 157 | 'today': 'Vandaag', 158 | 'monthShort': [ 159 | 'Jan', 160 | 'Feb', 161 | 'Mar', 162 | 'Apr', 163 | 'Mei', 164 | 'Jun', 165 | 'Jul', 166 | 'Aug', 167 | 'Sep', 168 | 'Okt', 169 | 'Nov', 170 | 'Dec', 171 | ], 172 | 'monthLong': [ 173 | 'Januari', 174 | 'Februari', 175 | 'Maart', 176 | 'April', 177 | 'Mei', 178 | 'Juni', 179 | 'Juli', 180 | 'Augustus', 181 | 'September', 182 | 'Oktober', 183 | 'November', 184 | 'December', 185 | ], 186 | 'day': [ 187 | 'Ma', 188 | 'Di', 189 | 'Wo', 190 | 'Do', 191 | 'Vr', 192 | 'Za', 193 | 'Zo', 194 | ], 195 | 'am': 'AM', 196 | 'pm': 'PM' 197 | }, 198 | 'ru': { 199 | 'cancel': 'Отмена', 200 | 'done': 'Готово', 201 | 'today': 'Сегодня', 202 | 'monthShort': [ 203 | 'Янв', 204 | 'Фев', 205 | 'Март', 206 | 'Апр', 207 | 'Май', 208 | 'Июнь', 209 | 'Июль', 210 | 'Авг', 211 | 'Сен', 212 | 'Окт', 213 | 'Ноя', 214 | 'Дек' 215 | ], 216 | 'monthLong': [ 217 | 'Январь', 218 | 'Февраль', 219 | 'Март', 220 | 'Апрель', 221 | 'Май', 222 | 'Июнь', 223 | 'Июль', 224 | 'Август', 225 | 'Сентябрь', 226 | 'Октябрь', 227 | 'Ноябрь', 228 | 'Декабрь' 229 | ], 230 | 'day': ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Вс'], 231 | 'am': 'AM', 232 | 'pm': 'PM' 233 | }, 234 | 'it': { 235 | 'cancel': 'Annulla', 236 | 'done': 'Conferma', 237 | 'today': 'Oggi', 238 | 'monthShort': [ 239 | 'Gen', 240 | 'Feb', 241 | 'Mar', 242 | 'Apr', 243 | 'Mag', 244 | 'Giu', 245 | 'Lug', 246 | 'Ago', 247 | 'Set', 248 | 'Ott', 249 | 'Nov', 250 | 'Dic' 251 | ], 252 | 'monthLong': [ 253 | 'Gennaio', 254 | 'Febbraio', 255 | 'Marzo', 256 | 'Aprile', 257 | 'Maggio', 258 | 'Giugno', 259 | 'Luglio', 260 | 'Agosto', 261 | 'Settembre', 262 | 'Ottobre', 263 | 'Novembre', 264 | 'Dicembre' 265 | ], 266 | 'day': ['Lun', 'Mar', 'Mer', 'Giov', 'Ven', 'Sab', 'Dom'], 267 | 'am': 'AM', 268 | 'pm': 'PM' 269 | }, 270 | 'fr': { 271 | 'cancel': 'Annuler', 272 | 'done': 'Confirmer', 273 | 'today': "Aujourd'hui", 274 | 'monthShort': [ 275 | 'Jan', 276 | 'Fév', 277 | 'Mar', 278 | 'Avr', 279 | 'Mai', 280 | 'Juin', 281 | 'Juil', 282 | 'Aoû', 283 | 'Sep', 284 | 'Oct', 285 | 'Nov', 286 | 'Déc' 287 | ], 288 | 'monthLong': [ 289 | 'Janvier', 290 | 'Février', 291 | 'Mars', 292 | 'Avril', 293 | 'Mai', 294 | 'Juin', 295 | 'Juillet', 296 | 'Août', 297 | 'Septembre', 298 | 'Octobre', 299 | 'Novembre', 300 | 'Décembre' 301 | ], 302 | 'day': ['Lun', 'Mar', 'Mer', 'Jeu', 'Ven', 'Sam', 'Dim'], 303 | 'am': 'AM', 304 | 'pm': 'PM' 305 | }, 306 | 'es': { 307 | 'cancel': 'Cancelar', 308 | 'done': 'Confirmar', 309 | 'today': 'Hoy', 310 | 'monthShort': [ 311 | 'Ene', 312 | 'Feb', 313 | 'Mar', 314 | 'Abr', 315 | 'May', 316 | 'Jun', 317 | 'Jul', 318 | 'Ago', 319 | 'Sep', 320 | 'Oct', 321 | 'Nov', 322 | 'Dic' 323 | ], 324 | 'monthLong': [ 325 | 'Enero', 326 | 'Febrero', 327 | 'Marzo', 328 | 'Abril', 329 | 'Mayo', 330 | 'Junio', 331 | 'Julio', 332 | 'Agosto', 333 | 'Septiembre', 334 | 'Octubre', 335 | 'Noviembre', 336 | 'Diciembre' 337 | ], 338 | 'day': ['Lun', 'Mar', 'Mié', 'Jue', 'Vie', 'Sáb', 'Dom'], 339 | 'am': 'AM', 340 | 'pm': 'PM' 341 | }, 342 | 'pl': { 343 | 'cancel': 'Anuluj', 344 | 'done': 'Gotowe', 345 | 'today': 'Dziś', 346 | 'monthShort': [ 347 | 'Sty', 348 | 'Lut', 349 | 'Mar', 350 | 'Kwi', 351 | 'Maj', 352 | 'Cze', 353 | 'Lip', 354 | 'Sie', 355 | 'Wrz', 356 | 'Paź', 357 | 'Lis', 358 | 'Gru' 359 | ], 360 | 'monthLong': [ 361 | 'Styczeń', 362 | 'Luty', 363 | 'Marzec', 364 | 'Kwiecień', 365 | 'Maj', 366 | 'Czerwiec', 367 | 'Lipiec', 368 | 'Sierpień', 369 | 'Wrzesień', 370 | 'Październik', 371 | 'Listopad', 372 | 'Grudzień' 373 | ], 374 | 'day': ['Pn', 'Wt', 'Śr', 'Cz', 'Pt', 'Sb', 'Nd'], 375 | 'am': 'AM', 376 | 'pm': 'PM' 377 | }, 378 | 'pt': { 379 | 'cancel': 'Cancelar', 380 | 'done': 'Confirmar', 381 | 'today': 'Hoje', 382 | 'monthShort': [ 383 | 'Jan', 384 | 'Fev', 385 | 'Mar', 386 | 'Abr', 387 | 'Mai', 388 | 'Jun', 389 | 'Jul', 390 | 'Ago', 391 | 'Set', 392 | 'Out', 393 | 'Nov', 394 | 'Dez' 395 | ], 396 | 'monthLong': [ 397 | 'Janeiro', 398 | 'Fevereiro', 399 | 'Março', 400 | 'Abril', 401 | 'Maio', 402 | 'Junho', 403 | 'Julho', 404 | 'Agosto', 405 | 'Setembro', 406 | 'Outubro', 407 | 'Novembro', 408 | 'Dezembro' 409 | ], 410 | 'day': ['Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sáb', 'Dom'], 411 | 'am': 'AM', 412 | 'pm': 'PM' 413 | }, 414 | 'ko': { 415 | 'cancel': '취소', 416 | 'done': '완료', 417 | 'today': '오늘', 418 | 'monthShort': ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], 419 | 'monthLong': ['1월', '2월', '3월', '4월', '5월', '6월', '7월', '8월', '9월', '10월', '11월', '12월'], 420 | 'day': ['월', '화', '수', '목', '금', '토', '일'], 421 | 'am': '오전', 422 | 'pm': '오후' 423 | }, 424 | 'kk': { 425 | 'cancel': 'Жою', 426 | 'done': 'Дайын', 427 | 'today': 'бүгін', 428 | 'monthShort': [ 429 | 'Қаң', 430 | 'Ақп', 431 | 'Нау', 432 | 'Сәу', 433 | 'Мам', 434 | 'Мау', 435 | 'Шіл', 436 | 'Там', 437 | 'Қыр', 438 | 'Қаз', 439 | 'Қар', 440 | 'Жел' 441 | ], 442 | 'monthLong': [ 443 | 'Қаңтар', 444 | 'Ақпан', 445 | 'Наурыз', 446 | 'Сәуір', 447 | 'Мамыр', 448 | 'Маусым', 449 | 'Шілде', 450 | 'Тамыз', 451 | 'Қыркүйек', 452 | 'Қазан', 453 | 'Қараша', 454 | 'Желтоқсан' 455 | ], 456 | 'day': ['Дү', 'Сй', 'Ср', 'Бе', 'Жм', 'Сн', 'Же'], 457 | 'am': 'AM', 458 | 'pm': 'PM' 459 | }, 460 | 'ar': { 461 | 'cancel': 'إنهاء', 462 | 'done': 'تأكيد', 463 | 'today': 'اليوم', 464 | 'monthShort': [ 465 | 'يناير', 466 | 'فبراير', 467 | 'مارس', 468 | 'إبريل', 469 | 'مايو', 470 | 'يونيو', 471 | 'يوليو', 472 | 'أغسطس', 473 | 'سبتمبر', 474 | 'أكتوبر', 475 | 'نوفمبر', 476 | 'ديسمبر' 477 | ], 478 | 'monthLong': [ 479 | 'يناير', 480 | 'فبراير', 481 | 'مارس', 482 | 'إبريل', 483 | 'مايو', 484 | 'يونيو', 485 | 'يوليو', 486 | 'أغسطس', 487 | 'سبتمبر', 488 | 'أكتوبر', 489 | 'نوفمبر', 490 | 'ديسمبر' 491 | ], 492 | 'day': ['الإثنين', 'الثلاثاء', 'الأربعاء', 'الخميس', 'الجمعه', 'السبت', 'الاحد'], 493 | 'am': 'ص', 494 | 'pm': 'م' 495 | }, 496 | 'tr': { 497 | 'cancel': 'İptal', 498 | 'done': 'Tamam', 499 | 'today': 'Bugün', 500 | 'monthShort': [ 501 | 'Oca', 502 | 'Şub', 503 | 'Mar', 504 | 'Nis', 505 | 'May', 506 | 'Haz', 507 | 'Tem', 508 | 'Ağu', 509 | 'Eyl', 510 | 'Eki', 511 | 'Kas', 512 | 'Ara' 513 | ], 514 | 'monthLong': [ 515 | 'Ocak', 516 | 'Şubat', 517 | 'Mart', 518 | 'Nisan', 519 | 'Mayıs', 520 | 'Haziran', 521 | 'Temmuz', 522 | 'Ağustos', 523 | 'Eylül', 524 | 'Ekim', 525 | 'Kasım', 526 | 'Aralık' 527 | ], 528 | 'day': ['Pzt', 'Sal', 'Çarş', 'Perş', 'Cum', 'Ctes', 'Paz'], 529 | 'am': 'ÖÖ', 530 | 'pm': 'ÖS' 531 | }, 532 | 'az': { 533 | 'cancel': 'Ləğv et', 534 | 'done': 'Bitdi', 535 | 'today': 'Bugün', 536 | 'monthShort': [ 537 | 'Yan', 538 | 'Fev', 539 | 'Mar', 540 | 'Apr', 541 | 'May', 542 | 'İyn', 543 | 'İyl', 544 | 'Avq', 545 | 'Sen', 546 | 'Okt', 547 | 'Noy', 548 | 'Dek' 549 | ], 550 | 'monthLong': [ 551 | 'Yanvar', 552 | 'Fevral', 553 | 'Mart', 554 | 'Aprel', 555 | 'May', 556 | 'İyun', 557 | 'İyul', 558 | 'Avqust', 559 | 'Sentyabr', 560 | 'Oktyabr', 561 | 'Noyabr', 562 | 'Dekabr' 563 | ], 564 | 'day': ['B.E', 'Ç.A', 'Ç', 'C.A', 'C.', 'Ş.', 'B.'], 565 | 'am': 'ÖÖ', 566 | 'pm': 'ÖS' 567 | }, 568 | 'jp': { 569 | //Japanese 570 | 'cancel': 'キャンセル', 571 | 'done': '完了', 572 | 'today': '今日', 573 | 'monthShort': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], 574 | 'monthLong': ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], 575 | 'day': ['月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日', '日曜日'], 576 | 'am': '午前', 577 | 'pm': '午後' 578 | }, 579 | 'de': { 580 | //German 581 | 'cancel': 'Abbrechen', 582 | 'done': 'OK', 583 | 'today': 'Heute', 584 | 'monthShort': [ 585 | 'Jan', 586 | 'Feb', 587 | 'Mrz', 588 | 'Apr', 589 | 'Mai', 590 | 'Jun', 591 | 'Jul', 592 | 'Aug', 593 | 'Sep', 594 | 'Okt', 595 | 'Nov', 596 | 'Dez' 597 | ], 598 | 'monthLong': [ 599 | 'Januar', 600 | 'Februar', 601 | 'März', 602 | 'April', 603 | 'Mai', 604 | 'Juni', 605 | 'Juli', 606 | 'August', 607 | 'September', 608 | 'Oktober', 609 | 'November', 610 | 'Dezember' 611 | ], 612 | 'day': ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'], 613 | 'am': 'AM', 614 | 'pm': 'PM' 615 | }, 616 | 'da': { 617 | //Danish 618 | 'cancel': 'Annullér', 619 | 'done': 'OK', 620 | 'today': 'I dag', 621 | 'monthShort': [ 622 | 'jan', 623 | 'feb', 624 | 'mar', 625 | 'apr', 626 | 'maj', 627 | 'juni', 628 | 'juli', 629 | 'aug', 630 | 'sept', 631 | 'okt', 632 | 'nov', 633 | 'dec' 634 | ], 635 | 'monthLong': [ 636 | 'januar', 637 | 'februar', 638 | 'marts', 639 | 'april', 640 | 'maj', 641 | 'juni', 642 | 'juli', 643 | 'august', 644 | 'september', 645 | 'oktober', 646 | 'november', 647 | 'december' 648 | ], 649 | 'day': ['man', 'tirs', 'ons', 'tors', 'fre', 'lør', 'søn'], 650 | 'am': 'AM', 651 | 'pm': 'PM' 652 | }, 653 | 'bn': { 654 | //Bengali 655 | 'cancel': 'বাতিল', 656 | 'done': 'সম্পন্ন', 657 | 'today': 'আজ', 658 | 'monthShort': [ 659 | "জানু", 660 | "ফেব্", 661 | "মার্চ", 662 | "এপ্রিল", 663 | "মে", 664 | "জুন", 665 | "জুলাই", 666 | "অগাস্ট", 667 | "সেপ্ট", 668 | "অক্ট", 669 | "নভেম্", 670 | "ডিসেম্" 671 | ], 672 | 'monthLong': [ 673 | "জানুয়ারী", 674 | "ফেব্রুয়ারি", 675 | "মার্চ", 676 | "এপ্রিল", 677 | "মে", 678 | "জুন", 679 | "জুলাই", 680 | "অগাস্ট", 681 | "সেপ্টেম্বর", 682 | "অক্টোবর", 683 | "নভেম্বর", 684 | "ডিসেম্বর" 685 | ], 686 | 'day': [ 687 | "রবিবার", 688 | "সোমবার", 689 | "মঙ্গলবার", 690 | "বুধবার", 691 | "বৃহস্পতিবার", 692 | "শুক্রবার", 693 | "শনিবার", 694 | ], 695 | 'am': 'AM', 696 | 'pm': 'PM' 697 | }, 698 | 'vi': { 699 | 'cancel': 'Hủy bỏ', 700 | 'done': 'Xong', 701 | 'today': 'Hôm nay', 702 | 'monthShort': [ 703 | 'Thg1', 704 | 'Thg2', 705 | 'Thg3', 706 | 'Thg4', 707 | 'Thg5', 708 | 'Thg6', 709 | 'Thg7', 710 | 'Thg8', 711 | 'Thg9', 712 | 'Thg10', 713 | 'Thg11', 714 | 'Thg12' 715 | ], 716 | 'monthLong': [ 717 | 'Tháng 1', 718 | 'Tháng 2', 719 | 'Tháng 3', 720 | 'Tháng 4', 721 | 'Tháng 5', 722 | 'Tháng 6', 723 | 'Tháng 7', 724 | 'Tháng 8', 725 | 'Tháng 9', 726 | 'Tháng 10', 727 | 'Tháng 11', 728 | 'Tháng 12' 729 | ], 730 | 'day': ['T2', 'T3', 'T4', 'T5', 'T6', 'T7', 'CN'], 731 | 'am': 'SA', 732 | 'pm': 'CH' 733 | }, 734 | 'hy': { 735 | //Armenian 736 | 'cancel': 'Չեղարկել', 737 | 'done': 'հաստատել', 738 | 'today': 'Այսօր', 739 | 'monthShort': [ 740 | 'Հնվ', 741 | 'Փետ', 742 | 'Մար', 743 | 'Ապր', 744 | 'Մայ', 745 | 'Հուն', 746 | 'Հուլ', 747 | 'Օգոս', 748 | 'Սեպ', 749 | 'Հոկ', 750 | 'Նոյ', 751 | 'Դեկ' 752 | ], 753 | 'monthLong': [ 754 | 'Հունվար', 755 | 'Փետրվար', 756 | 'Մարտ', 757 | 'Ապրիլ', 758 | 'Մայիս', 759 | 'Հունիս', 760 | 'Հուլիս', 761 | 'Օգոստոս', 762 | 'Սեպտեմբեր', 763 | 'Հոկտեմբեր', 764 | 'Նոյեմբեր', 765 | 'Դեկտեմբեր' 766 | ], 767 | 'day': ['Երկ', 'Երք', 'Չրք', 'Հնգ', 'Ուր', 'Շբթ', 'Կիր'], 768 | 'am': 'AM', 769 | 'pm': 'PM' 770 | }, 771 | 'id': { 772 | 'cancel': 'Batal', 773 | 'done': 'Pilih', 774 | 'today': 'Hari Ini', 775 | 'monthShort': [ 776 | 'Jan', 777 | 'Feb', 778 | 'Mar', 779 | 'Apr', 780 | 'Mei', 781 | 'Jun', 782 | 'Jul', 783 | 'Agu', 784 | 'Sep', 785 | 'Okt', 786 | 'Nov', 787 | 'Des' 788 | ], 789 | 'monthLong': [ 790 | 'Januari', 791 | 'Februari', 792 | 'Maret', 793 | 'April', 794 | 'Mei', 795 | 'Juni', 796 | 'Juli', 797 | 'Agustus', 798 | 'September', 799 | 'Oktober', 800 | 'November', 801 | 'Desember' 802 | ], 803 | 'day': ['Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab', 'Min'], 804 | 'am': 'AM', 805 | 'pm': 'PM' 806 | }, 807 | 'bg': { 808 | 'cancel': 'Отказ', 809 | 'done': 'Готово', 810 | 'today': 'Днес', 811 | 'monthShort': [ 812 | 'Яну', 813 | 'Фев', 814 | 'Март', 815 | 'Апр', 816 | 'Май', 817 | 'Юни', 818 | 'Юли', 819 | 'Авг', 820 | 'Сен', 821 | 'Окт', 822 | 'Ное', 823 | 'Дек' 824 | ], 825 | 'monthLong': [ 826 | 'Януари', 827 | 'Февруари', 828 | 'Март', 829 | 'Април', 830 | 'Май', 831 | 'Юни', 832 | 'Юли', 833 | 'Август', 834 | 'Септември', 835 | 'Октомври', 836 | 'Ноември', 837 | 'Декември' 838 | ], 839 | 'day': ['Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб', 'Нд'], 840 | 'am': 'AM', 841 | 'pm': 'PM' 842 | }, 843 | 'eu': { 844 | // basque 845 | 'cancel': 'Ezeztau', 846 | 'done': 'Onartu', 847 | 'today': 'Gaur', 848 | 'monthShort': [ 849 | 'urt.', 850 | 'ots.', 851 | 'mar.', 852 | 'api.', 853 | 'mai.', 854 | 'eka.', 855 | 'uzt.', 856 | 'abu.', 857 | 'ira.', 858 | 'urr.', 859 | 'aza.', 860 | 'abe.' 861 | ], 862 | 'monthLong': [ 863 | 'urtarrila', 864 | 'otsaila', 865 | 'martxoa', 866 | 'apirila', 867 | 'maiatza', 868 | 'ekaina', 869 | 'uztaila', 870 | 'abuztua', 871 | 'iraila', 872 | 'urria', 873 | 'azaroa', 874 | 'abendua' 875 | ], 876 | 'day': ['al.', 'ar.', 'az.', 'og.', 'or.', 'lr.', 'ig.'], 877 | 'am': 'AM', 878 | 'pm': 'PM' 879 | }, 880 | 'cat': { 881 | // catalan 882 | 'cancel': 'Cancel·la', 883 | 'done': 'Confirmar', 884 | 'today': 'Avui', 885 | 'monthShort': [ 886 | 'Gen', 887 | 'Febr', 888 | 'Març', 889 | 'Abr', 890 | 'Maig', 891 | 'Juny', 892 | 'Jul', 893 | 'Ag', 894 | 'Set', 895 | 'Oct', 896 | 'Nov', 897 | 'Des' 898 | ], 899 | 'monthLong': [ 900 | 'Gener', 901 | 'Febrer', 902 | 'Març', 903 | 'Abril', 904 | 'Maig', 905 | 'Juny', 906 | 'Juliol', 907 | 'Agost', 908 | 'Setembre', 909 | 'Octubre', 910 | 'Novembre', 911 | 'Decembre' 912 | ], 913 | 'day': ['Dl', 'Dt', 'Dc', 'Dj', 'Dv', 'Ds', 'Dg'], 914 | 'am': 'AM', 915 | 'pm': 'PM' 916 | }, 917 | 'th': { 918 | //thai 919 | 'cancel': 'ยกเลิก', 920 | 'done': 'ตกลง', 921 | 'today': 'วันนี้', 922 | 'monthShort': [ 923 | 'ม.ค', 924 | 'ก.พ', 925 | 'มี.ค', 926 | 'เม.ย', 927 | 'พ.ค', 928 | 'มิ.ย', 929 | 'ก.ค', 930 | 'ส.ค', 931 | 'ก.ย', 932 | 'ต.ค', 933 | 'พ.ย', 934 | 'ธ.ค' 935 | ], 936 | 'monthLong': [ 937 | 'มกราคม', 938 | 'กุมภาพันธ์', 939 | 'มีนาคม', 940 | 'เมษายน', 941 | 'พฤษภาคม', 942 | 'มิถุนายน', 943 | 'กรกฎาคม', 944 | 'สิงหาคม', 945 | 'กันยายน', 946 | 'ตุลาคม', 947 | 'พฤศจิกายน', 948 | 'ธันวาคม' 949 | ], 950 | 'day': ['จ.', 'อ.', 'พ.', 'พฤ.', 'ศ.', 'ส.', 'อา.'], 951 | 'am': 'AM', 952 | 'pm': 'PM' 953 | }, 954 | 'si': { 955 | //Slovenian 956 | 'cancel': 'Prekliči', 957 | 'done': 'V redu', 958 | 'today': 'Danes', 959 | 'monthShort': [ 960 | 'jan', 961 | 'feb', 962 | 'mar', 963 | 'apr', 964 | 'maj', 965 | 'jun', 966 | 'jul', 967 | 'avg', 968 | 'sep', 969 | 'okt', 970 | 'nov', 971 | 'dec' 972 | ], 973 | 'monthLong': [ 974 | 'januar', 975 | 'februar', 976 | 'marec', 977 | 'april', 978 | 'maj', 979 | 'junij', 980 | 'julij', 981 | 'avgust', 982 | 'september', 983 | 'oktober', 984 | 'november', 985 | 'december' 986 | ], 987 | 'day': ['pon', 'tor', 'sre', 'čet', 'pet', 'sob', 'ned'], 988 | 'am': '', 989 | 'pm': '' 990 | }, 991 | 'no': { 992 | 'cancel': 'Avbryt', 993 | 'done': 'Ferdig', 994 | 'today': 'Idag', 995 | 'monthShort': [ 996 | 'Jan', 997 | 'Feb', 998 | 'Mar', 999 | 'Apr', 1000 | 'Mai', 1001 | 'Jun', 1002 | 'Jul', 1003 | 'Aug', 1004 | 'Sep', 1005 | 'Okt', 1006 | 'Nov', 1007 | 'Des' 1008 | ], 1009 | 'monthLong': [ 1010 | 'Januar', 1011 | 'Februar', 1012 | 'Mars', 1013 | 'April', 1014 | 'Mai', 1015 | 'Juni', 1016 | 'Juli', 1017 | 'August', 1018 | 'September', 1019 | 'Oktober', 1020 | 'November', 1021 | 'Desember' 1022 | ], 1023 | 'day': ['Man', 'Tir', 'Ons', 'Tor', 'Fre', 'Lør', 'Søn'], 1024 | 'am': '', 1025 | 'pm': '' 1026 | }, 1027 | }; 1028 | //get international object 1029 | Map i18nObjInLocale(LocaleType type) { 1030 | switch (type) { 1031 | case LocaleType.fa: 1032 | return _i18nModel['fa']; 1033 | case LocaleType.zh: 1034 | return _i18nModel['zh']; 1035 | case LocaleType.nl: 1036 | return _i18nModel['nl']; 1037 | case LocaleType.ru: 1038 | return _i18nModel['ru']; 1039 | case LocaleType.it: 1040 | return _i18nModel['it']; 1041 | case LocaleType.fr: 1042 | return _i18nModel['fr']; 1043 | case LocaleType.es: 1044 | return _i18nModel['es']; 1045 | case LocaleType.pl: 1046 | return _i18nModel['pl']; 1047 | case LocaleType.pt: 1048 | return _i18nModel['pt']; 1049 | case LocaleType.ko: 1050 | return _i18nModel['ko']; 1051 | case LocaleType.kk: 1052 | return _i18nModel['kk']; 1053 | case LocaleType.ar: 1054 | return _i18nModel['ar']; 1055 | case LocaleType.tr: 1056 | return _i18nModel['tr']; 1057 | case LocaleType.az: 1058 | return _i18nModel['az']; 1059 | case LocaleType.jp: 1060 | return _i18nModel['jp']; 1061 | case LocaleType.de: 1062 | return _i18nModel['de']; 1063 | case LocaleType.da: 1064 | return _i18nModel['da']; 1065 | case LocaleType.mn: 1066 | return _i18nModel['mn']; 1067 | case LocaleType.bn: 1068 | return _i18nModel['bn']; 1069 | case LocaleType.vi: 1070 | return _i18nModel['vi']; 1071 | case LocaleType.hy: 1072 | return _i18nModel['hy']; 1073 | case LocaleType.id: 1074 | return _i18nModel['id']; 1075 | case LocaleType.bg: 1076 | return _i18nModel['bg']; 1077 | case LocaleType.eu: 1078 | return _i18nModel['eu']; 1079 | case LocaleType.cat: 1080 | return _i18nModel['cat']; 1081 | case LocaleType.th: 1082 | return _i18nModel['th']; 1083 | case LocaleType.si: 1084 | return _i18nModel['si']; 1085 | case LocaleType.no: 1086 | return _i18nModel['no']; 1087 | default: 1088 | return _i18nModel['en']; 1089 | } 1090 | } 1091 | --------------------------------------------------------------------------------