Skip to content

Commit 14e5cd9

Browse files
committed
Add loading animation app (fix #4089)
1 parent 45deeb0 commit 14e5cd9

File tree

9 files changed

+219
-0
lines changed

9 files changed

+219
-0
lines changed

apps/loadanim/ChangeLog

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

apps/loadanim/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Loading Animations
2+
3+
This app adds an animation that happens while Bangle.js is loading an app. It requires 2v29+ (or 2v28 cutting edge) firmware to work.
4+
5+
**Note:** loading time will be slightly negatively impacted because of the extra time
6+
taken to update the screen during the animation, but it's not likely to be more than 20% worse.
7+
8+
## Usage
9+
10+
Once installed, any app you load that doesn't 'fast load' will cause the loading animation to be displayed. For instance swapping
11+
between the clock and launcher may not put up the loading screen, but loading an app from the launcher will.
12+
13+
To change the animation, go to `Settings -> Apps -> Load Anim`. There, you can tap on the `Anim` option
14+
and can choose from different animations. Tap on one to view it, and answer `Yes` to the prompt if you wish
15+
to use it.
16+
17+
## Creator
18+
19+
Gordon Williams (@gfwilliams)

apps/loadanim/_progress_img.png

4.59 KB
Loading

apps/loadanim/app.png

772 Bytes
Loading

apps/loadanim/boot.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
let timer;try {timer=require("timer");}catch{print("loadscr: need FW 2v29+");}if(timer){
3+
let o = Graphics.createArrayBuffer(g.getWidth(),g.getHeight(),1);
4+
let n = 10, gl = g;
5+
o.transparent = 1;
6+
o.palette = new Uint16Array(2);//all black
7+
o.fillCircle(88,88,n);
8+
Bangle.setLCDOverlay(o,0,0,{id:"loadanim"});
9+
gl.clear(1).flip(1);
10+
let id = timer.add({
11+
type:"EXEC", fn: () => { "ram";
12+
n+=10;
13+
if (n>170) done();
14+
else {
15+
o.fillCircle(88,88,n);
16+
gl.flip(1);
17+
}
18+
},
19+
time:100,
20+
interval:100,
21+
});
22+
let done = function() {
23+
if (id===undefined) return;
24+
require("timer").remove(id);
25+
id = undefined;
26+
Bangle.setLCDOverlay(undefined, {id: "loadanim"});
27+
};
28+
setTimeout(done, 0);
29+
}
30+
}

apps/loadanim/metadata.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{ "id": "loadanim",
2+
"name": "Loading Animations",
3+
"shortName":"Load Anim",
4+
"version":"0.01",
5+
"author": "gfwilliams",
6+
"description": "Add an animation that happens while Bangle.js is loading an app. Requires 2v29+ (or 2v28 cutting edge) firmware to work.",
7+
"icon": "app.png",
8+
"screenshots" : [ { "url":"screenshot.png" } ],
9+
"type": "settings",
10+
"tags": "loading,animate,anim,load,progress",
11+
"supports" : ["BANGLEJS2"],
12+
"readme": "README.md",
13+
"storage": [
14+
{"name":"loadanim.0.boot.js","url":"boot.js"},
15+
{"name":"loadanim.settings.js","url":"settings.js"}
16+
],
17+
"data": [
18+
{"name":"loadanim.json"},
19+
{"name":".loading"}
20+
]
21+
}

apps/loadanim/screenshot.png

1.85 KB
Loading

