Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/taglaunch/ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
0.06: Fixed a crash if an app has no tags (app.tags is undefined)
0.07: Clear cached app list when updating showClocks setting
0.08: Add haptic feedback option when selecting app or category in menu, increase vector size limit in settings
0.09: Add option to set up to 3 shortcut apps that you can access straight from the tag menu for quicker access
5 changes: 3 additions & 2 deletions apps/taglaunch/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Tag Launcher
========

Based on the default launcher but puts all applications in a submenu by their tag.
Based on the default launcher but puts all applications in a submenu by their tag. There are three customizable spots at the top of the launcher for quicker access to your favorite apps.

With many applications installed this can result in a faster applications selection than the linear access of the default launcher.

Currently the following tags are supported: clock, game, tool, bluetooth, outdoors, health and misc.

Settings
--------

- `Shortcuts` - Change the app shortcuts at the top of the launcher. If no apps are set as the shortcut, the launcher will not have a section at the top, instead beginning with the first tag. (Default: No shortcuts)
- `Font` - The font used (`4x6`, `6x8`, `12x20`, `6x15` or `Vector`). Default `12x20`.
- `Vector Font Size` - The size of the font if `Font` is set to `Vector`. Default `10`.
- `Haptic Feedback` - Whether or not to vibrate slightly when selecting an app or category in the launcher. Default `No`.
Expand Down
59 changes: 47 additions & 12 deletions apps/taglaunch/app.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{ // must be inside our own scope here so that when we are unloaded everything disappears
let s = require("Storage");

// TODO: Allow to change sortorder in settings

let tags = {"clock": {name: /*LANG*/"Clocks", icon: () => atob("MDCEBERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERESIiIiIREREREREREREREREREREREREiIiIiIiIiIhERERERERERERERERERESIiIiIiIiIiIiIREREREREREREREREREiIiIiIiIiIiIiIhERERERERERERERESIiIiIgz//8ziIiIiIREREREREREREREiIiIg////////ziIiIhERERERERERERIiIiD//////////84iIiERERERERERESIiIg/////8A/////ziIiIRERERERERESIiI//////8A//////+IiIREREREREREiIiP//////8A///////4iIhERERERERIiIg///////8A///////ziIiERERERERIiIP///////8A////////OIiERERERESIiI////////8A////////+IiIRERERESIiD////////8A////////84iIRERERESIiP////////8A/////////4iIRERERESIiP////////8A/////////4iIREREREiIg/////////8A/////////ziIhEREREiIg/////////IAL////////ziIhEREREiIj////////yAAAv////////iIhEREREiIgiIv/////wCIAP/////yIiiIhEREREiIgiIv/////wCIAP/////yIiiIhEREREiIj////////yAAAD////////iIhEREREiIg/////////IAABP//////ziIhEREREiIg///////////IAE//////ziIhERERESIiP//////////8gAT/////4iIRERERESIiP///////////yABP////4iIRERERESIiD////////////IAL///84iIRERERESIiI////////////8i////+IiIRERERERIiIP/////////////////OIiERERERERIiIg////////////////ziIiEREREREREiIiP///////////////4iIhERERERERESIiI//////////////+IiIRERERERERESIiIg/////8i/////ziIiIRERERERERERIiIiD////8i////84iIiEREREREREREREiIiIg///8i///ziIiIhERERERERERERESIiIiIgz8i8ziIiIiIREREREREREREREREiIiIiIiIiIiIiIhERERERERERERERERESIiIiIiIiIiIiIREREREREREREREREREREiIiIiIiIiIhERERERERERERERERERERERESIiIiIRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERA==")},
"game": {name: /*LANG*/"Games", sortorder: 1, icon: () => atob("MDCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAzMzMzMzMzMzMzMzMzMzMzMwAAAAAAAAAzMzMzMzMzMzMzMzMzMzMzMwAAAAAAAAAzIiIiIiIiIiIiIiIiIiIiMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzIiIi////IiIi////IiIiMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi///yMwAAAAAAAAAzL///IiIi////IiIi8R/xERABEAAAAAAzL///IiIi////IiIi8R/xERABEAAAAAAzL///IiIi////IiIi8R/xERABEAAAAAAzL///IiIi////IiIi8RMxERABEAAAAAAzIiIi////IiIi////IREREREREAAAAAAzIiIi////IiIi////IREREREREAAAAAAzIiIi////IiIi////IREREREREAAAAAAzIiIi////IiIi////IhERERERAAAAAAAzIiIi////IiIi////IiMzMzMwAAAAAAAzIiIi////IiIi////IiMzMzMwAAAAAAAzL///IiIi////IiIi///xERAAAAAAAAAzL///IiIi////IiIi//8xERAAAAAAAAAzL///IiIi////IiIi//8hEREAAAAAAAAzL///IiIi////IiIi//8REREAAAAAAAAzL///IiIi////IiIi//MREREAAAAAAAAzIiIiIiIiIiIiIiIiIzMzMzMzMAAAAAAzMzMzMzMzMzMzMzMzMzMzMzMzMAAAAAAzMzMzMzMzMzMzMzMzMhEREREREAAAAAAAAAAAAAAAAAAAAAAAEREREREREQAAAAAAAAAAAAAAAAAAAAAAEREREREREQAAAAAAAAAAAAAAAAAAAAAAEREREREREQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")},
"tool": {name: /*LANG*/"Tools", sortorder: -1, icon: () => atob("MDCEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMwAAAAAAAAAAAAAAIiIgAAAAAAAAAAADMzMAAAAAAAAAAAAiIiIgAAAAAAAAAAADMzMwAAAAAAAAAAIiIiIAAAAAAAAAAAAAMzMzAAAAAAAAACIiIiAAAAAAAAAAAAAAMzMzMAAAAAAAACIiIgAAAAAAAAAAAAAAAzMzMAAAAAAAAiIiIAAAAAAAAAAAAAAAADMzMwAAAAAAAiIiIAAAAAIgAAAAAAAAAAMzMzAAAAAAAiIiIgAAACIgAAAAAAAAAAADMzMAAAAAAiIiIiAAAiIgAAAAAAAAAAAAMzMwAAAAAiIiIiIAIiIgAAAAAAAAAAAAAzMzAAAAACIiIiIiIiIgAAAAAAAAAAAAADMzMAAAAiIiIiIiIiIAAAAAAAAAAAAAAAMzMwDdQiIiIiIiIiIAAAAAAAAAAAAAAAAzMz3d0iIiIiIiIiAAAAAAAAAAAAAAAAADM93d1CIiIiIiIgAAAAAAAAAAAAAAAAAAPd3d3iIiACIiAAAAAAAAAAAAAAAAAAAA3d3d7kIgAAAAAAAAAAAAAAAAAAAAAAAN3d3e7uQAAAAAAAAAAAAAAAAAAAAAAAAN3d3u7u4AAAAAAAAAAAAAAAAAAAAAAAAC3d7u7u7gAAAAAAAAAAAAAAAAAAAAAAAiJO7u7u7uAAAAAAAAAAAAAAAAAAAAAAIiIiTu7u7u7gAAAAAAAAAAAAAAAAAAACIiIiIu7u7u7uAAAAAAAAAAAAAAAAAAAiIiIiIA7u7u7u4AAAAAAAAAAAAAAAAAIiIiIiAADu7u7u7uAAAAAAAAAAAAAAACIiIiIgAAAO7u7u7u4AAAAAAAAAAAAAAiIiIiIAAAAO7u7u7u7gAAAAAAAAAAAAIiIiIiAAAAAA7u7u7u7uAAAAAAAAAAAiIiIiIgAAAAAADu7u7u7u4AAAAAAAAAIiIiIiIAAAAAAAAO7u7u7u7gAAAAAAAAIiIiIiAAAAAAAAAO7u7u7u7gAAAAAAACIgAiIgAAAAAAAAAA7u7u7u7gAAAAAAACIgAiIAAAAAAAAAAADu7u7u7gAAAAAAACIiIiIAAAAAAAAAAAAO7u7u4AAAAAAAAAIiIiAAAAAAAAAAAAAO7u7uAAAAAAAAAAAiIAAAAAAAAAAAAAAADu7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")},
Expand All @@ -18,7 +18,8 @@ let font = g.getFonts().includes("12x20") ? "12x20" : "6x8:2";
let settings = Object.assign({
showClocks: true,
fullscreen: false,
buzz:false
buzz:false,
shortcuts:["","",""]
}, s.readJSON("taglaunch.json", true) || {});
if ("vectorsize" in settings)
vectorval = parseInt(settings.vectorsize);
Expand Down Expand Up @@ -84,6 +85,15 @@ const unload = () => {
Bangle.removeListener("lock", lockHandler);
};

let shortcuts=settings.shortcuts;
let noShortcuts=shortcuts[0]==""&&shortcuts[1]==""&&shortcuts[2]=="";

let loadShortcut=function(idx){
if(shortcuts[idx]!=""){
if(settings.buzz)Bangle.buzz(25);
load(shortcuts[idx]+".app.js");
}
};
// 10s of inactivity goes back to clock
Bangle.setLocked(false); // unlock initially
let lockTimeout;
Expand Down Expand Up @@ -137,21 +147,46 @@ let showTagMenu = (tag) => {

let showMainMenu = () => {
E.showScroller({
h : 64*scaleval, c : tagKeys.length,
h : 64*scaleval, c : noShortcuts ? tagKeys.length : tagKeys.length+1,
draw : (i, r) => {
let tag = tagKeys[i];
g.clearRect((r.x),(r.y),(r.x+r.w-1), (r.y+r.h-1));
g.setFont(font).setFontAlign(-1,0).drawString(tags[tag].name,64*scaleval,r.y+(32*scaleval));

if(!noShortcuts)i-=1;
if(i==-1){
for(let j=0;j<3;j++){
const img = s.read(shortcuts[j]+".img");
if (img) {
try {
g.drawImage(img,8*scaleval+((g.getWidth()/3)*j), r.y+(8*scaleval), {scale: scaleval});}
catch(e){}
}
}

const img = tags[tag].icon ? tags[tag].icon() : s.read("taglaunch." + tag + ".img");
if (img) {
try {g.drawImage(img,8*scaleval, r.y+(8*scaleval), {scale: scaleval});} catch(e){}

}else{
let tag = tagKeys[i]; g.setFont(font).setFontAlign(-1,0).drawString(tags[tag].name,64*scaleval,r.y+(32*scaleval));

const img = tags[tag].icon ? tags[tag].icon() : s.read("taglaunch." + tag + ".img");
if (img) {
try {g.drawImage(img,8*scaleval, r.y+(8*scaleval), {scale: scaleval});} catch(e){}
}
}
},
select : i => {
if(settings.buzz)Bangle.buzz(25);
let tag = tagKeys[i];
showTagMenu(tag);
select : (i,e) => {
if(!noShortcuts)i-=1;
if(i==-1){
if(e.x<g.getWidth()/3){
loadShortcut(0)
}else if(e.x<(g.getWidth()/3)*2){
loadShortcut(1)
}else{
loadShortcut(2)
}
}else{
if(settings.buzz)Bangle.buzz(25);
let tag = tagKeys[i];
showTagMenu(tag);
}
},
back : Bangle.showClock, // button press or tap in top left shows clock now
remove : unload
Expand Down
6 changes: 3 additions & 3 deletions apps/taglaunch/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"id": "taglaunch",
"name": "Tag Launcher",
"shortName": "Taglauncher",
"version": "0.08",
"version": "0.09",
"author": "nxdefiant",
"description": "Launcher that puts all applications into submenus based on their tag. With many applications installed this can result in a faster application selection than the linear access from the default launcher.",
"description": "Launcher that puts all applications into submenus based on their tag, with three customizable app shortcuts at the top. With many applications installed this can result in a faster application selection than the linear access from the default launcher.",
"readme": "README.md",
"icon": "app.png",
"type": "launch",
"tags": "tool,system,launcher",
"supports": ["BANGLEJS2"],
"screenshots": [ {"url":"screenshot.png"} ],
"screenshots": [ {"url":"screenshot.png"},{"url":"screenshot2.png"} ],
"storage": [
{"name":"taglaunch.app.js","url":"app.js"},
{"name":"taglaunch.settings.js","url":"settings.js"}
Expand Down
Binary file added apps/taglaunch/screenshot2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
90 changes: 88 additions & 2 deletions apps/taglaunch/settings.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,105 @@
// make sure to enclose the function in parentheses
(function(back) {

let launchCache;
let settings = Object.assign({
showClocks: true,
fullscreen: false,
buzz:false
buzz:false,
shortcuts:["","",""]
}, require("Storage").readJSON("taglaunch.json", true) || {});

let fonts = g.getFonts();
function save(key, value) {
settings[key] = value;
require("Storage").write("taglaunch.json",settings);
}

function setShortcut(id,spot,bk){
let shortcuts=settings.shortcuts;
shortcuts[spot]=id;
save("shortcuts",shortcuts);
bk();
}

function showAppList(spot,bk){
//make sure cache is present
launchCache=require("Storage").readJSON("taglaunch.cache.json");
if (!launchCache || !launchCache.appsByTag) {
E.showAlert("Caching apps, returning to launcher","Loading").then(function(v){
Bangle.load("taglaunch.app.js");
});
} else {
var appsByTag = launchCache.appsByTag;
var appsById = {};
for (var tag in appsByTag) {
var list = appsByTag[tag];
for (var i = 0; i < list.length; i++) {
var app = list[i];
// Use app.id as key to deduplicate
if (!appsById[app.id]) {
appsById[app.id] = {
name: app.name,
src: app.src || app.name,
id: app.id
};
}
}
}
var apps = Object.values(appsById);

var menu = {};
var spotText="";
if(spot==0)spotText+="Left ";
if(spot==1)spotText+="Center ";
if(spot==2)spotText+="Right ";
spotText+="App";
menu[""] = { "title" : spotText }; // Title for the menu

menu["None"] = function(){

E.showPrompt("Remove the "+spotText+" shortcut?",{
title:"Confirm",
buttons: {"Cancel":false,"Ok":true}
}).then(function(v){
if(v)setShortcut("",spot,bk);
else showAppList(spot,bk)
})
}
apps.forEach(a => {
menu[a.name] = function(){
E.showPrompt("Set "+a.name+" as the "+spotText+"?",{
title:"Confirm",
buttons: {"Cancel":false,"Ok":true}
}).then(function(v){
if(v)setShortcut(a.id,spot,bk);
else showAppList(spot,bk)
})
}
});
menu["< Back"] = bk;

// Show it
E.showMenu(menu);
}
}

function showSpotMenu(){
E.showMenu({
"":{ "title" : "Select Spot"}, // Title for the menu
"< Back":function(){
eval(require("Storage").read("taglaunch.settings.js"))(()=>load());
},
"Left": function() { showAppList(0,showSpotMenu); },
"Center": function() { showAppList(1,showSpotMenu); },
"Right": function() { showAppList(2,showSpotMenu);}
})
}
const appMenu = {
"": { "title": /*LANG*/"Tag Launcher" },
"< Back": back,
/*LANG*/"Shortcuts": function(){
showSpotMenu()
},
/*LANG*/"Font": {
value: fonts.includes(settings.font)? fonts.indexOf(settings.font) : fonts.indexOf("12x20"),
min:0, max:fonts.length-1, step:1,wrap:true,
Expand Down