Z!0}N;Co8`5rEyR?5v}XS!&tN
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
+
+
+
+
+
+
+
+ Contacts exchanger
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/project/js/app.config.js b/project/js/app.config.js
new file mode 100644
index 0000000..e0332c3
--- /dev/null
+++ b/project/js/app.config.js
@@ -0,0 +1,28 @@
+/**
+ * @class Config
+ */
+function Config() {
+ 'use strict';
+}
+
+(function () { // strict mode wrapper
+ 'use strict';
+ Config.prototype = {
+
+ properties: {
+ 'templateDir': 'templates',
+ 'templateExtension': '.tpl'
+ },
+
+ /**
+ * Returns config value
+ */
+ get: function (value, defaultValue) {
+
+ if (this.properties.hasOwnProperty(value)) {
+ return this.properties[value];
+ }
+ return defaultValue;
+ }
+ };
+}());
diff --git a/project/js/app.js b/project/js/app.js
new file mode 100644
index 0000000..c38e777
--- /dev/null
+++ b/project/js/app.js
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.org/license/
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*jslint devel: true*/
+/*global $, tizen, Config */
+
+var App = null;
+
+// App instance
+var app = null;
+
+(function () { // strict mode wrapper
+ 'use strict';
+
+ /**
+ * Creates a new application object
+ *
+ * @class Application
+ */
+ App = function App() {};
+
+ App.prototype = {
+ nfcAdapter: null,
+ addressBook: null,
+ started: false,
+ timeOutHandler: null,
+ counterState: true,
+ nfc: null,
+
+ init: function appInit() {
+ this.config = new Config();
+ this.ui = new App.Ui(this);
+ this.nfc = new App.NFCControl(this);
+ this.ui.defineEvents();
+ this.initAddressBook(this.nfc.startNFC.bind(this.nfc));
+ },
+
+ saveDefaultCard: function saveDefaultCard() {
+ var elementSelected = $('#list-choose li.selected');
+ localStorage.started = true;
+ localStorage.id = elementSelected.data('id');
+ localStorage.caller = elementSelected.data('caller');
+ localStorage.firstName = elementSelected.data('firstName');
+ localStorage.lastName = elementSelected.data('lastName');
+ localStorage.phoneNumber = elementSelected.data('phoneNumber');
+ localStorage.vCard = elementSelected.data('vCard');
+ this.started = true;
+ $.mobile.changePage('#start');
+ },
+
+ updateDefaultCard: function updateDefaultCard (contact) {
+ localStorage.caller = this.ui.prepareCallerName(contact);
+ localStorage.firstName = contact.name.firstName || '';
+ localStorage.lastName = contact.name.lastName || '';
+ localStorage.phoneNumber = contact.phoneNumbers[0].number;
+ localStorage.id = contact.id;
+ localStorage.vCard = contact.convertToString('VCARD_30');
+ },
+
+ /**
+ * @param {Array} addressbooks
+ */
+ getAddressBooksSuccess: function getAddressBooksSuccess(addressbooks) {
+ if (addressbooks.length > 0) {
+ var self = this,
+ resetLocalSorage = function () {
+ // Reset localStorage
+ localStorage.clear();
+ self.started = false;
+
+ // Load start page with temporary content
+ self.ui.moveToStartPage();
+ self.ui.loadTemporaryContent();
+ };
+ this.addressBook = addressbooks[0];
+
+ if (localStorage.id) {
+ try {
+ this.updateDefaultCard(
+ this.addressBook.get(localStorage.id)
+ );
+ } catch (err) {
+ if (err.name === "NotFoundError") {
+ resetLocalSorage();
+ }
+ }
+ }
+
+ // Registers to be notified when the address book changes
+ this.addressBook.addChangeListener({
+ oncontactsadded: function(contacts) {
+ // Refresh if choose page active
+ self.ui.refreshIfActivePage("choose");
+ },
+ oncontactsremoved: function(ids) {
+ // Refresh localStorage if default contact was deleted
+ if (ids.indexOf(localStorage.id) >= 0) {
+ resetLocalSorage();
+ alert("Your default contact has been removed. Please choose another one.");
+ } else {
+ // Refresh if choose page active
+ self.ui.refreshIfActivePage("choose");
+ }
+ },
+ oncontactsupdated: function (contacts) {
+ var index = contacts.length;
+
+ // check if default contact was updated
+ while (index--) {
+ if (contacts[index].id === localStorage.id) {
+ self.updateDefaultCard(contacts[index]);
+ break;
+ }
+ }
+
+ self.ui.refreshIfActivePage("start");
+ }
+ });
+ } else {
+ console.error('initAddressBook failed');
+ }
+ },
+
+ /**
+ *
+ * @param {Error} e
+ */
+ getAddressBooksError: function getAddressBooksError(e) {
+ console.error('getAddressBooks() error: ' + e.message);
+ },
+
+ initAddressBook: function initAddressBook(callback) {
+ try {
+ tizen.contact.getAddressBooks(
+ function (addressbook) {
+ this.getAddressBooksSuccess(addressbook)
+ callback();
+ }.bind(this),
+ this.getAddressBooksError.bind(this)
+ );
+ } catch (e) {
+ if (e.name === "SecurityError") {
+ this.ui.showPopupWarning();
+ }
+ console.error('getAddressBooks() error: ' + e.message);
+ }
+ },
+
+ countDown: function countDown(time, obj) {
+ if (!this.counterState) {
+ setTimeout(function () {
+ this.countDown(time, obj);
+ }.bind(this), 500);
+ return;
+ }
+
+ obj.text(time);
+ if (time > 0) {
+ if (this.nfc.isPowered()) {
+ time -= 1;
+ this.timeOutHandler = setTimeout(function () {
+ this.countDown(time, obj);
+ }.bind(this), 1000);
+ } else {
+ this.nfc.timeExpired();
+ }
+ } else {
+ this.nfc.timeExpired();
+ }
+ },
+
+ saveContact: function saveContact() {
+ var contact = null, i, empty = true,
+ data = $('#contact').data('contactsData');
+
+ for (i in data) {
+ if (data.hasOwnProperty(i) && empty) {
+ if (data[i] !== '') {
+ empty = false;
+ }
+ }
+ }
+
+ if (empty) {
+ this.ui.moveToStartPage('Cannot add empty contact');
+ console.error('saveContact error: empty contact');
+ } else {
+ try {
+ contact = new tizen.Contact({
+ name: new tizen.ContactName({
+ caller: data.caller,
+ firstName: data.first,
+ lastName: data.last
+ }),
+ phoneNumbers: [new tizen.ContactPhoneNumber(data.phone)]
+ });
+ this.addressBook.add(contact);
+ this.ui.moveToStartPage('New contact added');
+ } catch (err) {
+ this.ui.moveToStartPage('Problem with new contact adding');
+ console.error('saveContact error:' + err.name);
+ }
+ }
+ },
+
+ /**
+ * Load contacts from the address book and pass the result to a callback
+ *
+ * @param {function} successCallback
+ * @param {function} errorCallback
+ */
+ loadContacts: function loadContacts(successCallback, errorCallback) {
+ this.addressBook.find(successCallback, errorCallback);
+ }
+
+ };
+
+}());
+
+app = new App();
+
+$(document).ready(app.init.bind(app));
diff --git a/project/js/app.nfc.card.js b/project/js/app.nfc.card.js
new file mode 100644
index 0000000..d6ad313
--- /dev/null
+++ b/project/js/app.nfc.card.js
@@ -0,0 +1,99 @@
+/*jslint devel: true*/
+/*global $, tizen, App, app */
+
+(function () { // strict mode wrapper
+ 'use strict';
+
+ /**
+ * Constructs NFCCard
+ * @constructor
+ * @param {NFCControl} nfc
+ */
+ App.NFCCard = function nfc_NFCCard(nfc) {
+ this.nfc = nfc;
+ };
+
+ App.NFCCard.prototype = {
+
+ readMessageErr: function nfc_card_readMessageErr(e) {
+ console.error('Read error! ' + e.message, e);
+ this.nfc.timeExpired('Read error! ' + e.message);
+ },
+
+ /**
+ * Read contents from a tag
+ * @param {NFCTag} tag
+ */
+ sucTagReadAttach: function nfc_card_sucTagReadAttach(tag) {
+ try {
+ if (!tag.isSupportedNDEF) {
+ throw {message: "This tag doesn't support NDEF"};
+ }
+ tag.readNDEF(
+ this.nfc.readMessage.bind(this.nfc),
+ this.readMessageErr.bind(this)
+ );
+ } catch (e) {
+ this.readMessageErr(e);
+ }
+ },
+
+ /**
+ * Set tag listener
+ */
+ setTagDetectRead: function nfc_card_setTagDetectRead() {
+ try {
+ this.nfc.nfcAdapter.setTagListener({
+ onattach: this.sucTagReadAttach.bind(this),
+ ondetach: this.nfc.sucDetach.bind(this.nfc)
+ });
+ } catch (error) {
+ this.readMessageErr(error);
+ }
+ },
+
+ sucSend: function nfc_card_sucSend() {
+ this.nfc.timeExpired('Send success!');
+ },
+
+ errSend: function nfc_card_errSend(e) {
+ console.warn('errSend', e);
+ this.nfc.timeExpired('Write error! ' + e.message);
+ },
+
+ sucTagWriteAttach: function nfc_card_sucTagWriteAttach(tag) {
+ var newMessage = null,
+ fullContact = '';
+
+ try {
+ fullContact = this.nfc.prepareForNFC(localStorage);
+ newMessage = this.nfc.phoneNumber2NDEF(fullContact);
+ if (!tag.isSupportedNDEF) {
+ throw {message: "This tag doesn't support NDEF"};
+ }
+ tag.writeNDEF(
+ newMessage,
+ this.sucSend.bind(this),
+ this.errSend.bind(this)
+ );
+ } catch (e) {
+ this.errSend(e);
+ }
+ },
+
+ setTagDetectWrite: function nfc_card_setTagDetectWrite() {
+ var suc = {
+ onattach: this.sucTagWriteAttach.bind(this),
+ ondetach: this.nfc.sucDetach.bind(this.nfc)
+ };
+
+ try {
+ this.nfc.nfcAdapter.setTagListener(suc);
+ } catch (error) {
+ console.error(error);
+ }
+ }
+
+ };
+
+}());
diff --git a/project/js/app.nfc.js b/project/js/app.nfc.js
new file mode 100644
index 0000000..4d86ffb
--- /dev/null
+++ b/project/js/app.nfc.js
@@ -0,0 +1,288 @@
+/*jslint devel: true*/
+/*global $, tizen, App, app */
+
+(function () { // strict mode wrapper
+ 'use strict';
+
+ /**
+ * Constructs NFCControl
+ * @constructor
+ * @param {App} app
+ */
+ App.NFCControl = function NFCControl(app) {
+ this.app = app;
+ this.init();
+ };
+
+ App.NFCControl.prototype = {
+ nfcTarget: null,
+ nfcStateMemory: false,
+
+ /**
+ * Initialize NFC application module
+ */
+ init: function nfc_init() {
+ this.card = new App.NFCCard(this);
+ this.peer = new App.NFCPeer(this);
+ this.separator = String.fromCharCode(30);
+ this.endOfText = String.fromCharCode(3);
+ },
+ /**
+ * Disable tag/target detection and move to start page
+ *
+ * @param {string} monit message text to be displayed
+ */
+ timeExpired: function nfc_timeExpired(monit) {
+ clearTimeout(this.app.timeOutHandler);
+ this.unsetTargetDetect();
+ this.unsetTagDetect();
+ this.app.ui.moveToStartPage(monit);
+ },
+
+ /**
+ * Get the field separator
+ *
+ * @returns {string}
+ */
+ getSeparator: function nfc_getSeparator() {
+ return this.separator;
+ },
+
+ /**
+ * Get the end of text marker
+ *
+ * @returns {string}
+ */
+ getEndOfText: function nfc_getEndOfText() {
+ return this.endOfText;
+ },
+
+ createContactString: function createContactString(contact) {
+ var contactString;
+ contactString = contact.phoneNumber + this.getSeparator();
+ contactString += contact.firstName + this.getSeparator();
+ contactString += contact.lastName;
+ return contactString;
+ },
+
+ /**
+ *
+ * @param {string|object} contact
+ * @returns {string}
+ */
+ prepareForNFC: function nfc_prepareForNFC(contact) {
+ if ($.type(contact) !== 'string') {
+ contact = this.createContactString(contact);
+ }
+ if (contact.length > 31) {
+ contact = contact.substring(0, 31);
+ if (contact[29] !== this.getSeparator()) {
+ contact = contact.substring(0, 30) + this.getEndOfText();
+ }
+ }
+ return contact;
+ },
+
+ resolveData: function nfc_resolveData(value, endOfText) {
+ if (!value) {
+ return '';
+ }
+
+ endOfText = endOfText || this.getEndOfText();
+
+ return value.replace(endOfText, 'â¦');
+ },
+
+ resolveContact: function nfc_resolveContact(contactsString) {
+ var separator = this.getSeparator(),
+ contactsArray = contactsString.split(separator);
+
+ return {
+ phone: this.resolveData(contactsArray[0]),
+ first: this.resolveData(contactsArray[1]),
+ last: this.resolveData(contactsArray[2])
+ };
+ },
+
+ /**
+ *
+ * @param {type} record
+ * @returns {undefined}
+ */
+ fillRecordInfo: function nfc_fillRecordInfo(record) {
+ try {
+ var contactsData = this.resolveContact(this.convertNDEF2phoneNumber(record.payload));
+ this.app.nfc.displayContact(contactsData);
+ } catch (error) {
+ console.error(error);
+ }
+ },
+
+ /**
+ *
+ * @param {NDEFMessage} message
+ */
+ readMessage: function nfc_readMessage(message) {
+ try {
+ this.fillRecordInfo(message.records[0]);
+ } catch (e) {
+ console.error(e.message);
+ }
+ },
+
+ /**
+ *
+ * @param {string|object} contact
+ * @returns {NDEFMessage}
+ */
+ contact2NDEF: function nfc_contact2NDEF(contact) {
+ var t, a = [], len, i, newMessage = new tizen.NDEFMessage();
+ if (typeof contact === 'string') {
+ t = contact;
+ } else {
+ t = contact.convertToString("VCARD_30");
+ }
+ len = t.length;
+ for (i = 0; i < len; i += 1) {
+ a[i] = t.charCodeAt(i);
+ }
+ newMessage.records[0] = new tizen.NDEFRecordMedia('text/x-vcard', a);
+ return newMessage;
+ },
+
+ /**
+ *
+ * @param {string} contact
+ * @returns {NDEFMessage}
+ */
+ phoneNumber2NDEF: function nfc_phoneNumber2NDEF(contact) {
+ var phoneNumberArray = [], i, length = contact.length, newMessage = new tizen.NDEFMessage();
+ for (i = 0; i < length; i += 1) {
+ phoneNumberArray.push(contact.charCodeAt(i));
+ }
+ newMessage.records[0] = new tizen.NDEFRecordMedia('text/x-vcard', phoneNumberArray);
+ return newMessage;
+ },
+
+ /**
+ *
+ * @param {string} contact
+ * @returns {string}
+ */
+ convertNDEF2phoneNumber: function nfc_convertNDEF2phoneNumber(contact) {
+ var i, length = contact.length, phoneNumber = '';
+ for (i = 0; i < length; i += 1) {
+ phoneNumber += String.fromCharCode(contact[i]);
+ }
+ return phoneNumber;
+ },
+
+ /**
+ * NFC setPowered success callback
+ * @returns {undefined}
+ */
+ onPowerOn: function nfc_onPowerOn() {
+ console.log('Power On succeeded.');
+ this.app.started = true;
+ this.app.ui.loadStartPage();
+ },
+
+ /**
+ * NFC setPowered error callback
+ * @param {Error} err
+ * @returns {undefined}
+ */
+ onPowerOnFails: function nfc_onPowerOnFails(err) {
+ console.error('Power On error: ' + err.message);
+ this.app.ui.showPopupWarning();
+ },
+
+ /**
+ * NFC setPowered success callback
+ * @returns {undefined}
+ */
+ onPowerOff: function nfc_onPowerOff() {
+ tizen.application.getCurrentApplication().exit();
+ },
+
+ /**
+ * NFC setPowered error callback
+ * @param {Error} err
+ * @returns {undefined}
+ */
+ onPowerOffFails: function nfc_onPowerOffFails(err) {
+ console.error('Power Off error', err);
+ tizen.application.getCurrentApplication().exit();
+ },
+
+ isPowered: function nfc_isPowered() {
+ return this.nfcAdapter.powered;
+ },
+
+ startNFC: function nfc_startNFC() {
+ try {
+ this.nfcAdapter = tizen.nfc.getDefaultAdapter();
+ if (this.nfcAdapter.powered) {
+ this.nfcStateMemory = true;
+ this.onPowerOn();
+ return;
+ }
+ this.nfcStateMemory = false;
+ console.log('Turning NFC adapter On...');
+ this.nfcAdapter.setPowered(true, this.onPowerOn.bind(this), this.onPowerOnFails.bind(this));
+ } catch (e) {
+ console.error('startNFC problem', e);
+ this.app.ui.showPopupWarning();
+ }
+ },
+
+ stopNFC: function nfc_stopNFC() {
+ try {
+ if (this.nfcStateMemory) {
+ this.onPowerOff();
+ } else {
+ this.nfcAdapter.setPowered(false, this.onPowerOff.bind(this), this.onPowerOffFails.bind(this));
+ }
+ } catch (err) {
+ console.error('setPowered(false) problem', err);
+ }
+ },
+
+ unsetTargetDetect: function nfc_unsetTargetDetect() {
+ try {
+ if (this.nfcTarget) {
+ this.nfcTarget.unsetReceiveNDEFListener();
+ this.nfcTarget = null;
+ } else {
+ //console.warn("app.nfc.nfcTarget not set");
+ }
+ } catch (error) {
+ console.error('error: ' + error.message);
+ }
+ try {
+ this.nfcAdapter.unsetPeerListener();
+ } catch (e) {
+ console.error('error: ' + e.message);
+ }
+ },
+
+ unsetTagDetect: function nfc_unsetTagDetect() {
+ try {
+ this.nfcAdapter.unsetTagListener();
+ } catch (error) {
+ console.error('error: ' + error.message);
+ }
+ },
+
+ displayContact: function nfc_displayContact(obj) {
+ clearTimeout(this.app.timeOutHandler);
+ this.unsetTargetDetect();
+ this.unsetTagDetect();
+ this.app.ui.moveToContactPage(obj);
+ },
+
+ sucDetach: function nfc_sucDetach() {
+ }
+ };
+
+}());
diff --git a/project/js/app.nfc.peer.js b/project/js/app.nfc.peer.js
new file mode 100644
index 0000000..f1999b7
--- /dev/null
+++ b/project/js/app.nfc.peer.js
@@ -0,0 +1,72 @@
+/*jslint devel: true*/
+/*global $, tizen, App, app */
+
+(function () { // strict mode wrapper
+ 'use strict';
+
+ /**
+ * Constructs NFCPeer
+ * @constructor
+ * @param {NFCControl} nfc
+ */
+ App.NFCPeer = function (nfc) {
+ this.nfc = nfc;
+ };
+
+ App.NFCPeer.prototype = {
+
+ sucSendToTarget: function nfc_peer_sucSendToTarget() {
+ },
+
+ errSendToTarget: function nfc_peer_errSendToTarget(e) {
+ this.nfc.timeExpired('Send problem! ' + e.message);
+ },
+
+ setReceiveFromTarget: function nfc_peer_setReceiveFromTarget() {
+ try {
+ if (!this.nfc.nfcTarget) {
+ console.warn("app.nfc.nfcTarget not set");
+ return;
+ }
+ this.nfc.nfcTarget.setReceiveNDEFListener(
+ this.nfc.readMessage.bind(this.nfc)
+ );
+ } catch (error) {
+ console.error('setReceiveFromTarget error: ' + error.message);
+ }
+ },
+
+ sucTargetAttach: function nfc_peer_sucTargetAttach(target) {
+ var newMessage = null,
+ fullContact = this.nfc.prepareForNFC(localStorage);
+
+ this.nfc.nfcTarget = target;
+ this.setReceiveFromTarget();
+
+ try {
+ newMessage = this.nfc.phoneNumber2NDEF(fullContact);
+ target.sendNDEF(
+ newMessage,
+ this.sucSendToTarget.bind(this),
+ this.errSendToTarget.bind(this)
+ );
+ } catch (e) {
+ console.error("NDEFMessage problem: " + e.message);
+ }
+ },
+
+ setTargetDetect: function nfc_peer_setTargetDetect() {
+ var successCallbacks = {
+ onattach: this.sucTargetAttach.bind(this),
+ ondetach: this.nfc.sucDetach.bind(this.nfc)
+ };
+
+ try {
+ this.nfc.nfcAdapter.setPeerListener(successCallbacks);
+ } catch (error) {
+ console.error(error.message);
+ }
+ }
+ };
+
+}());
diff --git a/project/js/app.ui.js b/project/js/app.ui.js
new file mode 100644
index 0000000..3f7b1b7
--- /dev/null
+++ b/project/js/app.ui.js
@@ -0,0 +1,571 @@
+/*jslint devel: true*/
+/*global $, tizen, App, app, localStorage: true, TemplateManager, document, window, setTimeout */
+
+App.Ui = null;
+
+(function () { // strict mode wrapper
+ 'use strict';
+
+ App.Ui = function App_Ui(app) {
+ this.app = app;
+ this.templateManager = new TemplateManager(app.config);
+ };
+
+ App.Ui.prototype = {
+ prepareCallerName: function ui_prepareCallerName(contact) {
+ var callerName, firstName, lastName;
+
+ callerName = '';
+ firstName = contact.name.firstName;
+ lastName = contact.name.lastName;
+
+ if (firstName !== '' && firstName !== null) {
+ callerName = firstName;
+ }
+ if (lastName !== '' && lastName !== null) {
+ if (callerName !== '') {
+ callerName += ' ';
+ }
+ callerName += lastName;
+ }
+ if (callerName === '') {
+ callerName = 'No Name';
+ }
+ return callerName;
+ },
+
+ /**
+ * Show a popup
+ * @param {string} message
+ */
+ showPopup: function ui_showPopup(message) {
+ var popup = $("#alertPopup");
+ if(!popup.hasClass('ui-popup')) {
+ popup.popup().trigger('create');
+ }
+ $(".ui-popup-text", popup).text(message);
+ popup.popup("open", {positionTo: 'window'});
+ },
+
+ closePopup: function ui_closePopup() {
+ var activePopup = $.mobile.popup.active;
+ if (activePopup) {
+ if (activePopup.attr('id') === 'alertPopup') {
+ activePopup.close();
+ }
+ }
+ },
+
+ createListRecord: function ui_createListRecord() {
+ $.mobile.changePage('#choose');
+ },
+
+ /**
+ *
+ * @param {string} text
+ * @returns {string}
+ */
+ getWaitingContentHtml: function getWaitingContentHtml(text) {
+ var html;
+ html += '';
+ html += text;
+ html += '
';
+
+ html += '';
+
+ return html;
+ },
+
+ /**
+ *
+ * @param {string} title
+ * @param {string} text
+ */
+ prepareWaitingPage: function ui_prepareWaitingPage(title, text) {
+ var waitingBox, waitingContent,
+ contentTransfer = $('#content-transfer');
+ waitingBox = $('');
+ waitingContent = $(this.getWaitingContentHtml(text));
+ $('#header-transfer H1').text(title);
+ contentTransfer.empty();
+ waitingBox.append(waitingContent);
+ contentTransfer.append(waitingBox);
+ $('#content-start').trigger('create');
+ this.app.countDown(10, $('#counter'));
+ },
+
+ /**
+ * @returns {string}
+ */
+ getTemporaryBoxHtml: function ui_getTemporaryBoxHtml() {
+ return '';
+ },
+
+ /**
+ * @returns {string}
+ */
+ showPopupWarning: function ui_showPopupWarning(){
+ setTimeout(function(){
+ $("#contact-nfc-error").popup("open",{"positionTo":"window"});
+ },500);
+ },
+
+ getTemporaryBoxContentHtml: function ui_getTemporaryBoxContentHtml() {
+ return ''
+ + 'Default card is not defined yet!
'
+ + 'Do you want to define it now?'
+ + '
';
+ },
+
+ loadTemporaryContent: function ui_loadTemporaryContent() {
+ var temporaryBox, temporaryContent, temporaryButton;
+
+ temporaryBox = $(this.getTemporaryBoxHtml());
+ temporaryContent = $(this.getTemporaryBoxContentHtml());
+ temporaryButton = $(this.getButtonHtml('Create default card'));
+
+ temporaryButton.on('click', function (event) {
+ event.preventDefault();
+ $.mobile.changePage('#choose');
+ });
+
+ temporaryBox.append(temporaryContent).append(temporaryButton);
+
+ $('#content-start').empty().append(temporaryBox).trigger('create');
+ },
+ /**
+ *
+ * @param {string} text button text
+ * @returns {string}
+ */
+ getButtonHtml: function ui_getButtonHtml(text) {
+ return ''
+ + text
+ + '
';
+ },
+
+ /**
+ *
+ * @param {string} firstName
+ * @param {string} lastName
+ * @returns {string}
+ */
+ getCommentHtml: function ui_getCommentHtml(data) {
+ var def_name = $('';
+ },
+
+
+ /**
+ * Change Contact button action
+ * @event
+ * @param {Event} event
+ */
+ changeContact: function ui_changeContact(event) {
+ event.preventDefault();
+ $.mobile.changePage('#choose');
+ },
+
+ /**
+ * @returns {jQuery}
+ */
+ getChangeContactButton: function ui_getChangeContactButton() {
+ var changeContactButton;
+ changeContactButton = $(this.getButtonHtml('Change your default contact'));
+ changeContactButton.on('click', this.changeContact);
+ return changeContactButton;
+ },
+
+ /**
+ * Read From Card button action
+ * @event
+ * @param {Event} event
+ */
+ readFromCard: function ui_readFromCard(event) {
+ event.preventDefault();
+ if (tizen.nfc.getDefaultAdapter().powered) {
+ try {
+ $('#transfer').data('option', 'read');
+ $.mobile.changePage('#transfer');
+ } catch (e) {
+ console.error(e.message);
+ }
+ } else {
+ $.mobile.changePage('#start');
+ alert('Please turn on NFC adapter');
+ }
+ },
+
+ /**
+ * @returns {jQuery}
+ */
+ getReadFromCardButton: function ui_getReadFromCardButton() {
+ var readFromCardButton;
+ readFromCardButton = $(this.getButtonHtml('Read from card'));
+ readFromCardButton.on('click', this.readFromCard);
+ return readFromCardButton;
+ },
+
+ /**
+ * Write To Card button action
+ * @param {Event} event
+ */
+ writeToCard: function ui_writeToCard(event) {
+ event.preventDefault();
+ if (tizen.nfc.getDefaultAdapter().powered) {
+ try {
+ $('#transfer').data('option', 'write');
+ $.mobile.changePage('#transfer');
+ } catch (e) {
+ console.error(e.message);
+ }
+ } else {
+ alert('Please turn on NFC adapter');
+ }
+ },
+
+ /**
+ * @returns {jQuery}
+ */
+ getWriteToCardButton: function ui_getWriteToCardButton() {
+ var writeToCardButton;
+ writeToCardButton = $(this.getButtonHtml('Write to card'));
+ writeToCardButton.on('click', this.writeToCard);
+ return writeToCardButton;
+ },
+
+ /**
+ * Communicate With Other Device button action
+ * @param {type} event
+ */
+ communicateWithOtherDevice: function ui_communicateWithOtherDevice(event) {
+ event.preventDefault();
+ if (tizen.nfc.getDefaultAdapter().powered) {
+ try {
+ $('#transfer').data('option', 'communicate');
+ $.mobile.changePage('#transfer');
+ } catch (e) {
+ console.error(e.message);
+ }
+ } else {
+ alert('Please turn on NFC adapter');
+ }
+ },
+
+ /**
+ * @returns {jQuery}
+ */
+ getCommunicateWithOtherDeviceButton: function ui_getCommunicateWithOtherDeviceButton() {
+ var communicateWithOtherDeviceButton;
+ communicateWithOtherDeviceButton = $(this.getButtonHtml('Communicate with another device'));
+ communicateWithOtherDeviceButton.on('click', this.communicateWithOtherDevice);
+ return communicateWithOtherDeviceButton;
+ },
+
+ loadStartContent: function ui_loadStartContent() {
+ var startBox, contentStart, gap, comment;
+ contentStart = $('#content-start');
+ startBox = $('');
+ gap = $('');
+ comment = $(this.getCommentHtml(localStorage));
+
+ contentStart.empty();
+ startBox
+ .append(this.getChangeContactButton())
+ .append(gap.clone())
+ .append(this.getReadFromCardButton())
+ .append(gap.clone())
+ .append(this.getWriteToCardButton())
+ .append(gap.clone())
+ .append(this.getCommunicateWithOtherDeviceButton())
+ .prepend(comment);
+
+ contentStart.append(startBox);
+ contentStart.trigger('create');
+ },
+
+ loadStartPage: function ui_loadStartPage() {
+ if (localStorage.started === undefined) {
+ this.loadTemporaryContent();
+ } else {
+ this.loadStartContent();
+ }
+ },
+
+ /**
+ *
+ * @param {string} value
+ * @param {string} label
+ * @returns {string}
+ */
+ getLiHtml: function ui_getLiHtml(value, label) {
+ var html;
+ html = ''
+ + ''
+ + '' + label + ''
+ + ''
+ + ((!value) ? '...' : value)
+ + ''
+ + ''
+ + '';
+ return html;
+ },
+
+ /**
+ *
+ * @param {string} phone
+ * @param {string} first
+ * @param {string} last
+ * @returns {string}
+ */
+ getContactsUlHtml: function ui_getContactsUlHtml(phone, first, last) {
+ var html;
+ html = '';
+ return html;
+ },
+
+ /**
+ * @param {object} contact
+ * @returns {string}
+ */
+ getContactsListElement: function ui_getContactsListElement(contact) {
+ var caller = $('')
+ .text(contact.caller).html(),
+ phoneNumber = contact.phoneNumber,
+ html =
+ ''
+ + '' + caller
+ + '' + phoneNumber + ''
+ + ''
+ + '';
+ return html;
+ },
+
+ prepareContactsTemplate: function ui_prepareContactsTemplate(phone, first, last) {
+ $('#content-contact > .ui-scrollview-view')
+ .empty()
+ .append(this.getContactsUlHtml(phone, first, last));
+ $('#content-contact').trigger('create');
+ },
+
+ contactsCompare: function ui_contactsCompare(a, b) {
+ if (a.caller < b.caller) {
+ return -1;
+ }
+ if (a.caller > b.caller) {
+ return 1;
+ }
+ return 0;
+ },
+
+ createSortedContactArray: function ui_createSortedContactArray(contacts) {
+ var i, len, sortedContactList = [], contact, phoneNumber;
+
+ for (i = 0, len = contacts.length; i < len; i += 1) {
+ contact = contacts[i];
+ if (contact.phoneNumbers.length === 0) {
+ phoneNumber = '';
+ } else {
+ phoneNumber = contact.phoneNumbers[0].number;
+ }
+ sortedContactList.push({
+ caller: this.prepareCallerName(contact),
+ firstName: contact.name.firstName || '',
+ lastName: contact.name.lastName || '',
+ phoneNumber: phoneNumber,
+ id: contact.id,
+ vCard: contact.convertToString('VCARD_30'),
+ contact: contact
+ });
+ }
+ sortedContactList.sort(this.contactsSort);
+
+ return sortedContactList;
+ },
+
+ createSortedContactList: function ui_createSortedContactList(contacts) {
+ var sortedContactList = this.createSortedContactArray(contacts),
+ ul = $(''),
+ i,
+ len,
+ listElement,
+ listElementTap,
+ self = this,
+ contact;
+
+ listElementTap = function (event) {
+ event.preventDefault();
+ $(this).addClass('selected').siblings().removeClass('selected');
+ self.app.saveDefaultCard();
+ };
+
+ for (i = 0, len = sortedContactList.length; i < len; i += 1) {
+ contact = sortedContactList[i];
+ if (contact.phoneNumber !== '') {
+ listElement = $(this.getContactsListElement(contact));
+ listElement
+ .data('caller', contact.caller)
+ .data('firstName', contact.firstName)
+ .data('lastName', contact.lastName)
+ .data('phoneNumber', contact.phoneNumber)
+ .data('id', contact.id)
+ .data('vCard', contact.vCard);
+ if (localStorage.id === listElement.data('id')) {
+ listElement.addClass('selected');
+ }
+ ul.append(listElement);
+ }
+ }
+ ul.on('tap taphold click', 'li', listElementTap);
+ return ul;
+ },
+
+ showContactsList: function ui_showContactsList(contacts) {
+ var ul = this.createSortedContactList(contacts);
+ $('#content-choose > .ui-scrollview-view').empty().append(ul);
+ $('#content-choose').trigger('create');
+ },
+
+ moveToStartPage: function ui_moveToStartPage(monit) {
+ $('#start').data('monit', monit || '');
+ $.mobile.changePage('#start');
+ },
+
+ isActivePage: function ui_isActivePage(id) {
+ return (id === $.mobile.activePage.attr("id"));
+ },
+
+ refreshIfActivePage: function ui_refreshIfActivePage(id) {
+ if (this.isActivePage(id)) {
+ $.mobile.activePage
+ .trigger("pagebeforeshow")
+ .trigger("pageshow");
+ }
+ },
+
+ moveToContactPage: function ui_moveToContactPage(obj) {
+ $('#start').data('monit', '');
+ $('#contact').data('contactsData', obj);
+ $.mobile.changePage('#contact');
+ },
+
+ defineEvents: function ui_defineEvents() {
+ var self = this;
+
+ $('#header-start .ui-btn-back').on('click', function (event) {
+ event.preventDefault();
+ self.app.nfc.stopNFC();
+ });
+
+ $('#header-start').on('click', '.ui-btn-back.ui-focus', function () {
+ return false;
+ });
+
+ $('#footer-contact').on('click', '.ui-btn-back', function (event) {
+ event.preventDefault();
+ $.mobile.changePage('#start');
+ });
+
+ $('#footer-choose').on('click', '.ui-btn-back', function (event) {
+ event.preventDefault();
+ $.mobile.changePage('#start');
+ });
+
+ $('#choose').on('pageshow', function (event) {
+ self.app.loadContacts(self.showContactsList.bind(self), function (e) {
+ alert('Cannot load the contacts list: ' + e.message);
+ console.error(e.message, e);
+ });
+ });
+
+ $('#contact').on('pageshow', function (event) {
+ var data = $(this).data('contactsData');
+ self.prepareContactsTemplate(data.phone, data.first, data.last);
+ });
+
+ $('#save-contact').on('click', function (event) {
+ event.preventDefault();
+ self.app.saveContact();
+ });
+
+ $('#start').on('pagebeforeshow', function () {
+ if (self.app.started) {
+ self.loadStartPage();
+ }
+ });
+
+ $('#start').on('pageshow', function () {
+ var obj = $(this), monit = obj.data('monit');
+ if (monit !== '' && monit !== undefined) {
+ self.showPopup(obj.data('monit'));
+ obj.data('monit', '');
+ }
+ });
+
+ $( "#contact-nfc-error" ).bind({
+ popupafterclose: function(){
+ tizen.application.getCurrentApplication().exit();
+ }
+ });
+
+ window.addEventListener('tizenhwkey', function(e) {
+ if (e.keyName == "back") {
+ if ($.mobile.popup.active) {
+ $.mobile.popup.active.close();
+ } else if ($.mobile.activePage.attr('id') === 'start') {
+ tizen.application.getCurrentApplication().exit();
+ } else {
+ self.app.nfc.timeExpired();
+ }
+ }
+ });
+
+ document.addEventListener('webkitvisibilitychange', function () {
+ if(document.webkitVisibilityState === "visible") {
+ if ($.mobile.activePage.attr('id') === "choose") {
+ $.mobile.activePage.trigger('pageshow');
+ }
+ app.counterState = true;
+ } else {
+ app.counterState = false;
+ }
+ });
+
+ $('#transfer').on('pageshow', function () {
+ if (tizen.nfc.getDefaultAdapter().powered) {
+ try {
+ var option = $(this).data('option');
+ if (option === 'read') {
+ self.prepareWaitingPage('Card to device', 'PUT WIRELESS TAG
CLOSE TO
YOUR DEVICE');
+ self.app.nfc.card.setTagDetectRead();
+ } else if (option === 'write') {
+ self.prepareWaitingPage('Device to card', 'PUT WIRELESS TAG
CLOSE TO
YOUR DEVICE');
+ self.app.nfc.card.setTagDetectWrite();
+ } else {
+ self.prepareWaitingPage('Device to device', 'PUT YOUR DEVICE
CLOSE TO
OTHER DEVICE');
+ self.app.nfc.peer.setTargetDetect();
+ }
+ } catch (e) {
+ console.error(e.message);
+ }
+ } else {
+ $.mobile.changePage('#start');
+ alert('Please turn on NFC adapter');
+ }
+ });
+ }
+
+ };
+
+}());
diff --git a/project/js/app.ui.templateManager.js b/project/js/app.ui.templateManager.js
new file mode 100644
index 0000000..68c6678
--- /dev/null
+++ b/project/js/app.ui.templateManager.js
@@ -0,0 +1,111 @@
+/*global tizen, $, app */
+/**
+ * @class TemplateManager
+ */
+function TemplateManager() {
+ 'use strict';
+ this.init();
+}
+
+(function () { // strict mode wrapper
+ 'use strict';
+ TemplateManager.prototype = {
+
+ /**
+ * Template cache
+ */
+ cache: {},
+
+ /**
+ * UI module initialisation
+ */
+ init: function init() {
+ },
+
+ /**
+ * Returns template html (from cache)
+ * @param {string} tplName
+ * @param {string} tplParams
+ */
+ get: function TemplateManager_get(tplName, tplParams) {
+ if (this.cache[tplName] !== undefined) {
+ return this.getCompleted(this.cache[tplName], tplParams);
+ }
+ return '';
+ },
+
+ /**
+ * Load templates to cache
+ * @param {string} tplNames
+ * @param {function} onSuccess
+ */
+ loadToCache: function TemplateManager_loadToCache(tplNames, onSuccess) {
+ var self = this,
+ cachedTemplates = 0,
+ tplName,
+ tplPath;
+
+ if ($.isArray(tplNames)) {
+
+ // for each template
+ $.each(tplNames, function (index, fileName) {
+
+ // cache template html
+ if (self.cache[fileName] === undefined) {
+ tplName = [fileName, app.config.get('templateExtension')].join('');
+ tplPath = [app.config.get('templateDir'), tplName].join('/');
+
+ $.ajax({
+ url: tplPath,
+ cache: true,
+ dataType: 'html',
+ async: true,
+ success: function (data) {
+ // increase counter
+ cachedTemplates += 1;
+
+ // save to cache
+ self.cache[fileName] = data;
+
+ // if all templates are cached launch callback
+ if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') {
+ onSuccess();
+ }
+ },
+ error: function (jqXHR, textStatus, errorThrown) {
+ console.error('templateManagerError: ' + errorThrown);
+ }
+ });
+ } else {
+ // template is already cached
+ cachedTemplates += 1;
+ // if all templates are cached launch callback
+ if (cachedTemplates >= tplNames.length && typeof onSuccess === 'function') {
+ onSuccess();
+ }
+ }
+ });
+
+ }
+ },
+
+ /**
+ * Returns template completed by specified params
+ * @param {string} tplHtml
+ * @param {string} tplParams
+ */
+ getCompleted: function TemplateManager_getCompleted(tplHtml, tplParams) {
+ var tplParam, replaceRegExp;
+
+ for (tplParam in tplParams) {
+ if (tplParams.hasOwnProperty(tplParam)) {
+ replaceRegExp = new RegExp(['%', tplParam, '%'].join(''), 'g');
+ tplHtml = tplHtml.replace(replaceRegExp, tplParams[tplParam]);
+ }
+ }
+
+ return tplHtml;
+ }
+ };
+
+}());
\ No newline at end of file
diff --git a/tizen-app-template.xml b/tizen-app-template.xml
new file mode 100755
index 0000000..92633c5
--- /dev/null
+++ b/tizen-app-template.xml
@@ -0,0 +1,12 @@
+
+
+ ContactsExchanger
+ TIZEN
+
+ description.xml
+
+
+
+
+
+
diff --git a/tizen_32.png b/tizen_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..61f35c0507d8a7275c92019e8dcc399148d7e1d9
GIT binary patch
literal 4563
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
literal 0
HcmV?d00001
diff --git a/tizen_64.png b/tizen_64.png
new file mode 100644
index 0000000000000000000000000000000000000000..b1880832b1ee1bf80498667f1dde9b8b744761ec
GIT binary patch
literal 6849
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
literal 0
HcmV?d00001
--
2.7.4