Skip to content

Commit

Permalink
Merge pull request espruino#1158 from crazysaem/ptlaunch
Browse files Browse the repository at this point in the history
Pattern launcher: improve pattern detection and pattern drawing
  • Loading branch information
gfwilliams committed Jan 4, 2022
2 parents 9d548ef + 968e31c commit 5105a7e
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 316 deletions.
2 changes: 1 addition & 1 deletion apps.json
Original file line number Diff line number Diff line change
Expand Up @@ -4861,7 +4861,7 @@
"id": "ptlaunch",
"name": "Pattern Launcher",
"shortName": "Pattern Launcher",
"version": "0.11",
"version": "0.13",
"description": "Directly launch apps from the clock screen with custom patterns.",
"icon": "app.png",
"screenshots": [{"url":"manage_patterns_light.png"}],
Expand Down
4 changes: 3 additions & 1 deletion apps/ptlaunch/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@
0.02: Turn on lcd when launching an app if the lock screen was disabled in the settings
0.03: Make tap to confirm new pattern more reliable. Also allow for easier creation of single circle patterns.
0.10: Improve the management of existing patterns: Draw the linked pattern on the left hand side of the app name within a scroller, similar to the default launcher. Slighlty clean up the code to make it less horrible.
0.11: Respect theme colors. Fix: Do not pollute global space with internal variables ans functions in boot.js
0.11: Respect theme colors. Fix: Do not pollute global space with internal variables ans functions in boot.js
0.12: Improve pattern detection code readability by PaddeK http://forum.espruino.com/profiles/117930/
0.13: Improve pattern rendering by HughB http://forum.espruino.com/profiles/167235/
39 changes: 24 additions & 15 deletions apps/ptlaunch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,32 +29,41 @@ Then launch the linked apps directly from the clock screen by simply drawing the
## Detailed Steps

From the main menu you can:

- Add a new pattern and link it to an app (first entry)
- To create a new pattern first select "Add Pattern"
- Now draw any pattern you like, this will later launch the linked app from the clock screen
- You can also draw a single-circle pattern (meaning a single tap on one circle) instead of drawing a 'complex' pattern
- If you don't like the pattern, simply re-draw it. The previous pattern will be discarded.
- If you are happy with the pattern tap on screen or press the button to continue
- Now select the app you want to launch with the pattern.
- Note, you can bind multiple patterns to the same app.
- To create a new pattern first select "Add Pattern"
- Now draw any pattern you like, this will later launch the linked app from the clock screen
- You can also draw a single-circle pattern (meaning a single tap on one circle) instead of drawing a 'complex' pattern
- If you don't like the pattern, simply re-draw it. The previous pattern will be discarded.
- If you are happy with the pattern press the button to continue
- Now select the app you want to launch with the pattern.
- Note, you can bind multiple patterns to the same app.
- Manage created patterns (second entry)
- To manage your patterns first select "Manage Patterns"
- You will now see a scrollabe list of patterns + linked apps
- If you want to deletion a pattern (and unlink the app) simply tap on it, and confirm the deletion
- To manage your patterns first select "Manage Patterns"
- You will now see a scrollabe list of patterns + linked apps
- If you want to deletion a pattern (and unlink the app) simply tap on it, and confirm the deletion
- Disable the lock screen on the clock screen from the settings (third entry)
- To launch the app from the pattern on the clock screen the watch must be unlocked.
- If this annoys you, you can disable the lock on the clock screen from the setting here
- To launch the app from the pattern on the clock screen the watch must be unlocked.
- If this annoys you, you can disable the lock on the clock screen from the setting here

## FAQ

1) Nothing happens when I draw on the clock screen!
1. Nothing happens when I draw on the clock screen!

Please double-check if you actually have a pattern linked to an app.

2) I have a pattern linked to an app and still nothing happens when I draw on the clock screen!
2. I have a pattern linked to an app and still nothing happens when I draw on the clock screen!

Make sure the watch is unlocked before you start drawing. If this bothers you, you can permanently disable the watch-lock from within the Pattern Launcher app (via the Settings).

3) I have done all that and still nothing happens!
3. I have done all that and still nothing happens!

Please note that drawing on the clock screen will not visually show the pattern you drew. It will start the app as soon as the pattern was recognized - this might take 1 or 2 seconds! If still nothing happens, that might be a bug, sorry!

## Authors

