//Clock renders date, time and pre,current,next week calender view class TimeCalClock{ DATE_FONT_SIZE(){ return 20; } TIME_FONT_SIZE(){ return 40; } /** * @param{Date} date optional the date (e.g. for testing) * @param{Settings} settings optional settings to use e.g. for testing */ constructor(date, settings){ if (date) this.date=date; if (settings) this._settings = settings; else this._settings = require("Storage").readJSON("timecal.settings.json", 1) || {}; const defaults = { shwDate:1, //0:none, 1:locale, 2:month, 3:monthshort.year #week wdStrt:0, //identical to getDay() 0->Su, 1->Mo, ... //Issue #1154: weekstart So/Mo, -1 for use today 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:3, //px suClr:1, //0:fg, 1:red=#E00, 2:green=#0E0, 3:blue=#00E //phColor:"#E00", //public holiday 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 g.clear(); Bangle.setUI("clock"); Bangle.loadWidgets(); Bangle.drawWidgets(); this.centerX = Bangle.appRect.w/2; this.nrgb = [g.theme.fg, "#E00", "#0E0", "#00E"]; //fg, r ,g , b this.ABR_DAY=[]; if (require("locale") && require("locale").dow) for (let d=0; d<=6; d++) { var refDay=new Date(); refDay.setFullYear(1972); refDay.setMonth(0); refDay.setDate(2+d); this.ABR_DAY.push(require("locale").dow(refDay)); } else this.ABR_DAY=["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; } /** * @returns {Object} current settings object */ settings(){ return this._settings; } /* * Run forest run **/ draw(){ this.drawTime(); if (this.TZOffset===undefined || this.TZOffset!==d.getTimezoneOffset()) this.drawDateAndCal(); } /** * draw given or current time from date * overwatch timezone changes * schedules itself to update */ drawTime(){ d=this.date ? this.date : new Date(); const Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10; d=d?d :new Date(); g.setFontAlign(0, -1).setFont("Vector", this.TIME_FONT_SIZE()).setColor(g.theme.fg) .clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7) .drawString(("0" + require("locale").time(d, 1)).slice(-5), this.centerX, Y, true); //.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+this.TIME_FONT_SIZE()-7); //DEV-Option setTimeout(this.draw.bind(this), 60000-(d.getSeconds()*1000)-d.getMilliseconds()); } /** * draws given date and cal * @param{Date} d provide date or uses today */ drawDateAndCal(){ d=this.date ? this.date : new Date(); this.TZOffset=d.getTimezoneOffset(); this.drawDate(); this.drawCal(); if (this.tOutD) //abort exisiting clearTimeout(this.tOutD); this.tOutD=setTimeout(this.drawDateAndCal.bind(this), 86400000-(d.getHours()*24*60*1000)-(d.getMinutes()*60*1000)-d.getSeconds()-d.getMilliseconds()); } /** * draws given date as defiend in settings */ drawDate(){ d=this.date ? this.date : new Date(); const FONT_SIZE=20; const Y=Bangle.appRect.y; var render=false; var dateStr = ""; 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; dateStr+=require("locale").date(d,1); break; } case "m":{ //month e.g. Jan. render=true; dateStr+=require("locale").month(d,1); break; } 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. #2 dateStr+=(this.ISO8601calWeek(d)); break; } case "W":{ //week e.g. #02 dateStr+=("0"+this.ISO8601calWeek(d)).slice(-2); break; } default: //append c dateStr+=c; render=dateStr.length>0; break; //noop } } } if (render){ g.setFont("Vector", FONT_SIZE).setColor(g.theme.fg).setFontAlign(0, -1).clearRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3).drawString(dateStr,this.centerX,Y); } //g.drawRect(Bangle.appRect.x, Y, Bangle.appRect.x2, Y+FONT_SIZE-3); //DEV-Option } /** * draws calender week view (-1,0,1) for given date */ drawCal(){ d=this.date ? this.date : new Date(); const DAY_NAME_FONT_SIZE=10; const CAL_Y=Bangle.appRect.y+this.DATE_FONT_SIZE()+10+this.TIME_FONT_SIZE()+3; const CAL_AREA_H=Bangle.appRect.h-CAL_Y+24; //+24: top widegtes only const CELL_W=Bangle.appRect.w/7; //cell width const CELL_H=(CAL_AREA_H-DAY_NAME_FONT_SIZE)/3; //cell heigth const DAY_NUM_FONT_SIZE=Math.min(CELL_H-1,15); //size down, max 15 g.setFont("Vector", DAY_NAME_FONT_SIZE).setColor(g.theme.fg).setFontAlign(-1, -1).clearRect(Bangle.appRect.x, CAL_Y, Bangle.appRect.x2, CAL_Y+CAL_AREA_H); //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; dNo=0 ? (dNo+this.settings().wdStrt)%7 : (dNo+d.getDay()+4)%7; const dName=dNames[dIdx]; if(dNo>0) g.drawLine(dNo*CELL_W, CAL_Y, dNo*CELL_W, CAL_Y+CAL_AREA_H-1); if (dIdx==0) g.setColor(this.nrgb[this.settings().suClr]); //sunday maybe colorize txt g.drawString(dName, dNo*CELL_W+(CELL_W-g.stringWidth(dName))/2+2, CAL_Y+1).setColor(g.theme.fg); } var nextY=CAL_Y+DAY_NAME_FONT_SIZE; for(i=0; i<3; i++){ const y=nextY+i*CELL_H; g.drawLine(Bangle.appRect.x, y, Bangle.appRect.x2, y); } g.setFont("Vector", DAY_NUM_FONT_SIZE); //write days const tdyDate=d.getDate(); const days=this.settings().wdStrt>=0 ? 7+((7+d.getDay()-this.settings().wdStrt)%7) : 10;//start day (week before=7 days + days in this week realtive to week start) or fixed 7+3 days var rD=new Date(d.getTime()); rD.setDate(rD.getDate()-days); var rDate=rD.getDate(); for(var y=0; y<3; y++){ for(var x=0; x