Add a date separator between messages

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2019-11-11 13:43:24 +01:00
Родитель bc6c1fb8f7
Коммит 96a16df589
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 7076EA9751AACDDA
5 изменённых файлов: 160 добавлений и 19 удалений

47
package-lock.json сгенерированный
Просмотреть файл

@ -1663,7 +1663,6 @@
"version": "7.7.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.2.tgz",
"integrity": "sha512-JONRbXbTXc9WQE2mAZd1p0Z3DZ/6vaQIkgYMSTP3KjRCyd7rCZCcfhCyX+YjwcKxcZ82UrxbRD358bpExNgrjw==",
"dev": true,
"requires": {
"regenerator-runtime": "^0.13.2"
}
@ -1807,6 +1806,39 @@
}
}
},
"@nextcloud/moment": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/@nextcloud/moment/-/moment-0.2.2.tgz",
"integrity": "sha512-ZnZ8hsXuj/smzO4aykR4LCROfmqZfxpceVIbRwsCFXbvHzxshmle/QRPP9mlzXxoBuh2IS+LPm8x7neeZXYVMQ==",
"requires": {
"@nextcloud/l10n": "0.2.0",
"core-js": "3.2.1",
"i18next": "17.0.18",
"moment": "2.24.0"
},
"dependencies": {
"@nextcloud/l10n": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/@nextcloud/l10n/-/l10n-0.2.0.tgz",
"integrity": "sha512-UyOWCaL5yhsGlR6wtVBrUJoCMR06u58UjMgWyJsofmN6ayyaTJMxqwDAoJQDC0oMj01orMMF7H8dX1vQfvtbvw==",
"requires": {
"core-js": "3.1.4"
},
"dependencies": {
"core-js": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz",
"integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ=="
}
}
},
"core-js": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.2.1.tgz",
"integrity": "sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw=="
}
}
},
"@nextcloud/router": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-0.1.0.tgz",
@ -6077,6 +6109,14 @@
"integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=",
"dev": true
},
"i18next": {
"version": "17.0.18",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-17.0.18.tgz",
"integrity": "sha512-FpLbLwzYV/qen9ZTA+mOHiNzLxESnF+sQCe5wT7UShssfDiW/df5JdXuxnPsPQiUd+M1kpB3Jaawcn9RN6atig==",
"requires": {
"@babel/runtime": "^7.3.1"
}
},
"iconv-lite": {
"version": "0.4.24",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
@ -7259,6 +7299,11 @@
}
}
},
"moment": {
"version": "2.24.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
"integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
},
"move-concurrently": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz",

Просмотреть файл

@ -19,6 +19,7 @@
"@nextcloud/axios": "^0.5.0",
"@nextcloud/initial-state": "^0.2.0",
"@nextcloud/l10n": "^0.2.1",
"@nextcloud/moment": "^0.2.2",
"@nextcloud/router": "^0.1.0",
"@nextcloud/vue": "^1.2.0",
"crypto-js": "^3.1.9-1",

Просмотреть файл

