diff --git a/www/assets/js/add.js b/www/assets/js/add.js index 79ec632..6e24bdb 100644 --- a/www/assets/js/add.js +++ b/www/assets/js/add.js @@ -35,6 +35,16 @@ $("#addpackagebtn").click(function () { }); return; } + if ($("input[name=zipcode]").val().trim() == "") { + playSound("error"); + app.toast.show({ + text: "Please fill in a ZIP code.", + position: "bottom", + destroyOnClose: true, + closeTimeout: 1000 * 10 + }); + return; + } // Save city/state if changed if (getStorage("citystate") != $("input[name=citystate]").val().trim()) { @@ -49,6 +59,7 @@ $("#addpackagebtn").click(function () { $("#no-history").addClass("display-none"); addPackageByAddress( $("input[name=number]").val().toUpperCase(), + $("input[name=unit]").val().toUpperCase(), $("input[name=street]").val().toUpperCase(), $("input[name=citystate]").val().toUpperCase(), $("input[name=zipcode]").val().toUpperCase(), @@ -68,6 +79,9 @@ $("#addpackagebtn").click(function () { + ' ' + ''); }); + // Clear out unit value since it's unlikely to + // be used twice + $("input[name=unit]").val(""); }); // Remove any pre-existing click handlers from the history list, diff --git a/www/assets/js/location.js b/www/assets/js/location.js index e02bc67..6b5f8f9 100644 --- a/www/assets/js/location.js +++ b/www/assets/js/location.js @@ -11,7 +11,8 @@ var userPosition = { latitude: 0.0, longitude: 0.0, accuracy: 999999 - } + }, + updated: 0 }; // Preload last known location while GPS warms up @@ -31,6 +32,7 @@ $.ajax({ userPosition.coords.latitude = resp.location.latitude; userPosition.coords.longitude = resp.location.longitude; userPosition.coords.accuracy = 99999; + userPosition.updated = time(); } } }); @@ -41,7 +43,8 @@ var mapLocationControlStarted = false; if ("geolocation" in navigator) { navigator.geolocation.watchPosition(function (position) { - userPosition = position; + userPosition.coords = position.coords; + userPosition.updated = time(); setStorage("user_latitude", userPosition.coords.latitude); setStorage("user_longitude", userPosition.coords.longitude); if (mapLocationControlStarted) { diff --git a/www/assets/js/packages.js b/www/assets/js/packages.js index fd573bd..747755a 100644 --- a/www/assets/js/packages.js +++ b/www/assets/js/packages.js @@ -91,6 +91,13 @@ function addPackage(address, latitude, longitude, type, callback, deadline) { deadline = false; } + if (typeof address == "object") { + var extendedaddress = address; + address = extendedaddress.address; + } else { + var extendedaddress = false; + } + // Extra precision makes the map stupider, // and doesn't really increase accuracy since four decimal places ~= 11m latitude = +(parseFloat("" + latitude).toFixed(4)); @@ -103,6 +110,7 @@ function addPackage(address, latitude, longitude, type, callback, deadline) { if (packages[i].coords[0] == latitude && packages[i].coords[1] == longitude) { coordsID = packages[i].id; packages[i].items.push({ + extended: extendedaddress, address: address, delivered: false, type: type, @@ -124,6 +132,7 @@ function addPackage(address, latitude, longitude, type, callback, deadline) { address: address, items: [ { + extended: extendedaddress, address: address, delivered: false, type: type, @@ -203,10 +212,96 @@ function importPackageList(newlist) { return skipped; } +function mapCalibrate(item, packagesentry) { + // Determine if the delivery location isn't near the map pin + if (userPosition.coords.accuracy < 20 && timeDiff(userPosition.updated) < 10) { + // User location is accurate, check distance + var distance = getDistance(packagesentry.coords[0], packagesentry.coords[1], userPosition.coords.latitude, userPosition.coords.longitude); + var lat = userPosition.coords.latitude; + var lon = userPosition.coords.longitude; + if (distance > 100) { // Over 100 meters distance + if (typeof item.extended == "object") { + // we have all the info we need + var fixmap = function (item, latitude, longitude, locationtype) { + $.ajax({ + type: "POST", + url: SETTINGS.mapfixapi, + data: { + number: item.extended.number, + unit: item.extended.unit, + street: item.extended.street, + citystate: item.extended.citystate, + zip: item.extended.zip, + latitude: latitude, + longitude: longitude, + locationtype: locationtype + }, + success: function () { + app.toast.show({ + text: "Calibration recorded. Thank you for improving the map!", + position: "bottom", + destroyOnClose: true, + closeTimeout: 1000 * 3 + }); + }, + error: function () { + // try again in five minutes + setTimeout(function () { + fixmap(item, latitude, longitude, locationtype); + }, 1000 * 60 * 5); + }, + dataType: "json" + }); + }; + + app.dialog.create({ + title: 'Map Calibration', + text: "Your actual location doesn't match the map location for the " + SETTINGS.itemtypes[item.type].name + " at " + item.address + ". Where are you?", + buttons: [ + { + text: 'Address', + close: true + }, + { + text: 'Mailbox/CBU', + close: true + }, + { + text: 'Parcel Locker', + close: true + }, + { + text: "Other/Cancel", + close: true + } + ], + verticalButtons: true, + onClick: function (dialog, index) { + switch (index) { + case 0: + fixmap(item, lat, lon, "address"); + break; + case 1: + fixmap(item, lat, lon, "mailbox"); + break; + case 2: + fixmap(item, lat, lon, "locker"); + break; + default: + return; + } + } + }).open(); + } + } + } +} + function markDelivered(id, delivered) { for (var i = 0; i < packages.length; i++) { for (var j = 0; j < packages[i].items.length; j++) { if (packages[i].items[j].id == id) { + if (typeof delivered == 'undefined') { if (packages[i].items[j].delivered == false) { delivered = true; @@ -218,12 +313,16 @@ function markDelivered(id, delivered) { packages[i].items[j].delivered = delivered; if (delivered) { packages[i].items[j].deliverytimestamp = Date.now(); + + setStorage("packages", JSON.stringify(packages)); + + mapCalibrate(packages[i].items[j], packages[i]); + + return; // so we don't keep looping over the rest of the packages } } } } - - setStorage("packages", JSON.stringify(packages)); } function confirmDeletePackage(package, callback) { @@ -284,7 +383,7 @@ function countPackages() { return count; } -function addPackageByAddress(number, street, citystate, zip, type, callback) { +function addPackageByAddress(number, unit, street, citystate, zip, type, callback) { var requestfinished = false; var searchingdialogopen = false; var deadline = false; @@ -297,7 +396,10 @@ function addPackageByAddress(number, street, citystate, zip, type, callback) { } geocodecache = JSON.parse(geocodecache); - var cachekey = number + " || " + street + " || " + citystate; + var cachekey = number + " || " + street + " || " + citystate + " || " + zip + " || " + SETTINGS.itemtypes[type].allowedlocationtypes; + if (unit != '') { + cachekey = number + " || " + unit + " || " + street + " || " + citystate + " || " + zip + " || " + SETTINGS.itemtypes[type].allowedlocationtypes; + } var cacheitem = geocodecache[cachekey]; var timestamp = Math.floor(Date.now() / 1000); if (typeof cacheitem != 'undefined') { @@ -307,7 +409,14 @@ function addPackageByAddress(number, street, citystate, zip, type, callback) { setStorage("geocode_cache", JSON.stringify(geocodecache)); } else { console.log("Info", "Using cached geocode result", cacheitem); - addPackage(cacheitem.address, cacheitem.latitude, cacheitem.longitude, type, callback, deadline); + addPackage({ + address: cacheitem.address, + number: number, + unit: unit, + street: street, + citystate: citystate, + zip: zip + }, cacheitem.latitude, cacheitem.longitude, type, callback, deadline); return; } } @@ -317,9 +426,11 @@ function addPackageByAddress(number, street, citystate, zip, type, callback) { dataType: 'json', data: { number: number, + unit: unit, street: street, citystate: citystate, - zip: zip + zip: zip, + type: SETTINGS.itemtypes[type].allowedlocationtypes }, timeout: 15 * 1000, success: function (resp) { @@ -330,8 +441,17 @@ function addPackageByAddress(number, street, citystate, zip, type, callback) { requestfinished = true; if (resp.status == "OK") { if (resp.accuracy.ok) { - addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback, deadline); + addPackage({ + address: resp.address.street, + number: number, + unit: unit, + street: street, + citystate: citystate, + zip: zip + }, resp.coords[0], resp.coords[1], type, callback, deadline); geocodecache[cachekey] = { + number: resp.address.number, + unit: unit, address: resp.address.street, latitude: resp.coords[0], longitude: resp.coords[1], @@ -345,9 +465,23 @@ function addPackageByAddress(number, street, citystate, zip, type, callback) { "Accuracy Warning", function (ok) { if (resp.address.street == "") { - addPackage(address, resp.coords[0], resp.coords[1], type, callback, deadline); + addPackage({ + address: address, + number: number, + unit: unit, + street: street, + citystate: citystate, + zip: zip + }, resp.coords[0], resp.coords[1], type, callback, deadline); } else { - addPackage(resp.address.street, resp.coords[0], resp.coords[1], type, callback, deadline); + addPackage({ + address: resp.address.street, + number: number, + unit: unit, + street: street, + citystate: citystate, + zip: zip + }, resp.coords[0], resp.coords[1], type, callback, deadline); } } ); diff --git a/www/assets/js/util.js b/www/assets/js/util.js index b2d4aa8..2982c4c 100644 --- a/www/assets/js/util.js +++ b/www/assets/js/util.js @@ -38,4 +38,21 @@ function timestampToTimeString(timestamp) { var time = hours + ":" + (minutes < 10 ? "0" + minutes : minutes) + " " + (pm ? "PM" : "AM"); return time; +} + +/** + * Get the current UNIX timestamp in seconds. + * @returns {Number} + */ +function time() { + return Date.now() / 1000; +} + +/** + * Get the number of seconds between now and the given timestamp. + * @param {Number} compareto + * @returns {Number} + */ +function timeDiff(compareto) { + return time() - compareto; } \ No newline at end of file diff --git a/www/pages/add.html b/www/pages/add.html index e8a1517..f48ef22 100644 --- a/www/pages/add.html +++ b/www/pages/add.html @@ -37,12 +37,23 @@