Private methods in a module, and modules in BangleApps

Posted on
Page
of 2
/ 2
Next
  • I'm trying to write a module for shared code between my BangleJs Apps.
    According to the tutorial, everything should be working at this Point.
    I required the module with the GitHub URL to it and it downloads, but when i create the object that should have all public functions and constants, it only has the variables that were set in the constructor.
    Am I doing something wrong or is the tutorial not working?
    Here is the module: https://github.com/OmegaVoid/EspruinoDocs/blob/master/modules/dane_arwes.js

  • Could you give me an example of what's not working that you expect?

    I just tried and this works...

    var d = require("https://raw.githubusercontent.com/OmegaVoid/EspruinoDocs/master/modules/dane_arwes.js");
    var x = d.create(1,2,3);
    print(x.C);
    /*{
      color: {
        primary: {...*/
    

    But one thing I can see is you've got:

    function drawTopLeftCorner(x, y) {
      g.setColor(this.C.color.primary.base);
    

    But drawTopLeftCorner isn't a method - it's just a bare function. So in that case, this won't point to the object and you won't find C...

  • that works, thanks! But do I need to make the Corner draw functions into public methods or is there some way to make them into private methods?

  • You could pass in the constants, if that is what you need?

    function drawTopLeftCorner(C, x, y) {
      g.setColor(C.color.primary.base);
    
    ....
    // then in a public method:
    drawTopLeftCorner(this,x,y)
    
  • It's not the most elegant way, because i need to pass in the entire object because both constants and variables are required, but it works

    function drawBottomLeftCorner(obj, x, y) {
    
    
      g.setColor(obj.C.color.primary.base);
      const x1 = x - obj.cornerOffset;
      const y1 = y + obj.cornerOffset;
      g.fillRect(x1, y1, x1 + obj.cornerSize, y1 - obj.cornerSize);
      g.setColor("#000000");
      g.fillRect(x, y, x + obj.cornerSize - obj.cornerOffset, y - obj.cornerSize + obj.cornerOffset);
    }
    
    
  • Great! You could always keep using this and do:

    drawTopLeftCorner.call(this, x, y);
    

    But IMO that's maybe even a bit less tidy than just passing it in as an argument

  • Would it be possible to use JavaScript classes in modules? Because then I could use actual private methods, and IMO that would be more elegant than using a constructor function with prototype methods and constants

  • You could use JS classes I believe but that doesn't help you - private fields are still only a JS proposal and not part of standard JS or implemented in Espruino: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields

  • i could of course just make the functions into public methods, but they aren't that useful outside of the module itself

  • Keeping them private would allow minification, which would be a big bonus.

    Do you need separate functions for each corner? being able to bring them into one function would probably increase the execution speed a lot.

    Also, not sure if this helps but:

    • I think you could just do two small fillRects for the two sides of the corner, rather than filling and then clearing? It should be a bit quicker and less flickery
    • Or if you did have to clear, you can use fillRect (fg color) and then clearRect (bg color) to avoid you having to reset the color all the time.
  • I can just do two small fillRects for it, and I can bring them into one function:

    function drawCorner(obj, x, y, n) {
      g.setColor(obj.C.color.primary.base));
      let x1;
      let y1;
      switch(n) {
      case 0: // Top Left
        x1 = x - obj.cornerOffset;
        y1 = y - obj.cornerOffset;
        g.fillRect(x1, y1, x, y + obj.cornerSize - obj.cornerOffset);
        g.fillRect(x1, y1, x + obj.cornerSize - obj.cornerOffset, y);
        break;
      case 1: // Top Right
        x1 = x + obj.cornerOffset;
        y1 = y - obj.cornerOffset;
        g.fillRect(x1, y1, x, y + obj.cornerSize - obj.cornerOffset);
        g.fillRect(x1, y1, x - obj.cornerSize + obj.cornerOffset, y);
        break;
      case 2: // Bottom Left
        x1 = x - obj.cornerOffset;
        y1 = y + obj.cornerOffset;
        g.fillRect(x1, y1, x, y - obj.cornerSize + obj.cornerOffset);
        g.fillRect(x1, y1, x + obj.cornerSize - obj.cornerOffset, y);
        break;
      case 3: // Bottom Right
        x1 = x + obj.cornerOffset;
        y1 = y + obj.cornerOffset;
        g.fillRect(x1, y1, x, y - obj.cornerSize + obj.cornerOffset);
        g.fillRect(x1, y1, x - obj.cornerSize + obj.cornerOffset, y);
        break;
      }
    }
    

    but that seems a bit redundant, because depending on the corner position the operations are different

  • one possible solution to that would be to use scaled, floored sine functions to get the correct signs, but i don't know if that would be faster or slower

  • I just meant whether you just needed it at all, or could roll it all into drawFrame?

    Do you have a need to draw individual corners on their own?

  • yes, because only some corners are needed for the frames with corners only on one side

  • either way, this is definetly shorter:

    function drawCorner(obj, x, y, n) {
      g.setColor(obj.C.color.primary.base);
      let s1, s2 = 1;
      switch (n) {
        case 0: // Top Left
          s1 = s2 = -1;
          break;
        case 1: // Top Right
          s2 = -1;
          break;
        case 2: // Bottom Left
          s1 = -1;
          break;
        case 3: // Bottom
          break;
      }
      const x1 = x + obj.cornerOffset *s1;
      const y1 = y + obj.cornerOffset *s2;
      g.fillRect(x1, y1, x, y - obj.cornerSize*(s1*-1) + obj.cornerOffset*s1);
      g.fillRect(x1, y1, x - obj.cornerSize*(s2*-1) + obj.cornerOffset*s2, y);
    }
    
    Arwes.prototype.drawFrameNoCorners = function (x1, y1, x2, y2) {
      g.setColor(this.C.color.primary.dark);
      g.drawRect(x1, y1, x2, y2);
    }
    
  • Good plan - I'm not sure s1 gets set up? You could actually do:

    let s1 = (n&1)?1:-1, s2 = (n&2)?1:-1;
    

    and remove the whole switch

    I've just updated the app loader to allow local modules for you: https://github.com/espruino/BangleApps#modules

    So add the module in modules/, then reference it from your code as just require("mymodule") and you should be good.

  • I don't know if it's just a problem with my fork of the app loader often only updating partly after a new deployment, but my apps are still not uploading to my bangle now with the module

  • at least not the launcher

  • and the watchface is uploading, but after that the bangle is stuck at searching for gps time

  • Maybe start up the Chrome Debug Console, right-click on the normal page refresh icon, and choose Empty Cache and Hard Reload?

    If that doesn't work, maybe you could post up what's shown by the debug console when you try to upload your app and maybe what error the Web IDE gives when you connect to the Bangle and long-press BTN3 to reload the app?

    Also if you had a link to your app loader online then I could try it here

  • https://gist.github.com/OmegaRogue/0beda87a1a80dccb3bc4e8d8c84b70cb
    here is the log
    here is the app loader: https://omegavoid.codes/BangleApps
    its hosted using GitHub pages, and recently its been having alot of problems with actually rebuilding everything on deploy, my custom css had alot of problems with having the latest changes after rebuilding

  • Ahh - so yeah, what's happened is the core submodule is out of date somehow.

    core/js/appinfo.js should looks like https://github.com/espruino/EspruinoAppLoaderCore/blob/8bfdeebf705ced95699dcbbccfa05a99e7d3f4a9/js/appinfo.js:

    // Run JS through EspruinoTools to pull in modules/etc
    function parseJS(storageFile, options) {
      if (storageFile.url && storageFile.url.endsWith(".js") && !storageFile.url.endsWith(".min.js")) {
        // if original file ends in '.js'...
        var localModulesURL = window.location.origin + window.location.pathname.replace(/[^\/]*$/,"") + "modules";
        return Espruino.transform(storageFile.content, {
          SET_TIME_ON_WRITE : false,
          PRETOKENISE : options.settings.pretokenise,
          MODULE_URL : localModulesURL+"|https://www.espruino.com/modules",
          //MINIFICATION_LEVEL : "ESPRIMA", // disable due to https://github.com/espruino/BangleApps/pull/355#issuecomment-620124162
          builtinModules : "Flash,Storage,heatshrink,tensorflow,locale,notify"
        }).then(content => {
    

    But on yours it looks like:

    function parseJS(storageFile, options) {
      if (storageFile.url && storageFile.url.endsWith(".js") && !storageFile.url.endsWith(".min.js")) { // if original file ends in '.js'...
        return Espruino.transform(storageFile.content, {
          SET_TIME_ON_WRITE : false,
          PRETOKENISE : options.settings.pretokenise,
          //MINIFICATION_LEVEL : "ESPRIMA", // disable due to https://github.com/espruino/BangleApps/pull/355#issuecomment-620124162
          builtinModules : "Flash,Storage,heatshrink,tensorflow,locale,notify"
        }).then(content => {
    
  • how do I get it to update the core submodule?

  • this is my current folder structure (.git and .idea folders are hidden)

  • git submodule update might do it?

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

Private methods in a module, and modules in BangleApps

Posted by Avatar for OmegaRogue @OmegaRogue

Actions