ticktock 0.0.3 copy "ticktock: ^0.0.3" to clipboard
ticktock: ^0.0.3 copied to clipboard

A customizable clock picker widget for Flutter with scroll bar time selection.

TickTock ⏰ #

A customizable scrollable time picker widget for Flutter with intuitive scroll wheel interface for precise time selection.

Screenshots #

[Image 1] [Image 2] [Image 3]

Features #

  • 🎨 Highly Customizable: Extensive styling options for colors, fonts, and appearance
  • πŸ“± Scroll Interface: Modern scroll wheel picker for hours, minutes, and AM/PM
  • 🌍 24-Hour Support: Toggle between 12-hour and 24-hour formats
  • πŸ”„ Infinite Scroll: Optional infinite scrolling for seamless time selection
  • 🎯 Precise Selection: Dedicated columns for hours, minutes, and period
  • 🎨 Custom Labels: Customizable text and styling for column labels
  • πŸ”§ Action Buttons: Optional Done/Cancel buttons with custom styling
  • ⚑ Real-time Callbacks: Continuous time updates during scrolling

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  ticktock: ^0.0.1

Then run:

flutter pub get

Quick Start #

Basic Usage #

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('TickTock Example')),
        body: Center(
          child: TickTock(
            initialTime: TimeOfDay.now(),
            onTimeChanged: (time) {
              print('Selected time: ${time.format(context)}');
            },
          ),
        ),
      ),
    );
  }
}

With Custom Styling #

TickTock(
  initialTime: TimeOfDay(hour: 14, minute: 30),
  height: 250.0,
  onTimeChanged: (time) {
    print('Time changed: ${time.format(context)}');
  },
  style: TicktockStyle(
    selectedTimeColor: Colors.deepPurple,
    backgroundColor: Colors.purple.shade50,
    use24HourFormat: false,
    infiniteScroll: true,
    hourLabelText: 'Hours',
    minuteLabelText: 'Minutes',
    periodLabelText: 'AM/PM',
  ),
)

Comprehensive Examples #

1. 24-Hour Format with Action Buttons #

class TimePicker24Hour extends StatefulWidget {
  @override
  _TimePicker24HourState createState() => _TimePicker24HourState();
}

class _TimePicker24HourState extends State<TimePicker24Hour> {
  TimeOfDay selectedTime = TimeOfDay.now();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(
          'Selected: ${selectedTime.format(context)}',
          style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
        ),
        SizedBox(height: 20),
        TickTock(
          initialTime: selectedTime,
          height: 300,
          onTimeChanged: (time) {
            setState(() {
              selectedTime = time;
            });
          },
          onTimeSelected: (time) {
            // Handle confirmed selection
            ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text('Time confirmed: ${time.format(context)}')),
            );
          },
          onTimeCancelled: (time) {
            // Handle cancellation
            setState(() {
              selectedTime = TimeOfDay.now(); // Reset to current time
            });
          },
          style: TicktockStyle(
            use24HourFormat: true,
            infiniteScroll: true,
            showDoneButton: true,
            showCancelButton: true,
            selectedTimeColor: Colors.teal,
            backgroundColor: Colors.teal.shade50,
            hourLabelText: 'Hour (24h)',
            minuteLabelText: 'Minute',
            doneButtonText: 'Confirm',
            cancelButtonText: 'Reset',
            hourLabelTextStyle: TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w600,
              color: Colors.teal.shade700,
            ),
          ),
        ),
      ],
    );
  }
}

2. Dark Theme Picker #

