Remove BangleRun as it's unmaintained and no longer works nicely with PR #1052 for Typescript support

Remove Travis builds as we're now switching to GitHub actions
master
Gordon Williams 2022-02-28 13:10:55 +00:00
parent a375853e46
commit 52d54c9234
22 changed files with 0 additions and 1047 deletions

View File

@ -1,3 +0,0 @@
language: node_js
node_js:
- "node"

View File

@ -1,13 +0,0 @@
0.01: First release
0.02: Bugfix time: Reset minutes to 0 when hitting 60
0.03: Fix distance >=10 km (fix #529)
0.04: Use offscreen buffer for flickerless updates
0.05: Complete rewrite. New UI, GPS & HRM Kalman filters, activity logging
0.06: Reading HDOP directly from the GPS event (needs Espruino 2v07 or above)
0.07: Fixed GPS update, added guards against NaN values
0.08: Fix issue with GPS coordinates being wrong after the first one
0.09: Another GPS fix (log raw coordinates - not filtered ones)
0.10: Removed kalman filtering to allow distance log to work
Only log data every 5 seconds (not 1 sec)
Don't create a file until the first log entry is ready
Add labels for buttons

View File

@ -1,40 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.stopActivity = exports.startActivity = exports.clearActivity = void 0;
const display_1 = require("./display");
const log_1 = require("./log");
const state_1 = require("./state");
function startActivity(state) {
if (state.status === state_1.ActivityStatus.Stopped) {
(0, log_1.initLog)(state);
}
if (state.status === state_1.ActivityStatus.Running) {
state.status = state_1.ActivityStatus.Paused;
}
else {
state.status = state_1.ActivityStatus.Running;
}
(0, display_1.draw)(state);
}
exports.startActivity = startActivity;
function stopActivity(state) {
if (state.status === state_1.ActivityStatus.Paused) {
clearActivity(state);
}
if (state.status === state_1.ActivityStatus.Running) {
state.status = state_1.ActivityStatus.Paused;
}
else {
state.status = state_1.ActivityStatus.Stopped;
}
(0, display_1.draw)(state);
}
exports.stopActivity = stopActivity;
function clearActivity(state) {
state.duration = 0;
state.distance = 0;
state.speed = 0;
state.steps = 0;
state.cadence = 0;
}
exports.clearActivity = clearActivity;

View File

@ -1,41 +0,0 @@
import { draw } from './display';
import { initLog } from './log';
import { ActivityStatus, AppState } from './state';
function startActivity(state: AppState): void {
if (state.status === ActivityStatus.Stopped) {
initLog(state);
}
if (state.status === ActivityStatus.Running) {
state.status = ActivityStatus.Paused;
} else {
state.status = ActivityStatus.Running;
}
draw(state);
}
function stopActivity(state: AppState): void {
if (state.status === ActivityStatus.Paused) {
clearActivity(state);
}
if (state.status === ActivityStatus.Running) {
state.status = ActivityStatus.Paused;
} else {
state.status = ActivityStatus.Stopped;
}
draw(state);
}
function clearActivity(state: AppState): void {
state.duration = 0;
state.distance = 0;
state.speed = 0;
state.steps = 0;
state.cadence = 0;
}
export { clearActivity, startActivity, stopActivity };

View File

@ -1 +0,0 @@
require("heatshrink").decompress(atob("mEwwIHEuAEDgP8ApMDAqAXBjAGD/E8AgUcgF8CAX/BgIFBn//wAFCv//8PwAoP///5Aon/8AcB+IFB4AFB8P/34FBgfj/8fwAFB4f+g4cBg/H/w/Cg+HKQcPx4FEh4/CAoMfAocOj4/CKYRwELIIFDLII6BAoZSBLIYeCgP+v4FD/k/GAQFBHgcD/ABBIIX4gIFBSYPwAoUPAog/B8AFEwAFDDQQCBQoQFCZYYFigCKEgFwgAA=="))

View File

@ -1,15 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const activity_1 = require("./activity");
const display_1 = require("./display");
const gps_1 = require("./gps");
const hrm_1 = require("./hrm");
const state_1 = require("./state");
const step_1 = require("./step");
const appState = (0, state_1.initState)();
(0, gps_1.initGps)(appState);
(0, hrm_1.initHrm)(appState);
(0, step_1.initStep)(appState);
(0, display_1.initDisplay)(appState);
setWatch(() => (0, activity_1.startActivity)(appState), BTN1, { repeat: true, edge: 'falling' });
setWatch(() => (0, activity_1.stopActivity)(appState), BTN3, { repeat: true, edge: 'falling' });

View File

@ -1,20 +0,0 @@
import { startActivity, stopActivity } from './activity';
import { initDisplay } from './display';
import { initGps } from './gps';
import { initHrm } from './hrm';
import { initState } from './state';
import { initStep } from './step';
declare var BTN1: any;
declare var BTN3: any;
declare var setWatch: any;
const appState = initState();
initGps(appState);
initHrm(appState);
initStep(appState);
initDisplay(appState);
setWatch(() => startActivity(appState), BTN1, { repeat: true, edge: 'falling' });
setWatch(() => stopActivity(appState), BTN3, { repeat: true, edge: 'falling' });

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

View File

@ -1,106 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initDisplay = exports.formatTime = exports.formatPace = exports.formatDistance = exports.formatClock = exports.drawValue = exports.drawBackground = exports.drawAll = exports.draw = void 0;
const state_1 = require("./state");
const STATUS_COLORS = {
'STOP': 0xF800,
'PAUSE': 0xFFE0,
'RUN': 0x07E0,
};
function initDisplay(state) {
Bangle.loadWidgets();
Bangle.on('lcdPower', (on) => {
state.drawing = on;
if (on) {
drawAll(state);
}
});
drawAll(state);
}
exports.initDisplay = initDisplay;
function drawBackground() {
g.clear();
g.setColor(0xC618);
g.setFont('6x8', 2);
g.setFontAlign(0, -1, 0);
g.drawString('DIST (KM)', 60, 32);
g.drawString('TIME', 172, 32);
g.drawString('PACE', 60, 92);
g.drawString('HEART', 172, 92);
g.drawString('STEPS', 60, 152);
g.drawString('CADENCE', 172, 152);
}
exports.drawBackground = drawBackground;
function drawValue(value, x, y) {
g.setColor(0x0000);
g.fillRect(x - 60, y, x + 60, y + 30);
g.setColor(0xFFFF);
g.drawString(value, x, y);
}
exports.drawValue = drawValue;
function draw(state) {
g.setFontVector(30);
g.setFontAlign(0, -1, 0);
drawValue(formatDistance(state.distance), 60, 55);
drawValue(formatTime(state.duration), 172, 55);
drawValue(formatPace(state.speed), 60, 115);
drawValue(state.hr.toFixed(0), 172, 115);
drawValue(state.steps.toFixed(0), 60, 175);
drawValue(state.cadence.toFixed(0), 172, 175);
g.setFont('6x8', 2);
g.setColor(state.gpsValid ? 0x07E0 : 0xF800);
g.fillRect(0, 216, 80, 240);
g.setColor(0x0000);
g.drawString('GPS', 40, 220);
g.setColor(0xFFFF);
g.fillRect(80, 216, 160, 240);
g.setColor(0x0000);
g.drawString(formatClock(new Date()), 120, 220);
g.setColor(STATUS_COLORS[state.status]);
g.fillRect(160, 216, 230, 240);
g.setColor(0x0000);
g.drawString(state.status, 200, 220);
g.setFont("6x8").setFontAlign(0, 0, 1).setColor(-1);
if (state.status === state_1.ActivityStatus.Paused) {
g.drawString("START", 236, 60, 1).drawString(" CLEAR ", 236, 180, 1);
}
else if (state.status === state_1.ActivityStatus.Running) {
g.drawString(" PAUSE ", 236, 60, 1).drawString(" PAUSE ", 236, 180, 1);
}
else {
g.drawString("START", 236, 60, 1).drawString(" ", 236, 180, 1);
}
}
exports.draw = draw;
function drawAll(state) {
drawBackground();
draw(state);
Bangle.drawWidgets();
}
exports.drawAll = drawAll;
function formatClock(date) {
return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2);
}
exports.formatClock = formatClock;
function formatDistance(meters) {
return (meters / 1000).toFixed(2);
}
exports.formatDistance = formatDistance;
function formatPace(speed) {
if (speed < 0.1667) {
return `__'__"`;
}
const pace = Math.round(1000 / speed);
const min = Math.floor(pace / 60);
const sec = pace % 60;
return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`;
}
exports.formatPace = formatPace;
function formatTime(time) {
const seconds = Math.round(time);
const hrs = Math.floor(seconds / 3600);
const min = Math.floor(seconds / 60) % 60;
const sec = seconds % 60;
return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2);
}
exports.formatTime = formatTime;

View File

@ -1,123 +0,0 @@
import { ActivityStatus, AppState } from './state';
declare var Bangle: any;
declare var g: any;
const STATUS_COLORS = {
'STOP': 0xF800,
'PAUSE': 0xFFE0,
'RUN': 0x07E0,
}
function initDisplay(state: AppState): void {
Bangle.loadWidgets();
Bangle.on('lcdPower', (on: boolean) => {
state.drawing = on;
if (on) {
drawAll(state);
}
});
drawAll(state);
}
function drawBackground(): void {
g.clear();
g.setColor(0xC618);
g.setFont('6x8', 2);
g.setFontAlign(0, -1, 0);
g.drawString('DIST (KM)', 60, 32);
g.drawString('TIME', 172, 32);
g.drawString('PACE', 60, 92);
g.drawString('HEART', 172, 92);
g.drawString('STEPS', 60, 152);
g.drawString('CADENCE', 172, 152);
}
function drawValue(value: string, x: number, y: number) {
g.setColor(0x0000);
g.fillRect(x - 60, y, x + 60, y + 30);
g.setColor(0xFFFF);
g.drawString(value, x, y);
}
function draw(state: AppState): void {
g.setFontVector(30);
g.setFontAlign(0, -1, 0);
drawValue(formatDistance(state.distance), 60, 55);
drawValue(formatTime(state.duration), 172, 55);
drawValue(formatPace(state.speed), 60, 115);
drawValue(state.hr.toFixed(0), 172, 115);
drawValue(state.steps.toFixed(0), 60, 175);
drawValue(state.cadence.toFixed(0), 172, 175);
g.setFont('6x8', 2);
g.setColor(state.gpsValid ? 0x07E0 : 0xF800);
g.fillRect(0, 216, 80, 240);
g.setColor(0x0000);
g.drawString('GPS', 40, 220);
g.setColor(0xFFFF);
g.fillRect(80, 216, 160, 240);
g.setColor(0x0000);
g.drawString(formatClock(new Date()), 120, 220);
g.setColor(STATUS_COLORS[state.status]);
g.fillRect(160, 216, 230, 240);
g.setColor(0x0000);
g.drawString(state.status, 200, 220);
g.setFont("6x8").setFontAlign(0,0,1).setColor(-1);
if (state.status === ActivityStatus.Paused) {
g.drawString("START",236,60,1).drawString(" CLEAR ",236,180,1);
} else if (state.status === ActivityStatus.Running) {
g.drawString(" PAUSE ",236,60,1).drawString(" PAUSE ",236,180,1);
} else {
g.drawString("START",236,60,1).drawString(" ",236,180,1);
}
}
function drawAll(state: AppState) {
drawBackground();
draw(state);
Bangle.drawWidgets();
}
function formatClock(date: Date): string {
return ('0' + date.getHours()).substr(-2) + ':' + ('0' + date.getMinutes()).substr(-2);
}
function formatDistance(meters: number): string {
return (meters / 1000).toFixed(2);
}
function formatPace(speed: number): string {
if (speed < 0.1667) {
return `__'__"`;
}
const pace = Math.round(1000 / speed);
const min = Math.floor(pace / 60);
const sec = pace % 60;
return ('0' + min).substr(-2) + `'` + ('0' + sec).substr(-2) + `"`;
}
function formatTime(time: number): string {
const seconds = Math.round(time);
const hrs = Math.floor(seconds / 3600);
const min = Math.floor(seconds / 60) % 60;
const sec = seconds % 60;
return (hrs ? hrs + ':' : '') + ('0' + min).substr(-2) + `:` + ('0' + sec).substr(-2);
}
export {
draw,
drawAll,
drawBackground,
drawValue,
formatClock,
formatDistance,
formatPace,
formatTime,
initDisplay,
};