apps/loadanim/settings.js

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
(function(back) {
2+
const SETTINGS_FILE = "loadanim.json";
3+
const storage = require('Storage');
4+
let timer;
5+
try { timer = require("timer"); } catch {
6+
E.showAlert("Needs FW 2v29 or later","Load Anim").then(back);
7+
return;
8+
}
9+
let settings = Object.assign({ anim:0 }, storage.readJSON(SETTINGS_FILE, 1)||{});
10+
const ANIM = [
11+
{
12+
name : "Circle",
13+
code : function() {
14+
let o = Graphics.createArrayBuffer(g.getWidth(),g.getHeight(),1);
15+
let n = 10, gl = g;
16+
o.transparent = 1;
17+
o.palette = new Uint16Array(2);//all black
18+
o.fillCircle(88,88,n);
19+
Bangle.setLCDOverlay(o,0,0,{id:"loadanim"});
20+
gl.clear(1).flip(1);
21+
let id = timer.add({
22+
type:"EXEC", fn: () => { "ram";
23+
n+=10;
24+
if (n>170) done();
25+
else {
26+
o.fillCircle(88,88,n);
27+
gl.flip(1);
28+
}
29+
},
30+
time:100,
31+
interval:100,
32+
});
33+
let done = function() {
34+
if (id===undefined) return;
35+
require("timer").remove(id);
36+
id = undefined;
37+
Bangle.setLCDOverlay(undefined, {id: "loadanim"});
38+
};
39+
setTimeout(done, 0);
40+
}
41+
},
42+
{
43+
name : "Slide Left",
44+
code : function() {
45+
let o = g.asImage();
46+
g.clear();
47+
let n = 10, gl = g;
48+
Bangle.setLCDOverlay(o,n,0,{id:"loadanim"});
49+
gl.flip(1);
50+
let id = timer.add({
51+
type:"EXEC", fn: () => {"ram";
52+
n+=10;
53+
if (n>170) done();
54+
else {
55+
Bangle.setLCDOverlay(o,n,0,{id:"loadanim"});
56+
gl.flip(1);
57+
}
58+
},
59+
time:100,
60+
interval:100,
61+
});
62+
let done = function() {
63+
if (id===undefined) return;
64+
require("timer").remove(id);
65+
id = undefined;
66+
Bangle.setLCDOverlay(undefined, {id: "loadanim"});
67+
};
68+
setTimeout(done, 0);
69+
}
70+
},
71+
{
72+
name : "Progress",
73+
code : function() {
74+
let o = Graphics.createArrayBuffer(120,30,1);
75+
let n = 10, gl = g;
76+
o.drawRect(2,2,117,27).drawRect(3,3,116,26);
77+
o.fillRect(7,7,7+n,22);
78+
Bangle.setLCDOverlay(o,28,96,{id:"loadanim"});
79+
gl.flip(1);
80+
let id = timer.add({
81+
type:"EXEC", fn: () => { "ram";
82+
if (n>=105)return;
83+
n+=5;
84+
o.fillRect(7,7,7+n,22);
85+
gl.flip(1);
86+
},
87+
time:100,
88+
interval:100,
89+
});
90+
let done = function() {
91+
if (id===undefined) return;
92+
require("timer").remove(id);
93+
id = undefined;
94+
Bangle.setLCDOverlay(undefined, {id: "loadanim"});
95+
};
96+
setTimeout(done, 0);
97+
}, // 'loading' is an image that the OS displays as soon as it restarts
98+
loading : atob("gFiCAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVQAFVVVVVVVVQAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVUAAFVVVVVVVUAAAFVVVVVVVVVVVVVVVVVVVVVVVVVVVAAAFVVVVVVVAAAAFVVUAAVVVVVVVVVVVVVVVVVVVVVUAAAVVVVVVVUAAAAVVVAAAVVVVVVVVVVVVVVVVVVVVVQDwBUAAEAAEADzwAAEAAAAVVVVVVVVVVVVVVVVVVVVVAPAFAAAAAAAAPPAAAAAAABVVVVVVVVVVVVVVVVVVVVUA8AQAAAAAAAA88AAAAA/AFVVVVVVVVVVVVVVVVVVVVQDwAAAAAAAAADwAAAAAPwAVVVVVVVVVVVVVVVVVVVVVAPAAA/wA/wA/PAPPwA/8ABVVVVVVVVVVVVVVVVVVVVUA8AAP/wP/wP/88//wP/8AFVVVVVVVVVVVVVVVVVVVVQDwAD8Pz8Pz8Pzz8Pz8D8AVVVVVVVVVVVVVVVVVVVVVAPAAPAPAAPPAPPPAPPADwBVVVVVVVVVVVVVVVVVVVVUA8AA8A8AA88A888A88APAFVVVVVVVVVVVVVVVVVVVVQDwADwDwP/zwDzzwDz8D8AVVVVVVVVVVVVVVVVVVVVVAPAAPAPD//PAPPPAPP//ABVVVVVVVVVVVVVVVVVVVVUA8AA8A8/A88A888A8P/wAAABVVVVVVVVVVVVVVVVVVQDwADwDzwDzwDzzwDw8AAAAABVVVVVVVVVVVVVVVVVVAPAAPAPPAPPAPPPAPDwAAAAABVVVVVVVVVVVVVVVVVUA8AA8A88A88A888A8D/wAAAAFVVVVVVVVVVVVVVVVVQDwAD8Pz8Pz8PzzwDw//w888AVVVVVVVVVVVVVVVVVVAP//D/8D//D//PPAPPwPzzzwBVVVVVVVVVVVVVVVVVUA//8D/AD88D8888A88APPPPAFVVVVVVVVVVVVVVVVVQAAAAAAAAAAAAAAAADwA8AAAAVVVVVVVVVVVVVVVVVVAAAAAAAAAAAAAAAAAPwPwAAABVVVVVVVVVVVVVVVVVUAAAAAAAAAAAAAAAAAP/8AAAAFVVVVVVVVVVVVVVVVVQAAAAAAAAAAAAAAAAAP/AAAAAVVVVVVVVVVVVVVVVVVAAAAAAAAAAAAAAAAAAAAAAAABVVVVVVVVVVVVVVVVVUAAAAAAAAAAAAAAAAAAAAAAAAFVVVVVVVVVVVVVVVVVQAAAAAAAAAAAAAAAAAAAAAAAAVVVVVVVVVVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVAP//////////////////////////////////////AFUA//////////////////////////////////////8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAPAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAPAFUA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA8AVQDwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADwBVAP//////////////////////////////////////AFUA//////////////////////////////////////8AVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV")
99+
}
100+
];
101+
102+
function save() {
103+
storage.write(SETTINGS_FILE, settings);
104+
}
105+
function saveBootAnim() {
106+
let a = ANIM[settings.anim];
107+
storage.write("loadanim.0.boot.js", `{let timer;try{timer=require("timer");}catch{print("loadscr: need FW 2v29+");}if(timer){${a.code["\xffcod"]}}}`);
108+
if (a.loading) storage.write(".loading", a.loading);
109+
else storage.erase(".loading");
110+
}
111+
function showAnimChooser() {
112+
let menu = { '': { 'title': 'Choose Anim', back:() => showMainMenu() } };
113+
ANIM.forEach((a,idx) => {
114+
menu[a.name] = function() {
115+
setTimeout(function() {
116+
if (a.loading)
117+
g.drawImage(a.loading,g.getWidth()/2,g.getHeight()/2,{rotate:0/*center*/});
118+
a.code();
119+
let t=getTime()+0.5;while(getTime()<t);
120+
E.showPrompt("Choose this?",{title:a.name,back:showAnimChooser}).then(ok => {
121+
print(ok);
122+
if (ok) {
123+
settings.anim = idx;
124+
saveBootAnim();
125+
save();
126+
showMainMenu();
127+
} else showAnimChooser();
128+
});
129+
Bangle.drawWidgets();
130+
t=getTime()+0.5;while(getTime()<t);
131+
},10);
132+
};
133+
});
134+
E.showMenu(menu);
135+
}
136+
function showMainMenu() {
137+
E.showMenu({
138+
'': { 'title': 'Load Anim' },
139+
/*LANG*/'< Back': back,
140+
/*LANG*/'Anim': {
141+
value: ANIM[settings.anim].name,
142+
onchange: () => showAnimChooser()
143+
},
144+
});
145+
}
146+
showMainMenu();
147+
})

bin/sanitycheck.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ var KNOWN_ERRORS = [
113113
var KNOWN_WARNINGS = [
114114
"App gpsrec data file wildcard .gpsrc? does not include app ID",
115115
"App owmweather data file weather.json is also listed as data file for app weather",
116+
"App loadanim data file .loading is also listed as data file for app loadingscreen",
116117
"App carcrazy has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"carcrazy.settings.json\"}]`)",
117118
"App loadingscreen has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"loadingscreen.settings.json\"}]`)",
118119
"App trex has a setting file but no corresponding data entry (add `\"data\":[{\"name\":\"trex.settings.json\"}]`)",

0 commit comments

Comments
 (0)