locuaz_wheel_pickers 1.0.8 copy "locuaz_wheel_pickers: ^1.0.8" to clipboard
locuaz_wheel_pickers: ^1.0.8 copied to clipboard

PlatformAndroid

A comprehensive collection of iOS-style wheel picker widgets for Flutter with advanced dependency management and performance optimization.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:locuaz_wheel_pickers/locuaz_wheel_pickers.dart';

/// Example app demonstrating Locuaz Wheel Pickers usage
void main() {
  runApp(const MyApp());
}

/// Main application widget
class MyApp extends StatelessWidget {
  /// Creates the main application widget
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) => MaterialApp(
    title: 'Locuaz Wheel Pickers Example',
    theme: ThemeData(
      colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      useMaterial3: true,
    ),
    home: const ExampleHomePage(),
  );
}

/// Home page widget with navigation to different examples
class ExampleHomePage extends StatelessWidget {
  /// Creates the home page widget
  const ExampleHomePage({super.key});

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      backgroundColor: Theme.of(context).colorScheme.inversePrimary,
      title: const Text('Locuaz Wheel Pickers Demo'),
      centerTitle: true,
    ),
    body: SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          const SizedBox(height: 20),
          const Text(
            'Locuaz Wheel Pickers',
            style: TextStyle(
              fontSize: 28,
              fontWeight: FontWeight.bold,
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 8),
          const Text(
            'iOS-style wheel picker widgets for Flutter',
            style: TextStyle(
              fontSize: 16,
              color: Colors.grey,
            ),
            textAlign: TextAlign.center,
          ),
          const SizedBox(height: 40),
          const Text(
            'Basic Examples',
            style: TextStyle(
              fontSize: 20,
              fontWeight: FontWeight.w600,
            ),
          ),
          const SizedBox(height: 16),
          _buildExampleCard(
            context,
            title: 'Simple Wheel Picker',
            description: 'Basic static wheel picker implementation',
            icon: Icons.view_carousel,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const SimpleWheelExamplePage(),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _buildExampleCard(
            context,
            title: 'Selective Wheel Picker',
            description: 'Dynamic wheel picker with selective recreation',
            icon: Icons.dynamic_form,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const SelectiveWheelExamplePage(),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _buildExampleCard(
            context,
            title: 'List Wheel Picker',
            description: 'Simple list selection wheel picker',
            icon: Icons.list,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const ListWheelExamplePage(),
              ),
            ),
          ),
          const SizedBox(height: 32),
          const Text(
            'Advanced Examples',
            style: TextStyle(
              fontSize: 20,
              fontWeight: FontWeight.w600,
            ),
          ),
          const SizedBox(height: 16),
          _buildExampleCard(
            context,
            title: 'Date Picker',
            description: 'Date picker with month-day dependencies',
            icon: Icons.calendar_today,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const DatePickerExamplePage(),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _buildExampleCard(
            context,
            title: 'Time Picker',
            description: 'Time picker with hour-minute-second wheels',
            icon: Icons.access_time,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const TimePickerExamplePage(),
              ),
            ),
          ),
          const SizedBox(height: 12),
          _buildExampleCard(
            context,
            title: 'Complex Dependencies',
            description: 'Country-State-City picker with dependencies',
            icon: Icons.location_on,
            onTap: () => Navigator.push<void>(
              context,
              MaterialPageRoute<void>(
                builder: (context) => const ComplexDependencyExamplePage(),
              ),
            ),
          ),
        ],
      ),
    ),
  );

  Widget _buildExampleCard(
    BuildContext context, {
    required String title,
    required String description,
    required IconData icon,
    required VoidCallback onTap,
  }) =>
      Card(
        elevation: 2,
        child: ListTile(
          leading: Icon(
            icon,
            color: Theme.of(context).colorScheme.primary,
            size: 28,
          ),
          title: Text(
            title,
            style: const TextStyle(
              fontWeight: FontWeight.w600,
              fontSize: 16,
            ),
          ),
          subtitle: Text(
            description,
            style: const TextStyle(fontSize: 14),
          ),
          trailing: const Icon(Icons.arrow_forward_ios, size: 16),
          onTap: onTap,
        ),
      );
}

// Placeholder pages for examples (will be implemented in subsequent tasks)

/// Simple wheel picker example page
class SimpleWheelExamplePage extends StatefulWidget {
  /// Creates the simple wheel example page
  const SimpleWheelExamplePage({super.key});

  @override
  State<SimpleWheelExamplePage> createState() => _SimpleWheelExamplePageState();
}

class _SimpleWheelExamplePageState extends State<SimpleWheelExamplePage> {
  String _selectedTime = '00:00';
  String _selectedDate = 'January 1';
  List<int> _customSelection = [0, 0, 0];