TickTock(
  initialTime: TimeOfDay.now(),
  height: 280,
  onTimeChanged: (time) => print('Dark theme time: $time'),
  style: TicktockStyle(
    backgroundColor: Colors.grey.shade900,
    selectedTimeColor: Colors.cyan,
    dialColor: Colors.cyan,
    hourTextStyle: TextStyle(
      fontSize: 16,
      fontWeight: FontWeight.w500,
      color: Colors.white70,
    ),
    selectedTimeTextStyle: TextStyle(
      fontSize: 22,
      fontWeight: FontWeight.bold,
      color: Colors.cyan,
    ),
    hourLabelTextStyle: TextStyle(
      fontSize: 12,
      fontWeight: FontWeight.w500,
      color: Colors.cyan.shade300,
    ),
    minuteLabelTextStyle: TextStyle(
      fontSize: 12,
      fontWeight: FontWeight.w500,
      color: Colors.cyan.shade300,
    ),
    periodLabelTextStyle: TextStyle(
      fontSize: 12,
      fontWeight: FontWeight.w500,
      color: Colors.cyan.shade300,
    ),
    hourLabelText: 'Hr',
    minuteLabelText: 'Min',
    periodLabelText: 'Period',
    infiniteScroll: true,
  ),
)

3. Minimal Design #

TickTock(
  initialTime: TimeOfDay.now(),
  height: 200,
  showAmPm: true,
  onTimeChanged: (time) => print('Minimal time: $time'),
  style: TicktockStyle(
    backgroundColor: Colors.transparent,
    selectedTimeColor: Colors.black87,
    dialColor: Colors.grey.shade300,
    hourTextStyle: TextStyle(
      fontSize: 16,
      color: Colors.grey.shade600,
    ),
    selectedTimeTextStyle: TextStyle(
      fontSize: 20,
      fontWeight: FontWeight.w600,
      color: Colors.black87,
    ),
    hourLabelTextStyle: TextStyle(
      fontSize: 11,
      color: Colors.grey.shade500,
      letterSpacing: 0.5,
    ),
    minuteLabelTextStyle: TextStyle(
      fontSize: 11,
      color: Colors.grey.shade500,
      letterSpacing: 0.5,
    ),
    periodLabelTextStyle: TextStyle(
      fontSize: 11,
      color: Colors.grey.shade500,
      letterSpacing: 0.5,
    ),
  ),
)

4. Custom Labels & Multilingual Support #

TickTock(
  initialTime: TimeOfDay.now(),
  onTimeChanged: (time) => print('Custom labels time: $time'),
  style: TicktockStyle(
    selectedTimeColor: Colors.orange,
    backgroundColor: Colors.orange.shade50,
    // Custom label text
    hourLabelText: 'Horas',
    minuteLabelText: 'Minutos', 
    periodLabelText: 'PerΓ­odo',
    // Custom label styling
    hourLabelTextStyle: TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.bold,
      color: Colors.orange.shade800,
      letterSpacing: 1.0,
    ),
    minuteLabelTextStyle: TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.bold,
      color: Colors.orange.shade800,
      letterSpacing: 1.0,
    ),
    periodLabelTextStyle: TextStyle(
      fontSize: 14,
      fontWeight: FontWeight.bold,
      color: Colors.orange.shade800,
      letterSpacing: 1.0,
    ),
    showDoneButton: true,
    doneButtonText: 'Confirmar',
    doneButtonTextStyle: TextStyle(
      fontSize: 16,
      fontWeight: FontWeight.bold,
      color: Colors.orange.shade700,
    ),
  ),
)

5. Dialog Integration #

class TimePickerDialog extends StatelessWidget {
  final TimeOfDay initialTime;
  final ValueChanged<TimeOfDay> onTimeSelected;

