mirror of https://github.com/espruino/BangleApps
messagelist: new app
parent
487742f037
commit
bc3ab8ef76
|
@ -0,0 +1 @@
|
|||
0.01: New app!
|
|
@ -0,0 +1,69 @@
|
|||
# Message List
|
||||
|
||||
Display messages inline as a single list:
|
||||
Displays one message at a time, if it doesn't fit on the screen you can scroll
|
||||
up/down. When you reach the bottom, you can scroll on to the next message.
|
||||
|
||||
## Installation
|
||||
**First** uninstall the default [Message UI](/?id=messagegui) app (`messagegui`,
|
||||
not the library!).
|
||||
Then install this app.
|
||||
|
||||
## Screenshots
|
||||
|
||||
### Main menu:
|
||||

|
||||
|
||||
### Unread message:
|
||||

|
||||
The chevrons are hints for swipe actions:
|
||||
- Swipe right to go back
|
||||
- Swipe left for the message-actions menu
|
||||
- Swipe down to show the previous message: We are currently viewing message 2 of 2,
|
||||
so message 1 is "above" this one.
|
||||
|
||||
### Long (read) message:
|
||||

|
||||
The button is disabled until you scroll all the way to the bottom.
|
||||
|
||||
### Music:
|
||||

|
||||
Minimal setup: album name and buttons disabled through settings.
|
||||
Swipe for next/previous song, tap to pause/resume.
|
||||
|
||||
## Settings
|
||||
|
||||
### Interface
|
||||
* `Font size` - The font size used when displaying messages/music.
|
||||
* `On Tap` - If messages are too large to fit on the screen, tapping the screen scrolls down.
|
||||
This is the action to take when tapping a message after reaching the bottom:
|
||||
- `Message menu`: Open menu with message actions
|
||||
- `Dismiss`: Dismiss message right away
|
||||
- `Back`: Go back to clock/main menu
|
||||
- `Nothing`: Do nothing
|
||||
* `Dismiss button` - Show inline button to dismiss message right away
|
||||
|
||||
### Behaviour
|
||||
* `Vibrate` - The pattern of buzzes when a new message is received.
|
||||
* `Vibrate for calls` - The pattern of buzzes for incoming calls.
|
||||
* `Vibrate for alarms` - The pattern of buzzes for (phone) alarms.
|
||||
* `Repeat` - How often buzzes repeat - the default of 4 means the Bangle will buzz every 4 seconds.
|
||||
* `Unread timer` - When a new message is received the Messages app is opened.
|
||||
If there is no user input for this amount of time then the app will exit and return to the clock.
|
||||
* `Auto-open` - Automatically open app when a new message arrives.
|
||||
* `Respect quiet mode` - Prevent auto-opening during quiet mode.
|
||||
|
||||
### Music
|
||||
* `Auto-open` - Automatically open app when music starts playing.
|
||||
* `Always visible` - Show "music" in the main menu even when nothing is playing.
|
||||
* `Buttons` - Show `previous`/`play/pause`/`next` buttons on music screen.
|
||||
* `Show album` - Display album names?
|
||||
|
||||
|
||||
### Util
|
||||
* `Delete all` - Erase all messages.
|
||||
|
||||
|
||||
## Attributions
|
||||
|
||||
Some icons used in this app are from https://icons8.com
|
|
@ -0,0 +1,17 @@
|
|||
## Nice to have:
|
||||
* Add labels to B1 music HW buttons
|
||||
* Add volume buttons to B2 music screen (when controls are enabled)
|
||||
* Draw messages ourselves instead of piling hacks on Layout
|
||||
* Make sure all icons are 24x24px: icon sizes affect layout
|
||||
* Check/optimize layout for B1, other fonts (scrolling for just 5px is a shame)
|
||||
|
||||
## Wishlist:
|
||||
* Option to swipe-dismiss (instead of action menu)
|
||||
* Maybe refactor showGrid() out into a general-use module?
|
||||
|
||||
* Message replies (needs `android` support)
|
||||
* Customize replies
|
||||
* Custom replies (i.e. `textinput`)
|
||||
* Hooks to add custom replies/actions,
|
||||
e.g. external code could add "Send intent" option to Home Assistant messages
|
||||
Maybe just use this for all replies, so we don't hardcode anything in "messages"?
|
|
@ -0,0 +1 @@
|
|||
require("heatshrink").decompress(atob("mEw4UA///rkcAYP9ohL/ABMBqoAEoALDioLFqgLDBQoABERIkEBZcFBY9QBed61QAC1oLF7wLD24LF24LD7wLF1vqBQOrvQLFA4IuC9QLFD4IuC1QLGGAQOBBYwgBEwQLHvQBBEZHVq4jI7wWBHY5TLNZaDLTZazLffMBBY9ABZsABY4KCgEVBQtUBYYkGEQYA/AAwA="))
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 8.8 KiB |
|
@ -0,0 +1,3 @@
|
|||
(function() {
|
||||
Bangle.on("message", require("messagegui").messageListener);
|
||||
})();
|
|
@ -0,0 +1,246 @@
|
|||
// Handle incoming messages while the app is not loaded
|
||||
// The messages app overrides Bangle.messageListener
|
||||
// (placed in separate file, so we don't read this all at boot time)
|
||||
exports.messageListener = function(type, msg) {
|
||||
if (msg.handled || (global.__FILE__ && __FILE__.startsWith("messagelist."))) return; // already handled/app open
|
||||
// clean up, in case previous message didn't load the app after all
|
||||
if (exports.loadTimeout) clearTimeout(exports.loadTimeout);
|
||||
delete exports.loadTimeout;
|
||||
delete exports.buzz;
|
||||
const quiet = () => (require("Storage").readJSON("setting.json", 1) || {}).quiet;
|
||||
/**
|
||||
* Quietly load the app for music/map, if not already loading
|
||||
*/
|
||||
function loadQuietly(msg) {
|
||||
if (exports.loadTimeout) return; // already loading
|
||||
exports.loadTimeout = setTimeout(function() {
|
||||
Bangle.load("messagelist.app.js");
|
||||
}, 500);
|
||||
}
|
||||
function loadNormal(msg) {
|
||||
if (exports.loadTimeout) clearTimeout(exports.loadTimeout); // restart timeout
|
||||
exports.loadTimeout = setTimeout(function() {
|
||||
delete exports.loadTimeout;
|
||||
// check there are still new messages (for #1362)
|
||||
let messages = require("messages").getMessages(msg);
|
||||
(Bangle.MESSAGES || []).forEach(m => require("messages").apply(m, messages));
|
||||
if (!messages.some(m => m.new)) return; // don't use `status()`: also load for new music!
|
||||
// if we're in a clock, or it's important, open app
|
||||
if (Bangle.CLOCK || msg.important) {
|
||||
if (exports.buzz) require("messages").buzz(msg.src);
|
||||
Bangle.load("messagelist.app.js");
|
||||
}
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark message as handled, and save it for the app
|
||||
*/
|
||||
const handled = () => {
|
||||
if (!Bangle.MESSAGES) Bangle.MESSAGES = [];
|
||||
require("messages").apply(msg, Bangle.MESSAGES);
|
||||
if (!Bangle.MESSAGES.length) delete Bangle.MESSAGES;
|
||||
if (msg.t==="remove") require("messages").save(msg);
|
||||
else msg.handled = true;
|
||||
};
|
||||
/**
|
||||
* Write messages to flash after all, when not laoding the app
|
||||
*/
|
||||
const saveToFlash = () => {
|
||||
(Bangle.MESSAGES||[]).forEach(m=>require("messages").save(m));
|
||||
delete Bangle.MESSAGES;
|
||||
}
|
||||
|
||||
switch(type) {
|
||||
case "music":
|
||||
if (!Bangle.CLOCK) return;
|
||||
// only load app if we are playing, and we know which song
|
||||
if (msg.state!=="play" || !msg.title) return;
|
||||
if (exports.openMusic===undefined) {
|
||||
// only read settings for first music message
|
||||
exports.openMusic = !!(exports.settings().openMusic);
|
||||
}
|
||||
if (!exports.openMusic) return; // we don't care about music
|
||||
if (quiet()) return;
|
||||
msg.new = true;
|
||||
handled();
|
||||
return loadQuietly();
|
||||
|
||||
case "map":
|
||||
handled();
|
||||
if (msg.t!=="remove" && Bangle.CLOCK) loadQuietly();
|
||||
else saveToFlash();
|
||||
return;
|
||||
|
||||
case "text":
|
||||
handled();
|
||||
if (exports.settings().autoOpen===false) return saveToFlash();
|
||||
if (quiet()) return saveToFlash();
|
||||
if (msg.t!=="add" || !msg.new || !(Bangle.CLOCK || msg.important)) {
|
||||
// not important enough to load the app
|
||||
if (msg.t==="add" && msg.new) require("messages").buzz(msg);
|
||||
return saveToFlash();
|
||||
}
|
||||
if (msg.t==="add" && msg.new) exports.buzz = true;
|
||||
return loadNormal(msg);
|
||||
|
||||
case "alarm":
|
||||
if (quiet()<2) return saveToFlash();
|
||||
// fall through
|
||||
case "call":
|
||||
handled();
|
||||
exports.buzz = true;
|
||||
return loadNormal(msg);
|
||||
|
||||
// case "clearAll": do nothing
|
||||
}
|
||||
};
|
||||
|
||||
exports.settings = function() {
|
||||
return Object.assign({
|
||||
// Interface //
|
||||
fontSize: 1,
|
||||
onTap: 0, // [Message menu, Dismiss, Back, Nothing]
|
||||
button: true,
|
||||
|
||||
// Behaviour //
|
||||
vibrate: ":",
|
||||
vibrateCalls: ":",
|
||||
vibrateAlarms: ":",
|
||||
repeat: 4,
|
||||
vibrateTimeout: 60,
|
||||
unreadTimeout: 60,
|
||||
autoOpen: true,
|
||||
|
||||
// Music //
|
||||
openMusic: true,
|
||||
// no default: alwaysShowMusic (auto-enabled by app when music happens)
|
||||
showAlbum: true,
|
||||
musicButtons: false,
|
||||
|
||||
// Widget //
|
||||
flash: true,
|
||||
// showRead: false,
|
||||
|
||||
// Utils //
|
||||
},
|
||||
// fall back to default app settings if not set for messagelist
|
||||
(require("Storage").readJSON("messages.settings.json", true) || {}),
|
||||
(require("Storage").readJSON("messagelist.settings.json", true) || {}));
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} icon Icon name
|
||||
* @returns string Icon image string, for use with g.drawImage()
|
||||
*/
|
||||
exports.getIcon = function(icon) {
|
||||
// TODO: icons should be 24x24px with 1bpp colors
|
||||
switch(icon.toLowerCase()) {
|
||||
// generic icons:
|
||||
case "alert":
|
||||
return atob("GBgBAAAAAP8AA//AD8PwHwD4HBg4ODwcODwccDwOcDwOYDwGYDwGYBgGYBgGcBgOcAAOOBgcODwcHDw4Hxj4D8PwA//AAP8AAAAA");
|
||||
case "alarm":
|
||||
case "alarmclockreceiver":
|
||||
return atob("GBjBAP////8AAAAAAAACAEAHAOAefng5/5wTgcgHAOAOGHAMGDAYGBgYGBgYGBgYGBgYDhgYBxgMATAOAHAHAOADgcAB/4AAfgAAAAAAAAA=");
|
||||
case "back": // TODO: 22x22
|
||||
return atob("FhYBAAAAEAAAwAAHAAA//wH//wf//g///BwB+DAB4EAHwAAPAAA8AADwAAPAAB4AAHgAB+AH/wA/+AD/wAH8AA==");
|
||||
case "calendar":
|
||||
return atob("GBiBAAAAAAAAAAAAAA//8B//+BgAGBgAGBgAGB//+B//+B//+B9m2B//+B//+Btm2B//+B//+Btm+B//+B//+A//8AAAAAAAAAAAAA==");
|
||||
case "mail": // TODO: 28x18
|
||||
case "sms message":
|
||||
case "notification":
|
||||
return atob("HBKBAD///8H///iP//8cf//j4//8f5//j/x/8//j/H//H4//4PB//EYj/44HH/Hw+P4//8fH//44///xH///g////A==");
|
||||
case "map": // TODO: 25x25,
|
||||
return atob("GRmBAAAAAAAAAAAAAAIAYAHx/wH//+D/+fhz75w/P/4f//8P//uH///D///h3f/w4P+4eO/8PHZ+HJ/nDu//g///wH+HwAYAIAAAAAAAAAAAAAA=");
|
||||
case "menu":
|
||||
return atob("GBiBAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAAAAAP///////wAAAAAAAAAAAAAAAA==");
|
||||
case "music": // TODO: 22x22
|
||||
return atob("FhaBAH//+/////////////h/+AH/4Af/gB/+H3/7/f/v9/+/3/7+f/vB/w8H+Dwf4PD/x/////////////3//+A=");
|
||||
case "nak": // TODO: 22x25
|
||||
return atob("FhmBAA//wH//j//+P//8///7///v//+///7//////////////v//////////z//+D8AAPwAAfgAB+AAD4AAPgAAeAAB4AAHAAA==");
|
||||
case "neg": // TODO: 22x22
|
||||
return atob("FhaBADAAMeAB78AP/4B/fwP4/h/B/P4D//AH/4AP/AAf4AB/gAP/AB/+AP/8B/P4P4fx/A/v4B//AD94AHjAAMA=");
|
||||
case "next":
|
||||
return atob("GBiBAAAAAAAAAAAAAAwAcB8A+B+A+B/g+B/4+B/8+B//+B//+B//+B//+B//+B//+B/8+B/4+B/g+B+A+B8A+AwAcAAAAAAAAAAAAA==");
|
||||
case "nophone": // TODO: 30x30
|
||||
return atob("Hh6BAAAAAAGAAAAHAAAADgAAABwADwA4Af8AcA/8AOB/+AHH/+ADv/8AB//wAA/HAAAeAAACOAAADHAAAHjgAAPhwAAfg4AAfgcAAfwOAA/wHAA/wDgA/gBwA/gA4AfAAcAfAAOAGAAHAAAADgAAABgAAAAA");
|
||||
case "ok": // TODO: 22x25
|
||||
return atob("FhmBAAHAAAeAAB4AAPgAA+AAH4AAfgAD8AAPwAD//+//////////////7//////////////v//+///7///v//8///gf/+A//wA==");
|
||||
case "pause":
|
||||
return atob("GBiBAAAAAAAAAAAAAAOBwAfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AfD4AOBwAAAAAAAAAAAAA==");
|
||||
case "phone": // TODO: 23x23
|
||||
case "call":
|
||||
return atob("FxeBABgAAPgAAfAAB/AAD+AAH+AAP8AAP4AAfgAA/AAA+AAA+AAA+AAB+AAB+AAB+OAB//AB//gB//gA//AA/8AAf4AAPAA=");
|
||||
case "play":
|
||||
return atob("GBiBAAAAAAAAAAAAAAcAAA+AAA/gAA/4AA/8AA//AA//wA//4A//8A//8A//4A//wA//AA/8AA/4AA/gAA+AAAcAAAAAAAAAAAAAAA==");
|
||||
case "pos": // TODO: 25x20
|
||||
return atob("GRSBAAAAAYAAAcAAAeAAAfAAAfAAAfAAAfAAAfAAAfBgAfA4AfAeAfAPgfAD4fAA+fAAP/AAD/AAA/AAAPAAADAAAA==");
|
||||
case "previous":
|
||||
return atob("GBiBAAAAAAAAAAAAAA4AMB8A+B8B+B8H+B8f+B8/+B//+B//+B//+B//+B//+B//+B8/+B8f+B8H+B8B+B8A+A4AMAAAAAAAAAAAAA==");
|
||||
case "settings": // TODO: 20x20
|
||||
return atob("FBSBAAAAAA8AAPABzzgf/4H/+A//APnwfw/n4H5+B+fw/g+fAP/wH/+B//gc84APAADwAAAA");
|
||||
case "to do":
|
||||
return atob("GBgBAAAAAAAAAAAwAAB4AAD8AAH+AAP/DAf/Hg//Px/+f7/8///4///wf//gP//AH/+AD/8AB/4AA/wAAfgAAPAAAGAAAAAAAAAA");
|
||||
case "trash":
|
||||
return atob("GBiBAAAAAAAAAAB+AA//8A//8AYAYAYAYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAZmYAYAYAYAYAf/4AP/wAAAAAAAAA==");
|
||||
case "unknown": // TODO: 30x30
|
||||
return atob("Hh6BAAAAAAAAAAAAAAAAAAPwAAA/8AAB/+AAD//AAD4fAAHwPgAHwPgAAAPgAAAfAAAA/AAAD+AAAH8AAAHwAAAPgAAAPgAAAPgAAAAAAAAAAAAAAAAAAHAAAAPgAAAPgAAAPgAAAHAAAAAAAAAAAAAAAAAA");
|
||||
case "unread": // TODO: 29x24
|
||||
return atob("HRiBAAAAH4AAAf4AAB/4AAHz4AAfn4AA/Pz/5+fj/z8/j/n5/j/P//j/Pn3j+PPPx+P8fx+Pw/x+AF/B4A78RiP3xwOPvHw+Pcf/+Ox//+NH//+If//+B///+A==");
|
||||
default: //should never happen
|
||||
return exports.getIcon("unknown");
|
||||
}
|
||||
};
|
||||
/**
|
||||
* @param {string} icon Icon
|
||||
* @returns {string} Color to use with g.setColor()
|
||||
*/
|
||||
exports.getColor = function(icon) {
|
||||
switch(icon.toLowerCase()) {
|
||||
// generic colors, using B2-safe colors
|
||||
case "alert":
|
||||
return "#ff0";
|
||||
case "alarm":
|
||||
return "#fff";
|
||||
case "calendar":
|
||||
return "#f00";
|
||||
case "mail":
|
||||
return "#ff0";
|
||||
case "map":
|
||||
return "#f0f";
|
||||
case "music":
|
||||
return "#f0f";
|
||||
case "neg":
|
||||
return "#f00";
|
||||
case "notification":
|
||||
return "#0ff";
|
||||
case "phone":
|
||||
case "call":
|
||||
return "#0f0";
|
||||
case "settings":
|
||||
return "#000";
|
||||
case "sms message":
|
||||
return "#0ff";
|
||||
case "trash":
|
||||
return "#f00";
|
||||
case "unknown":
|
||||
return g.theme.fg;
|
||||
case "unread":
|
||||
return "#ff0";
|
||||
default:
|
||||
return g.theme.fg;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Launch GUI app with given message
|
||||
* @param {object} msg
|
||||
*/
|
||||
exports.open = function(msg) {
|
||||
if (msg && msg.id && !msg.show) {
|
||||
// store which message to load
|
||||
msg.show = 1;
|
||||
}
|
||||
|
||||
Bangle.load((msg && msg.new && msg.id!=="music") ? "messagelist.new.js" : "messagelist.app.js");
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"id": "messagelist",
|
||||
"name": "Message List",
|
||||
"version": "0.01",
|
||||
"description": "Display notifications from iOS and Gadgetbridge/Android as a list",
|
||||
"icon": "app.png",
|
||||
"type": "app",
|
||||
"tags": "tool,system",
|
||||
"screenshots": [
|
||||
{"url": "screenshot0.png"},
|
||||
{"url": "screenshot1.png"},
|
||||
{"url": "screenshot2.png"},
|
||||
{"url": "screenshot3.png"}
|
||||
],
|
||||
"supports": ["BANGLEJS","BANGLEJS2"],
|
||||
"dependencies" : { "messageicons":"module" },
|
||||
"provides_modules": ["messagegui"],
|
||||
"readme": "README.md",
|
||||
"storage": [
|
||||
{"name":"messagelist.boot.js","url":"boot.js"},
|
||||
{"name":"messagegui","url":"lib.js"},
|
||||
{"name":"messagelist.app.js","url":"app.js"},
|
||||
{"name":"messagelist.settings.js","url":"settings.js"},
|
||||
{"name":"messagelist.img","url":"app-icon.js","evaluate":true}
|
||||
],
|
||||
"data": [{"name":"messagelist.settings.json"}],
|
||||
"sortorder": -9
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,139 @@
|
|||
(function(back) {
|
||||
let settings = require("messagegui").settings();
|
||||
const inApp = (global.__FILE__ && __FILE__.startsWith("messagelist."));
|
||||
|
||||
function updateSetting(setting, value) {
|
||||
settings[setting] = value;
|
||||
let file;
|
||||
switch(setting) {
|
||||
case "flash":
|
||||
case "showRead":
|
||||
case "iconColorMode":
|
||||
case "maxMessages":
|
||||
case "maxUnreadTimeout":
|
||||
case "openMusic":
|
||||
case "repeat":
|
||||
case "unlockWatch":
|
||||
case "unreadTimeout":
|
||||
case "vibrate":
|
||||
case "vibrateCalls":
|
||||
case "vibrateTimeout":
|
||||
// Default app has this setting: update that file
|
||||
file = "messages";
|
||||
break;
|
||||
default:
|
||||
// write to our own settings file
|
||||
file = "messagelist";
|
||||
}
|
||||
file += ".settings.json";
|
||||
let saved = require("Storage").readJSON(file, true) || {};
|
||||
saved[setting] = value;
|
||||
require("Storage").writeJSON(file, saved);
|
||||
}
|
||||
|
||||
function toggler(setting) {
|
||||
return {
|
||||
value: !!settings[setting],
|
||||
onchange: v => updateSetting(setting, v)
|
||||
};
|
||||
}
|
||||
|
||||
function showIfMenu() {
|
||||
const tapOptions = [/*LANG*/"Message menu",/*LANG*/"Dismiss",/*LANG*/"Back",/*LANG*/"Nothing"];
|
||||
E.showMenu({
|
||||
"": {"title": /*LANG*/"Interface"},
|
||||
"< Back": () => showMainMenu(),
|
||||
/*LANG*/"Font size": {
|
||||
value: 0|settings.fontSize,
|
||||
min: 0, max: 2,
|
||||
format: v => [/*LANG*/"Small",/*LANG*/"Medium",/*LANG*/"Large",/*LANG*/"Huge"][v],
|
||||
onchange: v => updateSetting("fontSize", v)
|
||||
},
|
||||
/*LANG*/"On Tap": {
|
||||
value: settings.onTap,
|
||||
min: 0, max: tapOptions.length-1, wrap: true,
|
||||
format: v => tapOptions[v],
|
||||
onchange: v => updateSetting("onTap", v)
|
||||
},
|
||||
/*LANG*/"Dismiss button": toggler("button"),
|
||||
});
|
||||
}
|
||||
|
||||
function showBMenu() {
|
||||
E.showMenu({
|
||||
"": {"title": /*LANG*/"Behaviour"},
|
||||
"< Back": () => showMainMenu(),
|
||||
/*LANG*/"Vibrate": require("buzz_menu").pattern(settings.vibrate, v => updateSetting("vibrate", v)),
|
||||
/*LANG*/"Vibrate for calls": require("buzz_menu").pattern(settings.vibrateCalls, v => updateSetting("vibrateCalls", v)),
|
||||
/*LANG*/"Vibrate for alarms": require("buzz_menu").pattern(settings.vibrateAlarms, v => updateSetting("vibrateAlarms", v)),
|
||||
/*LANG*/"Repeat": {
|
||||
value: settings.repeat,
|
||||
min: 0, max: 10,
|
||||
format: v => v ? v+"s" :/*LANG*/"Off",
|
||||
onchange: v => updateSetting("repeat", v)
|
||||
},
|
||||
/*LANG*/"Vibrate timer": {
|
||||
value: settings.vibrateTimeout,
|
||||
min: 0, max: 240, step: 10,
|
||||
format: v => v ? v+"s" :/*LANG*/"Forever",
|
||||
onchange: v => updateSetting("vibrateTimeout", v)
|
||||
},
|
||||
/*LANG*/"Unread timer": {
|
||||
value: settings.unreadTimeout,
|
||||
min: 0, max: 240, step: 10,
|
||||
format: v => v ? v+"s" :/*LANG*/"Off",
|
||||
onchange: v => updateSetting("unreadTimeout", v)
|
||||
},
|
||||
/*LANG*/"Auto-open": toggler("autoOpen"),
|
||||
});
|
||||
}
|
||||
|
||||
function showMusicMenu() {
|
||||
E.showMenu({
|
||||
"": {"title": /*LANG*/"Music"},
|
||||
"< Back": () => showMainMenu(),
|
||||
/*LANG*/"Auto-open": toggler("openMusic"),
|
||||
/*LANG*/"Always visible": toggler("alwaysShowMusic"),
|
||||
/*LANG*/"Buttons": toggler("musicButtons"),
|
||||
/*LANG*/"Show album": toggler("showAlbum"),
|
||||
});
|
||||
}
|
||||
|
||||
function showWidMenu() {
|
||||
E.showMenu({
|
||||
"": {"title": /*LANG*/"Widget"},
|
||||
"< Back": () => showMainMenu(),
|
||||
/*LANG*/"Flash icon": toggler("flash"),
|
||||
// /*LANG*/"Show Read": toggler("showRead"),
|
||||
});
|
||||
}
|
||||
|
||||
function showUtilsMenu() {
|
||||
let m = E.showMenu({
|
||||
"": {"title": /*LANG*/"Utilities"},
|
||||
"< Back": () => showMainMenu(),
|
||||
/*LANG*/"Delete all": () => {
|
||||
E.showPrompt(/*LANG*/"Are you sure?",
|
||||
{title:/*LANG*/"Delete All Messages"})
|
||||
.then(isYes => {
|
||||
if (isYes) require("messages").write([]);
|
||||
showUtilsMenu();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showMainMenu() {
|
||||
E.showMenu({
|
||||
"": {"title": inApp ?/*LANG*/"Settings" :/*LANG*/"Messages"},
|
||||
"< Back": back,
|
||||
/*LANG*/"Interface": () => showIfMenu(),
|
||||
/*LANG*/"Behaviour": () => showBMenu(),
|
||||
/*LANG*/"Music": () => showMusicMenu(),
|
||||
/*LANG*/"Widget": () => showWidMenu(),
|
||||
/*LANG*/"Utils": () => showUtilsMenu(),
|
||||
});
|
||||
}
|
||||
|
||||
showMainMenu();
|
||||
});
|
|
@ -94,6 +94,7 @@ const INTERNAL_FILES_IN_APP_TYPE = { // list of app types and files they SHOULD
|
|||
var KNOWN_WARNINGS = [
|
||||
"App gpsrec data file wildcard .gpsrc? does not include app ID",
|
||||
"App owmweather data file weather.json is also listed as data file for app weather",
|
||||
"App messagegui storage file messagegui is also listed as storage file for app messagelist",
|
||||
];
|
||||
|
||||
function globToRegex(pattern) {
|
||||
|
|
Loading…
Reference in New Issue