-
• #52
I get this after I install widgetupdate on a fresh install:
>OK OK OK Uncaught Error: Cannot read property 'filter' of undefined at line 1 col 112 in messages.wid.js msgs.filter(msg=>msg.new&&msg.id!="music").map(m=>m.src).filter((m... ^ in function "filterMessages" called from line 1 col 1371 in messages.wid.js ...msgs=filterMessages(rawMsgs);this.width=24*E.clip(this.msgs.length... ^ in function "update" called from line 16 col 329 in .boot0 ...ETS[i];if(w.update)w.update();}} ^ in function "updateWidgets" called from line 16 col 1049 in .boot0 ...};});}Bangle.updateWidgets();if(!WIDGETS_LOADED)WIDGETS_LOADE... ^ in function "o" called from line 35 col 29 in .boot0 o();const s=require("Storage").readJSON("wid_edit.json",1)||{};const c=... ^ in function "loadWidgets" called from line 3 col 7789 in antonclk.app.js ...all;}});Bangle.loadWidgets();Bangle.drawWidgets();} ^ > Uncaught Error: Cannot read property 'filter' of undefined at line 1 col 112 in messages.wid.js msgs.filter(msg=>msg.new&&msg.id!="music").map(m=>m.src).filter((m... ^ in function "filterMessages" called from line 1 col 1371 in messages.wid.js ...msgs=filterMessages(rawMsgs);this.width=24*E.clip(this.msgs.length... ^ in function "update" called from line 16 col 329 in .boot0 ...ETS[i];if(w.update)w.update();}} ^ in function "updateWidgets" called from line 16 col 1049 in .boot0 ...};});}Bangle.updateWidgets();if(!WIDGETS_LOADED)WIDGETS_LOADE... ^ in function "o" called from line 35 col 29 in .boot0 o();const s=require("Storage").readJSON("wid_edit.json",1)||{};const c=... ^ in function "loadWidgets" called from line 1 col 157 in iconlaunch.app.js ...screen){Bangle.loadWidgets();Bangle.drawWidgets();}let launchCa... ^ >
Step-by-step:
- Factory reset watch via web IDE
- Install favorite apps, among them Icon Launcher, Anton Clock and Fastload helper.
- Install widgetupdate.
- Long press physical button to reset after loading apps.
- On Anton Clock no widgets are drawn.
- Press physical button go to launcher.
- Stuck on "Fastloading..."
- Factory reset watch via web IDE
-
• #53
That's not because of
wid_edit
, it's themessages
widget: it already had anupdate
method which expects an incoming message as argument.Actually, I think I'd like to rewrite the
messages
library/app/widget some more, so it just passes everything throughBangle.emit("message", type, message);
, instead of directly calling widget methods or global functions. -
• #54
Ok! EDIT: But I don't seem to get the error if I don't install widgetupdate.
EDIT2: Another thing I'm noticing now is "Exit to launcher"-widget and "Light switch widget" will sit in the same postition, overlapping each other depending on which of them had the latest draw.
-
• #55
I get about 3-5 calls to
drawWidgets
with around 100ms each. So the bangle is computing, drawing and using power for 400ms on average while not doing anything useful on each clock<->launcher transition.Since the main use of the update method is prevention of additional calls to
drawWidgets
, how about something like the following duringdrawWidgets
:let origDraw = Bangle.drawWidgets; let drawCount = 0; Bangle.drawWidgets = ()=>{drawCount++;}; for (wd of WIDGETS) wd.draw(wd); Bangle.drawWidgets = origDraw; if (drawCount > 0) setTimeout(Bangle.drawWidgets,0);
That would reduce drawing the widgets to one additional time after every change for width/area has been done. Still one call more than needed when using update methods, but less overhead on memory and code size.
appRect
could be updated there as well to keep it dynamic.The wrapping of
draw
to check if widgets are currently hidden could be replaced by just settingdraw = ()=>{}
and restoring that on showing the widgets. Actually thewidget_utils
module could now be used there. That would probably remove the need for my some of myBangle.*Widgets
-methods altogether. -
• #56
I reverted all changes to message, should have kept that one commit... Its now back ;)
I have also seen some problems with overlapping widgets, there are some bugs in the update methods of widgets, will fix that. Or remove the update methods completely, should also fix this :)
-
• #57
Sorry, I mixed up wid_edit and widgetupdate... So I should have said widgetupdate and not wid_edit... I will update #52
EDIT: Updated and now Fastload helper+widgetupdate+messages from your app loader plays nice for me, @halemmerich. wid_edit seemed to work as well.
-
• #58
Just a note that because I got a complaint about widclose/etc (https://github.com/espruino/BangleApps/commit/f6b38b34437572498b9ab8403dc333164b0b193a#r88164680) I put some fixes in now that just use drawWidgets for now, just to get it working properly again.
If you're getting 3-5 calls for drawWidgets, it'd be good to find out where they are all coming from.
Perhaps we should consider making drawWidgets actually only queue up a redraw, so if it gets called >1 time before we next idle there is only ever one full redraw?
-
• #59
Just tried with:
Bangle.drawWidgets = (dw => { return function() { var t=getTime();dw();print(getTime()-t); } })(Bangle.drawWidgets);
And
widclk
installed, and when swapping between the normal launcher and anton clock I see only two calls todrawWidgets
taking 50ms each, so I think right now the most recent changes are probably 'good enough'. -
• #60
Perhaps we should consider making drawWidgets actually only queue up a redraw, so if it gets called >1 time before we next idle there is only ever one full redraw?
One call will not be enough when at least one widget changes it's width during draw. But we can do with one or two draws, first draw executed instantly and then capture all other
drawWidgets
and queue one for next idle. I have tried it and it works fine.The changes to the 4 widgets are working well, I could remove about half of the code of
widgetupdate
while keeping it working the same way. It now essentially only handles automatically hiding of the widgets and the queuing ofdrawWidgets
-
• #61
@halemmerich I just worked out that Bootloader 0.101 on your app loader makes it so that 'Swipe menus' doesn't work. The modifications to E.showMessage in this guide also doesn't work with Bootloader 0.101. So something about loading modifications to system functions at boot doesn't work. Just a heads up :)
-
• #62
I suspect both the example as well as swipe menu work as expected and override whatever exists before :) So probably my wrapping the methods to apply the remove methods are just overriden. Since those would probably most useful in firmware instead of boot code that would not be catastrophic once mine or similar changes are in firmware. There is however the problem that stuff overriding functions like this breaks all new features implemented later in those system functions. Wrapping/Enhancing should probably be preferred to hard replacing existing functions.
-
• #63
How should var/let be used now in regards to fast loading? I saw that you changed most var statements to let statements in launch, @Gordon. But there are still some var statements left, e.g. line 58:
var app = apps\[i\];
.In iconlaunch code, @halemmerich have changed all var statements to let statements.
I've read some about var vs let here.
-
• #64
If you want to use a block scope (
{ code here ... }
) to let the garbage collector do it's job, you need to use let/const and not function/var, because function/var would be defined in the global scope. Everything defined in a block scope with var/function would need to be cleaned up manually before switching. -
• #65
Ok, thanks! So then I guess I've overdone it with deletes in this PR for dtlaunch? Since most of the variables are now declared with let statements within the block scope of the app, those do not have to be deleted and will be handled by the garbage collector?
-
• #67
Thanks!
-
• #68
With the newest additions to the cutting edge firmware I could reduce down the code in my experimental
fastload
andwidgetupdate
apps.fastload
does close to nothing now, it essentially only shows the "Fastloading..." screen as a visual aid to differentiate between fast and normal loading.widgetupdate
still does some trickery while loading widgets to wrap their display input related handlers to prevent them registering interactions while not visible and to reduce the number ofdrawWidgets
calls to at most two per call from an app.I think the state in the normal development apploader is now plenty fast for daily use and we are currently at a point of diminishing returns for experiments like mine. That does not mean I will stop playing around with this but I think there have been some really great improvements the last few weeks.
-
• #69
The ones inside a function are fine since they are defined at function scope anyway. It's just the ones in global scope that need to change...
Is this true for variables declared without any initiating keyword before them as well? Is
x = 42;
the same asvar x = 42;
in that regard? -
• #70
I think the state in the normal development apploader is now plenty fast ...
Agreed! Thank you for the work on this and other speed improvements, @Gordon and @halemmerich!
-
• #71
Is this true for variables declared without any initiating keyword before them as well? Is x = 42; the same as var x = 42; in that regard?
No... if you don't have
var
in a function it's defined as a global variable :) -
• #72
Thanks!
-
• #73
I have done a new version of my
fastload
app. This can fastload any app when it contains widgets and the calling app implements a remove method. It is essentially the same thing.bootcde
does, but for any app. Thewidgetupdate
app from my apploader should be removed, if you have it installed. It is not yet modified to work correctly with the slide out widgets and has fallen behind the changes tofastload
.It works by overloading
Bangle.load
andload
to catch all load attempts and then tries usingBangle.load
for everything withBangle.loadWidgets()
in it. That causes a fast load if possible or a normal load if the calling app does not have a removal method. Currently this means fastloading everything with widgets from launchers with removal method and normal loading on the way back. @Gordon do you think something like this would be ok for the normal apploader? -
• #74
and then tries using Bangle.load for everything with Bangle.loadWidgets() in it
What kind of speed improvements do you see? With the clocks, I found that the act of scanning for
Bangle.loadWidgets
added enough of an overhead that it wasn't worth it unless it could be precomputed.Right now I'd like to hold off on changing anything like this by default as I'm not sure so many people have even updated to 2v16 yet (and it's not like that many clocks support the
remove
method at the moment), but if it's just one app, and it's clear in the description that it is experimental then I think that'd be fine. -
• #75
The improvements are pretty much the same as between clock and launcher minus the CRC32 check for changes.
Checking forloadWidgets
everytime would take between around 200ms and 1000ms, so essentially eating all improvements. Caching the results and just checking the CRC takes 30ms-150ms.
Assuming a 300ms boot there is a 2x to 5x decrease in loading time from launcher. My bloated bangle install takes a lot longer than 300ms to boot ;)I would not install this by default or integrate in firmware at this point in time either. Since it has no dependencies and "only" applies what is already done in
.bootcde
to other loads it should not have that many side effects (there are probably some with other apps redefiningload
). After leaving an app there is still a full reload every time as long as apps do not widely implementremove
.
Ahh, thanks! Sorry, I missed that. That could be a good change to pull into the main Espruino versions and will be backwards compatible.
How slow is it really though? I just tested here and I get 70ms for a full widget redraw (which will only happen when apps are swapped from clock->something else or back). But because it's executed in a timeout, the app will load, everything will display fine and then the widget redraw will happen - so it's not going add a noticeable delay to loading.
I'm just conscious that this is for 4 widgets (widclk,widclkbttm,widclose and widcloselaunch), two of which are basically forks, so really only 2 widgets (neither of which are super popular). I wonder how much effort we really need to put into saving that extra 70ms that won't be noticed anyway.
widgetupdate
is interesting, but by wrapping every widget draw function with a check it is adding several ms of overhead to every draw call (and memory use). Also previously appRect was dynamic (if you had a widget that updated itself to appear or disappear, appRect could change over time).I guess one option is to modify drawWidgets at https://github.com/espruino/Espruino/blob/master/libs/js/banglejs/Bangle_drawWidgets_Q3.js#L11 to add
if (wd.update) wd.update();
So then if a widget needed to change its size (or
area
), it could do it on the next drawWidgets call without having to reschedule a whole new draw. That'd add maybe a ms or two todrawWidgets
but in total it's pretty tiny.Yes, I only really noticed it recently. It's a shame there's not a better way around it.
Yes, absolutely!