mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-04-15 07:45:54 +00:00
added unread message label
This commit is contained in:
parent
f8477c0307
commit
8dfab316a7
@ -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()
|
||||
}))
|
||||
}
|
||||
// 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) {
|
||||
// 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()
|
||||
}))
|
||||
// this.isPageVisible = true
|
||||
// if (this.chatId) {
|
||||
// window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
|
||||
// key: this.chatId,
|
||||
// timestamp: Date.now()
|
||||
// }))
|
||||
|
||||
}
|
||||
} else {
|
||||
this.isPageVisible = false
|
||||
}
|
||||
})
|
||||
}
|
||||
// }
|
||||
// } 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,25 +3321,47 @@ 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=${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=true&before=${lastReadMessageTimestamp}&haschatreference=false&encoding=BASE64`
|
||||
})
|
||||
getInitialMessages = [...newMessages]
|
||||
const getInitialMessagesAfter = await parentEpml.request('apiCall', {
|
||||
type: 'api',
|
||||
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 = [...getInitialMessagesBefore, ...getInitialMessagesAfter]
|
||||
} else {
|
||||
getInitialMessages = await parentEpml.request('apiCall', {
|
||||
type: 'api',
|
||||
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=${chatLimit}&reverse=true&haschatreference=false&encoding=BASE64`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
const lastMessage = cachedData[cachedData.length - 1]
|
||||
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})
|
||||
|
||||
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`
|
||||
})
|
||||
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`
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
this.processMessages(getInitialMessages, true)
|
||||
this.processMessages(getInitialMessages, true, isUnread)
|
||||
|
||||
initial = initial + 1
|
||||
} else {
|
||||
|
@ -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;
|
||||
|
@ -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) {
|
||||
@ -346,6 +352,57 @@ 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) {
|
||||
@ -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…
x
Reference in New Issue
Block a user