2. Geolocation
Let’s update Kilo to save the location when entries are created.
Once we have that information, we’ll add a Map Location button that will
open the built-in Maps application and drop a pin at the point where the
entry was created.
The first step is to add latitude and
longitude columns to the database to store the information. To do so,
replace the CREATE TABLE statement in
~/Desktop/KiloGap/assets/www/kilo.js with the
following:
db.transaction(
function(transaction) {
transaction.executeSql(
'CREATE TABLE IF NOT EXISTS entries ' +
' (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, ' +
' date DATE NOT NULL, food TEXT NOT NULL, ' +
' calories INTEGER NOT NULL, ' +
' longitude TEXT NOT NULL, latitude TEXT NOT NULL);'
);
}
);
Replace the existing
createEntry() function in kilo.js with
this:
function createEntry() {
navigator.geolocation.getCurrentPosition(
function(position){
var latitude = position.coords.latitude;
var longitude = position.coords.longitude;
insertEntry(latitude, longitude);
},
function(){
insertEntry();
}
);
return false;
}
Wondering where the SQL INSERT statement got to? Let’s
take a look at the insertEntry()
function. This new function creates the entry in the database. Add the
following to kilo.js:
function insertEntry(latitude, longitude) {
var date = sessionStorage.currentDate;
var calories = $('#calories').val();
var food = $('#food').val();
db.transaction(
function(transaction) {
transaction.executeSql(
'INSERT INTO entries (date, calories, food, latitude, longitude) ' +
'VALUES (?, ?, ?, ?, ?);',
[date, calories, food, latitude, longitude],
function(){
refreshEntries();
checkBudget();
jQT.goBack();
},
errorHandler
);
}
);
}
To confirm that Kilo is actually saving these
location values, we’ll want to display them somewhere in the interface.
Let’s add an Inspect Entry panel to display the stored values. We’ll include a Map Location
button on the panel that will display where the entry was created. Add
the following to index.html, right before the
closing body tag (</body>):<div id="inspectEntry">
<div class="toolbar">
<h1>Inspect Entry</h1>
<a class="button cancel" href="#">Cancel</a>
</div>
<form method="post">
<ul class="rounded">
<li><input type="text" placeholder="Food" name="food" value="" /></li>
<li><input type="tel" placeholder="Calories"
name="calories" value="" /></li>
<li><input type="submit" value="Save Changes" /></li>
</ul>
<ul class="rounded">
<li><input type="text" name="latitude" value="" /></li>
<li><input type="text" name="longitude" value="" /></li>
<li><p class="whiteButton" id="mapLocation">Map Location</p></li>
</ul>
</form>
</div>
Now we need to give the user a way to
navigate to this Inspect Entry panel, so we’ll modify the behavior of
the Date panel such that when the user taps an entry in the list, the
Inspect Entry panel will slide up from the bottom of the screen.
The first step is to wire up the click event
handler (which we’ll create next), and also modify the way clicks on the
Delete button are processed. Add the three highlighted changes below to
the refreshEntries() function in
kilo.js:
function refreshEntries() {
var currentDate = sessionStorage.currentDate;
$('#date h1').text(currentDate);
$('#date ul li:gt(0)').remove();
db.transaction(
function(transaction) {
transaction.executeSql(
'SELECT * FROM entries WHERE date = ? ORDER BY food;',
[currentDate],
function (transaction, result) {
for (var i=0; i < result.rows.length; i++) {
var row = result.rows.item(i);
var newEntryRow = $('#entryTemplate').clone();
newEntryRow.removeAttr('id');
newEntryRow.removeAttr('style');
newEntryRow.data('entryId', row.id);
newEntryRow.appendTo('#date ul');
newEntryRow.find('.label').text(row.food);
newEntryRow.find('.calories').text(row.calories);
newEntryRow.find('.delete').click(function(e){
var clickedEntry = $(this).parent();
var clickedEntryId = clickedEntry.data('entryId');
deleteEntryById(clickedEntryId);
clickedEntry.slideUp();
e.stopPropagation();
});
newEntryRow.click(entryClickHandler);
}
},
errorHandler
);
}
);
}
Now let’s add the
entryClickHandler() function to
kilo.js:function entryClickHandler(e){
sessionStorage.entryId = $(this).data('entryId');
db.transaction(
function(transaction) {
transaction.executeSql(
'SELECT * FROM entries WHERE id = ?;',
[sessionStorage.entryId],
function (transaction, result) {
var row = result.rows.item(0);
var food = row.food;
var calories = row.calories;
var latitude = row.latitude;
var longitude = row.longitude;
$('#inspectEntry input[name="food"]').val(food);
$('#inspectEntry input[name="calories"]').val(calories);
$('#inspectEntry input[name="latitude"]').val(latitude);
$('#inspectEntry input[name="longitude"]').val(longitude);
$('#mapLocation').click(function(){
window.location = 'http://maps.google.com/maps?z=15&q='+
food+'@'+latitude+','+longitude;
});
jQT.goTo('#inspectEntry', 'slideup');
},
errorHandler
);
}
);
}
To test your changes, open a command prompt,
cd into the KiloGap directory,
and run the following commands to recompile and install the app on your
phone:
ant debug
adb -d install -r ~/Desktop/KiloGap/bin/Kilo-debug.apk