@@ -65,6 +65,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
6565 protected viewDestroyed = false ;
6666 protected memberInfoObserver : any ;
6767 protected showLoadingModal = false ; // Whether to show a loading modal while fetching data.
68+ protected scrollListener ;
6869
6970 conversationId : number ; // Conversation ID. Undefined if it's a new individual conversation.
7071 conversation : AddonMessagesConversationFormatted ; // The conversation object (if it exists).
@@ -95,6 +96,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
9596 isSelf = false ;
9697 muteEnabled = false ;
9798 muteIcon = 'volume-off' ;
99+ newMessages = 0 ;
98100
99101 constructor ( private eventsProvider : CoreEventsProvider , sitesProvider : CoreSitesProvider , navParams : NavParams ,
100102 private userProvider : CoreUserProvider , private navCtrl : NavController , private messagesSync : AddonMessagesSyncProvider ,
@@ -134,28 +136,35 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
134136 this . fetchData ( ) ;
135137 }
136138 } , this . siteId ) ;
139+
140+ this . scrollListener = this . scrollListenerFunction . bind ( this ) ;
137141 }
138142
139143 /**
140144 * Adds a new message to the message list.
141145 *
142146 * @param message Message to be added.
143147 * @param keep If set the keep flag or not.
148+ * @return If message is not mine and was recently added.
144149 */
145150 protected addMessage ( message : AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted ,
146- keep : boolean = true ) : void {
151+ keep : boolean = true ) : boolean {
147152
148153 /* Create a hash to identify the message. The text of online messages isn't reliable because it can have random data
149154 like VideoJS ID. Try to use id and fallback to text for offline messages. */
150155 message . hash = Md5 . hashAsciiStr ( String ( message . id || message . text || '' ) ) + '#' + message . timecreated + '#' +
151156 message . useridfrom ;
152157
158+ let added = false ;
153159 if ( typeof this . keepMessageMap [ message . hash ] === 'undefined' ) {
154160 // Message not added to the list. Add it now.
155161 this . messages . push ( message ) ;
162+ added = message . useridfrom != this . currentUserId ;
156163 }
157164 // Message needs to be kept in the list.
158165 this . keepMessageMap [ message . hash ] = keep ;
166+
167+ return added ;
159168 }
160169
161170 /**
@@ -306,9 +315,10 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
306315 /**
307316 * Convenience function to fetch messages.
308317 *
318+ * @param messagesAreNew If messages loaded are new messages.
309319 * @return Resolved when done.
310320 */
311- protected fetchMessages ( ) : Promise < void > {
321+ protected fetchMessages ( messagesAreNew : boolean = true ) : Promise < void > {
312322 this . loadMoreError = false ;
313323
314324 if ( this . messagesBeingSent > 0 ) {
@@ -348,7 +358,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
348358 } ) ;
349359 }
350360 } ) . then ( ( messages : ( AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted ) [ ] ) => {
351- this . loadMessages ( messages ) ;
361+ this . loadMessages ( messages , messagesAreNew ) ;
352362 } ) . finally ( ( ) => {
353363 this . fetching = false ;
354364 } ) ;
@@ -357,10 +367,11 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
357367 /**
358368 * Format and load a list of messages into the view.
359369 *
370+ * @param messagesAreNew If messages loaded are new messages.
360371 * @param messages Messages to load.
361372 */
362- protected loadMessages ( messages : ( AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted ) [ ] )
363- : void {
373+ protected loadMessages ( messages : ( AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted ) [ ] ,
374+ messagesAreNew : boolean = true ) : void {
364375
365376 if ( this . viewDestroyed ) {
366377 return ;
@@ -380,9 +391,14 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
380391 }
381392
382393 // Add new messages to the list and mark the messages that should still be displayed.
383- messages . forEach ( ( message ) => {
384- this . addMessage ( message ) ;
385- } ) ;
394+ const newMessages = messages . reduce ( ( val , message ) => {
395+ return val + ( this . addMessage ( message ) ? 1 : 0 ) ;
396+ } , 0 ) ;
397+
398+ // Set the new badges message if we're loading new messages.
399+ if ( messagesAreNew ) {
400+ this . setNewMessagesBadge ( this . newMessages + newMessages ) ;
401+ }
386402
387403 // Remove messages that shouldn't be in the list anymore.
388404 for ( const hash in this . keepMessageMap ) {
@@ -414,6 +430,63 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
414430 this . markMessagesAsRead ( forceMark ) ;
415431 }
416432
433+ /**
434+ * Set the new message badge number and set scroll listener if needed.
435+ *
436+ * @param addMessages NUmber of messages still to be read.
437+ */
438+ protected setNewMessagesBadge ( addMessages : number ) : void {
439+ if ( this . newMessages == 0 && addMessages > 0 ) {
440+ // Setup scrolling.
441+ this . content . getScrollElement ( ) . addEventListener ( 'scroll' , this . scrollListener ) ;
442+
443+ this . scrollListenerFunction ( ) ;
444+ } else if ( this . newMessages > 0 && addMessages == 0 ) {
445+ // Remove scrolling.
446+ this . content . getScrollElement ( ) . removeEventListener ( 'scroll' , this . scrollListener ) ;
447+ }
448+
449+ this . newMessages = addMessages ;
450+ }
451+
452+ /**
453+ * The scroll was moved. Update new messages count.
454+ */
455+ protected scrollListenerFunction ( ) : void {
456+ if ( this . newMessages > 0 ) {
457+ const scrollBottom = this . domUtils . getScrollTop ( this . content ) + this . domUtils . getContentHeight ( this . content ) ;
458+ const scrollHeight = this . domUtils . getScrollHeight ( this . content ) ;
459+ if ( scrollBottom > scrollHeight - 40 ) {
460+ // At the bottom, reset.
461+ this . setNewMessagesBadge ( 0 ) ;
462+
463+ return ;
464+ }
465+
466+ const scrollElRect = this . content . getScrollElement ( ) . getBoundingClientRect ( ) ;
467+ const scrollBottomPos = ( scrollElRect && scrollElRect . bottom ) || 0 ;
468+
469+ if ( scrollBottomPos == 0 ) {
470+ return ;
471+ }
472+
473+ const messages = Array . from ( document . querySelectorAll ( '.addon-message-not-mine' ) ) . slice ( - this . newMessages ) . reverse ( ) ;
474+
475+ const newMessagesUnread = messages . findIndex ( ( message , index ) => {
476+ const elementRect = message . getBoundingClientRect ( ) ;
477+ if ( ! elementRect ) {
478+ return false ;
479+ }
480+
481+ return elementRect . bottom <= scrollBottomPos ;
482+ } ) ;
483+
484+ if ( newMessagesUnread > 0 && newMessagesUnread < this . newMessages ) {
485+ this . setNewMessagesBadge ( newMessagesUnread ) ;
486+ }
487+ }
488+ }
489+
417490 /**
418491 * Get the conversation.
419492 *
@@ -887,7 +960,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
887960 return this . waitForFetch ( ) . finally ( ( ) => {
888961 this . pagesLoaded ++ ;
889962
890- this . fetchMessages ( ) . then ( ( ) => {
963+ this . fetchMessages ( false ) . then ( ( ) => {
891964
892965 // Try to keep the scroll position.
893966 const scrollBottom = scrollHeight - this . domUtils . getScrollTop ( this . content ) ;
@@ -972,6 +1045,20 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
9721045 }
9731046 } ) ;
9741047 this . scrollBottom = false ;
1048+
1049+ // Reset the badge.
1050+ this . setNewMessagesBadge ( 0 ) ;
1051+ }
1052+ }
1053+
1054+ /**
1055+ * Scroll to the first new unread message.
1056+ */
1057+ scrollToFirstUnreadMessage ( ) : void {
1058+ if ( this . newMessages > 0 ) {
1059+ const messages = Array . from ( document . querySelectorAll ( '.addon-message-not-mine' ) ) ;
1060+
1061+ this . domUtils . scrollToElement ( this . content , < HTMLElement > messages [ messages . length - this . newMessages ] ) ;
9751062 }
9761063 }
9771064
@@ -987,6 +1074,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
9871074
9881075 this . showDelete = false ;
9891076 this . scrollBottom = true ;
1077+ this . setNewMessagesBadge ( 0 ) ;
9901078
9911079 message = {
9921080 id : null ,
0 commit comments