-
Hi everyone,
I got quite some feedback on my last video with the Bangle.js 2 overview. So, I decided to produce another one, this time about the GPS functions of the Bangle.js 2. You can find it on
This time, I released the English version first. A German one will most probably follow.
Let me know of any remarks or comments you have. And: Spread the word!
Best regards,
Dirk -
-
-
Hi Gordon,
this is a great idea! I already thought about this, too, but did not come up with a suggestion as I also saw the problem of the apps.json file creation. github magic and shell script would be perfect.
I also host my own app loader with the small subset of apps I actively work on. Currently, I've stripped down apps.json manually and solve merge conflicts on rebasing my own app loader branch manually.
I think that the use case "local app loader with app subset" is quite common. May I suggest to add a "restrictedapplist.json" (or whatever name it gets) in the main app loader directory. If it does not exist, the apps.json builder behaves exactly as proposed and includes the metadata of all apps into the apps.json. If however, restricedapplist.json exists and contains a ['list','of','app','ids'], only those apps are added to apps.json. This would allow to have that restrictedapplist in pesonal app loaders, it would not create merge conflicts (as the official loader of course does not have it) and make continuous integration of the official app loader into personal copies a charm.
One could even think about moving the restrictedapplist.json evaluation alternatively into the loader code. It could work like this (pseudo-code):
getAppsJson() { if apps.json exists load it else if restricedapplist.json exists load it apps.json={} for each app in restrictedapplist.json load app's metadata apps.json['appid']=app's metadata else bail out
Small development-only app loader could leave out the apps.json creation altogether this way. Loader with more traffic would create it by script or jekyll and had no performance loss. I must admit that my time and my Javascript skills are too restricted so that I have not tried to implement this myself so far.
Best regards,
Dirk
(who just created parts of the footage about a Bangle.js GPS video) -
Some days ago I posted a link to an introductionary video on the Bangle.js 2 in German. I got some feedback and decided to produce another version in English:
https://www.youtube.com/watch?v=LwSAEcJUAu8
Now, there is also a video you can point people to who do not understand German. Note that this is NOT a subtitled or overdubbed version of the German video, but a completely new version for which I even recreated some of the language-independent footage. I did my best to produce understandable English as a non-native speaker...
Let me know if you have any comments or suggestions!
Best regards,
Dirk -
Hi everyone,
after having played around with the Bangle.js 2 for some time now I decided to let the world know about this great system. I made an overview video on the clock showing unboxing and first steps. I also decided to create this in my mother tongue, German; mainly because I found absolutely no German videos about the Bangle.js 2 at all so far. You can find it on Youtube:
Die Bangle.js-2-Smartwatch - Ein Überblick
So while this might not be of much use for - perhaps - most of you, it could help making the Bangle.js 2 better known in the German-speaking countries.
Let me know if you have any comments or remarks. And: Spread the word!
Best regards,
Dirk -
Hi,
many thanks for this great watch face! Some feedback
Broader hands, especially the seconds hand, would increase readability. The "always on" display of the Bangle.js 2 is a real "killer feature", it just needs software which makes the most use of it.
You might think about making the seconds hand only drawn when the screen is unlocked. Without seconds hand, the clock only has to wake up once per minute and that really makes a difference to power consumption. This can be made an option, however.
Your settings dialog should be at the usual place in the app settings. It is really confusing if it does not stick to standards.
You also might think about using the default settings menus with
E.showMenu()
. Yes, yours are definitely more beautiful! But again - special solutions make things more complicated for the every day user. And if there is one thing that annoys people then it's if an every day item (like, say, a watch) has an overcomplicated configuration mechanism. And that would be a pity, because your watch is really nice.Your watch face overwrites the lower widget area. But I am a bit unsure whether this is really a think on the Bangle.js 2. So far, I have not yet seen a widget in that area...
May I also suggest a name change? I mean, being "configurable" is not really an outstanding feature for a computer program, is it? What do you think about "Versatile analog watch". Because that's its unique selling point: An analog watch face which has a versatile look'n'feel.
Best regards,
Dirk -
Hi,
I also had a "spontaneous factory reset" once. It was in the beginning of my development of Anton clock. I started with copying it into a new app but garbled the app.json entry. My "antwsclk" overwrote the "antonclk" files on the Bangle as I did not change the file names. After some back and forth, I removed my app and therefore (parts of) Anton clock - which was still the default clock at that moment (I had not understood the concept of "default clock" at that time...).
However, I locked up the Bangle.js severely and the boot screen talked about "corrupted boot data" or did simply nothing. I left the Bangle alone for some 30 minutes and when I looked at it again, it obviously had performed a factory reset. Stock Anton clock etc.
I did not see this behaviour again once I corrected my app.json entries. There was another factory reset lateron, but for that I can absolutly not say any suspicious circumstances - it just happened.
Perhaps this helps more than it sounds...
Regards,
Dirk -
-
Hi @crazysaem,
thanks for the reply. I have enhanced the documentation to make this clearer. Even if this app might become obsolete in the forseeable future, it should be documented well so that it does not confuse or frustrate someone who wants to give it a try.
You might want to have a look at my app loader. I have only made changes to the README.md. If I don't hear any objections from you, I will file a pull request for this doc change tomorrow.
Regards,
Dirk -
Hi,
I played a bit around with the Pattern Loader and have a question: Is it correct that you install this launcher beside the defaut launcher, i.e. you do not replace it. And: Is it correct that Pattern Launcher only works in the Clock face, not if any other apps are running?
No critics, idea and implementation concept seem great to me! It's just that the documentation was not clear to me about these issues.
Regards,
Dirk -
-
Hi,
ok, thank you @Gordon, then I will follow a "mixed strategy": Always rebase upon master before issuing any pull requests, and then rebase "from time to time" to stay near to master, but more on a weekly than on a daily base.
To everyone else: Sorry that I did not explain in greater detail what I am actually doing. I work with git for some 14 years now and in my company, we have a quite nice scheme with release branch, integration branch and feature branches. Currently, I work with the Bangle app loader repo as follows:
I cloned it into my own github namespace ("dirkhillbrecht/BangleApps").
From there, I cloned it as workspace onto my workstation ("$HOME/Projekte/BangleApps").
In the workspace, I create a feature branch where I want to change or add stuff: "git checkout -b feature".
I do all my work in that feature branch.
I push the feature branch back to my cloned github repo. The first time, I have to give the push target for the new branch explicitly: "git push --set-upstream origin feature".
When I think I'm finished, I issue a pull request on the feature branch in my cloned github repo back to the official app loader repo.
This way, "master" on my cloned github repo and in my workspace repo can always follow "master" of the official app loader. To stay on top of development, I do the following:
From time to time, I fetch the updated "master" of the official app loader into my github repo ("Fetch upstream" button).
I pull the updated master from github to workspace repo ("git checkout master && git pull").
I switch to my feature branch ("git checkout feature").
I issue "git rebase master" - and solve any merge issues.
I push my feature back to my github repo. As it has been rebased and therefore its history is non-linear, I have to push forcefully: "git push --force"
If I do that last step while the branch is already in the pull request review process, other people see my disruptive operation also and potentially must cope with it. I hoped that this was not too big of an issue and learned that it indeed not is.
Regards,
Dirk -
Hello @HughB,
I extended the original Anton clock and issued the pull request for this extended version. However, I also keep an independed "Anton clock with seconds" in parallel. It is exactly the same code, the only difference is the name of the settings file. I use that as long as the pull request has not gone through - and would continue from there if the request were torn down.
I don't think being "minimal" is a good design target for software (or, in fact, any system). "Functional" is a good one. Sometimes "functional" may mean "minimal" as good functionality comes from simplicity. In case of watches, personal preferences vary. I think, there is no reason to keep the watch face that basic in this case. I added a bunch of configuration options to make "Anton clock" versatile while keeping its best feature: Being very well readable even if the display is unlit.
If you don't do anything, "my" Anton clock 0.04 looks and behaves exactly like 0.03. But suddenly you have lots of configuration knobs to adjust it to your needs and preferences.
Best regards,
Dirk -
Hi everyone,
thanks for all your ideas and suggestions. I read through them and integrated some of them into my Anton clock enhancement proposal. However:
- "Anton clock" is named Anton clock because it uses the Anton bold font for the clock digits. In my opinion, using another font is beyond this watch faces scope. It would need tweaking lots of tiny position adjustments, too.
- "Anton" and any other special fonts must be rendered explicitly for this app. This increases its size considerably. As not more than one font would be used at the same time, this would be rather a waste of space.
- The "Anton" fonts included in this watch face do only contain digits and a minimum amount of other characters. Therefore, they cannot be used for much more than presenting the time.
- Finally, the big advantage of the bold Anton font is ... well ... its boldness. The watch face can be read even if the screen is locked and unlit. The much lighter fonts suggested above do not have this advantage, neither btw. has the built-in Vector font. This bold font is key feature why I like Anton clock so much.
Having said this, I did make the following changes:
- Seconds use a smaller version of the Anton font now. This removes the biggest flaw of my former proposal: The lower widget area is now unobstructed.
- Colon in front of seconds can be disabled.
- In seconds mode, date can be shown with weekday instead of year.
- I use multi-selections in the settings now instead of only booleans. That makes configuration a bit smaller and much clearer as there are no implicit dependencies between options any more.
If you already use the extended version of Anton clock, some settings might be lost due to the settings changes. Just reconfigure them.
The new version is available in my app loader, either as Anton clock 0.04 or as a separate, independent "Anton clock with seconds 0.10". My pull request for the Anton clock 0.04 is still pending (and has been updated accordingly).
Best regards,
Dirk - "Anton clock" is named Anton clock because it uses the Anton bold font for the clock digits. In my opinion, using another font is beyond this watch faces scope. It would need tweaking lots of tiny position adjustments, too.
-
Hi,
in my company, we have a strict rebase policy: Rebase your feature branch on top of the integration branch until it is ready for inclusion. I see that the branches here are usually not rebased before inclusion. A pull-request-based workflow does not make that really deasibe after all. But how are such rebases seen here if done by the pull request issuer during the pull request handling time? Encouraged? Frowned upon? Not seen as an issue?
I just don't want to annoy anyone with my branch handling...
Regards,
Dirk -
Hello @Gordon,
thanks for your feedback. I just issued the pull request after rebasing Puzzle15 out of my own app loader branch and onto the official current master. Finally new apps! :-)
Best regards and many thanks for creating this awesome Espruino ecosystem!
Dirk -
Hi everyone,
thanks for the feedback. I have now released v0.05 on my app loader which I see as "complete". I have not however, walked through @HughB suggestions so far, as I just became aware of them. A fast walk-through shows that some things are already included:
- The 5x5 font size is already corrected.
- The readme is vastly extended (even though without screenshots so far).
- The "green square" at the top right is actually grey :-) and it should open the menu. The clicking coordinates seem to be quite inaccurate, you have mentioned that the "messages" app suffers from the same problem.
- I don't like pressuring the player. 15 puzzle is a short-time leisure game. Try to solve it in less and less moves if you want a challenge. :-) 57 is the mean, no puzzle needs more than 80 minimum. But finding the best solution is an NP-hard problem. You have been warned…
- I dont't like mocking the player, either. Puzzle15 generates solvable puzzles only. This could made be an option, however.
I'll take a look at the other things. Expect a v0.06…
Regards,
Dirk - The 5x5 font size is already corrected.
-
Hello everyone,
I'd like to announce the first pre-release of my 15-puzzle implementation "Puzzle15" for the Bangle.js 2. You can find it in my app loader instance at
https://dirkhillbrecht.github.io/BangleApps/#puzzle15
It is not completely finished, but already useful (well, as useful as a 15-puzzle can be…). If you like, download it, try it, and give me feedback. I plan to issue a pull request into the official app loader within the next days.
Best regards,
Dirk -
Hello @HughB,
thanks for the feedback. Yes, after I found the real reason for the deployment problem, I removed the "garbled" version of Puzzle15. The "real" version in my app loader is under heavy development. I just released v0.03 which is the first one with a working menu system and everything more or less ready. I want to add some settings and then think about a merge request into the official app loader. But you might want to give it a try.
Regards,
Dirk -
Hi @rigrig ,
thanks for explaining (or guessing…) what's going on! Can't have been too wrong, as
setTimeout(showMenu,0)
did not help, butsetTimeout(showMenu,10)
actually does! With 10 milisconds delay the events seem to be correctly assigned. Very cool!Best regards,
Dirk -
Hi everyone,
I have a problem with the
E.showMenu()
function in the Bangle.js 2. Setup: An app shows its screen. Interaction is done via dragging over the screen or clicking into certain areas. All user input is handled viaBangle.on("drag",…)
. Short drags are interpreted as a "click".This way, when the user clicks into a certain area (a "button" so to say), a menu should open. I use
E.showMenu()
. Problem is: In 99% of all cases, the menu immediately detects a click on the first menu item. This happens before the menu is even shown. As the first menu item is "Continue", the app simply continues and it looks as the menu has never been presented at all.I have shrunken down my app to demonstrate the problem. I hope, the mere 123 lines aren't too long.
// Test program for the event handling problem with the menu var gameValue = 3; var buttonsize = 30; // Evaluate drag and click events, massively reduce version which evaluates // each drag end as "click". That's sufficient to show the problem class Dragger { constructor(clickHandler) { this.clickHandler = clickHandler; this.enabled = true; } // Enable or disable the Dragger setEnabled(b) { this.enabled = b; } // Handle a raw drag event from the UI handleRawDrag(e) { if (!this.enabled) return; if (e.b === 0) { // Drag event ended: Evaluate full drag console.log("GGG - D.hRD - C, drag ended, assuming click"); this.clickHandler(e); // take x and y from the drag end } } // Attach the drag evaluator to the UI attach() { Bangle.on("drag", e => this.handleRawDrag(e)); } } // Representation of a field on the screen class Field { constructor(left, top) { this.left = left; this.top = top; } // Returns whether this field contains the given coordinate contains(x, y) { return (this.left < x && this.left + buttonsize > x && this.top < y && this.top + buttonsize > y); } // Special field for the menu static forMenu() { return new Field(g.getWidth() - (buttonsize + 2), 26); } } // Representation of game area class Board { // Generates the actual playing field with all fields and buttons constructor() { this.menuField = Field.forMenu(); } // Draws the complete playing field draw() { console.log("GGG - B.d - A"); g.setFont("Vector", 20).setFontAlign(0, 0).setColor(0, 0, 0); g.drawString("Value: " + gameValue, g.getWidth() / 2, g.getHeight() / 2); g.drawRect(this.menuField.left, this.menuField.top, this.menuField.left + buttonsize, this.menuField.top + buttonsize); } } var board = new Board(); var dragger; function continueGame(logmsg) { E.showMenu(); board.draw(); dragger.setEnabled(true); console.log(logmsg); } function initGame(bpl, logmsg) { gameValue = bpl; board = new Board(); continueGame(logmsg); } function showMenu(withContinue) { var mainmenu = { "": { "title": "Menu" }, "Continue": () => continueGame("GGG - menu detected Continue"), "Set 3": () => initGame(3, "GGG - menu detected Set 3"), "Set 4": () => initGame(4, "GGG - menu detected Set 4") }; console.log("GGG - sM - B"); dragger.setEnabled(false); g.clear(true); console.log("GGG - sM - C, mainmenu: " + mainmenu); E.showMenu(mainmenu); console.log("GGG - sM - D"); } function handleclick(e) { console.log("GGG - handleclick - A, e: " + JSON.stringify(e)); if (board.menuField.contains(e.x, e.y)) { console.log("GGG - handleclick - B, menu button pressed"); showMenu(); console.log("GGG - handleclick - C, menu shown"); } } // Clear the screen once, at startup g.clear(); // Clock mode allows short-press on button to exit Bangle.setUI("clock"); // Load widgets Bangle.loadWidgets(); Bangle.drawWidgets(); // Draw the board initially board.draw(); dragger = new Dragger(handleclick); dragger.attach(); showMenu(); // works // end of file
If you run this code, at first the menu is shown (explicitly in the main code, line 121). Then, the main part of the app starts. The square on the top right is the "menu button". If you click into it, the menu should open.
...only that it doesn't. In the emulator, you can only see that something is happening through the console log output. On the real hardware, the menu opens shortly and is immediately closed again. The console output shows in both cases that the first menu item, "Continue" is selected.
In the emulator, you can trick the UI: If you perform a drag which ends outside the emulator window, then the next click on the menu button works. And on very rare occasions, the menu on the real hardware also does not close immediately but works flawlessly as expected. But you really need to be lucky to witness this behaviour.
I do not know what is going on here. Do I make something wrong? Is it a bug in the menu system? Some interference with my way of interpreting input? Can anyone help me?
Best regards,
Dirk -
You are right, id and directory name must match. Also, in the
storage
section, thename
entries for the app's files must match themyapp.(app|settings|…).(js|…)
pattern. But the local names of the files, which are referenced in theurl
property of thestorage
entries, can be arbitrary. In the official app loader,<appname>.app.js
andapp.js
are both used. After testing around, I decided to stick with the long version even within the app loader.The 404 is also gone, I've changed the branch name template in
loader.js
to match the setup of my app loader.
Thank you for your comment, @zasqwer . I have lots of experience in programming, but only little in such restricted environments like the Bangle.js. I also think that the code is not too bad, but I'd say this is only possible because the development environment of the Bangle.js is so good: It's really simple, well-documented and quite powerful at the same time. So, let's take it as a sign that the Espruino crew really does a great job!