@ -124,7 +124,7 @@ export default {
* The message id.
*/
id: {
type: Number,
type: [String, Number],
required: true,
},
/**

Просмотреть файл

@ -20,22 +20,27 @@
-->
<template>
<div class="wrapper">
<div class="messages__avatar">
<AuthorAvatar v-if="!isSystemMessage"
:author-type="actorType"
:author-id="actorId"
:display-name="actorDisplayName" />
<div class="message-group">
<div v-if="dateSeparator" class="message-group__date-header">
<span class="date">{{ dateSeparator }}</span>
</div>
<div class="messages">
<Message
v-for="(message, index) of messages"
:key="message.id"
v-bind="message"
:is-first-message="index === 0"
:actor-display-name="actorDisplayName"
:show-author="!isSystemMessage"
:is-temporary="message.timestamp === 0" />
<div class="wrapper">
<div class="messages__avatar">
<AuthorAvatar v-if="!isSystemMessage"
:author-type="actorType"
:author-id="actorId"
:display-name="actorDisplayName" />
</div>
<div class="messages">
<Message
v-for="(message, index) of messages"
:key="message.id"
v-bind="message"
:is-first-message="index === 0"
:actor-display-name="actorDisplayName"
:show-author="!isSystemMessage"
:is-temporary="message.timestamp === 0" />
</div>
</div>
</div>
</template>
@ -55,7 +60,7 @@ export default {
* The message id.
*/
id: {
type: Number,
type: [String, Number],
required: true,
},
/**
@ -89,6 +94,13 @@ export default {
actorId() {
return this.messages[0].actorId
},
/**
* The message date.
* @returns {string}
*/
dateSeparator() {
return this.messages[0].dateSeparator || ''
},
/**
* The message actor display name.
* @returns {string}
@ -120,6 +132,33 @@ export default {
<style lang="scss" scoped>
@import '../../../assets/variables';
.message-group {
&__date-header {
display: block;
text-align: center;
margin: 40px 15px 0;
border-top: 1px solid var(--color-border);
padding-top: 20px;
position: relative;
.date {
content: attr(data-date);
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%) translateY(-50%);
padding: 0 7px 0 7px;
text-align: center;
white-space: nowrap;
color: var(--color-text-maxcontrast);
background-color: var(--color-main-background);
}
}
}
.wrapper {
max-width: $message-max-width;
display: flex;

Просмотреть файл

@ -45,6 +45,7 @@ the Vue virtual scroll list component, whose docs you can find [here.](https://g
</template>
<script>
import moment from '@nextcloud/moment'
import virtualList from 'vue-virtual-scroll-list'
import MessagesGroup from './MessagesGroup/MessagesGroup'
import { fetchMessages, lookForNewMessages } from '../../services/messagesService'
@ -120,6 +121,11 @@ export default {
let lastMessage = null
for (const message of this.messagesList) {
if (!this.messagesShouldBeGrouped(message, lastMessage)) {
// Add the date separator for different days
if (this.messagesHaveDifferentDate(message, lastMessage)) {
message.dateSeparator = this.generateDateSeparator(message.timestamp)
}
groups.push([message])
lastMessage = message
} else {
@ -164,11 +170,13 @@ export default {
* @param {string} message1.actorType Actor type of the new message
* @param {string} message1.actorId Actor id of the new message
* @param {string} message1.systemMessage System message content of the new message
* @param {int} message1.timestamp Timestamp of the new message
* @param {null|object} message2 The previous message
* @param {string} message2.actorType Actor type of the previous message
* @param {string} message2.actorId Actor id of the previous message
* @param {string} message2.systemMessage System message content of the previous message
* @returns {bool} Boolean if the messages should be grouped or not
* @param {int} message2.timestamp Timestamp of the second message
* @returns {boolean} Boolean if the messages should be grouped or not
*/
messagesShouldBeGrouped(message1, message2) {
return message2 // Is there a previous message
@ -178,6 +186,54 @@ export default {
&& (message1.systemMessage.length === 0) === (message2.systemMessage.length === 0) // Only group system messages with each others
&& message1.actorType === message2.actorType // To have the same author, the type
&& message1.actorId === message2.actorId // and the id of the author must be the same
&& !this.messagesHaveDifferentDate(message1, message2) // Posted on the same day
},
/**
* Check if 2 messages are from the same date
*
* @param {object} message1 The new message
* @param {int} message1.timestamp Timestamp of the new message
* @param {null|object} message2 The previous message
* @param {int} message2.timestamp Timestamp of the second message
* @returns {boolean} Boolean if the messages have the same date
*/
messagesHaveDifferentDate(message1, message2) {
return !message2 // There is no previous message
|| moment.unix(message1.timestamp).format('YYYY-MM-DD') !== moment.unix(message2.timestamp).format('YYYY-MM-DD')
},
/**
* Generate the date header between the messages
*
* @param {int} timestamp The timestamp of the message
* @returns {string} Translated string of "<Today>, <November 11th, 2019>", "<3 days ago>, <November 8th, 2019>"
*/
generateDateSeparator(timestamp) {
const date = moment.unix(timestamp)
const dayOfYear = date.format('YYYY-DDD')
let relativePrefix = date.fromNow()
// Use the relative day for today and yesterday
const dayOfYearToday = moment().format('YYYY-DDD')
if (dayOfYear === dayOfYearToday) {
relativePrefix = t('spreed', 'Today')
} else {
const dayOfYearYesterday = moment().subtract(1, 'days').format('YYYY-DDD')
if (dayOfYear === dayOfYearYesterday) {
relativePrefix = t('spreed', 'Yesterday')
}
}
// <Today>, <November 11th, 2019>
return t('spreed', '{relativeDate}, {absoluteDate}', {
relativeDate: relativePrefix,
// 'LL' formats a localized date including day of month, month
// name and year
absoluteDate: date.format('LL'),
}, undefined, {
escape: false, // French "Today" has a ' in it
})
},
/**