Timely X Flutter
A powerful and customizable calendar and resource scheduling library for Flutter applications. Timely X provides beautiful, responsive calendar views and resource scheduling components to help you build professional scheduling applications with ease.
📱 Screenshots
Day View | Week View | Month View | Resource View |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
✨ Features
- Multiple View Modes: Switch between Day, Week, and Month views
- Resource Scheduling: Manage resources like rooms, employees, or equipment
- Fully Customizable: Customize colors, layouts, and behaviors
- Responsive Design: Works on mobile, tablet, and desktop
- Interactive: Support for drag & drop, swipe gestures, and more
- Localization: Built-in support for multiple languages
- Theming: Seamlessly integrates with your app's theme
🚀 Installation
Add the following to your pubspec.yaml
file:
dependencies:
timely_x: ^0.0.1 # Check for the latest version
intl: ^0.18.0 # For date formatting
jiffy: ^6.2.0 # For date manipulation
Then run:
flutter pub get
🎯 Quick Start
Basic Calendar
import 'package:flutter/material.dart';
import 'package:timely_x/timely_x.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Timely X Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: CalendarScreen(),
);
}
}
class CalendarScreen extends StatelessWidget {
final List<TyxEvent> events = [
TyxEvent(
id: '1',
title: 'Team Meeting',
start: DateTime.now().add(Duration(hours: 10)),
end: DateTime.now().add(Duration(hours: 11)),
color: Colors.blue,
),
// Add more events...
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Timely X Calendar'),
actions: [
IconButton(
icon: Icon(Icons.today),
onPressed: () {
// Handle today button press
},
),
],
),
body: Expanded(
child: TyxCalendarView<AppointmentModel>(
onViewChanged: (view) {
// _activeView = view;
},
onDateChanged: (view, events) {},
onBorderChanged: (border) {
_filter = (_filter ?? AppointmentFilter())
.copyWith(startDate: border.start, endDate: border.end);
_loadAppointments();
},
option: TyxCalendarOption<AppointmentModel>(
timesCellWidth: 60,
initialView: TyxView.day,
events: allEvents,
monthOption: TyxCalendarMonthOption<AppointmentModel>(
eventListTileBuilder: (context, event) {
var colorScheme = ColorScheme.fromSeed(
seedColor: event.provider!.appointmentColor != null
? ColorsUtils.hexToColor(
event.provider!.appointmentColor!)
: event.color,
);
return Card(
margin: const EdgeInsets.only(bottom: 8),
elevation: 0.2,
surfaceTintColor: colorScheme.primaryContainer,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 4,
height: 50,
decoration: BoxDecoration(
color: colorScheme.primary,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Container(
padding: EdgeInsets.symmetric(
horizontal: 4, vertical: 4),
decoration: BoxDecoration(
color: colorScheme.primaryContainer,
borderRadius:
BorderRadius.circular(20),
),
child: SelectableText(
event.code ?? 'N/A',
style: TextStyle(
color: colorScheme
.onPrimaryContainer,
fontWeight: FontWeight.w600,
fontSize: 11,
),
),
),
SizedBox(width: 8),
Expanded(
child: Text(
AppointmentUtils
.getAppointmentTitle(event),
style: Theme.of(context)
.textTheme
.titleSmall
?.copyWith(
fontWeight: FontWeight.bold,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
const SizedBox(height: 4),
Text(
'${TimeOfDay.fromDateTime(event.start).format(context)} - ${TimeOfDay.fromDateTime(event.end).format(context)}',
style:
Theme.of(context).textTheme.bodySmall,
),
if (event.store != null)
Padding(
padding: const EdgeInsets.only(top: 4),
child: Row(
children: [
Icon(
Icons.location_on_outlined,
size: 14,
color: Theme.of(context)
.disabledColor,
),
const SizedBox(width: 4),
Expanded(
child: Text(
event.store!.name!,
style: Theme.of(context)
.textTheme
.bodySmall
?.copyWith(
color: Theme.of(context)
.disabledColor,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
],
),
),
],
),
),
],
),
),
);
},
),
),
onEventTapped: (event) {
context.router.push(AppointmentDetailsRoute(id: event.id));
},
),
),,
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add new event
},
child: Icon(Icons.add),
),
);
}
}
🛠️ Advanced Usage
Custom Event Widget
eventBuilder: (context, event) {
return Container(
margin: EdgeInsets.symmetric(horizontal: 2, vertical: 1),
padding: EdgeInsets.all(4),
decoration: BoxDecoration(
color: event.color?.withOpacity(0.2) ?? Theme.of(context).primaryColor.withOpacity(0.2),
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: event.color ?? Theme.of(context).primaryColor,
width: 1,
),
),
child: Text(
event.title ?? '',
style: TextStyle(
color: event.color ?? Theme.of(context).primaryColor,
fontSize: 12,
fontWeight: FontWeight.w500,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
);
},
Localization
import 'package:flutter_localizations/flutter_localizations.dart';
// In your MaterialApp
MaterialApp(
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: [
const Locale('en', ''), // English
const Locale('fr', ''), // French
// Add other locales
],
// ...
)
📚 API Reference
TyxCalendarView Properties
Property | Type | Description |
---|---|---|
option |
TyxCalendarOption |
Required. Configuration options for the calendar |
onDateChanged |
Function(DateTime) |
Callback when the selected date changes |
onEventTapped |
Function(TyxEvent) |
Callback when an event is tapped |
onViewChanged |
Function(TyxView) |
Callback when the view type changes |
TyxCalendarOption Properties
Property | Type | Default | Description |
---|---|---|---|
initialView |
TyxView |
TyxView.month |
Initial view type (day, week, month) |
initialDate |
DateTime |
DateTime.now() |
Initial selected date |
events |
List<TyxEvent> |
[] |
List of events to display |
timeslotHeight |
double |
60.0 |
Height of each time slot in pixels |
timeslotStartTime |
TimeOfDay |
TimeOfDay(hour: 0, minute: 0) |
Start time for day/week view |
timeslotEndTime |
TimeOfDay |
TimeOfDay(hour: 23, minute: 59) |
End time for day/week view |
showTrailingDays |
bool |
false |
Whether to show days from next/previous months |
startWeekDay |
int |
7 (Sunday) |
First day of week (1 = Monday, 7 = Sunday) |
🤝 Contributing
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature
) - Commit your changes (
git commit -m 'Add some AmazingFeature'
) - Push to the branch (
git push origin feature/AmazingFeature
) - Open a Pull Request
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments
- Built with ❤️ using Flutter
- Inspired by various calendar and scheduling applications
- Special thanks to all contributors
Made with ❤️ by Loic NGOU