Merge branch 'feature/persistent-data' into qchat-updates-integration

This commit is contained in:
2022-10-22 15:56:01 +03:00
19 changed files with 294 additions and 109 deletions

View File

@@ -19,7 +19,8 @@
"dependencies": {
"@material/mwc-list": "0.27.0",
"@material/mwc-select": "0.27.0",
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js"
"emoji-picker-js": "https://github.com/Qortal/emoji-picker-js",
"localforage": "^1.10.0"
},
"devDependencies": {
"@babel/core": "7.19.1",
@@ -62,4 +63,4 @@
"engines": {
"node": ">=14.17.0"
}
}
}

View File

@@ -2,7 +2,7 @@ import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import localForage from "localforage";
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
@@ -20,6 +20,10 @@ import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
const messagesCache = localForage.createInstance({
name: "messages-cache",
});
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatPage extends LitElement {
@@ -229,9 +233,12 @@ class ChatPage extends LitElement {
`
}
firstUpdated() {
async firstUpdated() {
const keys = await messagesCache.keys()
console.log({ keys })
// TODO: Load and fetch messages from localstorage (maybe save messages to localstorage...)
// this.changeLanguage();
this.emojiPickerHandler = this.shadowRoot.querySelector('.emoji-button');
this.mirrorChatInput = this.shadowRoot.getElementById('messageBox');
@@ -340,6 +347,20 @@ class ChatPage extends LitElement {
parentEpml.imReady();
}
async updated(changedProperties) {
if (changedProperties.has('messagesRendered')) {
let data = {}
console.log('chatId', this._chatId)
console.log(this.isReceipient)
const chatReference1 = this.isReceipient ? 'direct' : 'group';
const chatReference2 = this._chatId
if (chatReference1 && chatReference2) {
await messagesCache.setItem(`${chatReference1}-${chatReference2}`, this.messagesRendered);
}
}
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
@@ -380,28 +401,64 @@ class ChatPage extends LitElement {
async getOldMessage(scrollElement) {
if (this._messages.length <= 15 && this._messages.length >= 1) { // 15 is the default number of messages...
let __msg = [...this._messages]
this._messages = []
this.messagesRendered = [...__msg, ...this.messagesRendered]
if (this.isReceipient) {
const getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${this._chatId}&limit=20&reverse=true&before=${scrollElement.messageObj.timestamp}`,
});
const decodeMsgs = getInitialMessages.map((eachMessage) => {
return this.decodeMessage(eachMessage)
})
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp
- b.timestamp
})
await this.getUpdateComplete();
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
return { oldMessages: __msg, scrollElement: scrollElement }
} else if (this._messages.length > 15) {
this.messagesRendered = [...this._messages.splice(this._messages.length - 15), ...this.messagesRendered]
await this.getUpdateComplete();
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
return { oldMessages: this._messages.splice(this._messages.length - 15), scrollElement: scrollElement }
} else {
const getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${Number(this._chatId)}&limit=20&reverse=true&before=${scrollElement.messageObj.timestamp}`,
});
const decodeMsgs = getInitialMessages.map((eachMessage) => {
return this.decodeMessage(eachMessage)
})
this.messagesRendered = [...decodeMsgs, ...this.messagesRendered].sort(function (a, b) {
return a.timestamp
- b.timestamp
})
await this.getUpdateComplete();
scrollElement.scrollIntoView({ behavior: 'auto', block: 'center' });
return false
}
}
async processMessages(messages, isInitial) {
async processMessages(messages, isInitial) {
if (isInitial) {
this.messages = messages.map((eachMessage) => {
@@ -417,7 +474,10 @@ class ChatPage extends LitElement {
}
})
this._messages = [...this.messages]
this._messages = [...this.messages].sort(function (a, b) {
return a.timestamp
- b.timestamp
})
const adjustMessages = () => {
@@ -427,47 +487,33 @@ class ChatPage extends LitElement {
}
// TODO: Determine number of initial messages by screen height...
this._messages.length <= 15 ? adjustMessages() : this._initialMessages = this._messages.splice(this._messages.length - 15);
this._initialMessages = this._messages
this.messagesRendered = this._initialMessages
// try {
// const viewElement = this.shadowRoot.querySelector('chat-scroller')
// console.log({viewElement})
// // viewElement.scrollTop = this.viewElement.scrollHeight + 50
// } catch (error) {
// console.error(error)
// }
this.isLoadingMessages = false
setTimeout(() => this.downElementObserver(), 500)
} else {
let _newMessages = messages.map((eachMessage) => {
if (eachMessage.isText === true) {
let _eachMessage = this.decodeMessage(eachMessage)
messages.forEach((eachMessage) => {
const _eachMessage = this.decodeMessage(eachMessage)
this.renderNewMessage(_eachMessage)
if (this.messageSignature !== eachMessage.signature) {
this.messageSignature = eachMessage.signature
// What are we waiting for, send in the message immediately...
this.renderNewMessage(_eachMessage)
}
return _eachMessage
} else {
let _eachMessage = this.decodeMessage(eachMessage)
if (this.messageSignature !== eachMessage.signature) {
this.messageSignature = eachMessage.signature
this.renderNewMessage(_eachMessage)
}
return _eachMessage
}
})
this.newMessages = this.newMessages.concat(_newMessages)
// this.newMessages = this.newMessages.concat(_newMessages)
this.messagesRendered = [...this.messagesRendered].sort(function (a, b) {
return a.timestamp
- b.timestamp
})
}
}
@@ -537,27 +583,27 @@ class ChatPage extends LitElement {
}
}
async renderNewMessage(newMessage) {
async renderNewMessage(newMessage) {
const viewElement = this.shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement');
if (newMessage.sender === this.selectedAddress.address) {
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
viewElement.scrollTop = viewElement.scrollHeight;
} else if (this.isUserDown) {
// Append the message and scroll to the bottom if user is down the page
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
viewElement.scrollTop = viewElement.scrollHeight;
} else {
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
this.showNewMesssageBar();
}
@@ -601,7 +647,7 @@ class ChatPage extends LitElement {
async fetchChatMessages(chatId) {
const initDirect = (cid) => {
const initDirect = async (cid) => {
let initial = 0
@@ -621,6 +667,9 @@ class ChatPage extends LitElement {
directSocketLink = `ws://${nodeUrl}/websockets/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}`;
}
const directSocket = new WebSocket(directSocketLink);
// Open Connection
@@ -630,13 +679,37 @@ class ChatPage extends LitElement {
}
// Message Event
directSocket.onmessage = (e) => {
directSocket.onmessage = async (e) => {
if (initial === 0) {
const isReceipient = this.chatId.includes('direct')
const chatReference1 = isReceipient ? 'direct' : 'group';
const chatReference2 = this.chatId.split('/')[1];
const cachedData = await messagesCache.getItem(`${chatReference1}-${chatReference2}`);
let getInitialMessages = []
if (cachedData && cachedData.length !== 0) {
const lastMessage = cachedData[cachedData.length - 1]
const newMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=20&reverse=true&after=${lastMessage.timestamp}`,
});
getInitialMessages = [...cachedData, ...newMessages]
} else {
getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?involving=${window.parent.reduxStore.getState().app.selectedAddress.address}&involving=${cid}&limit=20&reverse=true`,
});
}
this.processMessages(getInitialMessages, true)
this.isLoadingMessages = true
this.processMessages(JSON.parse(e.data), true)
initial = initial + 1
} else {
this.processMessages(JSON.parse(e.data), false)
@@ -692,12 +765,38 @@ class ChatPage extends LitElement {
}
// Message Event
groupSocket.onmessage = (e) => {
groupSocket.onmessage = async (e) => {
if (initial === 0) {
const isGroup = this.chatId.includes('group')
const chatReference1 = isGroup ? 'group' : 'direct';
const chatReference2 = this.chatId.split('/')[1];
const cachedData = await messagesCache.getItem(`${chatReference1}-${chatReference2}`);
let getInitialMessages = []
if (cachedData && cachedData.length !== 0) {
const lastMessage = cachedData[cachedData.length - 1]
const newMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=20&reverse=true&after=${lastMessage.timestamp}`,
});
getInitialMessages = [...cachedData, ...newMessages]
} else {
getInitialMessages = await parentEpml.request('apiCall', {
type: 'api',
url: `/chat/messages?txGroupId=${groupId}&limit=20&reverse=true`,
});
}
this.processMessages(getInitialMessages, true)
this.isLoadingMessages = true
this.processMessages(JSON.parse(e.data), true)
initial = initial + 1
} else {