• That is why I tried to add the remove handler to the options given to E.show

    Ahh, thanks! Sorry, I missed that. That could be a good change to pull into the main Espruino versions and will be backwards compatible.

    I think we need at least a solution for the widgets not beeing updated correctly either in draw methods (multiple calls to Bangle.drawWidgets() => slow)

    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/blo­b/master/libs/js/banglejs/Bangle_drawWid­gets_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 to drawWidgets but in total it's pretty tiny.

    Didn't think about the code reading/parsing implications of wrapping in a function.

    Yes, I only really noticed it recently. It's a shame there's not a better way around it.

    stuff similar to fastloading will happen inside of apps (showing menus, scrollers and using setUI() for different parts of the app etc.) and I think we should have working cleanup for those scenarios.

    Yes, absolutely!

  • 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.wid­th=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(!WIDG­ETS_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.d­rawWidgets();}
                                  ^
    >
    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.wid­th=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(!WIDG­ETS_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.d­rawWidgets();}let launchCa...
                                     ^
    >
    

    Step-by-step:

    1. Factory reset watch via web IDE
    2. Install favorite apps, among them Icon Launcher, Anton Clock and Fastload helper.
    3. Install widgetupdate.
    4. Long press physical button to reset after loading apps.
    5. On Anton Clock no widgets are drawn.
    6. Press physical button go to launcher.
    7. Stuck on "Fastloading..."
  • That's not because of wid_edit, it's the messages widget: it already had an update 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 through Bangle.emit("message", type, message);, instead of directly calling widget methods or global functions.

  • 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.

  • 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 during drawWidgets:

        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 setting draw = ()=>{} and restoring that on showing the widgets. Actually the widget_utils module could now be used there. That would probably remove the need for my some of my Bangle.*Widgets-methods altogether.

  • 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 :)

  • 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.

  • Just a note that because I got a complaint about widclose/etc (https://github.com/espruino/BangleApps/c­ommit/f6b38b34437572498b9ab8403dc333164b­0b193a#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?

  • 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 to drawWidgets taking 50ms each, so I think right now the most recent changes are probably 'good enough'.

  • 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 of drawWidgets

  • @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 :)

  • 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.

  • 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.

  • 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.

  • 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?

  • @Gordon. But there are still some var statements left, e.g. line 58

    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...

  • With the newest additions to the cutting edge firmware I could reduce down the code in my experimental fastload and widgetupdate 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 of drawWidgets 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.

  • 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 as var x = 42; in that regard?

  • 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!

  • 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 :)

  • 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. The widgetupdate 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 to fastload.

    It works by overloading Bangle.load and load to catch all load attempts and then tries using Bangle.load for everything with Bangle.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?

  • 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.

  • The improvements are pretty much the same as between clock and launcher minus the CRC32 check for changes.
    Checking for loadWidgets 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 redefining load). After leaving an app there is still a full reload every time as long as apps do not widely implement remove.

  • Post a reply
    • Bold
    • Italics
    • Link
    • Image
    • List
    • Quote
    • code
    • Preview
About

POC - Combining BW Clock and Desktop Launcher to spend less time "Loading..."

Posted by Avatar for Ganblejs @Ganblejs

Actions