View File

@ -1,71 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateGps = exports.readGps = exports.initGps = void 0;
const display_1 = require("./display");
const log_1 = require("./log");
const state_1 = require("./state");
const EARTH_RADIUS = 6371008.8;
function initGps(state) {
Bangle.on('GPS', (gps) => readGps(state, gps));
Bangle.setGPSPower(1);
}
exports.initGps = initGps;
function readGps(state, gps) {
state.lat = gps.lat;
state.lon = gps.lon;
state.alt = gps.alt;
state.vel = gps.speed / 3.6;
state.fix = gps.fix;
state.dop = gps.hdop;
state.gpsValid = state.fix > 0;
updateGps(state);
(0, display_1.draw)(state);
/* Only log GPS data every 5 secs if we
have a fix and we're running. */
if (state.gpsValid &&
state.status === state_1.ActivityStatus.Running &&
state.timeSinceLog > 5) {
state.timeSinceLog = 0;
(0, log_1.updateLog)(state);
}
}
exports.readGps = readGps;
function updateGps(state) {
const t = Date.now();
let dt = (t - state.t) / 1000;
if (!isFinite(dt))
dt = 0;
state.t = t;
state.timeSinceLog += dt;
if (state.status === state_1.ActivityStatus.Running) {
state.duration += dt;
}
if (!state.gpsValid) {
return;
}
const r = EARTH_RADIUS + state.alt;
const lat = state.lat * Math.PI / 180;
const lon = state.lon * Math.PI / 180;
const x = r * Math.cos(lat) * Math.cos(lon);
const y = r * Math.cos(lat) * Math.sin(lon);
const z = r * Math.sin(lat);
if (!state.x) {
state.x = x;
state.y = y;
state.z = z;
return;
}
const dx = x - state.x;
const dy = y - state.y;
const dz = z - state.z;
const dpMag = Math.sqrt(dx * dx + dy * dy + dz * dz);
state.x = x;
state.y = y;
state.z = z;
if (state.status === state_1.ActivityStatus.Running) {
state.distance += dpMag;
state.speed = (state.distance / state.duration) || 0;
state.cadence = (60 * state.steps / state.duration) || 0;
}
}
exports.updateGps = updateGps;

