@@ -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,117 @@ 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+ const LINES_PER_SCREEN = APP_RECT . h / FONT_HEIGHT ;
299+ let initScroll ;
300+ var titleLines = [ ] ;
301+ let allLines = [ ] ;
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+ msgIter . new = false ;
306+
307+ var lines = [ ] ;
308+ const TITLE_STRING = msgIter . title || msgIter . sender || msgIter . subject || msgIter . src || /*LANG*/ "No Title" ;
309+ lines = g . wrapString ( TITLE_STRING , APP_RECT . w - 10 ) ;
310+ for ( let i = 0 ; i < lines . length ; i ++ ) {
311+ titleLines . 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+ function identifyDisplayedMsg ( scrollIdx ) {
324+ let firstTitleLinePerMsg = [ titleLines [ 0 ] ] ;
325+ for ( let i = 1 ; i < titleLines . length ; i ++ ) {
326+ if ( titleLines [ i ] - titleLines [ i - 1 ] === 1 ) { continue ; }
327+ firstTitleLinePerMsg . push ( titleLines [ i ] ) ;
328+ }
329+ for ( let i = titleLines . length - 1 ; i >= 0 ; i -- ) {
330+ if ( scrollIdx >= firstTitleLinePerMsg [ i ] ) {
331+ return MESSAGES [ i ] ;
332+ }
333+ }
334+ }
335+
336+ // Used to choose how to identify displayed message when selecting with hw button.
337+ let prevScrollIdxs = [ undefined , undefined ] ; // [prevIdx, prevPrevIdx]
338+
259339 E . showScroller ( {
260- h : g . getFontHeight ( ) , // height of each menu item in pixels
261- c : lines . length , // number of menu items
340+ scroll : initScroll ,
341+ h : FONT_HEIGHT , // height of each menu item in pixels
342+ c : allLines . length , // number of menu items
262343 // 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 ) ;
344+ draw : function ( scrollIdx , r ) { "ram" ;
345+ g . setBgColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . bg2 : g . theme . bg ) .
346+ setColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . fg2 : g . theme . fg ) .
347+ clearRect ( r ) ;
348+ g . setFont ( bodyFont ) . setFontAlign ( 0 , - 1 ) . drawString ( allLines [ scrollIdx ] , r . x + r . w / 2 , r . y ) ;
349+ if ( prevScrollIdxs [ 1 ] !== prevScrollIdxs [ 0 ] ) {
350+ prevScrollIdxs [ 1 ] = prevScrollIdxs [ 0 ] ;
351+ if ( ! persist ) { resetReloadTimeout ( ) ; }
352+ }
353+ prevScrollIdxs [ 0 ] = scrollIdx ;
272354 } ,
273- back : ( ) => showMessage ( msg . id , true )
355+ select : function ( scrollIdx , touch ) {
356+ WU . show ( ) ;
357+ const MSG_SELECT = identifyDisplayedMsg ( scrollIdx ) ;
358+ clearBtnHandler ( ) ;
359+ if ( ! touch ) { showMessageRouter ( MSG_SELECT , true , "overview" ) ; return ; }
360+ if ( touch . type == 0 ) { showMessageRouter ( MSG_SELECT , true , "overview" ) ; }
361+ if ( touch . type == 2 ) { showMessageSettings ( MSG_SELECT ) ; }
362+ }
274363 } ) ;
364+
365+ function clearBtnHandler ( ) {
366+ if ( Bangle . btnHandler ) { clearWatch ( Bangle . btnHandler ) ; Bangle . btnHandler = undefined ; }
367+ }
368+ clearBtnHandler ( ) ;
369+
370+ // If Bangle.js 2 add an external select hw button handler.
371+ Bangle . btnHandler = ( ( 2 === process . env . HWVERSION ) && ( setWatch ( ( ) => {
372+ Bangle . emit ( "drag" , { dy :0 } ) ; // Compatibility with `kineticscroll`, stopping the scroller so it doesn't continue scrolling when the `showMessageOverview` screen is loaded.
373+ // Zero ms timeout as to not move on before the scroller has registered the emitted drag event.
374+ setTimeout ( ( ) => {
375+ if ( "messagegui.new.js" === global . __FILE__ ) { return load ( ) ; }
376+ const SCROLL_IDX_CENTER_SCREEN = prevScrollIdxs [ 0 ] > prevScrollIdxs [ 1 ] ?
377+ prevScrollIdxs [ 0 ] - LINES_PER_SCREEN / 2 :prevScrollIdxs [ 0 ] + LINES_PER_SCREEN / 2 ;
378+ WU . show ( ) ;
379+ showMessageOverview ( identifyDisplayedMsg ( SCROLL_IDX_CENTER_SCREEN ) . id , true ) ;
380+ } , 0 ) ;
381+ } , BTN , { edge :'rising' } ) ) ) ;
275382}
276383
277384function showMessageSettings ( msg ) {
278385 active = "settings" ;
279386 var menu = { "" :{
280387 "title" :/*LANG*/ "Message" ,
281- back :( ) => showMessage ( msg . id , true )
388+ back :( ) => showMessageOverview ( msg . id , true )
282389 } ,
283390 } ;
284391
285392 if ( msg . id != "music" )
286- menu [ /*LANG*/ "View Message" ] = ( ) => showMessageScroller ( msg ) ;
393+ menu [ /*LANG*/ "View Message" ] = ( ) => showMessagesScroller ( msg ) ;
287394
288395 if ( msg . reply && reply ) {
289396 menu [ /*LANG*/ "Reply" ] = ( ) => {
@@ -292,11 +399,11 @@ function showMessageSettings(msg) {
292399 . then ( result => {
293400 Bluetooth . println ( JSON . stringify ( result ) ) ;
294401 replying = false ;
295- showMessage ( msg . id ) ;
402+ showMessageOverview ( msg . id ) ;
296403 } )
297404 . catch ( ( ) => {
298405 replying = false ;
299- showMessage ( msg . id ) ;
406+ showMessageOverview ( msg . id ) ;
300407 } ) ;
301408 } ;
302409 }
@@ -340,7 +447,7 @@ function showMessageSettings(msg) {
340447 E . showMenu ( menu ) ;
341448}
342449
343- function showMessage ( msgid , persist ) {
450+ function showMessageOverview ( msgid , persist ) {
344451 if ( replying ) { return ; }
345452 if ( ! persist ) resetReloadTimeout ( ) ;
346453 let idx = MESSAGES . findIndex ( m => m . id == msgid ) ;
@@ -350,15 +457,7 @@ function showMessage(msgid, persist) {
350457 updateLabelsInterval = undefined ;
351458 }
352459 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" ;
460+ active = "overview" ;
362461 // Normal text message display
363462 var title = msg . title , titleFont = fontLarge , lines ;
364463 var body = msg . body , bodyFont = fontLarge ;
@@ -426,7 +525,7 @@ function showMessage(msgid, persist) {
426525 . catch ( ( ) => {
427526 replying = false ;
428527 layout . render ( ) ;
429- showMessage ( msg . id ) ;
528+ showMessageOverview ( msg . id ) ;
430529 } ) ;
431530 } ; footer . push ( { type :"img" , src :atob ( "QRABAAAAAAAH//+AAAAABgP//8AAAAADgf//4AAAAAHg4ABwAAAAAPh8APgAAAAAfj+B////////geHv///////hf+f///////GPw///////8cGBwAAAAAPx/gDgAAAAAfD/gHAAAAAA8DngOAAAAABwDHP8AAAAADACGf4AAAAAAAAM/w==" ) , col :"#0f0" , cb :posHandler } ) ;
432531 }
@@ -456,16 +555,16 @@ function showMessage(msgid, persist) {
456555 ] } ,
457556 { type :"txt" , font :bodyFont , label :body , fillx :1 , filly :1 , pad :2 , cb :( ) => {
458557 // allow tapping to show a larger version
459- showMessageScroller ( msg ) ;
558+ showMessagesScroller ( msg ) ;
460559 } } ,
461560 { type :"h" , fillx :1 , c : footer }
462561 ] } , { back :goBack } ) ;
463562
464563 Bangle . swipeHandler = ( lr , ud ) => {
465564 if ( lr > 0 && posHandler ) posHandler ( ) ;
466565 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 ) ;
566+ if ( ud > 0 && idx < MESSAGES . length - 1 ) showMessageOverview ( MESSAGES [ idx + 1 ] . id , true ) ;
567+ if ( ud < 0 && idx > 0 ) showMessageOverview ( MESSAGES [ idx - 1 ] . id , true ) ;
469568 } ;
470569 Bangle . on ( "swipe" , Bangle . swipeHandler ) ;
471570 g . reset ( ) . clearRect ( Bangle . appRect ) ;
@@ -502,8 +601,8 @@ function checkMessages(options) {
502601 // If we have a new message, show it
503602 if ( ! options . ignoreUnread && newMessages . length ) {
504603 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
604+ showMessagesScroller ( newMessages [ 0 ] , false ) ;
605+ // buzz after showMessagesScroller , so being busy during scroller setup doesn't affect the buzz pattern
507606 if ( global . BUZZ_ON_NEW_MESSAGE ) {
508607 // this is set if we entered the messages app by loading `messagegui.new.js`
509608 // ... but only buzz the first time we view a new message
@@ -515,7 +614,7 @@ function checkMessages(options) {
515614 }
516615 // no new messages: show playing music? Only if we have playing music, or state=="show" (set by messagesmusic)
517616 if ( options . openMusic && MESSAGES . some ( m => m . id == "music" && ( ( m . track && m . state == "play" ) || m . state == "show" ) ) )
518- return showMessage ( 'music' , true ) ;
617+ return showMessageOverview ( 'music' , true ) ;
519618 // no new messages - go to clock?
520619 if ( options . clockIfAllRead && newMessages . length == 0 )
521620 return load ( ) ;
@@ -524,7 +623,7 @@ function checkMessages(options) {
524623 E . showScroller ( {
525624 h : 48 ,
526625 c : Math . max ( MESSAGES . length , 3 ) , // workaround for 2v10.219 firmware (min 3 not needed for 2v11)
527- draw : function ( idx , r ) { "ram"
626+ draw : function ( idx , r ) { "ram" ;
528627 var msg = MESSAGES [ idx ] ;
529628 if ( msg && msg . new ) g . setBgColor ( g . theme . bgH ) . setColor ( g . theme . fgH ) ;
530629 else g . setBgColor ( g . theme . bg ) . setColor ( g . theme . fg ) ;
@@ -564,13 +663,13 @@ function checkMessages(options) {
564663 } ,
565664 select : idx => {
566665 if ( idx < MESSAGES . length )
567- showMessage ( MESSAGES [ idx ] . id , true ) ;
666+ showMessageRouter ( MESSAGES [ idx ] , true , "overview" ) ;
568667 } ,
569668 back : ( ) => load ( )
570669 } ) ;
571670}
572671
573- function returnToCheckMessages ( clock ) {
672+ function returnToCheckMessages ( ) {
574673 checkMessages ( { clockIfNoMsg :1 , clockIfAllRead :1 , ignoreUnread :settings . ignoreUnread , openMusic} ) ;
575674}
576675
@@ -611,8 +710,14 @@ setTimeout(() => {
611710} , 10 ) ; // if checkMessages wants to 'load', do that
612711
613712/* If the Bangle is unlocked by the user, treat that
614- as a queue to stop repeated buzzing */
713+ as a queue to stop repeated buzzing.
714+ Also suspend the reload timeout while the watch is unlocked. */
615715Bangle . on ( 'lock' , locked => {
616- if ( ! locked )
716+ if ( ! locked ) {
617717 require ( "messages" ) . stopBuzz ( ) ;
718+ cancelReloadTimeout ( ) ;
719+ }
720+ if ( locked ) {
721+ if ( "messagegui.new.js" === global . __FILE__ ) { resetReloadTimeout ( ) ; }
722+ }
618723} ) ;
0 commit comments