From 8681b91a0ed507fb93f91a1f0524fbcbce24b2d7 Mon Sep 17 00:00:00 2001 From: Dani Palou Date: Thu, 1 Jul 2021 11:12:54 +0200 Subject: [PATCH] MOBILE-3320 messages: Fix scroll to bottom in iOS --- .../pages/discussion/discussion.page.ts | 42 +++++++++++++------ src/core/services/utils/utils.ts | 9 ++++ 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/addons/messages/pages/discussion/discussion.page.ts b/src/addons/messages/pages/discussion/discussion.page.ts index 89e954d6a..a77b7f46b 100644 --- a/src/addons/messages/pages/discussion/discussion.page.ts +++ b/src/addons/messages/pages/discussion/discussion.page.ts @@ -109,6 +109,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView newMessages = 0; scrollElement?: HTMLElement; unreadMessageFrom = 0; + initialized = false; constructor( protected route: ActivatedRoute, @@ -162,6 +163,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView this.route.queryParams.subscribe(async (params) => { const oldConversationId = this.conversationId; const oldUserId = this.userId; + let forceScrollToBottom = false; this.conversationId = CoreNavigator.getRouteNumberParam('conversationId', { params }) || undefined; this.userId = CoreNavigator.getRouteNumberParam('userId', { params }) || undefined; this.showInfo = !params.hideInfo; @@ -169,13 +171,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView if (oldConversationId != this.conversationId || oldUserId != this.userId) { // Showing reload again can break animations. this.loaded = false; + this.initialized = false; + forceScrollToBottom = true; } this.showKeyboard = CoreNavigator.getRouteBooleanParam('showKeyboard', { params }) || false; await this.fetchData(); - this.scrollToBottom(); + this.scrollToBottom(forceScrollToBottom); }); } @@ -481,10 +485,6 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView message.showTail = this.showTail(message, this.messages[index + 1]); }); - // Call resize to recalculate the dimensions. - // @todo probably not needed. - // this.content!.resize(); - // If we received a new message while using group messaging, force mark messages as read. const last = this.messages[this.messages.length - 1]; const forceMark = this.groupMessagingEnabled && last && last.useridfrom != this.currentUserId && this.lastMessage.text != '' @@ -1036,6 +1036,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView * @return Resolved when done. */ async loadPrevious(infiniteComplete?: () => void): Promise { + if (!this.initialized) { + // Don't load previous if the view isn't fully initialized. + // Don't put the initialized condition in the "enabled" input because then the load more is hidden and + // the scroll height changes when it appears. + infiniteComplete && infiniteComplete(); + + return; + } + let infiniteHeight = this.infinite?.infiniteEl?.nativeElement.getBoundingClientRect().height || 0; const scrollHeight = (this.scrollElement?.scrollHeight || 0); @@ -1122,20 +1131,27 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView /** * Scroll bottom when render has finished. + * + * @param force Whether to force scroll to bottom. */ - scrollToBottom(): void { + async scrollToBottom(force = false): Promise { // Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new. - if (this.scrollBottom) { - // Need a timeout to leave time to the view to be rendered. - setTimeout(() => { - if (!this.viewDestroyed) { - this.content!.scrollToBottom(0); - } - }); + if (this.scrollBottom || force) { this.scrollBottom = false; // Reset the badge. this.setNewMessagesBadge(0); + + // Leave time for the view to be rendered. + await CoreUtils.nextTicks(5); + + if (!this.viewDestroyed) { + this.content!.scrollToBottom(0); + } + + if (force) { + this.initialized = true; + } } } diff --git a/src/core/services/utils/utils.ts b/src/core/services/utils/utils.ts index ddf711a7e..6c5ca7826 100644 --- a/src/core/services/utils/utils.ts +++ b/src/core/services/utils/utils.ts @@ -1666,6 +1666,15 @@ export class CoreUtilsProvider { return this.wait(0); } + /** + * Wait until several next ticks. + */ + async nextTicks(numTicks = 0): Promise { + for (let i = 0; i < numTicks; i++) { + await this.wait(0); + } + } + /** * Given some options, check if a file should be opened with showOpenWithDialog. *