Skip to content

Commit 9057b62

Browse files
authored
Merge pull request #2376 from crazyserver/MOBILE-3382
Mobile 3382
2 parents bd4a295 + b031919 commit 9057b62

File tree

5 files changed

+134
-12
lines changed

5 files changed

+134
-12
lines changed

src/addon/messages/pages/discussion/discussion.html

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ <h6 text-center *ngIf="message.showDate" class="addon-messages-date">
4141
</h6>
4242

4343
<ion-chip class="addon-messages-unreadfrom" *ngIf="unreadMessageFrom && message.id == unreadMessageFrom" color="light">
44-
<ion-label>{{ 'addon.messages.newmessages' | translate:{$a: title} }}</ion-label>
44+
<ion-label>{{ 'addon.messages.newmessages' | translate }}</ion-label>
4545
<ion-icon name="arrow-round-down"></ion-icon>
4646
</ion-chip>
4747

@@ -68,6 +68,13 @@ <h2 class="addon-message-user">
6868
</ion-item>
6969
</ng-container>
7070
</ion-list>
71+
<!-- Scroll bottom. -->
72+
<ion-fab core-fab bottom end *ngIf="newMessages > 0">
73+
<button ion-fab mini (click)="scrollToFirstUnreadMessage(true)" color="light" [attr.aria-label]="'addon.messages.newmessages' | translate">
74+
<ion-icon name="arrow-round-down"></ion-icon>
75+
<span class="core-discussion-messages-badge">{{ newMessages }}</span>
76+
</button>
77+
</ion-fab>
7178
<core-empty-box *ngIf="!messages || messages.length <= 0" icon="chatbubbles" [message]="'addon.messages.nomessagesfound' | translate"></core-empty-box>
7279
</core-loading>
7380
</ion-content>

src/addon/messages/pages/discussion/discussion.scss

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ $item-message-note-text: $gray-dark !default;
44
$item-message-note-font-size: 75% !default;
55
$item-message-mine-bg: $gray-light !default;
66

7+
$core-discussion-messages-badge: $core-color !default;
8+
$core-discussion-messages-badge-text: $white !default;
9+
710
@mixin message-page {
811
ion-content {
912
background-color: $gray-lighter !important;
@@ -194,6 +197,28 @@ $item-message-mine-bg: $gray-light !default;
194197
border-top-right-radius: 0;
195198
border-top-left-radius: 0;
196199
}
200+
201+
.has-fab .scroll-content {
202+
padding-bottom: 0;
203+
}
204+
ion-fab button {
205+
overflow: visible;
206+
position: relative;
207+
.core-discussion-messages-badge {
208+
position: absolute;
209+
border-radius: 50%;
210+
color: $core-discussion-messages-badge-text;
211+
background-color: $core-discussion-messages-badge;
212+
display: block;
213+
line-height: 20px;
214+
height: 20px;
215+
width: 20px;
216+
right: -6px;
217+
top: -6px;
218+
219+
}
220+
}
221+
197222
}
198223

199224

src/addon/messages/pages/discussion/discussion.ts

Lines changed: 97 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -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,

src/core/login/pages/site-onboarding/site-onboarding.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<ion-header>
22
<ion-navbar>
33
<ion-buttons step>
4-
<button ion-button icon-only (click)="previous($$event)" [attr.aria-label]="'core.back' | translate">
4+
<button ion-button icon-only (click)="previous($event)" [attr.aria-label]="'core.back' | translate">
55
<ion-icon name="arrow-back"></ion-icon>
66
</button>
77
</ion-buttons>

src/core/login/pages/site/site.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
import { Component, ViewChild, ElementRef } from '@angular/core';
1616
import { IonicPage, NavController, ModalController, AlertController, NavParams } from 'ionic-angular';
17+
import { CoreSite } from '@classes/site';
1718
import { CoreAppProvider } from '@providers/app';
1819
import { CoreEventsProvider } from '@providers/events';
1920
import { CoreSitesProvider, CoreSiteCheckResponse, CoreLoginSiteInfo } from '@providers/sites';
@@ -293,8 +294,9 @@ export class CoreLoginSitePage {
293294
}
294295
];
295296

297+
// @TODO: Remove CoreSite.MINIMUM_MOODLE_VERSION, not used on translations since 3.8.3.
296298
this.domUtils.showAlertWithOptions({
297-
title: this.translate.instant('core.cannotconnect'),
299+
title: this.translate.instant('core.cannotconnect', {$a: CoreSite.MINIMUM_MOODLE_VERSION}),
298300
message,
299301
buttons,
300302
});

0 commit comments

Comments
 (0)