mirror of
https://github.com/Qortal/qortal-ui.git
synced 2025-03-30 09:15:54 +00:00
added tab notification and fixed websocket q-chat
This commit is contained in:
parent
02a78173a3
commit
22ca790f51
@ -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
|
||||||
|
@ -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>
|
||||||
|
|
||||||
${tab.myPlugObj && tab.myPlugObj.title}
|
${title}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="close" @click=${() => { this.removeTab(index) }}>x</div>
|
<div class="close" @click=${() => { this.removeTab(index) }}>x</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`)}
|
`
|
||||||
|
})}
|
||||||
<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
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
@ -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'
|
@ -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
|
||||||
|
@ -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.
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -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>
|
||||||
|
@ -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'
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user