Skip to content

Commit 21825d9

Browse files
authored
Merge pull request #3448 from slynchDev/master
Burn - Simple Calorie Counter
2 parents 13e2527 + 6cc24ef commit 21825d9

8 files changed

+298
-0
lines changed

apps/burn/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.prettierignore

apps/burn/ChangeLog

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
0.01: New App!
2+
0.02: Added README.md
3+
0.03: Icon update
4+
0.04: Icon Fix
5+
0.05: Misc cleanup for PR
6+
0.06: Implementing fixes from PR comments
7+
0.07: Bug fix

apps/burn/README.md

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Burn: Calorie Counter
2+
3+
Burn is a simple calorie counter application. It is based on the original Counter app and has been enhanced with additional features (I recommend using
4+
it with the "Digital Clock Widget", if you intend to keep it running).
5+
6+
## Features
7+
8+
- **Persistent counter**: The counter value is saved to flash, so it persists even when the app is closed or the device is restarted.
9+
- **Daily reset**: The counter resets each day, allowing you to track your calorie intake on a daily basis.
10+
- **Adjustable increment value**: You can adjust the increment value to suit your needs.
11+
12+
## Controls
13+
14+
### Bangle.js 1
15+
16+
- **BTN1**: Increase (or tap right)
17+
- **BTN3**: Decrease (or tap left)
18+
- **Press BTN2**: Change increment
19+
20+
### Bangle.js 2
21+
22+
- **Swipe up**: Increase
23+
- **Swipe down**: Decrease
24+
- **Press BTN**: Change increment
25+
26+
## How it Works
27+
28+
The counter value and the date are stored in a file named "kcal.txt". The counter value is read from the file when the app starts and written to the file whenever the counter value is updated.
29+
30+
The app uses the current date to determine whether to reset the counter. If the date has changed since the last time the counter was updated, the counter is reset to 0.

apps/burn/app-icon.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/burn/app-icon.png

1.7 KB
Loading

apps/burn/app-screenshot.png

13.6 KB
Loading

apps/burn/app.js

+243
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*
2+
* Burn: Calories Counter for Bangle.js (Espruino). Based on the original Counter app.
3+
* Features:
4+
* - Persistent counter: saved to a file.
5+
* - Daily reset: counter resets each day.
6+
* - Adjustable increment value.
7+
*
8+
* Bangle.js 1 Controls:
9+
* - BTN1: Increase (or tap right)
10+
* - BTN3: Decrease (or tap left)
11+
* - Press BTN2: Change increment
12+
*
13+
* Bangle.js 2 Controls:
14+
* - Swipe up: Increase
15+
* - Swipe down: Decrease
16+
* - Press BTN: Change increment
17+
*/
18+
19+
// File variable to handle file operations
20+
let file;
21+
22+
// Check if the hardware version is Bangle.js 2
23+
const BANGLEJS2 = process.env.HWVERSION == 2;
24+
25+
// Importing the Storage module for file operations
26+
const Storage = require("Storage");
27+
28+
// File path for the counter data
29+
const PATH = "kcal.txt";
30+
31+
// Function to get the current date as a string
32+
function dayString() {
33+
const date = new Date();
34+
// Month is 0-indexed, so we add 1 to get the correct month number
35+
return `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}`;
36+
}
37+
38+
// Counter object to keep track of the count and the date
39+
let counter = { count: 0, date: dayString() };
40+
41+
// Function to read the counter from the file
42+
function readCounterFromFile() {
43+
try {
44+
// Open the file in read mode
45+
file = Storage.open(PATH, "r");
46+
let line = file.readLine();
47+
48+
// If the file has content, parse it and update the counter
49+
if (line) {
50+
let splitLine = line.trim().split(",");
51+
counter = { count: parseInt(splitLine[0]), date: splitLine[1] };
52+
}
53+
} catch (err) {
54+
// If the file does not exist, the counter will remain 0
55+
}
56+
}
57+
58+
// Function to write the counter to the file
59+
function writeCounterToFile() {
60+
// Open the file in write mode
61+
file = Storage.open(PATH, "w");
62+
// Write the counter and date to the file
63+
file.write(counter.count.toString() + "," + counter.date + "\n");
64+
}
65+
66+
// Function to reset the counter
67+
function resetCounter() {
68+
// Reset the counter to 0 and update the date
69+
counter = { count: 0, date: dayString() };
70+
}
71+
72+
// Function to update the counter value
73+
function updateCounterValue(value) {
74+
// Update the counter with the new value, ensuring it's not less than 0
75+
counter = { count: Math.max(0, value), date: dayString() };
76+
}
77+
78+
// Function to update the counter
79+
function updateCounter(value) {
80+
// If the date has changed, reset the counter
81+
if (counter.date != dayString()) {
82+
resetCounter();
83+
} else {
84+
// Otherwise, update the counter value
85+
updateCounterValue(value);
86+
}
87+
88+
// Write the updated counter to the file
89+
writeCounterToFile();
90+
// Update the screen with the new counter value
91+
updateScreen();
92+
}
93+
94+
// Function to set a watch on a button to update the counter when pressed
95+
function counterButtonWatch(button, increment) {
96+
setWatch(
97+
() => {
98+
// If the button is for incrementing, or the counter is greater than 0, update the counter
99+
if (increment || counter.count > 0) {
100+
updateCounter(
101+
counter.count + (increment ? getInterval() : -getInterval())
102+
);
103+
// Update the screen with the new counter value
104+
updateScreen();
105+
}
106+
},
107+
button,
108+
{ repeat: true }
109+
);
110+
}
111+
112+
// Function to create interval functions
113+
const createIntervalFunctions = function () {
114+
// Array of intervals
115+
const intervals = [50, 100, 200, 10];
116+
// Current location in the intervals array
117+
let location = 0;
118+
119+
// Function to get the current interval
120+
const getInterval = function () {
121+
return intervals[location];
122+
};
123+
124+
// Function to rotate the increment
125+
const rotateIncrement = function () {
126+
// Update the location to the next index in the intervals array, wrapping around if necessary
127+
location = (location + 1) % intervals.length;
128+
// Update the screen with the new increment
129+
updateScreen();
130+
};
131+
132+
// Return the getInterval and rotateIncrement functions
133+
return { getInterval, rotateIncrement };
134+
};
135+
136+
// Create the interval functions
137+
const intervalFunctions = createIntervalFunctions();
138+
const getInterval = intervalFunctions.getInterval;
139+
const rotateIncrement = intervalFunctions.rotateIncrement;
140+
141+
// Function to update the screen
142+
function updateScreen() {
143+
// Clear the screen area for the counter
144+
g.clearRect(0, 50, 250, BANGLEJS2 ? 130 : 150)
145+
.setBgColor(g.theme.bg)
146+
.setColor(g.theme.fg)
147+
.setFont("Vector", 40)
148+
.setFontAlign(0, 0)
149+
// Draw the counter value
150+
.drawString(Math.floor(counter.count), g.getWidth() / 2, 100)
151+
.setFont("6x8")
152+
// Clear the screen area for the increment
153+
.clearRect(g.getWidth() / 2 - 50, 140, g.getWidth() / 2 + 50, 160)
154+
// Draw the increment value
155+
.drawString("Increment: " + getInterval(), g.getWidth() / 2, 150);
156+
157+
// If the hardware version is Bangle.js 1, draw the increment and decrement buttons
158+
if (!BANGLEJS2) {
159+
g.drawString("-", 45, 100).drawString("+", 185, 100);
160+
}
161+
}
162+
163+
// If the hardware version is Bangle.js 2, set up the drag handling and button watch
164+
165+
let drag;
166+
167+
if (BANGLEJS2) {
168+
// Set up drag handling
169+
Bangle.on("drag", (e) => {
170+
// If this is the start of a drag, record the initial coordinates
171+
if (!drag) {
172+
drag = { x: e.x, y: e.y };
173+
return;
174+
}
175+
176+
// If the button is still being pressed, ignore this event
177+
if (e.b) return;
178+
179+
// Calculate the change in x and y from the start of the drag
180+
const dx = e.x - drag.x;
181+
const dy = e.y - drag.y;
182+
// Reset the drag start coordinates
183+
drag = null;
184+
185+
// Determine if the drag is primarily horizontal or vertical
186+
const isHorizontalDrag = Math.abs(dx) > Math.abs(dy) + 10;
187+
const isVerticalDrag = Math.abs(dy) > Math.abs(dx) + 10;
188+
189+
// If the drag is primarily horizontal, ignore it
190+
if (isHorizontalDrag) {
191+
return;
192+
}
193+
194+
// If the drag is primarily vertical, update the counter
195+
if (isVerticalDrag) {
196+
// If the drag is downwards and the counter is greater than 0, decrease the counter
197+
if (dy > 0 && counter.count > 0) {
198+
updateCounter(counter.count - getInterval());
199+
} else if (dy < 0) {
200+
// If the drag is upwards, increase the counter
201+
updateCounter(counter.count + getInterval());
202+
}
203+
// Update the screen with the new counter value
204+
updateScreen();
205+
}
206+
});
207+
208+
// Set a watch on the button to rotate the increment when pressed
209+
setWatch(rotateIncrement, BTN1, { repeat: true });
210+
} else {
211+
// If the hardware version is Bangle.js 1, set up the button watches
212+
213+
// Set watch on button to increase the counter
214+
counterButtonWatch(BTN1, true);
215+
counterButtonWatch(BTN5, true); // screen tap
216+
// Set watch on button to decrease the counter
217+
counterButtonWatch(BTN3, false);
218+
counterButtonWatch(BTN4, false); // screen tap
219+
220+
// Set a watch on button to rotate the increment when pressed
221+
setWatch(
222+
() => {
223+
rotateIncrement();
224+
},
225+
BTN2,
226+
{ repeat: true }
227+
);
228+
}
229+
230+
// clear the screen
231+
g.clear();
232+
233+
// Set the background and foreground colors
234+
g.setBgColor(g.theme.bg).setColor(g.theme.fg);
235+
236+
// Load and draw the widgets
237+
Bangle.loadWidgets();
238+
Bangle.drawWidgets();
239+
240+
// Read the counter from the file
241+
readCounterFromFile();
242+
// Update the screen with the counter value
243+
updateScreen();

apps/burn/metadata.json

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"id": "burn",
3+
"name": "Burn",
4+
"version": "0.07",
5+
"description": "Simple Calorie Counter -- saves to flash and resets at midnight. I often keep mine running while the digital clock widget is at the top",
6+
"icon": "app-icon.png",
7+
"tags": "tool",
8+
"readme":"README.md",
9+
"supports": ["BANGLEJS", "BANGLEJS2"],
10+
"screenshots": [{"url":"app-screenshot.png"}],
11+
"allow_emulator": true,
12+
"storage": [
13+
{"name":"burn.app.js","url":"app.js"},
14+
{"name":"burn.img","url":"app-icon.js","evaluate":true}
15+
]
16+
}

0 commit comments

Comments
 (0)