  const TimePickerDialog({
    Key? key,
    required this.initialTime,
    required this.onTimeSelected,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return AlertDialog(
      title: Text('Select Time'),
      content: SizedBox(
        height: 250,
        width: 300,
        child: TickTock(
          initialTime: initialTime,
          onTimeSelected: (time) {
            onTimeSelected(time);
            Navigator.of(context).pop();
          },
          onTimeCancelled: (_) {
            Navigator.of(context).pop();
          },
          style: TicktockStyle(
            showDoneButton: true,
            showCancelButton: true,
            selectedTimeColor: Theme.of(context).primaryColor,
            backgroundColor: Colors.transparent,
            infiniteScroll: true,
          ),
        ),
      ),
    );
  }

  static Future<TimeOfDay?> show(
    BuildContext context, {
    required TimeOfDay initialTime,
  }) {
    return showDialog<TimeOfDay>(
      context: context,
      builder: (context) => TimePickerDialog(
        initialTime: initialTime,
        onTimeSelected: (time) => Navigator.of(context).pop(time),
      ),
    );
  }
}

// Usage:
// TimeOfDay? selectedTime = await TimePickerDialog.show(
//   context,
//   initialTime: TimeOfDay.now(),
// );

Customization Reference #

TicktockStyle Properties #

Colors

Property Type Default Description
selectedTimeColor Color Colors.blue Color for selected time values
backgroundColor Color Colors.white Background color of picker
dialColor Color Colors.blue Color for separators and accents

Text Styling

Property Type Default Description
hourTextStyle TextStyle Default Style for unselected items
selectedTimeTextStyle TextStyle Default Style for selected items
hourLabelTextStyle TextStyle Default Style for hour column label
minuteLabelTextStyle TextStyle Default Style for minute column label
periodLabelTextStyle TextStyle Default Style for AM/PM column label

Behavior Options

Property Type Default Description
use24HourFormat bool false Use 24-hour (00-23) vs 12-hour format
infiniteScroll bool false Enable infinite scrolling
showAmPm bool true Show AM/PM selector (12-hour only)

Action Buttons

Property Type Default Description
showDoneButton bool false Show confirmation button
showCancelButton bool false Show cancel button
doneButtonText String 'OK' Text for done button
cancelButtonText String 'Cancel' Text for cancel button

Custom Labels

Property Type Default Description
hourLabelText String 'Hour' Text for hour column label
minuteLabelText String 'Minute' Text for minute column label
periodLabelText String 'Period' Text for AM/PM column label

Widget Properties #

TickTock

Property Type Required Description
initialTime TimeOfDay Yes Starting time to display
onTimeChanged ValueChanged No Called during scrolling
onTimeSelected ValueChanged No Called when Done pressed
onTimeCancelled ValueChanged No Called when Cancel pressed
style TicktockStyle No Styling configuration
height double No Height of picker (default: 200)
showAmPm bool No Show AM/PM selector (default: true)

Common Use Cases #

1. Settings Page Time Picker #

ListTile(
  title: Text('Wake up time'),
  subtitle: Text(wakeUpTime.format(context)),
  onTap: () {
    showModalBottomSheet(
      context: context,
      builder: (context) => Container(
        height: 300,
        child: TickTock(
          initialTime: wakeUpTime,
          onTimeSelected: (time) {
            setState(() => wakeUpTime = time);
            Navigator.pop(context);
          },
          style: TicktockStyle(
            showDoneButton: true,
            infiniteScroll: true,
          ),
        ),
      ),
    );
  },
)

2. Alarm App Integration #

TickTock(
  initialTime: alarmTime,
  onTimeChanged: (time) {
    setState(() => alarmTime = time);
    // Update alarm service immediately
    AlarmService.updateAlarm(alarmId, time);
  },
  style: TicktockStyle(
    use24HourFormat: true,
    selectedTimeColor: Colors.red,
    infiniteScroll: true,
    hourLabelText: 'H',
    minuteLabelText: 'M',
  ),
)

3. Appointment Booking #

TickTock(
  initialTime: TimeOfDay(hour: 9, minute: 0),
  onTimeSelected: (time) {
    bookAppointment(selectedDate, time);
  },
  style: TicktockStyle(
    showDoneButton: true,
    doneButtonText: 'Book Appointment',
    selectedTimeColor: Colors.green,
    backgroundColor: Colors.green.shade50,
  ),
)

Contributing #

Contributions are welcome! Please feel free to submit a Pull Request.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog #

See CHANGELOG.md for a list of changes.

4
likes
0
points
34
downloads

Publisher

unverified uploader

Weekly Downloads

A customizable clock picker widget for Flutter with scroll bar time selection.

Repository (GitHub)
View/report issues

License

unknown (license)

Dependencies

flutter

More

Packages that depend on ticktock