Flutter Table Calendar : Showing Event from API to Table Calendar
You can copy paste run full code below
I simulate network delay with 3 seconds.
code snippet for you model
Future<Map<DateTime, List>> getTask1() async {
Map<DateTime, List> mapFetch = {};
List<EventModel> event = await getAllEvent();
for (int i = 0; i < event.length; i++) {
var createTime = DateTime(event[i].createTime.year,
event[i].createTime.month, event[i].createTime.day);
var original = mapFetch[createTime];
if (original == null) {
print("null");
mapFetch[createTime] = [event[i].tanggalEvent];
} else {
print(event[i].tanggalEvent);
mapFetch[createTime] = List.from(original)
..addAll([event[i].tanggalEvent]);
}
}
return mapFetch;
}
code snippet
WidgetsBinding.instance.addPostFrameCallback((_) {
getTask().then((val) => setState(() {
_events = val;
}));
//print( ' ${_events.toString()} ');
});
Future<Map<DateTime, List>> getTask() async {
Map<DateTime, List> mapFetch = {};
await Future.delayed(const Duration(seconds: 3), () {});
String responseString = '''
{
"status": "ok",
"message": "Event Is Found",
...
Event event = eventFromJson(responseString);
for (int i = 0; i < event.data.length; i++) {
var createTime = DateTime(event.data[i].createTime.year,
event.data[i].createTime.month, event.data[i].createTime.day);
var original = mapFetch[createTime];
if (original == null) {
print("null");
mapFetch[createTime] = [event.data[i].tanggalEvent];
} else {
print(event.data[i].tanggalEvent);
mapFetch[createTime] = List.from(original)..addAll([event.data[i].tanggalEvent]);
}
}
return mapFetch;
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';
import 'dart:convert';
Event eventFromJson(String str) => Event.fromJson(json.decode(str));
String eventToJson(Event data) => json.encode(data.toJson());
class Event {
String status;
String message;
List<Datum> data;
Event({
this.status,
this.message,
this.data,
});
factory Event.fromJson(Map<String, dynamic> json) => Event(
status: json["status"],
message: json["message"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"status": status,
"message": message,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
String kodeEvent;
DateTime tanggalEvent;
String judulEvent;
String lokasiEvent;
String isiEvent;
String fotoEvent;
String waktuEvent;
String statusEvent;
String createBy;
DateTime createTime;
String updateBy;
String updateTime;
Datum({
this.kodeEvent,
this.tanggalEvent,
this.judulEvent,
this.lokasiEvent,
this.isiEvent,
this.fotoEvent,
this.waktuEvent,
this.statusEvent,
this.createBy,
this.createTime,
this.updateBy,
this.updateTime,
});
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
kodeEvent: json["kodeEvent"],
tanggalEvent: DateTime.parse(json["tanggalEvent"]),
judulEvent: json["judulEvent"],
lokasiEvent: json["lokasiEvent"],
isiEvent: json["isiEvent"],
fotoEvent: json["fotoEvent"],
waktuEvent: json["waktuEvent"],
statusEvent: json["statusEvent"],
createBy: json["createBy"],
createTime: DateTime.parse(json["createTime"]),
updateBy: json["updateBy"],
updateTime: json["updateTime"],
);
Map<String, dynamic> toJson() => {
"kodeEvent": kodeEvent,
"tanggalEvent":
"${tanggalEvent.year.toString().padLeft(4, '0')}-${tanggalEvent.month.toString().padLeft(2, '0')}-${tanggalEvent.day.toString().padLeft(2, '0')}",
"judulEvent": judulEvent,
"lokasiEvent": lokasiEvent,
"isiEvent": isiEvent,
"fotoEvent": fotoEvent,
"waktuEvent": waktuEvent,
"statusEvent": statusEvent,
"createBy": createBy,
"createTime": createTime.toIso8601String(),
"updateBy": updateBy,
"updateTime": updateTime,
};
}
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
List _selectedEvents;
int _counter = 0;
Map<DateTime, List> _events;
CalendarController _calendarController;
AnimationController _animationController;
void _incrementCounter() {
setState(() {
_counter++;
});
}
Future<List<EventModel>> getAllEvent() async {
try {
//final response = await http.get(_baseUrl);
String responseString = '''
{
"status": "ok",
"message": "Event Is Found",
"data": [
{
"kodeEvent": "1",
"tanggalEvent": "2020-01-15",
"judulEvent": "Bangun Kembali 200 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Lombok",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8cd198530_202002181405.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "0",
"createTime": "2020-01-29 16:37:26",
"updateBy": "",
"updateTime": "2020-02-18 14:05:53"
},
{
"kodeEvent": "2",
"tanggalEvent": "2020-03-31",
"judulEvent": "Bangun Kembali 100 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Jakarta",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8d3d74b44_202002181407.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "",
"createTime": "2020-02-18 14:07:41",
"updateBy": "",
"updateTime": "0000-00-00 00:00:00"
},
{
"kodeEvent": "3",
"tanggalEvent": "2020-01-31",
"judulEvent": "Bangun Kembali 200 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Bandung",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8d72e2d37_202002181408.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "",
"createTime": "2020-02-18 14:08:34",
"updateBy": "",
"updateTime": "0000-00-00 00:00:00"
}
]
}
''';
final Map<String, dynamic> responseJson = json.decode(responseString);
if (responseJson["status"] == "ok") {
List eventList = responseJson['data'];
final result = eventList
.map<EventModel>((json) => EventModel.fromJson(json))
.toList();
return result;
} else {
//throw CustomError(responseJson['message']);
}
} catch (e) {
return Future.error(e.toString());
}
}
Future<Map<DateTime, List>> getTask1() async {
Map<DateTime, List> mapFetch = {};
List<EventModel> event = await getAllEvent();
for (int i = 0; i < event.length; i++) {
var createTime = DateTime(event[i].createTime.year,
event[i].createTime.month, event[i].createTime.day);
var original = mapFetch[createTime];
if (original == null) {
print("null");
mapFetch[createTime] = [event[i].tanggalEvent];
} else {
print(event[i].tanggalEvent);
mapFetch[createTime] = List.from(original)
..addAll([event[i].tanggalEvent]);
}
}
return mapFetch;
}
Future<Map<DateTime, List>> getTask() async {
Map<DateTime, List> mapFetch = {};
await Future.delayed(const Duration(seconds: 3), () {});
/*String link = baseURL + fetchTodoByDate;
var res = await http.post(Uri.encodeFull(link), headers: {"Accept": "application/json"});
if (res.statusCode == 200) {
// need help in creating fetch logic here
}*/
String responseString = '''
{
"status": "ok",
"message": "Event Is Found",
"data": [
{
"kodeEvent": "1",
"tanggalEvent": "2020-01-15",
"judulEvent": "Bangun Kembali 200 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Lombok",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8cd198530_202002181405.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "0",
"createTime": "2020-01-29 16:37:26",
"updateBy": "",
"updateTime": "2020-02-18 14:05:53"
},
{
"kodeEvent": "2",
"tanggalEvent": "2020-03-31",
"judulEvent": "Bangun Kembali 100 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Jakarta",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8d3d74b44_202002181407.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "",
"createTime": "2020-02-18 14:07:41",
"updateBy": "",
"updateTime": "0000-00-00 00:00:00"
},
{
"kodeEvent": "3",
"tanggalEvent": "2020-01-31",
"judulEvent": "Bangun Kembali 200 Masjid dan Mushalla Anti Gempa",
"lokasiEvent": "Bandung",
"isiEvent": "Gempa Bumi dahsyat bertubi-tubi guncang lombok, kini Pulau seribu Masjid lemah tak berdaya, Lebih dari 500 Masjid dan Mushalla rata dengan tanah, kini ibadah saudara kita harus bertebaran dimana-mana , masih banyak warga yang tak bisa melaksanakan shalat dengan nyaman. Lokasi masjid dan mushalla sudah tak dapat dipake kembali , semua rusak parah dan bahkan sudh rata dengan tanah.<br /><br />Terpaksa mereka shalat di luar, tempat terbuka , bahkan di atas reruntuhan bangunan rumah sekalipun. Kini tak kurang dari 300 Masjid dan Mushalla yang dilaporkan rusak, dan lebih dari 70 masjid yang hancur rata dengan tanah karena gempa. semua masjid ini tersebar di 3 kabupaten (lombok utara, lombok barat dan lombok timur).",
"fotoEvent": "event_5e4b8d72e2d37_202002181408.jpg",
"waktuEvent": "09:00 s.d Selesai",
"statusEvent": "t",
"createBy": "",
"createTime": "2020-02-18 14:08:34",
"updateBy": "",
"updateTime": "0000-00-00 00:00:00"
}
]
}
''';
Event event = eventFromJson(responseString);
for (int i = 0; i < event.data.length; i++) {
var createTime = DateTime(event.data[i].createTime.year,
event.data[i].createTime.month, event.data[i].createTime.day);
var original = mapFetch[createTime];
if (original == null) {
print("null");
mapFetch[createTime] = [event.data[i].tanggalEvent];
} else {
print(event.data[i].tanggalEvent);
mapFetch[createTime] = List.from(original)
..addAll([event.data[i].tanggalEvent]);
}
}
return mapFetch;
}
void _onDaySelected(DateTime day, List events) {
print('CALLBACK: _onDaySelected');
setState(() {
_selectedEvents = events;
});
}
@override
void initState() {
final _selectedDay = DateTime.now();
_selectedEvents = [];
_calendarController = CalendarController();
_animationController = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 400),
);
_animationController.forward();
WidgetsBinding.instance.addPostFrameCallback((_) {
getTask1().then((val) => setState(() {
_events = val;
}));
//print( ' ${_events.toString()} ');
});
super.initState();
}
@override
void dispose() {
_calendarController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
_buildTableCalendarWithBuilders(),
const SizedBox(height: 8.0),
const SizedBox(height: 8.0),
Expanded(child: _buildEventList()),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
Widget _buildTableCalendarWithBuilders() {
return TableCalendar(
//locale: 'pl_PL',
calendarController: _calendarController,
events: _events,
//holidays: _holidays,
initialCalendarFormat: CalendarFormat.month,
formatAnimation: FormatAnimation.slide,
startingDayOfWeek: StartingDayOfWeek.sunday,
availableGestures: AvailableGestures.all,
availableCalendarFormats: const {
CalendarFormat.month: '',
CalendarFormat.week: '',
},
calendarStyle: CalendarStyle(
outsideDaysVisible: false,
weekendStyle: TextStyle().copyWith(color: Colors.blue[800]),
holidayStyle: TextStyle().copyWith(color: Colors.blue[800]),
),
daysOfWeekStyle: DaysOfWeekStyle(
weekendStyle: TextStyle().copyWith(color: Colors.blue[600]),
),
headerStyle: HeaderStyle(
centerHeaderTitle: true,
formatButtonVisible: false,
),
builders: CalendarBuilders(
selectedDayBuilder: (context, date, _) {
return FadeTransition(
opacity: Tween(begin: 0.0, end: 1.0).animate(_animationController),
child: Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.deepOrange[300],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
),
);
},
todayDayBuilder: (context, date, _) {
return Container(
margin: const EdgeInsets.all(4.0),
padding: const EdgeInsets.only(top: 5.0, left: 6.0),
color: Colors.amber[400],
width: 100,
height: 100,
child: Text(
'${date.day}',
style: TextStyle().copyWith(fontSize: 16.0),
),
);
},
markersBuilder: (context, date, events, holidays) {
final children = <Widget>[];
if (events.isNotEmpty) {
children.add(
Positioned(
right: 1,
bottom: 1,
child: _buildEventsMarker(date, events),
),
);
}
if (holidays.isNotEmpty) {
children.add(
Positioned(
right: -2,
top: -2,
child: _buildHolidaysMarker(),
),
);
}
return children;
},
),
onDaySelected: (date, events) {
_onDaySelected(date, events);
_animationController.forward(from: 0.0);
},
onVisibleDaysChanged: _onVisibleDaysChanged,
);
}
void _onVisibleDaysChanged(
DateTime first, DateTime last, CalendarFormat format) {
print('CALLBACK: _onVisibleDaysChanged');
}
Widget _buildEventsMarker(DateTime date, List events) {
return AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: BoxDecoration(
shape: BoxShape.rectangle,
color: _calendarController.isSelected(date)
? Colors.brown[500]
: _calendarController.isToday(date)
? Colors.brown[300]
: Colors.blue[400],
),
width: 16.0,
height: 16.0,
child: Center(
child: Text(
'${events.length}',
style: TextStyle().copyWith(
color: Colors.white,
fontSize: 12.0,
),
),
),
);
}
Widget _buildHolidaysMarker() {
return Icon(
Icons.add_box,
size: 20.0,
color: Colors.blueGrey[800],
);
}
Widget _buildEventList() {
return ListView(
children: _selectedEvents
.map((event) => Container(
decoration: BoxDecoration(
border: Border.all(width: 0.8),
borderRadius: BorderRadius.circular(12.0),
),
margin:
const EdgeInsets.symmetric(horizontal: 8.0, vertical: 4.0),
child: ListTile(
title: Text(event.toString()),
onTap: () => print('$event tapped!'),
),
))
.toList(),
);
}
}
class EventModel {
String kodeEvent;
DateTime tanggalEvent;
String judulEvent;
String lokasiEvent;
String isiEvent;
String fotoEvent;
String waktuEvent;
String statusEvent;
String createBy;
DateTime createTime;
String updateBy;
String updateTime;
EventModel({
this.kodeEvent,
this.tanggalEvent,
this.judulEvent,
this.lokasiEvent,
this.isiEvent,
this.fotoEvent,
this.waktuEvent,
this.statusEvent,
this.createBy,
this.createTime,
this.updateBy,
this.updateTime,
});
factory EventModel.fromJson(Map<String, dynamic> json) => EventModel(
kodeEvent: json["kodeEvent"],
tanggalEvent: DateTime.parse(json["tanggalEvent"]),
judulEvent: json["judulEvent"],
lokasiEvent: json["lokasiEvent"],
isiEvent: json["isiEvent"],
fotoEvent: json["fotoEvent"],
waktuEvent: json["waktuEvent"],
statusEvent: json["statusEvent"],
createBy: json["createBy"],
createTime: DateTime.parse(json["createTime"]),
updateBy: json["updateBy"],
updateTime: json["updateTime"],
);
}
Flutter Table Calendar : Showing Event from API to Table Calendar Pub version table_calendar: ^3.0.6
Used
var mass= masslist_page.mass_list.groupListsBy((element) => DateTime.parse(element.mass_date));
and passed the grouped to
kEvents = LinkedHashMap<DateTime, List<MassListDetatils>>(
equals: isSameDay,
hashCode: getHashCode,
)..addAll(mass);
this solved to get the data from Api and passing it to the table Calender plugin in flutter. it groups the dates from the API and passes it to the list map and use that list map to pass it in the liked list format specified by the table_calender plugin which fetches the events on a particular date. masslist_page.mass_list
is the model created to the resulting json API
Is there a way to test if a gem is working? Or a way to see what functions it has
if you use bundler to install the gems you can do:
bundle show table_builder #show gem path
bundle open table_builder #open gem in default editor
Without bundler:
gem which table_builder #show gem path
#then open it...
In general you can see the code of all installed gems when you know their location. Then just debug the code ;)
Best way to implement a Calendar interface using Google Cal feeds for events?
Ok the word limit on comments is ridiculously low and irritating, so after having posted two comments and still having more to say, I decided to just post an answer. Sorry...
Yes, GCal is perfect, but I can't trust the technologically challenged students of my school to manually subscribe to ical feeds. So i wanna provide a site where people can select from a list of courses, and automatically get a customized event feed.
Right now, I have a rough implementation going by making a common Google Account that has separate calendars for each course. Then with some url trickery, I embed a custom iframe that gives a special read-only version of the calendar with only the calendars applicable to that specific user. This will probably raise problems when I want email notifications of events and stuff, and might force me to go into the Google Calendar API in detail. :(
Can you check out my other question at Is there anything wrong with the way I'm implementing a Calendar on my site? and give some feedback?
Related Topics
How to Test 'Rand()' with Rspec
Missing Host to Link To! Please Provide the :Host Parameter, for Rails 4
Deleting a Modified Object from a Set in a No-Op
Rails: Unable to Access Log File
How to "Unflatten" a Ruby Array
Form_For "First Argument in Form Cannot Contain Nil or Be Empty" Error
How to Run a Single Test/Spec File in Rspec
How to Run a .Rb File from Irb
How to Click First Link in List of Items After Upgrading to Capybara 2.0
How to Change Column Type in Heroku
Override Rails Helpers with Access to Original
Ruby Method That Returns Itself
Render Three Different Partials Depending on Button Clicked
Sass/Compass Compile into Many Locations
New Rails Project: 'Bundle Install' Can't Install Rails in Gemfile