  @override
  Widget build(BuildContext context) => Scaffold(
    appBar: AppBar(
      title: const Text('Simple Wheel Picker'),
      backgroundColor: Theme.of(context).colorScheme.inversePrimary,
    ),
    body: SingleChildScrollView(
      padding: const EdgeInsets.all(16),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          _buildExampleCard(
            title: 'Time Picker',
            description: 'Simple hour:minute picker using static wheels',
            selectedValue: _selectedTime,
            child: SimpleWheelPickerBuilder(
              wheels: [
                WheelConfig(
                  itemCount: 24,
                  initialIndex: 0,
                  formatter: (i) => i.toString().padLeft(2, '0'),
                  width: 60,
                  trailingSeparator: const Text(
                    ':',
                    style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                  ),
                ),
                WheelConfig(
                  itemCount: 60,
                  initialIndex: 0,
                  formatter: (i) => i.toString().padLeft(2, '0'),
                  width: 60,
                ),
              ],
              onChanged: (indices) {
                setState(() {
                  _selectedTime = 
                      '${indices[0].toString().padLeft(2, '0')}:'
                      '${indices[1].toString().padLeft(2, '0')}';
                });
              },
            ),
          ),
          const SizedBox(height: 24),
          _buildExampleCard(
            title: 'Month-Day Picker',
            description: 'Static month and day selection',
            selectedValue: _selectedDate,
            child: SimpleWheelPickerBuilder(
              wheels: [
                WheelConfig(
                  itemCount: 12,
                  initialIndex: 0,
                  formatter: (i) => [
                    'January', 'February', 'March', 'April',
                    'May', 'June', 'July', 'August',
                    'September', 'October', 'November', 'December'
                  ][i],
                  width: 120,
                ),
                WheelConfig(
                  itemCount: 31,
                  initialIndex: 0,
                  formatter: (i) => (i + 1).toString(),
                  width: 60,
                ),
              ],
              onChanged: (indices) {
                final months = [
                  'January', 'February', 'March', 'April',
                  'May', 'June', 'July', 'August',
                  'September', 'October', 'November', 'December'
                ];
                setState(() {
                  _selectedDate = '${months[indices[0]]} ${indices[1] + 1}';
                });
              },
            ),
          ),
          const SizedBox(height: 24),
          _buildExampleCard(
            title: 'Custom Multi-Wheel',
            description: 'Three custom wheels with different configurations',
            selectedValue: 'Selection: ${_customSelection.join(', ')}',
            child: SimpleWheelPickerBuilder(
              wheels: [
                WheelConfig(
                  itemCount: 5,
                  initialIndex: 0,
                  formatter: (i) => 'A${i + 1}',
                  width: 50,
                ),
                WheelConfig(
                  itemCount: 10,
                  initialIndex: 0,
                  formatter: (i) => 'B${i + 1}',
                  width: 50,
                ),
                WheelConfig(
                  itemCount: 3,
                  initialIndex: 0,
                  formatter: (i) => 'C${i + 1}',
                  width: 50,
                ),
              ],
              selectedItemColor: Colors.blue,
              barColor: Colors.blue.withValues(alpha: 0.1),
              onChanged: (indices) {
                setState(() {
                  _customSelection = indices;
                });
              },
            ),
          ),
        ],
      ),
    ),
  );

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String selectedValue,
    required Widget child,
  }) =>
      Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                description,
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $selectedValue',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(child: child),
            ],
          ),
        ),
      );
}

/// Selective wheel picker example page
class SelectiveWheelExamplePage extends StatefulWidget {
  /// Creates the selective wheel example page
  const SelectiveWheelExamplePage({super.key});

  @override
  State<SelectiveWheelExamplePage> createState() => _SelectiveWheelExamplePageState();
}

