The following post was published at Iscaros Tizen Development Blog:
Hello everyone, today we will add a new feature in the message App. Now it will be possible to create template messages to send to your contacts.
Just as an example, imagine that you want to ask to Jim, Gary and Tom what are they doing. Usually you would create three different SMSs to send to them. But with this new feature you would create a template like this: “Hey, what are you doing tonight, <name> ?” and then you add your friends and click send. The App will parse your message and send to each of your friends the following message:
Message to Jim – “Hey, what are you doing tonight, Jim?”
Message to Gary – “Hey, what are you doing tonight, Gary?”
Message to Tom – “Hey, what are you doing tonight, Tom?”
So let’s start!
As usual we will start with the HTML changes, because they are easier to understand.
In the main screen I added one button that will send you to the templates screen where you can manage your templates:
01 |
< div id = "home" data-role = "page" > |
02 |
< div data-role = "header" > |
07 |
< div data-role = "content" ></ div > |
09 |
< div data-role = "footer" > |
10 |
< div data-role = "controlbar" data-style = "tabbar" > |
12 |
< li >< a href = "javascript:composeSMS();" data-icon = "ctrlbar-compose" >Compose SMS</ a ></ li > |
13 |
< li >< a href = "javascript:createTemplate();" data-icon = "ctrlbar-chat" >Templates</ a ></ li > |
14 |
< li >< a href = "javascript:aboutApp();" data-icon = "ctrlbar-info" >About</ a ></ li > |
15 |
< li >< a href = "javascript:exitApp();" data-icon = "ctrlbar-close" >Exit</ a ></ li > |
18 |
<!-- /navbar --> </ div > |
19 |
<!-- /footer --> </ div > |
The new link is at line 13.
In the message view I also added a link to the templates page, so I can add my templates to a SMS:
01 |
< div id = "message_view" data-role = "page" > |
02 |
< div data-role = "header" ></ div > |
03 |
< div id = "content_sms" data-role = "content" > |
04 |
< input id = "contact_number" type = "hidden" /> |
06 |
< input id = "message_ready_to_sent" type = "hidden" /> |
07 |
< div data-role = "fieldcontain" >< label for = "sms_to_send" >Message:</ label > |
08 |
< input id = "sms_to_send" type = "text" maxlength = "160" /></ div > |
10 |
< div data-role = "footer" data-position = "fixed" > |
11 |
< div data-role = "controlbar" data-style = "toolbar" > |
13 |
< li >< a href = "javascript:sendSMS();" data-icon = "ctrlbar-share" >Send</ a ></ li > |
14 |
< li >< a href = "javascript:useTemplate();" data-icon = "ctrlbar-chat" >Template</ a ></ li > |
15 |
< li >< a id = "add_contacts" style = "visibility: hidden;" href = "javascript:contactPopulate();" data-icon = "ctrlbar-contacts" > |
The new link is at line 14.
Moving on to the template page. This is a simple page with a list to show all the templates and a button to create a new template.
01 |
< div id = "templates_page" data-role = "page" > |
02 |
< div data-role = "header" > |
05 |
< div data-role = "content" > |
06 |
< ul id = "templates_list" data-role = "listview" data-autodividers = "alpha" > |
10 |
< div data-role = "footer" data-position = "fixed" > |
11 |
< div data-role = "controlbar" data-style = "toolbar" > |
13 |
< li >< a href = "javascript:createTemplatePage();" data-icon = "ctrlbar-create" >Create Template</ a ></ li > |
And now the last page. Here we will create the template, save it, modify it, use it and delete it.
01 |
< div id = "templates_create_page" data-role = "page" > |
02 |
< div data-role = "header" > |
05 |
< div data-role = "content" > |
07 |
< label for = "template_title_txt" >Title:</ label > |
08 |
< input id = "template_title_txt" type = "text" /> |
10 |
< label for = "template_content_txt" >Content:</ label > |
11 |
< textarea id = "template_content_txt" rows = "20" cols = "20" ></ textarea > |
13 |
< a id = "templete_delete_btn" style = "visibility: hidden;" href = "javascript:deleteTemplate();" data-icon = "ctrlbar-share" >Delete template</ a > |
15 |
< a id = "templete_select_btn" style = "visibility: hidden;" href = "javascript:useTemplate();" data-icon = "ctrlbar-share" >Use this template</ a ></ div > |
16 |
< div data-role = "footer" data-position = "fixed" > |
17 |
< div data-role = "controlbar" data-style = "toolbar" > |
19 |
< li >< a href = "javascript:saveTemplate();" data-icon = "ctrlbar-save" >Save</ a ></ li > |
20 |
< li >< a href = "javascript:cancelTemplate();" data-icon = "ctrlbar-close" >Cancel</ a ></ li > |
And that’s all for the HTML.
Because we are creating templates to send in the future we must store them somewhere. However we will not use the Tizen’s file system API to store the template. I will use a HTML5 Storage specification, basically it’s a persistent Hashmap. But if you want to read more about it, check here: http://www.w3.org/TR/webstorage/ And the reason that I’m not using the file system API it is because the HTML5 specification is much more suitable for our requirements.
To store values in the phone’s hard drive we will use localStorage.setItem(key, value), where key is going to be the template title and value the template’s content.
So let’s start.
Looking in the init function, we added some lines:
1 |
var init = function () { |
2 |
templateToSendOrCreate = true ; |
The variable peopleToSend is an array that will store the contacts that we would like to send the SMS to, the indexPeopleToSend is the index of this array and templateToSendOrCreate is a flag that says if we are creating or sending a template.
In our home screen we have a button for the template page, this button will call the function createTemplate() and what createTemplate does is call the function templatePage with false as argument. So I will skip createTemplate and jump to templatePage():
01 |
function templatePage(sendOrCreate) |
03 |
if (localStorage == null || typeof localStorage == "undefined" ) |
05 |
alert( 'Templates not avaliable' ); |
09 |
templateToSendOrCreate = sendOrCreate; |
10 |
$.mobile.changePage( '#templates_page' ); |
We first check if localStorage is available and of course it is, because Tizen has a recent WebKit implementation. However it’s a good practice to check if resources are available, then after this we call the function loadTemplates() to load the templates.
01 |
function loadTemplates() |
06 |
$( '#templates_list' ).html( '' ); |
08 |
if (templateToSendOrCreate == false ) |
10 |
funcToCall = 'setTemplateForMessage' ; |
14 |
funcToCall = 'editTemplate' ; |
17 |
for ( var key in localStorage){ |
18 |
titleSafe = $( '<div/>' ).text(key).html(); |
20 |
+ '<a href="javascript:' +funcToCall+ '(\'' +$.trim(key.toString())+ '\');">' + |
22 |
titleSafe+ '</a></span></li>' ; |
24 |
$( '#templates_list' ).append(element); |
Loading the templates is basically iterating over our localStorage variable and putting the key (the template title) in the list. But first we check from where we came from to know what function should I call if the user click on the item. If the user came from the compose SMS screen we will call setTemplateForMessage otherwise editTemplate.
Now let’s take a look in the function that actually saves our template:
01 |
function saveTemplate() |
03 |
var title, content, id; |
05 |
id = $.trim($( '#template_id' ).val()); |
06 |
title = $.trim($( '#template_title_txt' ).val()); |
07 |
content = $.trim($( 'textarea#template_content_txt' ).val()); |
09 |
if (title == null || title == "" || content == null || |
12 |
alert( 'Enter the template information' ); |
16 |
if (id != title && id.length > 0) //updating |
18 |
localStorage.removeItem(id); |
19 |
localStorage.setItem(title, content); //save on the disk |
20 |
} else { //new template |
21 |
localStorage.setItem(title, content); //save on the disk |
25 |
history.go(-1); //back page |
Before I save the template I make the check to see if the user is editing a template title. So I check the id with the possible new title if they are different it means the user changed the template’s title. Otherwise is a new template or the user is just editing the template’s content, so just save it.
Now to delete a template is even easier
1 |
function deleteTemplate() |
3 |
localStorage.removeItem(templateIdUpdate); |
5 |
history.go(-1); //back page |
Just retrieve the value from the tempalteIdUpdate variable and remove it.
Now I have two functions that their job are just put the template content in the screen to send the SMS or edit the template itself.
01 |
function setTemplateForMessage(id) |
05 |
if ( typeof id == "undefined" ) |
07 |
id = $( '#template_id' ).val(); |
10 |
templateContent = $.trim(unescape(localStorage.getItem(id))); |
12 |
templateToSendOrCreate = true ; |
13 |
$.mobile.changePage( '#message_view' ); |
14 |
$( '#add_contacts' ).css( 'visibility' , 'visible' ); |
16 |
$( '#sms_to_send' ).val(templateContent); |
This function is called when the user wants to use the template in the SMS, so we just get its value and put in the message text box. And the last function is called when the user is going to edit a template.
01 |
function editTemplate(templateId) |
04 |
$.mobile.changePage( '#templates_create_page' ); |
05 |
$( '#templete_delete_btn' ).css( 'visibility' , 'visible' ); |
06 |
$( '#templete_select_btn' ).css( 'visibility' , 'visible' ); |
07 |
templateIdUpdate = templateId; |
09 |
content = localStorage.getItem(templateId); |
11 |
$( '#template_id' ).val($( '<div/>' ).text(templateId).html()); |
12 |
$( '#template_title_txt' ).val($( '<div/>' ).text(templateId).html()); |
13 |
$( 'textarea#template_content_txt' ).val(unescape(content)); |
That’s all for template management.
Remenber that I said that the App would replace “<name>” with the contact name and send the SMS?
So to do this we use a very simple function:
1 |
function parseContent(content, name) |
5 |
contentToSend = content.replace( //ig, name); |
Also its possible to send SMSs to multiple contacts at once so I had to modify the functions composeSMS and sendSMS to support this. The changes are simple, lets start with composeSMS:
01 |
function composeSMS(contactId){ |
03 |
var contact,fistName,lastName; |
06 |
$.mobile.changePage( '#message_view' ); |
07 |
$( '#message_thread' ).html( '' ); |
08 |
$( '#add_contacts' ).css( 'visibility' , 'visible' ); |
10 |
if (contactId != null ){ |
11 |
contact = getContact(contactId); |
12 |
lastName = contact.name.lastName; |
13 |
firstName = contact.name.firstName; |
15 |
if (lastName == null ){ |
19 |
peopleToSend.push([contactId,firstName + ' ' +lastName]); |
21 |
for ( var i = 0; i < peopleToSend.length; i++){ |
22 |
names += peopleToSend[i][1]+ ',' ; |
25 |
$( '#contact_name' ).html( '<h3>' + |
26 |
$( '<div/>' ).text( names ).html()+ |
29 |
$( '#contact_name' ).html( 'Select a contact' ); |
What we modified here is the peopleToSend array, we are pushing the contactId and their names to be used in the sendSMS function. Doing this we are able to send SMS to as many contacts as we want !
Now our last function, sendSMS:
01 |
//Send the SMS to the recipients |
04 |
var contact, contentToSend; |
07 |
if (peopleToSend.length == 0){ |
08 |
alert( 'Add a receipient' ); |
12 |
if (indexPeopleToSend >= peopleToSend.length){ |
13 |
indexPeopleToSend = 0; |
15 |
$( "#sms_to_send" ).val( '' ); |
19 |
content = $( '#sms_to_send' ).val(); |
20 |
//contact = getContact($('#contact_number').val()); |
21 |
contact = getContact(peopleToSend[indexPeopleToSend][0]); |
23 |
//This means we don't have the contact in the list. |
24 |
//We only have the phone number |
26 |
phoneNumber = contact.phoneNumbers[0].number; |
28 |
phoneNumber = peopleToSend[indexPeopleToSend][0]; |
31 |
contentToSend = parseContent(content, peopleToSend[indexPeopleToSend][1]); |
33 |
$( '#message_ready_to_sent' ).val(contentToSend); |
35 |
msg = new tizen.Message( "messaging.sms" , {plainBody:contentToSend,to:[phoneNumber]}); |
37 |
timeLastMsg = msg.timestamp.toLocaleDateString(); |
39 |
smsService.sendMessage(msg, messageSent, onError); |
This part is interesting, because I had some problems when I tried to call smsService.sendMessage() over and over again inside a “for” loop. It seems it’s not safe to call this function until the callback was called.
So what I did is just call the function peopleToSend.length times. The messageSent callback is responsible to call the smsSend again and we use the variable indexPeopleToSend to control if we have to stop it or not. So let’s take a look the in the messageSent callback:
01 |
function messageSent(recipients) { |
03 |
$( '#message_thread' ).append( '<li>' + |
04 |
$( '<div/>' ).text( $( "#message_ready_to_sent" ).val() ).html()+ |
See? I update the indexPeopleToSend and call the sendSMS again.
Take a look at the App:
Source Iscaro’s