From 4c151051eb6e60ffaa1f4914e9e1ceeb7ca790bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Tue, 10 Sep 2019 13:57:06 +0200 Subject: [PATCH] MOBILE-3142 chat: Change chat look and feel --- .../messages/pages/discussion/discussion.scss | 11 +- src/addon/mod/chat/lang/en.json | 2 + src/addon/mod/chat/pages/chat/chat.html | 82 ++++++++------ src/addon/mod/chat/pages/chat/chat.scss | 5 +- src/addon/mod/chat/pages/chat/chat.ts | 106 ++++++++++++++++-- src/addon/mod/chat/pages/users/users.ts | 8 +- src/assets/lang/en.json | 2 + src/components/ion-tabs/ion-tabs.scss | 3 +- .../core-send-message-form.html | 2 +- .../send-message-form/send-message-form.ts | 9 +- 10 files changed, 173 insertions(+), 57 deletions(-) diff --git a/src/addon/messages/pages/discussion/discussion.scss b/src/addon/messages/pages/discussion/discussion.scss index 5b8ee2a35..4591793e5 100644 --- a/src/addon/messages/pages/discussion/discussion.scss +++ b/src/addon/messages/pages/discussion/discussion.scss @@ -4,8 +4,7 @@ $item-message-note-text: $gray-dark !default; $item-message-note-font-size: 75% !default; $item-message-mine-bg: $gray-light !default; -ion-app.app-root page-addon-messages-discussion.ion-page { - +@mixin message-page { ion-content { background-color: $gray-lighter !important; @include darkmode() { @@ -194,6 +193,12 @@ ion-app.app-root page-addon-messages-discussion.ion-page { .addon-message-not-mine.activated .tail { border-bottom-color: darken($item-message-bg, 10%); } +} + + +ion-app.app-root page-addon-messages-discussion.ion-page { + + @include message-page(); .toolbar-title { padding: 0; @@ -224,4 +229,4 @@ ion-app.app-root page-addon-messages-discussion.ion-page { ion-app.app-root.ios page-addon-messages-discussion ion-footer .toolbar:last-child { padding-bottom: 4px; min-height: 0; -} \ No newline at end of file +} diff --git a/src/addon/mod/chat/lang/en.json b/src/addon/mod/chat/lang/en.json index 4348b5d63..04c334410 100644 --- a/src/addon/mod/chat/lang/en.json +++ b/src/addon/mod/chat/lang/en.json @@ -9,10 +9,12 @@ "errorwhilegettingchatusers": "Error while getting chat users.", "errorwhileretrievingmessages": "Error while retrieving messages from the server.", "errorwhilesendingmessage": "Error while sending the message.", + "messagebeepseveryone": "{{$a}} beeps everyone!", "messagebeepsyou": "{{$a}} has just beeped you!", "messageenter": "{{$a}} has just entered this chat", "messageexit": "{{$a}} has left this chat", "messages": "Messages", + "messageyoubeep": "You beeped {{$a}}", "modulenameplural": "Chats", "mustbeonlinetosendmessages": "You must be online to send messages.", "nomessages": "No messages yet", diff --git a/src/addon/mod/chat/pages/chat/chat.html b/src/addon/mod/chat/pages/chat/chat.html index 47f744618..4141ba329 100644 --- a/src/addon/mod/chat/pages/chat/chat.html +++ b/src/addon/mod/chat/pages/chat/chat.html @@ -8,55 +8,63 @@ - + -
-
+ + -
- - {{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }} +
+ {{ message.timestamp * 1000 | coreFormatDate:"strftimedayshort" }} +
+ +
+ + {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} + + + + {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} + + + + {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} + {{ 'addon.mod_chat.messagebeepseveryone' | translate:{$a: message.userfullname} }} + + + + {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} + {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} + + + + {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} + {{ 'addon.mod_chat.messageyoubeep' | translate:{$a: message.beepwho} }}
-
- - {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageenter' | translate:{$a: message.userfullname} }} - -
- -
- - {{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }} {{ 'addon.mod_chat.messageexit' | translate:{$a: message.userfullname} }} - -
- -
- - {{ 'addon.mod_chat.messagebeepsyou' | translate:{$a: message.userfullname} }} - -
- - - -

-

{{ message.timestamp * 1000 | coreFormatDate:"strftimetime" }}

- + + +

+ +
{{ message.userfullname }}
+ {{ message.timestamp * 1000 | coreFormatDate: "strftimetime" }}

- -
-

-
-

{{ 'addon.mod_chat.nomessages' | translate}}

-
-
+

+ +

+
+ + + + +

{{ 'addon.mod_chat.mustbeonlinetosendmessages' | translate }}

- +
diff --git a/src/addon/mod/chat/pages/chat/chat.scss b/src/addon/mod/chat/pages/chat/chat.scss index fe62c5619..3e34e5324 100644 --- a/src/addon/mod/chat/pages/chat/chat.scss +++ b/src/addon/mod/chat/pages/chat/chat.scss @@ -1,9 +1,8 @@ ion-app.app-root page-addon-mod-chat-chat { + @include message-page(); + .addon-mod-chat-notice { margin-top: 10px; margin-bottom: 10px; } - .addon-mod-chat-message { - align-items: flex-start; - } } diff --git a/src/addon/mod/chat/pages/chat/chat.ts b/src/addon/mod/chat/pages/chat/chat.ts index 0123de12d..a8a0760cc 100644 --- a/src/addon/mod/chat/pages/chat/chat.ts +++ b/src/addon/mod/chat/pages/chat/chat.ts @@ -22,6 +22,8 @@ import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreTextUtilsProvider } from '@providers/utils/text'; import { AddonModChatProvider, AddonModChatMessageWithUserData } from '../../providers/chat'; import { Network } from '@ionic-native/network'; +import { coreSlideInOut } from '@classes/animations'; +import { CoreSendMessageFormComponent } from '@components/send-message-form/send-message-form'; import * as moment from 'moment'; /** @@ -31,9 +33,11 @@ import * as moment from 'moment'; @Component({ selector: 'page-addon-mod-chat-chat', templateUrl: 'chat.html', + animations: [coreSlideInOut] }) export class AddonModChatChatPage { @ViewChild(Content) content: Content; + @ViewChild(CoreSendMessageFormComponent) sendMessageForm: CoreSendMessageFormComponent; loaded = false; title: string; @@ -41,7 +45,8 @@ export class AddonModChatChatPage { newMessage: string; polling: any; isOnline: boolean; - currentUserBeep: string; + currentUserId: number; + sending: boolean; protected logger; protected courseId: number; @@ -53,6 +58,7 @@ export class AddonModChatChatPage { protected keyboardObserver: any; protected viewDestroyed = false; protected pollingRunning = false; + protected users = []; constructor(navParams: NavParams, logger: CoreLoggerProvider, network: Network, zone: NgZone, private navCtrl: NavController, private chatProvider: AddonModChatProvider, private appProvider: CoreAppProvider, sitesProvider: CoreSitesProvider, @@ -63,7 +69,7 @@ export class AddonModChatChatPage { this.courseId = navParams.get('courseId'); this.title = navParams.get('title'); this.logger = logger.getInstance('AddonModChoiceChoicePage'); - this.currentUserBeep = 'beep ' + sitesProvider.getCurrentSiteUserId(); + this.currentUserId = sitesProvider.getCurrentSiteUserId(); this.isOnline = this.appProvider.isOnline(); this.onlineObserver = network.onchange().subscribe(() => { // Execute the callback in the Angular zone, so change detection doesn't stop working. @@ -127,11 +133,14 @@ export class AddonModChatChatPage { modal.onDidDismiss((data) => { if (data && data.talkTo) { - this.newMessage = `To ${data.talkTo}: `; + this.newMessage = `To ${data.talkTo}: ` + this.sendMessageForm.message; } if (data && data.beepTo) { this.sendMessage('', data.beepTo); } + if (data && data.users) { + this.users = data.users; + } }); modal.present({ @@ -139,6 +148,38 @@ export class AddonModChatChatPage { }); } + /** + * Get the user fullname for a beep. + * + * @param id User Id before parsing. + * @return User fullname. + */ + protected getUserFullname(id: string): Promise { + if (isNaN(parseInt(id, 10))) { + return Promise.resolve(id); + } + + const user = this.users.find((user) => user.id == id); + + if (user) { + return Promise.resolve(user.fullname); + } + + return this.chatProvider.getChatUsers(this.sessionId).then((data) => { + this.users = data.users; + const user = this.users.find((user) => user.id == id); + + if (user) { + return user.fullname; + } + + return id; + }).catch((error) => { + // Ignore errors. + return id; + }); + } + /** * Convenience function to login the user. * @@ -160,8 +201,33 @@ export class AddonModChatChatPage { this.lastTime = messagesInfo.chatnewlasttime || 0; return this.chatProvider.getMessagesUserData(messagesInfo.messages, this.courseId).then((messages) => { - this.messages = this.messages.concat( messages); if (messages.length) { + const previousLength = this.messages.length; + this.messages = this.messages.concat( messages); + + // Calculate which messages need to display the date or user data. + for (let index = previousLength ; index < this.messages.length; index++) { + const message = this.messages[index]; + const prevMessage = index > 0 ? this.messages[index - 1] : null; + + message.showDate = this.showDate(message, prevMessage); + message.beep = message.message.substr(0, 5) == 'beep ' && message.message.substr(5).trim(); + + if (message.beep && message.beep != this.currentUserId) { + this.getUserFullname(message.beep).then((fullname) => { + message.beepwho = fullname; + }); + } + + message.special = message.system || !!message.beep; + + message.showUserData = this.showUserData(message, prevMessage); + prevMessage ? + prevMessage.showTail = this.showTail(prevMessage, message) : null; + } + + this.messages[this.messages.length - 1].showTail = true; + // New messages or beeps, scroll to bottom. setTimeout(() => this.scrollToBottom()); } @@ -196,6 +262,30 @@ export class AddonModChatChatPage { } } + /** + * Check if the user info should be displayed for the current message. + * User data is only displayed if the previous message was from another user. + * + * @param message Current message where to show the user info. + * @param prevMessage Previous message. + * @return Whether user data should be shown. + */ + showUserData(message: any, prevMessage?: any): boolean { + return message.userid != this.currentUserId && + (!prevMessage || prevMessage.userid != message.userid || message.showDate || prevMessage.special); + } + + /** + * Check if a css tail should be shown. + * + * @param message Current message where to show the user info. + * @param nextMessage Next message. + * @return Whether user data should be shown. + */ + showTail(message: any, nextMessage?: any): boolean { + return !nextMessage || nextMessage.userid != message.userid || nextMessage.showDate || nextMessage.special; + } + /** * Convenience function to be called every certain time to fetch chat messages. * @@ -259,9 +349,8 @@ export class AddonModChatChatPage { // Silent error. return; } - text = this.textUtils.replaceNewLines(text, '
'); - const modal = this.domUtils.showModalLoading('core.sending', true); + this.sending = true; this.chatProvider.sendMessage(this.sessionId, text, beep).then(() => { // Update messages to show the sent message. this.fetchMessagesInterval().catch(() => { @@ -272,9 +361,12 @@ export class AddonModChatChatPage { messages without the keyboard being closed. */ this.appProvider.closeKeyboard(); + this.newMessage = text; + this.domUtils.showErrorModalDefault(error, 'addon.mod_chat.errorwhilesendingmessage', true); }).finally(() => { - modal.dismiss(); + this.sending = false; + this.sendMessageForm.focus(); }); } diff --git a/src/addon/mod/chat/pages/users/users.ts b/src/addon/mod/chat/pages/users/users.ts index f54560ba3..3ec2b36e4 100644 --- a/src/addon/mod/chat/pages/users/users.ts +++ b/src/addon/mod/chat/pages/users/users.ts @@ -69,7 +69,7 @@ export class AddonModChatUsersPage { * Close the chat users modal. */ closeModal(): void { - this.viewCtrl.dismiss(); + this.viewCtrl.dismiss({users: this.users}); } /** @@ -77,8 +77,8 @@ export class AddonModChatUsersPage { * * @param user User object. */ - talkTo(user: AddonModChatUser): void { - this.viewCtrl.dismiss({talkTo: user.fullname}); + talkTo(user: AddonModChatUser): void { + this.viewCtrl.dismiss({talkTo: user.fullname, users: this.users}); } /** @@ -87,7 +87,7 @@ export class AddonModChatUsersPage { * @param user User object. */ beepTo(user: AddonModChatUser): void { - this.viewCtrl.dismiss({beepTo: user.id}); + this.viewCtrl.dismiss({beepTo: user.id, users: this.users}); } /** diff --git a/src/assets/lang/en.json b/src/assets/lang/en.json index d4514cc94..2d744257b 100644 --- a/src/assets/lang/en.json +++ b/src/assets/lang/en.json @@ -432,10 +432,12 @@ "addon.mod_chat.errorwhilegettingchatusers": "Error while getting chat users.", "addon.mod_chat.errorwhileretrievingmessages": "Error while retrieving messages from the server.", "addon.mod_chat.errorwhilesendingmessage": "Error while sending the message.", + "addon.mod_chat.messagebeepseveryone": "{{$a}} beeps everyone!", "addon.mod_chat.messagebeepsyou": "{{$a}} has just beeped you!", "addon.mod_chat.messageenter": "{{$a}} has just entered this chat", "addon.mod_chat.messageexit": "{{$a}} has left this chat", "addon.mod_chat.messages": "Messages", + "addon.mod_chat.messageyoubeep": "You beeped {{$a}}", "addon.mod_chat.modulenameplural": "Chats", "addon.mod_chat.mustbeonlinetosendmessages": "You must be online to send messages.", "addon.mod_chat.nomessages": "No messages yet", diff --git a/src/components/ion-tabs/ion-tabs.scss b/src/components/ion-tabs/ion-tabs.scss index 31f667650..ec2e85b66 100644 --- a/src/components/ion-tabs/ion-tabs.scss +++ b/src/components/ion-tabs/ion-tabs.scss @@ -60,7 +60,8 @@ ion-app.app-root core-ion-tabs { } } - .scroll-content, .fixed-content { + ion-content:not(.has-footer) > .scroll-content, + ion-content:not(.has-footer) > .fixed-content { margin-bottom: 0 !important; } } diff --git a/src/components/send-message-form/core-send-message-form.html b/src/components/send-message-form/core-send-message-form.html index b1829854a..8caa886c3 100644 --- a/src/components/send-message-form/core-send-message-form.html +++ b/src/components/send-message-form/core-send-message-form.html @@ -1,7 +1,7 @@
- diff --git a/src/components/send-message-form/send-message-form.ts b/src/components/send-message-form/send-message-form.ts index 48a7a87c6..ac7f82578 100644 --- a/src/components/send-message-form/send-message-form.ts +++ b/src/components/send-message-form/send-message-form.ts @@ -19,6 +19,7 @@ import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreTextUtilsProvider } from '@providers/utils/text'; +import { CoreDomUtilsProvider } from '@providers/utils/dom'; import { CoreConstants } from '@core/constants'; /** @@ -39,13 +40,15 @@ export class CoreSendMessageFormComponent implements OnInit { @Input() message: string; // Input text. @Input() placeholder = ''; // Placeholder for the input area. @Input() showKeyboard = false; // If keyboard is shown or not. + @Input() sendDisabled = false; // If send is disabled. @Output() onSubmit: EventEmitter; // Send data when submitting the message form. @Output() onResize: EventEmitter; // Emit when resizing the textarea. protected sendOnEnter: boolean; constructor(private utils: CoreUtilsProvider, private textUtils: CoreTextUtilsProvider, configProvider: CoreConfigProvider, - eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider) { + eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider, private appProvider: CoreAppProvider, + private domUtils: CoreDomUtilsProvider) { this.onSubmit = new EventEmitter(); this.onResize = new EventEmitter(); @@ -99,6 +102,10 @@ export class CoreSendMessageFormComponent implements OnInit { * @param other The name of the other key that was clicked, undefined if no other key. */ enterClicked(e: Event, other: string): void { + if (this.sendDisabled) { + return; + } + if (this.sendOnEnter && !other) { // Enter clicked, send the message. this.submitForm(e);