Initial creation: [crazysaem](https://github.com/crazysaem)

Improve pattern detection code readability: [PaddeK](http://forum.espruino.com/profiles/117930/)

Improve pattern rendering: [HughB](http://forum.espruino.com/profiles/167235/)
Binary file modified apps/ptlaunch/add_pattern_dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified apps/ptlaunch/add_pattern_light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
214 changes: 49 additions & 165 deletions apps/ptlaunch/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,6 @@ var showMainMenu = () => {
E.showMenu(mainmenu);
};

var positions = [];
var recognizeAndDrawPattern = () => {
return new Promise((resolve) => {
E.showMenu();
Expand All @@ -135,150 +134,55 @@ var recognizeAndDrawPattern = () => {
resolve(pattern.join(""));
};
setWatch(() => finishHandler(), BTN);
setTimeout(() => Bangle.on("tap", finishHandler), 250);

positions = [];
var dragHandler = (position) => {
log(position);
positions.push(position);

debounce().then(() => {
if (isFinished) {
return;
}

// This might actually be a 'tap' event.
// Use this check in addition to the actual tap handler to make it more reliable
if (pattern.length > 0 && positions.length === 2) {
if (
positions[0].x === positions[1].x &&
positions[0].y === positions[1].y
) {
finishHandler();
positions = [];
return;
// setTimeout(() => Bangle.on("tap", finishHandler), 250);

var positions = [];
var getPattern = (positions) => {
var circles = [
{ x: 25, y: 25, i: 0 },
{ x: 87, y: 25, i: 1 },
{ x: 150, y: 25, i: 2 },
{ x: 25, y: 87, i: 3 },
{ x: 87, y: 87, i: 4 },
{ x: 150, y: 87, i: 5 },
{ x: 25, y: 150, i: 6 },
{ x: 87, y: 150, i: 7 },
{ x: 150, y: 150, i: 8 },
];
return positions.reduce((pattern, p, i, arr) => {
var idx = circles.findIndex((c) => {
var dx = p.x > c.x ? p.x - c.x : c.x - p.x;
if (dx > CIRCLE_RADIUS) {
return false;
}
}

E.showMessage("Calculating...");
var t0 = Date.now();

log(positions.length);

var circlesClone = cloneCirclesArray();
pattern = [];

var step = Math.floor(positions.length / 100) + 1;

var p, a, b, circle;

for (var i = 0; i < positions.length; i += step) {
p = positions[i];

circle = circlesClone[0];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(0, 1);
}
var dy = p.y > c.y ? p.y - c.y : c.y - p.y;
if (dy > CIRCLE_RADIUS) {
return false;
}

circle = circlesClone[1];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(1, 1);
}
}

circle = circlesClone[2];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(2, 1);
}
}

circle = circlesClone[3];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(3, 1);
}
}

circle = circlesClone[4];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(4, 1);
}
}

circle = circlesClone[5];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(5, 1);
}
}

circle = circlesClone[6];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(6, 1);
}
}
circle = circlesClone[7];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(7, 1);
}
}

circle = circlesClone[8];
if (circle) {
a = p.x - circle.x;
b = p.y - circle.y;
if (CIRCLE_RADIUS_2 - (a * a + b * b) >= 0) {
pattern.push(circle.i);
circlesClone.splice(8, 1);
}
if (dx + dy <= CIRCLE_RADIUS) {
return true;
}
return dx * dx + dy * dy <= CIRCLE_RADIUS_2;
});
if (idx >= 0) {
pattern += circles[idx].i;
circles.splice(idx, 1);
}
var tx = Date.now();
log(tx - t0);
positions = [];
var t1 = Date.now();
log(t1 - t0);

log("pattern:");
log(pattern);

log("redrawing");
if (circles.length === 0) {
arr.splice(1);
}
return pattern;
}, "");
};
var dragHandler = (position) => {
positions.push(position);
if (position.b === 0 || positions.length >= 200) {
pattern = getPattern(positions).split("");
g.clear();
drawCirclesWithPattern(pattern);
});
positions = [];
}
};

Bangle.on("drag", dragHandler);
});
};
Expand Down Expand Up @@ -488,7 +392,8 @@ var drawCircle = (circle, drawBuffer, scale) => {
log("drawing circle");
log({ x: x, y: y, r: r });

drawBuffer.drawCircle(x, y, r);
drawBuffer.setColor(0);
drawBuffer.fillCircle(x, y, r);
};

var cachedCirclesDrawings = {};
Expand Down Expand Up @@ -533,8 +438,11 @@ var drawCirclesWithPattern = (pattern, options) => {
{ msb: true }
);

CIRCLES.forEach((circle) => drawCircle(circle, drawBuffer, scale));
drawBuffer.setColor(1);
drawBuffer.fillRect(0, 0, drawBuffer.getWidth(), drawBuffer.getHeight());

CIRCLES.forEach((circle) => drawCircle(circle, drawBuffer, scale));
drawBuffer.setColor(1);
drawBuffer.setFontAlign(0, 0);
drawBuffer.setFont("Vector", 40 * scale);
pattern.forEach((circleIndex, patternIndex) => {
Expand All @@ -545,12 +453,12 @@ var drawCirclesWithPattern = (pattern, options) => {
circle.y * scale
);
});

image = {
width: drawBuffer.getWidth(),
height: drawBuffer.getHeight(),
bpp: 1,
buffer: drawBuffer.buffer,
palette: new Uint16Array([g.theme.fg, g.theme.bg], 0, 1),
};

if (enableCaching) {
Expand All @@ -563,16 +471,6 @@ var drawCirclesWithPattern = (pattern, options) => {
g.drawImage(image, offset.x, offset.y);
};

var cloneCirclesArray = () => {
var circlesClone = Array(CIRCLES.length);

for (var i = 0; i < CIRCLES.length; i++) {
circlesClone[i] = CIRCLES[i];
}

return circlesClone;
};

//////
// misc lib functions
//////
Expand All @@ -583,20 +481,6 @@ var log = (message) => {
}
};

var debounceTimeoutId;
var debounce = (delay) => {
if (debounceTimeoutId) {
clearTimeout(debounceTimeoutId);
}

return new Promise((resolve) => {
debounceTimeoutId = setTimeout(() => {
debounceTimeoutId = undefined;
resolve();
}, delay || 500);
});
};

//////
// run main function
//////
Expand Down
Loading

0 comments on commit 5105a7e

Please sign in to comment.