PimentaCall Messages
This topic explains how the web and mobile apps can show a custom message to users about calls.
Always that a call object is changed, Meteor application change a special Message
object.
This Message
object contains a field called call
. This field contains all details about call, and web and mobile apps can write code to interpret the call status and show a custom message to users.
User role and actions
To show custom messages to users, we will have two type of actors: Caller
and Receiver
.
The Caller
is the user that make the call to one (direct or group call) or more (group call) Receiver
.
The Caller
can cancels the call and Receiver
can reject or accept the call.
There’s a timeout of approximately 36 seconds. In this case, call will consider terminated and server application will set the flag finished
of PimentaCall
object to the current date.
The Seven Statuses
For each role (Caller
or Receiver
) we will have 7 status possible in a call to show a custom message to user:
- Start a Call: This is the status when a
Caller
STARTs a call. - In Call: This is the status when a
Receiver
accept a call and it start with the firstReceiver
and theCaller
- Finished: Here we have more 4 possible status:
3.1. Timeout: This is when a call is finished because user not responds
3.2. Rejected: This is when the
Receiver
or All Receives (in a group call) reject the call or One Receiver reject and others timeout 3.3. Terminated: This is when a call started and now was finished because All participants left the call 3.4. Canceled: This is when theCaller
cancel the call before anyReceiver
responds.
Implementation of message details
Each message related to a call will have a PimentaCall
object assigned to it.
When a call is active
- This message will appear when a call is active, in a direct or group call.
- This type of message will be showed when
started
field is notnull
andfinished
field isnull
When a call is canceled by caller
- This happens when the user that make the call, cancels it before any other user responds to call
- This message is showed only for the caller, for recipients, the term will be “Missed” or “Unanswered”
- To show this message, field
started
have to benull
andcallerCancel
istrue
When a call is missed
- This happens when the user that see the message missed the call, but was respond by other user
- You have to check if current user accepts the call by checking
acceptedUserIds
array.
When a call is unanswered
- This will be show only to the caller
- If the call was not canceled by caller, but was not answered by any user or timeout.
- Check if
finished
is notnull
andaccepted
isfalse
anduserId
is the same that current user.
When a call was completed and finished
- When a call was completed and terminated
- First, check if
started
andfinished
are notnull
- The field
started
contains the date of start of call, but can be from any user (on group call). Is the moment that call is accepted from any user. - So, to check the start of each user, you have to check on
log
field. To accesslog
field of user, you have to access by userId, likelog[userId]
. - The log object for a user contains the fields:
startDate
, is the time that user enter on call,endDate
, is the time he left the call andping
, that is the time of last ping from this user.
When a call is finished and is group (timeout)
- The only difference for group is that this message will show more names (if applicable) and the date that user left the call.
- You can get the names from
toNames
array.
Table of colors and icons
Icon | Color | Description |
---|---|---|
or | #FF0000 for icon and red text#FDEDEE for block background#F1CDCF for border with 3px |
This is applied to all messages that was not completed. started field is null and is a video message |
or | #FF0000 for icon and red text#F7F9F8 for block background#DCF3DD for border with 3px |
This is applied to all messages that was started, finished or not. |
All icons:
The script bellow is exactly script used to format call message from pimentaCHAT web:
const call = message.call;
if (call) {
let name = call.senderName;
let pronoun = 'is';
let isCaller = false;
let directionIcon = 'call-from';
if (call.userId == userId) {
name = 'You';
isCaller = true;
pronoun = 'are'
directionIcon = 'call-to';
}
let callType = 'Video call';
icon = 'video-alt';
if (call.onlyAudio) {
callType = 'Audio call';
icon = 'phone-alt';
}
if (call.waiting && call.isGroup) {
msg = `${name} started a group <strong>${callType}</strong> in <strong>${call.senderGroup}</strong>:
<a href="${call.channel}" target="_blank">${call.channel}</a>`;
} else {
// Names of recipients
let toNames = '';
if (call.toNames) {
toNames = call.toNames.join(', ');
}
// Message if user out of call
let userOutCall = '';
if (call.log && call.log[userId] && call.log[userId]['endDate']) {
userOutCall = ' (You left the call at ' + call.log[userId]['endDate'].toLocaleTimeString() + ')';
}
// Participants string
let participantsHtml = '';
let participants = [];
if (call.acceptedUsers && call.acceptedUsers.length > 0) {
for (var i = 0; i < call.acceptedUsers.length; i++) {
let userName = call.acceptedUsers[i].name;
if (call.acceptedUsers[i]._id == userId)
userName = 'You';
participants.push(userName);
}
// Add the caller
participantsHtml = participants.join(', ');
participantsHtml += ', ' + name; // We do not add to array because we need participants array without caller
participantsHtml = `<div>Participants: ${participantsHtml}</div>`;
}
if (call.finished) {
// When the call is finished
msg = `<h4><strong>${callType}</strong> with <strong>${toNames}</strong></h4>`;
let direction = `<svg class="rc-icon tab-button-icon tab-button-icon--${directionIcon}" aria-hidden="true"><use xlink:href="${baseUrl}#icon-${directionIcon}"></use></svg>`;
if (call.acceptedUsers.length == 0 || (call.acceptedUserIds && call.acceptedUserIds.indexOf(userId) < 0 && userId != call.userId)) {
// Missed for all
svgClass = 'done';
let action;
if (call.callerCancel && isCaller) {
action = 'Canceled';
} else if (isCaller) {
action = 'Unanswered';
} else {
action = 'Missed';
}
let nameRelation = 'from';
if (isCaller) {
nameRelation = 'with';
}
msg = `<h4><strong>${callType}</strong> ${nameRelation} <strong>${toNames}</strong></h4>`;
msg += `<p class="not-received-color">${direction} <strong>${action}</strong> at ${call.finished.toLocaleString()}</p>`;
} else {
svgClass = 'calling';
wrapperClass = 'received';
// In this case, the current user was in the call
let diff = (call.finished - call.date) / 1000;
let duration = `<svg class="rc-icon tab-button-icon tab-button-icon--video-log" aria-hidden="true"><use xlink:href="${baseUrl}#icon-video-log"></use></svg>`;
let typeDirection;
if (call.userId == userId) typeDirection = 'Started at: ';
else typeDirection = ' Received on: ';
msg += '<p class="received-color">' + direction + typeDirection + call.date.toLocaleString() + ' - Ended at: ' + call.finished.toLocaleTimeString() + '</p>';
msg += '<p>' + duration + ' Duration: ' + this.getFormatedTime(diff) + userOutCall + '</p>';
}
} else if (call.started) {
// Call started but not finished yet
svgClass = 'calling';
wrapperClass = 'received';
icon = 'phone-alt';
msg = `<h4><strong>${name}</strong> ${pronoun} in a <strong>${callType}</strong> with <strong>${participants.join(', ')}</strong>`;
} else {
// Only ringing or fail
}
}
}
return `
<div class="pimenta-call-resume__wrapper pimenta-call-resume__wrapper--${wrapperClass}">
<span class="pimenta-call-resume__icon pimenta-call-resume__icon__${svgClass}">
<svg class="rc-icon tab-button-icon tab-button-icon--${icon}" aria-hidden="true">
<use xlink:href="${baseUrl}#icon-${icon}"></use>
</svg>
</span>
<span class="pimenta-call-resume__content">${msg}</span>
</div>`;