-
Notifications
You must be signed in to change notification settings - Fork 259
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Added month view - Added day view - Added example to demonstrate month view and day view.
- Loading branch information
1 parent
1408efb
commit ecb8852
Showing
32 changed files
with
3,080 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,3 +46,4 @@ app.*.map.json | |
/android/app/release | ||
|
||
pubspec.lock | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import 'dart:ui'; | ||
|
||
class AppConstants { | ||
AppConstants._(); | ||
|
||
static const Color black = Color(0xff444444); | ||
static const Color white = Color(0xffefefef); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,209 @@ | ||
import 'package:example/constants.dart'; | ||
import 'package:example/date_time_selector.dart'; | ||
import 'package:example/event.dart'; | ||
import 'package:flutter/cupertino.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_calendar_page/flutter_calendar_page.dart'; | ||
|
||
import 'extension.dart'; | ||
|
||
class CreateEventPage extends StatefulWidget { | ||
final bool withDuration; | ||
|
||
const CreateEventPage({Key? key, this.withDuration = false}) | ||
: super(key: key); | ||
|
||
@override | ||
_CreateEventPageState createState() => _CreateEventPageState(); | ||
} | ||
|
||
class _CreateEventPageState extends State<CreateEventPage> { | ||
GlobalKey<FormState> _formKey = GlobalKey(); | ||
|
||
late DateTime _date; | ||
DateTime? _startTime; | ||
DateTime? _endTime; | ||
String _title = ""; | ||
String _description = ""; | ||
|
||
late FocusNode _titleNode; | ||
late FocusNode _descriptionNode; | ||
late FocusNode _dateNode; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
|
||
_titleNode = FocusNode(); | ||
_descriptionNode = FocusNode(); | ||
_dateNode = FocusNode(); | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_titleNode.dispose(); | ||
_descriptionNode.dispose(); | ||
_dateNode.dispose(); | ||
|
||
super.dispose(); | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return Scaffold( | ||
appBar: AppBar( | ||
elevation: 0, | ||
backgroundColor: Theme.of(context).scaffoldBackgroundColor, | ||
centerTitle: false, | ||
leading: IconButton( | ||
onPressed: context.popRoute, | ||
icon: Icon( | ||
Icons.arrow_back, | ||
color: AppConstants.black, | ||
), | ||
), | ||
title: Text( | ||
"Create New Event", | ||
style: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 20.0, | ||
fontWeight: FontWeight.bold, | ||
), | ||
), | ||
), | ||
body: Form( | ||
key: _formKey, | ||
child: ListView( | ||
padding: const EdgeInsets.symmetric(vertical: 30.0, horizontal: 10.0), | ||
shrinkWrap: true, | ||
scrollDirection: Axis.vertical, | ||
children: [ | ||
TextFormField( | ||
focusNode: _titleNode, | ||
style: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 17.0, | ||
), | ||
decoration: InputDecoration( | ||
labelText: "Title", | ||
), | ||
textInputAction: TextInputAction.next, | ||
validator: (value) { | ||
if (value == null || value.trim() == "") return "Invalid Title"; | ||
return null; | ||
}, | ||
onSaved: (value) => _title = value ?? "", | ||
), | ||
SizedBox( | ||
height: 15.0, | ||
), | ||
DateTimeSelectorFormField( | ||
decoration: InputDecoration( | ||
labelText: "Select Date", | ||
), | ||
onSave: (date) => _date = date, | ||
textStyle: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 17.0, | ||
), | ||
type: DateTimeSelectionType.date, | ||
), | ||
SizedBox( | ||
height: 15.0, | ||
), | ||
if (widget.withDuration) ...[ | ||
Row( | ||
mainAxisSize: MainAxisSize.max, | ||
children: [ | ||
Expanded( | ||
child: DateTimeSelectorFormField( | ||
decoration: InputDecoration( | ||
labelText: "Start Time", | ||
), | ||
textStyle: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 17.0, | ||
), | ||
onSave: (date) => _startTime = date, | ||
type: DateTimeSelectionType.time, | ||
), | ||
), | ||
SizedBox(width: 20.0), | ||
Expanded( | ||
child: DateTimeSelectorFormField( | ||
decoration: InputDecoration( | ||
labelText: "End Time", | ||
), | ||
textStyle: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 17.0, | ||
), | ||
onSave: (date) => _endTime = date, | ||
type: DateTimeSelectionType.time, | ||
), | ||
), | ||
], | ||
), | ||
SizedBox( | ||
height: 15.0, | ||
), | ||
], | ||
TextFormField( | ||
focusNode: _descriptionNode, | ||
style: TextStyle( | ||
color: AppConstants.black, | ||
fontSize: 17.0, | ||
), | ||
keyboardType: TextInputType.multiline, | ||
textInputAction: TextInputAction.newline, | ||
selectionControls: MaterialTextSelectionControls(), | ||
minLines: 1, | ||
maxLines: 10, | ||
maxLength: 1000, | ||
validator: (value) { | ||
if (value == null || value.trim() == "") | ||
return "Invalid Description"; | ||
return null; | ||
}, | ||
decoration: InputDecoration( | ||
labelText: "Description", | ||
), | ||
onSaved: (value) => _description = value ?? "", | ||
), | ||
SizedBox( | ||
height: 50.0, | ||
), | ||
ElevatedButton( | ||
onPressed: () { | ||
if (_formKey.currentState?.validate() ?? false) { | ||
_formKey.currentState?.save(); | ||
CalendarEventData<Event> event = CalendarEventData<Event>( | ||
date: _date, | ||
event: Event(title: _title), | ||
title: _title, | ||
description: _description, | ||
startTime: _startTime, | ||
endTime: _endTime, | ||
); | ||
context.popRoute(event); | ||
} | ||
}, | ||
child: Text( | ||
"Create", | ||
style: Theme.of(context) | ||
.textTheme | ||
.subtitle1! | ||
.copyWith(color: AppConstants.white), | ||
), | ||
style: ButtonStyle( | ||
elevation: MaterialStateProperty.all<double>(8), | ||
padding: MaterialStateProperty.all<EdgeInsets>( | ||
EdgeInsets.symmetric(vertical: 10.0)), | ||
), | ||
), | ||
], | ||
), | ||
), | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_calendar_page/flutter_calendar_page.dart'; | ||
|
||
import 'extension.dart'; | ||
|
||
typedef Validator = String? Function(String? value); | ||
|
||
enum DateTimeSelectionType { date, time } | ||
|
||
class DateTimeSelectorFormField extends StatefulWidget { | ||
final Function(DateTime?)? onSelect; | ||
final DateTimeSelectionType? type; | ||
final FocusNode? focusNode; | ||
final DateTime? minimumDateTime; | ||
final Validator? validator; | ||
final bool displayDefault; | ||
final TextStyle? textStyle; | ||
final void Function(DateTime date)? onSave; | ||
final InputDecoration? decoration; | ||
|
||
const DateTimeSelectorFormField({ | ||
this.onSelect, | ||
this.type, | ||
this.onSave, | ||
this.decoration, | ||
this.focusNode, | ||
this.minimumDateTime, | ||
this.validator, | ||
this.displayDefault = false, | ||
this.textStyle, | ||
}); | ||
|
||
@override | ||
_DateTimeSelectorFormFieldState createState() => | ||
_DateTimeSelectorFormFieldState(); | ||
} | ||
|
||
class _DateTimeSelectorFormFieldState extends State<DateTimeSelectorFormField> { | ||
late TextEditingController _textEditingController; | ||
late FocusNode _focusNode; | ||
|
||
late DateTime _selectedDate; | ||
|
||
@override | ||
void initState() { | ||
super.initState(); | ||
|
||
_textEditingController = TextEditingController(); | ||
_focusNode = FocusNode(); | ||
|
||
_selectedDate = widget.minimumDateTime ?? DateTime.now(); | ||
|
||
if (widget.displayDefault && widget.minimumDateTime != null) { | ||
if (widget.type == DateTimeSelectionType.date) { | ||
_textEditingController.text = widget.minimumDateTime | ||
?.dateToStringWithFormat(format: "dd/MM/yyyy") ?? | ||
""; | ||
} else { | ||
_textEditingController.text = | ||
widget.minimumDateTime?.getTimeInFormat(TimeStampFormat.parse_12) ?? | ||
""; | ||
} | ||
} | ||
} | ||
|
||
@override | ||
void dispose() { | ||
_focusNode.dispose(); | ||
_textEditingController.dispose(); | ||
super.dispose(); | ||
} | ||
|
||
Future<void> _showSelector() async { | ||
DateTime? date; | ||
|
||
if (widget.type == DateTimeSelectionType.date) { | ||
date = await _showDateSelector(); | ||
_textEditingController.text = | ||
(date ?? _selectedDate).dateToStringWithFormat(format: "dd/MM/yyyy"); | ||
} else { | ||
date = await _showTimeSelector(); | ||
_textEditingController.text = | ||
(date ?? _selectedDate).getTimeInFormat(TimeStampFormat.parse_12); | ||
} | ||
|
||
_selectedDate = date ?? DateTime.now(); | ||
|
||
if (mounted) { | ||
setState(() {}); | ||
} | ||
|
||
widget.onSelect?.call(date); | ||
} | ||
|
||
Future<DateTime?> _showDateSelector() async { | ||
DateTime now = widget.minimumDateTime ?? DateTime.now(); | ||
|
||
DateTime? date = await showDatePicker( | ||
context: context, | ||
initialDate: now, | ||
firstDate: widget.minimumDateTime ?? now, | ||
lastDate: Constants.maxDate, | ||
); | ||
|
||
if (date == null) return null; | ||
|
||
return date; | ||
} | ||
|
||
Future<DateTime?> _showTimeSelector() async { | ||
DateTime now = widget.minimumDateTime ?? DateTime.now(); | ||
TimeOfDay? time = await showTimePicker( | ||
context: context, | ||
builder: (context, widget) { | ||
return widget ?? Container(); | ||
}, | ||
initialTime: TimeOfDay(hour: now.hour, minute: now.minute), | ||
); | ||
|
||
if (time == null) return null; | ||
|
||
DateTime? date = now.copyWith( | ||
hour: time.hour, | ||
minute: time.minute, | ||
); | ||
|
||
if (widget.minimumDateTime == null) return date; | ||
|
||
return date; | ||
} | ||
|
||
@override | ||
Widget build(BuildContext context) { | ||
return GestureDetector( | ||
onTap: _showSelector, | ||
child: TextFormField( | ||
style: widget.textStyle, | ||
controller: _textEditingController, | ||
validator: widget.validator, | ||
minLines: 1, | ||
onSaved: (value) => widget.onSave?.call(_selectedDate), | ||
enabled: false, | ||
decoration: widget.decoration, | ||
), | ||
); | ||
} | ||
} |
Oops, something went wrong.