1
- /**
1
+ /************************************************
2
2
* AI Clock
3
3
*/
4
+ const storage = require ( 'Storage' ) ;
5
+ const clock_info = require ( "clock_info" ) ;
6
+
7
+
8
+
9
+ /************************************************
10
+ * Assets
11
+ */
4
12
require ( "Font7x11Numeric7Seg" ) . add ( Graphics ) ;
5
13
Graphics . prototype . setFontGochiHand = function ( scale ) {
6
14
// Actual height 27 (29 - 3)
@@ -13,14 +21,128 @@ Graphics.prototype.setFontGochiHand = function(scale) {
13
21
return this ;
14
22
}
15
23
16
- /*
24
+ /************************************************
17
25
* Set some important constants such as width, height and center
18
26
*/
19
27
var W = g . getWidth ( ) , R = W / 2 ;
20
28
var H = g . getHeight ( ) ;
21
29
var cx = W / 2 ;
22
30
var cy = H / 2 ;
23
31
var drawTimeout ;
32
+ var lock_input = false ;
33
+
34
+
35
+ /************************************************
36
+ * SETTINGS
37
+ */
38
+ const SETTINGS_FILE = "aiclock.setting.json" ;
39
+ let settings = {
40
+ menuPosX : 0 ,
41
+ menuPosY : 0 ,
42
+ } ;
43
+ let saved_settings = storage . readJSON ( SETTINGS_FILE , 1 ) || settings ;
44
+ for ( const key in saved_settings ) {
45
+ settings [ key ] = saved_settings [ key ]
46
+ }
47
+
48
+
49
+ /************************************************
50
+ * Menu
51
+ */
52
+ function getDate ( ) {
53
+ var date = new Date ( ) ;
54
+ return ( "0" + date . getDate ( ) ) . substr ( - 2 ) + "/" + ( "0" + ( date . getMonth ( ) + 1 ) ) . substr ( - 2 )
55
+ }
56
+
57
+
58
+ // Custom clockItems menu - therefore, its added here and not in a clkinfo.js file.
59
+ var clockItems = {
60
+ name : getDate ( ) ,
61
+ img : null ,
62
+ items : [
63
+ { name : "Week" ,
64
+ get : ( ) => ( { text : "Week " + weekOfYear ( ) , img : null } ) ,
65
+ show : function ( ) { clockItems . items [ 0 ] . emit ( "redraw" ) ; } ,
66
+ hide : function ( ) { }
67
+ } ,
68
+ ]
69
+ } ;
70
+
71
+ function weekOfYear ( ) {
72
+ var date = new Date ( ) ;
73
+ date . setHours ( 0 , 0 , 0 , 0 ) ;
74
+ // Thursday in current week decides the year.
75
+ date . setDate ( date . getDate ( ) + 3 - ( date . getDay ( ) + 6 ) % 7 ) ;
76
+ // January 4 is always in week 1.
77
+ var week1 = new Date ( date . getFullYear ( ) , 0 , 4 ) ;
78
+ // Adjust to Thursday in week 1 and count number of weeks from date to week1.
79
+ return 1 + Math . round ( ( ( date . getTime ( ) - week1 . getTime ( ) ) / 86400000
80
+ - 3 + ( week1 . getDay ( ) + 6 ) % 7 ) / 7 ) ;
81
+ }
82
+
83
+
84
+
85
+ // Load menu
86
+ var menu = clock_info . load ( ) ;
87
+ menu = menu . concat ( clockItems ) ;
88
+
89
+
90
+ // Ensure that our settings are still in range (e.g. app uninstall). Otherwise reset the position it.
91
+ if ( settings . menuPosX >= menu . length || settings . menuPosY > menu [ settings . menuPosX ] . items . length ) {
92
+ settings . menuPosX = 0 ;
93
+ settings . menuPosY = 0 ;
94
+ }
95
+
96
+ // Set draw functions for each item
97
+ menu . forEach ( ( menuItm , x ) => {
98
+ menuItm . items . forEach ( ( item , y ) => {
99
+ function drawItem ( ) {
100
+ // For the clock, we have a special case, as we don't wanna redraw
101
+ // immediately when something changes. Instead, we update data each minute
102
+ // to save some battery etc. Therefore, we hide (and disable the listener)
103
+ // immedeately after redraw...
104
+ item . hide ( ) ;
105
+
106
+ // After drawing the item, we enable inputs again...
107
+ lock_input = false ;
108
+
109
+ var info = item . get ( ) ;
110
+ drawMenuItem ( info . text , info . img ) ;
111
+ }
112
+
113
+ item . on ( 'redraw' , drawItem ) ;
114
+ } )
115
+ } ) ;
116
+
117
+
118
+ function canRunMenuItem ( ) {
119
+ if ( settings . menuPosY == 0 ) {
120
+ return false ;
121
+ }
122
+
123
+ var menuEntry = menu [ settings . menuPosX ] ;
124
+ var item = menuEntry . items [ settings . menuPosY - 1 ] ;
125
+ return item . run !== undefined ;
126
+ }
127
+
128
+
129
+ function runMenuItem ( ) {
130
+ if ( settings . menuPosY == 0 ) {
131
+ return ;
132
+ }
133
+
134
+ var menuEntry = menu [ settings . menuPosX ] ;
135
+ var item = menuEntry . items [ settings . menuPosY - 1 ] ;
136
+ try {
137
+ var ret = item . run ( ) ;
138
+ if ( ret ) {
139
+ Bangle . buzz ( 300 , 0.6 ) ;
140
+ }
141
+ } catch ( ex ) {
142
+ // Simply ignore it...
143
+ }
144
+ }
145
+
24
146
25
147
/*
26
148
* Based on the great multi clock from https://github.com/jeffmer/BangleApps/
@@ -76,7 +198,50 @@ function toAngle(a){
76
198
return a
77
199
}
78
200
201
+
202
+ function drawMenuItem ( text , image ) {
203
+ if ( text == null ) {
204
+ drawTime ( ) ;
205
+ return
206
+ }
207
+ // image = atob("GBiBAAD+AAH+AAH+AAH+AAH/AAOHAAYBgAwAwBgwYBgwYBgwIBAwOBAwOBgYIBgMYBgAYAwAwAYBgAOHAAH/AAH+AAH+AAH+AAD+AA==");
208
+
209
+ text = String ( text ) ;
210
+
211
+ g . reset ( ) . setBgColor ( "#fff" ) . setColor ( "#000" ) ;
212
+ g . setFontAlign ( 0 , 0 ) ;
213
+ g . setFont ( "Vector" , 20 ) ;
214
+
215
+ var imgWidth = image == null ? 0 : 24 ;
216
+ var strWidth = g . stringWidth ( text ) ;
217
+ var strHeight = text . split ( '\n' ) . length > 1 ? 40 : Math . max ( 24 , imgWidth + 2 ) ;
218
+ var w = imgWidth + strWidth ;
219
+
220
+ g . clearRect ( cx - w / 2 - 8 , 40 - strHeight / 2 - 1 , cx + w / 2 + 4 , 40 + strHeight / 2 )
221
+
222
+ // Draw right line as designed by stable diffusion
223
+ g . drawLine ( cx + w / 2 + 5 , 40 - strHeight / 2 - 1 , cx + w / 2 + 5 , 40 + strHeight / 2 ) ;
224
+ g . drawLine ( cx + w / 2 + 6 , 40 - strHeight / 2 - 1 , cx + w / 2 + 6 , 40 + strHeight / 2 ) ;
225
+ g . drawLine ( cx + w / 2 + 7 , 40 - strHeight / 2 - 1 , cx + w / 2 + 7 , 40 + strHeight / 2 ) ;
226
+
227
+ // And finally the text
228
+ g . drawString ( text , cx + imgWidth / 2 , 42 ) ;
229
+ g . drawString ( text , cx + 1 + imgWidth / 2 , 41 ) ;
230
+
231
+ if ( image != null ) {
232
+ var scale = image . width ? imgWidth / image . width : 1 ;
233
+ g . drawImage ( image , W / 2 + - strWidth / 2 - 4 - parseInt ( imgWidth / 2 ) , 41 - 12 , { scale : scale } ) ;
234
+ }
235
+
236
+ drawTime ( ) ;
237
+ }
238
+
239
+
79
240
function drawTime ( ) {
241
+ // Draw digital time first
242
+ drawDigits ( ) ;
243
+
244
+ // And now the analog time
80
245
var drawHourHand = g . drawRotRect . bind ( g , 8 , 12 , R - 38 ) ;
81
246
var drawMinuteHand = g . drawRotRect . bind ( g , 6 , 12 , R - 12 ) ;
82
247
@@ -90,42 +255,13 @@ function drawTime(){
90
255
h += date . getMinutes ( ) / 60.0 ;
91
256
h = parseInt ( h * 360 / 12 ) ;
92
257
93
- // Draw minute and hour bg
94
- g . setColor ( g . theme . bg ) ;
95
- drawHourHand ( toAngle ( h - 3 ) ) ;
96
- drawHourHand ( toAngle ( h + 3 ) ) ;
97
- drawMinuteHand ( toAngle ( m - 2 ) ) ;
98
- drawMinuteHand ( toAngle ( m + 3 ) ) ;
99
-
100
258
// Draw minute and hour fg
101
259
g . setColor ( g . theme . fg ) ;
102
260
drawHourHand ( h ) ;
103
261
drawMinuteHand ( m ) ;
104
262
}
105
263
106
264
107
-
108
- function drawDate ( ) {
109
- var date = new Date ( ) ;
110
- g . setFontAlign ( 0 , 0 ) ;
111
- g . setFontGochiHand ( ) ;
112
-
113
- var text = ( "0" + date . getDate ( ) ) . substr ( - 2 ) + "/" + ( "0" + ( date . getMonth ( ) + 1 ) ) . substr ( - 2 ) ;
114
- var w = g . stringWidth ( text ) ;
115
- g . setColor ( g . theme . bg ) ;
116
- g . fillRect ( cx - w / 2 - 4 , 20 , cx + w / 2 + 4 , 40 + 12 ) ;
117
-
118
- g . setColor ( g . theme . fg ) ;
119
- // Draw right line as designed by stable diffusion
120
- g . drawLine ( cx + w / 2 + 5 , 20 , cx + w / 2 + 5 , 40 + 12 ) ;
121
- g . drawLine ( cx + w / 2 + 6 , 20 , cx + w / 2 + 6 , 40 + 12 ) ;
122
- g . drawLine ( cx + w / 2 + 7 , 20 , cx + w / 2 + 7 , 40 + 12 ) ;
123
-
124
- // And finally the text
125
- g . drawString ( text , cx , 40 ) ;
126
- }
127
-
128
-
129
265
function drawDigits ( ) {
130
266
var date = new Date ( ) ;
131
267
@@ -156,20 +292,35 @@ function drawDigits(){
156
292
}
157
293
158
294
295
+ function drawDate ( ) {
296
+ var menuEntry = menu [ settings . menuPosX ] ;
297
+
298
+ // The first entry is the overview...
299
+ if ( settings . menuPosY == 0 ) {
300
+ drawMenuItem ( menuEntry . name , menuEntry . img ) ;
301
+ return ;
302
+ }
303
+
304
+ // Draw item if needed
305
+ lock_input = true ;
306
+ var item = menuEntry . items [ settings . menuPosY - 1 ] ;
307
+ item . show ( ) ;
308
+ }
309
+
310
+
311
+
312
+
159
313
160
314
function draw ( ) {
161
315
// Queue draw in one minute
162
316
queueDraw ( ) ;
163
317
164
-
165
318
g . reset ( ) ;
166
319
g . clearRect ( 0 , 0 , g . getWidth ( ) , g . getHeight ( ) ) ;
167
-
168
320
g . setColor ( 1 , 1 , 1 ) ;
321
+
169
322
drawBackground ( ) ;
170
323
drawDate ( ) ;
171
- drawDigits ( ) ;
172
- drawTime ( ) ;
173
324
drawCircle ( Bangle . isLocked ( ) ) ;
174
325
}
175
326
@@ -190,6 +341,68 @@ Bangle.on('lock', function(isLocked) {
190
341
drawCircle ( isLocked ) ;
191
342
} ) ;
192
343
344
+ Bangle . on ( 'touch' , function ( btn , e ) {
345
+ var left = parseInt ( g . getWidth ( ) * 0.22 ) ;
346
+ var right = g . getWidth ( ) - left ;
347
+ var upper = parseInt ( g . getHeight ( ) * 0.22 ) ;
348
+ var lower = g . getHeight ( ) - upper ;
349
+
350
+ var is_upper = e . y < upper ;
351
+ var is_lower = e . y > lower ;
352
+ var is_left = e . x < left && ! is_upper && ! is_lower ;
353
+ var is_right = e . x > right && ! is_upper && ! is_lower ;
354
+ var is_center = ! is_upper && ! is_lower && ! is_left && ! is_right ;
355
+
356
+ if ( lock_input ) {
357
+ return ;
358
+ }
359
+
360
+ if ( is_lower ) {
361
+ Bangle . buzz ( 40 , 0.6 ) ;
362
+ settings . menuPosY = ( settings . menuPosY + 1 ) % ( menu [ settings . menuPosX ] . items . length + 1 ) ;
363
+
364
+ draw ( ) ;
365
+ }
366
+
367
+ if ( is_upper ) {
368
+ Bangle . buzz ( 40 , 0.6 ) ;
369
+ settings . menuPosY = settings . menuPosY - 1 ;
370
+ settings . menuPosY = settings . menuPosY < 0 ? menu [ settings . menuPosX ] . items . length : settings . menuPosY ;
371
+
372
+ draw ( ) ;
373
+ }
374
+
375
+ if ( is_right ) {
376
+ Bangle . buzz ( 40 , 0.6 ) ;
377
+ settings . menuPosX = ( settings . menuPosX + 1 ) % menu . length ;
378
+ settings . menuPosY = 0 ;
379
+ draw ( ) ;
380
+ }
381
+
382
+ if ( is_left ) {
383
+ Bangle . buzz ( 40 , 0.6 ) ;
384
+ settings . menuPosY = 0 ;
385
+ settings . menuPosX = settings . menuPosX - 1 ;
386
+ settings . menuPosX = settings . menuPosX < 0 ? menu . length - 1 : settings . menuPosX ;
387
+ draw ( ) ;
388
+ }
389
+
390
+ if ( is_center ) {
391
+ if ( canRunMenuItem ( ) ) {
392
+ runMenuItem ( ) ;
393
+ }
394
+ }
395
+ } ) ;
396
+
397
+
398
+ E . on ( "kill" , function ( ) {
399
+ try {
400
+ storage . write ( SETTINGS_FILE , settings ) ;
401
+ } catch ( ex ) {
402
+ // If this fails, we still kill the app...
403
+ }
404
+ } ) ;
405
+
193
406
194
407
/*
195
408
* Some helpers
@@ -203,7 +416,6 @@ function queueDraw() {
203
416
}
204
417
205
418
206
-
207
419
/*
208
420
* Lets start widgets, listen for btn etc.
209
421
*/
@@ -216,6 +428,7 @@ Bangle.loadWidgets();
216
428
* area to the top bar doesn't get cleared.
217
429
*/
218
430
require ( 'widget_utils' ) . hide ( ) ;
431
+
219
432
// Clear the screen once, at startup and draw clock
220
433
g . setTheme ( { bg :"#fff" , fg :"#000" , dark :false } ) . clear ( ) ;
221
434
draw ( ) ;
0 commit comments