Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
MomentumV committed Feb 13, 2025
2 parents 9a19799 + 04cff3c commit f5cb050
Show file tree
Hide file tree
Showing 14 changed files with 1,149 additions and 71 deletions.
1 change: 1 addition & 0 deletions apps/calendar/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@
0.17: Load holidays before events so the latter is not overpainted
0.18: Minor code improvements
0.19: Read events synchronized from Gadgetbridge
0.20: Correct start time of all-day events synchronized from Gadgetbridge
8 changes: 5 additions & 3 deletions apps/calendar/calendar.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@ const loadEvents = () => {
}));
// all events synchronized from Gadgetbridge
events = events.concat((require("Storage").readJSON("android.calendar.json",1) || []).map(a => {
// timestamp is in seconds, Date requires milliseconds
const date = new Date(a.timestamp * 1000);
return {date: date, msg: a.title, type: "e"};
// All-day events always start at 00:00:00 UTC, so we need to "undo" the
// timezone offsetting to make sure that the day is correct.
const offset = a.allDay ? new Date().getTimezoneOffset() * 60 : 0
const date = new Date((a.timestamp+offset) * 1000);
return {date: date, msg: a.title, type: a.allDay ? "o" : "e"};
}));
};

Expand Down
2 changes: 1 addition & 1 deletion apps/calendar/metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "calendar",
"name": "Calendar",
"version": "0.19",
"version": "0.20",
"description": "Monthly calendar, displays holidays uploaded from the web interface and scheduled events.",
"icon": "calendar.png",
"screenshots": [{"url":"screenshot_calendar.png"}],
Expand Down
1 change: 1 addition & 0 deletions apps/gbmusic/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
0.11: Use default Bangle formatter for booleans
0.12: Issue newline before GB commands (solves issue with console.log and ignored commands)
0.13: Upgrade to new translation system
0.14: Fix auto-start saved state; fix clearing track number; allow widget clicks
73 changes: 14 additions & 59 deletions apps/gbmusic/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ function rScroller(l) {
const w = g.stringWidth(l.label)+40,
y = l.y+l.h/2;
l.offset = l.offset%w;
g.setClipRect(l.x, l.y, l.x+l.w-1, l.y+l.h-1)
.setColor(l.col).setBgColor(l.bgCol) // need to set colors: iScroll calls this function outside Layout
g.setColor(l.col).setBgColor(l.bgCol) // need to set colors: iScroll calls this function outside Layout
.setFontAlign(-1, 0) // left center
.clearRect(l.x, l.y, l.x+l.w-1, l.y+l.h-1)
.drawString(l.label, l.x-l.offset+40, y)
Expand Down Expand Up @@ -128,57 +127,8 @@ function rInfo(l) {
.setFontAlign(0, -1) // center top
.drawString(l.label, l.x+l.w/2, l.y);
}
/**
* Render icon
* @param l
*/
function rIcon(l) {
const x2 = l.x+l.w-1,
y2 = l.y+l.h-1;
switch(l.icon) {
case "pause": {
const w13 = l.w/3;
g.drawRect(l.x, l.y, l.x+w13, y2);
g.drawRect(l.x+l.w-w13, l.y, x2, y2);
break;
}
case "play": {
g.drawPoly([
l.x, l.y,
x2, l.y+l.h/2,
l.x, y2,
], true);
break;
}
case "previous": {
const w15 = l.w*1/5;
g.drawPoly([
x2, l.y,
l.x+w15, l.y+l.h/2,
x2, y2,
], true);
g.drawRect(l.x, l.y, l.x+w15, y2);
break;
}
case "next": {
const w45 = l.w*4/5;
g.drawPoly([
l.x, l.y,
l.x+w45, l.y+l.h/2,
l.x, y2,
], true);
g.drawRect(l.x+w45, l.y, x2, y2);
break;
}
default: { // red X
console.log(`Unknown icon: ${l.icon}`);
g.setColor("#f00")
.drawRect(l.x, l.y, x2, y2)
.drawLine(l.x, l.y, x2, y2)
.drawLine(l.x, y2, x2, l.y);
}
}
}


let layout;
function makeUI() {
Bangle.loadWidgets();
Expand Down Expand Up @@ -417,7 +367,7 @@ function handleButton2Press() {
let tCommand = {};
/**
* Send command and highlight corresponding control
* @param {string} command - "play"/"pause"/"next"/"previous"/"volumeup"/"volumedown"
* @param {"play"|"pause"|"playpause"|"next"|"previous"|"volumeup"|"volumedown"} command
*/
function sendCommand(command) {
Bluetooth.println("");
Expand All @@ -433,15 +383,21 @@ function sendCommand(command) {
drawControls();
}

function handleTouch(btn, pos) {
if (pos === undefined || pos.y >= Bangle.appRect.y) {
togglePlay();
}
}

function togglePlay() {
sendCommand(stat==="play" ? "pause" : "play");
sendCommand("playpause");
}

/**
* Setup touch+swipe for Bangle.js 1
*/
function touch1() {
Bangle.on("touch", togglePlay);
Bangle.on("touch", handleTouch);
Bangle.on("swipe", dir => {
sendCommand(dir===1 ? "previous" : "next");
});
Expand All @@ -450,7 +406,7 @@ function touch1() {
* Setup touch+swipe for Bangle.js 2
*/
function touch2() {
Bangle.on("touch", togglePlay);
Bangle.on("touch", handleTouch);
// swiping
let drag;
Bangle.on("drag", e => {
Expand Down Expand Up @@ -483,10 +439,9 @@ function startLCDWatch() {
Bangle.on("lcdPower", (on) => {
if (on) {
// redraw and resume scrolling
tick();
layout.render();
fadeOut();
if (offset.offset!==null) {
if (layout.title.offset!==null) { // Making an assumption about what offset.offset was supposed to be
if (!iScroll) {
iScroll = setInterval(scroll, 200);
}
Expand Down
15 changes: 8 additions & 7 deletions apps/gbmusic/boot.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
setTimeout( // make other boot code run first, so we override e.g. android.boot.js GB
() => {
const APP = global.__FILE__==="gbmusic.app.js",
const APP = globalThis.__FILE__==="gbmusic.app.js",
a = !!(require("Storage").readJSON("gbmusic.json", 1) || {}).autoStart;

let s, i; // state, info
Expand All @@ -10,7 +10,7 @@ setTimeout( // make other boot code run first, so we override e.g. android.boot.
* Only runs while other apps are loaded
*/
function check() {
if (s!=="play" || !i || !a || !Bangle.CLOCK) return; // only launch app if we know which song we are playing, and autoLoad is enabled
if ((!s || s.state!=="play") || !i || !a || !Bangle.CLOCK) return; // only launch app if we know which song we are playing, and autoLoad is enabled
delete (i.t);
// store info and launch music app
require("Storage").writeJSON("gbmusic.load.json", {
Expand All @@ -20,18 +20,19 @@ setTimeout( // make other boot code run first, so we override e.g. android.boot.
load("gbmusic.app.js");
}

global.GB = (_GB => e => {

globalThis.GB = (_GB => e => {
// we eat music events!
switch(e.t) {
case "musicinfo":
i = e;
return APP ? info(e) : check();
return APP ? globalThis.info(e) : check();
case "musicstate":
s = e.state;
return APP ? state(e) : check();
s = e;
return APP ? globalThis.state(e) : check();
default:
// pass on other events
if (_GB) setTimeout(_GB, 0, e);
}
})(global.GB);
})(globalThis.GB);
}, 1);
2 changes: 1 addition & 1 deletion apps/gbmusic/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "gbmusic",
"name": "Gadgetbridge Music Controls",
"shortName": "Music Controls",
"version": "0.13",
"version": "0.14",
"description": "Control the music on your Gadgetbridge-connected phone",
"icon": "icon.png",
"screenshots": [{"url":"screenshot_v1_d.png"},{"url":"screenshot_v1_l.png"},
Expand Down
56 changes: 56 additions & 0 deletions apps/pacer/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
## Pacer

![icon](app.png)

Run with a virtual partner at your chosen pace, and export the GPX data
from the Bangle.js App Store.

## Usage

Pacer starts up with a menu.

* **Recording** - whether to record the run
* **Units** - imperial or metric
* **Lap** - the multiple of a mile or kilometer to use for splits
* **Dark mode** - use black or white background
* **Eco battery** - display will turn off after 10 seconds
* **Eco storage** - only record GPS position every 10 seconds
* **Steps** - display step count or cadence
* **Pacer** - pace of virtual partner

On selecting **Start**, GPS position will be detected. A run cannot be
started without a GPS fix. The watch touchscreen is disabled while the
app is running.

The app will run on Bangle.js 1 and 2, although use on Bangle.js 2 is not
recommended due to poor GPS accuracy.

On a Bangle.js 1, the top button reverses the screen colours, the middle
button starts, pauses or resumes a run, and the bottom button ends the run.

On a Bangle.js 2, a short press of the button starts, pauses or resumes a
run, and a long press (over 0.5 seconds, but under 2!) ends the run. Note
that holding the button for 2 seconds will exit back to the default clock
app.

## Downloading

GPX tracks can be downloaded using the
[App Loader](https://banglejs.com/apps/?id=pacer). Connect the
Bangle.js and click on the Pacer app's disk icon to see the tracks
available for downloading.

## Tips

For best results, only start a run when the satellite signal strength bar is
green.

Use the [Assisted GPS Updater](https://banglejs.com/apps/#AGPS) to improve
the time taken to get a GPS fix.

## Bugs

The eco settings are unlikely to be useful.

GPS track smoothing is accomplished simply by reducing the frequency with
which readings are taken, depending on signal strength.
1 change: 1 addition & 0 deletions apps/pacer/app-icon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit f5cb050

Please sign in to comment.