View File

@ -1,90 +0,0 @@
import { draw } from './display';
import { updateLog } from './log';
import { ActivityStatus, AppState } from './state';
declare var Bangle: any;
interface GpsEvent {
lat: number;
lon: number;
alt: number;
speed: number;
hdop: number;
fix: number;
}
const EARTH_RADIUS = 6371008.8;
function initGps(state: AppState): void {
Bangle.on('GPS', (gps: GpsEvent) => readGps(state, gps));
Bangle.setGPSPower(1);
}
function readGps(state: AppState, gps: GpsEvent): void {
state.lat = gps.lat;
state.lon = gps.lon;
state.alt = gps.alt;
state.vel = gps.speed / 3.6;
state.fix = gps.fix;
state.dop = gps.hdop;
state.gpsValid = state.fix > 0;
updateGps(state);
draw(state);
/* Only log GPS data every 5 secs if we
have a fix and we're running. */
if (state.gpsValid &&
state.status === ActivityStatus.Running &&
state.timeSinceLog > 5) {
state.timeSinceLog = 0;
updateLog(state);
}
}
function updateGps(state: AppState): void {
const t = Date.now();
let dt = (t - state.t) / 1000;
if (!isFinite(dt)) dt=0;
state.t = t;
state.timeSinceLog += dt;
if (state.status === ActivityStatus.Running) {
state.duration += dt;
}
if (!state.gpsValid) {
return;
}
const r = EARTH_RADIUS + state.alt;
const lat = state.lat * Math.PI / 180;
const lon = state.lon * Math.PI / 180;
const x = r * Math.cos(lat) * Math.cos(lon);
const y = r * Math.cos(lat) * Math.sin(lon);
const z = r * Math.sin(lat);
if (!state.x) {
state.x = x;
state.y = y;
state.z = z;
return;
}
const dx = x - state.x;
const dy = y - state.y;
const dz = z - state.z;
const dpMag = Math.sqrt(dx * dx + dy * dy + dz * dz);
state.x = x;
state.y = y;
state.z = z;
if (state.status === ActivityStatus.Running) {
state.distance += dpMag;
state.speed = (state.distance / state.duration) || 0;
state.cadence = (60 * state.steps / state.duration) || 0;
}
}
export { initGps, readGps, updateGps };

