1+ {
2+ const SunCalc = require ( "suncalc" ) ; // from modules folder
3+ const storage = require ( 'Storage' ) ;
4+ const widget_utils = require ( 'widget_utils' ) ;
5+ const global_settings = storage . readJSON ( "setting.json" , true ) || { } ;
6+ const LOCATION_FILE = "mylocation.json" ;
7+ const h = g . getHeight ( ) ;
8+ const w = g . getWidth ( ) ;
9+ let location ;
10+ let cachedSunTimes = null ;
11+ let lastSunCalcDate = null ;
12+ var prevVals = { } ;
13+ let drawTimeout ;
14+
15+ var settings = {
16+ hr_12 : global_settings [ "12hour" ] !== undefined ? global_settings [ "12hour" ] : false ,
17+ dark_mode : g . theme . dark
18+ } ;
19+
20+ let clrs = {
21+ tab : "#505050" , // grey
22+ keys : settings . dark_mode ? "#4287f5" : "#0000FF" , // blue
23+ strings : settings . dark_mode ? "#F0A000" : "#FF0000" , // orange or red
24+ ints : settings . dark_mode ? "#00FF00" : "#005F00" , // green
25+ bg : g . theme . bg ,
26+ brackets : g . theme . fg ,
27+ } ;
28+
29+
30+ let jsonText ;
31+ let lines = [ ] ;
32+ let fontSize = 13 ;
33+ const lineHeight = 16 ;
34+
35+ const buttonHeight = 12 ;
36+ const buttonX = 78 ;
37+ const buttonY = 3 ;
38+
39+ let valuePositions = [ ] ;
40+ const headerHeight = 16 ;
41+ const usableHeight = h - headerHeight ;
42+ const maxLines = Math . floor ( usableHeight / lineHeight ) ;
43+ var numWidth = 0 ;
44+
45+ // requires the myLocation app
46+ let loadLocation = function ( ) {
47+ location = require ( "Storage" ) . readJSON ( LOCATION_FILE , 1 ) || { } ;
48+ location . lat = location . lat || 0 ;
49+ location . lon = location . lon || 0 ;
50+ location . location = location . location || null ;
51+ } ;
52+
53+ let getHr = function ( h ) {
54+ var amPm = "" ;
55+ if ( settings . hr_12 ) {
56+ amPm = h < 12 ? "AM" : "PM" ;
57+ h = h % 12 ;
58+ if ( h == 0 ) h = 12 ;
59+ }
60+ return [ h , amPm ] ;
61+ } ;
62+
63+ let extractTime = function ( d ) {
64+ const out = getHr ( d . getHours ( ) ) ;
65+ const h = out [ 0 ] ;
66+ const amPm = out [ 1 ] ;
67+ const m = d . getMinutes ( ) ;
68+ return `${ h } :${ ( "0" + m ) . substr ( - 2 ) } ${ amPm } ` ;
69+ } ;
70+
71+ let extractDate = function ( d ) {
72+ const weekdays = [ "Sun" , "Mon" , "Tue" , "Wed" , "Thu" , "Fri" , "Sat" ] ;
73+ const months = [ "Jan" , "Feb" , "Mar" , "Apr" , "May" , "Jun" ,
74+ "Jul" , "Aug" , "Sep" , "Oct" , "Nov" , "Dec"
75+ ] ;
76+
77+ const weekday = weekdays [ d . getDay ( ) ] ;
78+ const month = months [ d . getMonth ( ) ] ;
79+ const day = d . getDate ( ) ;
80+
81+ return `${ weekday } ${ month } ${ day } ` ;
82+ } ;
83+
84+ let getSteps = function ( ) {
85+ try {
86+ return Bangle . getHealthStatus ( "day" ) . steps ;
87+ } catch ( e ) {
88+ if ( WIDGETS . wpedom !== undefined )
89+ return WIDGETS . wpedom . getSteps ( ) ;
90+ else
91+ return null ;
92+ }
93+ } ;
94+
95+ let getVal = function ( now , loc ) {
96+ const vals = { } ;
97+ const currentDateStr = extractDate ( now ) ;
98+ if ( loc . location ) {
99+ if ( lastSunCalcDate !== currentDateStr ) {
100+ cachedSunTimes = SunCalc . getTimes ( now , location . lat , location . lon ) ;
101+ lastSunCalcDate = currentDateStr ;
102+ }
103+ vals . rise = extractTime ( cachedSunTimes . sunrise ) ;
104+ vals . set = extractTime ( cachedSunTimes . sunset ) ;
105+ }
106+ vals . time = extractTime ( now ) ;
107+ vals . date = currentDateStr ;
108+ vals . batt_pct = E . getBattery ( ) ;
109+ vals . steps = getSteps ( ) ;
110+ return vals ;
111+ } ;
112+
113+ let loadJson = function ( ) {
114+ const now = new Date ( ) ;
115+ const vals = getVal ( now , location ) ;
116+ //vals.steps = null; // For testing; uncomment to see the steps not appear
117+ //location.location = null; // For testing, if null, the time becomes an struct to take up sun's struct
118+ let raw ;
119+
120+ if ( location . location !== null ) {
121+ raw = {
122+ time : vals . time ,
123+ dt : vals . date ,
124+ sun : {
125+ rise : vals . rise ,
126+ set : vals . set ,
127+ } ,
128+ "batt_%" : vals . batt_pct ,
129+ } ;
130+ } else {
131+ raw = {
132+ time : {
133+ hr : getHr ( now . getHours ( ) ) [ 0 ] ,
134+ min : now . getMinutes ( ) ,
135+ } ,
136+ dt : vals . date ,
137+ "batt_%" : vals . batt_pct ,
138+ } ;
139+ }
140+
141+ if ( vals . steps != null ) raw . steps = vals . steps ;
142+
143+ jsonText = JSON . stringify ( raw , null , 2 ) ;
144+ lines = jsonText . split ( "\n" ) ;
145+ } ;
146+
147+ let draw = function ( ) {
148+ g . clear ( ) ;
149+ g . setFontAlign ( - 1 , - 1 ) ;
150+ g . setFont ( "Vector" , 10 ) ;
151+ valuePositions = [ ] ;
152+
153+ g . setColor ( clrs . tab ) ;
154+
155+ g . fillRect ( 90 , 0 , w , headerHeight ) ;
156+ g . setColor ( clrs . brackets ) ;
157+ g . drawString ( "clockface.json" , 3 , 3 ) ;
158+
159+ g . setFont ( "Vector" , buttonHeight ) ;
160+ g . drawString ( "X" , buttonX , buttonY ) ;
161+ g . setFont ( "Vector" , fontSize ) ;
162+
163+ for ( let i = 0 ; i < maxLines ; i ++ ) {
164+ const y = headerHeight + i * lineHeight ;
165+ const lineNumberStr = ( i + 1 ) . toString ( ) . padStart ( 2 , " " ) + " " ;
166+ g . drawString ( lineNumberStr , 0 , y ) ;
167+ numWidth = Math . max ( numWidth , g . stringWidth ( lineNumberStr ) ) ;
168+ }
169+
170+ redrawValues ( ) ;
171+ } ;
172+
173+ let redraw = function ( ) {
174+ for ( let i = 0 ; i < maxLines ; i ++ ) {
175+ const lineIndex = i ;
176+ const line = lines [ lineIndex ] ;
177+ if ( ! line ) continue ;
178+ const y = headerHeight + i * lineHeight ;
179+
180+ const indentMatch = line . match ( / ^ ( \s * ) / ) ;
181+ const indent = indentMatch ? indentMatch [ 1 ] : "" ;
182+
183+ const kvMatch = line . trim ( ) . match ( / ^ " ( [ ^ " ] + ) " : \s * ( .+ ) $ / ) ;
184+ if ( kvMatch ) {
185+ const key = kvMatch [ 1 ] ;
186+ let value = kvMatch [ 2 ] ;
187+
188+ if ( prevVals . key == value ) continue ;
189+ prevVals . key = value ;
190+
191+ // Key
192+ g . setColor ( clrs . keys ) ;
193+ g . drawString ( indent + `"${ key } "` , numWidth , y ) ;
194+ const keyWidth = g . stringWidth ( indent + `"${ key } "` ) ;
195+ const valueX = numWidth + keyWidth ;
196+ const valueText = ": " + value ;
197+
198+ // Value color
199+ if ( value . startsWith ( '"' ) ) {
200+ g . setColor ( clrs . strings ) ;
201+ } else if ( value . startsWith ( '{' ) || value . startsWith ( '}' ) ) {
202+ g . setColor ( clrs . brackets ) ;
203+ } else {
204+ g . setColor ( clrs . ints ) ;
205+ }
206+ g . drawString ( valueText , valueX , y ) ;
207+
208+ valuePositions . push ( {
209+ key,
210+ x : valueX ,
211+ y,
212+ text : value
213+ } ) ;
214+ } else {
215+ g . setColor ( clrs . brackets ) ;
216+ g . drawString ( line , numWidth , y ) ;
217+ }
218+ }
219+ } ;
220+
221+ let clearVals = function ( ) {
222+ g . setFont ( "Vector" , fontSize ) ;
223+ g . setFontAlign ( - 1 , - 1 ) ;
224+ valuePositions . forEach ( pos => {
225+ g . setColor ( clrs . bg ) ;
226+ g . fillRect ( pos . x , pos . y , w , pos . y + lineHeight ) ;
227+ } ) ;
228+ } ;
229+
230+ let redrawValues = function ( ) {
231+ loadJson ( ) ;
232+ clearVals ( ) ;
233+ redraw ( ) ;
234+ if ( drawTimeout ) clearTimeout ( drawTimeout ) ;
235+ drawTimeout = setTimeout ( function ( ) {
236+ drawTimeout = undefined ;
237+ redrawValues ( ) ;
238+ } , 60000 - ( Date . now ( ) % 60000 ) ) ;
239+ } ;
240+
241+ Bangle . on ( 'touch' , ( zone , e ) => {
242+ if ( e . x >= ( buttonY - buttonHeight ) && e . x <= ( buttonX + buttonHeight ) &&
243+ ( e . y >= ( buttonY - buttonHeight ) && e . y <= ( buttonY + buttonHeight ) ) ) {
244+ Bangle . showLauncher ( ) ; // Exit app
245+ }
246+ } ) ;
247+
248+ Bangle . on ( 'backlight' , function ( on ) {
249+ if ( on ) {
250+ redrawValues ( ) ;
251+ }
252+ } ) ;
253+
254+ Bangle . setUI ( "clock" ) ;
255+ loadLocation ( ) ;
256+ Bangle . loadWidgets ( ) ;
257+ widget_utils . hide ( ) ;
258+ draw ( ) ;
259+ }
0 commit comments