added tab notification and fixed websocket q-chat

This commit is contained in:
Phillip 2023-06-13 13:30:23 +03:00
parent 02a78173a3
commit 22ca790f51
10 changed files with 1361 additions and 1122 deletions

View File

@ -15,7 +15,7 @@ import './login-section.js'
import '../qort-theme-toggle.js' import '../qort-theme-toggle.js'
import settings from '../../functional-components/settings-page.js' import settings from '../../functional-components/settings-page.js'
import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists } from '../../redux/app/app-actions.js' import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists, addTabInfo, setTabNotifications, setNewTab } from '../../redux/app/app-actions.js'
window.reduxStore = store window.reduxStore = store
window.reduxAction = { window.reduxAction = {
@ -25,7 +25,10 @@ window.reduxAction = {
allowQAPPAutoAuth: allowQAPPAutoAuth, allowQAPPAutoAuth: allowQAPPAutoAuth,
removeQAPPAutoAuth: removeQAPPAutoAuth, removeQAPPAutoAuth: removeQAPPAutoAuth,
allowQAPPAutoLists: allowQAPPAutoLists, allowQAPPAutoLists: allowQAPPAutoLists,
removeQAPPAutoLists: removeQAPPAutoLists removeQAPPAutoLists: removeQAPPAutoLists,
addTabInfo: addTabInfo,
setTabNotifications: setTabNotifications,
setNewTab: setNewTab
} }
const animationDuration = 0.7 // Seconds const animationDuration = 0.7 // Seconds

View File

@ -6,9 +6,13 @@ import { addPluginRoutes } from '../plugins/addPluginRoutes.js'
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js';
import ShortUniqueId from 'short-unique-id'; import ShortUniqueId from 'short-unique-id';
import { setNewTab } from '../redux/app/app-actions.js' import { setNewTab } from '../redux/app/app-actions.js'
import localForage from "localforage";
import '@material/mwc-icon' import '@material/mwc-icon'
const chatLastSeen = localForage.createInstance({
name: "chat-last-seen",
});
class ShowPlugin extends connect(store)(LitElement) { class ShowPlugin extends connect(store)(LitElement) {
static get properties() { static get properties() {
return { return {
@ -20,6 +24,9 @@ class ShowPlugin extends connect(store)(LitElement) {
currentTab: { type: Number }, currentTab: { type: Number },
tabs: { type: Array }, tabs: { type: Array },
theme: { type: String, reflect: true }, theme: { type: String, reflect: true },
tabInfo: { type: Object },
chatLastSeen: { type: Array },
chatHeads: { type: Array }
} }
} }
@ -50,7 +57,7 @@ class ShowPlugin extends connect(store)(LitElement) {
} }
.hideIframe { .hideIframe {
visibility: hidden; display: none;
position: absolute; position: absolute;
zIndex: -10; zIndex: -10;
} }
@ -58,7 +65,7 @@ class ShowPlugin extends connect(store)(LitElement) {
.showIframe { .showIframe {
zIndex: 1; zIndex: 1;
position: relative; position: relative;
visibility: visible; display: block;
} }
.tabs { .tabs {
@ -155,6 +162,20 @@ class ShowPlugin extends connect(store)(LitElement) {
color: #999; color: #999;
--mdc-icon-size: 20px; --mdc-icon-size: 20px;
} }
.count {
position: absolute;
background: red;
color: white;
padding: 5px;
font-size: 12px;
border-radius: 50%;
height: 10px;
width: 10px;
display: flex;
justify-content: center;
align-items: center;
}
` `
} }
@ -165,6 +186,9 @@ class ShowPlugin extends connect(store)(LitElement) {
this.tabs = [] this.tabs = []
this.uid = new ShortUniqueId() this.uid = new ShortUniqueId()
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
this.tabInfo = {}
this.chatLastSeen = []
this.chatHeads = []
} }
async getUpdateComplete() { async getUpdateComplete() {
@ -189,9 +213,44 @@ class ShowPlugin extends connect(store)(LitElement) {
return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}` return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}`
} }
return html` return html`
<div class="tabs"> <div class="tabs">
${this.tabs.map((tab, index) => html` ${this.tabs.map((tab, index) => {
let title = ''
let count = 0
if (tab.myPlugObj && tab.myPlugObj.title) {
title = tab.myPlugObj.title
}
if (tab.myPlugObj && (tab.myPlugObj.url === 'websites' || tab.myPlugObj.url === 'qapps') && this.tabInfo[tab.id]) {
title = this.tabInfo[tab.id].name
}
if (tab.myPlugObj && (tab.myPlugObj.url === 'websites' || tab.myPlugObj.url === 'qapps') && this.tabInfo[tab.id]) {
count = this.tabInfo[tab.id].count
}
if (tab.myPlugObj && tab.myPlugObj.url === 'q-chat') {
for (const chat of this.chatHeads) {
const lastReadMessage = this.chatLastSeen.find((ch) => {
let id
if (chat.groupId === 0) {
id = chat.groupId
} else if (chat.groupId) {
id = chat.groupId
} else {
id = chat.address
}
return ch.key.includes(id)
})
if (lastReadMessage && lastReadMessage.timestamp < chat.timestamp) {
count = count + 1
}
}
}
return html`
<div <div
class="tab ${this.currentTab === index ? 'active' : ''}" class="tab ${this.currentTab === index ? 'active' : ''}"
@click=${() => this.currentTab = index} @click=${() => this.currentTab = index}
@ -200,15 +259,20 @@ class ShowPlugin extends connect(store)(LitElement) {
<div class="${this.currentTab === index ? "iconActive" : "iconInactive"}"> <div class="${this.currentTab === index ? "iconActive" : "iconInactive"}">
<mwc-icon>${tab.myPlugObj && tab.myPlugObj.mwcicon}</mwc-icon> <mwc-icon>${tab.myPlugObj && tab.myPlugObj.mwcicon}</mwc-icon>
</div> </div>
${count ? html`
<div class="count">${count}</div>
` : ''}
<div> <div>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
${tab.myPlugObj && tab.myPlugObj.title} ${title}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</div> </div>
<div class="close" @click=${() => { this.removeTab(index) }}>x</div> <div class="close" @click=${() => { this.removeTab(index) }}>x</div>
</div> </div>
</div> </div>
`)}&nbsp;&nbsp;&nbsp; `
})}&nbsp;&nbsp;&nbsp;
<button <button
class="add-tab-button" class="add-tab-button"
title="Add Tab" title="Add Tab"
@ -227,7 +291,7 @@ class ShowPlugin extends connect(store)(LitElement) {
${repeat(this.tabs, (tab) => tab.id, (tab, index) => html` ${repeat(this.tabs, (tab) => tab.id, (tab, index) => html`
<div class=${this.currentTab === index ? "showIframe" : "hideIframe"}> <div class=${this.currentTab === index ? "showIframe" : "hideIframe"}>
<iframe src="${plugSrc(tab.myPlugObj)}" id="showPluginFrame${index}" style="width:100%; <iframe src="${plugSrc(tab.myPlugObj)}" data-id=${tab.id} id="showPluginFrame${index}" style="width:100%;
height:calc(var(--window-height) - 102px); height:calc(var(--window-height) - 102px);
border:0; border:0;
padding:0; padding:0;
@ -321,7 +385,7 @@ class ShowPlugin extends connect(store)(LitElement) {
this.tabs = copiedTabs this.tabs = copiedTabs
} }
stateChanged(state) { async stateChanged(state) {
const split = state.app.url.split('/') const split = state.app.url.split('/')
const newRegisteredUrls = state.app.registeredUrls const newRegisteredUrls = state.app.registeredUrls
@ -352,6 +416,23 @@ class ShowPlugin extends connect(store)(LitElement) {
if (newLinkParam !== this.linkParam) { if (newLinkParam !== this.linkParam) {
this.linkParam = newLinkParam this.linkParam = newLinkParam
} }
if (this.tabInfo !== state.app.tabInfo) {
this.tabInfo = state.app.tabInfo
}
if (this.chatLastSeen !== state.app.chatLastSeen) {
this.chatLastSeen = state.app.chatLastSeen
}
if (state.app.chatHeads !== this.unModifiedChatHeads) {
let chatHeads = []
if (state.app.chatHeads && state.app.chatHeads.groups) {
chatHeads = [...chatHeads, ...state.app.chatHeads.groups]
}
if (state.app.chatHeads && state.app.chatHeads.direct) {
chatHeads = [...chatHeads, ...state.app.chatHeads.direct]
}
this.chatHeads = chatHeads
this.unModifiedChatHeads = state.app.chatHeads
}
if (state.app.newTab) { if (state.app.newTab) {
const newTab = state.app.newTab const newTab = state.app.newTab

View File

@ -1,5 +1,5 @@
// Core App Actions here... // Core App Actions here...
import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB } from '../app-action-types.js' import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS } from '../app-action-types.js'
export const doUpdateBlockInfo = (blockObj) => { export const doUpdateBlockInfo = (blockObj) => {
return (dispatch, getState) => { return (dispatch, getState) => {
@ -127,3 +127,16 @@ export const setNewTab = (payload) => {
} }
} }
export const addTabInfo = (payload) => {
return {
type: ADD_TAB_INFO,
payload
}
}
export const setTabNotifications = (payload) => {
return {
type: SET_TAB_NOTIFICATIONS,
payload
}
}

View File

@ -26,3 +26,5 @@ export const REMOVE_QAPP_AUTO_LISTS = 'REMOVE_QAPP_AUTO_LISTS'
export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN' export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN'
export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN' export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN'
export const SET_NEW_TAB = 'SET_NEW_TAB' export const SET_NEW_TAB = 'SET_NEW_TAB'
export const ADD_TAB_INFO = 'ADD_TAB_INFO'
export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'

View File

@ -1,6 +1,6 @@
// Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage. // Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage.
import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js' import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js'
import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB } from './app-action-types.js' import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS, SET_NEW_TAB, ADD_TAB_INFO, SET_TAB_NOTIFICATIONS } from './app-action-types.js'
import { initWorkersReducer } from './reducers/init-workers.js' import { initWorkersReducer } from './reducers/init-workers.js'
import { loginReducer } from './reducers/login-reducer.js' import { loginReducer } from './reducers/login-reducer.js'
import { setNode, addNode } from './reducers/manage-node.js' import { setNode, addNode } from './reducers/manage-node.js'
@ -47,7 +47,8 @@ const INITIAL_STATE = {
qAPPAutoAuth: loadStateFromLocalStorage('qAPPAutoAuth') || false, qAPPAutoAuth: loadStateFromLocalStorage('qAPPAutoAuth') || false,
qAPPAutoLists: loadStateFromLocalStorage('qAPPAutoLists') || false, qAPPAutoLists: loadStateFromLocalStorage('qAPPAutoLists') || false,
chatLastSeen: [], chatLastSeen: [],
newTab: null newTab: null,
tabInfo: {}
} }
export default (state = INITIAL_STATE, action) => { export default (state = INITIAL_STATE, action) => {
@ -228,6 +229,40 @@ export default (state = INITIAL_STATE, action) => {
newTab: action.payload newTab: action.payload
} }
} }
case ADD_TAB_INFO: {
const newTabInfo = action.payload
if (state.tabInfo[newTabInfo.id] && state.tabInfo[newTabInfo.id].name && newTabInfo.name === state.tabInfo[newTabInfo.id].name) break
return {
...state,
tabInfo: {
...state.tabInfo,
[newTabInfo.id]: {
...newTabInfo,
count: 0
}
}
}
}
case SET_TAB_NOTIFICATIONS: {
const count = action.payload.count
const name = action.payload.name
const newTabInfo = {}
Object.keys(state.tabInfo).forEach((key) => {
const tab = state.tabInfo[key]
if (tab.name == name) {
newTabInfo[key] = {
...tab,
count
}
} else {
newTabInfo[key] = tab
}
})
return {
...state,
tabInfo: newTabInfo
}
}
default: default:
return state return state

View File

@ -1459,7 +1459,7 @@ class ChatPage extends LitElement {
this.shadowRoot.querySelector("chat-scroller").shadowRoot.getElementById("downObserver") this.shadowRoot.querySelector("chat-scroller").shadowRoot.getElementById("downObserver")
.scrollIntoView({ .scrollIntoView({
behavior: 'smooth', behavior: 'smooth',
block: 'nearest',
}); });
}}> }}>
</vaadin-icon> </vaadin-icon>
@ -1832,8 +1832,7 @@ class ChatPage extends LitElement {
this.setUserName(""); this.setUserName("");
this.setSelectedHead({}); this.setSelectedHead({});
}} }}
style=${ style=${this.openUserInfo ? "display: block" : "display: none"
this.openUserInfo ? "display: block" : "display: none"
}> }>
<user-info <user-info
.setOpenUserInfo=${(val) => this.setOpenUserInfo(val)} .setOpenUserInfo=${(val) => this.setOpenUserInfo(val)}
@ -1939,7 +1938,8 @@ class ChatPage extends LitElement {
} }
}}) }
})
] ]
}) })
@ -1966,7 +1966,8 @@ class ChatPage extends LitElement {
return true return true
} }
} }
}}) }
})
] ]
}) })
@ -1993,7 +1994,8 @@ class ChatPage extends LitElement {
return true return true
} }
} }
}}) }
})
] ]
}) })
document.addEventListener('keydown', this.initialChat); document.addEventListener('keydown', this.initialChat);
@ -2004,6 +2006,36 @@ class ChatPage extends LitElement {
timestamp: Date.now() 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
};
// 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);
} }
disconnectedCallback() { disconnectedCallback() {
@ -2024,6 +2056,9 @@ class ChatPage extends LitElement {
if (this.editorImage) { if (this.editorImage) {
this.editorImage.destroy() this.editorImage.destroy()
} }
if (this.observer) {
this.observer.disconnect();
}
document.removeEventListener('keydown', this.initialChat); document.removeEventListener('keydown', this.initialChat);
document.removeEventListener('paste', this.pasteImage); document.removeEventListener('paste', this.pasteImage);
@ -2774,7 +2809,7 @@ class ChatPage extends LitElement {
await this.renderNewMessage(msg) await this.renderNewMessage(msg)
}) })
await Promise.all(renderEachMessage) await Promise.all(renderEachMessage)
if(this.chatId){ if (this.chatId && this.isPageVisible) {
window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({ window.parent.reduxStore.dispatch(window.parent.reduxAction.addChatLastSeen({
key: this.chatId, key: this.chatId,
timestamp: Date.now() timestamp: Date.now()
@ -2832,8 +2867,10 @@ class ChatPage extends LitElement {
const findOriginalMessageIndex = this.messagesRendered.findIndex(msg => msg.signature === newMessage.chatReference || (msg.chatReference && msg.chatReference === newMessage.chatReference)) const findOriginalMessageIndex = this.messagesRendered.findIndex(msg => msg.signature === newMessage.chatReference || (msg.chatReference && msg.chatReference === newMessage.chatReference))
if (findOriginalMessageIndex !== -1 && this.messagesRendered[findOriginalMessageIndex].sender === newMessage.sender) { if (findOriginalMessageIndex !== -1 && this.messagesRendered[findOriginalMessageIndex].sender === newMessage.sender) {
const newMessagesRendered = [...this.messagesRendered] const newMessagesRendered = [...this.messagesRendered]
newMessagesRendered[findOriginalMessageIndex] = {...newMessage, timestamp: newMessagesRendered[findOriginalMessageIndex].timestamp, senderName: newMessagesRendered[findOriginalMessageIndex].senderName, newMessagesRendered[findOriginalMessageIndex] = {
sender: newMessagesRendered[findOriginalMessageIndex].sender, editedTimestamp: newMessage.timestamp } ...newMessage, timestamp: newMessagesRendered[findOriginalMessageIndex].timestamp, senderName: newMessagesRendered[findOriginalMessageIndex].senderName,
sender: newMessagesRendered[findOriginalMessageIndex].sender, editedTimestamp: newMessage.timestamp
}
this.messagesRendered = newMessagesRendered this.messagesRendered = newMessagesRendered
await this.getUpdateComplete(); await this.getUpdateComplete();
} }
@ -2906,6 +2943,7 @@ class ChatPage extends LitElement {
async fetchChatMessages(chatId) { async fetchChatMessages(chatId) {
const initDirect = async (cid, noInitial) => { const initDirect = async (cid, noInitial) => {
let timeoutId
let initial = 0 let initial = 0
let directSocketTimeout let directSocketTimeout
@ -2932,6 +2970,11 @@ class ChatPage extends LitElement {
// Message Event // Message Event
this.webSocket.onmessage = async (e) => { this.webSocket.onmessage = async (e) => {
if (e.data === 'pong') {
clearTimeout(timeoutId);
directSocketTimeout = setTimeout(pingDirectSocket, 45000)
return
}
if (initial === 0) { if (initial === 0) {
if (noInitial) return if (noInitial) return
const cachedData = null const cachedData = null
@ -2983,10 +3026,13 @@ class ChatPage extends LitElement {
const pingDirectSocket = () => { const pingDirectSocket = () => {
this.webSocket.send('ping') this.webSocket.send('ping')
timeoutId = setTimeout(() => {
directSocketTimeout = setTimeout(pingDirectSocket, 295000) this.webSocket.close();
clearTimeout(directSocketTimeout)
}, 5000);
} }
}; };
const restartDirectWebSocket = () => { const restartDirectWebSocket = () => {
const noInitial = true const noInitial = true
@ -2999,6 +3045,7 @@ class ChatPage extends LitElement {
} }
const initGroup = (gId, noInitial) => { const initGroup = (gId, noInitial) => {
let timeoutId
let groupId = Number(gId) let groupId = Number(gId)
let initial = 0 let initial = 0
@ -3029,7 +3076,11 @@ class ChatPage extends LitElement {
// Message Event // Message Event
this.webSocket.onmessage = async (e) => { this.webSocket.onmessage = async (e) => {
if (e.data === 'pong') {
clearTimeout(timeoutId);
groupSocketTimeout = setTimeout(pingGroupSocket, 45000)
return
}
if (initial === 0) { if (initial === 0) {
if (noInitial) return if (noInitial) return
const cachedData = null; const cachedData = null;
@ -3078,12 +3129,15 @@ class ChatPage extends LitElement {
// Error Event // Error Event
this.webSocket.onerror = () => { this.webSocket.onerror = () => {
clearTimeout(groupSocketTimeout) clearTimeout(groupSocketTimeout)
this.webSocket.close();
} }
const pingGroupSocket = () => { const pingGroupSocket = () => {
this.webSocket.send('ping') this.webSocket.send('ping')
timeoutId = setTimeout(() => {
groupSocketTimeout = setTimeout(pingGroupSocket, 295000) this.webSocket.close();
clearTimeout(groupSocketTimeout)
}, 5000); // Close the WebSocket connection if no pong message is received within 5 seconds.
} }
}; };

View File

@ -24,10 +24,12 @@ import axios from "axios";
import StarterKit from '@tiptap/starter-kit' import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'; import Underline from '@tiptap/extension-underline';
import Highlight from '@tiptap/extension-highlight' import Highlight from '@tiptap/extension-highlight'
import ShortUniqueId from 'short-unique-id';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
let toggledMessage = {} let toggledMessage = {}
const uid = new ShortUniqueId()
const getApiKey = () => { const getApiKey = () => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey;
@ -113,7 +115,20 @@ function processText(input) {
if (path) { if (path) {
query = query + `&path=${path}` query = query + `&path=${path}`
} }
window.location = `../../qdn/browser/index.html${query}` window.parent.reduxStore.dispatch(window.parent.reduxAction.setNewTab({
url: `qdn/browser/index.html${query}`,
id: uid(),
myPlugObj: {
"url": service === 'WEBSITE' ? "websites" : "qapps",
"domain": "core",
"page": `qdn/browser/index.html${query}`,
"title": name,
"mwcicon": service === 'WEBSITE' ? 'vaadin:desktop' : 'open_in_browser',
"menus": [],
"parent": false
}
}))
} catch (error) { } catch (error) {
console.log({ error }) console.log({ error })
} }
@ -1155,7 +1170,8 @@ class MessageTemplate extends LitElement {
name: attachment.name, name: attachment.name,
identifier: attachment.identifier, identifier: attachment.identifier,
editedMessageObj: this.messageObj, editedMessageObj: this.messageObj,
})} })
}
}> }>
Yes Yes
</button> </button>

View File

@ -45,3 +45,6 @@ export const DECRYPT_DATA = 'DECRYPT_DATA'
// SAVE_FILE // SAVE_FILE
export const SAVE_FILE = 'SAVE_FILE' export const SAVE_FILE = 'SAVE_FILE'
//SET_TAB_NOTIFICATIONS
export const SET_TAB_NOTIFICATIONS = 'SET_TAB_NOTIFICATIONS'

View File

@ -892,10 +892,42 @@ class WebBrowser extends LitElement {
this.service = data.service; this.service = data.service;
this.identifier = data.identifier; this.identifier = data.identifier;
this.displayUrl = url; this.displayUrl = url;
const frame = window.frameElement
let tabId = ""
if (frame && frame.dataset.id) {
tabId = frame.dataset.id
}
if (data.name === 'Q-Mail') { if (data.name === 'Q-Mail') {
localStorage.setItem("Q-Mail-last-visited", Date.now()) localStorage.setItem("Q-Mail-last-visited", Date.now())
} }
window.parent.reduxStore.dispatch(window.parent.reduxAction.addTabInfo({
name: data.name,
service: data.service,
id: tabId ? tabId : ""
}))
return; return;
case actions.SET_TAB_NOTIFICATIONS: {
const { count } = data
if (isNaN(count)) {
response['error'] = 'count is not a number'
break
}
if (count === undefined) {
response['error'] = 'missing count'
break
}
window.parent.reduxStore.dispatch(window.parent.reduxAction.setTabNotifications({
name: this.name,
count: count
}))
response = true
break
}
case actions.PUBLISH_QDN_RESOURCE: { case actions.PUBLISH_QDN_RESOURCE: {
// optional fields: encrypt:boolean recipientPublicKey:string // optional fields: encrypt:boolean recipientPublicKey:string

View File

@ -115,6 +115,7 @@ let closeGracefully = false
let onceLoggedIn = false let onceLoggedIn = false
let retryOnClose = false let retryOnClose = false
let canPing = false let canPing = false
let timeoutId
parentEpml.subscribe('logged_in', async isLoggedIn => { parentEpml.subscribe('logged_in', async isLoggedIn => {
@ -127,18 +128,16 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
if (window.parent.location.protocol === "https:") { if (window.parent.location.protocol === "https:") {
activeChatSocketLink = `wss://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}`; activeChatSocketLink = `wss://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64`;
} else { } else {
activeChatSocketLink = `ws://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}`; activeChatSocketLink = `ws://${nodeUrl}/websockets/chat/active/${window.parent.reduxStore.getState().app.selectedAddress.address}?encoding=BASE64`;
} }
const activeChatSocket = new WebSocket(activeChatSocketLink); const activeChatSocket = new WebSocket(activeChatSocketLink);
// Open Connection // Open Connection
activeChatSocket.onopen = () => { activeChatSocket.onopen = () => {
console.log(`[SOCKET]: Connected.`);
socketObject = activeChatSocket socketObject = activeChatSocket
initial = initial + 1 initial = initial + 1
@ -147,28 +146,26 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
// Message Event // Message Event
activeChatSocket.onmessage = (e) => { activeChatSocket.onmessage = (e) => {
if (e.data === 'pong') {
clearTimeout(timeoutId);
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 45000)
return
}
try {
chatHeadWatcher(JSON.parse(e.data)) chatHeadWatcher(JSON.parse(e.data))
} catch (error) {
}
} }
// Closed Event // Closed Event
activeChatSocket.onclose = () => { activeChatSocket.onclose = () => {
console.log(`[SOCKET]: CLOSED`);
clearInterval(activeChatSocketTimeout) clearInterval(activeChatSocketTimeout)
if (closeGracefully === false && initial <= 52) { if (closeGracefully === false) {
if (initial <= 52) {
parentEpml.request('showSnackBar', "Connection to the Qortal Core was lost, is your Core running ?")
retryOnClose = true retryOnClose = true
setTimeout(pingActiveChatSocket, 10000) setTimeout(pingActiveChatSocket, 10000)
initial = initial + 1
} else {
parentEpml.request('showSnackBar', "Cannot connect to the Qortal Core, restart UI and Core!")
}
} }
} }
@ -188,18 +185,21 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
initChatHeadSocket() initChatHeadSocket()
onceLoggedIn = true onceLoggedIn = true
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000) activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 45000)
} else if (retryOnClose) { } else if (retryOnClose) {
retryOnClose = false retryOnClose = false
clearTimeout(activeChatSocketTimeout) clearTimeout(activeChatSocketTimeout)
initChatHeadSocket() initChatHeadSocket()
onceLoggedIn = true onceLoggedIn = true
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000) activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 45000)
} else if (canPing) { } else if (canPing) {
socketObject.send('ping') socketObject.send('ping')
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 295000) timeoutId = setTimeout(() => {
socketObject.close();
clearTimeout(activeChatSocketTimeout)
}, 5000);
} }
} else { } else {