diff --git a/apps/timecal/timecal.app.js b/apps/timecal/timecal.app.js index 090464be1..17daf127a 100644 --- a/apps/timecal/timecal.app.js +++ b/apps/timecal/timecal.app.js @@ -17,19 +17,19 @@ class TimeCalClock{ this._settings = require("Storage").readJSON("timecal.settings.json", 1) || {}; const defaults = { - showDate:"l", //(n)one, (l)ocale, (m)onth short(y)ear(w)eek - - wdStrt:1, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, + shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week + + wdStrt:1, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today - todayNumClr:"#00E", - todayMrker:"r", //(n)one, (c)ircle, (r)ect, (f)illed - todayMrkClr:"#0E0", - todayMrkMrkPxl:3, + tdyNumClr:0, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:3, //px - suColor:"#E00", //sunday - phColor:"#E00", //public holiday + suClr:0, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday - calBorder:true + calBrdr:false }; for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults @@ -39,7 +39,9 @@ class TimeCalClock{ Bangle.loadWidgets(); Bangle.drawWidgets(); - this.center_x = Bangle.appRect.w/2; + this.centerX = Bangle.appRect.w/2; + this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b + this.ABR_DAY = require("locale") && require("locale").abday ? require("locale").abday : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; } /** @@ -64,7 +66,6 @@ class TimeCalClock{ */ drawTime(){ d=this.date ? this.date : new Date(); - console.log("drawTime", d); const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10; d=d?d :new Date(); @@ -73,7 +74,7 @@ class TimeCalClock{ g.setFont("Vector", this.TIME_FONT_SIZE()); g.setColor(g.theme.fg); g.clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); - g.drawString(("0" + require("locale").time(d, 1)).slice(-5), this.center_x, Y); + g.drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y); //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option setTimeout(this.drawTime.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds()); @@ -107,9 +108,9 @@ class TimeCalClock{ const Y=Bangle.appRect.y; var render=false; var dateStr = ""; - console.log(">"+this.settings().showDate+"<"); - if (!(this.settings().showDate==="n")) - for (let c of this.settings().showDate) { //add part as configured + if (this.settings().shwDate>0) { //skip if exactly -none + const dateSttngs = ["","l","M","m.Y #W"]; + for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured switch (c){ case "l":{ //locale render=true; @@ -121,12 +122,26 @@ class TimeCalClock{ dateStr+=require("locale").month(d,1); break; } - case "y":{ //year e.g. 2022 + case "M":{ //month e.g. January + render=true; + dateStr+=require("locale").month(d,0); + break; + } + case "y":{ //year e.g. 22 + render=true; + dateStr+=d.getFullYear().slice(-2); + break; + } + case "Y":{ //year e.g. 2022 render=true; dateStr+=d.getFullYear(); break; } - case "w":{ //week e.g. #02 + case "w":{ //week e.g. #2 + dateStr+=(this.ISO8601calWeek(d)); + break; + } + case "W":{ //week e.g. #02 dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2); break; } @@ -136,12 +151,13 @@ class TimeCalClock{ break; //noop } } + } if (render){ g.clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); g.setFont("Vector", FONT_SIZE); g.setColor(g.theme.fg); g.setFontAlign(0, -1); - g.drawString(dateStr,this.center_x,Y); + g.drawString(dateStr,this.centerX,Y); } //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option } @@ -161,19 +177,18 @@ class TimeCalClock{ g.clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); - var dNames=[]; - if (require("locale") && require("locale").abday) - dNames=require("locale").abday.map((a) => a.length>2 ? a.substr(0, 2) : a ); //retrieve from locale and force max 2 chars - else - dNames=["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; //fallback - g.setFont("Vector", DAY_NAME_FONT_SIZE); g.setColor(g.theme.fg); g.setFontAlign(-1, -1); + + const tdyDate=d.getDate(); + const sttngsWdStrt=this.settings().wdStrt>=0 ? this.settings().wdStrt : tdyDate.getDay(); + //draw grid & Headline + const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2 for(var dNo=0; dNo0) g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1); @@ -189,31 +204,30 @@ class TimeCalClock{ g.setFont("Vector", DAY_NUM_FONT_SIZE); //write days - const todayDate=d.getDate(); - const days=7+(7+d.getDay()-this.settings().wdStrt)%7;//start day (week before=7 days + days in this week realtive to week start) + const days=7+(7+d.getDay()-sttngsWdStrt)%7;//start day (week before=7 days + days in this week realtive to week start) var rD=new Date(); rD.setDate(rD.getDate()-days); var rDate=rD.getDate(); for(var y=0; y<3; y++){ for(var x=0; xSu, 1->Mo, ... //Issue #1154: weekstart So/Mo, + shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week + + wdStrt:1, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today - todayNumClr:"#00E", - todayMrker:"r", //(n)one, (c)ircle, (r)ect, (f)illed - todayMrkClr:"#0E0", - todayMrkMrkPxl:3, + tdyNumClr:0, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:3, //px - suColor:"#E00", //sunday - phColor:"#E00", //public holiday + suClr:0, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday - calBorder:true + calBrdr:false }; for (const k in this._settings) if (!defaults.hasOwnProperty(k)) delete this._settings[k]; //remove invalid settings for (const k in defaults) if(!this._settings.hasOwnProperty(k)) this._settings[k] = defaults[k]; //assign missing defaults @@ -39,7 +39,9 @@ class TimeCalClock{ Bangle.loadWidgets(); Bangle.drawWidgets(); - this.center_x = Bangle.appRect.w/2; + this.centerX = Bangle.appRect.w/2; + this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b + this.ABR_DAY = require("locale") && require("locale").abday ? require("locale").abday : ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; } /** @@ -64,7 +66,6 @@ class TimeCalClock{ */ drawTime(){ d=this.date ? this.date : new Date(); - console.log("drawTime", d); const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10; d=d?d :new Date(); @@ -73,7 +74,7 @@ class TimeCalClock{ g.setFont("Vector", this.TIME_FONT_SIZE()); g.setColor(g.theme.fg); g.clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); - g.drawString(("0" + require("locale").time(d, 1)).slice(-5), this.center_x, Y); + g.drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y); //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option setTimeout(this.drawTime.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds()); @@ -107,9 +108,9 @@ class TimeCalClock{ const Y=Bangle.appRect.y; var render=false; var dateStr = ""; - console.log(this.settings().showDate); - if (this.settings().showDate!=="n"); - for (let c of this.settings().showDate) { //add part as configured + if (this.settings().shwDate>0) { //skip if exactly -none + const dateSttngs = ["","l","M","m.Y #W"]; + for (let c of dateSttngs[this.settings().shwDate]) { //add part as configured switch (c){ case "l":{ //locale render=true; @@ -121,12 +122,26 @@ class TimeCalClock{ dateStr+=require("locale").month(d,1); break; } - case "y":{ //year e.g. 2022 + case "M":{ //month e.g. January + render=true; + dateStr+=require("locale").month(d,0); + break; + } + case "y":{ //year e.g. 22 + render=true; + dateStr+=d.getFullYear().slice(-2); + break; + } + case "Y":{ //year e.g. 2022 render=true; dateStr+=d.getFullYear(); break; } - case "w":{ //week e.g. #02 + case "w":{ //week e.g. #2 + dateStr+=(this.ISO8601calWeek(d)); + break; + } + case "W":{ //week e.g. #02 dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2); break; } @@ -136,12 +151,13 @@ class TimeCalClock{ break; //noop } } + } if (render){ g.clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); g.setFont("Vector", FONT_SIZE); g.setColor(g.theme.fg); g.setFontAlign(0, -1); - g.drawString(dateStr,this.center_x,Y); + g.drawString(dateStr,this.centerX,Y); } //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option } @@ -161,19 +177,18 @@ class TimeCalClock{ g.clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); - var dNames=[]; - if (require("locale") && require("locale").abday) - dNames=require("locale").abday.map((a) => a.length>2 ? a.substr(0, 2) : a ); //retrieve from locale and force max 2 chars - else - dNames=["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]; //fallback - g.setFont("Vector", DAY_NAME_FONT_SIZE); g.setColor(g.theme.fg); g.setFontAlign(-1, -1); + + const tdyDate=d.getDate(); + const sttngsWdStrt=this.settings().wdStrt>=0 ? this.settings().wdStrt : tdyDate.getDay(); + //draw grid & Headline + const dNames = this.ABR_DAY.map((a) => a.length<=2 ? a : a.substr(0, 2)); //force shrt 2 for(var dNo=0; dNo0) g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1); @@ -189,31 +204,30 @@ class TimeCalClock{ g.setFont("Vector", DAY_NUM_FONT_SIZE); //write days - const todayDate=d.getDate(); - const days=7+(7+d.getDay()-this.settings().wdStrt)%7;//start day (week before=7 days + days in this week realtive to week start) + const days=7+(7+d.getDay()-sttngsWdStrt)%7;//start day (week before=7 days + days in this week realtive to week start) var rD=new Date(); rD.setDate(rD.getDate()-days); var rDate=rD.getDate(); for(var y=0; y<3; y++){ for(var x=0; x", - functionNames: ["required, ", "..."], cases: [ { value: "required,", @@ -335,7 +354,10 @@ class TestSetting extends Test{ afterText: "optional,", afterExpression: "optional," } - ] + ], + constructorParams: ["optional: ","|TEST_SETTINGS|","..."], //TEST_SETTINGS will be replcaed with each current {setting: case} + functionNames: ["required, ", "..."], + functionParams: ["optional: ","|TEST_SETTINGS|","..."] } } @@ -344,7 +366,6 @@ class TestSetting extends Test{ this._validate(data); this.setting = data.setting; - this.methodNames = data.functionNames; this.cases = data.cases.map((entry) => { return { value: entry.value, @@ -354,6 +375,9 @@ class TestSetting extends Test{ afterExpression: entry.afterExpression||true }; }); + this.constructorParams = data.constructorParams, + this.functionNames = data.functionNames; + this.functionParams = data.functionParams; } /** @@ -362,11 +386,11 @@ class TestSetting extends Test{ _validate(data){ //validate given config if (!data.setting) throw new EmptyMandatoryError("setting", data, this.TEST_SETTING_SAMPLE()); - if (!data.cases instanceof Array || data.cases.length==0) throw new EmptyMandatoryError("cases", data, this.TEST_SETTING_SAMPLE()); - if (!data.functionNames instanceof Array || data.functionNames==0) throw new EmptyMandatoryError("functionNames", data, this.TEST_SETTING_SAMPLE()); + if (!(data.cases instanceof Array) || data.cases.length==0) throw new EmptyMandatoryError("cases", data, this.TEST_SETTING_SAMPLE()); + if (!(data.functionNames instanceof Array) || data.functionNames==0) throw new EmptyMandatoryError("functionNames", data, this.TEST_SETTING_SAMPLE()); data.cases.forEach((entry,idx) => { - if (!entry.value) throw new EmptyMandatoryError("cases["+idx+"].value", entry, this.TEST_SETTING_SAMPLE()); + if (entry.value === undefined) throw new EmptyMandatoryError("cases["+idx+"].value", entry, this.TEST_SETTING_SAMPLE()); }); } } @@ -398,8 +422,8 @@ class BangleTestRunner{ * add a Setting Test, return instance for chaining * @param {TestSetting} */ - addSetting(test) { - this.tests.push(test); + addTestSettings(sttngs) { + this.tests.push(new TestSetting(sttngs)); return this; } @@ -416,14 +440,14 @@ class BangleTestRunner{ this._afterCase(); } this._afterTest(); - }; + } } /** - * global prepare + * global prepare - before all test */ _init() { - console.log(new Date(),">>init"); + console.log(new Date().getTime(),">>init"); this.currentTestNum=-1; this.currentCaseNum=-1; } @@ -448,45 +472,33 @@ class BangleTestRunner{ } } + /** + * testcase runner + */ _runCase() { console.log(new Date(), ">>running..."); var returns = []; - this.currentTest.methodNames.forEach((methodName) => { - var instance = eval("new " + this.oClass + ""); - console.log(instance); - const method = instance[methodName]; - //console.log(">>"+this.oClass+"["+methodName+"]()"); - //if (typeof method !== "function") - // throw new InvalidMethodName(this.oClass, methodName); - let settings={}; settings[this.currentTest.setting] = this.currentCase.value; - returns.push(new TimeCalClock(new Date(), settings).drawDate()); - //returns.push(method()); - console.log("<<"+this.oClass+"["+methodName+"]()"); - g.dump() + this.currentTest.functionNames.forEach((fName) => { + var settings={}; settings[this.currentTest.setting] = this.currentCase.value; + var cParams = this.currentTest.constructorParams||[]; + cParams = cParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v)//replace settings in call params + var fParams = this.currentTest.functionParams||[]; + fParams = fParams.map((v) => (v && v instanceof String && v==="|TEST_SETTINGS|") ? settings : v)//replace settings in call params + + var creatorFunc = new Function("return new " + this.oClass + "(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6],arguments[7],arguments[8],arguments[9])"); //prepare spwan arguments[0],arguments[1] + let instance = creatorFunc.call(this.oClass, cParams[0], cParams[1], cParams[2], cParams[3], cParams[4], cParams[5], cParams[6], cParams[7], cParams[8], cParams[9]); //spwan + + console.log(">>"+this.oClass+"["+fName+"]()"); + returns.push(instance[fName](fParams[0], fParams[1], fParams[2], fParams[3], fParams[4], fParams[5], fParams[6], fParams[7], fParams[8], fParams[9])); //run method and store result + console.log("<<"+this.oClass+"["+fName+"]()"); + g.dump(); }); - - //this._delay(1).then((result) => console.log(new Date(), "finished")); - //g.dump(); - /*var testCaseNum=0; - test.cases.forEach(testcase => { //execute test - testcase.dates.forEach(date => { //spawn with each date - testCaseNum++; - E.showMessage( - "="+testcase.value+"\n" - +"expected: "+testcase.descr, - "#"+testCaseNum+": "+test.setting - ); - this._delay(TESTCASE_MSG_TIMEOUT).then((r,e) => { - const objUnderTest = new Object.create(this.ObjClass)(date, new Object()[test.setting]=test.value ); - objUnderTest.draw(); - this._delay(TESTCASE_RUN_TIMEOUT).then((r,e) => { - }); - }); - }); - });*/ console.log(new Date(), "<<...running"); } + /** + * after each testcase + */ _afterCase() { if (this.currentTest instanceof TestSetting) { if (this.currentCase.afterTxt.length>0) { @@ -498,10 +510,16 @@ class BangleTestRunner{ console.log(new Date(), "<Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for always focus/center today - function writeSettings() { + tdyNumClr:3, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkr:0, //0:none, 1:circle, 2:rectangle, 3:filled + tdyMrkClr:2, //1:red=#E00, 2:green=#0E0, 3:blue=#00E + tdyMrkPxl:2, //px + + suClr:0, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E + //phColor:"#E00", //public holiday + + calBrdr:false + }, + require('Storage').readJSON(FILE, true) || {} + ); + + const SETTINGS_AT_START = Object.assign(settings); //hardcopy of current and defaults + + var saveSettings = () => { require('Storage').writeJSON(FILE, settings); }; -}); -var mainmenu = { - "": { - "title": "Time calendar clock" - }, - "< Back": () => back(), - "Cal.Start Day": { - value: settings.wdStrt === undefined ? 1 : settings.wdStrt, //def: 1: mon - min: -1, max: 6, - //render dow from locale or LANG"today" - format: v => (v>=0 ? (require("locale") && require("locale").abday && require("locale").abday[v] ? : && require("locale").abday[v] : DOW_abbr_FB[v]) : /*LANG*/"today"), - onchange: v => { - settings.weekDay = v; - writeSettings(); - } - } -}; \ No newline at end of file + var restoreAndExitSettings = () => { + require('Storage').writeJSON(FILE, SETTINGS_AT_START); + E.showMenu(); + }; + + var showMainMenu = () => { + E.showMenu({ + "": { + "title": /*LANG*/"Time cal clock" + }, + /*LANG*/"< Save": () => save(), + /*LANG*/"Show date": { + value: settings.shwDate, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"locale", /*LANG*/"M", /*LANG*/"m.Y #W"][v], + onchange: v => { + settings.shwDate = v; + saveSettings(); + } + }, + /*LANG*/"Start wday": { + value: settings.wdStrt, + min: -1, max: 6, + format: v => v>=0 ? ABR_DAY[v] : /*LANG*/"today", + onchange: v => { + settings.wdStrt = v; + saveSettings(); + } + }, + /*LANG*/"Su color": { + value: settings.suClr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => { + settings.suClr = v; + saveSettings(); + } + }, + /*LANG*/"Border": { + value: settings.calBrdr, + format: v => v ? "show" : "none", + onchange: v => { + settings.calBrdr = v; + saveSettings(); + } + }, + /*LANG*/"Today settings": () => { + showTodayMenu(); + }, + /*LANG*/"< Cancel": () => restoreAndExitSettings() + }); + }; + + var showTodayMenu = () => { + E.showMenu({ + "": { + "title": /*LANG*/"Today settings" + }, + "< Back": () => showMainMenu(), + /*LANG*/"Color": { + value: settings.tdyNumClr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => { + settings.tdyNumClr = v; + saveSettings(); + } + }, + /*LANG*/"Marker": { + value: settings.tdyMrkr, + min: 0, max: 3, + format: v => [/*LANG*/"none", /*LANG*/"circle", /*LANG*/"rectangle", /*LANG*/"filled"][v], + onchange: v => { + settings.tdyMrkr = v; + saveSettings(); + } + }, + /*LANG*/"Mrk.Color": { + value: settings.tdyMrkClr, + min: 0, max: 2, + format: v => [/*LANG*/"red", /*LANG*/"green", /*LANG*/"blue"][v], + onchange: v => { + settings.tdyMrkClr = v; + saveSettings(); + } + }, + /*LANG*/"Mrk.Size": { + value: settings.tdyMrkPxl, + min: 0, max: 10, + format: v => v+"px", + onchange: v => { + settings.tdyMrkPxl = v; + saveSettings(); + } + }, + /*LANG*/"< Cancel": () => restoreAndExitSettings() + }); + }; + + showMainMenu(); +});