Timeline¶
A timeline displays tasks and the order in which they need to be completed.
Anatomy¶
Timeline Cell Views consist of a timestamp, an icon, a node, a vertical timeline, up to two statuses, and text content that can contain a headline, description, a left attribute, and a right attribute.
Timeline Preview Cell Views consist of a timestamp, a node, a horizontal timeline, and a headline.
Timeline Views consist of a scrollable list of Timeline Cell Views displayed vertically. The cells are ordered by date and are grouped under sticky headers displaying either the month or the date. The current day is marked by a colored line. If there are no cells, a customizable image and message is displayed instead.
Timeline View Anatomy |
Timeline Preview Views consist of a title, a button, and a list of Timeline Preview Cell Views displayed horizontally. This list is non-scrollable and displays two cells for mobile devices, and four cells for tablets.
Timeline Preview View Anatomy |
Usage¶
A Timeline Cell is used to represent an event and should lead to more details on the event upon being clicked. A Timeline View is used to display these cells in chronological order.
A Timeline Preview Cell gives a high-level overview of an event and is not clickable. A Timeline Preview View is used to display the Preview Cells along with a See All button. Clicking the Timeline Preview View should lead to the full Timeline View.
Construction¶
The recommended approach for creating a Timeline Cell is through binding
a TimelineCellData
to a TimelineCellProvider
, which will be covered
in detail in "Populating the Timeline". The rest of this section will go
over direct creation of the components.
A Timeline Cell can be created by the constructor in code:
TimelineCellView cell = new TimelineCellView(getContext());
A Timeline Cell can also be created by declaring a TimelineCellView
element in XML, like this:
<com.sap.cloud.mobile.fiori.timelineview.TimelineCellView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:headline="@string/timeline_headline"
app:headlineTextAppearance="@style/TextAppearance.Body"
app:timelinePreviewHeadlineTextAppearance="@style/TextAppearance.Body"
app:description="@string/timeline_description"
app:descriptionTextAppearance="@style/TextAppearance.Body"
app:timelineAttribute="@string/timeline_attribute"
app:timelineAttributeTextAppearance="@style/TextAppearance.Body"
app:timelineRightAttribute="@string/timeline_right_attribute"
app:timelineRightAttributeTextAppearance="@style/TextAppearance.Body"
app:timelineTimestampTextAppearance="@style/TextAppearance.Body"
app:timelineMonthTextAppearance="@style/TextAppearance.Body"
app:timelineTodayLineColor="@color/timeline_today_line_color"
app:timelineDateFormat="@string/timeline_date_format"
app:timelineTimeFormat="@string/timeline_time_format"
app:timelineDayDateFormat="@string/timeline_day_date_format"
app:timelineMonthFormat="@string/timeline_month_format"
app:timelineDateHeaderFormat="@string/timeline_date_header_format"
app:timelineButtonTextAppearance="@style/FioriButton.Flat"
app:timelineButtonBackground="@drawable/fiori_flat_btn_ripple">
</com.sap.cloud.mobile.fiori.timelineview.TimelineCellView>
The above XML declaration creates a TimelineCellView
with the following attributes of note:
app:timelineTodayLineColor
– The color of the line displayed to mark the current day.app:timelinePreviewHeadlineTextAppearance
– The properties of the headline text in Preview View.app:timelineButtonTextAppearance
– The properties of the text on the button for Preview View.app:timelineButtonBackground
– The properties of the background on the button for Preview View.app:timelineDateFormat
– The timestamp format when the timestamp type isDATE
.app:timelineTimeFormat
– The timestamp format when the timestamp type isTIME
.app:timelineDayDateFormat
– The timestamp format when the timestamp type isDAY_DATE
.app:timelineMonthFormat
– The format of the month text that appears inPREVIEW
cells andMONTH
states when usingTIMELINE_GROUP_MODE_MONTH
.app:timelineDateHeaderFormat
– The format of the header text when usingTIMELINE_GROUP_MODE_DATE
.
A Timeline can be created by the constructor in code:
TimelineView timeline = new TimelineView(getContext());
A Timeline can also be created by declaring a TimelineView
element in
XML, like this:
<com.sap.cloud.mobile.fiori.timelineview.TimelineView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:timelineEmptyDrawable="@drawable/ic_event_note_24dp"
app:timelineEmptyHeadline="@string/timeline_empty_headline"
app:timelineEmptyHeadlineTextAppearance="@style/TextAppearance.Body"
app:timelineEmptyDescription="@string/timeline_empty_description"
app:timelineEmptyDescriptionTextAppearance="@style/TextAppearance.Body">
</com.sap.cloud.mobile.fiori.timelineview.TimelineView>
The above XML declaration creates a TimelineView
with the following attributes:
app:timelineEmptyDrawable
– The image that is displayed when there are no cells.app:timelineEmptyHeadline
– The headline of the message that is displayed when there are no cells.app:timelineEmptyHeadlineTextAppearance
– The properties of the empty headline text.app:timelineEmptyDescription
– The description of the message that is displayed when there are no cells.app:timelineEmptyDescriptionTextAppearance
– The properties of the empty description text.
Fields¶
Headline¶
The headline displays a title for the event.
cell.setHeadline(R.string.headlineText);
Description¶
The description describes the event. It can display up to three lines.
cell.setDescription(R.string.descriptionText);
Attribute¶
The attribute displays the type of task or an aspect of the event. There can be an attribute that is left-aligned as well as right-aligned.
cell.setAttribute(R.string.attributeText);
cell.setRightAttribute(R.string.rightAttributeText);
Due Date¶
The due date represents the time period of the event and consists of a start date and an end date. The Timeline will automatically create a cell for each date within the range and will order the cells by their start date. The start date will determine what is displayed in the timestamp.
cell.setDueDate("22/10/2020", "25/10/2020");
If only one date is provided, that date is assumed to be the start date as well as the end date.
cell.setDueDate("22/10/2020");
If no date is provided, the cell's start date and end date are assumed to be the current time.
The accepted date formats are: dd/MM/yyyy
, dd/MM/yyyy HH:mm
, dd-MMM-yyyy
,
dd-MMM-yyyy HH:mm
, MMM dd yyyy
, MMM dd yyyy HH:mm
Timestamp¶
The timestamp displays the date or time when the event takes place,
depending on the start date and the timestamp type. The available timestamp
types are: DATE
, DAY_DATE
, and TIME
. By default, the timestamp type
is DATE
.
The timestamp format can be customized to display different date formats.
cell.setDueDate("22/10/2020 14:00");
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.DATE); // 22
cell.setDateFormat("ddd"); // 022
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.DAY_DATE); // THU\n22
cell.setDayDateFormat("EEE d"); // THU 22
cell.setTimestampType(TimelineCellView.TimelineCellTimestampType.TIME); // 2:00 PM
cell.setTimeFormat("hh:mm"); // 02:00
If consecutive cells have the same start date (YEAR
, MONTH
, DAY_OF_MONTH
),
then only the first cell in that sequence will display a timestamp. If the
consecutive cells are of type TIME
, then HOUR_OF_DAY
and MINUTE
will
be taken into account.
Icon¶
The icon is an image displayed under the timestamp.
cell.setIcon(R.drawable.icon, R.string.icon_description);
cell.setIconColor(iconColor);
Statuses¶
Up to two statuses can be displayed, stacked vertically, to show aspects of the event. A status can be customized as either text or an image.
cell.setStatus(R.drawable.status_icon, 0, R.string.status_description);
cell.setStatus(R.string.status, 1);
cell.setStatusColor(statusImageColor, 0);
cell.setStatusColor(statusTextColor, 1);
Enabled/Disabled State¶
In TimelineView
, each cell can be either enabled or disabled. The default
state is enabled. The disabled state prevents the cell from being clicked.
cell.setIsEnabled(false);
Enabled and Disabled State |
Node¶
The node represents the state of the event. The available states are:
State | Definition |
---|---|
PAST_START |
Start date of the project timeline that has passed. |
PAST |
Completed task with a due date that has passed. |
PAST_UPCOMING |
Incomplete task with a due date that has passed. |
PAST_PROGRESS |
In progress task with a due date that has passed. |
PAST_END |
End date of the project timeline that has passed. |
TODAY |
Dedicated cell for displaying the current day. The Timeline will automatically create a cell with this state. |
START |
Upcoming start date of the project timeline. |
DONE |
Upcoming task that has been completed. |
UPCOMING |
Upcoming task that has not been completed. |
PROGRESS |
Upcoming task that is in progress. |
END |
Upcoming end date of the project timeline. |
MONTH |
Dedicated cell for displaying the month. The Timeline will automatically create cells with this state. |
ADD |
Dedicated cell for adding an event. The Timeline will automatically create a cell with this state if TimelineCellProvider 's setShouldAddCreateCell(true) is called and the current day has no events. |
NOT_SPECIFIED |
Default state of the cell. |
cell.setState(TimelineCellView.TimelineCellState.START);
If an event with START
, DONE
, UPCOMING
, PROGRESS
, or END
is passed,
its state will change to PAST_START
, PAST
, PAST_UPCOMING
, PAST_PROGRESS
,
or PAST_END
, respectively.
Click Listener¶
The Timeline accepts a TimelineItemTouchListener.TimelineItemClickListener
that defines click behavior for each item.
Note
As of the 7.0 update, there is no longer a distinct card element, so onCardClick
takes priority as the primary click action and triggers upon a click on any area of the cell. As a result, click behavior should be defined in onCardClick
instead of onClick
.
TimelineItemTouchListener.TimelineItemClickListener listener = new TimelineItemTouchListener.TimelineItemClickListener() {
@Override
public void onCardClick(@NonNull View view, int position) {
Toast.makeText(getApplicationContext(), "Clicked on card in cell #" + position, Toast.LENGTH_SHORT).show();
}
@Override
public void onClick(@NonNull View view, int position) {
// As of the version 7.0 update, this is no longer called. Click behavior should be defined in `OnCardClick`.
}
@Override
public void onLongClick(@NonNull View view, int position) {
Toast.makeText(getApplicationContext(), "Long-clicked on cell #" + position, Toast.LENGTH_SHORT).show();
}
};
timeline.setClickListener(listener);
Populating the Timeline¶
The recommended approach for populating the timeline is through utilizing
the TimelineCellData
structure. The TimelineCellData
holds all the
same fields as TimelineCellView
as listed above. All of the fields are
optional, but it is recommended to at least specify the state, headline,
and due date.
TimelineCellData data = new TimelineCellData(getContext());
data.setState(TimelineCellView.TimelineCellState.START);
data.setHeadline(R.string.headlineText);
data.setDescription(R.string.descriptionText);
data.setAttribute(R.string.attributeText);
data.setRightAttribute(R.string.rightAttributeText);
data.setTimestampType(TimelineCellView.TimelineCellTimestampType.DATE);
data.setDateFormat("d MMM");
data.setTimeFormat("h:mm a");
data.setDayDateFormat("EEE\nd");
data.setMonthFormat("MMMM y");
data.setDateHeaderFormat("MMMM d, y");
data.setDueDate("22/10/2020", "25/10/2020");
TimelineCellView
can be added to TimelineView
by creating a
List<TimelineCellData>
and TimelineCellProvider
, like so:
List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelineView timeline = new TimelineView(getContext());
TimelineCellProvider provider = new TimelineCellProvider();
createList(); // populate mCellDataList with cell data
provider.setCellList(getContext(), mCellDataList);
timeline.setAdapter(provider);
Similarly, TimelinePreviewCellView
can be added to TimelinePreviewView
,
except without the need for a TimelineCellProvider
:
List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelinePreviewView timeline = new TimelinePreviewView(getContext());
createList(); // populate mCellDataList with cell data
timeline.setCellList(getContext(), mCellDataList);
The Timeline will automatically order the cells by due date, creating
TODAY
, MONTH
, and other cells as needed. The Timeline can be updated
at any time by calling setCellList(Context, List)
with an updated
List
.
Add Event¶
The Timeline is able to automatically create a cell with the ADD
state,
if the current day has no events, by telling the TimelineCellProvider
to do so:
TimelineCellProvider provider = new TimelineCellProvider();
provider.setShouldAddCreateCell(true);
Note
setShouldAddCreateCell(true)
should be called before setCellList(Context, List)
for the Timeline to properly create this cell.
Cell for Adding an Event |
This cell should have its behavior to add event data defined in the
TimelineItemTouchListener.TimelineItemClickListener
:
TimelineItemTouchListener.TimelineItemClickListener listener = new TimelineItemTouchListener.TimelineItemClickListener() {
@Override
public void onCardClick(@NonNull View view, int position) {
if (((TimelineCellView)view).getState() == TimelineCellView.TimelineCellState.ADD) {
// behavior to add event data
} else {
// normal click behavior
}
}
@Override
public void onClick(@NonNull View view, int position) {
// As of the version 7.0 update, this is no longer called. Click behavior should be defined in `OnCardClick`.
}
@Override
public void onLongClick(@NonNull View view, int position) {
Toast.makeText(getApplicationContext(), "Long-clicked on cell #" + position, Toast.LENGTH_SHORT).show();
}
};
Loading¶
Upon loading TimelineView
initially, the Timeline will display the latest
items, starting with the current day at the top. Past items can be seen
by scrolling upwards.
If there is data that still needs to be loaded, the current cells can be
displayed along with a loading indicator at the bottom by passing in the
current list of cell data and telling the TimelineCellProvider
that more
are loading:
List<TimelineCellData> mCellDataList = new ArrayList<>(); // member variable
TimelineView timeline = new TimelineView(getContext());
TimelineCellProvider provider = new TimelineCellProvider();
createList(); // populate mCellDataList with loaded cell data
provider.setIsLoading(true);
provider.setCellList(getContext(), mCellDataList);
timeline.setAdapter(provider);
Timeline View Loading |
The Timeline can be updated at any time by calling setCellList(Context, List)
with an updated List
, and setIsLoading(false)
should be called when
all the data is loaded.
Note
setIsLoading(boolean)
should be called before setCellList(Context, List)
for the Timeline to reflect any changes to the state of the
loading indicator.
If there are no cell data in the list passed to TimelineCellProvider
or if no TimelineCellProvider
has been set, then a customizable empty
state will be displayed.
timeline.setEmptyDrawable(R.drawable.ic_event_note_24dp);
timeline.setEmptyHeadline(R.string.emptyHeadlineText);
timeline.setEmptyDescription(R.string.emptyDescriptionText);
Empty Timeline View |
Customization¶
For further customization of the cells after they have been ordered, it
is possible to override TimelineCellProvider
's
onBindView(TimelineCellView, int, int)
method to handle special cases
or access methods only available to TimelineCellView
.
TimelineCellProvider provider = new TimelineCellProvider() {
@Override
public void onBindView(@NonNull TimelineCellView view, int position, int viewType) {
super.onBindView(view, position, viewType);
if (position - 1 > 0 && mOrderedCellDataList.get(position - 1).getCellType() == TimelineCellView.TimelineCellType.MARKER) {
view.setHeadline(R.string.firstEventOfMonthText);
view.setHeadlineTextAppearance(R.style.firstEventOfMonthStyle);
view.setTodayLineColor(R.color.todayLineColor);
view.setStartLine(R.color.startColor);
view.setEndLine(R.color.endColor);
view.setLineSize(R.dimen.lineSize);
view.setLinePadding(R.dimen.linePadding);
}
}
};