Avatar for stweedo

stweedo

Member since Apr 2023 • Last active Jun 2023
  • 4 conversations
  • 38 comments

Most recent activity

  • in Bangle.js
    Avatar for stweedo

    Very cool! Really shows how versatile this platform can be as a control interface for literally anything.

  • in Bangle.js
    Avatar for stweedo

    If anyone is curious to try out my new Ohm's Law Calculator app you can do so here.

    Thank you again Philip, I was really struggling with that menu transition to the layout and back. You rock!

    Another challenging task is still on my to do list: Get it to show the formula that was used as an expression with the letter placeholders like so "V = I*R" and then when that menu item is pressed it opens up a formula display page in a large font with the formula shown using the actual values now instead of the letters.

  • in Bangle.js
    Avatar for stweedo

    @Philip That was it! Thank you so much!

  • in Bangle.js
    Avatar for stweedo

    Hey, thanks for the reply.

    I did try placing layout.render() in different parts of my code but it didn't help.

    I'll have to check out that keyboard you helped make. Can't say I've tried using any keyboards on this watch so far, but I like the idea of using the swipe handler to do backspace or maybe as a back button replacement on the input screen in my case.

  • in Bangle.js
    Avatar for stweedo

    It's far from finished and there may be other bugs and errors, but here is the program I'm making. It's an Ohm's Law Calculator. This problem has been holding me back all day so I would really like to solve it, especially since it seems trivial.

    let Layout = require("Layout");
    
    const UNITS = {
      "Voltage (V)": "Volts",
      "Current (I)": "Amps",
      "Resistance (R)": "Ohms",
      "Power (P)": "Watts",
    };
    
    const FORMULAS = {
      'Voltage (V)': {
        'Current (I), Resistance (R)': "{0} * {1}",
        'Power (P), Current (I)': "{0} / {1}",
        'Power (P), Resistance (R)': "Math.sqrt({0} * {1})"
      },
      'Current (I)': {
        'Voltage (V), Resistance (R)': "{0} / {1}",
        'Power (P), Voltage (V)': "{0} / {1}",
        'Power (P), Resistance (R)': "Math.sqrt({0} / {1})"
      },
      'Resistance (R)': {
        'Voltage (V), Current (I)': "{0} / {1}",
        'Power (P), Current (I)': "{0} / (Math.pow({1}, 2))",
        'Power (P), Voltage (V)': "(Math.pow({0}, 2)) / {1}"
      },
      'Power (P)': {
        'Voltage (V), Current (I)': "{0} * {1}",
        'Current (I), Resistance (R)': "(Math.pow({0}, 2)) * {1}",
        'Voltage (V), Resistance (R)': "(Math.pow({0}, 2)) / {1}"
      },
    };
    
    let lastStringWidth = 0;
    let calculatedVariable;
    let selectedVariable;
    let variableValues = {};
    let inputStr = "";
    
    let layout = new Layout({
      type: "v",
      c: [
        { type: "txt", font: "6x8:3", label: "", id: "label" },
        { type: "h", c: "123".split("").map(i => ({ type: "btn", font: "6x8:3", label: i, cb: () => { handleButtonPress(i); }, fillx: 1, filly: 1 })) },
        { type: "h", c: "456".split("").map(i => ({ type: "btn", font: "6x8:3", label: i, cb: () => { handleButtonPress(i); }, fillx: 1, filly: 1 })) },
        { type: "h", c: "789".split("").map(i => ({ type: "btn", font: "6x8:3", label: i, cb: () => { handleButtonPress(i); }, fillx: 1, filly: 1 })) },
        { type: "h", c: ".0C".split("").map(i => ({ type: "btn", font: "6x8:3", label: i, cb: () => { handleButtonPress(i); }, fillx: 1, filly: 1 })) },
        { type: "h", c: [{ type: "btn", font: "6x8:2", label: "Enter", cb: () => { handleEnter(); }, fillx: 1, filly: 1 }] }
      ]
    }, { lazy: true });
    
    function clearInputArea() {
      let label = layout.label;
      // Calculate rectangle coordinates for clearing
      let xCenter = g.getWidth() / 2;
      let halfStringWidth = lastStringWidth / 2;
      let x1 = xCenter - halfStringWidth;
      let y1 = label.y;
      let x2 = xCenter + halfStringWidth;
      let y2 = label.y + g.getFontHeight();
      // Clear the old label area
      g.clearRect(x1, y1, x2, y2);
    }
    
    function clearTextArea() {
      let x1 = 0;
      let y1 = 0;
      let x2 = g.getWidth();
      let y2 = 22;
      // Clear the old label area
      g.clearRect(x1, y1, x2, y2);
    }
    
    function clearScreen() { // Except Back Button
      let x2 = g.getWidth();
      let y2 = g.getHeight();
      g.clearRect(24, 0, x2, 24);
      g.clearRect(0, 24, x2, y2);
    }
    
    function showCalculatorInputScreen(variable) {
      selectedVariable = variable;
      layout.render();
    }
    
    function setValue(newStr) {
      clearTextArea();
      inputStr = newStr;
      layout.label.label = inputStr;
      layout.render();
      lastStringWidth = g.stringWidth(inputStr);
    }
    
    function handleButtonPress(value) {
      if (value === 'C') {
        setValue("");
      } else {
        inputStr += value;
        setValue(inputStr);
      }
    }
    
    function calculateValue(calculatedVariable, variableValues) {
      let formulas = FORMULAS[calculatedVariable];
      let formulaKeys = Object.keys(formulas);
      for (let i = 0; i < formulaKeys.length; i++) {
        let formulaKey = formulaKeys[i];
        let variables = formulaKey.split(', ');
        if (variables.every(variable => variableValues.hasOwnProperty(variable))­) {
          let formula = formulas[formulaKey];
          let formulaValues = variables.map(variable => variableValues[variable]);
          let calculatedValue = eval(formula.replace(/\{(\d+)\}/g, (_, index) => formulaValues[index]));
          let result = Object.entries(variableValues).map(funct­ion (entry) {
            let variable = entry[0];
            let value = entry[1];
            return [variable, `${value} ${UNITS[variable]}`];
          });
          result.push([calculatedVariable, `${calculatedValue.toFixed(2)} ${UNITS[calculatedVariable]}`]);
          return {
            formula: formula.replace(/\{(\d+)\}/g, (_, index) => formulaValues[index]),
            value: calculatedValue.toFixed(2),
            unit: UNITS[calculatedVariable],
            result: result,
          };
        }
      }
    }
    
    (function () {
      let mainMenu = {
        '': { 'title': 'Ohm\'s Law Calc' },
        '< Back': () => Bangle.showClock()
      };
    
      Object.keys(UNITS).forEach(unit => {
        mainMenu[unit] = () => handleUnitSelection(unit);
      });
    
      function showVariableSelectionMenu() {
        let variableSelectionMenu = {
          '': { 'title': 'Select Variable' },
          '< Back': () => E.showMenu(mainMenu)
        };
    
        let variables = Object.keys(UNITS);
        let remainingVariables = variables.filter(v => v !== calculatedVariable);
        remainingVariables.forEach(variable => {
          variableSelectionMenu[variable] = function () {
            showInputMenu(variable);
          };
        });
        E.showMenu(variableSelectionMenu);
      }
    
      function showInputMenu(variable) {
        let inputMenu = {
          '': { 'title': variable },
        };
        E.showMenu(inputMenu);
        layout.render();
      }
    
      function handleEnter() {
        if (calculatedVariable === null) {
          return;
        }
    
        variableValues[selectedVariable] = parseFloat(inputStr);
    
        if (Object.keys(variableValues).length === 1 && variableValues.hasOwnProperty(selectedVa­riable)) {
          let temp = variableValues[selectedVariable];
          delete variableValues[selectedVariable];
          variableValues[Object.keys(variableValue­s)[0]] = temp;
        }
    
        if (Object.keys(variableValues).length === 2) {
          let result = calculateValue(calculatedVariable, variableValues);
          showResultsScreen(result);
          calculatedVariable = null;
          variableValues = {};
          inputStr = "";
        } else {
          clearScreen();
          showVariableSelectionMenu();
        }
    
        inputStr = "";
        setValue("");
      }
    
      function handleUnitSelection(unit) {
        calculatedVariable = unit;
        showVariableSelectionMenu();
      }
    
      function showResultsScreen(result) {
        let resultsMenu = {
          '': { 'title': 'Results' },
          '< Back': function () {
            clearScreen();
            E.showMenu(mainMenu);
          },
          'Formula': result.formula,
          ['Calculated ' + result.unit]: result.value + ' ' + result.unit
        };
    
        result.result.forEach(([variable, value]) => {
          resultsMenu[variable] = value;
        });
    
        E.showMenu(resultsMenu);
      }
    
      E.showMenu(mainMenu);
    })();
    
  • in Bangle.js
    Avatar for stweedo

    I'm having trouble getting my layout to work when called from within a menu. It seems to keep the menu running in the background even after clearing the screen. My layout is displayed but the on screen buttons aren't usable.

    Any suggestions?

  • in General
    Avatar for stweedo

    There is one thing I noticed that could be improved with regards to the tabs.

    If you open a file from storage and click "Copy to Editor" a new tab with its name appears. However if the tab remains open and the file on the device has been updated and reloaded from storage again, it doesn't actually update the open tab with the new file data when clicking "Copy to Editor" again.

    Also, ctrl+b doesn't seem to work for beautify anymore, and ctrl+` only switches from terminal to editor but not from editor to terminal.

  • in Bangle.js
    Avatar for stweedo

    I've been testing this out and there's a pretty big issue with how maps is sending the distance values when using imperial units.

    It will send the distance value to bangle.js in meters, which it's supposed to, until it gets to 0.1 miles at which point maps decides to send the distance value directly in feet instead.

    Now when the locale file on the bangle.js sees this new value in feet it still thinks it's working with meters and the distance becomes inaccurate as a result.

    I've tried getting the log data from gadgetbridge while using navigation, but it only showed one single nav message at the beginning of my drive with a distance of 0 and that's it. The navigation ran the whole trip on my phone and the watch so I don't know why there weren't more.

    I was also testing some formatting changes in the locale file to make it use one decimal place at less than 10 miles and convert to feet when less than 0.1 miles (this is about ~500ft or 152.4 meters which is when maps changes from miles to feet). This works great and makes the distances match exactly what is shown on the phone (except the bug with the units switching), but I'm thinking this may not be the right place for this code. Perhaps it would be better placed in the messagegui app and could be made compatible with all locales?

    distance: (n) => {
      var miles = n / 1609.34;
      var dp = miles < 10 ? (miles % 1 === 0 ? 1 : 2) : 0;
      return n < 152.4 ? Math.round(n * 3.28084) + "ft" : round(miles, dp) + "mi";
    },
    
  • in Bangle.js
    Avatar for stweedo

    Resistor calculator: Enter a resistance value in ohms and get a visual representation showing the color bands. Alternatively enter the colors and get a resistance value back. I'm picturing the resistance value on the top half of the screen and image on the bottom and show both.

Actions