MOBILE-3320 messages: Fix scroll to bottom in iOS

main
Dani Palou 2021-07-01 11:12:54 +02:00
parent 00ca38f8b6
commit 8681b91a0e
2 changed files with 38 additions and 13 deletions

View File

@ -109,6 +109,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
newMessages = 0; newMessages = 0;
scrollElement?: HTMLElement; scrollElement?: HTMLElement;
unreadMessageFrom = 0; unreadMessageFrom = 0;
initialized = false;
constructor( constructor(
protected route: ActivatedRoute, protected route: ActivatedRoute,
@ -162,6 +163,7 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
this.route.queryParams.subscribe(async (params) => { this.route.queryParams.subscribe(async (params) => {
const oldConversationId = this.conversationId; const oldConversationId = this.conversationId;
const oldUserId = this.userId; const oldUserId = this.userId;
let forceScrollToBottom = false;
this.conversationId = CoreNavigator.getRouteNumberParam('conversationId', { params }) || undefined; this.conversationId = CoreNavigator.getRouteNumberParam('conversationId', { params }) || undefined;
this.userId = CoreNavigator.getRouteNumberParam('userId', { params }) || undefined; this.userId = CoreNavigator.getRouteNumberParam('userId', { params }) || undefined;
this.showInfo = !params.hideInfo; this.showInfo = !params.hideInfo;
@ -169,13 +171,15 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
if (oldConversationId != this.conversationId || oldUserId != this.userId) { if (oldConversationId != this.conversationId || oldUserId != this.userId) {
// Showing reload again can break animations. // Showing reload again can break animations.
this.loaded = false; this.loaded = false;
this.initialized = false;
forceScrollToBottom = true;
} }
this.showKeyboard = CoreNavigator.getRouteBooleanParam('showKeyboard', { params }) || false; this.showKeyboard = CoreNavigator.getRouteBooleanParam('showKeyboard', { params }) || false;
await this.fetchData(); 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]); 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. // If we received a new message while using group messaging, force mark messages as read.
const last = this.messages[this.messages.length - 1]; const last = this.messages[this.messages.length - 1];
const forceMark = this.groupMessagingEnabled && last && last.useridfrom != this.currentUserId && this.lastMessage.text != '' 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. * @return Resolved when done.
*/ */
async loadPrevious(infiniteComplete?: () => void): Promise<void> { async loadPrevious(infiniteComplete?: () => void): Promise<void> {
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; let infiniteHeight = this.infinite?.infiniteEl?.nativeElement.getBoundingClientRect().height || 0;
const scrollHeight = (this.scrollElement?.scrollHeight || 0); const scrollHeight = (this.scrollElement?.scrollHeight || 0);
@ -1122,20 +1131,27 @@ export class AddonMessagesDiscussionPage implements OnInit, OnDestroy, AfterView
/** /**
* Scroll bottom when render has finished. * Scroll bottom when render has finished.
*
* @param force Whether to force scroll to bottom.
*/ */
scrollToBottom(): void { async scrollToBottom(force = false): Promise<void> {
// Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new. // Check if scroll is at bottom. If so, scroll bottom after rendering since there might be something new.
if (this.scrollBottom) { if (this.scrollBottom || force) {
// Need a timeout to leave time to the view to be rendered.
setTimeout(() => {
if (!this.viewDestroyed) {
this.content!.scrollToBottom(0);
}
});
this.scrollBottom = false; this.scrollBottom = false;
// Reset the badge. // Reset the badge.
this.setNewMessagesBadge(0); 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;
}
} }
} }

View File

@ -1666,6 +1666,15 @@ export class CoreUtilsProvider {
return this.wait(0); return this.wait(0);
} }
/**
* Wait until several next ticks.
*/
async nextTicks(numTicks = 0): Promise<void> {
for (let i = 0; i < numTicks; i++) {
await this.wait(0);
}
}
/** /**
* Given some options, check if a file should be opened with showOpenWithDialog. * Given some options, check if a file should be opened with showOpenWithDialog.
* *