19 Jan 2021
This contribution is a new feature.
LifeTime = ReasonML + calendars
To understand a little bit more about the solution you need to understand what ReasonML is.
ReasonML is a programming language created at Facebook and powered by OCaml.
It is a new syntax for the programming language OCaml. Anything possible in OCaml is possible in Reason!
It means that we can benefit from the OCaml solid type-system.
The idea behind Reason is pretty simple: if it compiles it will works! (99% of the time)
Here is a schema showing how ReasonML fits in the OCaml ecosystem.
The story of Messenger.com
On September 8, 2017 the team at Facebook working on ReasonML published a post where they explain that 50% of Messenger.com (the web version of Facebook Messenger) codebase was converted to Reason code.
Here are some benefits they noticed:
- Build of the entire Reason part of the codebase is ~2s (several hundred files)
- Bug reports has decreased (from a few one per day to 10 bugs a year)
- Refactors are faster and introduce fewer bugs
Let's go back to our project.
Currently when a User launches the app, he arrives on the Home screen with:
- the weekly chart: displaying the week activities average
- the top activities list: displaying in descending order the activities with the most time
When the User tap on an activity, he goes to the associated Activity detail screen with:
- the activity category list where he can choose the type of the activity
- the possibility to hide/show the activity
Home + Activity detail screens
The goal of the contribution is to add to this screen:
- an event list containing all the events of the activity
- a graph showing the different events
The code blocks are intentionally incomplete for the sake of readability.
If you want to read the full code you'll find it in the PR link at the top.
The idea is pretty straightforward, here are the user stories:
As a User I want to see the events of the week I was on the home page so that I can directly see more details about the current week.
- Find a way to keep the week currently viewed on the home screen
- Fetch the events related to this week
As a User I want to be able to switch between the 5 last weeks so that I can see the events related to the week that I want.
- Implement the graph: the events fetch will be triggered when the user will swipe between the weeks
As a User I want to see the events list of the current week so that I can see more details about the events.
- Implement the events list
Before fetching the events, we need to know from which week we'll fetch them.
To do so, the
TopActivites component (which is responsible for showing the activities) will need to know the current week the user is on.
When the user will tap an activity from the Home screen, we will pass to the Activity Detail Screen the current week information: the week start date and the week end date.
Here is a schema to show you the logic and the file hierarchy:
Now that we have our initial week we can fetch our events.
We will see the implementation of the
getEvents function later.
Here are the helpers:
filterEventsByTitle: used to filter the events according to their title
sortEventsByDecreasingStartDate: used to sort the events from the most recent to the oldest
This is for the initial events fetch when the user arrives on the activity detail screen.
We will see below how to fetch the events when the user changes week or trigger the refresh.
The user can refresh the data by pulling down the current screen.
In the screen component, we will add three things:
refreshingstate which will tell if the component is reloading
onRefreshcallback which will be triggered when the user will pull down
- sets the
- sets the
onRefreshDonecallback which will be triggered once the user has finished pulling down
- sets the
- sets the
Once we have set up our parent component, all that remains is for us to react to the different values of the parent's props in the child component in a
We will display the events in the form of a chronogram.
This chronogram will be used to display all the events day by day.
When the user changes the current week, we will update
supposedEndDate seen above (1. Fetch the events).
onViewableItemsChanged will trigger the events fetch with the new week range.
Every time events are fetched, the results are stored in a Map with (startDate, endDate).
When we don't allow the function to fetch new events, it will look in the Map to see if the values has already been fetched and if so it will return the events. You can see this like a store for our events.
Calendars - getEvents
As we have already fetched our events in the parent component
ActivityOptions, we'll need to retrieve the events already fetched.
To do so, we will set the boolean argument
allowFetch (3rd argument of
Now we are going to process our data in order to adapt it to our graph.
We need to group events that occur on the same day together.
To do so, we will compute a matrix thanks to the function
eventsPerDate which will return our data in the form:
(date, (event1, event2...)...)
This function iterates through all the days of the week and tests against the events if it overlaps with the current day.
Note: We also have to handle the case where an event starts on a day and ends the next day. This is the reason why we do
Date.min(endOfDate) in code sample bellow.
For each event we compute the starting point and the ending point of the time range.
There is 24 x 60 = 1440min within a day.
We know the available width for our graph, so we can compute a unit which will correspond to 1 minute in our timeline.
We can now put our ranges in our graph.
The user can change weeks by swiping to the right or left.
We will display the following information about the event:
- event date in the format: DD-MM
- event start date in the format: HH:SS
- event end date in the format: HH:SS
- event duration in the form of a duration bar
As seen above, the event duration will be displayed as a duration bar.
To do so we will need to compute some values:
availableWidthForBarwhich corresponds to the total width we can use to display the duration bar
maxDurationwhich corresponds to the max duration through all the events
eventsWithDurationwhich is create an Array with
If we have no events for the selected week, we will show a message to the user otherwise we will display the events list.
This component will be used to display the duration bar.
Here is the formula to compute the width of the bar, in
For example, given:
- max duration through all the events: 90min
- current event duration: 50min
- available width: 200dp
The result will be equal to (50 / 90) * 200 = 111dp
We can now display the rest of the event information to the User.
This is how it is implemented in
We can use several sizes that are the result of a ratio with a constant
This allows us to have more consistent margins in our application.
I will have to change some things to make the user experience more enjoyable.
As mentioned in the comments:
- load the current week then lazy load the other weeks
- in the same week, if a user has a lot of events, add a see more button to fetch the rest of the events
All these improvements will improve the performance and fluidity of navigation in the application.
Here is the final version of the Activity detail screen:
The first problem that I've encountered was about the way I built the Activity detail events list.
I started by building it by fetching events from all the weeks at once.
The events were grouped according to their week in the list.
As you can imagine, this could be problematic if the user has a lot of events and it could lead to performance issues. I then thought about fetching the events by week as on the Home screen (triggered when the user switch week).
As I said before, ReasonML is a language that I particularly love.
This contribution was the opportunity to me to put into practice some concepts that I've learned in the past. More specifically about building a mobile app in ReasonML.