class _SelectiveWheelExamplePageState extends State<SelectiveWheelExamplePage> {
  final GlobalKey _pickerKey = GlobalKey();
  String _selectedDate = 'January 1, 2024';
  String _selectedTime = '12:00:00';
  int _currentYear = 2024;
  int _currentMonth = 0;

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Selective Wheel Picker'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _buildExampleCard(
                title: 'Dynamic Date Picker',
                description: 'Day wheel updates based on month/year selection',
                selectedValue: _selectedDate,
                child: SelectiveWheelPickerBuilder(
                  key: _pickerKey,
                  wheels: [
                    WheelConfig(
                      itemCount: _getDaysInMonth(_currentYear, _currentMonth),
                      initialIndex: 0,
                      formatter: (i) => (i + 1).toString(),
                      width: 60,
                      wheelId: 'day_wheel',
                    ),
                    WheelConfig(
                      itemCount: 12,
                      initialIndex: 0,
                      formatter: (i) => [
                        'Jan', 'Feb', 'Mar', 'Apr',
                        'May', 'Jun', 'Jul', 'Aug',
                        'Sep', 'Oct', 'Nov', 'Dec'
                      ][i],
                      width: 60,
                      wheelId: 'month_wheel',
                    ),
                    WheelConfig(
                      itemCount: 50,
                      initialIndex: 24, // 2024
                      formatter: (i) => (2000 + i).toString(),
                      width: 80,
                      wheelId: 'year_wheel',
                    ),
                  ],
                  onChanged: (indices) {
                    final day = indices[0] + 1;
                    final month = indices[1];
                    final year = 2000 + indices[2];
                    
                    // Update day wheel if month or year changed
                    if (month != _currentMonth || year != _currentYear) {
                      _currentMonth = month;
                      _currentYear = year;
                      
                      final daysInMonth = _getDaysInMonth(year, month);
                      final newDayIndex = (day - 1).clamp(0, daysInMonth - 1);
                      
                      SelectiveWheelPickerBuilder.recreateWheelByKey(
                        _pickerKey,
                        0,
                        WheelConfig(
                          itemCount: daysInMonth,
                          initialIndex: newDayIndex,
                          formatter: (i) => (i + 1).toString(),
                          width: 60,
                          wheelId: 'day_wheel_${month}_$year',
                        ),
                      );
                    }
                    
                    final months = [
                      'January', 'February', 'March', 'April',
                      'May', 'June', 'July', 'August',
                      'September', 'October', 'November', 'December'
                    ];
                    
                    setState(() {
                      _selectedDate = '${months[month]} $day, $year';
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Time Picker with Seconds',
                description: 'Independent wheels with selective updates',
                selectedValue: _selectedTime,
                child: SelectiveWheelPickerBuilder(
                  wheels: [
                    WheelConfig(
                      itemCount: 24,
                      initialIndex: 12,
                      formatter: (i) => i.toString().padLeft(2, '0'),
                      width: 60,
                      wheelId: 'hour_wheel',
                      trailingSeparator: const Text(
                        ':',
                        style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                      ),
                    ),
                    WheelConfig(
                      itemCount: 60,
                      initialIndex: 0,
                      formatter: (i) => i.toString().padLeft(2, '0'),
                      width: 60,
                      wheelId: 'minute_wheel',
                      trailingSeparator: const Text(
                        ':',
                        style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                      ),
                    ),
                    WheelConfig(
                      itemCount: 60,
                      initialIndex: 0,
                      formatter: (i) => i.toString().padLeft(2, '0'),
                      width: 60,
                      wheelId: 'second_wheel',
                    ),
                  ],
                  selectedItemColor: Colors.green,
                  barColor: Colors.green.withValues(alpha: 0.1),
                  onChanged: (indices) {
                    setState(() {
                      _selectedTime = '${indices[0].toString().padLeft(2, '0')}:'
                          '${indices[1].toString().padLeft(2, '0')}:'
                          '${indices[2].toString().padLeft(2, '0')}';
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildControlButtons(),
            ],
          ),
        ),
      );

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String selectedValue,
    required Widget child,
  }) =>
      Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                description,
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $selectedValue',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(child: child),
            ],
          ),
        ),
      );

  Widget _buildControlButtons() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'External Control Demo',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 8),
              const Text(
                'These buttons demonstrate external control of the date picker',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 16),
              Wrap(
                spacing: 8,
                runSpacing: 8,
                children: [
                  ElevatedButton(
                    onPressed: () => _setToToday(),
                    child: const Text('Set to Today'),
                  ),
                  ElevatedButton(
                    onPressed: () => _setToNewYear(),
                    child: const Text('Set to New Year'),
                  ),
                  ElevatedButton(
                    onPressed: () => _setToRandomDate(),
                    child: const Text('Random Date'),
                  ),
                ],
              ),
            ],
          ),
        ),
      );

  void _setToToday() {
    final now = DateTime.now();
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _pickerKey,
      {
        0: now.day - 1,
        1: now.month - 1,
        2: now.year - 2000,
      },
      withAnimation: true,
    );
  }

  void _setToNewYear() {
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _pickerKey,
      {
        0: 0, // January 1st
        1: 0,
        2: 25, // 2025
      },
      withAnimation: true,
    );
  }

  void _setToRandomDate() {
    final random = DateTime.now().millisecondsSinceEpoch % 1000;
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _pickerKey,
      {
        0: random % 28, // Safe day range
        1: random % 12,
        2: 20 + (random % 30), // 2020-2049
      },
      withAnimation: true,
    );
  }

  int _getDaysInMonth(int year, int month) {
    return DateTime(year, month + 1, 0).day;
  }
}

/// List wheel picker example page
class ListWheelExamplePage extends StatefulWidget {
  /// Creates the list wheel example page
  const ListWheelExamplePage({super.key});

  @override
  State<ListWheelExamplePage> createState() => _ListWheelExamplePageState();
}

class _ListWheelExamplePageState extends State<ListWheelExamplePage> {
  String _selectedCountry = 'United States';
  String _selectedFruit = 'Apple';
  String _selectedColor = 'Red';

  final List<String> _countries = [
    'United States', 'Canada', 'Mexico', 'Brazil', 'Argentina',
    'United Kingdom', 'France', 'Germany', 'Spain', 'Italy',
    'China', 'Japan', 'South Korea', 'India', 'Australia',
    'Russia', 'South Africa', 'Egypt', 'Nigeria', 'Kenya',
  ];

