commit
9057b62333
|
@ -41,7 +41,7 @@
|
|||
</h6>
|
||||
|
||||
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" color="light">
|
||||
<ion-label>{{ 'addon.messages.newmessages' | translate:{$a: title} }}</ion-label>
|
||||
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
|
||||
<ion-icon name="arrow-round-down"></ion-icon>
|
||||
</ion-chip>
|
||||
|
||||
|
@ -68,6 +68,13 @@
|
|||
</ion-item>
|
||||
</ng-container>
|
||||
</ion-list>
|
||||
<!-- Scroll bottom. -->
|
||||
<ion-fab core-fab bottom end *ngIf="newMessages > 0">
|
||||
<button ion-fab mini (click)="scrollToFirstUnreadMessage(true)" color="light" [attr.aria-label]="'addon.messages.newmessages' | translate">
|
||||
<ion-icon name="arrow-round-down"></ion-icon>
|
||||
<span class="core-discussion-messages-badge">{{ newMessages }}</span>
|
||||
</button>
|
||||
</ion-fab>
|
||||
<core-empty-box *ngIf="!messages || messages.length <= 0" icon="chatbubbles" [message]="'addon.messages.nomessagesfound' | translate"></core-empty-box>
|
||||
</core-loading>
|
||||
</ion-content>
|
||||
|
|
|
@ -4,6 +4,9 @@ $item-message-note-text: $gray-dark !default;
|
|||
$item-message-note-font-size: 75% !default;
|
||||
$item-message-mine-bg: $gray-light !default;
|
||||
|
||||
$core-discussion-messages-badge: $core-color !default;
|
||||
$core-discussion-messages-badge-text: $white !default;
|
||||
|
||||
@mixin message-page {
|
||||
ion-content {
|
||||
background-color: $gray-lighter !important;
|
||||
|
@ -194,6 +197,28 @@ $item-message-mine-bg: $gray-light !default;
|
|||
border-top-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
}
|
||||
|
||||
.has-fab .scroll-content {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
ion-fab button {
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
.core-discussion-messages-badge {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
color: $core-discussion-messages-badge-text;
|
||||
background-color: $core-discussion-messages-badge;
|
||||
display: block;
|
||||
line-height: 20px;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
right: -6px;
|
||||
top: -6px;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
protected viewDestroyed = false;
|
||||
protected memberInfoObserver: any;
|
||||
protected showLoadingModal = false; // Whether to show a loading modal while fetching data.
|
||||
protected scrollListener;
|
||||
|
||||
conversationId: number; // Conversation ID. Undefined if it's a new individual conversation.
|
||||
conversation: AddonMessagesConversationFormatted; // The conversation object (if it exists).
|
||||
|
@ -95,6 +96,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
isSelf = false;
|
||||
muteEnabled = false;
|
||||
muteIcon = 'volume-off';
|
||||
newMessages = 0;
|
||||
|
||||
constructor(private eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, navParams: NavParams,
|
||||
private userProvider: CoreUserProvider, private navCtrl: NavController, private messagesSync: AddonMessagesSyncProvider,
|
||||
|
@ -134,6 +136,8 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
this.fetchData();
|
||||
}
|
||||
}, this.siteId);
|
||||
|
||||
this.scrollListener = this.scrollListenerFunction.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -141,21 +145,26 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
*
|
||||
* @param message Message to be added.
|
||||
* @param keep If set the keep flag or not.
|
||||
* @return If message is not mine and was recently added.
|
||||
*/
|
||||
protected addMessage(message: AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted,
|
||||
keep: boolean = true): void {
|
||||
keep: boolean = true): boolean {
|
||||
|
||||
/* Create a hash to identify the message. The text of online messages isn't reliable because it can have random data
|
||||
like VideoJS ID. Try to use id and fallback to text for offline messages. */
|
||||
message.hash = Md5.hashAsciiStr(String(message.id || message.text || '')) + '#' + message.timecreated + '#' +
|
||||
message.useridfrom;
|
||||
|
||||
let added = false;
|
||||
if (typeof this.keepMessageMap[message.hash] === 'undefined') {
|
||||
// Message not added to the list. Add it now.
|
||||
this.messages.push(message);
|
||||
added = message.useridfrom != this.currentUserId;
|
||||
}
|
||||
// Message needs to be kept in the list.
|
||||
this.keepMessageMap[message.hash] = keep;
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -306,9 +315,10 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
/**
|
||||
* Convenience function to fetch messages.
|
||||
*
|
||||
* @param messagesAreNew If messages loaded are new messages.
|
||||
* @return Resolved when done.
|
||||
*/
|
||||
protected fetchMessages(): Promise<void> {
|
||||
protected fetchMessages(messagesAreNew: boolean = true): Promise<void> {
|
||||
this.loadMoreError = false;
|
||||
|
||||
if (this.messagesBeingSent > 0) {
|
||||
|
@ -348,7 +358,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
});
|
||||
}
|
||||
}).then((messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[]) => {
|
||||
this.loadMessages(messages);
|
||||
this.loadMessages(messages, messagesAreNew);
|
||||
}).finally(() => {
|
||||
this.fetching = false;
|
||||
});
|
||||
|
@ -357,10 +367,11 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
/**
|
||||
* Format and load a list of messages into the view.
|
||||
*
|
||||
* @param messagesAreNew If messages loaded are new messages.
|
||||
* @param messages Messages to load.
|
||||
*/
|
||||
protected loadMessages(messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[])
|
||||
: void {
|
||||
protected loadMessages(messages: (AddonMessagesConversationMessageFormatted | AddonMessagesGetMessagesMessageFormatted)[],
|
||||
messagesAreNew: boolean = true): void {
|
||||
|
||||
if (this.viewDestroyed) {
|
||||
return;
|
||||
|
@ -380,9 +391,14 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
}
|
||||
|
||||
// Add new messages to the list and mark the messages that should still be displayed.
|
||||
messages.forEach((message) => {
|
||||
this.addMessage(message);
|
||||
});
|
||||
const newMessages = messages.reduce((val, message) => {
|
||||
return val + (this.addMessage(message) ? 1 : 0);
|
||||
}, 0);
|
||||
|
||||
// Set the new badges message if we're loading new messages.
|
||||
if (messagesAreNew) {
|
||||
this.setNewMessagesBadge(this.newMessages + newMessages);
|
||||
}
|
||||
|
||||
// Remove messages that shouldn't be in the list anymore.
|
||||
for (const hash in this.keepMessageMap) {
|
||||
|
@ -414,6 +430,63 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
this.markMessagesAsRead(forceMark);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new message badge number and set scroll listener if needed.
|
||||
*
|
||||
* @param addMessages NUmber of messages still to be read.
|
||||
*/
|
||||
protected setNewMessagesBadge(addMessages: number): void {
|
||||
if (this.newMessages == 0 && addMessages > 0) {
|
||||
// Setup scrolling.
|
||||
this.content.getScrollElement().addEventListener('scroll', this.scrollListener);
|
||||
|
||||
this.scrollListenerFunction();
|
||||
} else if (this.newMessages > 0 && addMessages == 0) {
|
||||
// Remove scrolling.
|
||||
this.content.getScrollElement().removeEventListener('scroll', this.scrollListener);
|
||||
}
|
||||
|
||||
this.newMessages = addMessages;
|
||||
}
|
||||
|
||||
/**
|
||||
* The scroll was moved. Update new messages count.
|
||||
*/
|
||||
protected scrollListenerFunction(): void {
|
||||
if (this.newMessages > 0) {
|
||||
const scrollBottom = this.domUtils.getScrollTop(this.content) + this.domUtils.getContentHeight(this.content);
|
||||
const scrollHeight = this.domUtils.getScrollHeight(this.content);
|
||||
if (scrollBottom > scrollHeight - 40) {
|
||||
// At the bottom, reset.
|
||||
this.setNewMessagesBadge(0);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const scrollElRect = this.content.getScrollElement().getBoundingClientRect();
|
||||
const scrollBottomPos = (scrollElRect && scrollElRect.bottom) || 0;
|
||||
|
||||
if (scrollBottomPos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messages = Array.from(document.querySelectorAll('.addon-message-not-mine')).slice(-this.newMessages).reverse();
|
||||
|
||||
const newMessagesUnread = messages.findIndex((message, index) => {
|
||||
const elementRect = message.getBoundingClientRect();
|
||||
if (!elementRect) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return elementRect.bottom <= scrollBottomPos;
|
||||
});
|
||||
|
||||
if (newMessagesUnread > 0 && newMessagesUnread < this.newMessages) {
|
||||
this.setNewMessagesBadge(newMessagesUnread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the conversation.
|
||||
*
|
||||
|
@ -887,7 +960,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
return this.waitForFetch().finally(() => {
|
||||
this.pagesLoaded++;
|
||||
|
||||
this.fetchMessages().then(() => {
|
||||
this.fetchMessages(false).then(() => {
|
||||
|
||||
// Try to keep the scroll position.
|
||||
const scrollBottom = scrollHeight - this.domUtils.getScrollTop(this.content);
|
||||
|
@ -972,6 +1045,20 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
}
|
||||
});
|
||||
this.scrollBottom = false;
|
||||
|
||||
// Reset the badge.
|
||||
this.setNewMessagesBadge(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scroll to the first new unread message.
|
||||
*/
|
||||
scrollToFirstUnreadMessage(): void {
|
||||
if (this.newMessages > 0) {
|
||||
const messages = Array.from(document.querySelectorAll('.addon-message-not-mine'));
|
||||
|
||||
this.domUtils.scrollToElement(this.content, <HTMLElement> messages[messages.length - this.newMessages]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,6 +1074,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
|
|||
|
||||
this.showDelete = false;
|
||||
this.scrollBottom = true;
|
||||
this.setNewMessagesBadge(0);
|
||||
|
||||
message = {
|
||||
id: null,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<ion-header>
|
||||
<ion-navbar>
|
||||
<ion-buttons step>
|
||||
<button ion-button icon-only (click)="previous($$event)" [attr.aria-label]="'core.back' | translate">
|
||||
<button ion-button icon-only (click)="previous($event)" [attr.aria-label]="'core.back' | translate">
|
||||
<ion-icon name="arrow-back"></ion-icon>
|
||||
</button>
|
||||
</ion-buttons>
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
import { Component, ViewChild, ElementRef } from '@angular/core';
|
||||
import { IonicPage, NavController, ModalController, AlertController, NavParams } from 'ionic-angular';
|
||||
import { CoreSite } from '@classes/site';
|
||||
import { CoreAppProvider } from '@providers/app';
|
||||
import { CoreEventsProvider } from '@providers/events';
|
||||
import { CoreSitesProvider, CoreSiteCheckResponse, CoreLoginSiteInfo } from '@providers/sites';
|
||||
|
@ -293,8 +294,9 @@ export class CoreLoginSitePage {
|
|||
}
|
||||
];
|
||||
|
||||
// @TODO: Remove CoreSite.MINIMUM_MOODLE_VERSION, not used on translations since 3.8.3.
|
||||
this.domUtils.showAlertWithOptions({
|
||||
title: this.translate.instant('core.cannotconnect'),
|
||||
title: this.translate.instant('core.cannotconnect', {$a: CoreSite.MINIMUM_MOODLE_VERSION}),
|
||||
message,
|
||||
buttons,
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue