Skip to content

Commit 4a30a8f

Browse files
author
thyttan
committed
slidertest: add app
1 parent 2afef7e commit 4a30a8f

File tree

12 files changed

+256
-0
lines changed

12 files changed

+256
-0
lines changed

apps/slidertest/ChangeLog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
0.01: New App!

apps/slidertest/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# Slider Test app
2+
3+
- 1: A volume slider that hides when not interacted with. It uses the incrementing mode.
4+
- 2: A hidden slider that increments a preview of a change to the
5+
backdrop color. When the user stops interacting with it the backdrop
6+
is updated.
7+
- 3: An always visible slider that controls the brightness level.
8+
- 4: A non-interactable progressbar that follows the position in a media
9+
track playing on a connected android device.
10+
11+
A square will blink when messages with music state arrives.
12+
13+
The app is started:
14+
15+
![s](screenshot-0.png)
16+
17+
The hidden volume slider on the left is draged:
18+
19+
![s](screenshot-1.png)
20+
21+
The colour slider in the middle is draged:
22+
23+
![s](screenshot-2.png)
24+
25+
The colour slider is released, redrawing with a new backgdrop:
26+
27+
![s](screenshot-3.png)
28+
29+
The rounded brightness slider on the right is draged:
30+
31+
![s](screenshot-4.png)
32+
33+
The progress bar at the bottom tracks a song on an android device.
34+
35+
![s](screenshot-5.png)
36+
37+
## Usage
38+
39+
## Features
40+
41+
Name the function
42+
43+
## Controls
44+
45+
Name the buttons and what they are used for
46+
47+
## Requests
48+
49+
Name who should be contacted for support/update requests
50+
51+
## Creator
52+
53+
[thyttan](https://github.com/thyttan)

apps/slidertest/app-icon.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
require("heatshrink").decompress(atob("mEwwJC/AH4A/AH4AgA=="))

apps/slidertest/app.js

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
{
2+
let setDevMode = ()=>{
3+
Bangle.setLCDTimeout(0); // Easier to read the screen while developing.
4+
Bangle.setLocked(false);
5+
Bangle.setLCDBrightness(0.6);
6+
Bangle.setLCDPower(true);
7+
};
8+
//setDevMode();
9+
10+
//// Drawing operations
11+
12+
Bangle.loadWidgets(); // So appRect takes widgets into account.
13+
let R = Bangle.appRect;
14+
15+
let backDropColor = [1,0,0];
16+
17+
let draw = (rect)=>{
18+
g.reset();
19+
if (rect) g.setClipRect(rect.x1, rect.y1, rect.x2, rect.y2);
20+
g.setColor(backDropColor[0],backDropColor[1],backDropColor[2]).fillRect(0,0,176,176);
21+
g.setColor(1,1,1).drawLine(xA, R.y, xA, yA).drawLine(xB, R.y, xB, yA);
22+
g.reset();
23+
Bangle.drawWidgets();
24+
};
25+
26+
let blink = ()=>{setTimeout(()=>{
27+
g.reset().setColor(backDropColor[1],backDropColor[0],backDropColor[2]).fillRect(R.x2/2-15,R.y2-29,R.x2/2-5,R.y2-19);
28+
setTimeout(()=>{g.reset().setColor(backDropColor[0],backDropColor[1],backDropColor[2]).fillRect(R.x2/2-15,R.y2-29,R.x2/2-5,R.y2-19);},100);
29+
},0);
30+
};
31+
32+
//// Functional logic
33+
34+
// Get audio levels from Android device
35+
let audioLevels = {u:30, c:15}; // Init with values to avoid "Uncaught Error: Cannot read property 'u' of undefined" if values were not gathered from Gadgetbridge.
36+
let audioHandler = (e)=>{audioLevels = e;print(audioLevels);};
37+
Bangle.on('audio', audioHandler);
38+
Bangle.musicControl("vg"); // vg = Volume Get level
39+
40+
// Handle music messages
41+
// Bangle.emit("message", type, msg);
42+
let trackPosition = 0;
43+
let trackDur = 30;
44+
let trackState = "pause";
45+
let messageHandler = (type, msg)=>{
46+
print("\n","type:"+type, "t:"+msg.t, "src:"+msg.src, "mode:"+msg.state, "pos:"+msg.position, "dur:"+msg.dur);
47+
if (type==='music' && msg.src=="musicstate") {
48+
trackState = msg.state;
49+
trackPosition = msg.position + (trackState==="play"?1:0); // +1 when playing to account for latency.
50+
trackDur = msg.dur;
51+
if (progressBar) {
52+
progressBar.f.stopAutoUpdate();
53+
initProgressBar();
54+
}
55+
blink(); // Indicate when a `musicstate` message arrived.
56+
}
57+
};
58+
Bangle.on('message', messageHandler);
59+
60+
// cbVolumeSlider is used with volumeSlider
61+
let cbVolumeSlider = (mode,fb)=>{
62+
if (mode =="incr") Bangle.musicControl(fb>0?"volumedown":"volumeup");
63+
if (mode =="remove") {
64+
audioLevels.c = fb;
65+
ebLast = 0;
66+
draw(volumeSlider.c.r);
67+
//progressBar.f.draw(progressBar.v.level);
68+
print(process.memory().usage);
69+
print("#drag handlers: " + Bangle["#ondrag"].length);
70+
}
71+
};
72+
73+
// cbColorSlider is used with progressBar
74+
let cbColorSlider = (mode,fb)=>{
75+
if (mode =="incr") {
76+
let l = colorSlider.v.level;
77+
print("color mode: " + l);
78+
if (l===0) backDropColor = [1,0,0];
79+
if (l===1) backDropColor = [0.75,0.25,0];
80+
if (l===2) backDropColor = [0.5,0.5,0];
81+
if (l===3) backDropColor = [0.25,0.75,0];
82+
if (l===4) backDropColor = [0,1,0];
83+
if (l===5) backDropColor = [0,0.75,0.25];
84+
if (l===6) backDropColor = [0,0.5,0.5];
85+
if (l===7) backDropColor = [0,0.25,0.75];
86+
if (l===8) backDropColor = [0,0,1];
87+
g.setColor(backDropColor[0],backDropColor[1],backDropColor[2]).fillRect(xA+1,R.y,xB-1,yA);
88+
}
89+
if (mode =="remove") {
90+
init();
91+
}
92+
};
93+
94+
// cbBrightnessSlider is used with progressBar
95+
let cbBrightnessSlider = (mode,fb)=>{
96+
if (mode =="map") Bangle.setLCDBrightness(fb/100);
97+
if (mode =="remove") {
98+
99+
}
100+
};
101+
102+
// cbProgressbar is used with progressBar
103+
let cbProgressbar = (mode,fb)=>{
104+
currentLevel = fb;
105+
//print(process.memory().usage);
106+
//print("#drag handlers: " + Bangle["#ondrag"].length)
107+
};
108+
109+
// For use when dividing the parts of the screen for different sliders.
110+
let xA = R.x+4*R.w/8;
111+
let xB = R.x+11*R.w/16;
112+
let yA = R.x2-Math.round(R.w/20)-5;
113+
114+
// volumeSlider controls volume level on the android device.
115+
let volumeSlider=require("Slider").create(
116+
cbVolumeSlider,
117+
{mode:"incr", steps:audioLevels.u, initLevel:audioLevels.c, horizontal:false, rounded:false, height:R.h-21, timeout:0.5, propagateDrag:true, xStart:R.x+4, dragRect:{x:R.x, y:0, x2:xA-1, y2: R.y2}}
118+
);
119+
120+
// colorSlider controls the background color of this app. It uses custom graphics defined in its callback function.
121+
let colorSlider = require("Slider").create(
122+
cbColorSlider,
123+
{mode:"incr", steps:8, drawableSlider:false, xStart: R.x2-2*R.w/4, height:R.h-21, initLevel:0, propagateDrag:true, timeout:0, dragRect:{x:xA, y:0, x2:xB-1, y2: R.y2}}
124+
);
125+
126+
// brightnessSlider controls the brightness of the Bangle.js
127+
let brightnessSlider = require("Slider").create(
128+
cbBrightnessSlider,
129+
{mode:"map", steps:100, height:R.h-21, timeout:0, initLevel:100*0.0, propagateDrag:true, dragRect:{x:xB, y:0, x2:R.x2, y2: R.y2}, rounded:true}
130+
);
131+
132+
// progressBar follows the media track playing on the android device.
133+
let progressBar;
134+
let initProgressBar = ()=>{
135+
progressBar = require("Slider").create(
136+
cbProgressbar,
137+
{dragableSlider:false, steps:trackDur, initLevel:trackPosition, horizontal:true, rounded:false, timeout:0, immediateDraw:false, propagateDrag:true, width:Math.round(R.w/20), xStart:R.x2-R.w/20-4, oversizeR:10, oversizeL:10, autoProgress:true, yStart: R.x+4, height: R.w-8}
138+
);
139+
progressBar.f.draw(progressBar.v.level);
140+
if (trackState==="play") progressBar.f.startAutoUpdate();
141+
};
142+
143+
let init = ()=> {
144+
draw();
145+
if (progressBar) {
146+
progressBar.f.draw(progressBar.v.level);
147+
} else {initProgressBar();}
148+
brightnessSlider.f.draw(brightnessSlider.v.level);
149+
};
150+
151+
let isAnySliderDragActive = ()=>{
152+
return (volumeSlider.v.dragActive || brightnessSlider.v.dragActive || colorSlider.v.dragActive || progressBar.v.dragActive);
153+
};
154+
155+
let ebLast = 0; // Used for fix/Hack needed because there is a timeout before the slider is called upon.
156+
Bangle.on('drag', (e)=>{
157+
if (ebLast==0) {
158+
// if (!isAnySliderDragActive()) {
159+
if (e.y<yA) {
160+
if (e.x<xA && !volumeSlider.v.dragActive) {
161+
Bangle.musicControl("vg"); // vg = Volume Get level
162+
setTimeout(()=>{ // Timeout so gadgetbridge has time to send back volume levels.
163+
volumeSlider.c.steps=audioLevels.u;
164+
volumeSlider.v.level=audioLevels.c;
165+
},200);
166+
Bangle.prependListener('drag', volumeSlider.f.dragSlider);
167+
}
168+
if (e.x>=xA && e.x<xB && !colorSlider.v.dragActive) {
169+
Bangle.prependListener('drag', colorSlider.f.dragSlider);
170+
}
171+
if (e.x>=xB && !brightnessSlider.v.dragActive) {
172+
Bangle.prependListener('drag', brightnessSlider.f.dragSlider);
173+
}
174+
}
175+
if (e.y>=yA) {
176+
progressBar.f.dragSlider&&Bangle.prependListener('drag',progressBar.f.dragSlider);
177+
}
178+
// }
179+
}
180+
ebLast = e.b;
181+
});
182+
183+
init();
184+
185+
//print("#drag handlers: " + Bangle["#ondrag"].length)
186+
}

apps/slidertest/app.png

1.58 KB
Loading

apps/slidertest/metadata.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{ "id": "slidertest",
2+
"name": "Slider test app",
3+
"shortName":"Slider test",
4+
"version":"0.01",
5+
"description": "A detailed description of my great app",
6+
"icon": "app.png",
7+
"tags": "ui",
8+
"supports": ["BANGLEJS2"],
9+
"readme": "README.md",
10+
"storage": [
11+
{"name":"slidertest.img","url":"app-icon.js","evaluate":"true"},
12+
{"name":"slidertest.app.js","url":"app.js"}
13+
]
14+
}
15+

apps/slidertest/screenshot-0.png

2.8 KB
Loading

apps/slidertest/screenshot-1.png

3.19 KB
Loading

apps/slidertest/screenshot-2.png

2.77 KB
Loading

apps/slidertest/screenshot-3.png

2.75 KB
Loading

0 commit comments

Comments
 (0)