  final List<String> _fruits = [
    'Apple', 'Banana', 'Cherry', 'Date', 'Elderberry',
    'Fig', 'Grape', 'Honeydew', 'Kiwi', 'Lemon',
    'Mango', 'Orange', 'Papaya', 'Quince', 'Raspberry',
    'Strawberry', 'Tangerine', 'Watermelon',
  ];

  final List<String> _colors = [
    'Red', 'Blue', 'Green', 'Yellow', 'Orange',
    'Purple', 'Pink', 'Brown', 'Black', 'White',
    'Gray', 'Cyan', 'Magenta', 'Lime', 'Indigo',
  ];

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('List Wheel Picker'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _buildExampleCard(
                title: 'Country Selector',
                description: 'Choose from a list of countries',
                selectedValue: _selectedCountry,
                child: WListPicker(
                  items: _countries,
                  initialIndex: 0,
                  onChanged: (index) {
                    setState(() {
                      _selectedCountry = _countries[index];
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Fruit Picker',
                description: 'Select your favorite fruit',
                selectedValue: _selectedFruit,
                child: WListPicker(
                  items: _fruits,
                  initialIndex: 0,
                  selectedItemColor: Colors.orange,
                  barColor: Colors.orange.withValues(alpha: 0.1),
                  onChanged: (index) {
                    setState(() {
                      _selectedFruit = _fruits[index];
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Color Selector',
                description: 'Pick a color with custom styling',
                selectedValue: _selectedColor,
                child: WListPicker(
                  items: _colors,
                  initialIndex: 0,
                  selectedItemColor: Colors.purple,
                  unselectedItemColor: Colors.grey,
                  barColor: Colors.purple.withValues(alpha: 0.15),
                  onChanged: (index) {
                    setState(() {
                      _selectedColor = _colors[index];
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildUsageExample(),
            ],
          ),
        ),
      );

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String selectedValue,
    required Widget child,
  }) =>
      Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                description,
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $selectedValue',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(child: child),
            ],
          ),
        ),
      );

  Widget _buildUsageExample() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Usage Example',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 8),
              const Text(
                'WListPicker is the simplest way to create a wheel picker:',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 12),
              Container(
                padding: const EdgeInsets.all(12),
                decoration: BoxDecoration(
                  color: Colors.grey[100],
                  borderRadius: BorderRadius.circular(8),
                ),
                child: const Text(
                  r'''WListPicker(
  items: ['Option 1', 'Option 2', 'Option 3'],
  onChanged: (index) {
    print('Selected: ${items[index]}');
  },
)''',
                  style: TextStyle(
                    fontFamily: 'monospace',
                    fontSize: 12,
                  ),
                ),
              ),
              const SizedBox(height: 12),
              Text(
                'Current selections: $_selectedCountry, '
                '$_selectedFruit, $_selectedColor',
                style: const TextStyle(
                  fontSize: 14,
                  fontStyle: FontStyle.italic,
                ),
              ),
            ],
          ),
        ),
      );
}

/// Date picker example page
class DatePickerExamplePage extends StatefulWidget {
  /// Creates the date picker example page
  const DatePickerExamplePage({super.key});

  @override
  State<DatePickerExamplePage> createState() => _DatePickerExamplePageState();
}

