kurdish_date_picker 1.3.1 copy "kurdish_date_picker: ^1.3.1" to clipboard
kurdish_date_picker: ^1.3.1 copied to clipboard

A professional Kurdish-first Date Picker and Calendar for Flutter: Sorani RTL, Kurdish day/month names, Kurdish numerals, and single/range/multiple selection with theming.

example/lib/main.dart

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

void main() {
  runApp(const KurdishDatePickerExampleApp());
}

class KurdishDatePickerExampleApp extends StatefulWidget {
  const KurdishDatePickerExampleApp({super.key});

  @override
  State<KurdishDatePickerExampleApp> createState() =>
      _KurdishDatePickerExampleAppState();
}

class _KurdishDatePickerExampleAppState
    extends State<KurdishDatePickerExampleApp> {
  ThemeMode _themeMode = ThemeMode.light;

  void _setThemeMode(ThemeMode mode) => setState(() => _themeMode = mode);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'بڕگەی رێکەوتی کوردی',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.light,
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.teal),
      ),
      darkTheme: ThemeData(
        useMaterial3: true,
        brightness: Brightness.dark,
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.teal,
          brightness: Brightness.dark,
        ),
      ),
      themeMode: _themeMode,
      home: HomePage(
        themeMode: _themeMode,
        onThemeModeChanged: _setThemeMode,
      ),
    );
  }
}

class HomePage extends StatefulWidget {
  const HomePage({
    super.key,
    required this.themeMode,
    required this.onThemeModeChanged,
  });

  final ThemeMode themeMode;
  final ValueChanged<ThemeMode> onThemeModeChanged;

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  KurdishLocale _locale = KurdishLocale.sorani;
  NumberSystem _numberSystem = NumberSystem.kurdish;

  DateTime? _singleDate;
  KurdishDateRange? _range;
  final List<DateTime> _multiDates = [];

  int _weekStart = DateTime.saturday;

  bool _responsive = true;

  // Interactive customization demo state (section "Customization").
  Color _customSelected = Colors.deepPurple;
  Color _customToday = Colors.amber;
  Color _customWeekend = Colors.pink;
  double _customRadius = 16;
  double _customCellSize = 48;
  double _customTextSize = 14;

  // A controller the demo uses to navigate the calendar programmatically.
  final KurdishCalendarController _controller = KurdishCalendarController();

