diff --git a/apps/contacts/ChangeLog b/apps/contacts/ChangeLog new file mode 100644 index 000000000..5560f00bc --- /dev/null +++ b/apps/contacts/ChangeLog @@ -0,0 +1 @@ +0.01: New App! diff --git a/apps/contacts/README.md b/apps/contacts/README.md new file mode 100644 index 000000000..1bfc99c8e --- /dev/null +++ b/apps/contacts/README.md @@ -0,0 +1,29 @@ +# Contacts + +This app provides a common way to set up the `contacts.json` file. + +## Contacts JSON file + +When the app is loaded from the app loader, a file named +`contacts.json` is loaded along with the javascript etc. The file +has the following contents: + +``` +[ + { + "name":"NONE" + }, + { + "name":"First Last", + "number":"123456789", + } +] +``` + +## Contacts Editor + +Clicking on the download icon of `Contents` in the app loader invokes +the contact editor. The editor downloads and displays the current +`contacts.json` file. Clicking the `Edit` button beside an entry +causes the entry to be deleted from the list and displayed in the edit +boxes. It can be restored - by clicking the `Add` button. \ No newline at end of file diff --git a/apps/contacts/app-icon.js b/apps/contacts/app-icon.js new file mode 100644 index 000000000..3012be8d8 --- /dev/null +++ b/apps/contacts/app-icon.js @@ -0,0 +1 @@ +require("heatshrink").decompress(atob("mEwwcBkmSpIC/AVsJCJ+AQaCZBCOeACKGQLKGQBA0ggARPJ4IRsYo0ggR9IoAIGiRiIpEECJsAiACBBYoRGpEAI4JBFI47CBLIRlDHYJrGYQIRCwQICL4MQOgx9GboUSeQ4RFwAFBiSGHCIo4CiVIWZyPICP4RaRIQROgARHdIwICoIIFkDpGBAKqHgGACI0AyVIggIDoEEMQ1ICINJCIj4CfwIREBwUgQYYOCfYoFDJQKDFCIopEO4RoDKAqJHRhAC/ATA=")) diff --git a/apps/contacts/app.png b/apps/contacts/app.png new file mode 100644 index 000000000..147dcc61a Binary files /dev/null and b/apps/contacts/app.png differ diff --git a/apps/contacts/contacts.app.js b/apps/contacts/contacts.app.js new file mode 100644 index 000000000..85eef625b --- /dev/null +++ b/apps/contacts/contacts.app.js @@ -0,0 +1,189 @@ +/* contacts.js */ + +var Layout = require("Layout"); + +const W = g.getWidth(); +const H = g.getHeight(); + +var wp = require('Storage').readJSON("contacts.json", true) || []; +// Use this with corrupted contacts +//var wp = []; + +var key; /* Shared between functions, typically wp name */ + +function writeContact() { + require('Storage').writeJSON("contacts.json", wp); +} + +function mainMenu() { + var menu = { + "< Back" : Bangle.load + }; + if (Object.keys(wp).length==0) Object.assign(menu, {"NO Contacts":""}); + else for (let id in wp) { + let i = id; + menu[wp[id]["name"]]=()=>{ decode(i); }; + } + menu["Add"]=addCard; + menu["Remove"]=removeCard; + g.clear(); + E.showMenu(menu); +} + +function decode(pin) { + var i = wp[pin]; + var l = i["name"] + "\n" + i["number"]; + var la = new Layout ({ + type:"v", c: [ + {type:"txt", font:"10%", pad:1, fillx:1, filly:1, label: l}, + {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label:"OK", cb:l=>{mainMenu();}} + ], lazy:true}); + g.clear(); + la.render(); +} + +function showNumpad(text, key_, callback) { + key = key_; + E.showMenu(); + function addDigit(digit) { + key+=digit; + if (1) { + l = text[key.length]; + switch (l) { + case '.': case ' ': case "'": + key+=l; + break; + case 'd': case 'D': default: + break; + } + } + Bangle.buzz(20); + update(); + } + function update() { + g.reset(); + g.clearRect(0,0,g.getWidth(),23); + s = key + text.substr(key.length, 999); + g.setFont("Vector:24").setFontAlign(1,0).drawString(s,g.getWidth(),12); + } + ds="12%"; + var numPad = new Layout ({ + type:"v", c: [{ + type:"v", c: [ + {type:"", height:24}, + {type:"h",filly:1, c: [ + {type:"btn", font:ds, width:58, label:"7", cb:l=>{addDigit("7");}}, + {type:"btn", font:ds, width:58, label:"8", cb:l=>{addDigit("8");}}, + {type:"btn", font:ds, width:58, label:"9", cb:l=>{addDigit("9");}} + ]}, + {type:"h",filly:1, c: [ + {type:"btn", font:ds, width:58, label:"4", cb:l=>{addDigit("4");}}, + {type:"btn", font:ds, width:58, label:"5", cb:l=>{addDigit("5");}}, + {type:"btn", font:ds, width:58, label:"6", cb:l=>{addDigit("6");}} + ]}, + {type:"h",filly:1, c: [ + {type:"btn", font:ds, width:58, label:"1", cb:l=>{addDigit("1");}}, + {type:"btn", font:ds, width:58, label:"2", cb:l=>{addDigit("2");}}, + {type:"btn", font:ds, width:58, label:"3", cb:l=>{addDigit("3");}} + ]}, + {type:"h",filly:1, c: [ + {type:"btn", font:ds, width:58, label:"0", cb:l=>{addDigit("0");}}, + {type:"btn", font:ds, width:58, label:"C", cb:l=>{key=key.slice(0,-1); update();}}, + {type:"btn", font:ds, width:58, id:"OK", label:"OK", cb:callback} + ]} + ]} + ], lazy:true}); + g.clear(); + numPad.render(); + update(); +} + +function removeCard() { + var menu = { + "" : {title : "Select Contact"}, + "< Back" : mainMenu + }; + if (Object.keys(wp).length==0) Object.assign(menu, {"No Contacts":""}); + else { + wp.forEach((val, card) => { + const name = wp[card].name; + menu[name]=()=>{ + E.showMenu(); + var confirmRemove = new Layout ( + {type:"v", c: [ + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:"Delete"}, + {type:"txt", font:"15%", pad:1, fillx:1, filly:1, label:name}, + {type:"h", c: [ + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: "YES", cb:l=>{ + wp.splice(card, 1); + writeContact(); + mainMenu(); + }}, + {type:"btn", font:"15%", pad:1, fillx:1, filly:1, label: " NO", cb:l=>{mainMenu();}} + ]} + ], lazy:true}); + g.clear(); + confirmRemove.render(); + }; + }); + } + E.showMenu(menu); +} + +function askPosition(callback) { + let full = ""; + showNumpad("dddDDDddd", "", function() { + callback(key, ""); + }); +} + +function createContact(lat, name) { + let n = {}; + n["name"] = name; + n["number"] = lat; + wp.push(n); + print("add -- contacts", wp); + writeContact(); +} + +function addCardName2(key) { + g.clear(); + askPosition(function(lat, lon) { + print("position -- ", lat, lon); + createContact(lat, result); + mainMenu(); + }); +} + +function addCardName(key) { + result = key; + if (wp[result]!=undefined) { + E.showMenu(); + var alreadyExists = new Layout ( + {type:"v", c: [ + {type:"txt", font:Math.min(15,100/result.length)+"%", pad:1, fillx:1, filly:1, label:result}, + {type:"txt", font:"12%", pad:1, fillx:1, filly:1, label:"already exists."}, + {type:"h", c: [ + {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label: "REPLACE", cb:l=>{ addCardName2(key); }}, + {type:"btn", font:"10%", pad:1, fillx:1, filly:1, label: "CANCEL", cb:l=>{mainMenu();}} + ]} + ], lazy:true}); + g.clear(); + alreadyExists.render(); + return; + } + addCardName2(key); +} + +function addCard() { + require("textinput").input({text:""}).then(result => { + if (result != "") { + addCardName(result); + } else + mainMenu(); + }); +} + +g.reset(); +Bangle.setUI(); +mainMenu(); diff --git a/apps/contacts/contacts.json b/apps/contacts/contacts.json new file mode 100644 index 000000000..40afa27dd --- /dev/null +++ b/apps/contacts/contacts.json @@ -0,0 +1,6 @@ +[ + { + "name":"EU emergency", + "number":"112" + } +] diff --git a/apps/contacts/interface.html b/apps/contacts/interface.html new file mode 100644 index 000000000..013478960 --- /dev/null +++ b/apps/contacts/interface.html @@ -0,0 +1,249 @@ + + +
+ + + + + + + + + + +