@@ -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+ //showMessage(msg&&msg.id, false);
94+ showMessagesScroller ( msg , false )
9495} ;
9596Bangle . on ( "message" , onMessagesModified ) ;
9697
@@ -246,32 +247,163 @@ function showMusicMessage(msg) {
246247 } , 400 ) ;
247248}
248249
249- function showMessageScroller ( msg ) {
250- cancelReloadTimeout ( ) ;
250+ function showMessagesScroller ( msg , persist , alreadyProcessed ) {
251+ if ( persist === undefined ) { persist = true ; }
252+ const MSG_IDX = msg ? MESSAGES . findIndex ( ( m ) => m . id == msg . id ) : 0 ;
253+ const INITIATED_FROM = (
254+ alreadyProcessed === undefined ? "other function" :
255+ ( MSG_IDX <= alreadyProcessed . idxSpan . start ? "scrolling up" :
256+ ( MSG_IDX >= alreadyProcessed . idxSpan . stop - 1 ? "scrolling down" :
257+ undefined ) )
258+ ) ;
259+ if ( ! alreadyProcessed ) { alreadyProcessed = { idxSpan :{ } } ; } // So `alreadyProcessed.idxSpan.start/stop` can be looked for on first run.
260+
261+ const WU = require ( "widget_utils" ) ;
262+ WU . hide ( ) ;
263+
264+ if ( replying ) { return ; }
265+ if ( persist ) { cancelReloadTimeout ( ) ; } else { resetReloadTimeout ( ) ; }
266+
267+ let idxSpan = (
268+ INITIATED_FROM === "other function" ?
269+ { start : Math . max ( MSG_IDX - 1 , 0 ) , stop : Math . min ( MSG_IDX + 2 , MESSAGES . length ) } :
270+ ( INITIATED_FROM === "scrolling up" ?
271+ { start : MSG_IDX , stop : alreadyProcessed . idxSpan . start } :
272+ ( INITIATED_FROM === "scrolling down" ?
273+ { start : alreadyProcessed . idxSpan . stop , stop : Math . min ( MSG_IDX + 1 , MESSAGES . length ) } :
274+ undefined ) )
275+ ) ;
276+
251277 active = "scroller" ;
252278 var bodyFont = fontBig ;
253279 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" ] ) ;
280+ var titleLines = [ ] ;
281+ var messagesWrapped = [ ] ;
282+ for ( let i = idxSpan . start ; i < idxSpan . stop ; i ++ ) {
283+ let msgLocal = MESSAGES [ i ] ;
284+ msgLocal . new = false ;
285+
286+ if ( msgLocal . id == "music" || msgLocal . source == "maps" || msgLocal . id == "call" ) {
287+ idxSpan . stop ++
288+ if ( idxSpan . stop >= MESSAGES . length ) { break ; }
289+ continue ;
290+ }
291+
292+ var lines = [ ] ;
293+ const TITLE_STRING = msgLocal . title || msgLocal . sender || msgLocal . subject || msgLocal . src || "No Title" ;
294+ //const TITLE_STRING = "".concat(msgLocal.title, msgLocal.title&&"\n",
295+ // msgLocal.sender, msgLocal.sender&&"\n",
296+ // msgLocal.subject, msgLocal.subject&&"\n", msgLocal.src) || "No Title";
297+ lines = g . wrapString ( TITLE_STRING , g . getWidth ( ) - 10 ) ;
298+ for ( let i = 0 ; i < lines . length ; i ++ ) {
299+ titleLines . push ( i + ( messagesWrapped [ 0 ] ?messagesWrapped [ 0 ] . length :0 ) +
300+ ( messagesWrapped [ 1 ] ?messagesWrapped [ 1 ] . length :0 ) ) ;
301+ }
302+ lines = lines . concat ( g . wrapString ( msgLocal . body , g . getWidth ( ) - 10 ) ,
303+ [ "-" . repeat ( 12 ) ] ) ;
304+ messagesWrapped . push ( lines ) ;
305+ }
306+
307+ let allLines = [ ] ;
308+ for ( let i = 0 ; i < messagesWrapped . length ; i ++ ) {
309+ allLines = allLines . concat ( messagesWrapped [ i ] ) ;
310+ }
311+
312+ var initScroll = messagesWrapped [ 0 ] . length ;
313+ if ( INITIATED_FROM === "other function" ) {
314+ if ( MSG_IDX == 0 ) { initScroll = 0 ; }
315+ } else if ( INITIATED_FROM === "scrolling up" ) {
316+ titleLines = titleLines . concat ( alreadyProcessed . titleLines .
317+ map ( ( x ) => x + allLines . length ) ) ;
318+ allLines = allLines . concat ( alreadyProcessed . lines ) ;
319+ } else if ( INITIATED_FROM === "scrolling down" ) {
320+ initScroll = alreadyProcessed . lines . length - ( g . getHeight ( ) / g . getFontHeight ( ) ) ;
321+ titleLines = alreadyProcessed . titleLines . concat ( titleLines .
322+ map ( ( x ) => x + alreadyProcessed . lines . length ) ) ;
323+ allLines = alreadyProcessed . lines . concat ( allLines ) ;
324+ }
325+
326+ if ( allLines . length == 0 && alreadyProcessed . lines . length == 0 ) {
327+ cancelReloadTimeout ( ) ;
328+ returnToClockIfEmpty ( ) ;
329+ }
330+
331+ alreadyProcessed = { // Update with the newly processed messages.
332+ lines : allLines ,
333+ titleLines : titleLines ,
334+ idxSpan : {
335+ start : Math . min ( idxSpan . start ,
336+ ( alreadyProcessed . idxSpan . start === undefined ) ?
337+ MESSAGES . length : alreadyProcessed . idxSpan . start ) ,
338+ stop : Math . max ( idxSpan . stop , alreadyProcessed . idxSpan . stop || 0 ) }
339+ } ;
340+
341+ function identifyDisplayedMsg ( scrollIdx ) {
342+ let firstTitleLinePerMsg = [ titleLines [ 0 ] ] ;
343+ for ( let i = 1 ; i < titleLines . length ; i ++ ) {
344+ if ( titleLines [ i ] - titleLines [ i - 1 ] === 1 ) { continue ; }
345+ firstTitleLinePerMsg . push ( titleLines [ i ] ) ;
346+ }
347+ for ( let i = titleLines . length - 1 ; i >= 0 ; i -- ) {
348+ if ( scrollIdx >= firstTitleLinePerMsg [ i ] ) {
349+ return MESSAGES [ i + alreadyProcessed . idxSpan . start ] ;
350+ }
351+ }
352+ }
353+
354+ let prevScrollIdx ; // Used for stopping repeated triggering of next message by the scroller.
355+ let prevPrevScrollIdx ; // Used to chose how to identify displayed message when selecting with button.
356+
259357 E . showScroller ( {
358+ scroll : initScroll * g . getFontHeight ( ) ,
260359 h : g . getFontHeight ( ) , // height of each menu item in pixels
261- c : lines . length , // number of menu items
360+ c : allLines . length , // number of menu items
262361 // 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 ) ;
362+ draw : function ( scrollIdx , r ) {
363+ "ram" ;
364+ g . setBgColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . bg2 : g . theme . bg ) .
365+ setColor ( titleLines . find ( e => e == scrollIdx ) !== undefined ? g . theme . fg2 : g . theme . fg ) .
366+ clearRect ( r ) ;
367+ g . setFont ( bodyFont ) . setFontAlign ( 0 , - 1 ) . drawString ( allLines [ scrollIdx ] , r . x + r . w / 2 , r . y ) ;
368+ // Load in next/previous message on demand by reinitializing showMessagesScroller while passing on the processed messages.
369+ if ( scrollIdx >= allLines . length - 1 && scrollIdx != prevScrollIdx &&
370+ alreadyProcessed . idxSpan . stop < MESSAGES . length ) {
371+ setTimeout ( ( ) => {
372+ E . showScroller ( ) ;
373+ showMessagesScroller ( MESSAGES [ alreadyProcessed . idxSpan . stop ] ,
374+ true , alreadyProcessed ) ;
375+ } , 40 ) ;
376+ }
377+ if ( scrollIdx == 0 && scrollIdx != prevScrollIdx && alreadyProcessed . idxSpan . start > 0 ) {
378+ setTimeout ( ( ) => {
379+ E . showScroller ( ) ;
380+ showMessagesScroller ( MESSAGES [ alreadyProcessed . idxSpan . start - 1 ] ,
381+ true , alreadyProcessed ) ;
382+ } , 40 ) ;
383+ }
384+ if ( prevPrevScrollIdx !== prevScrollIdx ) { prevPrevScrollIdx = prevScrollIdx ; }
385+ prevScrollIdx = scrollIdx ;
272386 } ,
273- back : ( ) => showMessage ( msg . id , true )
387+ select : function ( scrollIdx , touch ) {
388+ const MSG_SELECT = identifyDisplayedMsg ( scrollIdx ) ;
389+ if ( touch . type == 0 ) {
390+ WU . show ( ) ;
391+ if ( BTN_WATCH ) { clearWatch ( BTN_WATCH ) ; }
392+ showMessage ( MSG_SELECT . id , true ) ;
393+ }
394+ if ( touch . type == 2 ) {
395+ WU . show ( ) ;
396+ if ( BTN_WATCH ) { clearWatch ( BTN_WATCH ) ; }
397+ showMessageSettings ( MSG_SELECT ) ;
398+ }
399+ }
274400 } ) ;
401+ const BTN_WATCH = setWatch ( ( ) => {
402+ WU . show ( ) ;
403+ const SCROLL_IDX_CENTER_SCREEN = prevScrollIdx > prevPrevScrollIdx ?
404+ prevScrollIdx - 5 : prevScrollIdx + 5 ; // FIXME: `±5` should depend on screen height and font height.
405+ showMessage ( identifyDisplayedMsg ( SCROLL_IDX_CENTER_SCREEN ) . id , true ) ;
406+ } , BTN , { edge :'rising' } ) ;
275407}
276408
277409function showMessageSettings ( msg ) {
@@ -283,7 +415,7 @@ function showMessageSettings(msg) {
283415 } ;
284416
285417 if ( msg . id != "music" )
286- menu [ /*LANG*/ "View Message" ] = ( ) => showMessageScroller ( msg ) ;
418+ menu [ /*LANG*/ "View Message" ] = ( ) => showMessagesScroller ( msg ) ;
287419
288420 if ( msg . reply && reply ) {
289421 menu [ /*LANG*/ "Reply" ] = ( ) => {
@@ -392,7 +524,7 @@ function showMessage(msgid, persist) {
392524 var maxLines = Math . floor ( h / g . getFontHeight ( ) ) ;
393525 if ( lines . length > maxLines ) // if too long, wrap with a bit less spae so we have room for '...'
394526 body = g . setFont ( bodyFont ) . wrapString ( body , w - 10 ) . slice ( 0 , maxLines ) . join ( "\n" ) + "..." ;
395- else
527+ else
396528 body = lines . join ( "\n" ) ;
397529 }
398530 function goBack ( ) {
@@ -456,7 +588,7 @@ function showMessage(msgid, persist) {
456588 ] } ,
457589 { type :"txt" , font :bodyFont , label :body , fillx :1 , filly :1 , pad :2 , cb :( ) => {
458590 // allow tapping to show a larger version
459- showMessageScroller ( msg ) ;
591+ showMessagesScroller ( msg ) ;
460592 } } ,
461593 { type :"h" , fillx :1 , c : footer }
462594 ] } , { back :goBack } ) ;
@@ -502,7 +634,8 @@ function checkMessages(options) {
502634 // If we have a new message, show it
503635 if ( ! options . ignoreUnread && newMessages . length ) {
504636 delete newMessages [ 0 ] . show ; // stop us getting stuck here if we're called a second time
505- showMessage ( newMessages [ 0 ] . id , false ) ;
637+ //showMessage(newMessages[0].id, false);
638+ showMessagesScroller ( newMessages [ 0 ] , false ) ;
506639 // buzz after showMessage, so being busy during layout doesn't affect the buzz pattern
507640 if ( global . BUZZ_ON_NEW_MESSAGE ) {
508641 // this is set if we entered the messages app by loading `messagegui.new.js`
0 commit comments