  // Events fall on fixed dates so the developer can see the indicators.
  // A couple of days carry more than one event to demonstrate the tooltip and
  // the "+N" overflow indicator.
  final List<KurdishCalendarEvent> _events = [
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 3), title: 'چاوپێکەوتن (Meeting)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 3), title: 'نانی نیوەڕۆ (Lunch)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 3), title: 'راهێنان (Training)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 3), title: 'پێداچوونەوە (Review)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 3), title: 'بڵاوکراوە (Release)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 10), title: 'پڕۆژە (Project deadline)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 21), title: 'کۆبوونەوە (Board meeting)'),
    KurdishCalendarEvent(
        date: DateTime(2026, 9, 27), title: 'ڕۆژی لەدایکبوون (Birthday)'),
  ];

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  // Convenience so section titles and demo labels stay short.
  bool get _isRtlLocale => _locale != KurdishLocale.english;

  Future<void> _pickDate() async {
    final date = await showKurdishDatePicker(
      context: context,
      initialDate: _singleDate ?? DateTime.now(),
      firstDate: DateTime(2020),
      lastDate: DateTime(2030),
      locale: _locale,
      numberSystem: _numberSystem,
      weekStart: _weekStart,
      responsive: _responsive,
      events: _events,
    );
    if (date != null) {
      setState(() => _singleDate = date);
    }
  }

  Future<void> _pickRange() async {
    final range = await showKurdishDateRangePicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(2020),
      lastDate: DateTime(2030),
      locale: _locale,
      numberSystem: _numberSystem,
      weekStart: _weekStart,
      responsive: _responsive,
      events: _events,
    );
    if (range != null) {
      setState(() => _range = range);
    }
  }

  Future<void> _pickMulti() async {
    final dates = await showKurdishDateMultiPicker(
      context: context,
      initialDate: DateTime.now(),
      firstDate: DateTime(2020),
      lastDate: DateTime(2030),
      locale: _locale,
      numberSystem: _numberSystem,
      weekStart: _weekStart,
      responsive: _responsive,
      events: _events,
    );
    if (dates != null && mounted) {
      setState(() {
        _multiDates
          ..clear()
          ..addAll(dates);
      });
    }
  }

  String _fmt(DateTime date) => KurdishDateFormatter.format(
        date,
        locale: _locale,
        numberSystem: _numberSystem,
      );

  String _fmtHijri(DateTime date) {
    final hijri = KurdishHijriDate.fromGregorian(date);
    final localization = KurdishDateFormatter.localization(_locale);
    return hijri.format(
      monthName: localization.hijriMonthNames[hijri.month - 1],
      formatInt: (v) => KurdishNumberFormatter.toSystem(v, _numberSystem),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('بڕگەی رێکەوتی کوردی'),
        actions: [
          PopupMenuButton<ThemeMode>(
            tooltip: 'دۆخ (Mode)',
            initialValue: widget.themeMode,
            onSelected: widget.onThemeModeChanged,
            itemBuilder: (context) => const [
              PopupMenuItem(
                value: ThemeMode.light,
                child: Text('دۆخی ڕووناک'),
              ),
              PopupMenuItem(
                value: ThemeMode.dark,
                child: Text('دۆخی تاریک'),
              ),
              PopupMenuItem(
                value: ThemeMode.system,
                child: Text('سیستەم'),
              ),
            ],
          ),
        ],
      ),
      body: Directionality(
        // The whole example screen uses Kurdish RTL layout.
        textDirection: TextDirection.rtl,
        child: Center(
          child: ConstrainedBox(
            constraints: const BoxConstraints(maxWidth: 520),
            child: ListView(
              padding: const EdgeInsets.all(16),
              children: [
                // -----------------------------------------------------------------
                // 0. Locale & numeral system switcher
                // -----------------------------------------------------------------
                Card(
                  elevation: 0,
                  color: Theme.of(context).colorScheme.surfaceContainerHighest,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(14),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(12),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          'زمان و سیستەمی ژمارە',
                          style: Theme.of(context)
                              .textTheme
                              .titleSmall
                              ?.copyWith(fontWeight: FontWeight.bold),
                        ),
                        const SizedBox(height: 8),
                        SegmentedButton<KurdishLocale>(
                          segments: const [
                            ButtonSegment(
                              value: KurdishLocale.sorani,
                              label: Text('سۆرانی'),
                            ),
                            ButtonSegment(
                              value: KurdishLocale.english,
                              label: Text('EN'),
                            ),
                          ],
                          selected: {_locale},
                          onSelectionChanged: (selection) =>
                              setState(() => _locale = selection.first),
                        ),
                        const SizedBox(height: 8),
                        SegmentedButton<NumberSystem>(
                          segments: const [
                            ButtonSegment(
                              value: NumberSystem.kurdish,
                              label: Text('ژمارەی کوردی ٢٠٢٦'),
                            ),
                            ButtonSegment(
                              value: NumberSystem.latin,
                              label: Text('2026'),
                            ),
                          ],
                          selected: {_numberSystem},
                          onSelectionChanged: (selection) =>
                              setState(() => _numberSystem = selection.first),
                        ),
                        const SizedBox(height: 8),
                        SegmentedButton<int>(
                          segments: const [
                            ButtonSegment(
                              value: DateTime.saturday,
                              label: Text('شەممە'),
                            ),
                            ButtonSegment(
                              value: DateTime.sunday,
                              label: Text('یەکشەممە'),
                            ),
                            ButtonSegment(
                              value: DateTime.monday,
                              label: Text('دووشەممە'),
                            ),
                          ],
                          selected: {_weekStart},
                          onSelectionChanged: (selection) =>
                              setState(() => _weekStart = selection.first),
                        ),
                        const SizedBox(height: 8),
                        SwitchListTile(
                          contentPadding: EdgeInsets.zero,
                          dense: true,
                          title:
                              const Text('متناسب لجميع الشاشات (Responsive)'),
                          value: _responsive,
                          onChanged: (v) => setState(() => _responsive = v),
                        ),
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 16),

                // -----------------------------------------------------------------
                // 1. Basic Kurdish Date Picker (single) with events
                // -----------------------------------------------------------------
                _sectionTitle('1. بڕگەی سادە (Basic + Events)'),
                Row(
                  children: [
                    FilledButton.tonalIcon(
                      onPressed: () => _controller.previousMonth(),
                      icon: const Icon(Icons.chevron_left),
                      label: const Text('پێشوو'),
                    ),
                    FilledButton.tonalIcon(
                      onPressed: () => _controller.nextMonth(),
                      icon: const Icon(Icons.chevron_right),
                      label: const Text('دوواتر'),
                    ),
                  ],
                ),
                const SizedBox(height: 8),
                KurdishDatePicker(
                  controller: _controller,
                  initialDate: DateTime.now(),
                  firstDate: DateTime(2020),
                  lastDate: DateTime(2030),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  selectionMode: DateSelectionMode.single,
                  showTodayButton: true,
                  weekStart: _weekStart,
                  responsive: _responsive,
                  events: _events,
                  onDateSelected: (date) => setState(() => _singleDate = date),
                ),
                const SizedBox(height: 8),
                _resultLine(
                    'رێکەوتەکەت:',
                    _singleDate == null
                        ? 'نەهەڵبژێردراوە'
                        : _fmt(_singleDate!)),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 2. Dialog APIs
                // -----------------------------------------------------------------
                _sectionTitle('2. بڕگەی دیالۆگ (Dialog)'),
                Wrap(
                  spacing: 8,
                  runSpacing: 8,
                  children: [
                    FilledButton.icon(
                      onPressed: _pickDate,
                      icon: const Icon(Icons.calendar_today),
                      label: const Text('هەڵبژاردنی رۆژ'),
                    ),
                    FilledButton.tonalIcon(
                      onPressed: _pickRange,
                      icon: const Icon(Icons.date_range),
                      label: const Text('ماوە (Range)'),
                    ),
                    FilledButton.tonalIcon(
                      onPressed: _pickMulti,
                      icon: const Icon(Icons.calendar_month),
                      label: const Text('چەند رۆژ (Multiple)'),
                    ),
                  ],
                ),
                const SizedBox(height: 8),
                _resultLine(
                    'رۆژ:', _singleDate == null ? '—' : _fmt(_singleDate!)),
                _resultLine(
                    'ماوە:',
                    _range == null
                        ? '—'
                        : '${_fmt(_range!.start)} → ${_fmt(_range!.end)}'),
                if (_multiDates.isNotEmpty)
                  _resultLine(
                    'چەند رۆژ (${KurdishNumberFormatter.toSystem(_multiDates.length, _numberSystem)}):',
                    _multiDates.map(_fmt).join('، '),
                  ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 3. RTL + Kurdish numerals focus
                // -----------------------------------------------------------------
                _sectionTitle('3. RTL و ژمارە کوردییەکان (RTL + Numerals)'),
                Container(
                  padding: const EdgeInsets.all(12),
                  decoration: BoxDecoration(
                    color: _isRtlLocale
                        ? Theme.of(context).colorScheme.primaryContainer
                        : Theme.of(context).colorScheme.surfaceContainerHighest,
                    borderRadius: BorderRadius.circular(14),
                  ),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text(
                        _isRtlLocale
                            ? 'ئەم بڕگەیە بە شێوازی RTL دەردەکەوێت و هەموو ژمارەکان بە سیستەمی ${_numberSystem == NumberSystem.latin ? 'لاتینی' : '٢٠٢٦'}ن'
                            : 'English + Latin numerals (LTR)',
                        style: Theme.of(context).textTheme.bodyMedium,
                      ),
                      const SizedBox(height: 8),
                      KurdishMonthPicker(
                        locale: _locale,
                        year: 2026,
                        selectedMonth: DateTime.now().month,
                        numberSystem: _numberSystem,
                      ),
                    ],
                  ),
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 3.5 Customization (interactive theme controls)
                // -----------------------------------------------------------------
                _sectionTitle('3.5 تایبەتکردن (Customization)'),
                Card(
                  elevation: 0,
                  color: Theme.of(context).colorScheme.surfaceContainerHighest,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(14),
                  ),
                  child: Padding(
                    padding: const EdgeInsets.all(12),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        _colorRow('رەنگی هەڵبژێردراو', _customSelected,
                            (c) => setState(() => _customSelected = c)),
                        _colorRow('رەنگی ئەمڕۆ', _customToday,
                            (c) => setState(() => _customToday = c)),
                        _colorRow('رەنگی کۆتایی هەفتە', _customWeekend,
                            (c) => setState(() => _customWeekend = c)),
                        const SizedBox(height: 12),
                        Text(
                          'گۆشەی گەورە (Border radius): ${_customRadius.round()}',
                          style: Theme.of(context).textTheme.bodyMedium,
                        ),
                        Slider(
                            value: _customRadius,
                            min: 0,
                            max: 32,
                            onChanged: (v) =>
                                setState(() => _customRadius = v)),
                        Text(
                          'قەبارەی خانە (Cell size): ${_customCellSize.round()}',
                          style: Theme.of(context).textTheme.bodyMedium,
                        ),
                        Slider(
                            value: _customCellSize,
                            min: 32,
                            max: 72,
                            onChanged: (v) =>
                                setState(() => _customCellSize = v)),
                        Text(
                          'قەبارەی دەق (Text size): ${_customTextSize.round()}',
                          style: Theme.of(context).textTheme.bodyMedium,
                        ),
                        Slider(
                            value: _customTextSize,
                            min: 10,
                            max: 22,
                            onChanged: (v) =>
                                setState(() => _customTextSize = v)),
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 12),
                KurdishDatePicker(
                  initialDate: DateTime.now(),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  showTodayButton: true,
                  themeData: KurdishDatePickerTheme(
                    selectedColor: _customSelected,
                    todayColor: _customToday,
                    weekendColor: _customWeekend,
                    borderRadius:
                        BorderRadius.all(Radius.circular(_customRadius)),
                    cellSize: _customCellSize,
                    textTheme: Theme.of(context)
                        .textTheme
                        .apply(fontSizeFactor: _customTextSize / 14),
                  ),
                  onDateSelected: (date) {},
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 4. Custom theme
                // -----------------------------------------------------------------
                _sectionTitle('4. تێمای تایبەت (Custom Theme)'),
                KurdishDatePicker(
                  initialDate: DateTime.now(),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  showTodayButton: true,
                  themeData: const KurdishDatePickerTheme(
                    selectedColor: Colors.deepPurple,
                    todayColor: Colors.amber,
                    weekendColor: Colors.pink,
                    borderRadius: BorderRadius.all(Radius.circular(16)),
                    headerColor: Colors.deepPurple,
                    headerTextColor: Colors.white,
                  ),
                  onDateSelected: (date) {},
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 5. Range picker (inline)
                // -----------------------------------------------------------------
                _sectionTitle('5. ماوە (Range)'),
                KurdishDatePicker(
                  initialDate: DateTime.now(),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  selectionMode: DateSelectionMode.range,
                  showTodayButton: true,
                  onRangeSelected: (s, e) =>
                      setState(() => _range = KurdishDateRange(s, e)),
                ),
                _resultLine(
                    'ماوە:',
                    _range == null
                        ? 'نەهەڵبژێردراوە'
                        : '${_fmt(_range!.start)} → ${_fmt(_range!.end)}'),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 6. Multiple picker (inline)
                // -----------------------------------------------------------------
                _sectionTitle('6. چەند رۆژ (Multiple)'),
                KurdishDatePicker(
                  initialDate: DateTime.now(),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  selectionMode: DateSelectionMode.multiple,
                  showTodayButton: true,
                  onDatesSelected: (dates) => setState(() {
                    _multiDates
                      ..clear()
                      ..addAll(dates);
                  }),
                ),
                _resultLine(
                  'ژمارەی هەڵبژێردراو:',
                  KurdishNumberFormatter.toSystem(
                      _multiDates.length, _numberSystem),
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 7. Disabled dates + first/last restrictions
                // -----------------------------------------------------------------
                _sectionTitle('7. رۆژە ناچالاکەکان (Disabled)'),
                KurdishDatePicker(
                  initialDate: DateTime(2026, 9, 1),
                  firstDate: DateTime(2026, 9, 1),
                  lastDate: DateTime(2026, 9, 30),
                  locale: _locale,
                  numberSystem: _numberSystem,
                  disabledDates: [
                    DateTime(2026, 9, 10),
                    DateTime(2026, 9, 15),
                    DateTime(2026, 9, 20),
                  ],
                  onDateSelected: (date) {},
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 8. Date input
                // -----------------------------------------------------------------
                _sectionTitle('8. خانەی داخڵکردنی رێکەوت (Date Input)'),
                KurdishDateInput(
                  locale: _locale,
                  numberSystem: _numberSystem,
                  initialDate: DateTime.now(),
                  onDateChanged: (date) {},
                ),
                const Divider(height: 32),

                // -----------------------------------------------------------------
                // 9. Formatting helpers
                // -----------------------------------------------------------------
                _sectionTitle('9. ژمارە و فۆرماتکردن (Formatting)'),
                _resultLine('toSystem(2026):',
                    KurdishNumberFormatter.toSystem(2026, _numberSystem)),
                _resultLine(
                    'format date:',
                    KurdishDateFormatter.format(
                      DateTime(2026, 9, 3),
                      locale: _locale,
                      numberSystem: _numberSystem,
                    )),
                _resultLine(
                    'formatNumeric:',
                    KurdishDateFormatter.formatNumeric(
                      DateTime(2026, 6, 15),
                      numberSystem: _numberSystem,
                    )),
                _resultLine('toLatinString(٢٠٢٦):',
                    KurdishNumberFormatter.toLatinString('٢٠٢٦')),
                const SizedBox(height: 8),

                // -----------------------------------------------------------------
                // 10. Hijri (Islamic) date conversion
                // -----------------------------------------------------------------
                _sectionTitle('10. رێکەوتی کۆچی (Hijri)'),
                _resultLine('Hijri (ئەمڕۆ):', _fmtHijri(DateTime.now())),
                _resultLine(
                    'Hijri (هەڵبژێردراو):',
                    _singleDate == null
                        ? 'نەهەڵبژێردراوە'
                        : _fmtHijri(_singleDate!)),
                const SizedBox(height: 24),
              ],
            ),
          ),
        ),
      ),
    );
  }

  Widget _sectionTitle(String text) {
    return Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Text(
        text,
        style: Theme.of(context)
            .textTheme
            .titleMedium
            ?.copyWith(fontWeight: FontWeight.bold),
      ),
    );
  }

  Widget _resultLine(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 2),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '$label ',
            style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                color: Theme.of(context).colorScheme.primary,
                fontWeight: FontWeight.w600),
          ),
          Expanded(
            child: Text(
              value,
              textAlign: TextAlign.left,
              style: Theme.of(context).textTheme.bodyMedium,
            ),
          ),
        ],
      ),
    );
  }

  // A tappable color swatch that cycles through a small palette, used by the
  // interactive customization demo so developers can preview theme colors live.
  static const List<Color> _palette = [
    Colors.deepPurple,
    Colors.teal,
    Colors.indigo,
    Colors.orange,
    Colors.redAccent,
    Colors.green,
  ];

  Widget _colorRow(String label, Color color, ValueChanged<Color> onChange) {
    final index = _palette.indexOf(color);
    final next = _palette[(index + 1) % _palette.length];
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        children: [
          GestureDetector(
            onTap: () => onChange(next),
            child: Container(
              width: 28,
              height: 28,
              decoration: BoxDecoration(
                color: color,
                shape: BoxShape.circle,
                border: Border.all(
                    color: Theme.of(context).colorScheme.outline, width: 1.5),
              ),
            ),
          ),
          const SizedBox(width: 12),
          Text(label, style: Theme.of(context).textTheme.bodyMedium),
        ],
      ),
    );
  }
}
1
likes
160
points
257
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A professional Kurdish-first Date Picker and Calendar for Flutter: Sorani RTL, Kurdish day/month names, Kurdish numerals, and single/range/multiple selection with theming.

Homepage
Repository (GitHub)
View/report issues
Contributing

Topics

#date-picker #calendar #kurdish #rtl #localization

License

BSD-3-Clause (license)

Dependencies

flutter, intl

More

Packages that depend on kurdish_date_picker