├── .gitignore
├── .idea
├── vcs.xml
└── workspace.xml
├── .metadata
├── CHANGELOG.md
├── LICENSE
├── README.md
├── android
├── app
│ └── src
│ │ └── main
│ │ └── java
│ │ └── io
│ │ └── flutter
│ │ └── plugins
│ │ └── GeneratedPluginRegistrant.java
├── gradle
│ └── wrapper
│ │ └── gradle-wrapper.properties
├── local.properties
└── src
│ └── main
│ └── kotlin
│ └── com
│ └── benzneststudios
│ └── flutter_rounded_date_picker
│ └── FlutterRoundedDatePickerPlugin.kt
├── example
├── .gitignore
├── .metadata
├── README.md
├── android
│ ├── .gitignore
│ ├── app
│ │ ├── build.gradle
│ │ └── src
│ │ │ ├── debug
│ │ │ └── AndroidManifest.xml
│ │ │ ├── main
│ │ │ ├── AndroidManifest.xml
│ │ │ ├── java
│ │ │ │ └── com
│ │ │ │ │ └── benzneststudios
│ │ │ │ │ └── flutter_rounded_date_picker_example
│ │ │ │ │ └── MainActivity.java
│ │ │ └── res
│ │ │ │ ├── drawable-v21
│ │ │ │ └── launch_background.xml
│ │ │ │ ├── drawable
│ │ │ │ ├── launch_background.xml
│ │ │ │ └── normal_background.xml
│ │ │ │ ├── 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-night
│ │ │ │ └── styles.xml
│ │ │ │ └── values
│ │ │ │ ├── strings.xml
│ │ │ │ └── styles.xml
│ │ │ └── profile
│ │ │ └── AndroidManifest.xml
│ ├── build.gradle
│ ├── gradle.properties
│ ├── gradle
│ │ └── wrapper
│ │ │ └── gradle-wrapper.properties
│ └── settings.gradle
├── assets
│ ├── fonts
│ │ ├── Mali-Bold.ttf
│ │ └── Mali-Regular.ttf
│ └── images
│ │ ├── calendar_header.jpg
│ │ └── calendar_header_rainy.jpg
├── ios
│ ├── .gitignore
│ ├── Flutter
│ │ ├── AppFrameworkInfo.plist
│ │ ├── Debug.xcconfig
│ │ ├── Flutter.podspec
│ │ ├── Release.xcconfig
│ │ └── flutter_export_environment.sh
│ ├── Podfile
│ ├── Podfile.lock
│ ├── Runner.xcodeproj
│ │ ├── project.pbxproj
│ │ ├── project.xcworkspace
│ │ │ ├── contents.xcworkspacedata
│ │ │ └── xcshareddata
│ │ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ │ └── WorkspaceSettings.xcsettings
│ │ └── xcshareddata
│ │ │ └── xcschemes
│ │ │ └── Runner.xcscheme
│ ├── Runner.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── WorkspaceSettings.xcsettings
│ └── Runner
│ │ ├── AppDelegate.swift
│ │ ├── Assets.xcassets
│ │ ├── AppIcon.appiconset
│ │ │ ├── Contents.json
│ │ │ ├── Icon-App-1024x1024@1x.png
│ │ │ ├── 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-83.5x83.5@2x.png
│ │ └── LaunchImage.imageset
│ │ │ ├── Contents.json
│ │ │ ├── LaunchImage.png
│ │ │ ├── LaunchImage@2x.png
│ │ │ ├── LaunchImage@3x.png
│ │ │ └── README.md
│ │ ├── Base.lproj
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ │ ├── Info.plist
│ │ └── Runner-Bridging-Header.h
├── lib
│ ├── home.dart
│ └── main.dart
├── pubspec.yaml
├── test
│ └── widget_test.dart
├── web
│ ├── favicon.png
│ ├── icons
│ │ ├── Icon-192.png
│ │ └── Icon-512.png
│ ├── index.html
│ └── manifest.json
└── windows
│ ├── .gitignore
│ ├── CMakeLists.txt
│ ├── flutter
│ ├── CMakeLists.txt
│ ├── generated_plugin_registrant.cc
│ ├── generated_plugin_registrant.h
│ └── generated_plugins.cmake
│ └── runner
│ ├── CMakeLists.txt
│ ├── Runner.rc
│ ├── flutter_window.cpp
│ ├── flutter_window.h
│ ├── main.cpp
│ ├── resource.h
│ ├── resources
│ └── app_icon.ico
│ ├── run_loop.cpp
│ ├── run_loop.h
│ ├── runner.exe.manifest
│ ├── utils.cpp
│ ├── utils.h
│ ├── win32_window.cpp
│ └── win32_window.h
├── lib
├── flutter_rounded_date_picker.dart
└── src
│ ├── cupertino_rounded_date_picker.dart
│ ├── cupertino_rounded_duration_picker.dart
│ ├── dialogs
│ └── flutter_rounded_date_picker_dialog.dart
│ ├── era_mode.dart
│ ├── flutter_cupertino_rounded_date_picker_widget.dart
│ ├── flutter_rounded_button_action.dart
│ ├── flutter_rounded_date_picker_widget.dart
│ ├── flutter_rounded_time_picker_widget.dart
│ ├── material_rounded_date_picker_custom_Action_design_style.dart
│ ├── material_rounded_date_picker_style.dart
│ ├── material_rounded_year_picker_style.dart
│ ├── thai_date_utils.dart
│ └── widgets
│ ├── flutter_rounded_date_picker_header.dart
│ ├── flutter_rounded_day_picker.dart
│ ├── flutter_rounded_month_picker.dart
│ └── flutter_rounded_year_picker.dart
├── pubspec.yaml
└── screenshots
├── 1.png
├── 10.png
├── 11.png
├── 12.png
├── 13.png
├── 14.png
├── 15.png
├── 16.png
├── 17.png
├── 18.png
├── 19.png
├── 2.png
├── 20.png
├── 21.png
├── 22.png
├── 23.png
├── 24.png
├── 3.png
├── 4.png
├── 5.png
├── 6.png
├── 7.png
├── 8.png
├── 9.png
├── a1.gif
├── a2.gif
├── a3.gif
├── a4.gif
├── a5.gif
└── a6.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .dart_tool/
3 |
4 | .packages
5 | .pub/
6 |
7 | build/
8 | pubspec.lock
9 | .idea/
10 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
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 |
39 |
40 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | 1566887686516
100 |
101 |
102 | 1566887686516
103 |
104 |
105 | 1566910822276
106 |
107 |
108 |
109 | 1566910822276
110 |
111 |
112 | 1566912004554
113 |
114 |
115 |
116 | 1566912004554
117 |
118 |
119 | 1566912039491
120 |
121 |
122 |
123 | 1566912039491
124 |
125 |
126 | 1566912862137
127 |
128 |
129 |
130 | 1566912862137
131 |
132 |
133 | 1566913178345
134 |
135 |
136 |
137 | 1566913178345
138 |
139 |
140 | 1566913569297
141 |
142 |
143 |
144 | 1566913569297
145 |
146 |
147 | 1566913694823
148 |
149 |
150 |
151 | 1566913694823
152 |
153 |
154 | 1566913747334
155 |
156 |
157 |
158 | 1566913747334
159 |
160 |
161 | 1566973538134
162 |
163 |
164 |
165 | 1566973538134
166 |
167 |
168 | 1566974122907
169 |
170 |
171 |
172 | 1566974122907
173 |
174 |
175 | 1581682844904
176 |
177 |
178 |
179 | 1581682844904
180 |
181 |
182 | 1581909446290
183 |
184 |
185 |
186 | 1581909446290
187 |
188 |
189 | 1581911082354
190 |
191 |
192 |
193 | 1581911082354
194 |
195 |
196 | 1582027966028
197 |
198 |
199 |
200 | 1582027966028
201 |
202 |
203 | 1582028094505
204 |
205 |
206 |
207 | 1582028094505
208 |
209 |
210 | 1582028376205
211 |
212 |
213 |
214 | 1582028376205
215 |
216 |
217 | 1582028623398
218 |
219 |
220 |
221 | 1582028623398
222 |
223 |
224 | 1615673321672
225 |
226 |
227 |
228 | 1615673321672
229 |
230 |
231 | 1615673503906
232 |
233 |
234 |
235 | 1615673503907
236 |
237 |
238 | 1619948878123
239 |
240 |
241 |
242 | 1619948878124
243 |
244 |
245 | 1653899126569
246 |
247 |
248 |
249 | 1653899126569
250 |
251 |
252 |
253 |
254 |
255 |
256 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
--------------------------------------------------------------------------------
/.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: 2fefa8c7315c32191aa10ef0ef03afb565e99701
8 | channel: master
9 |
10 | project_type: plugin
11 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | ## 3.04
3 | * Fixed bug textStyleDayButton display.
4 |
5 | ## 3.0.3
6 | * Fixed Error: The getter 'accentTextTheme' isn't defined for the class 'ThemeData'.
7 |
8 | ## 3.0.2
9 | * Fixed warning Flutter 3.3
10 |
11 | ## 3.0.1
12 | * Fixed dragable Cupertino date picker.
13 | * Fixed warning Flutter 3.0.
14 |
15 | ## 3.0.0
16 | * Fixed SchedulerBinding.instance with nullable change.
17 |
18 | ## 2.0.2
19 | * add backgroundHeaderMonth field in MaterialRoundedDatePickerStyle
20 |
21 | ## 2.0.1
22 | * Fix bug about "cancel button doesn't return null". (issues/37).
23 | * Fix error example project.
24 |
25 | ## 2.0.0
26 | * Migrate to null safety (Thx @felixgabler)
27 |
28 | ## 1.0.5+1
29 | * Fix bug
30 |
31 | ## 1.0.5
32 | * add height field for fix height of date picker.
33 | * fix bugs disable date still be selected.
34 |
35 | ## 1.0.4
36 | * fix error when select date that before first date / last date.
37 |
38 | ## 1.0.3
39 | * Fix bug era.
40 |
41 | ## 1.0.2
42 | * Fix bug era.
43 |
44 | ## 1.0.1
45 | * Fix bug era.
46 |
47 | ## 1.0.0
48 | * Add custom style and builder for date picker on tablet.
49 |
50 | ## 0.3.0
51 |
52 | * Add possibility to have a custom button on left.
53 | * Add Android style time picker.
54 | * Some code improvements.
55 |
56 | ## 0.2.0
57 |
58 | * Support cupertino date time picker.
59 | * Support cupertino duration picker.
60 |
61 | ## 0.1.0
62 |
63 | * Support border radius date picker.
64 | * Support thai buddhist year.
65 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
2 |
3 | http://www.apache.org/licenses/LICENSE-2.0
4 |
5 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Flutter Rounded Date Picker
2 |
3 | The Flutter plugin that help you can choose dates and years with rounded calendars and customizable themes.
4 |
5 | 
6 | 
7 | 
8 | 
9 |
10 | ## Installing
11 |
12 | Add dependencies in pubspec.yaml file. Add 2 things in it including flutter_localizations
13 |
14 | ```dart
15 | dependencies:
16 | flutter_localizations:
17 | sdk: flutter
18 | flutter_rounded_date_picker: 3.0.2
19 | ```
20 |
21 | ## Importing
22 |
23 | import packages into your dart.
24 |
25 | ```dart
26 | import 'package:flutter_localizations/flutter_localizations.dart';
27 | import 'package:flutter_rounded_date_picker/rounded_picker.dart';
28 | ```
29 |
30 | ## Initialize localizations
31 |
32 | Add localization delegates in MaterialApp Widget and add languages that your app supports.
33 |
34 | ```dart
35 | MaterialApp(
36 | localizationsDelegates: [
37 | GlobalMaterialLocalizations.delegate,
38 | GlobalWidgetsLocalizations.delegate,
39 | ],
40 | supportedLocales: [
41 | const Locale('en', 'US'), // English
42 | const Locale('th', 'TH'), // Thai
43 | ],
44 | ...
45 | )
46 | ```
47 |
48 | ## Show Date Picker
49 |
50 | Show date picker which you can specify a date that allows users to choose.
51 |
52 | ```dart
53 | DateTime newDateTime = await showRoundedDatePicker(
54 | context: context,
55 | initialDate: DateTime.now(),
56 | firstDate: DateTime(DateTime.now().year - 1),
57 | lastDate: DateTime(DateTime.now().year + 1),
58 | borderRadius: 16,
59 | ),
60 | ```
61 |
62 | 
63 | 
64 |
65 | ## Show Year Picker
66 |
67 | Show year picker which you can specify a year start and end that allows users to choose.
68 |
69 | ```dart
70 | DateTime newDateTime = await showRoundedDatePicker(
71 | context: context,
72 | initialDatePickerMode: DatePickerMode.year,
73 | theme: ThemeData(primarySwatch: Colors.green),
74 | );
75 | ```
76 |
77 | 
78 |
79 | ## Theme
80 |
81 | You can assign themes to the date picker by using ThemeData class and PrimarySwatch.
82 |
83 | ```dart
84 | DateTime newDateTime = await showRoundedDatePicker(
85 | context: context,
86 | theme: ThemeData(primarySwatch: Colors.pink),
87 | );
88 | ```
89 |
90 | 
91 |
92 | Dark theme
93 |
94 | ```dart
95 | DateTime newDateTime = await showRoundedDatePicker(
96 | context: context,
97 | theme: ThemeData.dark(),
98 | );
99 | ```
100 |
101 | 
102 |
103 | Custom Theme with ThemeData
104 |
105 | ```dart
106 | DateTime newDateTime = await showRoundedDatePicker(
107 | context: context,
108 | background: Colors.white,
109 | theme: ThemeData(
110 | primaryColor: Colors.red[400],
111 | accentColor: Colors.green[800],
112 | dialogBackgroundColor: Colors.purple[50],
113 | textTheme: TextTheme(
114 | body1: TextStyle(color: Colors.red),
115 | caption: TextStyle(color: Colors.blue),
116 | ),
117 | disabledColor: Colors.orange,
118 | accentTextTheme: TextTheme(
119 | body2 : TextStyle(color: Colors.green[200]),
120 | ),
121 | ),
122 | );
123 | ```
124 |
125 | 
126 |
127 |
128 | ## Customize Date Picker
129 |
130 | You can use styleDatePicker field for date picker style such as font size, weight, text color each part in the date picker.
131 |
132 | Example custom font size and padding for displaying on a Tablet. (Pixel C, iPad 9.7")
133 | ```dart
134 | DateTime newDateTime = await showRoundedDatePicker(
135 | context: context,
136 | theme: ThemeData(primarySwatch: Colors.deepPurple),
137 | styleDatePicker: MaterialRoundedDatePickerStyle(
138 | textStyleDayButton: TextStyle(fontSize: 36, color: Colors.white),
139 | textStyleYearButton: TextStyle(
140 | fontSize: 52,
141 | color: Colors.white,
142 | ),
143 | textStyleDayHeader: TextStyle(
144 | fontSize: 24,
145 | color: Colors.white,
146 | ),
147 | textStyleCurrentDayOnCalendar:
148 | TextStyle(fontSize: 32, color: Colors.white, fontWeight: FontWeight.bold),
149 | textStyleDayOnCalendar: TextStyle(fontSize: 28, color: Colors.white),
150 | textStyleDayOnCalendarSelected:
151 | TextStyle(fontSize: 32, color: Colors.white, fontWeight: FontWeight.bold),
152 | textStyleDayOnCalendarDisabled: TextStyle(fontSize: 28, color: Colors.white.withOpacity(0.1)),
153 | textStyleMonthYearHeader:
154 | TextStyle(fontSize: 32, color: Colors.white, fontWeight: FontWeight.bold),
155 | paddingDatePicker: EdgeInsets.all(0),
156 | paddingMonthHeader: EdgeInsets.all(32),
157 | paddingActionBar: EdgeInsets.all(16),
158 | paddingDateYearHeader: EdgeInsets.all(32),
159 | sizeArrow: 50,
160 | colorArrowNext: Colors.white,
161 | colorArrowPrevious: Colors.white,
162 | marginLeftArrowPrevious: 16,
163 | marginTopArrowPrevious: 16,
164 | marginTopArrowNext: 16,
165 | marginRightArrowNext: 32,
166 | textStyleButtonAction: TextStyle(fontSize: 28, color: Colors.white),
167 | textStyleButtonPositive:
168 | TextStyle(fontSize: 28, color: Colors.white, fontWeight: FontWeight.bold),
169 | textStyleButtonNegative: TextStyle(fontSize: 28, color: Colors.white.withOpacity(0.5)),
170 | decorationDateSelected: BoxDecoration(color: Colors.orange[600], shape: BoxShape.circle),
171 | backgroundPicker: Colors.deepPurple[400],
172 | backgroundActionBar: Colors.deepPurple[300],
173 | backgroundHeaderMonth: Colors.deepPurple[300],
174 | ),
175 | styleYearPicker: MaterialRoundedYearPickerStyle(
176 | textStyleYear: TextStyle(fontSize: 40, color: Colors.white),
177 | textStyleYearSelected:
178 | TextStyle(fontSize: 56, color: Colors.white, fontWeight: FontWeight.bold),
179 | heightYearRow: 100,
180 | backgroundPicker: Colors.deepPurple[400],
181 | ));
182 | ```
183 |
184 | 
185 |
186 | 
187 |
188 | 
189 |
190 | ### Custom action button and text on button.
191 |
192 | Added the action button and the button's custom text.
193 |
194 | ```dart
195 | DateTime newDateTime = await showRoundedDatePicker(
196 | ...
197 | textActionButton: "ACTION",
198 | onTapActionButton: (){
199 | //
200 | },
201 | textPositiveButton: "OK",
202 | textNegativeButton: "CANCEL");
203 | ```
204 |
205 | 
206 |
207 | ### Custom weekday header text.
208 |
209 | Customize the header of the weekday.
210 |
211 | ```dart
212 | DateTime newDateTime = await showRoundedDatePicker(
213 | ...
214 | customWeekDays: ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"]);
215 | ```
216 |
217 | 
218 |
219 | ### Custom disabled date.
220 |
221 | Add closed date cannot be selected.
222 |
223 | ```dart
224 | DateTime newDateTime = await showRoundedDatePicker(
225 | ...
226 | listDateDisabled: [
227 | DateTime.now().subtract(Duration(days: 2)),
228 | DateTime.now().subtract(Duration(days: 4)),
229 | DateTime.now().subtract(Duration(days: 6)),
230 | DateTime.now().subtract(Duration(days: 8)),
231 | DateTime.now().subtract(Duration(days: 10)),
232 | DateTime.now().add(Duration(days: 2)),
233 | DateTime.now().add(Duration(days: 4)),
234 | DateTime.now().add(Duration(days: 6)),
235 | DateTime.now().add(Duration(days: 8)),
236 | DateTime.now().add(Duration(days: 10)),
237 | ]);
238 | ```
239 |
240 | 
241 |
242 | ### Custom callback on tap day.
243 |
244 | Add callback when tap on day.
245 |
246 | ```dart
247 | DateTime newDateTime = await showRoundedDatePicker(
248 | ...
249 | onTapDay: (DateTime dateTime, bool available) {
250 | if (!available) {
251 | showDialog(
252 | context: context,
253 | builder: (c) => CupertinoAlertDialog(title: Text("This date cannot be selected."),actions: [
254 | CupertinoDialogAction(child: Text("OK"),onPressed: (){
255 | Navigator.pop(context);
256 | },)
257 | ],));
258 | }
259 | return available;
260 | });
261 | ```
262 |
263 | 
264 |
265 | ### Custom builder day on date picker.
266 |
267 | Customize the display format of the day widget.
268 |
269 | ```dart
270 | DateTime newDateTime = await showRoundedDatePicker(
271 | ...
272 | builderDay:
273 | (DateTime dateTime, bool isCurrentDay, bool isSelected, TextStyle defaultTextStyle) {
274 | if (isSelected) {
275 | return Container(
276 | decoration: BoxDecoration(color: Colors.orange[600], shape: BoxShape.circle),
277 | child: Center(
278 | child: Text(
279 | dateTime.day.toString(),
280 | style: defaultTextStyle,
281 | ),
282 | ),
283 | );
284 | }
285 |
286 | if (dateTime.day == 10) {
287 | return Container(
288 | decoration: BoxDecoration(
289 | border: Border.all(color: Colors.pink[300], width: 4), shape: BoxShape.circle),
290 | child: Center(
291 | child: Text(
292 | dateTime.day.toString(),
293 | style: defaultTextStyle,
294 | ),
295 | ),
296 | );
297 | }
298 | if (dateTime.day == 12) {
299 | return Container(
300 | decoration: BoxDecoration(
301 | border: Border.all(color: Colors.pink[300], width: 4), shape: BoxShape.circle),
302 | child: Center(
303 | child: Text(
304 | dateTime.day.toString(),
305 | style: defaultTextStyle,
306 | ),
307 | ),
308 | );
309 | }
310 |
311 | return Container(
312 | child: Center(
313 | child: Text(
314 | dateTime.day.toString(),
315 | style: defaultTextStyle,
316 | ),
317 | ),
318 | );
319 | });
320 | ```
321 |
322 | 
323 |
324 | ## Image Background Header
325 |
326 | Use images as the header of the date picker and you can also add more details.
327 |
328 | * You need to specify the path of images in your asset (pubspec.yaml).
329 |
330 | ```dart
331 | DateTime newDateTime = await showRoundedDatePicker(
332 | context: context,
333 | theme: ThemeData(primarySwatch: Colors.blue),
334 | imageHeader: AssetImage("assets/images/calendar_header.jpg"),
335 | description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
336 | );
337 | ```
338 |
339 | 
340 |
341 | ## Customize Font in Date Picker
342 |
343 | You can adjust the Font-family in the date picker.
344 |
345 | * You need to specify the path of font in your fonts (pubspec.yaml).
346 |
347 | ```dart
348 | DateTime newDateTime = await showRoundedDatePicker(
349 | context: context,
350 | fontFamily: "Mali"
351 | );
352 | ```
353 |
354 | 
355 |
356 | ## Date Picker Locale
357 |
358 | You can set the date picker locale. By specifying the language code and country code.
359 | As of April 2019, this package supports about 52 languages.
360 |
361 | ```dart
362 | DateTime newDateTime = await showRoundedDatePicker(
363 | context: context,
364 | locale: Locale("zh","CN"),
365 | theme: ThemeData(primarySwatch: Colors.pink),
366 | );
367 | ```
368 |
369 | 
370 |
371 | ## Thai and Buddhist Year
372 |
373 | If you are using Thai language And use the Buddhist era (543 BCE). Plugins that support these capabilities.
374 |
375 | ```dart
376 | DateTime newDateTime = await showRoundedDatePicker(
377 | context: context,
378 | locale: Locale("th", "TH"),
379 | era: EraMode.BUDDHIST_YEAR,
380 | );
381 | ```
382 |
383 | 
384 |
385 | ## Show Time Picker
386 |
387 | Show time picker, all feature of date picker is available (except description)
388 |
389 | ```dart
390 | final timePicked = await showRoundedTimePicker(
391 | context: context,
392 | initialTime: TimeOfDay.now(),
393 | );
394 | ```
395 |
396 | 
397 |
398 | # Cupertino Date Picker
399 |
400 | Show date and duration picker iOS style.
401 |
402 | ## Installing
403 |
404 | Add Flutter Cupertino Localizations in dependencies pub.yaml.
405 |
406 | ```yaml
407 | dependencies:
408 | flutter:
409 | sdk: flutter
410 | flutter_localizations:
411 | sdk: flutter
412 | flutter_cupertino_localizations: 1.0.1
413 | ```
414 |
415 | ## Initialize localizations
416 |
417 | Add CupertinoLocalizations delegate to localizations delegate on your App.
418 | The cupertino date picker will use current app locale in picker.
419 |
420 | ```dart
421 | MaterialApp(
422 | debugShowCheckedModeBanner: false,
423 | localizationsDelegates: [
424 | GlobalMaterialLocalizations.delegate,
425 | GlobalWidgetsLocalizations.delegate,
426 | DefaultCupertinoLocalizations.delegate,
427 | GlobalCupertinoLocalizations.delegate, // Add global cupertino localiztions.
428 | ],
429 | locale: Locale('en', 'US'), // Current locale
430 | supportedLocales: [
431 | const Locale('en', 'US'), // English
432 | const Locale('th', 'TH'), // Thai
433 | ],
434 | )
435 | ```
436 |
437 | ## Show Cupertino Date Picker
438 |
439 | Call the method for displaying date picker.
440 | The callback date time instance will be return with onDateTimeChange.
441 |
442 | ```dart
443 | CupertinoRoundedDatePicker.show(
444 | context,
445 | fontFamily: "Mali",
446 | textColor: Colors.white,
447 | background: Colors.red[300],
448 | borderRadius: 16,
449 | initialDatePickerMode: CupertinoDatePickerMode.date,
450 | onDateTimeChanged: (newDateTime) {
451 | //
452 | },
453 | );
454 | ```
455 |
456 | 
457 |
458 | More Cupertino Date Picker Mode
459 |
460 | ```dart
461 | CupertinoDatePickerMode.date
462 | CupertinoDatePickerMode.dateAndTime
463 | CupertinoDatePickerMode.time
464 | ```
465 |
466 | 
467 | 
468 |
469 | using Thai and Buddhist Year
470 |
471 | ```dart
472 | /// Current locale is TH.
473 | CupertinoRoundedDatePicker.show(
474 | context,
475 | fontFamily: "Mali",
476 | textColor: Colors.white,
477 | era: EraMode.BUDDHIST_YEAR,
478 | background: Colors.red[300],
479 | borderRadius: 16,
480 | initialDatePickerMode: CupertinoDatePickerMode.date,
481 | onDateTimeChanged: (newDateTime) {
482 | //
483 | },
484 | );
485 | ```
486 |
487 | 
488 |
489 | ## Cupertino Duration Picker
490 |
491 | in iOS , Flutter cupertino support duration and timer picker.
492 |
493 | ```dart
494 | CupertinoRoundedDurationPicker.show(
495 | context,
496 | initialTimerDuration: Duration(minute:10),
497 | initialDurationPickerMode: CupertinoTimerPickerMode.hms,
498 | fontFamily: "Mali",
499 | onDurationChanged: (newDuration) {
500 | //
501 | },
502 | );
503 | ```
504 |
505 | 
506 |
507 | More Cupertino Duration Picker Mode
508 |
509 | ```dart
510 | CupertinoTimerPickerMode.hms
511 | CupertinoTimerPickerMode.hm
512 | CupertinoTimerPickerMode.ms
513 | ```
514 |
515 | 
516 | 
517 |
518 | ## Thanks
519 | [felixgabler](https://github.com/felixgabler)
520 |
--------------------------------------------------------------------------------
/android/app/src/main/java/io/flutter/plugins/GeneratedPluginRegistrant.java:
--------------------------------------------------------------------------------
1 | package io.flutter.plugins;
2 |
3 | import io.flutter.plugin.common.PluginRegistry;
4 |
5 | /**
6 | * Generated file. Do not edit.
7 | */
8 | public final class GeneratedPluginRegistrant {
9 | public static void registerWith(PluginRegistry registry) {
10 | if (alreadyRegisteredWith(registry)) {
11 | return;
12 | }
13 | }
14 |
15 | private static boolean alreadyRegisteredWith(PluginRegistry registry) {
16 | final String key = GeneratedPluginRegistrant.class.getCanonicalName();
17 | if (registry.hasPlugin(key)) {
18 | return true;
19 | }
20 | registry.registrarFor(key);
21 | return false;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | zipStoreBase=GRADLE_USER_HOME
4 | zipStorePath=wrapper/dists
5 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.6.1-all.zip
--------------------------------------------------------------------------------
/android/local.properties:
--------------------------------------------------------------------------------
1 | sdk.dir=C:\\Users\\User\\AppData\\Local\\Android\\sdk
2 | flutter.sdk=C:\\flutter\\flutter
--------------------------------------------------------------------------------
/android/src/main/kotlin/com/benzneststudios/flutter_rounded_date_picker/FlutterRoundedDatePickerPlugin.kt:
--------------------------------------------------------------------------------
1 | package com.benzneststudios.flutter_rounded_date_picker
2 |
3 | import io.flutter.plugin.common.MethodCall
4 | import io.flutter.plugin.common.MethodChannel
5 | import io.flutter.plugin.common.MethodChannel.MethodCallHandler
6 | import io.flutter.plugin.common.MethodChannel.Result
7 | import io.flutter.plugin.common.PluginRegistry.Registrar
8 |
9 | class FlutterRoundedDatePickerPlugin: MethodCallHandler {
10 | companion object {
11 | @JvmStatic
12 | fun registerWith(registrar: Registrar) {
13 | val channel = MethodChannel(registrar.messenger(), "flutter_rounded_date_picker")
14 | channel.setMethodCallHandler(FlutterRoundedDatePickerPlugin())
15 | }
16 | }
17 |
18 | override fun onMethodCall(call: MethodCall, result: Result) {
19 | if (call.method == "getPlatformVersion") {
20 | result.success("Android ${android.os.Build.VERSION.RELEASE}")
21 | } else {
22 | result.notImplemented()
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/example/.gitignore:
--------------------------------------------------------------------------------
1 | # Miscellaneous
2 | *.class
3 | *.log
4 | *.pyc
5 | *.swp
6 | .DS_Store
7 | .atom/
8 | .buildlog/
9 | .history
10 | .svn/
11 |
12 | # IntelliJ related
13 | *.iml
14 | *.ipr
15 | *.iws
16 | .idea/
17 |
18 | # The .vscode folder contains launch configuration and tasks you configure in
19 | # VS Code which you may wish to be included in version control, so this line
20 | # is commented out by default.
21 | #.vscode/
22 |
23 | # Flutter/Dart/Pub related
24 | **/doc/api/
25 | .dart_tool/
26 | .flutter-plugins
27 | .packages
28 | .pub-cache/
29 | .pub/
30 | /build/
31 | pubspec.lock
32 |
33 | # Android related
34 | **/android/**/gradle-wrapper.jar
35 | **/android/.gradle
36 | **/android/captures/
37 | **/android/gradlew
38 | **/android/gradlew.bat
39 | **/android/local.properties
40 | **/android/**/GeneratedPluginRegistrant.java
41 |
42 | # iOS/XCode related
43 | **/ios/**/*.mode1v3
44 | **/ios/**/*.mode2v3
45 | **/ios/**/*.moved-aside
46 | **/ios/**/*.pbxuser
47 | **/ios/**/*.perspectivev3
48 | **/ios/**/*sync/
49 | **/ios/**/.sconsign.dblite
50 | **/ios/**/.tags*
51 | **/ios/**/.vagrant/
52 | **/ios/**/DerivedData/
53 | **/ios/**/Icon?
54 | **/ios/**/Pods/
55 | **/ios/**/.symlinks/
56 | **/ios/**/profile
57 | **/ios/**/xcuserdata
58 | **/ios/.generated/
59 | **/ios/Flutter/App.framework
60 | **/ios/Flutter/Flutter.framework
61 | **/ios/Flutter/Generated.xcconfig
62 | **/ios/Flutter/app.flx
63 | **/ios/Flutter/app.zip
64 | **/ios/Flutter/flutter_assets/
65 | **/ios/ServiceDefinitions.json
66 | **/ios/Runner/GeneratedPluginRegistrant.*
67 |
68 | # Exceptions to above rules.
69 | !**/ios/**/default.mode1v3
70 | !**/ios/**/default.mode2v3
71 | !**/ios/**/default.pbxuser
72 | !**/ios/**/default.perspectivev3
73 | !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
74 |
--------------------------------------------------------------------------------
/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: 2fefa8c7315c32191aa10ef0ef03afb565e99701
8 | channel: master
9 |
10 | project_type: app
11 |
--------------------------------------------------------------------------------
/example/README.md:
--------------------------------------------------------------------------------
1 | # flutter_rounded_date_picker_example
2 |
3 | Demonstrates how to use the flutter_rounded_date_picker plugin.
4 |
5 | ## Getting Started
6 |
7 | This project is a starting point for a Flutter application.
8 |
9 | A few resources to get you started if this is your first Flutter project:
10 |
11 | - [Lab: Write your first Flutter app](https://flutter.dev/docs/get-started/codelab)
12 | - [Cookbook: Useful Flutter samples](https://flutter.dev/docs/cookbook)
13 |
14 | For help getting started with Flutter, view our
15 | [online documentation](https://flutter.dev/docs), which offers tutorials,
16 | samples, guidance on mobile development, and a full API reference.
17 |
--------------------------------------------------------------------------------
/example/android/.gitignore:
--------------------------------------------------------------------------------
1 | gradle-wrapper.jar
2 | /.gradle
3 | /captures/
4 | /gradlew
5 | /gradlew.bat
6 | /local.properties
7 | GeneratedPluginRegistrant.java
8 |
9 | # Remember to never publicly share your keystore.
10 | # See https://flutter.dev/docs/deployment/android#reference-the-keystore-from-the-app
11 | key.properties
12 |
--------------------------------------------------------------------------------
/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 33
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.benzneststudios.flutter_rounded_date_picker_example"
37 | minSdkVersion 16
38 | targetSdkVersion 31
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 | implementation 'androidx.appcompat:appcompat:1.1.0'
59 | testImplementation 'junit:junit:4.12'
60 | androidTestImplementation 'androidx.test:runner:1.1.1'
61 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
62 | }
63 |
--------------------------------------------------------------------------------
/example/android/app/src/debug/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
8 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
28 |
31 |
32 |
33 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/example/android/app/src/main/java/com/benzneststudios/flutter_rounded_date_picker_example/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.benzneststudios.flutter_rounded_date_picker_example;
2 |
3 | import android.os.Bundle;
4 |
5 | import io.flutter.embedding.android.FlutterActivity;
6 | import io.flutter.plugins.GeneratedPluginRegistrant;
7 |
8 | public class MainActivity extends FlutterActivity {
9 | @Override
10 | protected void onCreate(Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | GeneratedPluginRegistrant.registerWith(this.getFlutterEngine());
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable-v21/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/launch_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
12 |
13 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/drawable/normal_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values-night/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
9 |
15 |
18 |
19 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/example/android/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
14 |
15 |
--------------------------------------------------------------------------------
/example/android/app/src/profile/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/android/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | ext.kotlin_version = '1.8.21'
3 | repositories {
4 | google()
5 | mavenCentral()
6 | }
7 |
8 | dependencies {
9 | classpath 'com.android.tools.build:gradle:7.2.2'
10 | }
11 | }
12 |
13 | allprojects {
14 | repositories {
15 | google()
16 | jcenter()
17 | }
18 | }
19 |
20 | rootProject.buildDir = '../build'
21 | subprojects {
22 | project.buildDir = "${rootProject.buildDir}/${project.name}"
23 | }
24 | subprojects {
25 | project.evaluationDependsOn(':app')
26 | }
27 |
28 | tasks.register("clean", Delete) {
29 | delete rootProject.buildDir
30 | }
31 |
--------------------------------------------------------------------------------
/example/android/gradle.properties:
--------------------------------------------------------------------------------
1 | org.gradle.jvmargs=-Xmx8192M
2 | android.useAndroidX=true
3 | android.enableJetifier=true
4 | org.gradle.java.home=C:\\Program Files\\Java\\jdk-17.0.7
--------------------------------------------------------------------------------
/example/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Jun 23 08:50:38 CEST 2017
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-7.6.1-all.zip
7 |
--------------------------------------------------------------------------------
/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/assets/fonts/Mali-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/assets/fonts/Mali-Bold.ttf
--------------------------------------------------------------------------------
/example/assets/fonts/Mali-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/assets/fonts/Mali-Regular.ttf
--------------------------------------------------------------------------------
/example/assets/images/calendar_header.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/assets/images/calendar_header.jpg
--------------------------------------------------------------------------------
/example/assets/images/calendar_header_rainy.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/assets/images/calendar_header_rainy.jpg
--------------------------------------------------------------------------------
/example/ios/.gitignore:
--------------------------------------------------------------------------------
1 | *.mode1v3
2 | *.mode2v3
3 | *.moved-aside
4 | *.pbxuser
5 | *.perspectivev3
6 | **/*sync/
7 | .sconsign.dblite
8 | .tags*
9 | **/.vagrant/
10 | **/DerivedData/
11 | Icon?
12 | **/Pods/
13 | **/.symlinks/
14 | profile
15 | xcuserdata
16 | **/.generated/
17 | Flutter/App.framework
18 | Flutter/Flutter.framework
19 | Flutter/Flutter.podspec
20 | Flutter/Generated.xcconfig
21 | Flutter/app.flx
22 | Flutter/app.zip
23 | Flutter/flutter_assets/
24 | Flutter/flutter_export_environment.sh
25 | ServiceDefinitions.json
26 | Runner/GeneratedPluginRegistrant.*
27 |
28 | # Exceptions to above rules.
29 | !default.mode1v3
30 | !default.mode2v3
31 | !default.pbxuser
32 | !default.perspectivev3
33 |
--------------------------------------------------------------------------------
/example/ios/Flutter/AppFrameworkInfo.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
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 | 11.0
25 |
26 |
27 |
--------------------------------------------------------------------------------
/example/ios/Flutter/Debug.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/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/Release.xcconfig:
--------------------------------------------------------------------------------
1 | #include "Pods/Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"
2 | #include "Generated.xcconfig"
3 |
--------------------------------------------------------------------------------
/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=C:\flutter\flutter"
4 | export "FLUTTER_APPLICATION_PATH=C:\Works\flutter_rounded_date_picker\example"
5 | export "COCOAPODS_PARALLEL_CODE_SIGN=true"
6 | export "FLUTTER_TARGET=lib\main.dart"
7 | export "FLUTTER_BUILD_DIR=build"
8 | export "FLUTTER_BUILD_NAME=1.0.0"
9 | export "FLUTTER_BUILD_NUMBER=1"
10 | export "DART_OBFUSCATION=false"
11 | export "TRACK_WIDGET_CREATION=true"
12 | export "TREE_SHAKE_ICONS=false"
13 | export "PACKAGE_CONFIG=.dart_tool/package_config.json"
14 |
--------------------------------------------------------------------------------
/example/ios/Podfile:
--------------------------------------------------------------------------------
1 | # Using a CDN with CocoaPods 1.7.2 or later can save a lot of time on pod installation, but it's experimental rather than the default.
2 | # source 'https://cdn.cocoapods.org/'
3 |
4 | # Uncomment this line to define a global platform for your project
5 | # platform :ios, '11.0'
6 |
7 | # CocoaPods analytics sends network stats synchronously affecting flutter build latency.
8 | ENV['COCOAPODS_DISABLE_STATS'] = 'true'
9 |
10 | project 'Runner', {
11 | 'Debug' => :debug,
12 | 'Profile' => :release,
13 | 'Release' => :release,
14 | }
15 |
16 | def parse_KV_file(file, separator='=')
17 | file_abs_path = File.expand_path(file)
18 | if !File.exists? file_abs_path
19 | return [];
20 | end
21 | pods_ary = []
22 | skip_line_start_symbols = ["#", "/"]
23 | File.foreach(file_abs_path) { |line|
24 | next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
25 | plugin = line.split(pattern=separator)
26 | if plugin.length == 2
27 | podname = plugin[0].strip()
28 | path = plugin[1].strip()
29 | podpath = File.expand_path("#{path}", file_abs_path)
30 | pods_ary.push({:name => podname, :path => podpath});
31 | else
32 | puts "Invalid plugin specification: #{line}"
33 | end
34 | }
35 | return pods_ary
36 | end
37 |
38 | target 'Runner' do
39 | # use_frameworks!
40 |
41 | # Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
42 | # referring to absolute paths on developers' machines.
43 | system('rm -rf .symlinks')
44 | system('mkdir -p .symlinks/plugins')
45 |
46 | # Flutter Pods
47 | generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
48 | if generated_xcode_build_settings.empty?
49 | puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
50 | end
51 | generated_xcode_build_settings.map { |p|
52 | if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
53 | symlink = File.join('.symlinks', 'flutter')
54 | File.symlink(File.dirname(p[:path]), symlink)
55 | pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
56 | end
57 | }
58 |
59 | # Plugin Pods
60 | plugin_pods = parse_KV_file('../.flutter-plugins')
61 | plugin_pods.map { |p|
62 | symlink = File.join('.symlinks', 'plugins', p[:name])
63 | File.symlink(p[:path], symlink)
64 | pod p[:name], :path => File.join(symlink, 'ios')
65 | }
66 | end
67 |
68 | # Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
69 | install! 'cocoapods', :disable_input_output_paths => true
70 |
71 | post_install do |installer|
72 | installer.pods_project.targets.each do |target|
73 | target.build_configurations.each do |config|
74 | config.build_settings['ENABLE_BITCODE'] = 'NO'
75 | end
76 | end
77 | end
78 |
--------------------------------------------------------------------------------
/example/ios/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODFILE CHECKSUM: f8a865fed7e2ee0932de729c80580184ca4935e1
2 |
3 | COCOAPODS: 1.11.2
4 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreviewsEnabled
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/example/ios/Runner/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | import UIKit
2 | import Flutter
3 |
4 | @UIApplicationMain
5 | @objc class AppDelegate: FlutterAppDelegate {
6 | override func application(
7 | _ application: UIApplication,
8 | didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
9 | ) -> Bool {
10 | GeneratedPluginRegistrant.register(with: self)
11 | return super.application(application, didFinishLaunchingWithOptions: launchOptions)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/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/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/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/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png
--------------------------------------------------------------------------------
/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/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png
--------------------------------------------------------------------------------
/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png
--------------------------------------------------------------------------------
/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/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/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 |
--------------------------------------------------------------------------------
/example/ios/Runner/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | flutter_rounded_date_picker_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 | CADisableMinimumFrameDurationOnPhone
45 |
46 | UIApplicationSupportsIndirectInputEvents
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/example/ios/Runner/Runner-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | #import "GeneratedPluginRegistrant.h"
--------------------------------------------------------------------------------
/example/lib/main.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_localizations/flutter_localizations.dart';
4 | import 'package:flutter_rounded_date_picker_example/home.dart';
5 |
6 | void main() {
7 | WidgetsFlutterBinding.ensureInitialized();
8 | runApp(MyApp());
9 | }
10 |
11 | class MyApp extends StatefulWidget {
12 | @override
13 | _MyAppState createState() => _MyAppState();
14 | }
15 |
16 | class _MyAppState extends State {
17 |
18 | @override
19 | Widget build(BuildContext context) {
20 | return MaterialApp(
21 | debugShowCheckedModeBanner: false,
22 | localizationsDelegates: [
23 | GlobalMaterialLocalizations.delegate,
24 | GlobalWidgetsLocalizations.delegate,
25 | DefaultCupertinoLocalizations.delegate,
26 | GlobalCupertinoLocalizations.delegate,
27 | ],
28 | locale: Locale('en', 'US'),
29 | supportedLocales: [
30 | const Locale('en', 'US'), // English
31 | const Locale('th', 'TH'), // Thai
32 | ],
33 | home: Home(),
34 | );
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/example/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_rounded_date_picker_example
2 | description: Demonstrates how to use the flutter_rounded_date_picker plugin.
3 | publish_to: 'none'
4 | version: 1.0.0+1
5 |
6 | environment:
7 | sdk: ">=2.12.0 <4.0.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 | flutter_localizations:
13 | sdk: flutter
14 | flutter_rounded_date_picker:
15 | path: ../
16 |
17 | # For information on the generic Dart part of this file, see the
18 | # following page: https://dart.dev/tools/pub/pubspec
19 |
20 | # The following section is specific to Flutter.
21 | flutter:
22 |
23 | # The following line ensures that the Material Icons font is
24 | # included with your application, so that you can use the icons in
25 | # the material Icons class.
26 | uses-material-design: true
27 |
28 | # To add assets to your application, add an assets section, like this:
29 | assets:
30 | - assets/images/
31 | # - images/a_dot_ham.jpeg
32 |
33 | # An image asset can refer to one or more resolution-specific "variants", see
34 | # https://flutter.dev/assets-and-images/#resolution-aware.
35 |
36 | # For details regarding adding assets from package dependencies, see
37 | # https://flutter.dev/assets-and-images/#from-packages
38 |
39 | # To add custom fonts to your application, add a fonts section here,
40 | # in this "flutter" section. Each entry in this list should have a
41 | # "family" key with the font family name, and a "fonts" key with a
42 | # list giving the asset and other descriptors for the font. For
43 | # example:
44 | fonts:
45 | - family: Mali
46 | fonts:
47 | - asset: assets/fonts/Mali-Regular.ttf
48 | # - asset: fonts/Schyler-Italic.ttf
49 | # style: italic
50 | # - family: Trajan Pro
51 | # fonts:
52 | # - asset: fonts/TrajanPro.ttf
53 | # - asset: fonts/TrajanPro_Bold.ttf
54 | # weight: 700
55 | #
56 | # For details regarding fonts from package dependencies,
57 | # see https://flutter.dev/custom-fonts/#from-packages
58 |
--------------------------------------------------------------------------------
/example/test/widget_test.dart:
--------------------------------------------------------------------------------
1 | // // This is a basic Flutter widget test.
2 | // //
3 | // // To perform an interaction with a widget in your test, use the WidgetTester
4 | // // utility that Flutter provides. For example, you can send tap and scroll
5 | // // gestures. You can also use WidgetTester to find child widgets in the widget
6 | // // tree, read text, and verify that the values of widget properties are correct.
7 | //
8 | // import 'package:flutter/material.dart';
9 | // import 'package:flutter_test/flutter_test.dart';
10 | //
11 | // import 'package:example/main.dart';
12 | //
13 | // void main() {
14 | // testWidgets('Counter increments smoke test', (WidgetTester tester) async {
15 | // // Build our app and trigger a frame.
16 | // await tester.pumpWidget(MyApp());
17 | //
18 | // // Verify that our counter starts at 0.
19 | // expect(find.text('0'), findsOneWidget);
20 | // expect(find.text('1'), findsNothing);
21 | //
22 | // // Tap the '+' icon and trigger a frame.
23 | // await tester.tap(find.byIcon(Icons.add));
24 | // await tester.pump();
25 | //
26 | // // Verify that our counter has incremented.
27 | // expect(find.text('0'), findsNothing);
28 | // expect(find.text('1'), findsOneWidget);
29 | // });
30 | // }
31 |
--------------------------------------------------------------------------------
/example/web/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/web/favicon.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/web/icons/Icon-192.png
--------------------------------------------------------------------------------
/example/web/icons/Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/web/icons/Icon-512.png
--------------------------------------------------------------------------------
/example/web/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | example
30 |
31 |
32 |
33 |
36 |
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/example/web/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "short_name": "example",
4 | "start_url": ".",
5 | "display": "standalone",
6 | "background_color": "#0175C2",
7 | "theme_color": "#0175C2",
8 | "description": "A new Flutter project.",
9 | "orientation": "portrait-primary",
10 | "prefer_related_applications": false,
11 | "icons": [
12 | {
13 | "src": "icons/Icon-192.png",
14 | "sizes": "192x192",
15 | "type": "image/png"
16 | },
17 | {
18 | "src": "icons/Icon-512.png",
19 | "sizes": "512x512",
20 | "type": "image/png"
21 | }
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/example/windows/.gitignore:
--------------------------------------------------------------------------------
1 | flutter/ephemeral/
2 |
3 | # Visual Studio user-specific files.
4 | *.suo
5 | *.user
6 | *.userosscache
7 | *.sln.docstates
8 |
9 | # Visual Studio build-related files.
10 | x64/
11 | x86/
12 |
13 | # Visual Studio cache files
14 | # files ending in .cache can be ignored
15 | *.[Cc]ache
16 | # but keep track of directories ending in .cache
17 | !*.[Cc]ache/
18 |
--------------------------------------------------------------------------------
/example/windows/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(example LANGUAGES CXX)
3 |
4 | set(BINARY_NAME "example")
5 |
6 | cmake_policy(SET CMP0063 NEW)
7 |
8 | set(CMAKE_INSTALL_RPATH "$ORIGIN/lib")
9 |
10 | # Configure build options.
11 | get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
12 | if(IS_MULTICONFIG)
13 | set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release"
14 | CACHE STRING "" FORCE)
15 | else()
16 | if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
17 | set(CMAKE_BUILD_TYPE "Debug" CACHE
18 | STRING "Flutter build mode" FORCE)
19 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
20 | "Debug" "Profile" "Release")
21 | endif()
22 | endif()
23 |
24 | set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}")
25 | set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}")
26 | set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}")
27 | set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}")
28 |
29 | # Use Unicode for all projects.
30 | add_definitions(-DUNICODE -D_UNICODE)
31 |
32 | # Compilation settings that should be applied to most targets.
33 | function(APPLY_STANDARD_SETTINGS TARGET)
34 | target_compile_features(${TARGET} PUBLIC cxx_std_17)
35 | target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100")
36 | target_compile_options(${TARGET} PRIVATE /EHsc)
37 | target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0")
38 | target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>")
39 | endfunction()
40 |
41 | set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter")
42 |
43 | # Flutter library and tool build rules.
44 | add_subdirectory(${FLUTTER_MANAGED_DIR})
45 |
46 | # Application build
47 | add_subdirectory("runner")
48 |
49 | # Generated plugin build rules, which manage building the plugins and adding
50 | # them to the application.
51 | include(flutter/generated_plugins.cmake)
52 |
53 |
54 | # === Installation ===
55 | # Support files are copied into place next to the executable, so that it can
56 | # run in place. This is done instead of making a separate bundle (as on Linux)
57 | # so that building and running from within Visual Studio will work.
58 | set(BUILD_BUNDLE_DIR "$")
59 | # Make the "install" step default, as it's required to run.
60 | set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1)
61 | if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
62 | set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE)
63 | endif()
64 |
65 | set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data")
66 | set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}")
67 |
68 | install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}"
69 | COMPONENT Runtime)
70 |
71 | install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
72 | COMPONENT Runtime)
73 |
74 | install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
75 | COMPONENT Runtime)
76 |
77 | if(PLUGIN_BUNDLED_LIBRARIES)
78 | install(FILES "${PLUGIN_BUNDLED_LIBRARIES}"
79 | DESTINATION "${INSTALL_BUNDLE_LIB_DIR}"
80 | COMPONENT Runtime)
81 | endif()
82 |
83 | # Fully re-copy the assets directory on each build to avoid having stale files
84 | # from a previous install.
85 | set(FLUTTER_ASSET_DIR_NAME "flutter_assets")
86 | install(CODE "
87 | file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\")
88 | " COMPONENT Runtime)
89 | install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}"
90 | DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime)
91 |
92 | # Install the AOT library on non-Debug builds only.
93 | install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}"
94 | CONFIGURATIONS Profile;Release
95 | COMPONENT Runtime)
96 |
--------------------------------------------------------------------------------
/example/windows/flutter/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 |
3 | set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral")
4 |
5 | # Configuration provided via flutter tool.
6 | include(${EPHEMERAL_DIR}/generated_config.cmake)
7 |
8 | # TODO: Move the rest of this into files in ephemeral. See
9 | # https://github.com/flutter/flutter/issues/57146.
10 | set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper")
11 |
12 | # === Flutter Library ===
13 | set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll")
14 |
15 | # Published to parent scope for install step.
16 | set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE)
17 | set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE)
18 | set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE)
19 | set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE)
20 |
21 | list(APPEND FLUTTER_LIBRARY_HEADERS
22 | "flutter_export.h"
23 | "flutter_windows.h"
24 | "flutter_messenger.h"
25 | "flutter_plugin_registrar.h"
26 | "flutter_texture_registrar.h"
27 | )
28 | list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/")
29 | add_library(flutter INTERFACE)
30 | target_include_directories(flutter INTERFACE
31 | "${EPHEMERAL_DIR}"
32 | )
33 | target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib")
34 | add_dependencies(flutter flutter_assemble)
35 |
36 | # === Wrapper ===
37 | list(APPEND CPP_WRAPPER_SOURCES_CORE
38 | "core_implementations.cc"
39 | "standard_codec.cc"
40 | )
41 | list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/")
42 | list(APPEND CPP_WRAPPER_SOURCES_PLUGIN
43 | "plugin_registrar.cc"
44 | )
45 | list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/")
46 | list(APPEND CPP_WRAPPER_SOURCES_APP
47 | "flutter_engine.cc"
48 | "flutter_view_controller.cc"
49 | )
50 | list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/")
51 |
52 | # Wrapper sources needed for a plugin.
53 | add_library(flutter_wrapper_plugin STATIC
54 | ${CPP_WRAPPER_SOURCES_CORE}
55 | ${CPP_WRAPPER_SOURCES_PLUGIN}
56 | )
57 | apply_standard_settings(flutter_wrapper_plugin)
58 | set_target_properties(flutter_wrapper_plugin PROPERTIES
59 | POSITION_INDEPENDENT_CODE ON)
60 | set_target_properties(flutter_wrapper_plugin PROPERTIES
61 | CXX_VISIBILITY_PRESET hidden)
62 | target_link_libraries(flutter_wrapper_plugin PUBLIC flutter)
63 | target_include_directories(flutter_wrapper_plugin PUBLIC
64 | "${WRAPPER_ROOT}/include"
65 | )
66 | add_dependencies(flutter_wrapper_plugin flutter_assemble)
67 |
68 | # Wrapper sources needed for the runner.
69 | add_library(flutter_wrapper_app STATIC
70 | ${CPP_WRAPPER_SOURCES_CORE}
71 | ${CPP_WRAPPER_SOURCES_APP}
72 | )
73 | apply_standard_settings(flutter_wrapper_app)
74 | target_link_libraries(flutter_wrapper_app PUBLIC flutter)
75 | target_include_directories(flutter_wrapper_app PUBLIC
76 | "${WRAPPER_ROOT}/include"
77 | )
78 | add_dependencies(flutter_wrapper_app flutter_assemble)
79 |
80 | # === Flutter tool backend ===
81 | # _phony_ is a non-existent file to force this command to run every time,
82 | # since currently there's no way to get a full input/output list from the
83 | # flutter tool.
84 | set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_")
85 | set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE)
86 | add_custom_command(
87 | OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS}
88 | ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN}
89 | ${CPP_WRAPPER_SOURCES_APP}
90 | ${PHONY_OUTPUT}
91 | COMMAND ${CMAKE_COMMAND} -E env
92 | ${FLUTTER_TOOL_ENVIRONMENT}
93 | "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat"
94 | windows-x64 $
95 | VERBATIM
96 | )
97 | add_custom_target(flutter_assemble DEPENDS
98 | "${FLUTTER_LIBRARY}"
99 | ${FLUTTER_LIBRARY_HEADERS}
100 | ${CPP_WRAPPER_SOURCES_CORE}
101 | ${CPP_WRAPPER_SOURCES_PLUGIN}
102 | ${CPP_WRAPPER_SOURCES_APP}
103 | )
104 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.cc:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #include "generated_plugin_registrant.h"
8 |
9 |
10 | void RegisterPlugins(flutter::PluginRegistry* registry) {
11 | }
12 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugin_registrant.h:
--------------------------------------------------------------------------------
1 | //
2 | // Generated file. Do not edit.
3 | //
4 |
5 | // clang-format off
6 |
7 | #ifndef GENERATED_PLUGIN_REGISTRANT_
8 | #define GENERATED_PLUGIN_REGISTRANT_
9 |
10 | #include
11 |
12 | // Registers Flutter plugins.
13 | void RegisterPlugins(flutter::PluginRegistry* registry);
14 |
15 | #endif // GENERATED_PLUGIN_REGISTRANT_
16 |
--------------------------------------------------------------------------------
/example/windows/flutter/generated_plugins.cmake:
--------------------------------------------------------------------------------
1 | #
2 | # Generated file, do not edit.
3 | #
4 |
5 | list(APPEND FLUTTER_PLUGIN_LIST
6 | )
7 |
8 | list(APPEND FLUTTER_FFI_PLUGIN_LIST
9 | )
10 |
11 | set(PLUGIN_BUNDLED_LIBRARIES)
12 |
13 | foreach(plugin ${FLUTTER_PLUGIN_LIST})
14 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin})
15 | target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin)
16 | list(APPEND PLUGIN_BUNDLED_LIBRARIES $)
17 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries})
18 | endforeach(plugin)
19 |
20 | foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST})
21 | add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin})
22 | list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries})
23 | endforeach(ffi_plugin)
24 |
--------------------------------------------------------------------------------
/example/windows/runner/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.15)
2 | project(runner LANGUAGES CXX)
3 |
4 | add_executable(${BINARY_NAME} WIN32
5 | "flutter_window.cpp"
6 | "main.cpp"
7 | "run_loop.cpp"
8 | "utils.cpp"
9 | "win32_window.cpp"
10 | "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc"
11 | "Runner.rc"
12 | "runner.exe.manifest"
13 | )
14 | apply_standard_settings(${BINARY_NAME})
15 | target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX")
16 | target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app)
17 | target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}")
18 | add_dependencies(${BINARY_NAME} flutter_assemble)
19 |
--------------------------------------------------------------------------------
/example/windows/runner/Runner.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #pragma code_page(65001)
4 | #include "resource.h"
5 |
6 | #define APSTUDIO_READONLY_SYMBOLS
7 | /////////////////////////////////////////////////////////////////////////////
8 | //
9 | // Generated from the TEXTINCLUDE 2 resource.
10 | //
11 | #include "winres.h"
12 |
13 | /////////////////////////////////////////////////////////////////////////////
14 | #undef APSTUDIO_READONLY_SYMBOLS
15 |
16 | /////////////////////////////////////////////////////////////////////////////
17 | // English (United States) resources
18 |
19 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
20 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
21 |
22 | #ifdef APSTUDIO_INVOKED
23 | /////////////////////////////////////////////////////////////////////////////
24 | //
25 | // TEXTINCLUDE
26 | //
27 |
28 | 1 TEXTINCLUDE
29 | BEGIN
30 | "resource.h\0"
31 | END
32 |
33 | 2 TEXTINCLUDE
34 | BEGIN
35 | "#include ""winres.h""\r\n"
36 | "\0"
37 | END
38 |
39 | 3 TEXTINCLUDE
40 | BEGIN
41 | "\r\n"
42 | "\0"
43 | END
44 |
45 | #endif // APSTUDIO_INVOKED
46 |
47 |
48 | /////////////////////////////////////////////////////////////////////////////
49 | //
50 | // Icon
51 | //
52 |
53 | // Icon with lowest ID value placed first to ensure application icon
54 | // remains consistent on all systems.
55 | IDI_APP_ICON ICON "resources\\app_icon.ico"
56 |
57 |
58 | /////////////////////////////////////////////////////////////////////////////
59 | //
60 | // Version
61 | //
62 |
63 | #ifdef FLUTTER_BUILD_NUMBER
64 | #define VERSION_AS_NUMBER FLUTTER_BUILD_NUMBER
65 | #else
66 | #define VERSION_AS_NUMBER 1,0,0
67 | #endif
68 |
69 | #ifdef FLUTTER_BUILD_NAME
70 | #define VERSION_AS_STRING #FLUTTER_BUILD_NAME
71 | #else
72 | #define VERSION_AS_STRING "1.0.0"
73 | #endif
74 |
75 | VS_VERSION_INFO VERSIONINFO
76 | FILEVERSION VERSION_AS_NUMBER
77 | PRODUCTVERSION VERSION_AS_NUMBER
78 | FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
79 | #ifdef _DEBUG
80 | FILEFLAGS VS_FF_DEBUG
81 | #else
82 | FILEFLAGS 0x0L
83 | #endif
84 | FILEOS VOS__WINDOWS32
85 | FILETYPE VFT_APP
86 | FILESUBTYPE 0x0L
87 | BEGIN
88 | BLOCK "StringFileInfo"
89 | BEGIN
90 | BLOCK "040904e4"
91 | BEGIN
92 | VALUE "CompanyName", "com.benzneststudios" "\0"
93 | VALUE "FileDescription", "A new Flutter project." "\0"
94 | VALUE "FileVersion", VERSION_AS_STRING "\0"
95 | VALUE "InternalName", "example" "\0"
96 | VALUE "LegalCopyright", "Copyright (C) 2021 com.benzneststudios. All rights reserved." "\0"
97 | VALUE "OriginalFilename", "example.exe" "\0"
98 | VALUE "ProductName", "example" "\0"
99 | VALUE "ProductVersion", VERSION_AS_STRING "\0"
100 | END
101 | END
102 | BLOCK "VarFileInfo"
103 | BEGIN
104 | VALUE "Translation", 0x409, 1252
105 | END
106 | END
107 |
108 | #endif // English (United States) resources
109 | /////////////////////////////////////////////////////////////////////////////
110 |
111 |
112 |
113 | #ifndef APSTUDIO_INVOKED
114 | /////////////////////////////////////////////////////////////////////////////
115 | //
116 | // Generated from the TEXTINCLUDE 3 resource.
117 | //
118 |
119 |
120 | /////////////////////////////////////////////////////////////////////////////
121 | #endif // not APSTUDIO_INVOKED
122 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.cpp:
--------------------------------------------------------------------------------
1 | #include "flutter_window.h"
2 |
3 | #include
4 |
5 | #include "flutter/generated_plugin_registrant.h"
6 |
7 | FlutterWindow::FlutterWindow(RunLoop* run_loop,
8 | const flutter::DartProject& project)
9 | : run_loop_(run_loop), project_(project) {}
10 |
11 | FlutterWindow::~FlutterWindow() {}
12 |
13 | bool FlutterWindow::OnCreate() {
14 | if (!Win32Window::OnCreate()) {
15 | return false;
16 | }
17 |
18 | RECT frame = GetClientArea();
19 |
20 | // The size here must match the window dimensions to avoid unnecessary surface
21 | // creation / destruction in the startup path.
22 | flutter_controller_ = std::make_unique(
23 | frame.right - frame.left, frame.bottom - frame.top, project_);
24 | // Ensure that basic setup of the controller was successful.
25 | if (!flutter_controller_->engine() || !flutter_controller_->view()) {
26 | return false;
27 | }
28 | RegisterPlugins(flutter_controller_->engine());
29 | run_loop_->RegisterFlutterInstance(flutter_controller_->engine());
30 | SetChildContent(flutter_controller_->view()->GetNativeWindow());
31 | return true;
32 | }
33 |
34 | void FlutterWindow::OnDestroy() {
35 | if (flutter_controller_) {
36 | run_loop_->UnregisterFlutterInstance(flutter_controller_->engine());
37 | flutter_controller_ = nullptr;
38 | }
39 |
40 | Win32Window::OnDestroy();
41 | }
42 |
43 | LRESULT
44 | FlutterWindow::MessageHandler(HWND hwnd, UINT const message,
45 | WPARAM const wparam,
46 | LPARAM const lparam) noexcept {
47 | // Give Flutter, including plugins, an opporutunity to handle window messages.
48 | if (flutter_controller_) {
49 | std::optional result =
50 | flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam,
51 | lparam);
52 | if (result) {
53 | return *result;
54 | }
55 | }
56 |
57 | switch (message) {
58 | case WM_FONTCHANGE:
59 | flutter_controller_->engine()->ReloadSystemFonts();
60 | break;
61 | }
62 |
63 | return Win32Window::MessageHandler(hwnd, message, wparam, lparam);
64 | }
65 |
--------------------------------------------------------------------------------
/example/windows/runner/flutter_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_FLUTTER_WINDOW_H_
2 | #define RUNNER_FLUTTER_WINDOW_H_
3 |
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | #include "run_loop.h"
10 | #include "win32_window.h"
11 |
12 | // A window that does nothing but host a Flutter view.
13 | class FlutterWindow : public Win32Window {
14 | public:
15 | // Creates a new FlutterWindow driven by the |run_loop|, hosting a
16 | // Flutter view running |project|.
17 | explicit FlutterWindow(RunLoop* run_loop,
18 | const flutter::DartProject& project);
19 | virtual ~FlutterWindow();
20 |
21 | protected:
22 | // Win32Window:
23 | bool OnCreate() override;
24 | void OnDestroy() override;
25 | LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam,
26 | LPARAM const lparam) noexcept override;
27 |
28 | private:
29 | // The run loop driving events for this window.
30 | RunLoop* run_loop_;
31 |
32 | // The project to run.
33 | flutter::DartProject project_;
34 |
35 | // The Flutter instance hosted by this window.
36 | std::unique_ptr flutter_controller_;
37 | };
38 |
39 | #endif // RUNNER_FLUTTER_WINDOW_H_
40 |
--------------------------------------------------------------------------------
/example/windows/runner/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include "flutter_window.h"
6 | #include "run_loop.h"
7 | #include "utils.h"
8 |
9 | int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev,
10 | _In_ wchar_t *command_line, _In_ int show_command) {
11 | // Attach to console when present (e.g., 'flutter run') or create a
12 | // new console when running with a debugger.
13 | if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) {
14 | CreateAndAttachConsole();
15 | }
16 |
17 | // Initialize COM, so that it is available for use in the library and/or
18 | // plugins.
19 | ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED);
20 |
21 | RunLoop run_loop;
22 |
23 | flutter::DartProject project(L"data");
24 |
25 | std::vector command_line_arguments =
26 | GetCommandLineArguments();
27 |
28 | project.set_dart_entrypoint_arguments(std::move(command_line_arguments));
29 |
30 | FlutterWindow window(&run_loop, project);
31 | Win32Window::Point origin(10, 10);
32 | Win32Window::Size size(1280, 720);
33 | if (!window.CreateAndShow(L"example", origin, size)) {
34 | return EXIT_FAILURE;
35 | }
36 | window.SetQuitOnClose(true);
37 |
38 | run_loop.Run();
39 |
40 | ::CoUninitialize();
41 | return EXIT_SUCCESS;
42 | }
43 |
--------------------------------------------------------------------------------
/example/windows/runner/resource.h:
--------------------------------------------------------------------------------
1 | //{{NO_DEPENDENCIES}}
2 | // Microsoft Visual C++ generated include file.
3 | // Used by Runner.rc
4 | //
5 | #define IDI_APP_ICON 101
6 |
7 | // Next default values for new objects
8 | //
9 | #ifdef APSTUDIO_INVOKED
10 | #ifndef APSTUDIO_READONLY_SYMBOLS
11 | #define _APS_NEXT_RESOURCE_VALUE 102
12 | #define _APS_NEXT_COMMAND_VALUE 40001
13 | #define _APS_NEXT_CONTROL_VALUE 1001
14 | #define _APS_NEXT_SYMED_VALUE 101
15 | #endif
16 | #endif
17 |
--------------------------------------------------------------------------------
/example/windows/runner/resources/app_icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/example/windows/runner/resources/app_icon.ico
--------------------------------------------------------------------------------
/example/windows/runner/run_loop.cpp:
--------------------------------------------------------------------------------
1 | #include "run_loop.h"
2 |
3 | #include
4 |
5 | #include
6 |
7 | RunLoop::RunLoop() {}
8 |
9 | RunLoop::~RunLoop() {}
10 |
11 | void RunLoop::Run() {
12 | bool keep_running = true;
13 | TimePoint next_flutter_event_time = TimePoint::clock::now();
14 | while (keep_running) {
15 | std::chrono::nanoseconds wait_duration =
16 | std::max(std::chrono::nanoseconds(0),
17 | next_flutter_event_time - TimePoint::clock::now());
18 | ::MsgWaitForMultipleObjects(
19 | 0, nullptr, FALSE, static_cast(wait_duration.count() / 1000),
20 | QS_ALLINPUT);
21 | bool processed_events = false;
22 | MSG message;
23 | // All pending Windows messages must be processed; MsgWaitForMultipleObjects
24 | // won't return again for items left in the queue after PeekMessage.
25 | while (::PeekMessage(&message, nullptr, 0, 0, PM_REMOVE)) {
26 | processed_events = true;
27 | if (message.message == WM_QUIT) {
28 | keep_running = false;
29 | break;
30 | }
31 | ::TranslateMessage(&message);
32 | ::DispatchMessage(&message);
33 | // Allow Flutter to process messages each time a Windows message is
34 | // processed, to prevent starvation.
35 | next_flutter_event_time =
36 | std::min(next_flutter_event_time, ProcessFlutterMessages());
37 | }
38 | // If the PeekMessage loop didn't run, process Flutter messages.
39 | if (!processed_events) {
40 | next_flutter_event_time =
41 | std::min(next_flutter_event_time, ProcessFlutterMessages());
42 | }
43 | }
44 | }
45 |
46 | void RunLoop::RegisterFlutterInstance(
47 | flutter::FlutterEngine* flutter_instance) {
48 | flutter_instances_.insert(flutter_instance);
49 | }
50 |
51 | void RunLoop::UnregisterFlutterInstance(
52 | flutter::FlutterEngine* flutter_instance) {
53 | flutter_instances_.erase(flutter_instance);
54 | }
55 |
56 | RunLoop::TimePoint RunLoop::ProcessFlutterMessages() {
57 | TimePoint next_event_time = TimePoint::max();
58 | for (auto instance : flutter_instances_) {
59 | std::chrono::nanoseconds wait_duration = instance->ProcessMessages();
60 | if (wait_duration != std::chrono::nanoseconds::max()) {
61 | next_event_time =
62 | std::min(next_event_time, TimePoint::clock::now() + wait_duration);
63 | }
64 | }
65 | return next_event_time;
66 | }
67 |
--------------------------------------------------------------------------------
/example/windows/runner/run_loop.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_RUN_LOOP_H_
2 | #define RUNNER_RUN_LOOP_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 |
9 | // A runloop that will service events for Flutter instances as well
10 | // as native messages.
11 | class RunLoop {
12 | public:
13 | RunLoop();
14 | ~RunLoop();
15 |
16 | // Prevent copying
17 | RunLoop(RunLoop const&) = delete;
18 | RunLoop& operator=(RunLoop const&) = delete;
19 |
20 | // Runs the run loop until the application quits.
21 | void Run();
22 |
23 | // Registers the given Flutter instance for event servicing.
24 | void RegisterFlutterInstance(
25 | flutter::FlutterEngine* flutter_instance);
26 |
27 | // Unregisters the given Flutter instance from event servicing.
28 | void UnregisterFlutterInstance(
29 | flutter::FlutterEngine* flutter_instance);
30 |
31 | private:
32 | using TimePoint = std::chrono::steady_clock::time_point;
33 |
34 | // Processes all currently pending messages for registered Flutter instances.
35 | TimePoint ProcessFlutterMessages();
36 |
37 | std::set flutter_instances_;
38 | };
39 |
40 | #endif // RUNNER_RUN_LOOP_H_
41 |
--------------------------------------------------------------------------------
/example/windows/runner/runner.exe.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PerMonitorV2
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | #include
9 |
10 | void CreateAndAttachConsole() {
11 | if (::AllocConsole()) {
12 | FILE *unused;
13 | if (freopen_s(&unused, "CONOUT$", "w", stdout)) {
14 | _dup2(_fileno(stdout), 1);
15 | }
16 | if (freopen_s(&unused, "CONOUT$", "w", stderr)) {
17 | _dup2(_fileno(stdout), 2);
18 | }
19 | std::ios::sync_with_stdio();
20 | FlutterDesktopResyncOutputStreams();
21 | }
22 | }
23 |
24 | std::vector GetCommandLineArguments() {
25 | // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use.
26 | int argc;
27 | wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc);
28 | if (argv == nullptr) {
29 | return std::vector();
30 | }
31 |
32 | std::vector command_line_arguments;
33 |
34 | // Skip the first argument as it's the binary name.
35 | for (int i = 1; i < argc; i++) {
36 | command_line_arguments.push_back(Utf8FromUtf16(argv[i]));
37 | }
38 |
39 | ::LocalFree(argv);
40 |
41 | return command_line_arguments;
42 | }
43 |
44 | std::string Utf8FromUtf16(const wchar_t* utf16_string) {
45 | if (utf16_string == nullptr) {
46 | return std::string();
47 | }
48 | int target_length = ::WideCharToMultiByte(
49 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
50 | -1, nullptr, 0, nullptr, nullptr);
51 | if (target_length == 0) {
52 | return std::string();
53 | }
54 | std::string utf8_string;
55 | utf8_string.resize(target_length);
56 | int converted_length = ::WideCharToMultiByte(
57 | CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string,
58 | -1, utf8_string.data(),
59 | target_length, nullptr, nullptr);
60 | if (converted_length == 0) {
61 | return std::string();
62 | }
63 | return utf8_string;
64 | }
65 |
--------------------------------------------------------------------------------
/example/windows/runner/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_UTILS_H_
2 | #define RUNNER_UTILS_H_
3 |
4 | #include
5 | #include
6 |
7 | // Creates a console for the process, and redirects stdout and stderr to
8 | // it for both the runner and the Flutter library.
9 | void CreateAndAttachConsole();
10 |
11 | // Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string
12 | // encoded in UTF-8. Returns an empty std::string on failure.
13 | std::string Utf8FromUtf16(const wchar_t* utf16_string);
14 |
15 | // Gets the command line arguments passed in as a std::vector,
16 | // encoded in UTF-8. Returns an empty std::vector on failure.
17 | std::vector GetCommandLineArguments();
18 |
19 | #endif // RUNNER_UTILS_H_
20 |
--------------------------------------------------------------------------------
/example/windows/runner/win32_window.cpp:
--------------------------------------------------------------------------------
1 | #include "win32_window.h"
2 |
3 | #include
4 |
5 | #include "resource.h"
6 |
7 | namespace {
8 |
9 | constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW";
10 |
11 | // The number of Win32Window objects that currently exist.
12 | static int g_active_window_count = 0;
13 |
14 | using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd);
15 |
16 | // Scale helper to convert logical scaler values to physical using passed in
17 | // scale factor
18 | int Scale(int source, double scale_factor) {
19 | return static_cast(source * scale_factor);
20 | }
21 |
22 | // Dynamically loads the |EnableNonClientDpiScaling| from the User32 module.
23 | // This API is only needed for PerMonitor V1 awareness mode.
24 | void EnableFullDpiSupportIfAvailable(HWND hwnd) {
25 | HMODULE user32_module = LoadLibraryA("User32.dll");
26 | if (!user32_module) {
27 | return;
28 | }
29 | auto enable_non_client_dpi_scaling =
30 | reinterpret_cast(
31 | GetProcAddress(user32_module, "EnableNonClientDpiScaling"));
32 | if (enable_non_client_dpi_scaling != nullptr) {
33 | enable_non_client_dpi_scaling(hwnd);
34 | FreeLibrary(user32_module);
35 | }
36 | }
37 |
38 | } // namespace
39 |
40 | // Manages the Win32Window's window class registration.
41 | class WindowClassRegistrar {
42 | public:
43 | ~WindowClassRegistrar() = default;
44 |
45 | // Returns the singleton registar instance.
46 | static WindowClassRegistrar* GetInstance() {
47 | if (!instance_) {
48 | instance_ = new WindowClassRegistrar();
49 | }
50 | return instance_;
51 | }
52 |
53 | // Returns the name of the window class, registering the class if it hasn't
54 | // previously been registered.
55 | const wchar_t* GetWindowClass();
56 |
57 | // Unregisters the window class. Should only be called if there are no
58 | // instances of the window.
59 | void UnregisterWindowClass();
60 |
61 | private:
62 | WindowClassRegistrar() = default;
63 |
64 | static WindowClassRegistrar* instance_;
65 |
66 | bool class_registered_ = false;
67 | };
68 |
69 | WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr;
70 |
71 | const wchar_t* WindowClassRegistrar::GetWindowClass() {
72 | if (!class_registered_) {
73 | WNDCLASS window_class{};
74 | window_class.hCursor = LoadCursor(nullptr, IDC_ARROW);
75 | window_class.lpszClassName = kWindowClassName;
76 | window_class.style = CS_HREDRAW | CS_VREDRAW;
77 | window_class.cbClsExtra = 0;
78 | window_class.cbWndExtra = 0;
79 | window_class.hInstance = GetModuleHandle(nullptr);
80 | window_class.hIcon =
81 | LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON));
82 | window_class.hbrBackground = 0;
83 | window_class.lpszMenuName = nullptr;
84 | window_class.lpfnWndProc = Win32Window::WndProc;
85 | RegisterClass(&window_class);
86 | class_registered_ = true;
87 | }
88 | return kWindowClassName;
89 | }
90 |
91 | void WindowClassRegistrar::UnregisterWindowClass() {
92 | UnregisterClass(kWindowClassName, nullptr);
93 | class_registered_ = false;
94 | }
95 |
96 | Win32Window::Win32Window() {
97 | ++g_active_window_count;
98 | }
99 |
100 | Win32Window::~Win32Window() {
101 | --g_active_window_count;
102 | Destroy();
103 | }
104 |
105 | bool Win32Window::CreateAndShow(const std::wstring& title,
106 | const Point& origin,
107 | const Size& size) {
108 | Destroy();
109 |
110 | const wchar_t* window_class =
111 | WindowClassRegistrar::GetInstance()->GetWindowClass();
112 |
113 | const POINT target_point = {static_cast(origin.x),
114 | static_cast(origin.y)};
115 | HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST);
116 | UINT dpi = FlutterDesktopGetDpiForMonitor(monitor);
117 | double scale_factor = dpi / 96.0;
118 |
119 | HWND window = CreateWindow(
120 | window_class, title.c_str(), WS_OVERLAPPEDWINDOW | WS_VISIBLE,
121 | Scale(origin.x, scale_factor), Scale(origin.y, scale_factor),
122 | Scale(size.width, scale_factor), Scale(size.height, scale_factor),
123 | nullptr, nullptr, GetModuleHandle(nullptr), this);
124 |
125 | if (!window) {
126 | return false;
127 | }
128 |
129 | return OnCreate();
130 | }
131 |
132 | // static
133 | LRESULT CALLBACK Win32Window::WndProc(HWND const window,
134 | UINT const message,
135 | WPARAM const wparam,
136 | LPARAM const lparam) noexcept {
137 | if (message == WM_NCCREATE) {
138 | auto window_struct = reinterpret_cast(lparam);
139 | SetWindowLongPtr(window, GWLP_USERDATA,
140 | reinterpret_cast(window_struct->lpCreateParams));
141 |
142 | auto that = static_cast(window_struct->lpCreateParams);
143 | EnableFullDpiSupportIfAvailable(window);
144 | that->window_handle_ = window;
145 | } else if (Win32Window* that = GetThisFromHandle(window)) {
146 | return that->MessageHandler(window, message, wparam, lparam);
147 | }
148 |
149 | return DefWindowProc(window, message, wparam, lparam);
150 | }
151 |
152 | LRESULT
153 | Win32Window::MessageHandler(HWND hwnd,
154 | UINT const message,
155 | WPARAM const wparam,
156 | LPARAM const lparam) noexcept {
157 | switch (message) {
158 | case WM_DESTROY:
159 | window_handle_ = nullptr;
160 | Destroy();
161 | if (quit_on_close_) {
162 | PostQuitMessage(0);
163 | }
164 | return 0;
165 |
166 | case WM_DPICHANGED: {
167 | auto newRectSize = reinterpret_cast(lparam);
168 | LONG newWidth = newRectSize->right - newRectSize->left;
169 | LONG newHeight = newRectSize->bottom - newRectSize->top;
170 |
171 | SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth,
172 | newHeight, SWP_NOZORDER | SWP_NOACTIVATE);
173 |
174 | return 0;
175 | }
176 | case WM_SIZE: {
177 | RECT rect = GetClientArea();
178 | if (child_content_ != nullptr) {
179 | // Size and position the child window.
180 | MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left,
181 | rect.bottom - rect.top, TRUE);
182 | }
183 | return 0;
184 | }
185 |
186 | case WM_ACTIVATE:
187 | if (child_content_ != nullptr) {
188 | SetFocus(child_content_);
189 | }
190 | return 0;
191 | }
192 |
193 | return DefWindowProc(window_handle_, message, wparam, lparam);
194 | }
195 |
196 | void Win32Window::Destroy() {
197 | OnDestroy();
198 |
199 | if (window_handle_) {
200 | DestroyWindow(window_handle_);
201 | window_handle_ = nullptr;
202 | }
203 | if (g_active_window_count == 0) {
204 | WindowClassRegistrar::GetInstance()->UnregisterWindowClass();
205 | }
206 | }
207 |
208 | Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept {
209 | return reinterpret_cast(
210 | GetWindowLongPtr(window, GWLP_USERDATA));
211 | }
212 |
213 | void Win32Window::SetChildContent(HWND content) {
214 | child_content_ = content;
215 | SetParent(content, window_handle_);
216 | RECT frame = GetClientArea();
217 |
218 | MoveWindow(content, frame.left, frame.top, frame.right - frame.left,
219 | frame.bottom - frame.top, true);
220 |
221 | SetFocus(child_content_);
222 | }
223 |
224 | RECT Win32Window::GetClientArea() {
225 | RECT frame;
226 | GetClientRect(window_handle_, &frame);
227 | return frame;
228 | }
229 |
230 | HWND Win32Window::GetHandle() {
231 | return window_handle_;
232 | }
233 |
234 | void Win32Window::SetQuitOnClose(bool quit_on_close) {
235 | quit_on_close_ = quit_on_close;
236 | }
237 |
238 | bool Win32Window::OnCreate() {
239 | // No-op; provided for subclasses.
240 | return true;
241 | }
242 |
243 | void Win32Window::OnDestroy() {
244 | // No-op; provided for subclasses.
245 | }
246 |
--------------------------------------------------------------------------------
/example/windows/runner/win32_window.h:
--------------------------------------------------------------------------------
1 | #ifndef RUNNER_WIN32_WINDOW_H_
2 | #define RUNNER_WIN32_WINDOW_H_
3 |
4 | #include
5 |
6 | #include
7 | #include
8 | #include
9 |
10 | // A class abstraction for a high DPI-aware Win32 Window. Intended to be
11 | // inherited from by classes that wish to specialize with custom
12 | // rendering and input handling
13 | class Win32Window {
14 | public:
15 | struct Point {
16 | unsigned int x;
17 | unsigned int y;
18 | Point(unsigned int x, unsigned int y) : x(x), y(y) {}
19 | };
20 |
21 | struct Size {
22 | unsigned int width;
23 | unsigned int height;
24 | Size(unsigned int width, unsigned int height)
25 | : width(width), height(height) {}
26 | };
27 |
28 | Win32Window();
29 | virtual ~Win32Window();
30 |
31 | // Creates and shows a win32 window with |title| and position and size using
32 | // |origin| and |size|. New windows are created on the default monitor. Window
33 | // sizes are specified to the OS in physical pixels, hence to ensure a
34 | // consistent size to will treat the width height passed in to this function
35 | // as logical pixels and scale to appropriate for the default monitor. Returns
36 | // true if the window was created successfully.
37 | bool CreateAndShow(const std::wstring& title,
38 | const Point& origin,
39 | const Size& size);
40 |
41 | // Release OS resources associated with window.
42 | void Destroy();
43 |
44 | // Inserts |content| into the window tree.
45 | void SetChildContent(HWND content);
46 |
47 | // Returns the backing Window handle to enable clients to set icon and other
48 | // window properties. Returns nullptr if the window has been destroyed.
49 | HWND GetHandle();
50 |
51 | // If true, closing this window will quit the application.
52 | void SetQuitOnClose(bool quit_on_close);
53 |
54 | // Return a RECT representing the bounds of the current client area.
55 | RECT GetClientArea();
56 |
57 | protected:
58 | // Processes and route salient window messages for mouse handling,
59 | // size change and DPI. Delegates handling of these to member overloads that
60 | // inheriting classes can handle.
61 | virtual LRESULT MessageHandler(HWND window,
62 | UINT const message,
63 | WPARAM const wparam,
64 | LPARAM const lparam) noexcept;
65 |
66 | // Called when CreateAndShow is called, allowing subclass window-related
67 | // setup. Subclasses should return false if setup fails.
68 | virtual bool OnCreate();
69 |
70 | // Called when Destroy is called.
71 | virtual void OnDestroy();
72 |
73 | private:
74 | friend class WindowClassRegistrar;
75 |
76 | // OS callback called by message pump. Handles the WM_NCCREATE message which
77 | // is passed when the non-client area is being created and enables automatic
78 | // non-client DPI scaling so that the non-client area automatically
79 | // responsponds to changes in DPI. All other messages are handled by
80 | // MessageHandler.
81 | static LRESULT CALLBACK WndProc(HWND const window,
82 | UINT const message,
83 | WPARAM const wparam,
84 | LPARAM const lparam) noexcept;
85 |
86 | // Retrieves a class instance pointer for |window|
87 | static Win32Window* GetThisFromHandle(HWND const window) noexcept;
88 |
89 | bool quit_on_close_ = false;
90 |
91 | // window handle for top level window.
92 | HWND window_handle_ = nullptr;
93 |
94 | // window handle for hosted content.
95 | HWND child_content_ = nullptr;
96 | };
97 |
98 | #endif // RUNNER_WIN32_WINDOW_H_
99 |
--------------------------------------------------------------------------------
/lib/flutter_rounded_date_picker.dart:
--------------------------------------------------------------------------------
1 | library flutter_rounded_date_picker;
2 |
3 | export './src/flutter_rounded_date_picker_widget.dart' show showRoundedDatePicker;
4 | export './src/flutter_rounded_time_picker_widget.dart' show showRoundedTimePicker;
5 | export './src/cupertino_rounded_date_picker.dart' show CupertinoRoundedDatePicker;
6 | export './src/cupertino_rounded_duration_picker.dart' show CupertinoRoundedDurationPicker;
7 | export './src/material_rounded_date_picker_style.dart' show MaterialRoundedDatePickerStyle;
8 | export './src/material_rounded_year_picker_style.dart' show MaterialRoundedYearPickerStyle;
9 | export './src/era_mode.dart' show EraMode;
10 |
--------------------------------------------------------------------------------
/lib/src/cupertino_rounded_date_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
4 | import 'package:flutter_rounded_date_picker/src/flutter_cupertino_rounded_date_picker_widget.dart';
5 |
6 | class CupertinoRoundedDatePicker {
7 | static show(BuildContext context,
8 | {Locale? locale,
9 | DateTime? initialDate,
10 | DateTime? minimumDate,
11 | DateTime? maximumDate,
12 | int? minimumYear,
13 | int? maximumYear,
14 | Function(DateTime)? onDateTimeChanged,
15 | int minuteInterval = 1,
16 | bool use24hFormat = false,
17 | CupertinoDatePickerMode initialDatePickerMode =
18 | CupertinoDatePickerMode.date,
19 | EraMode era = EraMode.CHRIST_YEAR,
20 | double borderRadius = 16,
21 | String? fontFamily,
22 | Color background = Colors.white,
23 | Color textColor = Colors.black54,
24 | BoxConstraints? constraints}) async {
25 | initialDate ??= DateTime.now();
26 | minimumDate ??= DateTime.now().subtract(Duration(days: 7));
27 | maximumDate ??= DateTime.now().add(Duration(days: 7));
28 | minimumYear ??= DateTime.now().year - 1;
29 | maximumYear ??= DateTime.now().year + 1;
30 |
31 | return await showModalBottomSheet(
32 | backgroundColor: Colors.transparent,
33 | isScrollControlled: true,
34 | enableDrag: false,
35 | constraints: constraints ??
36 | BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.5),
37 | context: context,
38 | builder: (context) {
39 | return FlutterRoundedCupertinoDatePickerWidget(
40 | use24hFormat: use24hFormat,
41 | onDateTimeChanged: (dateTime) {
42 | if (onDateTimeChanged != null) {
43 | onDateTimeChanged(dateTime);
44 | }
45 | },
46 | era: era,
47 | background: background,
48 | textColor: textColor,
49 | borderRadius: borderRadius,
50 | fontFamily: fontFamily,
51 | initialDateTime: initialDate,
52 | mode: initialDatePickerMode,
53 | minuteInterval: minuteInterval,
54 | minimumDate: minimumDate,
55 | maximumDate: maximumDate,
56 | maximumYear: maximumYear,
57 | minimumYear: minimumYear!,
58 | );
59 | },
60 | );
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/lib/src/cupertino_rounded_duration_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
4 | import 'package:flutter_rounded_date_picker/src/flutter_cupertino_rounded_date_picker_widget.dart';
5 |
6 | class CupertinoRoundedDurationPicker {
7 | static show(BuildContext context,
8 | {Function(Duration)? onDurationChanged,
9 | int minuteInterval = 1,
10 | Duration? initialTimerDuration,
11 | CupertinoTimerPickerMode initialDurationPickerMode =
12 | CupertinoTimerPickerMode.hm,
13 | EraMode era = EraMode.CHRIST_YEAR,
14 | double borderRadius = 16,
15 | String? fontFamily,
16 | Color background = Colors.white,
17 | Color textColor = Colors.black54,
18 | BoxConstraints? constraints}) async {
19 | initialTimerDuration ??= Duration(minutes: 10);
20 |
21 | return await showModalBottomSheet(
22 | backgroundColor: Colors.transparent,
23 | context: context,
24 | isScrollControlled: true,
25 | enableDrag: false,
26 | constraints: constraints ??
27 | BoxConstraints(maxHeight: MediaQuery.of(context).size.height * 0.5),
28 | builder: (context) {
29 | return FlutterRoundedCupertinoDurationPickerWidget(
30 | onTimerDurationChanged: (duration) {
31 | if (onDurationChanged != null) {
32 | onDurationChanged(duration);
33 | }
34 | },
35 | background: background,
36 | textColor: textColor,
37 | borderRadius: borderRadius,
38 | fontFamily: fontFamily,
39 | initialTimerDuration: initialTimerDuration!,
40 | mode: initialDurationPickerMode,
41 | minuteInterval: minuteInterval,
42 | );
43 | },
44 | );
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/lib/src/dialogs/flutter_rounded_date_picker_dialog.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter/semantics.dart';
3 | import 'package:flutter/services.dart';
4 | import 'package:flutter_rounded_date_picker/flutter_rounded_date_picker.dart';
5 | import 'package:flutter_rounded_date_picker/src/flutter_rounded_button_action.dart';
6 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_date_picker_header.dart';
7 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
8 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_month_picker.dart';
9 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_year_picker.dart';
10 |
11 | class FlutterRoundedDatePickerDialog extends StatefulWidget {
12 | const FlutterRoundedDatePickerDialog(
13 | {Key? key,
14 | this.height,
15 | required this.initialDate,
16 | required this.firstDate,
17 | required this.lastDate,
18 | this.selectableDayPredicate,
19 | required this.initialDatePickerMode,
20 | required this.era,
21 | this.locale,
22 | required this.borderRadius,
23 | this.imageHeader,
24 | this.description = "",
25 | this.fontFamily,
26 | this.textNegativeButton,
27 | this.textPositiveButton,
28 | this.textActionButton,
29 | this.onTapActionButton,
30 | this.styleDatePicker,
31 | this.styleYearPicker,
32 | this.customWeekDays,
33 | this.builderDay,
34 | this.listDateDisabled,
35 | this.onTapDay,
36 | this.onMonthChange})
37 | : super(key: key);
38 |
39 | final DateTime initialDate;
40 | final DateTime firstDate;
41 | final DateTime lastDate;
42 | final SelectableDayPredicate? selectableDayPredicate;
43 | final DatePickerMode initialDatePickerMode;
44 |
45 | /// double height.
46 | final double? height;
47 |
48 | /// Custom era year.
49 | final EraMode era;
50 | final Locale? locale;
51 |
52 | /// Border
53 | final double borderRadius;
54 |
55 | /// Header;
56 | final ImageProvider? imageHeader;
57 | final String description;
58 |
59 | /// Font
60 | final String? fontFamily;
61 |
62 | /// Button
63 | final String? textNegativeButton;
64 | final String? textPositiveButton;
65 | final String? textActionButton;
66 |
67 | final VoidCallback? onTapActionButton;
68 |
69 | /// Style
70 | final MaterialRoundedDatePickerStyle? styleDatePicker;
71 | final MaterialRoundedYearPickerStyle? styleYearPicker;
72 |
73 | /// Custom Weekday
74 | final List? customWeekDays;
75 |
76 | final BuilderDayOfDatePicker? builderDay;
77 |
78 | final List? listDateDisabled;
79 | final OnTapDay? onTapDay;
80 |
81 | final Function? onMonthChange;
82 |
83 | @override
84 | _FlutterRoundedDatePickerDialogState createState() =>
85 | _FlutterRoundedDatePickerDialogState();
86 | }
87 |
88 | class _FlutterRoundedDatePickerDialogState
89 | extends State {
90 | @override
91 | void initState() {
92 | super.initState();
93 | _selectedDate = widget.initialDate;
94 | _mode = widget.initialDatePickerMode;
95 | }
96 |
97 | bool _announcedInitialDate = false;
98 |
99 | late MaterialLocalizations localizations;
100 | late TextDirection textDirection;
101 |
102 | @override
103 | void didChangeDependencies() {
104 | super.didChangeDependencies();
105 | localizations = MaterialLocalizations.of(context);
106 | textDirection = Directionality.of(context);
107 | if (!_announcedInitialDate) {
108 | _announcedInitialDate = true;
109 | SemanticsService.announce(
110 | localizations.formatFullDate(_selectedDate),
111 | textDirection,
112 | );
113 | }
114 | }
115 |
116 | late DateTime _selectedDate;
117 | late DatePickerMode _mode;
118 | final GlobalKey _pickerKey = GlobalKey();
119 |
120 | void _vibrate() {
121 | switch (Theme.of(context).platform) {
122 | case TargetPlatform.android:
123 | case TargetPlatform.fuchsia:
124 | HapticFeedback.vibrate();
125 | break;
126 | case TargetPlatform.iOS:
127 | default:
128 | break;
129 | }
130 | }
131 |
132 | void _handleModeChanged(DatePickerMode mode) {
133 | _vibrate();
134 | setState(() {
135 | _mode = mode;
136 | if (_mode == DatePickerMode.day) {
137 | SemanticsService.announce(
138 | localizations.formatMonthYear(_selectedDate),
139 | textDirection,
140 | );
141 | } else {
142 | SemanticsService.announce(
143 | localizations.formatYear(_selectedDate),
144 | textDirection,
145 | );
146 | }
147 | });
148 | }
149 |
150 | Future _handleYearChanged(DateTime value) async {
151 | if (value.isBefore(widget.firstDate)) {
152 | value = widget.firstDate;
153 | } else if (value.isAfter(widget.lastDate)) {
154 | value = widget.lastDate;
155 | }
156 | if (value == _selectedDate) return;
157 |
158 | if (widget.onMonthChange != null) await widget.onMonthChange!(value);
159 |
160 | _vibrate();
161 | setState(() {
162 | _mode = DatePickerMode.day;
163 | _selectedDate = value;
164 | });
165 | }
166 |
167 | void _handleDayChanged(DateTime value) {
168 | _vibrate();
169 | setState(() {
170 | _selectedDate = value;
171 | });
172 | }
173 |
174 | void _handleCancel() {
175 | Navigator.of(context).pop();
176 | }
177 |
178 | void _handleOk() {
179 | Navigator.of(context).pop(_selectedDate);
180 | }
181 |
182 | Widget _buildPicker() {
183 | switch (_mode) {
184 | case DatePickerMode.year:
185 | return FlutterRoundedYearPicker(
186 | key: _pickerKey,
187 | selectedDate: _selectedDate,
188 | onChanged: (DateTime date) async => await _handleYearChanged(date),
189 | firstDate: widget.firstDate,
190 | lastDate: widget.lastDate,
191 | era: widget.era,
192 | fontFamily: widget.fontFamily,
193 | style: widget.styleYearPicker,
194 | );
195 | case DatePickerMode.day:
196 | default:
197 | return FlutterRoundedMonthPicker(
198 | key: _pickerKey,
199 | selectedDate: _selectedDate,
200 | onChanged: _handleDayChanged,
201 | firstDate: widget.firstDate,
202 | lastDate: widget.lastDate,
203 | era: widget.era,
204 | locale: widget.locale,
205 | selectableDayPredicate: widget.selectableDayPredicate,
206 | fontFamily: widget.fontFamily,
207 | style: widget.styleDatePicker,
208 | borderRadius: widget.borderRadius,
209 | customWeekDays: widget.customWeekDays,
210 | builderDay: widget.builderDay,
211 | listDateDisabled: widget.listDateDisabled,
212 | onTapDay: widget.onTapDay,
213 | onMonthChange: widget.onMonthChange);
214 | }
215 | }
216 |
217 | @override
218 | Widget build(BuildContext context) {
219 | final ThemeData theme = Theme.of(context);
220 | final Widget picker = _buildPicker();
221 |
222 | final Widget actions = FlutterRoundedButtonAction(
223 | textButtonNegative: widget.textNegativeButton,
224 | textButtonPositive: widget.textPositiveButton,
225 | onTapButtonNegative: _handleCancel,
226 | onTapButtonPositive: _handleOk,
227 | textActionButton: widget.textActionButton,
228 | onTapButtonAction: widget.onTapActionButton,
229 | localizations: localizations,
230 | textStyleButtonNegative: widget.styleDatePicker?.textStyleButtonNegative,
231 | textStyleButtonPositive: widget.styleDatePicker?.textStyleButtonPositive,
232 | textStyleButtonAction: widget.styleDatePicker?.textStyleButtonAction,
233 | borderRadius: widget.borderRadius,
234 | paddingActionBar: widget.styleDatePicker?.paddingActionBar,
235 | background: widget.styleDatePicker?.backgroundActionBar,
236 | );
237 |
238 | Color backgroundPicker = theme.dialogBackgroundColor;
239 | if (_mode == DatePickerMode.day) {
240 | backgroundPicker = widget.styleDatePicker?.backgroundPicker ??
241 | theme.dialogBackgroundColor;
242 | } else {
243 | backgroundPicker = widget.styleYearPicker?.backgroundPicker ??
244 | theme.dialogBackgroundColor;
245 | }
246 |
247 | final Dialog dialog = Dialog(
248 | child: OrientationBuilder(
249 | builder: (BuildContext context, Orientation orientation) {
250 | final Widget header = FlutterRoundedDatePickerHeader(
251 | selectedDate: _selectedDate,
252 | mode: _mode,
253 | onModeChanged: _handleModeChanged,
254 | orientation: orientation,
255 | era: widget.era,
256 | borderRadius: widget.borderRadius,
257 | imageHeader: widget.imageHeader,
258 | description: widget.description,
259 | fontFamily: widget.fontFamily,
260 | style: widget.styleDatePicker);
261 | switch (orientation) {
262 | case Orientation.landscape:
263 | return Container(
264 | decoration: BoxDecoration(
265 | color: backgroundPicker,
266 | borderRadius: BorderRadius.circular(widget.borderRadius),
267 | ),
268 | child: Row(
269 | mainAxisSize: MainAxisSize.min,
270 | crossAxisAlignment: CrossAxisAlignment.stretch,
271 | children: [
272 | Flexible(flex: 1, child: header),
273 | Flexible(
274 | flex: 2, // have the picker take up 2/3 of the dialog width
275 | child: Column(
276 | mainAxisSize: MainAxisSize.min,
277 | crossAxisAlignment: CrossAxisAlignment.stretch,
278 | children: [
279 | Flexible(child: picker),
280 | actions,
281 | ],
282 | ),
283 | ),
284 | ],
285 | ),
286 | );
287 | case Orientation.portrait:
288 | default:
289 | return Container(
290 | decoration: BoxDecoration(
291 | color: backgroundPicker,
292 | borderRadius: BorderRadius.circular(widget.borderRadius),
293 | ),
294 | child: Column(
295 | mainAxisSize: MainAxisSize.min,
296 | crossAxisAlignment: CrossAxisAlignment.stretch,
297 | children: [
298 | header,
299 | if (widget.height == null)
300 | Flexible(child: picker)
301 | else
302 | SizedBox(
303 | height: widget.height,
304 | child: picker,
305 | ),
306 | actions,
307 | ],
308 | ),
309 | );
310 | }
311 | }),
312 | );
313 |
314 | return Theme(
315 | data: theme.copyWith(dialogBackgroundColor: Colors.transparent),
316 | child: dialog,
317 | );
318 | }
319 | }
320 |
--------------------------------------------------------------------------------
/lib/src/era_mode.dart:
--------------------------------------------------------------------------------
1 | enum EraMode { BUDDHIST_YEAR, CHRIST_YEAR }
2 |
3 | int calculateYearEra(EraMode? era, int christYear) {
4 | if (era == EraMode.BUDDHIST_YEAR) {
5 | return christYear + 543;
6 | }
7 | return christYear;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/src/flutter_rounded_button_action.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 |
3 | class FlutterRoundedButtonAction extends StatelessWidget {
4 | final String? textButtonNegative;
5 | final String? textButtonPositive;
6 | final String? textActionButton;
7 | final VoidCallback? onTapButtonNegative; // Default is "Cancel" button.
8 | final VoidCallback? onTapButtonPositive; // Default is "OK" button.
9 | final VoidCallback? onTapButtonAction; // Default is "Action" button which will be on the left.
10 | final TextStyle? textStyleButtonAction;
11 | final TextStyle? textStyleButtonPositive;
12 | final TextStyle? textStyleButtonNegative;
13 | final MaterialLocalizations localizations;
14 | final double borderRadius;
15 | final EdgeInsets? paddingActionBar;
16 | final Color? background;
17 |
18 | const FlutterRoundedButtonAction(
19 | {Key? key,
20 | required this.localizations,
21 | this.textButtonNegative,
22 | this.textButtonPositive,
23 | this.textActionButton,
24 | this.onTapButtonAction,
25 | this.onTapButtonPositive,
26 | this.onTapButtonNegative,
27 | this.textStyleButtonPositive,
28 | this.textStyleButtonNegative,
29 | this.textStyleButtonAction,
30 | required this.borderRadius,
31 | this.paddingActionBar,
32 | this.background})
33 | : super(key: key);
34 |
35 | List _buildActionsButton() {
36 | final Widget negativeButton = TextButton(
37 | child: Text(
38 | textButtonNegative ?? localizations.cancelButtonLabel,
39 | style: textStyleButtonNegative,
40 | ),
41 | onPressed: onTapButtonNegative,
42 | );
43 |
44 | final Widget positiveButton = TextButton(
45 | child: Text(
46 | textButtonPositive ?? localizations.okButtonLabel,
47 | style: textStyleButtonPositive,
48 | ),
49 | onPressed: onTapButtonPositive,
50 | );
51 |
52 | if (textActionButton != null) {
53 | final Widget leftButton = TextButton(
54 | child: Text(textActionButton!, style: textStyleButtonAction),
55 | onPressed: onTapButtonAction,
56 | );
57 | return [
58 | leftButton,
59 | Row(children: [negativeButton, positiveButton])
60 | ];
61 | }
62 |
63 | return [negativeButton, positiveButton];
64 | }
65 |
66 | @override
67 | Widget build(BuildContext context) {
68 | Orientation orientation = MediaQuery.of(context).orientation;
69 | return Container(
70 | padding: paddingActionBar,
71 | decoration: BoxDecoration(
72 | color: background,
73 | borderRadius:
74 | orientation == Orientation.landscape ? BorderRadius.only(bottomRight: Radius.circular(borderRadius)) : BorderRadius.vertical(bottom: Radius.circular(borderRadius))),
75 | child: ButtonBar(
76 | alignment: textActionButton != null ? MainAxisAlignment.spaceBetween : MainAxisAlignment.end,
77 | children: _buildActionsButton(),
78 | ),
79 | );
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/lib/src/flutter_rounded_date_picker_widget.dart:
--------------------------------------------------------------------------------
1 | // Copyright 2015 The Chromium Authors. All rights reserved.
2 | // Use of this source code is governed by a BSD-style license that can be
3 | // found in the LICENSE file.
4 |
5 | import 'dart:async';
6 |
7 | import 'package:flutter/material.dart';
8 | import 'package:flutter_rounded_date_picker/src/dialogs/flutter_rounded_date_picker_dialog.dart';
9 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
10 | import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
11 | import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
12 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
13 |
14 | // Examples can assume:
15 | // BuildContext context;
16 |
17 | /// Initial display mode of the date picker dialog.
18 | ///
19 | /// Date picker UI mode for either showing a list of available years or a
20 | /// monthly calendar initially in the dialog shown by calling [showDatePicker].
21 | ///
22 |
23 | // Shows the selected date in large font and toggles between year and day mode
24 |
25 | /// Signature for predicating dates for enabled date selections.
26 | ///
27 | /// See [showDatePicker].
28 | typedef SelectableDayPredicate = bool Function(DateTime day);
29 |
30 | /// Shows a dialog containing a material design date picker.
31 | ///
32 | /// The returned [Future] resolves to the date selected by the user when the
33 | /// user closes the dialog. If the user cancels the dialog, null is returned.
34 | ///
35 | /// An optional [selectableDayPredicate] function can be passed in to customize
36 | /// the days to enable for selection. If provided, only the days that
37 | /// [selectableDayPredicate] returned true for will be selectable.
38 | ///
39 | /// An optional [initialDatePickerMode] argument can be used to display the
40 | /// date picker initially in the year or month+day picker mode. It defaults
41 | /// to month+day, and must not be null.
42 | ///
43 | /// An optional [locale] argument can be used to set the locale for the date
44 | /// picker. It defaults to the ambient locale provided by [Localizations].
45 | ///
46 | /// An optional [textDirection] argument can be used to set the text direction
47 | /// (RTL or LTR) for the date picker. It defaults to the ambient text direction
48 | /// provided by [Directionality]. If both [locale] and [textDirection] are not
49 | /// null, [textDirection] overrides the direction chosen for the [locale].
50 | ///
51 | /// The [context] argument is passed to [showDialog], the documentation for
52 | /// which discusses how it is used.
53 | ///
54 | /// The [builder] parameter can be used to wrap the dialog widget
55 | /// to add inherited widgets like [Theme].
56 | ///
57 | /// {@tool sample}
58 | /// Show a date picker with the dark theme.
59 | ///
60 | /// ```dart
61 | /// Future selectedDate = showDatePicker(
62 | /// context: context,
63 | /// initialDate: DateTime.now(),
64 | /// firstDate: DateTime(2018),
65 | /// lastDate: DateTime(2030),
66 | /// builder: (BuildContext context, Widget child) {
67 | /// return Theme(
68 | /// data: ThemeData.dark(),
69 | /// child: child,
70 | /// );
71 | /// },
72 | /// );
73 | /// ```
74 | /// {@end-tool}
75 | ///
76 | /// The [context], [initialDate], [firstDate], and [lastDate] parameters must
77 | /// not be null.
78 | ///
79 | /// See also:
80 | ///
81 | /// * [showTimePicker], which shows a dialog that contains a material design
82 | /// time picker.
83 | /// * [DayPicker], which displays the days of a given month and allows
84 | /// choosing a day.
85 | /// * [MonthPicker], which displays a scrollable list of months to allow
86 | /// picking a month.
87 | /// * [YearPicker], which displays a scrollable list of years to allow picking
88 | /// a year.
89 | ///
90 |
91 | Future showRoundedDatePicker(
92 | {required BuildContext context,
93 | double? height,
94 | DateTime? initialDate,
95 | DateTime? firstDate,
96 | DateTime? lastDate,
97 | SelectableDayPredicate? selectableDayPredicate,
98 | DatePickerMode initialDatePickerMode = DatePickerMode.day,
99 | Locale? locale,
100 | TextDirection? textDirection,
101 | ThemeData? theme,
102 | double borderRadius = 16,
103 | EraMode era = EraMode.CHRIST_YEAR,
104 | ImageProvider? imageHeader,
105 | String description = "",
106 | String? fontFamily,
107 | bool barrierDismissible = false,
108 | Color background = Colors.transparent,
109 | String? textNegativeButton,
110 | String? textPositiveButton,
111 | String? textActionButton,
112 | VoidCallback? onTapActionButton,
113 | MaterialRoundedDatePickerStyle? styleDatePicker,
114 | MaterialRoundedYearPickerStyle? styleYearPicker,
115 | List? customWeekDays,
116 | BuilderDayOfDatePicker? builderDay,
117 | List? listDateDisabled,
118 | OnTapDay? onTapDay,
119 | Function? onMonthChange}) async {
120 | initialDate ??= DateTime.now();
121 | firstDate ??= DateTime(initialDate.year - 1);
122 | lastDate ??= DateTime(initialDate.year + 1);
123 | theme ??= ThemeData();
124 |
125 | assert(
126 | !initialDate.isBefore(firstDate),
127 | 'initialDate must be on or after firstDate',
128 | );
129 | assert(
130 | !initialDate.isAfter(lastDate),
131 | 'initialDate must be on or before lastDate',
132 | );
133 | assert(
134 | !firstDate.isAfter(lastDate),
135 | 'lastDate must be on or after firstDate',
136 | );
137 | assert(
138 | selectableDayPredicate == null || selectableDayPredicate(initialDate),
139 | 'Provided initialDate must satisfy provided selectableDayPredicate',
140 | );
141 | assert(
142 | (onTapActionButton != null && textActionButton != null) ||
143 | onTapActionButton == null,
144 | "If you provide onLeftBtn, you must provide leftBtn",
145 | );
146 | assert(debugCheckHasMaterialLocalizations(context));
147 |
148 | Widget child = GestureDetector(
149 | onTap: () {
150 | if (!barrierDismissible) {
151 | Navigator.pop(context);
152 | }
153 | },
154 | child: Container(
155 | color: background,
156 | child: GestureDetector(
157 | onTap: () {
158 | //
159 | },
160 | child: FlutterRoundedDatePickerDialog(
161 | height: height,
162 | initialDate: initialDate,
163 | firstDate: firstDate,
164 | lastDate: lastDate,
165 | selectableDayPredicate: selectableDayPredicate,
166 | initialDatePickerMode: initialDatePickerMode,
167 | era: era,
168 | locale: locale,
169 | borderRadius: borderRadius,
170 | imageHeader: imageHeader,
171 | description: description,
172 | fontFamily: fontFamily,
173 | textNegativeButton: textNegativeButton,
174 | textPositiveButton: textPositiveButton,
175 | textActionButton: textActionButton,
176 | onTapActionButton: onTapActionButton,
177 | styleDatePicker: styleDatePicker,
178 | styleYearPicker: styleYearPicker,
179 | customWeekDays: customWeekDays,
180 | builderDay: builderDay,
181 | listDateDisabled: listDateDisabled,
182 | onTapDay: onTapDay,
183 | onMonthChange: onMonthChange,
184 | ),
185 | ),
186 | ),
187 | );
188 |
189 | if (textDirection != null) {
190 | child = Directionality(
191 | textDirection: textDirection,
192 | child: child,
193 | );
194 | }
195 |
196 | if (locale != null) {
197 | child = Localizations.override(
198 | context: context,
199 | locale: locale,
200 | child: child,
201 | );
202 | }
203 |
204 | return await showDialog(
205 | context: context,
206 | barrierDismissible: barrierDismissible,
207 | builder: (_) => Theme(data: theme!, child: child),
208 | );
209 | }
210 |
--------------------------------------------------------------------------------
/lib/src/material_rounded_date_picker_custom_Action_design_style.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class MaterialRoundedDatePickerStyle {
4 | TextStyle? textStyleYearButton;
5 | TextStyle? textStyleDayButton;
6 | TextStyle? textStyleDayHeader;
7 | TextStyle? textStyleDayOnCalendar;
8 | TextStyle? textStyleDayOnCalendarSelected;
9 | TextStyle? textStyleDayOnCalendarDisabled;
10 | TextStyle? textStyleCurrentDayOnCalendar;
11 | TextStyle? textStyleMonthYearHeader;
12 | EdgeInsets? paddingDatePicker;
13 | EdgeInsets? paddingMonthHeader;
14 | EdgeInsets? paddingActionBar;
15 | EdgeInsets? paddingDateYearHeader;
16 | double? sizeArrow;
17 | double? marginTopArrowPrevious;
18 | double? marginLeftArrowPrevious;
19 | double? marginTopArrowNext;
20 | double? marginRightArrowNext;
21 | BoxDecoration? decorationDateSelected;
22 | Color? colorArrowPrevious;
23 | Color? colorArrowNext;
24 | Color? backgroundPicker;
25 | Color? backgroundActionBar;
26 | Color? backgroundHeader;
27 | Color? backgroundHeaderMonth;
28 | // ButtonStyle? textStyleButtonPositive;
29 | // ButtonStyle? textStyleButtonNegative;
30 | // ButtonStyle? textStyleButtonAction;
31 |
32 | MaterialRoundedDatePickerStyle({
33 | this.textStyleYearButton,
34 | this.textStyleDayButton,
35 | this.textStyleDayHeader,
36 | this.textStyleDayOnCalendar,
37 | this.textStyleCurrentDayOnCalendar,
38 | this.textStyleDayOnCalendarSelected,
39 | this.textStyleDayOnCalendarDisabled,
40 | this.textStyleMonthYearHeader,
41 | this.paddingDatePicker,
42 | this.paddingActionBar,
43 | this.paddingMonthHeader,
44 | this.paddingDateYearHeader,
45 | this.sizeArrow,
46 | this.marginRightArrowNext,
47 | this.marginTopArrowNext,
48 | this.marginLeftArrowPrevious,
49 | this.marginTopArrowPrevious,
50 | // this.textStyleButtonNegative,
51 | // this.textStyleButtonPositive,
52 | // this.textStyleButtonAction,
53 | this.decorationDateSelected,
54 | this.colorArrowNext,
55 | this.colorArrowPrevious,
56 | this.backgroundActionBar,
57 | this.backgroundPicker,
58 | this.backgroundHeader,
59 | this.backgroundHeaderMonth,
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/lib/src/material_rounded_date_picker_style.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class MaterialRoundedDatePickerStyle {
4 | TextStyle? textStyleYearButton;
5 | TextStyle? textStyleDayButton;
6 | TextStyle? textStyleDayHeader;
7 | TextStyle? textStyleDayOnCalendar;
8 | TextStyle? textStyleDayOnCalendarSelected;
9 | TextStyle? textStyleDayOnCalendarDisabled;
10 | TextStyle? textStyleCurrentDayOnCalendar;
11 | TextStyle? textStyleMonthYearHeader;
12 | EdgeInsets? paddingDatePicker;
13 | EdgeInsets? paddingMonthHeader;
14 | EdgeInsets? paddingActionBar;
15 | EdgeInsets? paddingDateYearHeader;
16 | double? sizeArrow;
17 | double? marginTopArrowPrevious;
18 | double? marginLeftArrowPrevious;
19 | double? marginTopArrowNext;
20 | double? marginRightArrowNext;
21 | BoxDecoration? decorationDateSelected;
22 | Color? colorArrowPrevious;
23 | Color? colorArrowNext;
24 | Color? backgroundPicker;
25 | Color? backgroundActionBar;
26 | Color? backgroundHeader;
27 | Color? backgroundHeaderMonth;
28 | TextStyle? textStyleButtonPositive;
29 | TextStyle? textStyleButtonNegative;
30 | TextStyle? textStyleButtonAction;
31 |
32 | MaterialRoundedDatePickerStyle({
33 | this.textStyleYearButton,
34 | this.textStyleDayButton,
35 | this.textStyleDayHeader,
36 | this.textStyleDayOnCalendar,
37 | this.textStyleCurrentDayOnCalendar,
38 | this.textStyleDayOnCalendarSelected,
39 | this.textStyleDayOnCalendarDisabled,
40 | this.textStyleMonthYearHeader,
41 | this.paddingDatePicker,
42 | this.paddingActionBar,
43 | this.paddingMonthHeader,
44 | this.paddingDateYearHeader,
45 | this.sizeArrow,
46 | this.marginRightArrowNext,
47 | this.marginTopArrowNext,
48 | this.marginLeftArrowPrevious,
49 | this.marginTopArrowPrevious,
50 | this.textStyleButtonNegative,
51 | this.textStyleButtonPositive,
52 | this.textStyleButtonAction,
53 | this.decorationDateSelected,
54 | this.colorArrowNext,
55 | this.colorArrowPrevious,
56 | this.backgroundActionBar,
57 | this.backgroundPicker,
58 | this.backgroundHeader,
59 | this.backgroundHeaderMonth,
60 | });
61 | }
62 |
--------------------------------------------------------------------------------
/lib/src/material_rounded_year_picker_style.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/cupertino.dart';
2 |
3 | class MaterialRoundedYearPickerStyle {
4 | TextStyle? textStyleYear;
5 | TextStyle? textStyleYearSelected;
6 | double? heightYearRow;
7 | Color? backgroundPicker;
8 |
9 | MaterialRoundedYearPickerStyle({this.textStyleYear, this.textStyleYearSelected, this.heightYearRow, this.backgroundPicker});
10 | }
11 |
--------------------------------------------------------------------------------
/lib/src/thai_date_utils.dart:
--------------------------------------------------------------------------------
1 | class ThaiDateUtils {
2 | static const List MONTH_FULL_TH = [
3 | "มกราคม",
4 | "กุมภาพันธ์",
5 | "มีนาคม",
6 | "เมษายน",
7 | "พฤษภาคม",
8 | "มิถุนายน",
9 | "กรกฎาคม",
10 | "สิงหาคม",
11 | "กันยายน",
12 | "ตุลาคม",
13 | "พฤศจิกายน",
14 | "ธันวาคม",
15 | ];
16 |
17 | static const List MONTH_SHORT_TH = [
18 | "ม.ค.",
19 | "ก.พ.",
20 | "มี.ค.",
21 | "เม.ย.",
22 | "พ.ค.",
23 | "มิ.ย.",
24 | "ก.ค.",
25 | "ส.ค.",
26 | "ก.ย.",
27 | "ต.ค.",
28 | "พ.ย.",
29 | "ธ.ค.",
30 | ];
31 |
32 | static getMonthNameShot(int month) {
33 | return MONTH_SHORT_TH[month - 1];
34 | }
35 |
36 | static getMonthNameFull(int month) {
37 | return MONTH_FULL_TH[month - 1];
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/lib/src/widgets/flutter_rounded_date_picker_header.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/material.dart';
2 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
3 | import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
4 |
5 | class FlutterRoundedDatePickerHeader extends StatelessWidget {
6 | const FlutterRoundedDatePickerHeader(
7 | {Key? key,
8 | required this.selectedDate,
9 | required this.mode,
10 | required this.onModeChanged,
11 | required this.orientation,
12 | required this.era,
13 | required this.borderRadius,
14 | this.imageHeader,
15 | this.description = "",
16 | this.fontFamily,
17 | this.style})
18 | : super(key: key);
19 |
20 | final DateTime selectedDate;
21 | final DatePickerMode mode;
22 | final ValueChanged onModeChanged;
23 | final Orientation orientation;
24 | final MaterialRoundedDatePickerStyle? style;
25 |
26 | /// Era custom
27 | final EraMode era;
28 |
29 | /// Border
30 | final double borderRadius;
31 |
32 | /// Header
33 | final ImageProvider? imageHeader;
34 |
35 | /// Header description
36 | final String description;
37 |
38 | /// Font
39 | final String? fontFamily;
40 |
41 | void _handleChangeMode(DatePickerMode value) {
42 | if (value != mode) onModeChanged(value);
43 | }
44 |
45 | @override
46 | Widget build(BuildContext context) {
47 | final MaterialLocalizations localizations =
48 | MaterialLocalizations.of(context);
49 | final ThemeData themeData = Theme.of(context);
50 | final TextTheme headerTextTheme = themeData.primaryTextTheme;
51 | Color? dayColor;
52 | Color? yearColor;
53 | switch (themeData.brightness) {
54 | case Brightness.light:
55 | dayColor = mode == DatePickerMode.day ? Colors.black87 : Colors.black54;
56 | yearColor =
57 | mode == DatePickerMode.year ? Colors.black87 : Colors.black54;
58 | break;
59 | case Brightness.dark:
60 | dayColor = mode == DatePickerMode.day ? Colors.white : Colors.white70;
61 | yearColor = mode == DatePickerMode.year ? Colors.white : Colors.white70;
62 | break;
63 | }
64 |
65 | if (style?.textStyleDayButton?.color != null) {
66 | style?.textStyleDayButton = style?.textStyleDayButton
67 | ?.copyWith(color: style?.textStyleDayButton?.color ?? dayColor);
68 | }
69 |
70 | if (style?.textStyleDayButton?.fontFamily != null) {
71 | style?.textStyleDayButton =
72 | style?.textStyleDayButton?.copyWith(fontFamily: fontFamily);
73 | }
74 |
75 | final TextStyle dayStyle = style?.textStyleDayButton ??
76 | headerTextTheme.headlineMedium!
77 | .copyWith(color: dayColor, fontFamily: fontFamily);
78 | final TextStyle yearStyle = style?.textStyleYearButton ??
79 | headerTextTheme.titleMedium!
80 | .copyWith(color: yearColor, fontFamily: fontFamily);
81 |
82 | Color? backgroundColor;
83 | if (style?.backgroundHeader != null) {
84 | backgroundColor = style?.backgroundHeader;
85 | } else {
86 | switch (themeData.brightness) {
87 | case Brightness.dark:
88 | backgroundColor = themeData.colorScheme.background;
89 | break;
90 | case Brightness.light:
91 | backgroundColor = themeData.primaryColor;
92 | break;
93 | }
94 | }
95 |
96 | EdgeInsets padding;
97 | MainAxisAlignment mainAxisAlignment;
98 | switch (orientation) {
99 | case Orientation.landscape:
100 | padding = style?.paddingDateYearHeader ?? EdgeInsets.all(8.0);
101 | mainAxisAlignment = MainAxisAlignment.start;
102 | break;
103 | case Orientation.portrait:
104 | default:
105 | padding = style?.paddingDateYearHeader ?? EdgeInsets.all(16.0);
106 | mainAxisAlignment = MainAxisAlignment.center;
107 | break;
108 | }
109 |
110 | final Widget yearButton = IgnorePointer(
111 | ignoring: mode != DatePickerMode.day,
112 | ignoringSemantics: false,
113 | child: _DateHeaderButton(
114 | color: Colors.transparent,
115 | onTap: Feedback.wrapForTap(
116 | () => _handleChangeMode(DatePickerMode.year),
117 | context,
118 | ),
119 | child: Semantics(
120 | selected: mode == DatePickerMode.year,
121 | child: Text(
122 | "${calculateYearEra(era, selectedDate.year)}",
123 | style: yearStyle,
124 | ),
125 | ),
126 | ),
127 | );
128 |
129 | final Widget dayButton = IgnorePointer(
130 | ignoring: mode == DatePickerMode.day,
131 | ignoringSemantics: false,
132 | child: _DateHeaderButton(
133 | color: Colors.transparent,
134 | onTap: Feedback.wrapForTap(
135 | () => _handleChangeMode(DatePickerMode.day),
136 | context,
137 | ),
138 | child: Semantics(
139 | selected: mode == DatePickerMode.day,
140 | child: Text(
141 | localizations.formatMediumDate(selectedDate),
142 | textScaleFactor: 1,
143 | style: dayStyle,
144 | ),
145 | ),
146 | ),
147 | );
148 |
149 | BorderRadius borderRadiusData = BorderRadius.only(
150 | topLeft: Radius.circular(borderRadius),
151 | topRight: Radius.circular(borderRadius),
152 | );
153 |
154 | if (orientation == Orientation.landscape) {
155 | borderRadiusData = BorderRadius.only(
156 | topLeft: Radius.circular(borderRadius),
157 | bottomLeft: Radius.circular(borderRadius),
158 | );
159 | }
160 |
161 | return Container(
162 | decoration: BoxDecoration(
163 | image: imageHeader != null
164 | ? DecorationImage(image: imageHeader!, fit: BoxFit.cover)
165 | : null,
166 | color: backgroundColor,
167 | borderRadius: borderRadiusData,
168 | ),
169 | padding: padding,
170 | child: Column(
171 | mainAxisAlignment: mainAxisAlignment,
172 | crossAxisAlignment: CrossAxisAlignment.start,
173 | children: [
174 | yearButton,
175 | dayButton,
176 | const SizedBox(height: 4.0),
177 | Visibility(
178 | visible: description.isNotEmpty,
179 | child: Padding(
180 | padding: EdgeInsets.symmetric(horizontal: 12),
181 | child: Text(
182 | description,
183 | style: TextStyle(
184 | color: yearColor,
185 | fontSize: 12,
186 | fontFamily: fontFamily,
187 | ),
188 | ),
189 | ),
190 | )
191 | ],
192 | ),
193 | );
194 | }
195 | }
196 |
197 | class _DateHeaderButton extends StatelessWidget {
198 | const _DateHeaderButton({
199 | Key? key,
200 | this.onTap,
201 | this.color,
202 | this.child,
203 | }) : super(key: key);
204 |
205 | final VoidCallback? onTap;
206 | final Color? color;
207 | final Widget? child;
208 |
209 | @override
210 | Widget build(BuildContext context) {
211 | final ThemeData theme = Theme.of(context);
212 |
213 | return Material(
214 | type: MaterialType.button,
215 | color: color,
216 | child: InkWell(
217 | borderRadius: kMaterialEdges[MaterialType.button],
218 | highlightColor: theme.highlightColor,
219 | splashColor: theme.splashColor,
220 | onTap: onTap,
221 | child: Container(
222 | padding: const EdgeInsets.symmetric(horizontal: 8.0),
223 | child: child,
224 | ),
225 | ),
226 | );
227 | }
228 | }
229 |
--------------------------------------------------------------------------------
/lib/src/widgets/flutter_rounded_day_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter/rendering.dart';
4 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
5 | import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
6 | import 'package:flutter_rounded_date_picker/src/thai_date_utils.dart';
7 | import 'dart:math' as math;
8 |
9 | /// Displays the days of a given month and allows choosing a day.
10 | ///
11 | /// The days are arranged in a rectangular grid with one column for each day of
12 | /// the week.
13 | ///
14 | /// The day picker widget is rarely used directly. Instead, consider using
15 | /// [showDatePicker], which creates a date picker dialog.
16 | ///
17 | /// See also:
18 | ///
19 | /// * [showDatePicker], which shows a dialog that contains a material design
20 | /// date picker.
21 | /// * [showTimePicker], which shows a dialog that contains a material design
22 | /// time picker.
23 | ///
24 |
25 | const _DayPickerGridDelegate _kDayPickerGridDelegate = _DayPickerGridDelegate();
26 | const double _kDayPickerRowHeight = 42.0;
27 | const int _kMaxDayPickerRowCount = 6; // A 31 day month that starts on Saturday.
28 |
29 | typedef BuilderDayOfDatePicker = Widget Function(DateTime dateTime,
30 | bool isCurrentDay, bool selected, TextStyle defaultTextStyle);
31 | typedef OnTapDay = bool Function(DateTime dateTime, bool available);
32 |
33 | class _DayPickerGridDelegate extends SliverGridDelegate {
34 | const _DayPickerGridDelegate();
35 |
36 | @override
37 | SliverGridLayout getLayout(SliverConstraints constraints) {
38 | const int columnCount = DateTime.daysPerWeek;
39 | final double tileWidth = constraints.crossAxisExtent / columnCount;
40 | final double viewTileHeight =
41 | constraints.viewportMainAxisExtent / (_kMaxDayPickerRowCount + 1);
42 | final double tileHeight = math.max(_kDayPickerRowHeight, viewTileHeight);
43 |
44 | return SliverGridRegularTileLayout(
45 | crossAxisCount: columnCount,
46 | mainAxisStride: tileHeight,
47 | crossAxisStride: tileWidth,
48 | childMainAxisExtent: tileHeight,
49 | childCrossAxisExtent: tileWidth,
50 | reverseCrossAxis: axisDirectionIsReversed(constraints.crossAxisDirection),
51 | );
52 | }
53 |
54 | @override
55 | bool shouldRelayout(_DayPickerGridDelegate oldDelegate) => false;
56 | }
57 |
58 | class FlutterRoundedDayPicker extends StatelessWidget {
59 | /// Creates a day picker.
60 | ///
61 | /// Rarely used directly. Instead, typically used as part of a [MonthPicker].
62 | FlutterRoundedDayPicker(
63 | {Key? key,
64 | required this.selectedDate,
65 | required this.currentDate,
66 | required this.onChanged,
67 | required this.firstDate,
68 | required this.lastDate,
69 | required this.displayedMonth,
70 | this.selectableDayPredicate,
71 | this.dragStartBehavior = DragStartBehavior.start,
72 | required this.era,
73 | this.locale,
74 | this.fontFamily,
75 | required this.borderRadius,
76 | this.style,
77 | this.customWeekDays,
78 | this.builderDay,
79 | this.listDateDisabled,
80 | this.onTapDay})
81 | : assert(!firstDate.isAfter(lastDate)),
82 | // assert(selectedDate.isAfter(firstDate) || selectedDate.isAtSameMomentAs(firstDate)),
83 | super(key: key);
84 |
85 | /// The currently selected date.
86 | ///
87 | /// This date is highlighted in the picker.
88 | final DateTime selectedDate;
89 |
90 | /// The current date at the time the picker is displayed.
91 | final DateTime currentDate;
92 |
93 | /// Called when the user picks a day.
94 | final ValueChanged onChanged;
95 |
96 | /// The earliest date the user is permitted to pick.
97 | final DateTime firstDate;
98 |
99 | /// The latest date the user is permitted to pick.
100 | final DateTime lastDate;
101 |
102 | /// The month whose days are displayed by this picker.
103 | final DateTime displayedMonth;
104 |
105 | /// Optional user supplied predicate function to customize selectable days.
106 | final SelectableDayPredicate? selectableDayPredicate;
107 |
108 | final EraMode era;
109 | final Locale? locale;
110 |
111 | final String? fontFamily;
112 |
113 | final double borderRadius;
114 | final MaterialRoundedDatePickerStyle? style;
115 | final List? customWeekDays;
116 | final BuilderDayOfDatePicker? builderDay;
117 | final List? listDateDisabled;
118 | final OnTapDay? onTapDay;
119 |
120 | /// Determines the way that drag start behavior is handled.
121 | ///
122 | /// If set to [DragStartBehavior.start], the drag gesture used to scroll a
123 | /// date picker wheel will begin upon the detection of a drag gesture. If set
124 | /// to [DragStartBehavior.down] it will begin when a down event is first
125 | /// detected.
126 | ///
127 | /// In general, setting this to [DragStartBehavior.start] will make drag
128 | /// animation smoother and setting it to [DragStartBehavior.down] will make
129 | /// drag behavior feel slightly more reactive.
130 | ///
131 | /// By default, the drag start behavior is [DragStartBehavior.start].
132 | ///
133 | /// See also:
134 | ///
135 | /// * [DragGestureRecognizer.dragStartBehavior], which gives an example for the different behaviors.
136 | final DragStartBehavior dragStartBehavior;
137 |
138 | /// Builds widgets showing abbreviated days of week. The first widget in the
139 | /// returned list corresponds to the first day of week for the current locale.
140 | ///
141 | /// Examples:
142 | ///
143 | /// ```
144 | /// ┌ Sunday is the first day of week in the US (en_US)
145 | /// |
146 | /// S M T W T F S <-- the returned list contains these widgets
147 | /// _ _ _ _ _ 1 2
148 | /// 3 4 5 6 7 8 9
149 | ///
150 | /// ┌ But it's Monday in the UK (en_GB)
151 | /// |
152 | /// M T W T F S S <-- the returned list contains these widgets
153 | /// _ _ _ _ 1 2 3
154 | /// 4 5 6 7 8 9 10
155 | /// ```
156 | List _getDayHeaders(
157 | TextStyle? headerStyle,
158 | MaterialLocalizations localizations,
159 | ) {
160 | final List result = [];
161 | if (customWeekDays != null) {
162 | for (int i = 0; i < 7; i++) {
163 | result.add(ExcludeSemantics(
164 | child: Center(
165 | child: Text(
166 | i < customWeekDays!.length ? customWeekDays![i] : "",
167 | style: headerStyle,
168 | )),
169 | ));
170 | }
171 | } else {
172 | for (int i = localizations.firstDayOfWeekIndex; true; i = (i + 1) % 7) {
173 | final String weekday = localizations.narrowWeekdays[i];
174 | result.add(ExcludeSemantics(
175 | child: Center(
176 | child: Text(
177 | weekday,
178 | style: headerStyle,
179 | )),
180 | ));
181 | if (i == (localizations.firstDayOfWeekIndex - 1) % 7) break;
182 | }
183 | }
184 |
185 | return result;
186 | }
187 |
188 | // Do not use this directly - call getDaysInMonth instead.
189 | static const List _daysInMonth = [
190 | 31,
191 | -1,
192 | 31,
193 | 30,
194 | 31,
195 | 30,
196 | 31,
197 | 31,
198 | 30,
199 | 31,
200 | 30,
201 | 31,
202 | ];
203 |
204 | /// Returns the number of days in a month, according to the proleptic
205 | /// Gregorian calendar.
206 | ///
207 | /// This applies the leap year logic introduced by the Gregorian reforms of
208 | /// 1582. It will not give valid results for dates prior to that time.
209 | static int getDaysInMonth(int year, int month) {
210 | if (month == DateTime.february) {
211 | final bool isLeapYear =
212 | (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
213 | if (isLeapYear) return 29;
214 | return 28;
215 | }
216 | return _daysInMonth[month - 1];
217 | }
218 |
219 | /// Computes the offset from the first day of week that the first day of the
220 | /// [month] falls on.
221 | ///
222 | /// For example, September 1, 2017 falls on a Friday, which in the calendar
223 | /// localized for United States English appears as:
224 | ///
225 | /// ```
226 | /// S M T W T F S
227 | /// _ _ _ _ _ 1 2
228 | /// ```
229 | ///
230 | /// The offset for the first day of the months is the number of leading blanks
231 | /// in the calendar, i.e. 5.
232 | ///
233 | /// The same date localized for the Russian calendar has a different offset,
234 | /// because the first day of week is Monday rather than Sunday:
235 | ///
236 | /// ```
237 | /// M T W T F S S
238 | /// _ _ _ _ 1 2 3
239 | /// ```
240 | ///
241 | /// So the offset is 4, rather than 5.
242 | ///
243 | /// This code consolidates the following:
244 | ///
245 | /// - [DateTime.weekday] provides a 1-based index into days of week, with 1
246 | /// falling on Monday.
247 | /// - [MaterialLocalizations.firstDayOfWeekIndex] provides a 0-based index
248 | /// into the [MaterialLocalizations.narrowWeekdays] list.
249 | /// - [MaterialLocalizations.narrowWeekdays] list provides localized names of
250 | /// days of week, always starting with Sunday and ending with Saturday.
251 | int _computeFirstDayOffset(
252 | int year, int month, MaterialLocalizations localizations) {
253 | // 0-based day of week, with 0 representing Monday.
254 | final int weekdayFromMonday = DateTime(year, month).weekday - 1;
255 | // 0-based day of week, with 0 representing Sunday.
256 | final int firstDayOfWeekFromSunday = localizations.firstDayOfWeekIndex;
257 | // firstDayOfWeekFromSunday recomputed to be Monday-based
258 | final int firstDayOfWeekFromMonday = (firstDayOfWeekFromSunday - 1) % 7;
259 | // Number of days between the first day of week appearing on the calendar,
260 | // and the day corresponding to the 1-st of the month.
261 | return (weekdayFromMonday - firstDayOfWeekFromMonday) % 7;
262 | }
263 |
264 | @override
265 | Widget build(BuildContext context) {
266 | Orientation orientation = MediaQuery.of(context).orientation;
267 | final ThemeData themeData = Theme.of(context);
268 | final MaterialLocalizations localizations =
269 | MaterialLocalizations.of(context);
270 | final int year = displayedMonth.year;
271 | final int month = displayedMonth.month;
272 | final int daysInMonth = getDaysInMonth(year, month);
273 | final int firstDayOffset = _computeFirstDayOffset(
274 | year,
275 | month,
276 | localizations,
277 | );
278 |
279 | final List labels = _getDayHeaders(
280 | style?.textStyleDayHeader ?? themeData.textTheme.bodySmall,
281 | localizations);
282 | for (int i = 0; true; i += 1) {
283 | // 1-based day of month, e.g. 1-31 for January, and 1-29 for February on
284 | // a leap year.
285 | final int day = i - firstDayOffset + 1;
286 | if (day > daysInMonth) break;
287 | if (day < 1) {
288 | labels.add(Container());
289 | } else {
290 | final DateTime dayToBuild = DateTime(year, month, day);
291 | bool disabled = dayToBuild.isAfter(lastDate) ||
292 | dayToBuild.isBefore(firstDate) ||
293 | (selectableDayPredicate != null &&
294 | !selectableDayPredicate!(dayToBuild));
295 |
296 | if (listDateDisabled != null) {
297 | for (DateTime dt in listDateDisabled!) {
298 | if (dt.day == day && dt.month == month && dt.year == year) {
299 | disabled = true;
300 | break;
301 | }
302 | }
303 | }
304 |
305 | BoxDecoration? decoration;
306 | TextStyle itemStyle = style?.textStyleDayOnCalendar ??
307 | themeData.textTheme.bodyMedium!.copyWith(
308 | fontFamily: fontFamily,
309 | );
310 |
311 | final bool isSelectedDay = selectedDate.year == year &&
312 | selectedDate.month == month &&
313 | selectedDate.day == day;
314 | final bool isCurrentDay = currentDate.year == year &&
315 | currentDate.month == month &&
316 | currentDate.day == day;
317 | if (isSelectedDay) {
318 | // The selected day gets a circle background highlight, and a contrasting text color.
319 | itemStyle = style?.textStyleDayOnCalendarSelected ??
320 | themeData.textTheme.bodyLarge!.copyWith(
321 | fontFamily: fontFamily,
322 | );
323 | decoration = style?.decorationDateSelected ??
324 | BoxDecoration(
325 | color: themeData.colorScheme.primary,
326 | shape: BoxShape.circle,
327 | );
328 | } else if (disabled) {
329 | itemStyle = style?.textStyleDayOnCalendarDisabled ??
330 | themeData.textTheme.bodyMedium!.copyWith(
331 | color: themeData.disabledColor,
332 | fontFamily: fontFamily,
333 | );
334 | } else if (isCurrentDay) {
335 | // The current day gets a different text color.
336 | itemStyle = style?.textStyleCurrentDayOnCalendar ??
337 | themeData.textTheme.bodyMedium!.copyWith(
338 | color: themeData.colorScheme.primary,
339 | fontFamily: fontFamily,
340 | );
341 | }
342 | Widget? dayWidget;
343 | if (builderDay != null) {
344 | dayWidget =
345 | builderDay!(dayToBuild, isCurrentDay, isSelectedDay, itemStyle);
346 | }
347 |
348 | dayWidget = dayWidget ??
349 | Container(
350 | decoration: decoration,
351 | child: Center(
352 | child: Semantics(
353 | // We want the day of month to be spoken first irrespective of the
354 | // locale-specific preferences or TextDirection. This is because
355 | // an accessibility user is more likely to be interested in the
356 | // day of month before the rest of the date, as they are looking
357 | // for the day of month. To do that we prepend day of month to the
358 | // formatted full date.
359 | label:
360 | '${localizations.formatDecimal(day)}, ${localizations.formatFullDate(dayToBuild)}',
361 | selected: isSelectedDay,
362 | sortKey: OrdinalSortKey(day.toDouble()),
363 | child: ExcludeSemantics(
364 | child: Text(
365 | localizations.formatDecimal(day),
366 | style: itemStyle,
367 | ),
368 | ),
369 | ),
370 | ),
371 | );
372 |
373 | dayWidget = GestureDetector(
374 | behavior: HitTestBehavior.opaque,
375 | onTap: () {
376 | bool allow = true;
377 |
378 | if (disabled) {
379 | allow = false;
380 | } else if ((dayToBuild.isAtSameMomentAs(firstDate) ||
381 | dayToBuild.isAfter(firstDate)) &&
382 | (dayToBuild.isAtSameMomentAs(lastDate) ||
383 | dayToBuild.isBefore(lastDate))) {
384 | allow = true;
385 | } else {
386 | allow = false;
387 | }
388 |
389 | if (onTapDay != null) {
390 | allow = onTapDay!(dayToBuild, !disabled);
391 | }
392 |
393 | if (allow) {
394 | onChanged(dayToBuild);
395 | }
396 | },
397 | child: dayWidget,
398 | dragStartBehavior: dragStartBehavior,
399 | );
400 |
401 | labels.add(dayWidget);
402 | }
403 | }
404 |
405 | String monthYearHeader = "";
406 | if (locale != null && locale!.languageCode.toLowerCase() == "th") {
407 | monthYearHeader =
408 | "${ThaiDateUtils.getMonthNameFull(displayedMonth.month)} ${calculateYearEra(era, displayedMonth.year)}";
409 | } else if (era == EraMode.BUDDHIST_YEAR) {
410 | monthYearHeader = localizations.formatMonthYear(displayedMonth);
411 | monthYearHeader = monthYearHeader.replaceAll(RegExp("\\d"), "");
412 | monthYearHeader = monthYearHeader.replaceAll("ค.ศ.", "");
413 | monthYearHeader =
414 | "$monthYearHeader ${calculateYearEra(era, displayedMonth.year)}"
415 | .replaceAll(RegExp(" "), " ");
416 | } else {
417 | monthYearHeader = localizations.formatMonthYear(displayedMonth);
418 | }
419 |
420 | return Padding(
421 | padding: style?.paddingDatePicker ??
422 | EdgeInsets.symmetric(horizontal: 8, vertical: 2),
423 | child: Column(
424 | children: [
425 | Container(
426 | height: 45,
427 | decoration: BoxDecoration(
428 | color: style?.backgroundHeaderMonth,
429 | borderRadius: orientation == Orientation.landscape
430 | ? BorderRadius.only(topRight: Radius.circular(borderRadius))
431 | : null),
432 | padding: style?.paddingMonthHeader,
433 | // height: _kDayPickerRowHeight,
434 | child: Center(
435 | child: ExcludeSemantics(
436 | child: Text(
437 | monthYearHeader,
438 | style: style?.textStyleMonthYearHeader ??
439 | themeData.textTheme.titleMedium!.copyWith(
440 | fontFamily: fontFamily,
441 | ),
442 | ),
443 | ),
444 | ),
445 | ),
446 | Flexible(
447 | child: GridView.custom(
448 | gridDelegate: _kDayPickerGridDelegate,
449 | childrenDelegate: SliverChildListDelegate(
450 | labels,
451 | addRepaintBoundaries: false,
452 | ),
453 | padding: EdgeInsets.zero,
454 | ),
455 | ),
456 | ],
457 | ),
458 | );
459 | }
460 | }
461 |
--------------------------------------------------------------------------------
/lib/src/widgets/flutter_rounded_month_picker.dart:
--------------------------------------------------------------------------------
1 | import 'dart:async';
2 |
3 | import 'package:flutter/gestures.dart';
4 | import 'package:flutter/material.dart';
5 | import 'package:flutter/semantics.dart';
6 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
7 | import 'package:flutter_rounded_date_picker/src/material_rounded_date_picker_style.dart';
8 | import 'package:flutter_rounded_date_picker/src/widgets/flutter_rounded_day_picker.dart';
9 |
10 | /// A scrollable list of months to allow picking a month.
11 | ///
12 | /// Shows the days of each month in a rectangular grid with one column for each
13 | /// day of the week.
14 | ///
15 | /// The month picker widget is rarely used directly. Instead, consider using
16 | /// [showDatePicker], which creates a date picker dialog.
17 | ///
18 | /// See also:
19 | ///
20 | /// * [showDatePicker], which shows a dialog that contains a material design
21 | /// date picker.
22 | /// * [showTimePicker], which shows a dialog that contains a material design
23 | /// time picker.
24 | ///
25 |
26 | const Duration _kMonthScrollDuration = Duration(milliseconds: 200);
27 |
28 | class FlutterRoundedMonthPicker extends StatefulWidget {
29 | /// Creates a month picker.
30 | ///
31 | /// Rarely used directly. Instead, typically used as part of the dialog shown
32 | /// by [showDatePicker].
33 | FlutterRoundedMonthPicker(
34 | {Key? key,
35 | required this.selectedDate,
36 | required this.onChanged,
37 | required this.firstDate,
38 | required this.lastDate,
39 | this.selectableDayPredicate,
40 | this.dragStartBehavior = DragStartBehavior.start,
41 | required this.era,
42 | this.locale,
43 | this.fontFamily,
44 | this.style,
45 | this.borderRadius = 0,
46 | this.customWeekDays,
47 | this.builderDay,
48 | this.listDateDisabled,
49 | this.onTapDay,
50 | this.onMonthChange})
51 | : assert(!firstDate.isAfter(lastDate)),
52 | // assert(selectedDate.isAfter(firstDate) || selectedDate.isAtSameMomentAs(firstDate)),
53 | super(key: key);
54 |
55 | /// The currently selected date.
56 | ///
57 | /// This date is highlighted in the picker.
58 | final DateTime selectedDate;
59 |
60 | /// Called when the user picks a month.
61 | final ValueChanged onChanged;
62 |
63 | /// The earliest date the user is permitted to pick.
64 | final DateTime firstDate;
65 |
66 | /// The latest date the user is permitted to pick.
67 | final DateTime lastDate;
68 |
69 | /// Optional user supplied predicate function to customize selectable days.
70 | final SelectableDayPredicate? selectableDayPredicate;
71 |
72 | /// {@macro flutter.widgets.scrollable.dragStartBehavior}
73 | final DragStartBehavior dragStartBehavior;
74 |
75 | /// Optional era year.
76 | final EraMode era;
77 | final Locale? locale;
78 |
79 | /// Font
80 | final String? fontFamily;
81 |
82 | /// Style
83 | final MaterialRoundedDatePickerStyle? style;
84 |
85 | final double borderRadius;
86 |
87 | /// Custom Weekday.
88 | final List? customWeekDays;
89 |
90 | final BuilderDayOfDatePicker? builderDay;
91 |
92 | final List? listDateDisabled;
93 | final OnTapDay? onTapDay;
94 |
95 | final Function? onMonthChange;
96 |
97 | @override
98 | _FlutterRoundedMonthPickerState createState() =>
99 | _FlutterRoundedMonthPickerState();
100 | }
101 |
102 | class _FlutterRoundedMonthPickerState extends State
103 | with SingleTickerProviderStateMixin {
104 | static final Animatable _chevronOpacityTween =
105 | Tween(begin: 1.0, end: 0.0)
106 | .chain(CurveTween(curve: Curves.easeInOut));
107 |
108 | @override
109 | void initState() {
110 | super.initState();
111 | // Initially display the pre-selected date.
112 | final int monthPage = _monthDelta(widget.firstDate, widget.selectedDate);
113 | _dayPickerController = PageController(initialPage: monthPage);
114 | _handleMonthPageChanged(monthPage);
115 | _updateCurrentDate();
116 |
117 | // Setup the fade animation for chevrons
118 | _chevronOpacityController = AnimationController(
119 | duration: const Duration(milliseconds: 250),
120 | vsync: this,
121 | );
122 | _chevronOpacityAnimation = _chevronOpacityController.drive(
123 | _chevronOpacityTween,
124 | );
125 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
126 | await _onMonthChange(_currentDisplayedMonthDate);
127 | });
128 | }
129 |
130 | @override
131 | void didUpdateWidget(FlutterRoundedMonthPicker oldWidget) {
132 | super.didUpdateWidget(oldWidget);
133 | if (widget.selectedDate != oldWidget.selectedDate) {
134 | final int monthPage = _monthDelta(widget.firstDate, widget.selectedDate);
135 | _dayPickerController = PageController(initialPage: monthPage);
136 | _handleMonthPageChanged(monthPage);
137 | WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
138 | await _onMonthChange(_currentDisplayedMonthDate);
139 | });
140 | }
141 | }
142 |
143 | late MaterialLocalizations localizations;
144 | late TextDirection textDirection;
145 |
146 | @override
147 | void didChangeDependencies() {
148 | super.didChangeDependencies();
149 | localizations = MaterialLocalizations.of(context);
150 | textDirection = Directionality.of(context);
151 | }
152 |
153 | late DateTime _todayDate;
154 | late DateTime _currentDisplayedMonthDate;
155 | Timer? _timer;
156 | late PageController _dayPickerController;
157 | late AnimationController _chevronOpacityController;
158 | late Animation _chevronOpacityAnimation;
159 |
160 | void _updateCurrentDate() {
161 | _todayDate = DateTime.now();
162 | final DateTime tomorrow =
163 | DateTime(_todayDate.year, _todayDate.month, _todayDate.day + 1);
164 | Duration timeUntilTomorrow = tomorrow.difference(_todayDate);
165 | // so we don't miss it by rounding
166 | timeUntilTomorrow += const Duration(seconds: 1);
167 | _timer?.cancel();
168 | _timer = Timer(timeUntilTomorrow, () {
169 | setState(() => _updateCurrentDate());
170 | });
171 | }
172 |
173 | static int _monthDelta(DateTime startDate, DateTime endDate) {
174 | return (endDate.year - startDate.year) * 12 +
175 | endDate.month -
176 | startDate.month;
177 | }
178 |
179 | /// Add months to a month truncated date.
180 | DateTime _addMonthsToMonthDate(DateTime monthDate, int monthsToAdd) {
181 | return DateTime(
182 | monthDate.year + monthsToAdd ~/ 12,
183 | monthDate.month + monthsToAdd % 12,
184 | );
185 | }
186 |
187 | Widget _buildItems(BuildContext context, int index) {
188 | final DateTime month = _addMonthsToMonthDate(widget.firstDate, index);
189 | return FlutterRoundedDayPicker(
190 | key: ValueKey(month),
191 | selectedDate: widget.selectedDate,
192 | currentDate: _todayDate,
193 | onChanged: widget.onChanged,
194 | firstDate: widget.firstDate,
195 | lastDate: widget.lastDate,
196 | displayedMonth: month,
197 | selectableDayPredicate: widget.selectableDayPredicate,
198 | dragStartBehavior: widget.dragStartBehavior,
199 | era: widget.era,
200 | locale: widget.locale,
201 | fontFamily: widget.fontFamily,
202 | style: widget.style,
203 | borderRadius: widget.borderRadius,
204 | customWeekDays: widget.customWeekDays,
205 | builderDay: widget.builderDay,
206 | listDateDisabled: widget.listDateDisabled,
207 | onTapDay: widget.onTapDay,
208 | );
209 | }
210 |
211 | Future _handleNextMonth() async {
212 | if (!_isDisplayingLastMonth) {
213 | SemanticsService.announce(
214 | localizations.formatMonthYear(_nextMonthDate),
215 | textDirection,
216 | );
217 | _dayPickerController.nextPage(
218 | duration: _kMonthScrollDuration,
219 | curve: Curves.ease,
220 | );
221 | }
222 | }
223 |
224 | Future _handlePreviousMonth() async {
225 | if (!_isDisplayingFirstMonth) {
226 | SemanticsService.announce(
227 | localizations.formatMonthYear(_previousMonthDate),
228 | textDirection,
229 | );
230 | _dayPickerController.previousPage(
231 | duration: _kMonthScrollDuration,
232 | curve: Curves.ease,
233 | );
234 | }
235 | }
236 |
237 | /// True if the earliest allowable month is displayed.
238 | bool get _isDisplayingFirstMonth {
239 | return !_currentDisplayedMonthDate.isAfter(
240 | DateTime(widget.firstDate.year, widget.firstDate.month),
241 | );
242 | }
243 |
244 | /// True if the latest allowable month is displayed.
245 | bool get _isDisplayingLastMonth {
246 | return !_currentDisplayedMonthDate.isBefore(
247 | DateTime(widget.lastDate.year, widget.lastDate.month),
248 | );
249 | }
250 |
251 | late DateTime _previousMonthDate;
252 | late DateTime _nextMonthDate;
253 |
254 | void _handleMonthPageChanged(int monthPage) {
255 | setState(() {
256 | _previousMonthDate = _addMonthsToMonthDate(
257 | widget.firstDate,
258 | monthPage - 1,
259 | );
260 | _currentDisplayedMonthDate = _addMonthsToMonthDate(
261 | widget.firstDate,
262 | monthPage,
263 | );
264 | _nextMonthDate = _addMonthsToMonthDate(widget.firstDate, monthPage + 1);
265 | });
266 | }
267 |
268 | Future _onMonthChange(DateTime newMonth) async {
269 | if (widget.onMonthChange != null) await widget.onMonthChange!(newMonth);
270 | setState(() {});
271 | }
272 |
273 | @override
274 | Widget build(BuildContext context) {
275 | Orientation orientation = MediaQuery.of(context).orientation;
276 | return Container(
277 | decoration: BoxDecoration(
278 | color: widget.style?.backgroundPicker,
279 | borderRadius: orientation == Orientation.landscape
280 | ? BorderRadius.only(
281 | topRight: Radius.circular(widget.borderRadius))
282 | : null),
283 | // The month picker just adds month navigation to the day picker, so make
284 | // it the same height as the DayPicker
285 | // height: _kMaxDayPickerHeight,
286 | child: Stack(
287 | children: [
288 | Semantics(
289 | sortKey: _MonthPickerSortKey.calendar,
290 | child: NotificationListener(
291 | onNotification: (_) {
292 | _chevronOpacityController.forward();
293 | return false;
294 | },
295 | child: NotificationListener(
296 | onNotification: (_) {
297 | _chevronOpacityController.reverse();
298 | return false;
299 | },
300 | child: PageView.builder(
301 | dragStartBehavior: widget.dragStartBehavior,
302 | key: ValueKey(widget.selectedDate),
303 | controller: _dayPickerController,
304 | scrollDirection: Axis.horizontal,
305 | itemCount: _monthDelta(widget.firstDate, widget.lastDate) + 1,
306 | itemBuilder: _buildItems,
307 | onPageChanged: (int monthPage) async {
308 | _handleMonthPageChanged(monthPage);
309 | await _onMonthChange(_currentDisplayedMonthDate);
310 | },
311 | ),
312 | ),
313 | ),
314 | ),
315 |
316 | /// Arrow Left
317 | PositionedDirectional(
318 | top: widget.style?.marginLeftArrowPrevious ?? 0.0,
319 | start: widget.style?.marginLeftArrowPrevious ?? 8.0,
320 | child: Semantics(
321 | sortKey: _MonthPickerSortKey.previousMonth,
322 | child: FadeTransition(
323 | opacity: _chevronOpacityAnimation,
324 | child: IconButton(
325 | icon: Icon(
326 | Icons.chevron_left,
327 | size: widget.style?.sizeArrow,
328 | color: widget.style?.colorArrowPrevious,
329 | ),
330 | tooltip: _isDisplayingFirstMonth
331 | ? null
332 | : '${localizations.previousMonthTooltip} ${localizations.formatMonthYear(_previousMonthDate)}',
333 | onPressed: () async => _isDisplayingFirstMonth == true
334 | ? null
335 | : await _handlePreviousMonth(),
336 | ),
337 | ),
338 | ),
339 | ),
340 |
341 | /// Arrow Right
342 | PositionedDirectional(
343 | top: widget.style?.marginTopArrowNext ?? 0.0,
344 | end: widget.style?.marginRightArrowNext ?? 8.0,
345 | child: Semantics(
346 | sortKey: _MonthPickerSortKey.nextMonth,
347 | child: FadeTransition(
348 | opacity: _chevronOpacityAnimation,
349 | child: IconButton(
350 | icon: Icon(
351 | Icons.chevron_right,
352 | size: widget.style?.sizeArrow,
353 | color: widget.style?.colorArrowNext,
354 | ),
355 | tooltip: _isDisplayingLastMonth
356 | ? null
357 | : '${localizations.nextMonthTooltip} ${localizations.formatMonthYear(_nextMonthDate)}',
358 | onPressed: () async =>
359 | _isDisplayingLastMonth ? null : await _handleNextMonth(),
360 | ),
361 | ),
362 | ),
363 | ),
364 | ],
365 | ),
366 | );
367 | }
368 |
369 | @override
370 | void dispose() {
371 | _timer?.cancel();
372 | _chevronOpacityController.dispose();
373 | _dayPickerController.dispose();
374 | super.dispose();
375 | }
376 | }
377 |
378 | // Defines semantic traversal order of the top-level widgets inside the month
379 | // picker.
380 | class _MonthPickerSortKey extends OrdinalSortKey {
381 | const _MonthPickerSortKey(double order) : super(order);
382 |
383 | static const _MonthPickerSortKey previousMonth = _MonthPickerSortKey(1.0);
384 | static const _MonthPickerSortKey nextMonth = _MonthPickerSortKey(2.0);
385 | static const _MonthPickerSortKey calendar = _MonthPickerSortKey(3.0);
386 | }
387 |
--------------------------------------------------------------------------------
/lib/src/widgets/flutter_rounded_year_picker.dart:
--------------------------------------------------------------------------------
1 | import 'package:flutter/gestures.dart';
2 | import 'package:flutter/material.dart';
3 | import 'package:flutter_rounded_date_picker/src/era_mode.dart';
4 | import 'package:flutter_rounded_date_picker/src/material_rounded_year_picker_style.dart';
5 |
6 | /// A scrollable list of years to allow picking a year.
7 | ///
8 | /// The year picker widget is rarely used directly. Instead, consider using
9 | /// [showDatePicker], which creates a date picker dialog.
10 | ///
11 | /// Requires one of its ancestors to be a [Material] widget.
12 | ///
13 | /// See also:
14 | ///
15 | /// * [showDatePicker], which shows a dialog that contains a material design
16 | /// date picker.
17 | /// * [showTimePicker], which shows a dialog that contains a material design
18 | /// time picker.
19 | class FlutterRoundedYearPicker extends StatefulWidget {
20 | /// Creates a year picker.
21 | ///
22 | /// The [selectedDate] and [onChanged] arguments must not be null. The
23 | /// [lastDate] must be after the [firstDate].
24 | ///
25 | /// Rarely used directly. Instead, typically used as part of the dialog shown
26 | /// by [showDatePicker].
27 | FlutterRoundedYearPicker(
28 | {Key? key,
29 | required this.selectedDate,
30 | required this.onChanged,
31 | required this.firstDate,
32 | required this.lastDate,
33 | required this.era,
34 | this.fontFamily,
35 | this.dragStartBehavior = DragStartBehavior.start,
36 | this.style})
37 | : assert(!firstDate.isAfter(lastDate)),
38 | super(key: key);
39 |
40 | /// The currently selected date.
41 | ///
42 | /// This date is highlighted in the picker.
43 | final DateTime selectedDate;
44 |
45 | /// Called when the user picks a year.
46 | final Function onChanged;
47 |
48 | /// The earliest date the user is permitted to pick.
49 | final DateTime firstDate;
50 |
51 | /// The latest date the user is permitted to pick.
52 | final DateTime lastDate;
53 |
54 | /// {@macro flutter.widgets.scrollable.dragStartBehavior}
55 | final DragStartBehavior dragStartBehavior;
56 |
57 | /// Era
58 | final EraMode era;
59 |
60 | /// Font
61 | final String? fontFamily;
62 |
63 | /// style
64 | final MaterialRoundedYearPickerStyle? style;
65 |
66 | @override
67 | _FlutterRoundedYearPickerState createState() =>
68 | _FlutterRoundedYearPickerState();
69 | }
70 |
71 | class _FlutterRoundedYearPickerState extends State {
72 | late double _itemExtent;
73 | ScrollController? scrollController;
74 |
75 | @override
76 | void initState() {
77 | super.initState();
78 | _itemExtent = widget.style?.heightYearRow ?? 50;
79 | scrollController = ScrollController(
80 | // Move the initial scroll position to the currently selected date's year.
81 | initialScrollOffset:
82 | (widget.selectedDate.year - widget.firstDate.year) * _itemExtent,
83 | );
84 | }
85 |
86 | @override
87 | Widget build(BuildContext context) {
88 | assert(debugCheckHasMaterial(context));
89 | final ThemeData themeData = Theme.of(context);
90 | final TextStyle style = themeData.textTheme.bodyMedium!.copyWith(
91 | fontFamily: widget.fontFamily,
92 | );
93 | return ListView.builder(
94 | dragStartBehavior: widget.dragStartBehavior,
95 | controller: scrollController,
96 | itemExtent: _itemExtent,
97 | itemCount: widget.lastDate.year - widget.firstDate.year + 1,
98 | itemBuilder: (BuildContext context, int index) {
99 | final int year = widget.firstDate.year + index;
100 | final bool isSelected = year == widget.selectedDate.year;
101 | final TextStyle itemStyle = isSelected
102 | ? (widget.style?.textStyleYearSelected ??
103 | themeData.textTheme.headlineSmall!.copyWith(
104 | color: themeData.colorScheme.primary,
105 | fontFamily: widget.fontFamily,
106 | ))
107 | : (widget.style?.textStyleYear ?? style);
108 | return InkWell(
109 | key: ValueKey(year),
110 | onTap: () {
111 | widget.onChanged(DateTime(
112 | year,
113 | widget.selectedDate.month,
114 | widget.selectedDate.day,
115 | ));
116 | },
117 | child: Center(
118 | child: Semantics(
119 | selected: isSelected,
120 | child: Text(
121 | "${calculateYearEra(widget.era, year)}",
122 | style: itemStyle,
123 | ),
124 | ),
125 | ),
126 | );
127 | },
128 | );
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/pubspec.yaml:
--------------------------------------------------------------------------------
1 | name: flutter_rounded_date_picker
2 | description: The Flutter plugin that help you can choose dates and years with rounded calendars and customizable themes.
3 | version: 3.0.4
4 | homepage: https://github.com/benznest/flutter_rounded_date_picker
5 |
6 | environment:
7 | sdk: ">=2.17.0 <4.0.0"
8 |
9 | dependencies:
10 | flutter:
11 | sdk: flutter
12 |
--------------------------------------------------------------------------------
/screenshots/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/1.png
--------------------------------------------------------------------------------
/screenshots/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/10.png
--------------------------------------------------------------------------------
/screenshots/11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/11.png
--------------------------------------------------------------------------------
/screenshots/12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/12.png
--------------------------------------------------------------------------------
/screenshots/13.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/13.png
--------------------------------------------------------------------------------
/screenshots/14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/14.png
--------------------------------------------------------------------------------
/screenshots/15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/15.png
--------------------------------------------------------------------------------
/screenshots/16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/16.png
--------------------------------------------------------------------------------
/screenshots/17.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/17.png
--------------------------------------------------------------------------------
/screenshots/18.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/18.png
--------------------------------------------------------------------------------
/screenshots/19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/19.png
--------------------------------------------------------------------------------
/screenshots/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/2.png
--------------------------------------------------------------------------------
/screenshots/20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/20.png
--------------------------------------------------------------------------------
/screenshots/21.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/21.png
--------------------------------------------------------------------------------
/screenshots/22.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/22.png
--------------------------------------------------------------------------------
/screenshots/23.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/23.png
--------------------------------------------------------------------------------
/screenshots/24.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/24.png
--------------------------------------------------------------------------------
/screenshots/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/3.png
--------------------------------------------------------------------------------
/screenshots/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/4.png
--------------------------------------------------------------------------------
/screenshots/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/5.png
--------------------------------------------------------------------------------
/screenshots/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/6.png
--------------------------------------------------------------------------------
/screenshots/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/7.png
--------------------------------------------------------------------------------
/screenshots/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/8.png
--------------------------------------------------------------------------------
/screenshots/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/9.png
--------------------------------------------------------------------------------
/screenshots/a1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a1.gif
--------------------------------------------------------------------------------
/screenshots/a2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a2.gif
--------------------------------------------------------------------------------
/screenshots/a3.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a3.gif
--------------------------------------------------------------------------------
/screenshots/a4.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a4.gif
--------------------------------------------------------------------------------
/screenshots/a5.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a5.gif
--------------------------------------------------------------------------------
/screenshots/a6.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/benznest/flutter_rounded_date_picker/d43fee10821bbdc7adc0031baf7800894479341b/screenshots/a6.gif
--------------------------------------------------------------------------------