View File

@ -1,19 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateHrm = exports.initHrm = void 0;
function initHrm(state) {
Bangle.on('HRM', (hrm) => updateHrm(state, hrm));
Bangle.setHRMPower(1);
}
exports.initHrm = initHrm;
function updateHrm(state, hrm) {
if (hrm.confidence === 0) {
return;
}
const dHr = hrm.bpm - state.hr;
const hrError = Math.abs(dHr) + 101 - hrm.confidence;
const hrGain = (state.hrError / (state.hrError + hrError)) || 0;
state.hr += dHr * hrGain;
state.hrError += (hrError - state.hrError) * hrGain;
}
exports.updateHrm = updateHrm;

View File

@ -1,29 +0,0 @@
import { AppState } from './state';
interface HrmData {
bpm: number;
confidence: number;
raw: string;
}
declare var Bangle: any;
function initHrm(state: AppState) {
Bangle.on('HRM', (hrm: HrmData) => updateHrm(state, hrm));
Bangle.setHRMPower(1);
}
function updateHrm(state: AppState, hrm: HrmData) {
if (hrm.confidence === 0) {
return;
}
const dHr = hrm.bpm - state.hr;
const hrError = Math.abs(dHr) + 101 - hrm.confidence;
const hrGain = (state.hrError / (state.hrError + hrError)) || 0;
state.hr += dHr * hrGain;
state.hrError += (hrError - state.hrError) * hrGain;
}
export { initHrm, updateHrm };

