BangleApps/apps/flightdash/flightdash.settings.js

328 lines
9.6 KiB
JavaScript
Raw Normal View History

2023-11-28 09:54:28 +00:00
(function(back) {
const APP_NAME = 'flightdash';
const FILE = APP_NAME+'.json';
// if the avwx module is available, include an extra menu item to query nearest airports via AVWX
var avwx;
try {
avwx = require('avwx');
} catch (error) {
// avwx module not installed
}
// Load settings
var settings = Object.assign({
useBaro: false,
speedUnits: 0, // KTS
altimeterUnits: 0, // FT
destID: 'KOSH',
destLat: 43.9844,
destLon: -88.5570,
}, require('Storage').readJSON(FILE, true) || {});
function writeSettings() {
require('Storage').writeJSON(FILE, settings);
}
// update the nav destination
function updateNavDest(destID, destLat, destLon) {
settings.destID = destID.replace(/[\W]+/g, '').slice(0, 7);
settings.destLat = parseFloat(destLat);
settings.destLon = parseFloat(destLon);
writeSettings();
createDestMainMenu();
}
2023-11-28 09:54:28 +00:00
var airports; // cache list of airports
function readAirportsList(empty_cb) {
if (airports) { // airport list has already been read in
return true;
}
airports = require('Storage').readJSON(APP_NAME+'.airports.json', true);
if (! airports) {
E.showPrompt('No airports stored - download from the Bangle Apps Loader!',
{title: 'Flight-Dash', buttons: {OK: true} }).then((v) => {
empty_cb();
});
return false;
}
return true;
}
// use GPS fix
var afterGPSfixMenu = 'destNearest';
function getLatLon(fix) {
if (!('fix' in fix) || fix.fix == 0 || fix.satellites < 4) return;
Bangle.setGPSPower(false, APP_NAME+'-settings');
Bangle.removeListener('GPS', getLatLon);
switch (afterGPSfixMenu) {
case 'destNearest':
loadNearest(fix.lat, fix.lon);
break;
case 'createUserWaypoint':
{
if (!('userWaypoints' in settings))
settings.userWaypoints = [];
let newIdx = settings.userWaypoints.length;
settings.userWaypoints[newIdx] = {
'ID': 'USER'+(newIdx + 1),
'lat': fix.lat,
'lon': fix.lon,
};
writeSettings();
showUserWaypoints();
break;
}
2023-11-28 09:54:28 +00:00
case 'destAVWX':
// the free ("hobby") account of AVWX is limited to 10 nearest stations
avwx.request('station/near/'+fix.lat+','+fix.lon, 'n=10&airport=true&reporting=false', data => {
loadAVWX(data);
}, error => {
console.log(error);
E.showPrompt('AVWX query failed: '+error, {title: 'Flight-Dash', buttons: {OK: true} }).then((v) => {
createDestMainMenu();
});
});
break;
default:
back();
}
}
// find nearest airports
function loadNearest(lat, lon) {
if (! readAirportsList(createDestMainMenu))
return;
const latRad1 = lat * Math.PI/180;
const lonRad1 = lon * Math.PI/180;
for (let i = 0; i < airports.length; i++) {
const latRad2 = airports[i].la * Math.PI/180;
const lonRad2 = airports[i].lo * Math.PI/180;
let x = (lonRad2 - lonRad1) * Math.cos((latRad1 + latRad2) / 2);
let y = (latRad2 - latRad1);
airports[i].distance = Math.sqrt(x*x + y*y) * 6371;
}
let nearest = airports.sort((a, b) => a.distance - b.distance).slice(0, 14);
let destNearest = {
'' : { 'title' : 'Nearest' },
'< Back' : () => createDestMainMenu(),
};
for (let i in nearest) {
let airport = nearest[i];
destNearest[airport.i+' - '+airport.n] =
() => setTimeout(updateNavDest, 10, airport.i, airport.la, airport.lo);
2023-11-28 09:54:28 +00:00
}
E.showMenu(destNearest);
}
// process the data returned by AVWX
function loadAVWX(data) {
let AVWXairports = JSON.parse(data.resp);
let destAVWX = {
'' : { 'title' : 'Nearest (AVWX)' },
'< Back' : () => createDestMainMenu(),
};
for (let i in AVWXairports) {
let airport = AVWXairports[i].station;
let airport_id = ( airport.icao ? airport.icao : airport.gps );
destAVWX[airport_id+' - '+airport.name] =
() => setTimeout(updateNavDest, 10, airport_id, airport.latitude, airport.longitude);
2023-11-28 09:54:28 +00:00
}
E.showMenu(destAVWX);
}
// individual user waypoint menu
function showUserWaypoint(idx) {
let wayptID = settings.userWaypoints[idx].ID;
let wayptLat = settings.userWaypoints[idx].lat;
let wayptLon = settings.userWaypoints[idx].lon;
let destUser = {
'' : { 'title' : wayptID },
'< Back' : () => showUserWaypoints(),
};
destUser['Set as Dest.'] =
() => setTimeout(updateNavDest, 10, wayptID, wayptLat, wayptLon);
2023-11-28 09:54:28 +00:00
destUser['Edit ID'] = function() {
require('textinput').input({text: wayptID}).then(result => {
if (result) {
if (result.length > 7) {
console.log('test');
E.showPrompt('ID is too long!\n(max. 7 chars)',
{title: 'Flight-Dash', buttons: {OK: true} }).then((v) => {
showUserWaypoint(idx);
});
} else {
settings.userWaypoints[idx].ID = result;
writeSettings();
showUserWaypoint(idx);
}
} else {
showUserWaypoint(idx);
}
});
};
destUser['Delete'] = function() {
E.showPrompt('Delete user waypoint '+wayptID+'?',
{'title': 'Flight-Dash'}).then((v) => {
if (v) {
settings.userWaypoints.splice(idx, 1);
writeSettings();
showUserWaypoints();
} else {
showUserWaypoint(idx);
}
});
};
E.showMenu(destUser);
}
// user waypoints menu
function showUserWaypoints() {
let destUser = {
'' : { 'title' : 'User Waypoints' },
'< Back' : () => createDestMainMenu(),
};
for (let i in settings.userWaypoints) {
let waypt = settings.userWaypoints[i];
let idx = i;
destUser[waypt.ID] =
() => setTimeout(showUserWaypoint, 10, idx);
2023-11-28 09:54:28 +00:00
}
destUser['Create New'] = function() {
E.showMessage('Waiting for GPS fix', {title: 'Flight-Dash'});
afterGPSfixMenu = 'createUserWaypoint';
Bangle.setGPSPower(true, APP_NAME+'-settings');
Bangle.on('GPS', getLatLon);
};
E.showMenu(destUser);
}
// destination main menu
function createDestMainMenu() {
let destMainMenu = {
'' : { 'title' : 'Nav Dest.' },
'< Back' : () => E.showMenu(mainMenu),
};
destMainMenu['Is: '+settings.destID] = {};
destMainMenu['Nearest'] = function() {
E.showMessage('Waiting for GPS fix', {title: 'Flight-Dash'});
afterGPSfixMenu = 'destNearest';
Bangle.setGPSPower(true, APP_NAME+'-settings');
Bangle.on('GPS', getLatLon);
};
destMainMenu['Search'] = function() {
require('textinput').input({text: ''}).then(result => {
if (result) {
if (! readAirportsList(createDestMainMenu))
return;
result = result.toUpperCase();
let matches = [];
let tooManyFound = false;
for (let i in airports) {
if (airports[i].i.toUpperCase().includes(result) ||
airports[i].n.toUpperCase().includes(result)) {
matches.push(airports[i]);
if (matches.length >= 15) {
tooManyFound = true;
break;
}
}
}
if (! matches.length) {
E.showPrompt('No airports found!', {title: 'Flight-Dash', buttons: {OK: true} }).then((v) => {
createDestMainMenu();
});
return;
}
let destSearch = {
'' : { 'title' : 'Search Results' },
'< Back' : () => createDestMainMenu(),
};
for (let i in matches) {
let airport = matches[i];
destSearch[airport.i+' - '+airport.n] =
() => setTimeout(updateNavDest, 10, airport.i, airport.la, airport.lo);
2023-11-28 09:54:28 +00:00
}
if (tooManyFound) {
destSearch['More than 15 airports found!'] = {};
}
E.showMenu(destSearch);
} else {
createDestMainMenu();
}
});
};
destMainMenu['User waypts'] = function() { showUserWaypoints(); };
if (avwx) {
destMainMenu['Nearest (AVWX)'] = function() {
E.showMessage('Waiting for GPS fix', {title: 'Flight-Dash'});
afterGPSfixMenu = 'destAVWX';
Bangle.setGPSPower(true, APP_NAME+'-settings');
Bangle.on('GPS', getLatLon);
};
}
E.showMenu(destMainMenu);
}
// main menu
mainMenu = {
'' : { 'title' : 'Flight-Dash' },
'< Back' : () => {
Bangle.setGPSPower(false, APP_NAME+'-settings');
Bangle.removeListener('GPS', getLatLon);
back();
},
'Nav Dest.': () => createDestMainMenu(),
'Speed': {
value: parseInt(settings.speedUnits) || 0,
min: 0,
max: 2,
format: v => {
switch (v) {
case 0: return 'Knots';
case 1: return 'km/h';
case 2: return 'MPH';
}
},
onchange: v => {
settings.speedUnits = v;
writeSettings();
}
},
'Altitude': {
value: parseInt(settings.altimeterUnits) || 0,
min: 0,
max: 1,
format: v => {
switch (v) {
case 0: return 'Feet';
case 1: return 'Meters';
}
},
onchange: v => {
settings.altimeterUnits = v;
writeSettings();
}
},
'Use Baro': {
value: !!settings.useBaro, // !! converts undefined to false
onchange: v => {
settings.useBaro = v;
writeSettings();
}
},
};
E.showMenu(mainMenu);
})