class _DatePickerExamplePageState extends State<DatePickerExamplePage> {
  DateTime _selectedDate1 = DateTime.now();
  DateTime _selectedDate2 = DateTime(2024, 1, 1);
  DateTime _selectedDate3 = DateTime(2025, 6, 15);

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Date Picker'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _buildExampleCard(
                title: 'Default Date Picker',
                description: 'Day-Month-Year with abbreviated month names',
                selectedValue: _formatDate(_selectedDate1),
                child: WDatePicker(
                  initialDate: _selectedDate1,
                  format: EDateFormat.dMMy,
                  language: Lang.en,
                  showSeparator: true,
                  onChanged: (date) {
                    setState(() {
                      _selectedDate1 = date;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Full Month Names',
                description: 'Date picker with full month names in Spanish',
                selectedValue: _formatDate(_selectedDate2),
                child: WDatePicker(
                  initialDate: _selectedDate2,
                  format: EDateFormat.dMMMy,
                  language: Lang.es,
                  showSeparator: false,
                  selectedItemColor: Colors.green,
                  barColor: Colors.green.withValues(alpha: 0.1),
                  onChanged: (date) {
                    setState(() {
                      _selectedDate2 = date;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Month-Year Only',
                description: 'Date picker without day wheel',
                selectedValue: _formatMonthYear(_selectedDate3),
                child: WDatePicker(
                  initialDate: _selectedDate3,
                  format: EDateFormat.xMMMy,
                  language: Lang.en,
                  startYear: 2020,
                  endYear: 2030,
                  selectedItemColor: Colors.purple,
                  barColor: Colors.purple.withValues(alpha: 0.1),
                  onChanged: (date) {
                    setState(() {
                      _selectedDate3 = date;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildFeatureCard(),
            ],
          ),
        ),
      );

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String selectedValue,
    required Widget child,
  }) =>
      Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                description,
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $selectedValue',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(child: child),
            ],
          ),
        ),
      );

  Widget _buildFeatureCard() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Smart Date Handling',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 8),
              const Text(
                'The date picker automatically handles:',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 12),
              _buildFeatureItem('• Different month lengths (28-31 days)'),
              _buildFeatureItem('• Leap year calculations'),
              _buildFeatureItem('• Invalid date adjustments (Feb 31 → Feb 28)'),
              _buildFeatureItem('• Smooth day wheel recreation'),
              _buildFeatureItem('• Multiple language support'),
              const SizedBox(height: 12),
              const Text(
                'Try changing months to see the day wheel update automatically!',
                style: TextStyle(
                  fontSize: 14,
                  fontStyle: FontStyle.italic,
                  color: Colors.blue,
                ),
              ),
            ],
          ),
        ),
      );

  Widget _buildFeatureItem(String text) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 2),
        child: Text(
          text,
          style: const TextStyle(fontSize: 14),
        ),
      );

  String _formatDate(DateTime date) {
    final months = [
      'January', 'February', 'March', 'April',
      'May', 'June', 'July', 'August',
      'September', 'October', 'November', 'December'
    ];
    return '${months[date.month - 1]} ${date.day}, ${date.year}';
  }

  String _formatMonthYear(DateTime date) {
    final months = [
      'January', 'February', 'March', 'April',
      'May', 'June', 'July', 'August',
      'September', 'October', 'November', 'December'
    ];
    return '${months[date.month - 1]} ${date.year}';
  }
}

/// Time picker example page
class TimePickerExamplePage extends StatefulWidget {
  /// Creates the time picker example page
  const TimePickerExamplePage({super.key});

  @override
  State<TimePickerExamplePage> createState() => _TimePickerExamplePageState();
}

class _TimePickerExamplePageState extends State<TimePickerExamplePage> {
  WTimeOfDay _selectedTime1 = WTimeOfDay(
    hour: DateTime.now().hour,
    minute: DateTime.now().minute,
    second: DateTime.now().second,
    is24Hour: true,
  );
  
  WTimeOfDay _selectedTime2 = const WTimeOfDay(
    hour: 14,
    minute: 30,
    second: 0,
    is24Hour: false,
  );
  
  WTimeOfDay _selectedTime3 = const WTimeOfDay(
    hour: 9,
    minute: 15,
    second: 45,
    is24Hour: true,
  );

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Time Picker'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _buildExampleCard(
                title: '24-Hour Format',
                description: 'Hour:Minute:Second in 24-hour format',
                selectedValue: _selectedTime1.toString(),
                child: WTimePicker(
                  use24Hour: true,
                  showSeconds: true,
                  showSeparator: true,
                  initialTime: _selectedTime1,
                  onChanged: (time) {
                    setState(() {
                      _selectedTime1 = time;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: '12-Hour Format with AM/PM',
                description: 'Hour:Minute with AM/PM selector',
                selectedValue: _selectedTime2.toString(),
                child: WTimePicker(
                  use24Hour: false,
                  showSeconds: false,
                  showSeparator: true,
                  initialTime: _selectedTime2,
                  selectedItemColor: Colors.orange,
                  barColor: Colors.orange.withValues(alpha: 0.1),
                  onChanged: (time) {
                    setState(() {
                      _selectedTime2 = time;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildExampleCard(
                title: 'Precise Time Selection',
                description: '24-hour format with seconds, no separators',
                selectedValue: _selectedTime3.toString(),
                child: WTimePicker(
                  use24Hour: true,
                  showSeconds: true,
                  showSeparator: false,
                  initialTime: _selectedTime3,
                  selectedItemColor: Colors.teal,
                  unselectedItemColor: Colors.grey,
                  barColor: Colors.teal.withValues(alpha: 0.15),
                  onChanged: (time) {
                    setState(() {
                      _selectedTime3 = time;
                    });
                  },
                ),
              ),
              const SizedBox(height: 24),
              _buildComparisonCard(),
            ],
          ),
        ),
      );

  Widget _buildExampleCard({
    required String title,
    required String description,
    required String selectedValue,
    required Widget child,
  }) =>
      Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                title,
                style: const TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              Text(
                description,
                style: TextStyle(
                  fontSize: 14,
                  color: Colors.grey[600],
                ),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $selectedValue',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(child: child),
            ],
          ),
        ),
      );

  Widget _buildComparisonCard() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Format Comparison',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 12),
              _buildComparisonRow('24-Hour Format:', _selectedTime1.toString()),
              _buildComparisonRow('12-Hour Format:', _selectedTime2.toString()),
              _buildComparisonRow('With Seconds:', _selectedTime3.toString()),
              const SizedBox(height: 12),
              const Text(
                'Features:',
                style: TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w600,
                ),
              ),
              const SizedBox(height: 8),
              _buildFeatureItem('• Automatic AM/PM handling for 12-hour format'),
              _buildFeatureItem('• Optional seconds wheel'),
              _buildFeatureItem('• Customizable separators'),
              _buildFeatureItem('• Smooth scrolling performance'),
              _buildFeatureItem('• Consistent WTimeOfDay interface'),
            ],
          ),
        ),
      );

  Widget _buildComparisonRow(String label, String value) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 4),
        child: Row(
          children: [
            SizedBox(
              width: 120,
              child: Text(
                label,
                style: const TextStyle(
                  fontSize: 14,
                  fontWeight: FontWeight.w500,
                ),
              ),
            ),
            Expanded(
              child: Text(
                value,
                style: const TextStyle(
                  fontSize: 14,
                  fontFamily: 'monospace',
                  color: Colors.blue,
                ),
              ),
            ),
          ],
        ),
      );

  Widget _buildFeatureItem(String text) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 2),
        child: Text(
          text,
          style: const TextStyle(fontSize: 14),
        ),
      );
}

