### Install and Use ScrollDateTimePicker Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Add the scroll_datetime_picker package to your Flutter project, import it, and use the ScrollDateTimePicker widget with basic configuration. ```shell dart pub add scroll_datetime_picker ``` ```dart import 'package:scroll_datetime_picker/scroll_datetime_picker.dart'; ``` ```dart ScrollDateTimePicker( itemExtent: 54, infiniteScroll: true, dateOption: DateTimePickerOption( dateFormat: DateFormat('yyyyMMMdd'), minDate: DateTime(2000, 6), maxDate: DateTime(2024, 6), initialDate: time, ), onChange: (datetime) => setState(() { time = datetime; }), ), ``` -------------------------------- ### Customize Flex Width with DateTimePickerItemFlex Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Controls the width (flex) of each date/time item using the DateTimePickerItemFlex class. The example sets flex values for weekday, day, month, and year items. ```dart ScrollDateTimePicker( itemFlex: const DateTimePickerItemFlex( weekdayFlex: 7, dayFlex: 2, monthFlex: 8, yearFlex: 4, ), ), ``` -------------------------------- ### Customize Item State with itemBuilder Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Customizes each item based on its state (active, non-active, or disabled) using the itemBuilder parameter. The example sets text color based on isDisabled and isActive flags. ```dart ScrollDateTimePicker( itemBuilder: (context, pattern, text, isActive, isDisabled) => Text( text, style: TextStyle( color: isDisabled ? Colors.grey : isActive ? Colors.blue : Colors.black, ), ), ), ``` -------------------------------- ### DateTimePickerController with ScrollDateTimePicker Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Complete example of using DateTimePickerController with ScrollDateTimePicker to manage date selection programmatically. It wires the controller to the picker, sets date formatting and range options, updates state on change, and includes a button that advances the date by 7 days via controller.changeDateTime(). ```dart class MyHomePage extends StatefulWidget { @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { final controller = DateTimePickerController(); final now = DateTime.now(); DateTime selectedDate = DateTime.now(); @override Widget build(BuildContext context) { return Scaffold( body: Column( children: [ ScrollDateTimePicker( controller: controller, itemExtent: 54, dateOption: DateTimePickerOption( dateFormat: DateFormat('EEEE dd MMMM yyyy'), minDate: DateTime(2000, 6), maxDate: DateTime(2030, 6), initialDate: selectedDate, ), onChange: (datetime) => setState(() { selectedDate = datetime; }), // ... other customizations ... ), // Add buttons or other widgets to programmatically change the date ElevatedButton( onPressed: () { final futureDate = selectedDate.add(const Duration(days: 7)); controller.changeDateTime(futureDate); }, child: const Text('Add 7 Days'), ), ], ), ); } } ``` -------------------------------- ### Customize Center Area with DateTimePickerCenterWidget Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Customizes the center area of the picker (the area indicating the chosen date/time) using the DateTimePickerCenterWidget class. The example applies a StadiumBorder shape with a specific color. ```dart ScrollDateTimePicker( centerWidget: DateTimePickerCenterWidget( builder: (context, constraints, child) => const DecoratedBox( decoration: ShapeDecoration( shape: StadiumBorder(side: BorderSide(width: 3)), color: AppColor.secondary, ), ), ), ), ``` -------------------------------- ### DateTimePickerWheelOption Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/date_time_picker_wheel_option.dart.gcov.html Constructs a DateTimePickerWheelOption with configurable appearance properties for the picker wheel. ```APIDOC ## DateTimePickerWheelOption ### Description A class to set custom appearance for the picker wheel, based on Flutter's ListWheelScrollView. ### Constructor ```dart const DateTimePickerWheelOption({ this.perspective = 0.005, this.diameterRatio = 1.75, this.offAxisFraction = 0, this.squeeze = 1, this.physics, this.renderChildrenOutsideViewport = false, this.clipBehavior = Clip.hardEdge, }) ``` ### Parameters - **perspective** (double) - Optional - Defaults to 0.005. Value allowed is > 0 && < 0.01. This value will strengthen the wheel effect. The bigger the value, the rounder the appearance; the lower the value, the flatter the appearance. - **diameterRatio** (double) - Optional - Defaults to 1.75. A ratio between the diameter of the cylinder and the viewport's size in the main axis. - **offAxisFraction** (double) - Optional - Defaults to 0.0. Defines how much the picker's scroll wheel is placed horizontally off-center, as a fraction of its width. - **squeeze** (double) - Optional - Defines distance between the picker's child. The higher the squeeze, the smaller the distance. Defaults to 1. - **physics** (ScrollPhysics?) - Optional - How the scroll view should respond to user input when it is overscrolled. If null, the physics will use the platform default. - **renderChildrenOutsideViewport** (bool) - Optional - Whether to paint children inside the viewport only or not. Defaults to false. Cannot be true if clipBehavior is not Clip.none. - **clipBehavior** (Clip) - Optional - How the picker clips the children. Defaults to Clip.hardEdge. ### Properties - **perspective** (double) - The perspective value for the wheel effect. Defaults to 0.005. - **diameterRatio** (double) - The ratio between the diameter of the cylinder and the viewport's size. Defaults to 1.75. - **offAxisFraction** (double) - Defines how much the picker's scroll wheel is placed horizontally off-center. Defaults to 0.0. - **squeeze** (double) - Defines distance between the picker's children. Defaults to 1. - **physics** (ScrollPhysics?) - How the scroll view should respond to user input when overscrolled. If null, uses platform default. - **clipBehavior** (Clip) - How the picker clips the children. Defaults to Clip.hardEdge. - **renderChildrenOutsideViewport** (bool) - Whether to paint children inside the viewport only or not. Defaults to false. Cannot be true if clipBehavior is not Clip.none. ### Constructor ```dart const DateTimePickerWheelOption({ this.perspective = 0.005, this.diameterRatio = 1.75, this.offAxisFraction = 0, this.squeeze = 1, this.physics, this.renderChildrenOutsideViewport = false, this.clipBehavior = Clip.hardEdge, }) ``` ### Properties #### `perspective` (double) - **Description**: This value will strengthen the wheel effect. The bigger the value, the rounder the appearance; the lower the value, the flatter. Value allowed is > 0 && < 0.01. Defaults to 0.005. #### `diameterRatio` (double) - **Description**: A ratio between the diameter of the cylinder and the viewport's size in the main axis. Defaults to 1.75. #### `offAxisFraction` (double) - **Description**: Defines how much the picker's scroll wheel is placed horizontally off-center, as a fraction of its width. Defaults to 0.0. #### `squeeze` (double) - **Description**: Defines distance between the picker's child. The higher the squeeze, the smaller the distance. Defaults to 1. #### `physics` (ScrollPhysics?) - **Description**: How the scroll view should respond to user input when it is overscrolled. If null, the physics will use the platform default. #### `clipBehavior` (Clip) - **Description**: How the picker clips the children. Defaults to [Clip.hardEdge]. #### `renderChildrenOutsideViewport` (bool) - **Description**: Whether to paint children inside the viewport only or not. Defaults to false. Cannot be true if [clipBehavior] is not [Clip.none]. #### `perspective` (double) - **Description**: This value will strengthen the wheel effect. The bigger the value, the rounder the appearance; the lower, the flatter. Value allowed is > 0 && < 0.01. Defaults to 0.005. #### `diameterRatio` (double) - **Description**: A ratio between the diameter of the cylinder and the viewport's size in the main axis. Defaults to 1.75. #### `offAxisFraction` (double) - **Description**: Defines how much the picker's scroll wheel is placed horizontally off-center, as a fraction of its width. Defaults to 0.0. #### `squeeze` (double) - **Description**: Defines distance between the picker's child. The higher the squeeze, the smaller the distance. Defaults to 1. ### Response #### Success Response (200) - **DateTimePickerWheelOption** - The constructed wheel option object with the specified parameters. #### Response Example ```json { "perspective": 0.005, "diameterRatio": 1.75, "offAxisFraction": 0.0, "squeeze": 1.0, "physics": null, "renderChildrenOutsideViewport": false, "clipBehavior": "hardEdge" } ``` ``` -------------------------------- ### DateTimePickerHelper class implementation Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/date_time_picker_helper.dart.gcov.html The complete source code of the DateTimePickerHelper class, including imports, constructor, and all methods for date/time picker logic. It uses the intl package for formatting and the scroll_datetime_picker package for options and enums. ```dart import 'package:intl/intl.dart'; import 'package:scroll_datetime_picker/scroll_datetime_picker.dart'; import 'package:scroll_datetime_picker/src/entities/enums.dart'; class DateTimePickerHelper { const DateTimePickerHelper(this.option); final DateTimePickerOption option; bool isAM(int hour) => hour < 12; int convertToHour12(int hour) => hour == 0 ? 12 : hour > 12 ? hour - 12 : hour; int get numOfYear => option.maxDate.year - option.minDate.year + 1; int maxDay(int month, int year) { switch (month) { case 1: return 31; case 2: return year.isLeapYear ? 29 : 28; case 3: return 31; case 4: return 30; case 5: return 31; case 6: return 30; case 7: return 31; case 8: return 31; case 9: return 30; case 10: return 31; case 11: return 30; case 12: return 31; default: return 0; } } List get years => List.generate( numOfYear, (index) => option.minDate.year + index, ); int itemCount(DateTimeType type) { switch (type) { case DateTimeType.year: return numOfYear; case DateTimeType.month: return 12; case DateTimeType.day: return 31; case DateTimeType.weekday: return 7; case DateTimeType.hour24: return 24; case DateTimeType.hour12: return 12; case DateTimeType.minute: return 60; case DateTimeType.second: return 60; case DateTimeType.amPM: return 2; } } String getText(DateTimeType type, String pattern, int rowIndex) { final normalizedRowIndex = rowIndex % itemCount(type); switch (type) { case DateTimeType.year: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(years[normalizedRowIndex])); case DateTimeType.month: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, normalizedRowIndex + 1)); case DateTimeType.day: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, normalizedRowIndex + 1)); case DateTimeType.weekday: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, normalizedRowIndex + 1)); case DateTimeType.hour24: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, 1, normalizedRowIndex)); case DateTimeType.hour12: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, 1, normalizedRowIndex == 0 ? 12 : normalizedRowIndex)); case DateTimeType.minute: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, 1, 0, normalizedRowIndex)); case DateTimeType.second: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, 1, 0, 0, normalizedRowIndex)); case DateTimeType.amPM: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2000, 1, 1, normalizedRowIndex == 0 ? 0 : 12)); } } } ``` -------------------------------- ### DateTimePickerOption class and patterns extension Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/lib/src/entities/date_time_picker_option.dart.gcov.html Defines the DateTimePickerOption class and its extension DateTimePickerOptionX. The class holds date format, min/max dates, and an optional initial date. The extension's patterns getter extracts letter sequences from the DateFormat pattern, throwing an Exception if the pattern is null. ```dart part of '../scroll_date_time_picker.dart'; /// Set datetime configuration for the picker class DateTimePickerOption { const DateTimePickerOption({ required this.dateFormat, required this.minDate, required this.maxDate, this.initialDate, }); /// Format used in the picker. /// /// The picker will automatically parse the format /// and show datetime according to DateFormat's pattern. /// Locale could also pass to this param to set the datetime picker locale. /// /// Example: /// /// DateFormat.yMMMd(); /// DateFormat('hhmmss'); /// DateFormat.yMMMd('en'); /// DateFormat('hhmmssa', 'fr'); final DateFormat dateFormat; /// Minimum date allowed to be chosen. /// /// If a date is before minimum date, date item in the picker /// will be disabled and not allowed to be chosen /// /// Example: /// /// DateTime.now().substract(Duration(days: 200)); /// DateTime(2020, 6); final DateTime minDate; /// Maximum date allowed to be chosen. /// /// If a date is after maximum date, date item in the picker /// will be disabled and not allowed to be chosen /// /// Example: /// /// DateTime.now().add(Duration(days: 200)); /// DateTime(2024, 6); final DateTime maxDate; /// Initial date to be shown in the picker. /// /// If null, fallback to: /// /// DateTime.now() final DateTime? initialDate; Locale get locale => Locale(dateFormat.locale); DateTime get getInitialDate => initialDate ?? DateTime.now(); } extension DateTimePickerOptionX on DateTimePickerOption { List get patterns { if (dateFormat.pattern == null) { throw Exception('DateFormat is not valid: $dateFormat'); } final pattern = dateFormat.pattern!.replaceAll(RegExp('[^a-zA-Z]'), ''); final result = []; final buffer = StringBuffer(); for (var i = 0; i < pattern.length; i++) { final currentChar = pattern[i]; // Write to buffer if first index if (i == 0) { buffer.write(currentChar); } // If current char is same, add to buffer else if (currentChar == buffer.toString()[0]) { buffer.write(currentChar); } // If current char is different, write buffer to result and reset buffer else { result.add(buffer.toString()); buffer.clear(); buffer.write(currentChar); } } // Write the last buffer to result if (buffer.isNotEmpty) { result.add(buffer.toString()); } return result; } } ``` -------------------------------- ### Customize Date/Time Order with DateFormat Patterns Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Arrange date/time elements by changing the pattern in dateFormat. 'yMMMMdd' gives Year-Month-Day order; 'ddMMMMy' gives Day-Month-Year order. ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('yMMMMdd'), ), ``` ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('ddMMMMy'), ), ``` -------------------------------- ### DateTimePickerHelper class with date/time formatting and utility methods Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/lib/src/entities/date_time_picker_helper.dart.gcov.html The DateTimePickerHelper class provides utility methods for the scroll datetime picker, including converting 24-hour to 12-hour format, determining if an hour is AM, calculating the number of years, maximum days in a month, generating a list of years, and returning the item count for each DateTimeType. It also formats date/time values using the intl package with the specified locale and pattern. ```dart import 'package:intl/intl.dart'; import 'package:scroll_datetime_picker/scroll_datetime_picker.dart'; import 'package:scroll_datetime_picker/src/entities/enums.dart'; class DateTimePickerHelper { const DateTimePickerHelper(this.option); final DateTimePickerOption option; bool isAM(int hour) => hour < 12; int convertToHour12(int hour) => hour == 0 ? 12 : hour > 12 ? hour - 12 : hour; int get numOfYear => option.maxDate.year - option.minDate.year + 1; int maxDay(int month, int year) { switch (month) { case 1: return 31; case 2: return year.isLeapYear ? 29 : 28; case 3: return 31; case 4: return 30; case 5: return 31; case 6: return 30; case 7: return 31; case 8: return 31; case 9: return 30; case 10: return 31; case 11: return 30; case 12: return 31; default: return 0; } } List get years => List.generate( numOfYear, (index) => option.minDate.year + index, ); int itemCount(DateTimeType type) { switch (type) { case DateTimeType.year: return numOfYear; case DateTimeType.month: return 12; case DateTimeType.day: return 31; case DateTimeType.weekday: return 7; case DateTimeType.hour24: return 24; case DateTimeType.hour12: return 12; case DateTimeType.minute: return 60; case DateTimeType.second: return 60; case DateTimeType.amPM: return 2; } } String getText(DateTimeType type, String pattern, int rowIndex) { final normalizedRowIndex = rowIndex % itemCount(type); switch (type) { case DateTimeType.year: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(years[normalizedRowIndex])); case DateTimeType.month: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, normalizedRowIndex + 1)); case DateTimeType.day: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, normalizedRowIndex + 1)); case DateTimeType.weekday: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, normalizedRowIndex + 1)); case DateTimeType.hour24: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, 1, normalizedRowIndex)); case DateTimeType.hour12: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, 1, normalizedRowIndex == 0 ? 12 : normalizedRowIndex)); case DateTimeType.minute: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, 1, 0, normalizedRowIndex)); case DateTimeType.second: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, 1, 0, 0, normalizedRowIndex)); case DateTimeType.amPM: return DateFormat( pattern, option.locale.languageCode, ).format(DateTime(2024, 1, 1, normalizedRowIndex == 0 ? 0 : 12)); } } } ``` -------------------------------- ### Configure Flutter Windows runner with CMake Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/example/windows/runner/CMakeLists.txt Defines the Windows runner executable target for a Flutter application. It sets the minimum CMake version, declares the project, and adds the executable with the required source files. It applies standard build settings, adds version and NOMINMAX preprocessor definitions, links the Flutter libraries, and adds the flutter_assemble dependency. ```cmake cmake_minimum_required(VERSION 3.14) project(runner LANGUAGES CXX) # Define the application target. To change its name, change BINARY_NAME in the # top-level CMakeLists.txt, not the value here, or `flutter run` will no longer # work. # # Any new source files that you add to the application should be added here. add_executable(${BINARY_NAME} WIN32 "flutter_window.cpp" "main.cpp" "utils.cpp" "win32_window.cpp" "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" "Runner.rc" "runner.exe.manifest" ) # Apply the standard set of build settings. This can be removed for applications # that need different build settings. apply_standard_settings(${BINARY_NAME}) # Add preprocessor definitions for the build version. target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") # Disable Windows macros that collide with C++ standard library functions. target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") # Add dependency libraries and include directories. Add any application-specific # dependencies here. target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") # Run the Flutter tool portions of the build. This must not be removed. add_dependencies(${BINARY_NAME} flutter_assemble) ``` -------------------------------- ### ScrollDateTimePicker State class with lifecycle and build methods Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/scroll_date_time_picker.dart.gcov.html State class for the ScrollDateTimePicker widget. Initializes date formatting, controllers, and style; handles updates when options or style change; disposes resources; builds the picker UI with a center decoration and a row of pattern columns. ```dart class _ScrollDateTimePickerState extends State { late final ValueNotifier _activeDate; late List _controllers; late DateTimePickerStyle _style; late DateTimePickerOption _option; late DateTimePickerHelper _helper; late final ValueNotifier isRecheckingPosition; @override void initState() { super.initState(); initializeDateFormatting(widget.dateOption.locale.languageCode); isRecheckingPosition = ValueNotifier(false); _option = widget.dateOption; _activeDate = ValueNotifier(_option.getInitialDate); _helper = DateTimePickerHelper(_option); _style = widget.style ?? DateTimePickerStyle(); _controllers = List.generate( _option.patterns.length, (index) => ScrollController(), ); SchedulerBinding.instance.addPostFrameCallback((_) { _initDate(); }); } @override void didUpdateWidget(covariant ScrollDateTimePicker oldWidget) { super.didUpdateWidget(oldWidget); if (widget.dateOption != _option) { setState(() { _option = widget.dateOption; _helper = DateTimePickerHelper(_option); if (_option.patterns.length != _controllers.length) { final difference = _option.patterns.length - _controllers.length; if (difference.isNegative) { _controllers.removeRange( _controllers.length - difference.abs(), _controllers.length, ); } else { _controllers.addAll( List.generate( difference, (_) => ScrollController(), ), ); } } }); } if (widget.style != _style) { setState(() { _style = widget.style ?? _style; }); } } @override void dispose() { isRecheckingPosition.dispose(); _activeDate.dispose(); for (final ctrl in _controllers) { ctrl.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return SizedBox( width: double.infinity, height: widget.itemExtent * widget.visibleItem, child: Stack( alignment: Alignment.center, children: [ /* Center Decoration */ Container( height: widget.itemExtent, width: double.infinity, decoration: _style.centerDecoration, ), /* Picker Widget */ SizedBox( width: double.infinity, height: widget.itemExtent * widget.visibleItem, child: Row( children: List.generate( _option.patterns.length, ``` -------------------------------- ### DateTimePattern class with splitPattern and dateTimeTypes getter Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/lib/src/entities/date_time_picker_option.dart.gcov.html Defines the DateTimePattern class with a pattern string, a method to split the pattern into segments based on single quotes, and a getter that maps patterns to DateTimeType values. The splitPattern method iterates through characters, handling quoted sections and accumulating characters into buffers, adding them to the result list when a quote or the end of the pattern is reached. The dateTimeTypes getter maps each pattern segment to a DateTimeType using the fromPattern factory. ```dart result.add(buffer.toString()); buffer ..clear() ..write(currentChar); } // Add to result if its last char if (i == pattern.length - 1) { result.add(buffer.toString()); } } return result; } List get dateTimeTypes => patterns .map( DateTimeType.fromPattern, ) .toList(); } ``` -------------------------------- ### DateTimePickerItemFlex class and getFlex extension Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/lib/src/entities/date_time_picker_item_flex.dart.gcov.html Defines the DateTimePickerItemFlex class and its extension DateTimePickerItemFlexX. The class provides configurable flex widths for each date/time item, all defaulting to 1. The extension's getFlex method returns the appropriate flex value based on the given DateTimeType. ```Dart part of '../scroll_date_time_picker.dart'; /// Class to specify the flex width (proportional space) for different date and time /// items in a datetime picker. /// /// This class provides a way to customize the width allocation for each item in /// a datetime picker. By adjusting the flex values for each date/time item, you can /// control the visual spacing and layout of the datetime picker items. class DateTimePickerItemFlex { /// Creates an instance of [DateTimePickerItemFlex]. /// /// All parameters are optional and default to 1. /// /// - [yearFlex]: The flex width for the year item. /// - [monthFlex]: The flex width for the month item. /// - [dayFlex]: The flex width for the day item. /// - [weekdayFlex]: The flex width for the weekday item. /// - [hour24Flex]: The flex width for the 24-hour format hour item. /// - [hour12Flex]: The flex width for the 12-hour format hour item. /// - [minuteFlex]: The flex width for the minute item. /// - [secondFlex]: The flex width for the second item. /// - [amPMFlex]: The flex width for the AM/PM item. const DateTimePickerItemFlex({ this.yearFlex = 1, this.monthFlex = 1, this.dayFlex = 1, this.weekdayFlex = 1, this.hour24Flex = 1, this.hour12Flex = 1, this.minuteFlex = 1, this.secondFlex = 1, this.amPMFlex = 1, }); /// The flex width for the year item. final int yearFlex; /// The flex width for the month item. final int monthFlex; /// The flex width for the day item. final int dayFlex; /// The flex width for the weekday item. final int weekdayFlex; /// The flex width for the 24-hour format hour item. final int hour24Flex; /// The flex width for the 12-hour format hour item. final int hour12Flex; /// The flex width for the minute item. final int minuteFlex; /// The flex width for the second item. final int secondFlex; /// The flex width for the AM/PM item. final int amPMFlex; } extension DateTimePickerItemFlexX on DateTimePickerItemFlex { /// Retrieves the flex width for a specific [DateTimeType]. /// /// - [type]: The date or time type for which to get the flex width. /// - Returns the flex width as an integer. int getFlex(DateTimeType type) { switch (type) { case DateTimeType.year: return yearFlex; case DateTimeType.month: return monthFlex; case DateTimeType.day: return dayFlex; case DateTimeType.weekday: return weekdayFlex; case DateTimeType.hour24: return hour24Flex; case DateTimeType.hour12: return hour12Flex; case DateTimeType.minute: return minuteFlex; case DateTimeType.second: return secondFlex; case DateTimeType.amPM: return amPMFlex; } } } ``` -------------------------------- ### PickerWidget Implementation Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/widgets/lib/src/widgets/picker_widget.dart.gcov.html The PickerWidget class defines the configuration for the datetime picker, including item dimensions, scroll behavior, and builder functions for active and inactive states. ```dart import 'package:flutter/material.dart'; import 'package:scroll_datetime_picker/scroll_datetime_picker.dart'; import 'package:scroll_datetime_picker/src/widgets/scroll_type_listener.dart'; class PickerWidget extends StatefulWidget { const PickerWidget({ super.key, required this.itemCount, required this.itemExtent, required this.infiniteScroll, required this.onChange, required this.controller, required this.activeBuilder, required this.inactiveBuilder, required this.wheelOption, }); final int itemCount; final double itemExtent; final bool infiniteScroll; final void Function(int index) onChange; final ScrollController controller; final Widget Function(int index) activeBuilder; final Widget Function(int index) inactiveBuilder; final DateTimePickerWheelOption wheelOption; @override State createState() => _PickerWidgetState(); } ``` -------------------------------- ### Implement _fixPosition Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/lib/src/scroll_date_time_picker.dart.gcov.html Calculates the scroll offset and animates the controller to the target position if it is not currently scrolling. ```dart Future _fixPosition({ required ScrollController controller, required int itemCount, required int targetPosition, }) async { if (controller.hasClients) { final scrollPosition = (controller.offset / widget.itemExtent).floor() % itemCount + 1; if (targetPosition != scrollPosition) { final difference = scrollPosition - targetPosition; final endOffset = controller.offset - (difference * widget.itemExtent); if (!controller.position.isScrollingNotifier.value) { await Future.delayed( const Duration(milliseconds: 100), () => controller.animateTo( endOffset, duration: const Duration(milliseconds: 500), curve: Curves.bounceOut, ), ); } } } return; } ``` -------------------------------- ### Customize Date/Time TextStyles Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Customize text styles for active, inactive, and disabled states using DateTimePickerStyle. activeStyle applies to the center area, inactiveStyle outside it, and disabledStyle for invalid dates. ```dart style: DateTimePickerStyle( activeStyle: TextStyle( fontSize: 24, letterSpacing: -0.5, color: Theme.of(context).primaryColor, ), inactiveStyle: TextStyle( fontSize: 20, color: Theme.of(context).primaryColor.withOpacity(0.7), ), disabledStyle: TextStyle( fontSize: 20, color: Theme.of(context).disabledColor, ), ), ``` -------------------------------- ### Finite Scroll ScrollDateTimePicker with DateTimePickerOption Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Configures the picker with finite scrolling, which stops at the end of the scroll items. Requires the dateOption with minDate and maxDate, and sets infiniteScroll to false. ```dart ScrollDateTimePicker( itemExtent: 54, infiniteScroll: false // Finite scroll onChange: (_){} dateOption: DateTimePickerOption( dateFormat: DateFormat('EddMMMy'), minDate: DateTime(2000, 6), maxDate: DateTime(2024, 6), ), ), ``` -------------------------------- ### PickerWidget State Management Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/widgets/lib/src/widgets/picker_widget.dart.gcov.html The _PickerWidgetState class handles the lifecycle of the widget, including scroll controller listeners, state updates when wheel options change, and resource disposal. ```dart class _PickerWidgetState extends State { late DateTimePickerWheelOption _wheelOption; final _isProgrammaticScroll = ValueNotifier(false); final _centerScrollCtl = ScrollController(); final _outerScrollCtl = ScrollController(); @override void initState() { super.initState(); widget.controller.addListener(_scrollListener); _wheelOption = widget.wheelOption; } @override void didUpdateWidget(covariant PickerWidget oldWidget) { super.didUpdateWidget(oldWidget); if (widget.wheelOption != _wheelOption) { setState(() { _wheelOption = widget.wheelOption; }); } } @override void dispose() { widget.controller.removeListener(_scrollListener); _isProgrammaticScroll.dispose(); _centerScrollCtl.dispose(); _outerScrollCtl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Stack( alignment: Alignment.center, children: [ /* Main Scrollable */ IgnorePointer( child: ClipPath( clipper: _OuterWidgetClipper( itemExtent: widget.itemExtent, ), child: ListWheelScrollView.useDelegate( controller: _outerScrollCtl, itemExtent: widget.itemExtent, physics: _wheelOption.physics, perspective: _wheelOption.perspective, ``` -------------------------------- ### PickerWidget StatefulWidget implementation Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/widgets/picker_widget.dart.gcov.html Defines the PickerWidget as a StatefulWidget with required itemCount, itemExtent, and infiniteScroll constructor parameters. Imports Flutter Material and the scroll_datetime_picker package along with the scroll_type_listener widget. ```dart import 'package:flutter/material.dart'; import 'package:scroll_datetime_picker/scroll_datetime_picker.dart'; import 'package:scroll_datetime_picker/src/widgets/scroll_type_listener.dart'; class PickerWidget extends StatefulWidget { const PickerWidget({ super.key, required this.itemCount, required this.itemExtent, required this.infiniteScroll, ``` -------------------------------- ### Set initial date with controller.changeDateTime() Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Sets the picker's initial date programmatically by calling controller.changeDateTime() with the current date. Requires an existing DateTimePickerController instance. ```dart final initialDate = DateTime.now(); final controller = DateTimePickerController(); controller.changeDateTime(initialDate); ``` -------------------------------- ### DateTimePickerWheelOption class definition Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/date_time_picker_wheel_option.dart.gcov.html Defines the DateTimePickerWheelOption class with configurable parameters for the picker wheel, based on Flutter's ListWheelScrollView. Use it to customize perspective, diameter ratio, off-axis fraction, squeeze, physics, renderChildrenOutsideViewport, and clipBehavior. The physics parameter defaults to null (platform default) and clipBehavior defaults to Clip.hardEdge. ```dart part of '../scroll_date_time_picker.dart'; /// Set custom appearance for the picker wheel /// /// The parameters here are based on flutter's [ListWheelScrollView] class DateTimePickerWheelOption { const DateTimePickerWheelOption({ this.perspective = 0.005, this.diameterRatio = 1.75, this.offAxisFraction = 0, this.squeeze = 1, this.physics, this.renderChildrenOutsideViewport = false, this.clipBehavior = Clip.hardEdge, }); /// How the scroll view should respond to user input when it is overscrolled. /// /// If null, the physics will use the platform default final ScrollPhysics? physics; /// How the picker clip the children /// /// Defaults to [Clip.hardEdge]. final Clip clipBehavior; ``` -------------------------------- ### Dart code from scroll_date_time_picker.dart with coverage annotations Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/scroll_date_time_picker.dart.gcov.html This snippet shows the source code of the scroll_date_time_picker.dart file as displayed in the LCOV coverage report. It includes the _fixPosition method and surrounding logic for handling date/time selection. The code is annotated with execution counts. ```dart 353 1 : case DateTimeType.weekday: 354 1 : targetPosition = date.weekday; 355 : break; 356 : default: 357 : break; 358 : } 359 : 360 : /* Check if other scroll controller is still scrolling */ 361 1 : await _fixPosition( 362 2 : controller: _controllers[index], 363 2 : itemCount: _helper.itemCount(type), 364 : targetPosition: targetPosition, 365 : ); 366 : } 367 : } 368 : 369 1 : Future _fixPosition({ 370 : required ScrollController controller, 371 : required int itemCount, 372 : required int targetPosition, 373 : }) async { 374 1 : if (controller.hasClients) { 375 : final scrollPosition = 376 7 : (controller.offset / widget.itemExtent).floor() % itemCount + 1; 377 : 378 1 : if (targetPosition != scrollPosition) { 379 1 : final difference = scrollPosition - targetPosition; 380 5 : final endOffset = controller.offset - (difference * widget.itemExtent); 381 : 382 3 : if (!controller.position.isScrollingNotifier.value) { 383 1 : await Future.delayed( 384 : const Duration(milliseconds: 100), 385 2 : () => controller.animateTo( 386 : endOffset, 387 : duration: const Duration(milliseconds: 500), 388 : curve: Curves.bounceOut, 389 : ), 390 : ); 391 : } 392 : } 393 : } 394 : 395 : return; 396 : } 397 : } ``` -------------------------------- ### Pattern parsing and DateTimeType conversion in date_time_picker_option.dart Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/entities/date_time_picker_option.dart.gcov.html This snippet shows the implementation of a pattern parser that splits a pattern string into segments and a getter that maps each pattern to a DateTimeType. The code includes coverage counts from LCOV, indicating execution frequencies. ```dart 87 2 : ..write(currentChar); 88 : } 89 : 90 : // Add to result if its last char 91 6 : if (i == pattern.length - 1) { 92 4 : result.add(buffer.toString()); 93 : } 94 : } 95 : 96 : return result; 97 : } 98 : 99 4 : List get dateTimeTypes => patterns 100 2 : .map( 101 : DateTimeType.fromPattern, 102 : ) 103 2 : .toList(); 104 : } ``` -------------------------------- ### ScrollDateTimePicker widget source code Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/scroll_date_time_picker.dart.gcov.html The complete source code of the scroll_date_time_picker.dart file, showing the ScrollDateTimePicker StatefulWidget with its constructor and properties. It includes imports, typedefs, and class definition. ```dart import 'package:flutter/material.dart'; import 'package:flutter/scheduler.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; import 'package:scroll_datetime_picker/src/entities/date_time_picker_helper.dart'; import 'package:scroll_datetime_picker/src/entities/enums.dart'; import 'package:scroll_datetime_picker/src/widgets/picker_widget.dart'; part 'entities/date_time_picker_option.dart'; part 'entities/date_time_picker_style.dart'; part 'entities/date_time_picker_wheel_option.dart'; typedef DateTimePickerItemBuilder = Widget Function( BuildContext context, String pattern, String text, bool isActive, bool isDisabled, ); /// A customizable Scrollable DateTimePicker. /// /// To set a custom datetime format, use DateFormat available in /// `[dateOption]` param /// /// To set styles for the picker, use `[style]` param class ScrollDateTimePicker extends StatefulWidget { const ScrollDateTimePicker({ super.key, required this.itemExtent, required this.dateOption, required this.onChange, this.itemBuilder, this.style, this.visibleItem = 3, this.infiniteScroll = false, this.wheelOption = const DateTimePickerWheelOption(), }); /// Height of every item in the picker /// /// Must not be null final double itemExtent; /// Number of item to be shown vertically /// /// Defaults to 3 final int visibleItem; /// Whether to implement infinite scroll or finite scroll. /// /// Defaults to false final bool infiniteScroll; /// Callback called when the selected date and/or time changes. /// /// Must not be null. final void Function(DateTime datetime)? onChange; /// Set datetime configuration /// /// Must not be null. final DateTimePickerOption dateOption; /// Set picker styles. /// /// If [itemBuilder] is not null, this value will be omitted. final DateTimePickerStyle? style; /// Set custom appearance for the picker wheel /// /// The parameters here are based on flutter's [ListWheelScrollView] final DateTimePickerWheelOption wheelOption; /// Set custom appearance for every item in the picker wheel /// /// - If null, the appearance of every item will be based on DateTimePickerStyle [style] /// - If not null, the appearance of every item will be based return value of this builder final DateTimePickerItemBuilder? itemBuilder; @override State createState() => _ScrollDateTimePickerState(); } ``` -------------------------------- ### Custom clipper for outer widget Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/coverage/html/src/widgets/picker_widget.dart.gcov.html Defines a CustomClipper that creates a path with two rectangles to clip the outer widget, using the item extent to calculate the visible area. ```dart class _OuterWidgetClipper extends CustomClipper { const _OuterWidgetClipper({ required this.itemExtent, }); final double itemExtent; @override bool shouldReclip(covariant CustomClipper oldClipper) => true; @override Path getClip(Size size) { const xMin = 0.0; final xMax = size.width; final yMin = (size.height - itemExtent) / 2; final yMax = yMin + itemExtent; final upperRect = Rect.fromPoints( Offset.zero, Offset(xMax, yMin), ); final lowerRect = Rect.fromPoints( Offset(xMin, yMax), Offset(size.width, size.height), ); final path = Path() ..addRect(upperRect) ..addRect(lowerRect) ..close(); return path; } } ``` -------------------------------- ### Customize Date/Time Format with DateFormat('EddMMMy') Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Customize the date/time format by setting the dateFormat property in DateTimePickerOption. The pattern follows the intl package's DateFormat patterns, e.g., 'EddMMMy'. ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('EddMMMy'), ), ``` -------------------------------- ### Customize Date/Time Locale Source: https://github.com/dhiyaaulauliyaa/scroll_datetime_picker/blob/master/README.md Set the locale by passing a locale code to DateFormat's second argument. 'en' for English, 'fr' for French, and no locale uses the default. Locale options are based on the intl package. ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('yMMMMdd', 'en'), ), ``` ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('yMMMMdd', 'fr'), ), ``` ```dart dateOption: DateTimePickerOption( dateFormat: DateFormat('ddMMMMy'), ), ```