Mooodify: The Calendar Page

Tim Se
4 min readNov 22, 2023

--

I am finally back after a busy schedule…

In the previous story, we talked about our Home page.

Which is where you can select a mood for that particular day. Today, we will create the Calendar page, giving us the bird eye’s view on our moods across the month.

The goals for today are:

  • Create a Calendar widget in a monthly format.
  • For each day that has a mood recorded, display an indicator.
  • Create a widget to display the mood of the selected day.

Just like before, I am not discussing much about the architecture of the app in this story, I will discuss it separately as it is a separate topic.

The Calendar Widget

Thanks to the table_calendar package, I did not need to create a calendar from scratch.

Here are some details when I setup my table calendar.

TableCalendar(
focusedDay: viewModel.focusedDay,
selectedDayPredicate: (day) => day == viewModel.focusedDay,
);
  • focusedDay is a DateTime and is stored in my viewmodel. It is used to keep track of which day is being focused.
  • selectedDayPredicate is a function that determines if a day is the focusedDay.

The Mood Indicator

Notice the dots, they appears under the days with moods recorded. To achieve this, we simply need to load the events and create the markupBuilder.

TableCalendar(
eventLoader: (day) {
return viewModel.getMoodsForDay(day);
},
);

// Inside my viewmodel:
// There will only be one mood per day, but the eventLoader expects a list
List<Mood?> getMoodsForDay(DateTime day) {
final moodOfDay = _moodService.getMood(day);
if (moodOfDay == Mood.none) {
return [];
}
return [moodOfDay];
}
  • eventLoader is called to load all events for a day. Here, I have a method in my viewmodel that will return the mood of the day.
TableCalendar(
markerBuilder: (context, date, events) {
if (events.isNotEmpty) {
return Positioned(
bottom: 5,
child: Container(
width: 5,
height: 5,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: _setDotColor(viewModel, date),
),
),
);
}
return Container();
},
);

If the events are not empty, we will show a small offset circle, indicating the day has a mood recorded.

Color _setDotColor(CalendarViewModel viewModel, DateTime datetime) {
// compare datetime and focusedDay;
final focusedDay = DateTime(viewModel.focusedDay.year,
viewModel.focusedDay.month, viewModel.focusedDay.day);
final date = DateTime(datetime.year, datetime.month, datetime.day);
if (date == focusedDay) {
return Colors.white;
}

return Colors.black;
}

The _setDotColor is a helper method that sets the color of the dot. If the day is selected, the day will have a black background, hence, we need the dot to be white.

Mood Of The Day

Ignore the styling, it’s ugly I know :/

We want a Text Widget to display the mood of the selected day. This is rather straightforward, we have a variable in the viewmodel called todayMood, which stores the mood of the selected day.

There is a parameter in the TableCalendar called onDaySelected, which is called when a day is tapped. From there, we get the mood of the day and update the state to reflect the changes.

void onDaySelected(DateTime day) {
todayMood = _moodService.getMood(day); // <-- get the mood of the day
focusedDay = day;
notifyListeners(); // <-- rebuild state
}

Conclusion

In conclusion, http://pub.dev/ is definitely one of the reasons why Flutter is an amazing framework to build apps. Just a few lines of code, you are seeing a fully working Calendar.

If want to follow along my month long journey (only a few days left 😱), consider following me to get the latest update.

To check out the full development of this project, do check out the public repo of this project here: https://github.com/timsedev/mooodify.

--

--