/// Complex dependency example page
class ComplexDependencyExamplePage extends StatefulWidget {
  /// Creates the complex dependency example page
  const ComplexDependencyExamplePage({super.key});

  @override
  State<ComplexDependencyExamplePage> createState() => 
      _ComplexDependencyExamplePageState();
}

class _ComplexDependencyExamplePageState extends State<ComplexDependencyExamplePage> {
  final GlobalKey _locationPickerKey = GlobalKey();
  final GlobalKey _performancePickerKey = GlobalKey();
  
  String _selectedLocation = 'United States - California - Los Angeles';
  String _selectedSpecs = 'Gaming - High - RTX 4080';
  
  // Sample data for location picker
  final Map<String, Map<String, List<String>>> _locationData = {
    'United States': {
      'California': ['Los Angeles', 'San Francisco', 'San Diego', 'Sacramento'],
      'New York': ['New York City', 'Buffalo', 'Rochester', 'Syracuse'],
      'Texas': ['Houston', 'Dallas', 'Austin', 'San Antonio'],
      'Florida': ['Miami', 'Orlando', 'Tampa', 'Jacksonville'],
    },
    'Canada': {
      'Ontario': ['Toronto', 'Ottawa', 'Hamilton', 'London'],
      'Quebec': ['Montreal', 'Quebec City', 'Laval', 'Gatineau'],
      'British Columbia': ['Vancouver', 'Victoria', 'Burnaby', 'Richmond'],
    },
    'United Kingdom': {
      'England': ['London', 'Manchester', 'Birmingham', 'Liverpool'],
      'Scotland': ['Edinburgh', 'Glasgow', 'Aberdeen', 'Dundee'],
      'Wales': ['Cardiff', 'Swansea', 'Newport', 'Wrexham'],
    },
  };
  
