@@ -45,7 +45,7 @@ if (Graphics.prototype.setFontIntl) {
4545 fontVLarge = noScale ?"Intl" :"Intl:3" ;
4646}
4747
48- var active ; // active screen (undefined/"list"/"music"/"map"/"message "/"scroller"/"settings")
48+ var active ; // active screen (undefined/"list"/"music"/"map"/"overview "/"scroller"/"settings")
4949var openMusic = false ; // go back to music screen after we handle something else?
5050var replying = false ; // If we're replying to a message, don't interrupt
5151// hack for 2v10 firmware's lack of ':size' font handling
@@ -90,7 +90,8 @@ var onMessagesModified = function(type,msg) {
9090 }
9191 if ( msg && msg . id == "nav" && msg . t == "modify" && active != "map" )
9292 return ; // don't show an updated nav message if we're just in the menu
93- showMessage ( msg && msg . id , false ) ;
93+ let persist = "messagegui.new.js" === global . __FILE__ ?false :true ;
94+ showMessageRouter ( msg , persist , "dependsOnActive" ) ;
9495} ;
9596Bangle . on ( "message" , onMessagesModified ) ;
9697
@@ -99,6 +100,39 @@ function saveMessages() {
99100}
100101E . on ( "kill" , saveMessages ) ;
101102
103+ function showMessageRouter ( msg , persist , explicitDestnation ) {
104+ //explicitDestnation (undefined/"scroller"/"overview"/"dependsOnActive")
105+
106+ ////var active; // active screen (undefined/"list"/"music"/"map"/"overview"/"scroller"/"settings")
107+ //if (active==undefined) { } else if (active=="list") ... //and so on.
108+
109+ if ( persist ) { cancelReloadTimeout ( ) }
110+
111+ if ( msg . id == "music" ) {
112+ cancelReloadTimeout ( ) ; // don't auto-reload to clock now
113+ return showMusicMessage ( msg ) ;
114+ }
115+ if ( msg . id == "nav" ) {
116+ cancelReloadTimeout ( ) ; // don't auto-reload to clock now
117+ return showMapMessage ( msg ) ;
118+ }
119+ if ( msg . id == "call" ) {
120+ return showMessageOverview ( msg . id , persist ) ;
121+ }
122+ if ( "scroller" === explicitDestnation ) {
123+ return showMessagesScroller ( msg , persist ) ;
124+ }
125+ if ( "overview" === explicitDestnation ) {
126+ return showMessageOverview ( msg . id , persist ) ;
127+ }
128+ if ( "dependsOnActive" === explicitDestnation ) {
129+ if ( "scroller" === active ) { return showMessagesScroller ( msg , persist ) ; } // reinit scroller with updated messages list.
130+ if ( "list" === active ) { return returnToMain ( ) ; }
131+ if ( "settings" === active || "overview" === active ) { return ; }
132+ }
133+ //if (false) {showMessageSettings(msg);}
134+ }
135+
102136function showMapMessage ( msg ) {
103137 active = "map" ;
104138 require ( "messages" ) . stopBuzz ( ) ; // stop repeated buzzing while the map is showing
@@ -246,44 +280,136 @@ function showMusicMessage(msg) {
246280 } , 400 ) ;
247281}
248282
249- function showMessageScroller ( msg ) {
250- cancelReloadTimeout ( ) ;
283+ function showMessagesScroller ( msg , persist ) {
284+ if ( persist === undefined ) { persist = true ; }
285+ const MSG_IDX = msg ? MESSAGES . findIndex ( ( m ) => m . id == msg . id ) : undefined ;
286+
287+ if ( replying ) { return ; }
251288 active = "scroller" ;
289+ if ( persist ) { cancelReloadTimeout ( ) ; } else { resetReloadTimeout ( ) ; }
290+
291+ const WU = require ( "widget_utils" ) ;
292+ WU . hide ( ) ;
293+ const APP_RECT = Bangle . appRect ;
294+
252295 var bodyFont = fontBig ;
253296 g . setFont ( bodyFont ) ;
254- var lines = [ ] ;
255- if ( msg . title ) lines = g . wrapString ( msg . title , g . getWidth ( ) - 10 ) ;
256- var titleCnt = lines . length ;
257- if ( titleCnt ) lines . push ( "" ) ; // add blank line after title
258- lines = lines . concat ( g . wrapString ( msg . body , g . getWidth ( ) - 10 ) , [ "" , /*LANG*/ "< Back" ] ) ;
297+ const FONT_HEIGHT = g . getFontHeight ( ) ;
298+ let initScroll ;
299+ var titleLines = [ ] ;
300+ let allLines = [ ] ;
301+ let firstTitleLinePerMsg = [ ] ;
302+ for ( let i = 0 ; i < MESSAGES . length ; i ++ ) {
303+ if ( MSG_IDX === i ) { initScroll = allLines . length * FONT_HEIGHT }
304+ let msgIter = MESSAGES [ i ] ;
305+
306+ var lines = [ ] ;
307+ const TITLE_STRING = msgIter . title || msgIter . sender || msgIter . subject || msgIter . src || /*LANG*/ "No Title" ;
308+ lines = g . wrapString ( TITLE_STRING , APP_RECT . w - 10 ) ;
309+ for ( let i = 0 ; i < lines . length ; i ++ ) {
310+ titleLines . push ( i + allLines . length ) ;
311+ if ( i == 0 ) firstTitleLinePerMsg . push ( i + allLines . length ) ;
312+ }
313+ lines = lines . concat ( g . wrapString ( msgIter . body , APP_RECT . w - 10 ) ,
314+ [ "-" . repeat ( 12 ) ] ) ;
315+ allLines = allLines . concat ( lines ) ;
316+ }
317+
318+ if ( allLines . length == 0 ) {
319+ cancelReloadTimeout ( ) ;
320+ returnToClockIfEmpty ( ) ;
321+ }
322+
323+ let shownIdxFirst = allLines . length
324+ let shownIdxLast = 0 ;
325+
259326 E . showScroller ( {
260- h : g . getFontHeight ( ) , // height of each menu item in pixels
261- c : lines . length , // number of menu items
327+ scroll : initScroll ,
328+ h : FONT_HEIGHT , // height of each menu item in pixels
329+ c : allLines . length , // number of menu items
262330 // a function to draw a menu item
263- draw : function ( idx , r ) {
264- // FIXME: in 2v13 onwards, clearRect(r) will work fine. There's a bug in 2v12
265- g . setBgColor ( idx < titleCnt ? g . theme . bg2 : g . theme . bg ) .
266- setColor ( idx < titleCnt ? g . theme . fg2 : g . theme . fg ) .
267- clearRect ( r . x , r . y , r . x + r . w , r . y + r . h ) ;
268- g . setFont ( bodyFont ) . setFontAlign ( 0 , - 1 ) . drawString ( lines [ idx ] , r . x + r . w / 2 , r . y ) ;
269- } , select : function ( idx ) {
270- if ( idx >= lines . length - 2 )
271- showMessage ( msg . id , true ) ;
331+ draw : function ( scrollIdx , r ) { "ram" ;
332+ //print(scrollIdx)
333+ g . setBgColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . bg2 : g . theme . bg ) .
334+ setColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . fg2 : g . theme . fg ) .
335+ clearRect ( r ) ;
336+ g . setFont ( bodyFont ) . setFontAlign ( 0 , - 1 ) . drawString ( allLines [ scrollIdx ] , r . x + r . w / 2 , r . y ) ;
337+ if ( scrollIdx < shownIdxFirst ) { shownIdxFirst = scrollIdx ; }
338+ if ( scrollIdx > shownIdxLast ) { shownIdxLast = scrollIdx ; }
339+ if ( ! persist ) { resetReloadTimeout ( ) ; }
272340 } ,
273- back : ( ) => showMessage ( msg . id , true )
341+ select : function ( scrollIdx , touch ) {
342+ WU . show ( ) ;
343+ for ( let i = firstTitleLinePerMsg . length - 1 ; i >= 0 ; i -- ) {
344+ if ( scrollIdx >= firstTitleLinePerMsg [ i ] ) {
345+ if ( ! touch || touch . type === 0 ) {
346+ showMessageRouter ( MESSAGES [ i ] , true , "overview" )
347+ } else if ( touch . type == 2 ) {
348+ showMessageSettings ( MESSAGES [ i ] ) ;
349+ }
350+ break ;
351+ }
352+ }
353+ clearBtnHandler ( ) ;
354+ updateReadMessages ( ) ;
355+ }
274356 } ) ;
357+
358+
359+ // If Bangle.js 2 add an external select hw button handler.
360+ let btnHandler = ( ( 2 === process . env . HWVERSION ) && ( setWatch ( ( ) => {
361+ Bangle . emit ( "drag" , { dy :0 } ) ; // Compatibility with `kineticscroll`, stopping the scroller so it doesn't continue scrolling when the `showMessageOverview` screen is loaded.
362+ // Zero ms timeout as to not move on before the scroller has registered the emitted drag event.
363+ setTimeout ( ( ) => {
364+ if ( "messagegui.new.js" === global . __FILE__ ) { return load ( ) ; }
365+ Bangle . emit ( "touch" , 1 , { x :APP_RECT . x2 / 2 , y :APP_RECT . y2 / 2 , type :0 } ) ;
366+ } , 0 ) ;
367+ } , BTN , { edge :'rising' , repeat :true } ) ) ) ;
368+
369+ function clearBtnHandler ( ) {
370+ if ( btnHandler ) { clearWatch ( btnHandler ) ; btnHandler = undefined ; }
371+ }
372+
373+ function updateReadMessages ( ) {
374+ let shownMsgIdxFirst , shownMsgIdxLast ;
375+ const LINES_PER_SCREEN = APP_RECT . h / FONT_HEIGHT ;
376+ //print(firstTitleLinePerMsg)
377+ //print(shownIdxFirst, shownIdxLast)
378+
379+ for ( let i = 0 ; i < firstTitleLinePerMsg . length - 1 ; i ++ ) {
380+
381+ if ( shownIdxFirst <= firstTitleLinePerMsg [ i ] && shownIdxFirst + LINES_PER_SCREEN > firstTitleLinePerMsg [ i ] ) {
382+ shownMsgIdxFirst = i ;
383+ }
384+
385+ if ( shownIdxLast >= firstTitleLinePerMsg [ i + 1 ] && shownIdxLast - LINES_PER_SCREEN < firstTitleLinePerMsg [ i + 1 ] ) {
386+ shownMsgIdxLast = i ;
387+ //print(i)
388+ }
389+
390+ }
391+ if ( shownIdxLast === allLines . length - 1 ) { shownMsgIdxLast = MESSAGES . length - 1 ; }
392+
393+ //print(shownIdxFirst, shownIdxLast)
394+ //print(shownMsgIdxFirst, shownMsgIdxLast)
395+ //print(MESSAGES)
396+ for ( let i = shownMsgIdxFirst ; i < shownMsgIdxLast + 1 ; i ++ ) {
397+ MESSAGES [ i ] . new = false ;
398+ }
399+ //print(MESSAGES)
400+ }
275401}
276402
277403function showMessageSettings ( msg ) {
278404 active = "settings" ;
279405 var menu = { "" :{
280406 "title" :/*LANG*/ "Message" ,
281- back :( ) => showMessage ( msg . id , true )
407+ back :( ) => showMessageOverview ( msg . id , true )
282408 } ,
283409 } ;
284410
285411 if ( msg . id != "music" )
286- menu [ /*LANG*/ "View Message" ] = ( ) => showMessageScroller ( msg ) ;
412+ menu [ /*LANG*/ "View Message" ] = ( ) => showMessagesScroller ( msg ) ;
287413
288414 if ( msg . reply && reply ) {
289415 menu [ /*LANG*/ "Reply" ] = ( ) => {
@@ -292,11 +418,11 @@ function showMessageSettings(msg) {
292418 . then ( result => {
293419 Bluetooth . println ( JSON . stringify ( result ) ) ;
294420 replying = false ;
295- showMessage ( msg . id ) ;
421+ showMessageOverview ( msg . id ) ;
296422 } )
297423 . catch ( ( ) => {
298424 replying = false ;
299- showMessage ( msg . id ) ;
425+ showMessageOverview ( msg . id ) ;
300426 } ) ;
301427 } ;
302428 }
@@ -340,7 +466,7 @@ function showMessageSettings(msg) {
340466 E . showMenu ( menu ) ;
341467}
342468
343- function showMessage ( msgid , persist ) {
469+ function showMessageOverview ( msgid , persist ) {
344470 if ( replying ) { return ; }
345471 if ( ! persist ) resetReloadTimeout ( ) ;
346472 let idx = MESSAGES . findIndex ( m => m . id == msgid ) ;
@@ -350,15 +476,7 @@ function showMessage(msgid, persist) {
350476 updateLabelsInterval = undefined ;
351477 }
352478 if ( ! msg ) return returnToClockIfEmpty ( ) ; // go home if no message found
353- if ( msg . id == "music" ) {
354- cancelReloadTimeout ( ) ; // don't auto-reload to clock now
355- return showMusicMessage ( msg ) ;
356- }
357- if ( msg . id == "nav" ) {
358- cancelReloadTimeout ( ) ; // don't auto-reload to clock now
359- return showMapMessage ( msg ) ;
360- }
361- active = "message" ;
479+ active = "overview" ;
362480 // Normal text message display
363481 var title = msg . title , titleFont = fontLarge , lines ;
364482 var body = msg . body , bodyFont = fontLarge ;
@@ -426,7 +544,7 @@ function showMessage(msgid, persist) {
426544 . catch ( ( ) => {
427545 replying = false ;
428546 layout . render ( ) ;
429- showMessage ( msg . id ) ;
547+ showMessageOverview ( msg . id ) ;
430548 } ) ;
431549 } ; footer . push ( { type :"img" , src :atob ( "QRABAAAAAAAH//+AAAAABgP//8AAAAADgf//4AAAAAHg4ABwAAAAAPh8APgAAAAAfj+B////////geHv///////hf+f///////GPw///////8cGBwAAAAAPx/gDgAAAAAfD/gHAAAAAA8DngOAAAAABwDHP8AAAAADACGf4AAAAAAAAM/w==" ) , col :"#0f0" , cb :posHandler } ) ;
432550 }
@@ -456,16 +574,16 @@ function showMessage(msgid, persist) {
456574 ] } ,
457575 { type :"txt" , font :bodyFont , label :body , fillx :1 , filly :1 , pad :2 , cb :( ) => {
458576 // allow tapping to show a larger version
459- showMessageScroller ( msg ) ;
577+ showMessagesScroller ( msg ) ;
460578 } } ,
461579 { type :"h" , fillx :1 , c : footer }
462580 ] } , { back :goBack } ) ;
463581
464582 Bangle . swipeHandler = ( lr , ud ) => {
465583 if ( lr > 0 && posHandler ) posHandler ( ) ;
466584 if ( lr < 0 && negHandler ) negHandler ( ) ;
467- if ( ud > 0 && idx < MESSAGES . length - 1 ) showMessage ( MESSAGES [ idx + 1 ] . id , true ) ;
468- if ( ud < 0 && idx > 0 ) showMessage ( MESSAGES [ idx - 1 ] . id , true ) ;
585+ if ( ud > 0 && idx < MESSAGES . length - 1 ) showMessageOverview ( MESSAGES [ idx + 1 ] . id , true ) ;
586+ if ( ud < 0 && idx > 0 ) showMessageOverview ( MESSAGES [ idx - 1 ] . id , true ) ;
469587 } ;
470588 Bangle . on ( "swipe" , Bangle . swipeHandler ) ;
471589 g . reset ( ) . clearRect ( Bangle . appRect ) ;
@@ -502,8 +620,8 @@ function checkMessages(options) {
502620 // If we have a new message, show it
503621 if ( ! options . ignoreUnread && newMessages . length ) {
504622 delete newMessages [ 0 ] . show ; // stop us getting stuck here if we're called a second time
505- showMessage ( newMessages [ 0 ] . id , false ) ;
506- // buzz after showMessage , so being busy during layout doesn't affect the buzz pattern
623+ showMessagesScroller ( newMessages [ 0 ] , false ) ;
624+ // buzz after showMessagesScroller , so being busy during scroller setup doesn't affect the buzz pattern
507625 if ( global . BUZZ_ON_NEW_MESSAGE ) {
508626 // this is set if we entered the messages app by loading `messagegui.new.js`
509627 // ... but only buzz the first time we view a new message
@@ -515,7 +633,7 @@ function checkMessages(options) {
515633 }
516634 // no new messages: show playing music? Only if we have playing music, or state=="show" (set by messagesmusic)
517635 if ( options . openMusic && MESSAGES . some ( m => m . id == "music" && ( ( m . track && m . state == "play" ) || m . state == "show" ) ) )
518- return showMessage ( 'music' , true ) ;
636+ return showMessageOverview ( 'music' , true ) ;
519637 // no new messages - go to clock?
520638 if ( options . clockIfAllRead && newMessages . length == 0 )
521639 return load ( ) ;
@@ -524,7 +642,7 @@ function checkMessages(options) {
524642 E . showScroller ( {
525643 h : 48 ,
526644 c : Math . max ( MESSAGES . length , 3 ) , // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
527- draw : function ( idx , r ) { "ram"
645+ draw : function ( idx , r ) { "ram" ;
528646 var msg = MESSAGES [ idx ] ;
529647 if ( msg && msg . new ) g . setBgColor ( g . theme . bgH ) . setColor ( g . theme . fgH ) ;
530648 else g . setBgColor ( g . theme . bg ) . setColor ( g . theme . fg ) ;
@@ -564,13 +682,13 @@ function checkMessages(options) {
564682 } ,
565683 select : idx => {
566684 if ( idx < MESSAGES . length )
567- showMessage ( MESSAGES [ idx ] . id , true ) ;
685+ showMessageRouter ( MESSAGES [ idx ] , true , "overview" ) ;
568686 } ,
569687 back : ( ) => load ( )
570688 } ) ;
571689}
572690
573- function returnToCheckMessages ( clock ) {
691+ function returnToCheckMessages ( ) {
574692 checkMessages ( { clockIfNoMsg :1 , clockIfAllRead :1 , ignoreUnread :settings . ignoreUnread , openMusic} ) ;
575693}
576694
@@ -611,8 +729,14 @@ setTimeout(() => {
611729} , 10 ) ; // if checkMessages wants to 'load', do that
612730
613731/* If the Bangle is unlocked by the user, treat that
614- as a queue to stop repeated buzzing */
732+ as a queue to stop repeated buzzing.
733+ Also suspend the reload timeout while the watch is unlocked. */
615734Bangle . on ( 'lock' , locked => {
616- if ( ! locked )
735+ if ( ! locked ) {
617736 require ( "messages" ) . stopBuzz ( ) ;
737+ cancelReloadTimeout ( ) ;
738+ }
739+ if ( locked ) {
740+ if ( "messagegui.new.js" === global . __FILE__ ) { resetReloadTimeout ( ) ; }
741+ }
618742} ) ;
0 commit comments