View File

@ -1,217 +0,0 @@
<html>
<head>
<link rel="stylesheet" href="../../css/spectre.min.css">
</head>
<body>
<div id="tracks"></div>
<script src="../../core/lib/interface.js"></script>
<script>
/* TODO: Calculate cadence from step count */
var domTracks = document.getElementById("tracks");
function saveKML(track,title) {
var kml = `<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
<Document>
<Schema id="schema">
<gx:SimpleArrayField name="heartrate" type="int">
<displayName>Heart Rate</displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="steps" type="int">
<displayName>Step Count</displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="distance" type="float">
<displayName>Distance</displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="cadence" type="int">
<displayName>Cadence</displayName>
</gx:SimpleArrayField>
</Schema>
<Folder>
<name>Tracks</name>
<Placemark>
<name>${title}</name>
<gx:Track>
${track.map(pt=>` <when>${pt.date.toISOString()}</when>\n`).join("")}
${track.map(pt=>` <gx:coord>${pt.lon} ${pt.lat} ${pt.alt}</gx:coord>\n`).join("")}
<ExtendedData>
<SchemaData schemaUrl="#schema">
<gx:SimpleArrayData name="heartrate">
${track.map(pt=>` <gx:value>${pt.heartrate}</gx:value>\n`).join("")}
</gx:SimpleArrayData>
<gx:SimpleArrayData name="steps">
${track.map(pt=>` <gx:value>${pt.steps}</gx:value>\n`).join("")}
</gx:SimpleArrayData>
<gx:SimpleArrayData name="distance">
${track.map(pt=>` <gx:value>${pt.distance}</gx:value>\n`).join("")}
</gx:SimpleArrayData>
</SchemaData>
</ExtendedData>
</gx:Track>
</Placemark>
</Folder>
</Document>
</kml>`;
var a = document.createElement("a"),
file = new Blob([kml], {type: "application/vnd.google-earth.kml+xml"});
var url = URL.createObjectURL(file);
a.href = url;
a.download = title+".kml";
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
function saveGPX(track, title) {
var gpx = `<?xml version="1.0" encoding="UTF-8"?>
<gpx creator="Bangle.js" version="1.1" xmlns="http://www.topografix.com/GPX/1/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3">
<metadata>
<time>${track[0].date.toISOString()}</time>
</metadata>
<trk>
<name>${title}</name>
<trkseg>`;
track.forEach(pt=>{
gpx += `
<trkpt lat="${pt.lat}" lon="${pt.lon}">
<ele>${pt.alt}</ele>
<time>${pt.date.toISOString()}</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:hr>${pt.heartrate}</gpxtpx:hr>
<gpxtpx:distance>${pt.distance}</gpxtpx:distance>
${/* <gpxtpx:cad>65</gpxtpx:cad> */""}
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>`;
});
gpx += `
</trkseg>
</trk>
</gpx>`;
var a = document.createElement("a"),
file = new Blob([gpx], {type: "application/gpx+xml"});
var url = URL.createObjectURL(file);
a.href = url;
a.download = title+".gpx";
document.body.appendChild(a);
a.click();
setTimeout(function() {
document.body.removeChild(a);
window.URL.revokeObjectURL(url);
}, 0);
}
function trackLineToObject(l, hasFileName) {
// "timestamp,latitude,longitude,altitude,duration,distance,heartrate,steps\n"
var t = l.trim().split(",");
var n = hasFileName ? 1 : 0;
var o = {
invalid : t.length < 8,
date : new Date(parseInt(t[n+0])),
lat : parseFloat(t[n+1]),
lon : parseFloat(t[n+2]),
alt : parseFloat(t[n+3]),
duration : parseFloat(t[n+4]),
distance : parseFloat(t[n+5]),
heartrate : parseInt(t[n+6]),
steps : parseInt(t[n+7]),
};
if (hasFileName)
o.filename = t[0];
return o;
}
function downloadTrack(trackid, callback) {
Util.showModal("Downloading Track...");
Util.readStorageFile(trackid, data=>{
Util.hideModal();
var trackLines = data.trim().split("\n");
trackLines.shift(); // remove first line, which is column header
// should be:
// "timestamp,latitude,longitude,altitude,duration,distance,heartrate,steps\n"
var track = trackLines.map(l=>trackLineToObject(l,false));
callback(track);
});
}
function getTrackList() {
Util.showModal("Loading Tracks...");
domTracks.innerHTML = "";
Puck.eval(`require("Storage").list(/banglerun_.*\\x01/).map(fn=>{fn=fn.slice(0,-1);var f=require("Storage").open(fn,"r");f.readLine();return fn+","+f.readLine()})`,trackLines=>{
var html = `<div class="container">
<div class="columns">\n`;
trackLines.forEach(l => {
var track = trackLineToObject(l, true /*has filename*/);
html += `
<div class="column col-12">
<div class="card-header">
<div class="card-title h5">Track ${track.filename}</div>
<div class="card-subtitle text-gray">${track.invalid ? "No Data":track.date.toString().substr(0,24)}</div>
</div>
${track.invalid?``:`<div class="card-image">
<iframe
width="100%"
height="250"
frameborder="0" style="border:0"
src="https://www.google.com/maps/embed/v1/place?key=AIzaSyBxTcwrrVOh2piz7EmIs1Xn4FsRxJWeVH4&q=${track.lat},${track.lon}&zoom=10" allowfullscreen>
</iframe>
</div>
<div class="card-body"></div>`}
<div class="card-footer">${track.invalid?``:`
<button class="btn btn-primary" trackid="${track.filename}" task="downloadkml">Download KML</button>
<button class="btn btn-primary" trackid="${track.filename}" task="downloadgpx">Download GPX</button>`}
<button class="btn btn-default" trackid="${track.filename}" task="delete">Delete</button>
</div>
</div>
`;
});
if (trackLines.length==0) {
html += `
<div class="column col-12">
<div class="card-header">
<div class="card-title h5">No tracks</div>
<div class="card-subtitle text-gray">No GPS tracks found</div>
</div>
</div>
`;
}
html += `
</div>
</div>`;
domTracks.innerHTML = html;
Util.hideModal();
var buttons = domTracks.querySelectorAll("button");
for (var i=0;i<buttons.length;i++) {
buttons[i].addEventListener("click",event => {
var button = event.currentTarget;
var trackid = button.getAttribute("trackid");
var task = button.getAttribute("task");
if (task=="delete") {
Util.showModal("Deleting Track...");
Util.eraseStorageFile(trackid,()=>{
Util.hideModal();
getTrackList();
});
}
if (task=="downloadkml") {
downloadTrack(trackid, track => saveKML(track, `Bangle.js Track ${trackid}`));
}
if (task=="downloadgpx") {
downloadTrack(trackid, track => saveGPX(track, `Bangle.js Track ${trackid}`));
}
});
}
})
}
function onInit() {
getTrackList();
}
</script>
</body>
</html>

View File

@ -1,37 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateLog = exports.initLog = void 0;
function initLog(state) {
const datetime = new Date().toISOString().replace(/[-:]/g, '');
const date = datetime.substr(2, 6);
const time = datetime.substr(9, 6);
const filename = `banglerun_${date}_${time}`;
return Object.assign(Object.assign({}, state), { file: require('Storage').open(filename, 'w'), fileWritten: false });
}
exports.initLog = initLog;
function updateLog(state) {
if (!state.fileWritten) {
state.file.write([
'timestamp',
'latitude',
'longitude',
'altitude',
'duration',
'distance',
'heartrate',
'steps',
].join(',') + '\n');
state.fileWritten = true;
}
state.file.write([
Date.now().toFixed(0),
state.lat.toFixed(6),
state.lon.toFixed(6),
state.alt.toFixed(2),
state.duration.toFixed(0),
state.distance.toFixed(2),
state.hr.toFixed(0),
state.steps.toFixed(0),
].join(',') + '\n');
}
exports.updateLog = updateLog;

View File

@ -1,47 +0,0 @@
import { AppState, AppStateWithLog } from './state';
declare var require: any;
function initLog(state: AppState): AppStateWithLog {
const datetime = new Date().toISOString().replace(/[-:]/g, '');
const date = datetime.substr(2, 6);
const time = datetime.substr(9, 6);
const filename = `banglerun_${date}_${time}`;
return {
...state,
file: require('Storage').open(filename, 'w'),
fileWritten: false,
} as AppStateWithLog;
}
function updateLog(state: AppStateWithLog): void {
if (!state.fileWritten) {
state.file.write(
[
'timestamp',
'latitude',
'longitude',
'altitude',
'duration',
'distance',
'heartrate',
'steps',
].join(',') + '\n'
);
state.fileWritten = true;
}
state.file.write(
[
Date.now().toFixed(0),
state.lat.toFixed(6),
state.lon.toFixed(6),
state.alt.toFixed(2),
state.duration.toFixed(0),
state.distance.toFixed(2),
state.hr.toFixed(0),
state.steps.toFixed(0),
].join(',') + '\n'
);
}
export { initLog, updateLog };

View File

@ -1,16 +0,0 @@
{
"id": "banglerun",
"name": "BangleRun",
"shortName": "BangleRun",
"version": "0.10",
"description": "An app for running sessions. Displays info and logs your run for later viewing.",
"icon": "banglerun.png",
"tags": "run,running,fitness,outdoors",
"supports": ["BANGLEJS"],
"interface": "interface.html",
"allow_emulator": false,
"storage": [
{"name":"banglerun.app.js","url":"app.js"},
{"name":"banglerun.img","url":"app-icon.js","evaluate":true}
]
}

View File

@ -1,37 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initState = exports.ActivityStatus = void 0;
var ActivityStatus;
(function (ActivityStatus) {
ActivityStatus["Stopped"] = "STOP";
ActivityStatus["Paused"] = "PAUSE";
ActivityStatus["Running"] = "RUN";
})(ActivityStatus || (ActivityStatus = {}));
exports.ActivityStatus = ActivityStatus;
function initState() {
return {
fix: NaN,
lat: NaN,
lon: NaN,
alt: NaN,
vel: NaN,
dop: NaN,
gpsValid: false,
x: NaN,
y: NaN,
z: NaN,
t: NaN,
timeSinceLog: 0,
hr: 60,
hrError: 100,
fileWritten: false,
drawing: false,
status: ActivityStatus.Stopped,
duration: 0,
distance: 0,
speed: 0,
steps: 0,
cadence: 0,
};
}
exports.initState = initState;

View File

@ -1,93 +0,0 @@
enum ActivityStatus {
Stopped = 'STOP',
Paused = 'PAUSE',
Running = 'RUN',
}
interface BasicAppState {
// GPS NMEA data
fix: number;
lat: number;
lon: number;
alt: number;
vel: number;
dop: number;
gpsValid: boolean;
// Absolute position data
x: number;
y: number;
z: number;
// Last fix time
t: number;
// Last time we saved log info
timeSinceLog : number;
// HRM data
hr: number,
hrError: number,
// Logger data
fileWritten: boolean;
// Drawing data
drawing: boolean;
// Activity data
duration: number;
distance: number;
speed: number;
steps: number;
cadence: number;
}
interface AppStateWithoutLog extends BasicAppState {
status: 'STOP';
}
interface AppStateWithLog extends BasicAppState {
file: File;
status: ActivityStatus;
}
type AppState = AppStateWithLog | AppStateWithoutLog;
interface File {
read: Function;
write: Function;
erase: Function;
}
function initState(): AppState {
return {
fix: NaN,
lat: NaN,
lon: NaN,
alt: NaN,
vel: NaN,
dop: NaN,
gpsValid: false,
x: NaN,
y: NaN,
z: NaN,
t: NaN,
timeSinceLog : 0,
hr: 60,
hrError: 100,
fileWritten: false,
drawing: false,
status: ActivityStatus.Stopped,
duration: 0,
distance: 0,
speed: 0,
steps: 0,
cadence: 0,
}
}
export { ActivityStatus, AppState, AppStateWithLog, File, initState };

View File

@ -1,14 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.updateStep = exports.initStep = void 0;
const state_1 = require("./state");
function initStep(state) {
Bangle.on('step', () => updateStep(state));
}
exports.initStep = initStep;
function updateStep(state) {
if (state.status === state_1.ActivityStatus.Running) {
state.steps += 1;
}
}
exports.updateStep = updateStep;

View File

@ -1,15 +0,0 @@
import { ActivityStatus, AppState } from './state';
declare var Bangle: any;
function initStep(state: AppState) {
Bangle.on('step', () => updateStep(state));
}
function updateStep(state: AppState) {
if (state.status === ActivityStatus.Running) {
state.steps += 1;
}
}
export { initStep, updateStep };