  // Sample data for performance picker
  final Map<String, Map<String, List<String>>> _performanceData = {
    'Gaming': {
      'Entry': ['GTX 1650', 'GTX 1660', 'RX 5500 XT'],
      'Mid': ['RTX 3060', 'RTX 3070', 'RX 6600 XT'],
      'High': ['RTX 4070', 'RTX 4080', 'RX 7800 XT'],
      'Ultra': ['RTX 4090', 'RTX 4080 Super', 'RX 7900 XTX'],
    },
    'Workstation': {
      'Basic': ['Quadro T400', 'Quadro T600', 'FirePro W2100'],
      'Professional': ['RTX A2000', 'RTX A4000', 'FirePro W7100'],
      'Enterprise': ['RTX A5000', 'RTX A6000', 'FirePro W9100'],
    },
    'Budget': {
      'Office': ['Integrated Graphics', 'GT 1030', 'RX 550'],
      'Light Gaming': ['GTX 1050', 'GTX 1050 Ti', 'RX 560'],
      'Multimedia': ['GTX 1060', 'RX 570', 'RX 580'],
    },
  };

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(
          title: const Text('Complex Dependencies'),
          backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        ),
        body: SingleChildScrollView(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _buildLocationPicker(),
              const SizedBox(height: 24),
              _buildPerformancePicker(),
              const SizedBox(height: 24),
              _buildControlPanel(),
              const SizedBox(height: 24),
              _buildPerformanceDemo(),
            ],
          ),
        ),
      );

  Widget _buildLocationPicker() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(2),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Padding(
                padding: const EdgeInsets.all(14),
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const Text(
                      'Location Picker (Country → State → City)',
                      style: TextStyle(
                        fontSize: 18,
                        fontWeight: FontWeight.bold,
                      ),
                    ),
                    const SizedBox(height: 4),
                    const Text(
                      'State wheel updates when country changes, '
                      'city wheel updates when state changes',
                      style: TextStyle(fontSize: 14),
                    ),
                    const SizedBox(height: 8),
                    Text(
                      'Selected: $_selectedLocation',
                      style: const TextStyle(
                        fontSize: 16,
                        fontWeight: FontWeight.w500,
                        color: Colors.blue,
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16),
              SelectiveWheelPickerBuilder(
                key: _locationPickerKey,
                wheels: _buildLocationWheels(),
                selectedItemColor: Colors.green,
                barColor: Colors.green.withValues(alpha: 0.1),
                onChanged: _handleLocationChange,
                textStyle: (isSelected) => TextStyle(
                  fontSize: 13,
                  color: isSelected ? Colors.green : Colors.black,
                ),
              ),
            ],
          ),
        ),
      );

  Widget _buildPerformancePicker() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'PC Specs Picker (Category → Tier → GPU)',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 4),
              const Text(
                'Tier wheel updates when category changes, '
                'GPU wheel updates when tier changes',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 8),
              Text(
                'Selected: $_selectedSpecs',
                style: const TextStyle(
                  fontSize: 16,
                  fontWeight: FontWeight.w500,
                  color: Colors.blue,
                ),
              ),
              const SizedBox(height: 16),
              Center(
                child: SelectiveWheelPickerBuilder(
                  key: _performancePickerKey,
                  wheels: _buildPerformanceWheels(),
                  selectedItemColor: Colors.purple,
                  barColor: Colors.purple.withValues(alpha: 0.1),
                  onChanged: _handlePerformanceChange,
                  textStyle: (isSelected) => TextStyle(
                    fontSize: 13,
                    color: isSelected ? Colors.purple : Colors.black,
                  ),
                ),
              ),
            ],
          ),
        ),
      );

  Widget _buildControlPanel() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'External Control Demo',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 8),
              const Text(
                'These buttons demonstrate external control of complex pickers',
                style: TextStyle(fontSize: 14),
              ),
              const SizedBox(height: 16),
              Wrap(
                spacing: 8,
                runSpacing: 8,
                children: [
                  ElevatedButton(
                    onPressed: _setToUSA,
                    child: const Text('Set to USA'),
                  ),
                  ElevatedButton(
                    onPressed: _setToCanada,
                    child: const Text('Set to Canada'),
                  ),
                  ElevatedButton(
                    onPressed: _setToGaming,
                    child: const Text('Gaming Setup'),
                  ),
                  ElevatedButton(
                    onPressed: _setToBudget,
                    child: const Text('Budget Build'),
                  ),
                ],
              ),
            ],
          ),
        ),
      );

  Widget _buildPerformanceDemo() => Card(
        elevation: 4,
        child: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              const Text(
                'Performance Benefits',
                style: TextStyle(
                  fontSize: 18,
                  fontWeight: FontWeight.bold,
                ),
              ),
              const SizedBox(height: 12),
              _buildFeatureItem('• Only dependent wheels recreate'),
              _buildFeatureItem('• Independent wheels maintain smooth scrolling'),
              _buildFeatureItem('• Intelligent dependency resolution'),
              _buildFeatureItem('• Automatic state validation'),
              _buildFeatureItem('• Memory-efficient controller reuse'),
              const SizedBox(height: 12),
              const Text(
                'Try changing the first wheel in each picker to see how '
                'only the dependent wheels update!',
                style: TextStyle(
                  fontSize: 14,
                  fontStyle: FontStyle.italic,
                  color: Colors.blue,
                ),
              ),
            ],
          ),
        ),
      );

  Widget _buildFeatureItem(String text) => Padding(
        padding: const EdgeInsets.symmetric(vertical: 2),
        child: Text(
          text,
          style: const TextStyle(fontSize: 14),
        ),
      );

  List<WheelConfig> _buildLocationWheels() {
    final countries = _locationData.keys.toList();
    final currentCountry = countries[0];
    final states = _locationData[currentCountry]!.keys.toList();
    final currentState = states[0];
    final cities = _locationData[currentCountry]![currentState]!;

    return [
      WheelConfig(
        itemCount: countries.length,
        initialIndex: 0,
        formatter: (i) => countries[i],
        width: 120,
        wheelId: 'country_wheel',
      ),
      WheelConfig(
        itemCount: states.length,
        initialIndex: 0,
        formatter: (i) => states[i],
        width: 100,
        wheelId: 'state_wheel',
        dependency: WheelDependency(
          dependsOn: [0],
          calculateItemCount: (deps) {
            final countryIndex = deps[0];
            final country = countries[countryIndex];
            return _locationData[country]!.keys.length;
          },
          calculateInitialIndex: (deps, current) => 0,
          buildFormatter: (deps) {
            final countryIndex = deps[0];
            final country = countries[countryIndex];
            final stateList = _locationData[country]!.keys.toList();
            return (i) => stateList[i];
          },
        ),
      ),
      WheelConfig(
        itemCount: cities.length,
        initialIndex: 0,
        formatter: (i) => cities[i],
        width: 120,
        wheelId: 'city_wheel',
        dependency: WheelDependency(
          dependsOn: [0, 1],
          calculateItemCount: (deps) {
            final countryIndex = deps[0];
            final stateIndex = deps[1];
            final country = countries[countryIndex];
            final state = _locationData[country]!.keys.toList()[stateIndex];
            return _locationData[country]![state]!.length;
          },
          calculateInitialIndex: (deps, current) => 0,
          buildFormatter: (deps) {
            final countryIndex = deps[0];
            final stateIndex = deps[1];
            final country = countries[countryIndex];
            final state = _locationData[country]!.keys.toList()[stateIndex];
            final cityList = _locationData[country]![state]!;
            return (i) => cityList[i];
          },
        ),
      ),
    ];
  }

  List<WheelConfig> _buildPerformanceWheels() {
    final categories = _performanceData.keys.toList();
    final currentCategory = categories[0];
    final tiers = _performanceData[currentCategory]!.keys.toList();
    final currentTier = tiers[0];
    final gpus = _performanceData[currentCategory]![currentTier]!;

    return [
      WheelConfig(
        itemCount: categories.length,
        initialIndex: 0,
        formatter: (i) => categories[i],
        width: 100,
        wheelId: 'category_wheel',
      ),
      WheelConfig(
        itemCount: tiers.length,
        initialIndex: 0,
        formatter: (i) => tiers[i],
        width: 80,
        wheelId: 'tier_wheel',
        dependency: WheelDependency(
          dependsOn: [0],
          calculateItemCount: (deps) {
            final categoryIndex = deps[0];
            final category = categories[categoryIndex];
            return _performanceData[category]!.keys.length;
          },
          calculateInitialIndex: (deps, current) => 0,
          buildFormatter: (deps) {
            final categoryIndex = deps[0];
            final category = categories[categoryIndex];
            final tierList = _performanceData[category]!.keys.toList();
            return (i) => tierList[i];
          },
        ),
      ),
      WheelConfig(
        itemCount: gpus.length,
        initialIndex: 0,
        formatter: (i) => gpus[i],
        width: 120,
        wheelId: 'gpu_wheel',
        dependency: WheelDependency(
          dependsOn: [0, 1],
          calculateItemCount: (deps) {
            final categoryIndex = deps[0];
            final tierIndex = deps[1];
            final category = categories[categoryIndex];
            final tier = _performanceData[category]!.keys.toList()[tierIndex];
            return _performanceData[category]![tier]!.length;
          },
          calculateInitialIndex: (deps, current) => 0,
          buildFormatter: (deps) {
            final categoryIndex = deps[0];
            final tierIndex = deps[1];
            final category = categories[categoryIndex];
            final tier = _performanceData[category]!.keys.toList()[tierIndex];
            final gpuList = _performanceData[category]![tier]!;
            return (i) => gpuList[i];
          },
        ),
      ),
    ];
  }

  void _handleLocationChange(List<int> indices) {
    final countries = _locationData.keys.toList();
    final country = countries[indices[0]];
    final states = _locationData[country]!.keys.toList();
    final state = states[indices[1]];
    final cities = _locationData[country]![state]!;
    final city = cities[indices[2]];

    setState(() {
      _selectedLocation = '$country - $state - $city';
    });
  }

  void _handlePerformanceChange(List<int> indices) {
    final categories = _performanceData.keys.toList();
    final category = categories[indices[0]];
    final tiers = _performanceData[category]!.keys.toList();
    final tier = tiers[indices[1]];
    final gpus = _performanceData[category]![tier]!;
    final gpu = gpus[indices[2]];

    setState(() {
      _selectedSpecs = '$category - $tier - $gpu';
    });
  }

  void _setToUSA() {
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _locationPickerKey,
      {0: 0, 1: 0, 2: 0}, // USA - California - Los Angeles
      withAnimation: true,
    );
  }

  void _setToCanada() {
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _locationPickerKey,
      {0: 1, 1: 0, 2: 0}, // Canada - Ontario - Toronto
      withAnimation: true,
    );
  }

  void _setToGaming() {
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _performancePickerKey,
      {0: 0, 1: 2, 2: 1}, // Gaming - High - RTX 4080
      withAnimation: true,
    );
  }

  void _setToBudget() {
    SelectiveWheelPickerBuilder.updateMultipleWheelPositionsByKey(
      _performancePickerKey,
      {0: 2, 1: 1, 2: 0}, // Budget - Light Gaming - GTX 1050
      withAnimation: true,
    );
  }
}
0
likes
140
points
46
downloads

Publisher

unverified uploader

Weekly Downloads

A comprehensive collection of iOS-style wheel picker widgets for Flutter with advanced dependency management and performance optimization.

Repository (GitHub)
View/report issues

Topics

#widget #picker #wheel #date-picker #time-picker

Documentation

API reference

License

MIT (license)

Dependencies

flutter, get, google_fonts

More

Packages that depend on locuaz_wheel_pickers