Browse Source

added unread message label

resolve-20231003
PhilReact 1 year ago
parent
commit
8dfab316a7
  1. 214
      plugins/plugins/core/components/ChatPage.js
  2. 11
      plugins/plugins/core/components/ChatScroller-css.js
  3. 88
      plugins/plugins/core/components/ChatScroller.js

214
plugins/plugins/core/components/ChatPage.js

@ -55,8 +55,8 @@ const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
export const queue = new RequestQueue();
export const chatLimit = 10
export const totalMsgCount = 20
export const chatLimit = 40
export const totalMsgCount = 120
class ChatPage extends LitElement {
static get properties() {
return {
@ -1367,6 +1367,8 @@ class ChatPage extends LitElement {
this.addToUpdateMessageHashmap = this.addToUpdateMessageHashmap.bind(this)
this.getAfterMessages = this.getAfterMessages.bind(this)
this.oldMessages = []
this.lastReadMessageTimestamp = 0
this.initUpdate = this.initUpdate.bind(this)
}
setOpenGifModal(value) {
@ -2006,42 +2008,42 @@ class ChatPage extends LitElement {
document.addEventListener('keydown', this.initialChat)
document.addEventListener('paste', this.pasteImage)
if (this.chatId) {
window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
key: this.chatId,
timestamp: Date.now()
}))
}
let callback = (entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.isPageVisible = true
if (this.chatId) {
window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
key: this.chatId,
timestamp: Date.now()
}))
}
} else {
this.isPageVisible = false
}
})
}
// if (this.chatId) {
// window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
// key: this.chatId,
// timestamp: Date.now()
// }))
// }
// let callback = (entries, observer) => {
// entries.forEach(entry => {
// if (entry.isIntersecting) {
// this.isPageVisible = true
// if (this.chatId) {
// window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
// key: this.chatId,
// timestamp: Date.now()
// }))
// }
// } else {
// this.isPageVisible = false
// }
// })
// }
let options = {
root: null,
rootMargin: '0px',
threshold: 0.5
}
// let options = {
// root: null,
// rootMargin: '0px',
// threshold: 0.5
// }
// Create the observer with the callback function and options
this.observer = new IntersectionObserver(callback, options)
const mainContainer = this.shadowRoot.querySelector('.main-container')
// // Create the observer with the callback function and options
// this.observer = new IntersectionObserver(callback, options)
// const mainContainer = this.shadowRoot.querySelector('.main-container')
this.observer.observe(mainContainer)
// this.observer.observe(mainContainer)
}
disconnectedCallback() {
@ -2416,6 +2418,17 @@ class ChatPage extends LitElement {
// this.selectedAddress = selectedAddress
// })
// })
this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatId) || 0
// parentEpml.subscribe('chat_last_seen', async chatList => {
// const parsedChatList = JSON.parse(chatList)
// console.log({parsedChatList}, this.chatId)
// const findChatSeen = parsedChatList.find(chat=> chat.key === this.chatId)
// console.log({findChatSeen})
// if(findChatSeen && this.lastReadMessageTimestamp !== findChatSeen.timestamp){
// this.lastReadMessageTimestamp = findChatSeen.timestamp
// }
// })
parentEpml.imReady()
@ -2994,9 +3007,28 @@ class ChatPage extends LitElement {
this.requestUpdate()
}
findContent(identifier, data) {
const [type, id] = identifier.split('/');
if (type === 'group') {
for (let group of data.groups) {
if (group.groupId === parseInt(id, 10)) {
return group;
}
}
} else if (type === 'direct') {
for (let direct of data.direct) {
if (direct.address === id) {
return direct;
}
}
}
return null;
}
async processMessages(messages, isInitial) {
async processMessages(messages, isInitial, isUnread) {
const isReceipient = this.chatId.includes('direct')
let decodedMessages = []
if(!this.webWorkerDecodeMessages){
@ -3058,10 +3090,27 @@ class ChatPage extends LitElement {
// TODO: Determine number of initial messages by screen height...
// this.messagesRendered = this._messages
this.messagesRendered = {
messages: this._messages,
type: 'initial'
const lastReadMessageTimestamp = this.lastReadMessageTimestamp
if(isUnread){
this.messagesRendered = {
messages: this._messages,
type: 'initialLastSeen',
lastReadMessageTimestamp
}
window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
key: this.chatId,
timestamp: Date.now()
}))
} else {
this.messagesRendered = {
messages: this._messages,
type: 'initial'
}
}
this.isLoadingMessages = false
setTimeout(() => this.downElementObserver(), 500)
@ -3272,17 +3321,37 @@ class ChatPage extends LitElement {
directSocketTimeout = setTimeout(pingDirectSocket, 45000)
return
}
if (initial === 0) {
this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatId) || 0
if (noInitial) return
const cachedData = null
let getInitialMessages = []
if (cachedData && cachedData.length !== 0) {
const lastMessage = cachedData[cachedData.length - 1]
const newMessages = await parentEpml.request('apiCall', {
let isUnread = false
const chatId = this.chatId
console.log('this.chatHeads', this.chatHeads)
const findContent = this.chatHeads.find((item)=> item.url === chatId)
const chatInfoTimestamp = findContent.timestamp || 0
const lastReadMessageTimestamp = this.lastReadMessageTimestamp
console.log({lastReadMessageTimestamp, chatInfoTimestamp})
if(lastReadMessageTimestamp && chatInfoTimestamp){
if(lastReadMessageTimestamp < chatInfoTimestamp){
isUnread = true
}
}
console.log({isUnread})
if(isUnread){
const getInitialMessagesBefore = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=${20}&reverse=true&before=${lastReadMessageTimestamp}&haschatreference=false&encoding=BASE64`
})
const getInitialMessagesAfter = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=${chatLimit}&reverse=true&after=${lastMessage.timestamp}&haschatreference=false&encoding=BASE64`
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=${20}&reverse=false&after=${lastReadMessageTimestamp - 1000}&haschatreference=false&encoding=BASE64`
})
getInitialMessages = [...newMessages]
getInitialMessages = [...getInitialMessagesBefore, ...getInitialMessagesAfter]
} else {
getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
@ -3290,7 +3359,9 @@ class ChatPage extends LitElement {
})
}
this.processMessages(getInitialMessages, true)
this.processMessages(getInitialMessages, true, isUnread)
initial = initial + 1
@ -3371,27 +3442,48 @@ class ChatPage extends LitElement {
return
}
if (initial === 0) {
this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatId) || 0
if (noInitial) return
const cachedData = null
let getInitialMessages = []
if (cachedData && cachedData.length !== 0) {
const lastReadMessageTimestamp = this.lastReadMessageTimestamp
let isUnread = false
const chatId = this.chatId
console.log('this.chatHeads', this.chatHeads)
const findContent = this.chatHeads.find((item)=> item.url === chatId)
const chatInfoTimestamp = findContent.timestamp || 0
console.log({lastReadMessageTimestamp, chatInfoTimestamp})
if(lastReadMessageTimestamp && chatInfoTimestamp){
if(lastReadMessageTimestamp < chatInfoTimestamp){
isUnread = true
}
}
console.log({isUnread}, '2')
if(isUnread){
const getInitialMessagesBefore = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=${20}&reverse=true&before=${lastReadMessageTimestamp}&haschatreference=false&encoding=BASE64`
})
const getInitialMessagesAfter = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=${20}&reverse=false&after=${lastReadMessageTimestamp - 1000}&haschatreference=false&encoding=BASE64`
})
getInitialMessages = [...getInitialMessagesBefore, ...getInitialMessagesAfter]
} else {
getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=${chatLimit}&reverse=true&haschatreference=false&encoding=BASE64`
})
}
const lastMessage = cachedData[cachedData.length - 1]
const newMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=${chatLimit}&reverse=true&after=${lastMessage.timestamp}&haschatreference=false&encoding=BASE64`
})
getInitialMessages = [...newMessages]
}else {
getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=${chatLimit}&reverse=true&haschatreference=false&encoding=BASE64`
})
}
this.processMessages(getInitialMessages, true)
this.processMessages(getInitialMessages, true, isUnread)
initial = initial + 1
} else {

11
plugins/plugins/core/components/ChatScroller-css.js

@ -753,6 +753,17 @@ export const chatStyles = css`
visibility: visible;
}
.unread-divider {
width: 100%;
background: #9B111E;
padding: 5px;
color: #FAEBD7;
display: flex;
justify-content: center;
border-radius: 2px;
margin-top: 5px;
}
.blink-bg{
border-radius: 8px;
animation: blinkingBackground 3s;

88
plugins/plugins/core/components/ChatScroller.js

@ -10,6 +10,7 @@ import { roundToNearestDecimal } from '../../utils/roundToNearestDecimal.js'
import { EmojiPicker } from 'emoji-picker-js'
import { generateHTML } from '@tiptap/core'
import isElectron from 'is-electron'
import localForage from 'localforage'
import axios from 'axios'
import Highlight from '@tiptap/extension-highlight'
@ -32,7 +33,9 @@ import '@vaadin/tooltip'
import { chatLimit, totalMsgCount } from './ChatPage.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const chatLastSeen = localForage.createInstance({
name: "chat-last-seen",
})
let toggledMessage = {}
const uid = new ShortUniqueId()
@ -259,7 +262,9 @@ class ChatScroller extends LitElement {
this.oldMessages = []
this._upObserverhandler = this._upObserverhandler.bind(this)
this.newListMessages = this.newListMessages.bind(this)
this.newListMessagesUnreadMessages = this.newListMessagesUnreadMessages.bind(this)
this._downObserverHandler = this._downObserverHandler.bind(this)
this.isLastMessageBeforeUnread = this.isLastMessageBeforeUnread.bind(this)
this.replaceMessagesWithUpdate = this.replaceMessagesWithUpdate.bind(this)
this.__bottomObserverForFetchingMessagesHandler = this.__bottomObserverForFetchingMessagesHandler.bind(this)
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
@ -273,6 +278,7 @@ class ChatScroller extends LitElement {
this.isLoadingBefore = false
this.isLoadingAfter = false
this.disableAddingNewMessages = false
this.lastReadMessageTimestamp = null
}
addSeenMessage(val) {
@ -344,10 +350,61 @@ class ChatScroller extends LitElement {
}
async newListMessagesUnreadMessages(newMessages, message, lastReadMessageTimestamp) {
const viewElement = this.shadowRoot.querySelector("#viewElement");
console.log('sup', lastReadMessageTimestamp);
let data = [];
const copy = [...newMessages];
let dividerPlaced = false; // To ensure the divider is added only once
// Start from the end of the list (newest messages)
for (let i = copy.length - 1; i >= 0; i--) {
let newMessage = copy[i];
// Initialize a property for the divider
newMessage.isDivider = false;
// Check if this is the message before which the divider should be placed
if (!dividerPlaced && newMessage.timestamp <= lastReadMessageTimestamp) {
console.log('true true')
newMessage.isDivider = true;
dividerPlaced = true; // Ensure the divider is only added once
break; // Exit once the divider is placed
}
}
copy.forEach((newMessage, groupIndex) => {
const lastGroupedMessage = data[data.length - 1];
if (this.shouldGroupWithLastMessage(newMessage, lastGroupedMessage)) {
lastGroupedMessage.messages.push(newMessage);
} else {
data.push({
messages: [newMessage],
...newMessage
});
}
});
console.log({ data });
this.messagesToRender = data;
this.clearLoaders();
this.requestUpdate();
await this.updateComplete;
const findElement = this.shadowRoot.getElementById('unread-divider-id')
if (findElement) {
findElement.scrollIntoView({ behavior: 'auto', block: 'center' })
}
}
async addNewMessages(newMessages, type) {
if(this.disableAddingNewMessages && type === 'newComingInAuto') return
let previousScrollTop;
@ -402,7 +459,7 @@ class ChatScroller extends LitElement {
if (type === 'initial') {
this.viewElement.scrollTop = this.viewElement.scrollHeight
viewElement.scrollTop = viewElement.scrollHeight
@ -547,13 +604,17 @@ class ChatScroller extends LitElement {
async updated(changedProperties) {
if (changedProperties && changedProperties.has('messages')) {
console.log({changedProperties}, this.messages)
if (this.messages.type === 'initial') {
this.addNewMessages(this.messages.messages, 'initial')
} else if (this.messages.type === 'new') this.addNewMessages(this.messages.messages)
} else if (this.messages.type === 'initialLastSeen') {
this.newListMessagesUnreadMessages(this.messages.messages, 'initialLastSeen', this.messages.lastReadMessageTimestamp)
}
else if (this.messages.type === 'new') this.addNewMessages(this.messages.messages)
else if(this.messages.type === 'newComingInAuto') this.addNewMessages(this.messages.messages, 'newComingInAuto')
else if (this.messages.type === 'old') this.prependOldMessages(this.messages.messages)
else if (this.messages.type === 'inBetween') this.newListMessages(this.messages.messages, this.messages.signature)
@ -567,6 +628,15 @@ class ChatScroller extends LitElement {
}
isLastMessageBeforeUnread(message, formattedMessages) {
// if the message is the last one in the older messages list and its timestamp is before the user's last seen timestamp
if (message.timestamp < this.lastReadMessageTimestamp && formattedMessages.indexOf(message) === (formattedMessages.length - 21)) {
return true;
}
return false;
}
render() {
// let formattedMessages = this.messages.reduce((messageArray, message) => {
// const currentMessage = this.updateMessageHash[message.signature] || message;
@ -617,10 +687,12 @@ class ChatScroller extends LitElement {
formattedMessages,
(formattedMessage) => formattedMessage.id, // Use .id as the unique key for formattedMessage.
(formattedMessage) => html`
${repeat(
formattedMessage.messages,
(message) => message.signature,
(message, indexMessage) => html`
<message-template
.emojiPicker=${this.emojiPicker}
.escapeHTML=${this.escapeHTML}
@ -644,8 +716,13 @@ class ChatScroller extends LitElement {
.addSeenMessage=${(val) => this.addSeenMessage(val)}
.listSeenMessages=${this.listSeenMessages}
chatId=${this.chatId}
></message-template>`
></message-template>
${message.isDivider ? html`<div class="unread-divider" id="unread-divider-id">Unread Messages Below</div>` : null}
`
)}
`
)}
<div style=${"height: 1px; margin-top: -100px"} id='bottomObserverForFetchingMessages'></div>
@ -708,7 +785,6 @@ class ChatScroller extends LitElement {
async firstUpdated() {
this.changeTheme()
window.addEventListener('storage', () => {
const checkTheme = localStorage.getItem('qortalTheme')

Loading…
Cancel
Save