4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-11 17:55:51 +00:00

Merge pull request #185 from Qortal/master

Update dev branch
This commit is contained in:
AlphaX-Projects 2023-08-02 10:46:44 +02:00 committed by GitHub
commit b581327c71
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 3509 additions and 14209 deletions

View File

@ -27,8 +27,8 @@ Easiest way to install the lastest required packages on Linux is via nvm.
``` source ~/.profile ``` (For Debian based distro) <br/> ``` source ~/.profile ``` (For Debian based distro) <br/>
``` source ~/.bashrc ``` (For Fedora / CentOS) <br/> ``` source ~/.bashrc ``` (For Fedora / CentOS) <br/>
``` nvm ls-remote ``` (Fetch list of available versions) <br/> ``` nvm ls-remote ``` (Fetch list of available versions) <br/>
``` nvm install v18.14.0 ``` (LTS: Hydrogen supported by Electron) <br/> ``` nvm install v18.15.0 ``` (LTS: Hydrogen supported by Electron) <br/>
``` npm --location=global install npm@9.7.2 ``` <br/> ``` npm --location=global install npm@9.8.1 ``` <br/>
Adding via binary package mirror will only work if you have set the package path. You can do a node or java build via ports instead by downloading ports with portsnap fetch method. Adding via binary package mirror will only work if you have set the package path. You can do a node or java build via ports instead by downloading ports with portsnap fetch method.

View File

@ -214,7 +214,8 @@
"wp1": "Prägung", "wp1": "Prägung",
"wp2": "Nicht am Prägen", "wp2": "Nicht am Prägen",
"wp3": "Kerninformationen", "wp3": "Kerninformationen",
"wp4": "Synchronisiert" "wp4": "Synchronisiert",
"wp5": "Synchronisierungsstatus"
}, },
"general": { "general": {
"yes": "Ja", "yes": "Ja",

View File

@ -214,7 +214,8 @@
"wp1": "Acuñación", "wp1": "Acuñación",
"wp2": "Sin acuñar", "wp2": "Sin acuñar",
"wp3": "Información básica", "wp3": "Información básica",
"wp4": "Sincronizado" "wp4": "Sincronizado",
"wp5": "Estado de sincronización"
}, },
"general": { "general": {
"yes": "Sí", "yes": "Sí",

View File

@ -214,7 +214,8 @@
"wp1": "Monnaie", "wp1": "Monnaie",
"wp2": "Pas de frappe", "wp2": "Pas de frappe",
"wp3": "Informations de base", "wp3": "Informations de base",
"wp4": "Synchronisé" "wp4": "Synchronisé",
"wp5": "État de la synchronisation"
}, },
"general": { "general": {
"yes": "Oui", "yes": "Oui",

View File

@ -215,7 +215,8 @@
"wp1": "खनन", "wp1": "खनन",
"wp2": "नॉट मिंटिंग", "wp2": "नॉट मिंटिंग",
"wp3": "मुख्य जानकारी", "wp3": "मुख्य जानकारी",
"wp4": "सिंक्रोनाइज़्ड" "wp4": "सिंक्रोनाइज़्ड",
"wp5": "सिंक स्थिति"
}, },
"general": { "general": {
"yes": "हाँ", "yes": "हाँ",

View File

@ -214,7 +214,8 @@
"wp1": "Kovanje", "wp1": "Kovanje",
"wp2": "Nije kovano", "wp2": "Nije kovano",
"wp3": "Osnovne informacije", "wp3": "Osnovne informacije",
"wp4": "Sinkronizirano" "wp4": "Sinkronizirano",
"wp5": "Status sinkronizacije"
}, },
"general": { "general": {
"yes": "Da", "yes": "Da",

View File

@ -214,7 +214,8 @@
"wp1": "verés", "wp1": "verés",
"wp2": "Nem pénzverés", "wp2": "Nem pénzverés",
"wp3": "Alapinformációk", "wp3": "Alapinformációk",
"wp4": "Szinkronizált" "wp4": "Szinkronizált",
"wp5": "Szinkronizálás állapota"
}, },
"general": { "general": {
"yes": "Igen", "yes": "Igen",

View File

@ -214,7 +214,8 @@
"wp1": "Conio", "wp1": "Conio",
"wp2": "Non conio", "wp2": "Non conio",
"wp3": "Informazioni principali", "wp3": "Informazioni principali",
"wp4": "Sincronizzato" "wp4": "Sincronizzato",
"wp5": "Stato sincronizzazione"
}, },
"general": { "general": {
"yes": "Yes", "yes": "Yes",

View File

@ -216,7 +216,8 @@
"wp1": "ミント", "wp1": "ミント",
"wp2": "鋳造しない", "wp2": "鋳造しない",
"wp3": "コア情報", "wp3": "コア情報",
"wp4": "同期済み" "wp4": "同期済み",
"wp5": "同期ステータス"
}, },
"general": { "general": {
"yes": "はい", "yes": "はい",

View File

@ -214,7 +214,8 @@
"wp1": "조폐", "wp1": "조폐",
"wp2": "조폐되지 않음", "wp2": "조폐되지 않음",
"wp3": "핵심 정보", "wp3": "핵심 정보",
"wp4": "동기화됨" "wp4": "동기화됨",
"wp5": "동기화 상태"
}, },
"general": { "general": {
"yes": "예", "yes": "예",

View File

@ -214,7 +214,8 @@
"wp1": "Minting", "wp1": "Minting",
"wp2": "Ikke preging", "wp2": "Ikke preging",
"wp3": "Kjerneinformasjon", "wp3": "Kjerneinformasjon",
"wp4": "Synkronisert" "wp4": "Synkronisert",
"wp5": "Synkroniseringsstatus"
}, },
"general": { "general": {
"yes": "Ja", "yes": "Ja",

View File

@ -214,7 +214,8 @@
"wp1": "Bicie", "wp1": "Bicie",
"wp2": "Nie bije", "wp2": "Nie bije",
"wp3": "Podstawowe informacje", "wp3": "Podstawowe informacje",
"wp4": "Zsynchronizowany" "wp4": "Zsynchronizowany",
"wp5": "Stan synchronizacji"
}, },
"general": { "general": {
"yes": "Tak", "yes": "Tak",

View File

@ -214,7 +214,8 @@
"wp1": "Criação", "wp1": "Criação",
"wp2": "Não está cunhando", "wp2": "Não está cunhando",
"wp3": "Informações essenciais", "wp3": "Informações essenciais",
"wp4": "Sincronizado" "wp4": "Sincronizado",
"wp5": "Status da sincronização"
}, },
"general": { "general": {
"yes": "Sim", "yes": "Sim",

View File

@ -214,7 +214,8 @@
"wp1": "Battering", "wp1": "Battering",
"wp2": "Nu se bate", "wp2": "Nu se bate",
"wp3": "Informații de bază", "wp3": "Informații de bază",
"wp4": "Sincronizat" "wp4": "Sincronizat",
"wp5": "Stare sincronizare"
}, },
"general": { "general": {
"yes": "Da", "yes": "Da",

View File

@ -214,7 +214,8 @@
"wp1": "Kovanje", "wp1": "Kovanje",
"wp2": "Ne kuje", "wp2": "Ne kuje",
"wp3": "Osnovne informacije", "wp3": "Osnovne informacije",
"wp4": "Sinhronizovano" "wp4": "Sinhronizovano",
"wp5": "Status sinhronizacije"
}, },
"general": { "general": {
"yes": "Da", "yes": "Da",

View File

@ -214,7 +214,8 @@
"wp1": "Чеканка", "wp1": "Чеканка",
"wp2": "Не чеканить", "wp2": "Не чеканить",
"wp3": "Основная информация", "wp3": "Основная информация",
"wp4": "Синхронизировано" "wp4": "Синхронизировано",
"wp5": "Статус синхронизации"
}, },
"general": { "general": {
"yes": "Да", "yes": "Да",

View File

@ -219,7 +219,8 @@
"wp1": "Minting", "wp1": "Minting",
"wp2": "Not Minting", "wp2": "Not Minting",
"wp3": "Core Information", "wp3": "Core Information",
"wp4": "Synchronized" "wp4": "Synchronized",
"wp5": "Sync Status"
}, },
"general": { "general": {
"yes": "Yes", "yes": "Yes",

View File

@ -214,7 +214,8 @@
"wp1": "铸造", "wp1": "铸造",
"wp2": "不铸造", "wp2": "不铸造",
"wp3": "核心信息", "wp3": "核心信息",
"wp4": "已同步" "wp4": "已同步",
"wp5": "同步状态"
}, },
"general": { "general": {
"yes": "是", "yes": "是",

View File

@ -214,7 +214,8 @@
"wp1": "鑄造", "wp1": "鑄造",
"wp2": "不鑄造", "wp2": "不鑄造",
"wp3": "核心信息", "wp3": "核心信息",
"wp4": "已同步" "wp4": "已同步",
"wp5": "同步狀態"
}, },
"general": { "general": {
"yes": "是", "yes": "是",

View File

@ -7,6 +7,7 @@ import { get, translate, translateUnsafeHTML } from 'lit-translate'
import localForage from 'localforage' import localForage from 'localforage'
import { encryptData, decryptData } from '../lockScreen.js' import { encryptData, decryptData } from '../lockScreen.js'
import { setChatLastSeen } from '../redux/app/app-actions.js' import { setChatLastSeen } from '../redux/app/app-actions.js'
import isElectron from 'is-electron'
const chatLastSeen = localForage.createInstance({ const chatLastSeen = localForage.createInstance({
name: "chat-last-seen", name: "chat-last-seen",
@ -427,7 +428,7 @@ class AppView extends connect(store)(LitElement) {
constructor() { constructor() {
super() super()
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
this.urls = []; this.urls = []
this.nodeType = '' this.nodeType = ''
this.addressInfo = {} this.addressInfo = {}
this.getAllBalancesLoading = false this.getAllBalancesLoading = false
@ -649,6 +650,8 @@ class AppView extends connect(store)(LitElement) {
addTradeBotRoutes(parentEpml) addTradeBotRoutes(parentEpml)
parentEpml.imReady() parentEpml.imReady()
this.clearTheCache()
this.helperMessage = this.renderHelperPass() this.helperMessage = this.renderHelperPass()
this.salt = '' this.salt = ''
@ -1581,14 +1584,14 @@ class AppView extends connect(store)(LitElement) {
} }
const getChatLastSeen = async () => { const getChatLastSeen = async () => {
let items = []; let items = []
await chatLastSeen.iterate(function (value, key, iterationNumber) { await chatLastSeen.iterate(function (value, key, iterationNumber) {
items.push({ key, timestamp: value })
items.push({ key, timestamp: value });
}) })
store.dispatch(setChatLastSeen(items)) store.dispatch(setChatLastSeen(items))
return items; return items
} }
await getOpenTradesBTC() await getOpenTradesBTC()
@ -1603,14 +1606,26 @@ class AppView extends connect(store)(LitElement) {
await appDelay(1000) await appDelay(1000)
await getOpenTradesARRR() await getOpenTradesARRR()
await getChatLastSeen() await getChatLastSeen()
setInterval(() => {
this.clearTheCache()
}, 60000)
} }
shBalanceTicker() { shBalanceTicker() {
const targetDiv = this.shadowRoot.getElementById("theTicker") const targetDiv = this.shadowRoot.getElementById("theTicker")
if (targetDiv.style.display !== "none") { if (targetDiv.style.display !== "none") {
targetDiv.style.display = "none"; targetDiv.style.display = "none"
} else { } else {
targetDiv.style.display = "inline"; targetDiv.style.display = "inline"
}
}
clearTheCache() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearMyCache()
window.parent.electronAPI.clearCache()
} }
} }

View File

@ -1,16 +1,17 @@
const { const {
app, app,
BrowserWindow, BrowserWindow,
ipcMain, ipcMain,
ipcRenderer, ipcRenderer,
Menu, Menu,
Notification, Notification,
Tray, Tray,
nativeImage, nativeImage,
dialog, dialog,
webContents, webContents,
nativeTheme, nativeTheme,
crashReporter crashReporter,
webFrame
} = require('electron') } = require('electron')
const { autoUpdater } = require('electron-updater') const { autoUpdater } = require('electron-updater')
@ -40,19 +41,16 @@ crashReporter.start({
uploadToServer: false uploadToServer: false
}) })
if (myMemory > 16000000000) { app.commandLine.appendSwitch('js-flags', '--max-executable-size=192 --max-old-space-size=1024 --max-semi-space-size=2')
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=8192')
log.info("Memory Size Is 16GB Using JS Memory Heap Size 8GB") setInterval (function() {
} else if (myMemory > 12000000000) { let mu = process.memoryUsage()
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=6144') log.info('heapTotal:', mu.heapTotal, 'heapUsed:', mu.heapUsed);
log.info("Memory Size Is 12GB Using JS Memory Heap Size 6GB") if (mu.heapUsed > 1024 * 1024 * 1024) {
} else if (myMemory > 7000000000) { log.info('Taking out the garbage')
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=4096') global.gc()
log.info("Memory Size Is 8GB Using JS Memory Heap Size 4GB") }
} else { }, 1000 * 120)
app.commandLine.appendSwitch('js-flags', '--max-old-space-size=2048')
log.info("Memory Size Is 4GB Using JS Memory Heap Size 2GB")
}
if (process.arch === 'arm') { if (process.arch === 'arm') {
app.disableHardwareAcceleration() app.disableHardwareAcceleration()
@ -1031,6 +1029,12 @@ if (!isLock) {
} }
}) })
}) })
ipcMain.on('clear-all-cache', (event) => {
const theWindows = BrowserWindow.getAllWindows()[0]
const ses = theWindows.webContents.session
console.clear()
ses.clearCache()
})
ipcMain.on('check-for-update', (event) => { ipcMain.on('check-for-update', (event) => {
const check = new Notification({ const check = new Notification({
title: i18n.__("electron_translate_43"), title: i18n.__("electron_translate_43"),

View File

@ -1,8 +1,12 @@
const { contextBridge, ipcRenderer } = require('electron') const { contextBridge, ipcRenderer, webFrame } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', { contextBridge.exposeInMainWorld('electronAPI', {
setStartCore: () => ipcRenderer.send('set-start-core'), setStartCore: () => ipcRenderer.send('set-start-core'),
checkForUpdate: () => ipcRenderer.send('check-for-update'), checkForUpdate: () => ipcRenderer.send('check-for-update'),
showMyMenu: () => ipcRenderer.send('show-my-menu'), showMyMenu: () => ipcRenderer.send('show-my-menu'),
focusApp: () => ipcRenderer.send('focus-app'), focusApp: () => ipcRenderer.send('focus-app'),
clearMyCache: () => ipcRenderer.send('clear-all-cache'),
clearCache() {
webFrame.clearCache()
},
}) })

2556
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -51,29 +51,29 @@
"prosemirror-gapcursor": "1.3.2", "prosemirror-gapcursor": "1.3.2",
"prosemirror-history": "1.3.2", "prosemirror-history": "1.3.2",
"prosemirror-keymap": "1.2.2", "prosemirror-keymap": "1.2.2",
"prosemirror-model": "1.19.2", "prosemirror-model": "1.19.3",
"prosemirror-schema-list": "1.3.0", "prosemirror-schema-list": "1.3.0",
"prosemirror-state": "1.4.3", "prosemirror-state": "1.4.3",
"prosemirror-transform": "1.7.3", "prosemirror-transform": "1.7.4",
"prosemirror-view": "1.31.5", "prosemirror-view": "1.31.7",
"sass": "1.63.6", "sass": "1.64.1",
"short-unique-id": "4.4.4", "short-unique-id": "4.4.4",
"@hapi/hapi": "21.3.2", "@hapi/hapi": "21.3.2",
"@hapi/inert": "7.1.0", "@hapi/inert": "7.1.0",
"@lit-labs/motion": "1.0.3", "@lit-labs/motion": "1.0.3",
"@tiptap/pm": "2.0.3", "@tiptap/pm": "2.0.4",
"@tiptap/core": "2.0.3", "@tiptap/core": "2.0.4",
"@tiptap/extension-highlight": "2.0.3", "@tiptap/extension-highlight": "2.0.4",
"@tiptap/extension-image": "2.0.3", "@tiptap/extension-image": "2.0.4",
"@tiptap/extension-placeholder": "2.0.3", "@tiptap/extension-placeholder": "2.0.4",
"@tiptap/extension-underline": "2.0.3", "@tiptap/extension-underline": "2.0.4",
"@tiptap/html": "2.0.3", "@tiptap/html": "2.0.4",
"@tiptap/starter-kit": "2.0.3" "@tiptap/starter-kit": "2.0.4"
}, },
"devDependencies": { "devDependencies": {
"axios": "1.4.0", "axios": "1.4.0",
"electron": "25.3.0", "electron": "25.3.2",
"electron-builder": "24.4.0", "electron-builder": "24.6.3",
"electron-packager": "17.1.1", "electron-packager": "17.1.1",
"epml": "0.3.3", "epml": "0.3.3",
"file-saver": "2.0.5", "file-saver": "2.0.5",
@ -86,7 +86,7 @@
"passive-events-support": "1.1.0", "passive-events-support": "1.1.0",
"redux": "4.2.1", "redux": "4.2.1",
"redux-thunk": "2.4.2", "redux-thunk": "2.4.2",
"rollup": "3.26.2", "rollup": "3.27.0",
"rollup-plugin-node-globals": "1.4.0", "rollup-plugin-node-globals": "1.4.0",
"rollup-plugin-progress": "1.1.2", "rollup-plugin-progress": "1.1.2",
"rollup-plugin-scss": "3.0.0", "rollup-plugin-scss": "3.0.0",
@ -130,19 +130,19 @@
"@qortal/rollup-plugin-web-worker-loader": "1.6.4", "@qortal/rollup-plugin-web-worker-loader": "1.6.4",
"@rollup/plugin-alias": "5.0.0", "@rollup/plugin-alias": "5.0.0",
"@rollup/plugin-babel": "6.0.3", "@rollup/plugin-babel": "6.0.3",
"@rollup/plugin-commonjs": "25.0.2", "@rollup/plugin-commonjs": "25.0.3",
"@rollup/plugin-node-resolve": "15.1.0", "@rollup/plugin-node-resolve": "15.1.0",
"@rollup/plugin-replace": "5.0.2", "@rollup/plugin-replace": "5.0.2",
"@rollup/plugin-terser": "0.4.3", "@rollup/plugin-terser": "0.4.3",
"@vaadin/avatar": "24.1.3", "@vaadin/avatar": "24.1.4",
"@vaadin/button": "24.1.3", "@vaadin/button": "24.1.4",
"@vaadin/grid": "24.1.3", "@vaadin/grid": "24.1.4",
"@vaadin/icons": "24.1.3", "@vaadin/icons": "24.1.4",
"@vaadin/password-field": "24.1.3", "@vaadin/password-field": "24.1.4",
"@vaadin/tooltip": "24.1.3", "@vaadin/tooltip": "24.1.4",
"@zip.js/zip.js": "2.7.20" "@zip.js/zip.js": "2.7.20"
}, },
"engines": { "engines": {
"node": ">=18.14.0" "node": ">=18.15.0"
} }
} }

View File

@ -134,6 +134,18 @@ class BecomeMinter extends LitElement {
window.parent.electronAPI.showMyMenu() window.parent.electronAPI.showMyMenu()
}) })
} }
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
async getRewardShareRelationship(recipientAddress) { async getRewardShareRelationship(recipientAddress) {

View File

@ -1,19 +1,15 @@
import { LitElement, html } from 'lit'; import { LitElement, html } from 'lit'
import { Epml } from '../../../../epml.js'; import { Epml } from '../../../../epml.js'
import '../../components/ButtonIconCopy.js'; import '../../components/ButtonIconCopy.js'
import { use, translate, registerTranslateConfig } from 'lit-translate'; import { use, get, translate, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({ import '@polymer/paper-spinner/paper-spinner-lite.js'
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json()), import '@material/mwc-button'
}); import '@material/mwc-textfield'
import '@vaadin/button'
import { pageStyles } from '../become-minter-css.src.js'
import '@polymer/paper-spinner/paper-spinner-lite.js'; const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
import '@material/mwc-button';
import '@material/mwc-textfield';
import '@vaadin/button';
import { pageStyles } from '../become-minter-css.src.js';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class NotSponsored extends LitElement { class NotSponsored extends LitElement {
static properties = { static properties = {
@ -27,18 +23,18 @@ class NotSponsored extends LitElement {
constructor() { constructor() {
super(); super();
this.isLoadingSponsorshipKeySubmit = false; this.isLoadingSponsorshipKeySubmit = false
this.sponsorshipKeyValue = ''; this.sponsorshipKeyValue = ''
this.addMintingAccountMessage = ''; this.addMintingAccountMessage = ''
this.atMount = () => {}; this.atMount = () => {}
} }
renderErr1Text() { renderErr1Text() {
return html`${translate('nodepage.nchange27')}`; return html`${translate('nodepage.nchange27')}`
} }
renderErr2Text() { renderErr2Text() {
return html`${translate('nodepage.nchange28')}`; return html`${translate('nodepage.nchange28')}`
} }
getApiKey() { getApiKey() {
@ -46,13 +42,13 @@ class NotSponsored extends LitElement {
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
window.parent.reduxStore.getState().app.nodeConfig.node window.parent.reduxStore.getState().app.nodeConfig.node
]; ];
let apiKey = myNode.apiKey; let apiKey = myNode.apiKey
return apiKey; return apiKey
} }
addMintingAccount(e) { addMintingAccount(e) {
this.isLoadingSponsorshipKeySubmit = true; this.isLoadingSponsorshipKeySubmit = true
this.addMintingAccountMessage = 'Loading...'; this.addMintingAccountMessage = 'Loading...'
parentEpml parentEpml
.request('apiCall', { .request('apiCall', {
@ -63,20 +59,20 @@ class NotSponsored extends LitElement {
.then((res) => { .then((res) => {
if (res === true) { if (res === true) {
// refetch data // refetch data
this.atMount(); this.atMount()
this.sponsorshipKeyValue = ''; this.sponsorshipKeyValue = ''
this.addMintingAccountMessage = this.renderErr1Text(); this.addMintingAccountMessage = this.renderErr1Text()
this.isLoadingSponsorshipKeySubmit = false; this.isLoadingSponsorshipKeySubmit = false
} else { } else {
this.sponsorshipKeyValue = ''; this.sponsorshipKeyValue = '';
this.addMintingAccountMessage = this.renderErr2Text(); this.addMintingAccountMessage = this.renderErr2Text()
this.isLoadingSponsorshipKeySubmit = false; this.isLoadingSponsorshipKeySubmit = false
} }
}); })
} }
inputHandler(e) { inputHandler(e) {
this.sponsorshipKeyValue = e.target.value; this.sponsorshipKeyValue = e.target.value
} }
render() { render() {
@ -130,8 +126,8 @@ class NotSponsored extends LitElement {
</div> </div>
</div> </div>
</div> </div>
`; `
} }
} }
window.customElements.define('not-sponsored', NotSponsored); window.customElements.define('not-sponsored', NotSponsored)

View File

@ -1,18 +1,14 @@
import { LitElement, html } from 'lit'; import { LitElement, html } from 'lit'
import { Epml } from '../../../../epml.js'; import { Epml } from '../../../../epml.js'
import '../../components/ButtonIconCopy.js'; import '../../components/ButtonIconCopy.js'
import { use, translate, registerTranslateConfig } from 'lit-translate'; import { use, get, translate, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({ import '@polymer/paper-spinner/paper-spinner-lite.js'
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json()), import '@material/mwc-button'
}); import '@material/mwc-textfield'
import '@vaadin/button'
import '@polymer/paper-spinner/paper-spinner-lite.js'; import { blocksNeed } from '../../../utils/blocks-needed.js'
import '@material/mwc-button'; import { pageStyles } from '../become-minter-css.src.js'
import '@material/mwc-textfield';
import '@vaadin/button';
import { blocksNeed } from '../../../utils/blocks-needed.js';
import { pageStyles } from '../become-minter-css.src.js';
class YesSponsored extends LitElement { class YesSponsored extends LitElement {
static get properties() { static get properties() {
@ -24,14 +20,13 @@ class YesSponsored extends LitElement {
} }
constructor() { constructor() {
super(); super()
this.addressInfo = {}
this.addressInfo = {}; this.rewardSharePublicKey = ''
this.rewardSharePublicKey = '';
this.isMinting = false this.isMinting = false
} }
static styles = [pageStyles]; static styles = [pageStyles]
_levelUpBlocks() { _levelUpBlocks() {
let countBlocksString = ( let countBlocksString = (
@ -39,7 +34,7 @@ class YesSponsored extends LitElement {
(this.addressInfo?.blocksMinted + (this.addressInfo?.blocksMinted +
this.addressInfo?.blocksMintedAdjustment) this.addressInfo?.blocksMintedAdjustment)
).toString(); ).toString();
return countBlocksString; return countBlocksString
} }
render() { render() {
@ -107,8 +102,8 @@ class YesSponsored extends LitElement {
</div> </div>
</div> </div>
</div> </div>
`; `
} }
} }
window.customElements.define('yes-sponsored', YesSponsored); window.customElements.define('yes-sponsored', YesSponsored)

View File

@ -5,12 +5,12 @@ import * as zip from '@zip.js/zip.js';
import '@material/mwc-icon'; import '@material/mwc-icon';
import ShortUniqueId from 'short-unique-id'; import ShortUniqueId from 'short-unique-id';
import {publishData} from '../../../utils/publish-image.js'; import {publishData} from '../../../utils/publish-image.js';
import {translate, get} from 'lit-translate';
import {gifExplorerStyles} from './ChatGifs-css.js'; import {gifExplorerStyles} from './ChatGifs-css.js';
import { bytesToMegabytes } from '../../../utils/bytesToMegabytes.js'; import { bytesToMegabytes } from '../../../utils/bytesToMegabytes.js';
import './ChatGifsExplore.js'; import './ChatGifsExplore.js';
import '../ImageComponent.js'; import '../ImageComponent.js';
import '@vaadin/tooltip'; import '@vaadin/tooltip';
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({type: 'WINDOW', source: window.parent}); const parentEpml = new Epml({type: 'WINDOW', source: window.parent});
@ -993,4 +993,4 @@ setOpenGifModal: { attribute: false }
} }
window.customElements.define('chat-gifs', ChatGifs); window.customElements.define('chat-gifs', ChatGifs)

View File

@ -1,8 +1,8 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { Epml } from '../../../../epml.js'; import { Epml } from '../../../../epml.js'
import { chatGifsExploreStyles } from './ChatGifsExplore-css.js'; import { chatGifsExploreStyles } from './ChatGifsExplore-css.js'
import { translate, get } from 'lit-translate'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@material/mwc-icon'; import '@material/mwc-icon'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }); const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
@ -69,9 +69,9 @@ class ChatGifsExplore extends LitElement {
this.elementObserver(); this.elementObserver();
} }
getApiKey() { 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
return apiKey; return apiKey
} }
async searchCollections() { async searchCollections() {
@ -169,4 +169,4 @@ class ChatGifsExplore extends LitElement {
} }
window.customElements.define('chat-gifs-explore', ChatGifsExplore); window.customElements.define('chat-gifs-explore', ChatGifsExplore)

View File

@ -1,6 +1,5 @@
import { LitElement, html, css } from "lit" import { LitElement, html, css } from "lit"
import { render } from "lit/html.js" import { render } from "lit/html.js"
import { get, translate } from "lit-translate"
import { Epml } from "../../../epml" import { Epml } from "../../../epml"
import snackbar from "./snackbar.js" import snackbar from "./snackbar.js"
import "@material/mwc-button" import "@material/mwc-button"
@ -8,6 +7,7 @@ import "@material/mwc-dialog"
import "@polymer/paper-spinner/paper-spinner-lite.js" import "@polymer/paper-spinner/paper-spinner-lite.js"
import "@material/mwc-icon" import "@material/mwc-icon"
import "./WrapperModal" import "./WrapperModal"
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: "WINDOW", source: window.parent }) const parentEpml = new Epml({ type: "WINDOW", source: window.parent })

View File

@ -1,13 +1,13 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { get, translate } from 'lit-translate'; import { Epml } from '../../../epml'
import { Epml } from '../../../epml';
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import '@material/mwc-button'; import '@material/mwc-button'
import '@material/mwc-dialog'; import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@material/mwc-icon'; import '@material/mwc-icon'
import './WrapperModal'; import './WrapperModal'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -25,7 +25,7 @@ class ChatGroupSettings extends LitElement {
} }
constructor() { constructor() {
super(); super()
this.isLoading = false; this.isLoading = false;
this.isOpenLeaveModal = false this.isOpenLeaveModal = false
this.leaveGroupObj = {} this.leaveGroupObj = {}

View File

@ -1,19 +1,19 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { get, translate } from 'lit-translate'; import { Epml } from '../../../epml'
import { Epml } from '../../../epml';
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import '@material/mwc-button'; import '@material/mwc-button'
import '@material/mwc-dialog'; import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@material/mwc-icon'; import '@material/mwc-icon'
import './WrapperModal'; import './WrapperModal'
import '@vaadin/tabs' import '@vaadin/tabs'
import '@vaadin/tabs/theme/material/vaadin-tabs.js'; import '@vaadin/tabs/theme/material/vaadin-tabs.js'
import '@vaadin/avatar'; import '@vaadin/avatar'
import '@vaadin/grid'; import '@vaadin/grid'
import '@vaadin/grid/vaadin-grid-filter-column.js'; import '@vaadin/grid/vaadin-grid-filter-column.js'
import { columnBodyRenderer } from '@vaadin/grid/lit.js'; import { columnBodyRenderer } from '@vaadin/grid/lit.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })

View File

@ -1,18 +1,20 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import localForage from "localforage"; import localForage from "localforage"
import { translate} from 'lit-translate'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@material/mwc-icon' import '@material/mwc-icon'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const chatLastSeen = localForage.createInstance({ const chatLastSeen = localForage.createInstance({
name: "chat-last-seen", name: "chat-last-seen",
}); })
class ChatHead extends LitElement { class ChatHead extends LitElement {
static get properties() { static get properties() {
return { return {
theme: { type: String, reflect: true },
selectedAddress: { type: Object }, selectedAddress: { type: Object },
config: { type: Object }, config: { type: Object },
chatInfo: { type: Object }, chatInfo: { type: Object },
@ -53,10 +55,7 @@ class ChatHead extends LitElement {
color: var(--chat-group); color: var(--chat-group);
} }
.about { .about {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
@ -109,12 +108,13 @@ class ChatHead extends LitElement {
this.imageFetches = 0 this.imageFetches = 0
this.lastReadMessageTimestamp = 0 this.lastReadMessageTimestamp = 0
this.loggedInAddress = window.parent.reduxStore.getState().app.selectedAddress.address this.loggedInAddress = window.parent.reduxStore.getState().app.selectedAddress.address
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
} }
createImage(imageUrl) { createImage(imageUrl) {
const imageHTMLRes = new Image(); const imageHTMLRes = new Image()
imageHTMLRes.src = imageUrl; imageHTMLRes.src = imageUrl
imageHTMLRes.style= "width:40px; height:40px; float: left; border-radius:50%"; imageHTMLRes.style= "width:40px; height:40px; float: left; border-radius:50%"
imageHTMLRes.onclick= () => { imageHTMLRes.onclick= () => {
this.openDialogImage = true; this.openDialogImage = true;
} }
@ -124,29 +124,25 @@ class ChatHead extends LitElement {
imageHTMLRes.onerror = () => { imageHTMLRes.onerror = () => {
if (this.imageFetches < 4) { if (this.imageFetches < 4) {
setTimeout(() => { setTimeout(() => {
this.imageFetches = this.imageFetches + 1; this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl; imageHTMLRes.src = imageUrl
}, 750); }, 750)
} else { } else {
this.isImageLoaded = false this.isImageLoaded = false
} }
}; };
return imageHTMLRes; return imageHTMLRes
} }
render() { render() {
let avatarImg = ''; let avatarImg = ''
let backupAvatarImg = '' let backupAvatarImg = ''
let isUnread = false let isUnread = false
if(this.chatInfo.name){ if(this.chatInfo.name){
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`; const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`
avatarImg= this.createImage(avatarUrl) avatarImg= this.createImage(avatarUrl)
} }
@ -189,6 +185,19 @@ class ChatHead extends LitElement {
} }
async firstUpdated() { async firstUpdated() {
this.changeTheme()
window.addEventListener('storage', () => {
const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
})
let configLoaded = false let configLoaded = false
this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatInfo.url) || 0 this.lastReadMessageTimestamp = await chatLastSeen.getItem(this.chatInfo.url) || 0
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
@ -217,6 +226,16 @@ class ChatHead extends LitElement {
parentEpml.imReady() parentEpml.imReady()
} }
changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
}
shouldUpdate(changedProperties) { shouldUpdate(changedProperties) {
if(changedProperties.has('activeChatHeadUrl')){ if(changedProperties.has('activeChatHeadUrl')){
return true return true

View File

@ -1,13 +1,14 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { get, translate } from 'lit-translate'; import { Epml } from '../../../epml'
import { Epml } from '../../../epml';
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import '@material/mwc-button'; import '@material/mwc-button'
import '@material/mwc-dialog'; import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@material/mwc-icon'; import '@material/mwc-icon'
import './WrapperModal'; import './WrapperModal'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatLeaveGroup extends LitElement { class ChatLeaveGroup extends LitElement {

View File

@ -1,7 +1,7 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })

View File

@ -1,10 +1,10 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { get, translate } from 'lit-translate'; import { Epml } from '../../../epml'
import { Epml } from '../../../epml';
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import '@material/mwc-button'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@material/mwc-dialog'; import '@material/mwc-button'
import '@material/mwc-dialog'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -18,15 +18,15 @@ class ChatModals extends LitElement {
hidePrivateMessageModal: {type: Function}, hidePrivateMessageModal: {type: Function},
hideBlockUserModal: {type: Function}, hideBlockUserModal: {type: Function},
toblockaddress: { type: String, attribute: true }, toblockaddress: { type: String, attribute: true },
chatBlockedAdresses: { type: Array }, chatBlockedAdresses: { type: Array }
} }
} }
constructor() { constructor() {
super(); super()
this.isLoading = false; this.isLoading = false
this.hidePrivateMessageModal = () => {}; this.hidePrivateMessageModal = () => {}
this.hideBlockUserModal = () => {}; this.hideBlockUserModal = () => {}
this.chatBlockedAdresses = [] this.chatBlockedAdresses = []
} }
@ -105,13 +105,13 @@ class ChatModals extends LitElement {
} else { } else {
this.sendMessage() this.sendMessage()
} }
}; }
async sendMessage() { async sendMessage() {
this.isLoading = true; this.isLoading = true
const _recipient = this.shadowRoot.getElementById('sendTo').value; const _recipient = this.shadowRoot.getElementById('sendTo').value
const messageBox = this.shadowRoot.getElementById('messageBox'); const messageBox = this.shadowRoot.getElementById('messageBox')
const messageText = messageBox.value; const messageText = messageBox.value
let recipient; let recipient;
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
@ -127,7 +127,7 @@ class ChatModals extends LitElement {
myRes = myNameRes myRes = myNameRes
} }
return myRes; return myRes
} }
const myNameRes = await validateName(_recipient) const myNameRes = await validateName(_recipient)
@ -138,8 +138,8 @@ class ChatModals extends LitElement {
recipient = myNameRes.owner recipient = myNameRes.owner
} }
let _reference = new Uint8Array(64); let _reference = new Uint8Array(64)
window.crypto.getRandomValues(_reference); window.crypto.getRandomValues(_reference)
let sendTimestamp = Date.now() let sendTimestamp = Date.now()
@ -200,17 +200,17 @@ class ChatModals extends LitElement {
const _computePow = async (chatBytes) => { const _computePow = async (chatBytes) => {
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }); const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; })
const chatBytesArray = new Uint8Array(_chatBytesArray) const chatBytesArray = new Uint8Array(_chatBytesArray)
const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result const chatBytesHash = new window.parent.Sha256().process(chatBytesArray).finish().result
const hashPtr = window.parent.sbrk(32, window.parent.heap); const hashPtr = window.parent.sbrk(32, window.parent.heap)
const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32); const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32)
hashAry.set(chatBytesHash); hashAry.set(chatBytesHash)
const difficulty = this.balance < 4 ? 18 : 8; const difficulty = this.balance < 4 ? 18 : 8
const workBufferLength = 8 * 1024 * 1024; const workBufferLength = 8 * 1024 * 1024;
const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap); const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap)
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty) let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
@ -250,9 +250,9 @@ class ChatModals extends LitElement {
} }
getApiKey() { 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
return apiKey; return apiKey
} }
getChatBlockedList() { getChatBlockedList() {
@ -263,7 +263,7 @@ class ChatModals extends LitElement {
localStorage.removeItem("ChatBlockedAddresses") localStorage.removeItem("ChatBlockedAddresses")
var obj = []; var obj = []
fetch(blockedAddressesUrl).then(response => { fetch(blockedAddressesUrl).then(response => {
return response.json() return response.json()
@ -412,4 +412,4 @@ class ChatModals extends LitElement {
} }
} }
customElements.define('chat-modals', ChatModals); customElements.define('chat-modals', ChatModals)

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
import { LitElement, html, css } from "lit"; import { LitElement, html, css } from "lit";
import { render } from "lit/html.js"; import { render } from "lit/html.js";
import { get, translate } from "lit-translate";
import { Epml } from "../../../epml"; import { Epml } from "../../../epml";
import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress"; import { getUserNameFromAddress } from "../../utils/getUserNameFromAddress";
import snackbar from "./snackbar.js"; import snackbar from "./snackbar.js";
@ -13,6 +12,9 @@ import '@vaadin/button';
import "./WrapperModal"; import "./WrapperModal";
import "./TipUser" import "./TipUser"
import "./UserInfo/UserInfo"; import "./UserInfo/UserInfo";
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatRightPanel extends LitElement { class ChatRightPanel extends LitElement {
static get properties() { static get properties() {

View File

@ -1,57 +1,63 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { repeat } from 'lit/directives/repeat.js'; import { repeat } from 'lit/directives/repeat.js'
import { translate, get } from 'lit-translate'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import { unsafeHTML } from 'lit/directives/unsafe-html.js'; import { unsafeHTML } from 'lit/directives/unsafe-html.js'
import { chatStyles } from './ChatScroller-css.js' import { chatStyles } from './ChatScroller-css.js'
import { Epml } from "../../../epml"; import { Epml } from '../../../epml'
import { cropAddress } from "../../utils/cropAddress"; import { cropAddress } from "../../utils/cropAddress"
import { roundToNearestDecimal } from '../../utils/roundToNearestDecimal.js'; import { roundToNearestDecimal } from '../../utils/roundToNearestDecimal.js'
import './LevelFounder.js'; import { EmojiPicker } from 'emoji-picker-js'
import './NameMenu.js'; import { generateHTML } from '@tiptap/core'
import './ChatModals.js'; import isElectron from 'is-electron'
import './WrapperModal';
import "./UserInfo/UserInfo"; import axios from 'axios'
import '@vaadin/icons';
import '@vaadin/icon';
import '@vaadin/tooltip';
import '@material/mwc-button';
import '@material/mwc-dialog';
import '@material/mwc-icon';
import { EmojiPicker } from 'emoji-picker-js';
import { generateHTML } from '@tiptap/core';
import axios from "axios";
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline';
import Highlight from '@tiptap/extension-highlight' import Highlight from '@tiptap/extension-highlight'
import ShortUniqueId from 'short-unique-id'; import ShortUniqueId from 'short-unique-id'
import StarterKit from '@tiptap/starter-kit'
import Underline from '@tiptap/extension-underline'
import './ChatModals.js'
import './LevelFounder.js'
import './NameMenu.js'
import './UserInfo/UserInfo.js'
import './WrapperModal'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@vaadin/icon'
import '@vaadin/icons'
import '@vaadin/tooltip'
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 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
return apiKey; return apiKey
} }
const extractComponents = async (url) => { const extractComponents = async (url) => {
if (!url.startsWith("qortal://")) { if (!url.startsWith("qortal://")) {
return null; return null
} }
url = url.replace(/^(qortal\:\/\/)/, ""); url = url.replace(/^(qortal\:\/\/)/, "")
if (url.includes("/")) { if (url.includes("/")) {
let parts = url.split("/"); let parts = url.split("/")
const service = parts[0].toUpperCase(); const service = parts[0].toUpperCase()
parts.shift(); parts.shift()
const name = parts[0]; const name = parts[0]
parts.shift(); parts.shift()
let identifier; let identifier
if (parts.length > 0) { if (parts.length > 0) {
identifier = parts[0]; // Do not shift yet identifier = parts[0] // Do not shift yet
// Check if a resource exists with this service, name and identifier combination // Check if a resource exists with this service, name and identifier combination
let responseObj = await parentEpml.request('apiCall', { let responseObj = await parentEpml.request('apiCall', {
url: `/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${getApiKey()}` url: `/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${getApiKey()}`
@ -59,48 +65,48 @@ const extractComponents = async (url) => {
if (responseObj.totalChunkCount > 0) { if (responseObj.totalChunkCount > 0) {
// Identifier exists, so don't include it in the path // Identifier exists, so don't include it in the path
parts.shift(); parts.shift()
} }
else { else {
identifier = null; identifier = null
} }
} }
const path = parts.join("/"); const path = parts.join("/")
const components = {}; const components = {}
components["service"] = service; components["service"] = service
components["name"] = name; components["name"] = name
components["identifier"] = identifier; components["identifier"] = identifier
components["path"] = path; components["path"] = path
return components; return components
} }
return null; return null
} }
function processText(input) { function processText(input) {
const linkRegex = /(qortal:\/\/\S+)/g; const linkRegex = /(qortal:\/\/\S+)/g
function processNode(node) { function processNode(node) {
if (node.nodeType === Node.TEXT_NODE) { if (node.nodeType === Node.TEXT_NODE) {
const parts = node.textContent.split(linkRegex); const parts = node.textContent.split(linkRegex)
if (parts.length > 1) { if (parts.length > 1) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment()
parts.forEach((part) => { parts.forEach((part) => {
if (part.startsWith('qortal://')) { if (part.startsWith('qortal://')) {
const link = document.createElement('span'); const link = document.createElement('span')
// Store the URL in a data attribute // Store the URL in a data attribute
link.setAttribute('data-url', part); link.setAttribute('data-url', part)
link.textContent = part; link.textContent = part
link.style.color = 'var(--nav-text-color)'; link.style.color = 'var(--nav-text-color)'
link.style.textDecoration = 'underline'; link.style.textDecoration = 'underline'
link.style.cursor = 'pointer' link.style.cursor = 'pointer'
link.addEventListener('click', async (e) => { link.addEventListener('click', async (e) => {
e.preventDefault(); e.preventDefault()
try { try {
const res = await extractComponents(part) const res = await extractComponents(part)
if (!res) return if (!res) return
@ -134,34 +140,36 @@ function processText(input) {
console.log({ error }) console.log({ error })
} }
}); })
fragment.appendChild(link); fragment.appendChild(link)
} else { } else {
const textNode = document.createTextNode(part); const textNode = document.createTextNode(part)
fragment.appendChild(textNode); fragment.appendChild(textNode)
} }
}); })
node.replaceWith(fragment); node.replaceWith(fragment)
} }
} else { } else {
for (const childNode of Array.from(node.childNodes)) { for (const childNode of Array.from(node.childNodes)) {
processNode(childNode); processNode(childNode)
} }
} }
} }
const wrapper = document.createElement('div'); const wrapper = document.createElement('div')
wrapper.innerHTML = input; wrapper.innerHTML = input
processNode(wrapper); processNode(wrapper)
return wrapper return wrapper
} }
class ChatScroller extends LitElement { class ChatScroller extends LitElement {
static get properties() { static get properties() {
return { return {
theme: { type: String, reflect: true },
getNewMessage: { attribute: false }, getNewMessage: { attribute: false },
getOldMessage: { attribute: false }, getOldMessage: { attribute: false },
escapeHTML: { attribute: false }, escapeHTML: { attribute: false },
@ -193,7 +201,7 @@ class ChatScroller extends LitElement {
} }
static get styles() { static get styles() {
return [chatStyles]; return [chatStyles]
} }
constructor() { constructor() {
@ -203,9 +211,10 @@ class ChatScroller extends LitElement {
this._downObserverHandler = this._downObserverHandler.bind(this) this._downObserverHandler = this._downObserverHandler.bind(this)
this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]") this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]")
this.openTipUser = false; this.openTipUser = false
this.openUserInfo = false; this.openUserInfo = false
this.listSeenMessages = [] this.listSeenMessages = []
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
} }
addSeenMessage(val) { addSeenMessage(val) {
@ -214,42 +223,41 @@ class ChatScroller extends LitElement {
render() { render() {
let formattedMessages = this.messages.reduce((messageArray, message, index) => { let formattedMessages = this.messages.reduce((messageArray, message, index) => {
const lastGroupedMessage = messageArray[messageArray.length - 1]; const lastGroupedMessage = messageArray[messageArray.length - 1]
let timestamp; let timestamp
let sender; let sender
let repliedToData; let repliedToData
let firstMessageInChat; let firstMessageInChat
if (index === 0) { if (index === 0) {
firstMessageInChat = true; firstMessageInChat = true
} else { } else {
firstMessageInChat = false; firstMessageInChat = false
} }
message = { ...message, firstMessageInChat } message = { ...message, firstMessageInChat }
if (lastGroupedMessage) { if (lastGroupedMessage) {
timestamp = lastGroupedMessage.timestamp; timestamp = lastGroupedMessage.timestamp
sender = lastGroupedMessage.sender; sender = lastGroupedMessage.sender
repliedToData = lastGroupedMessage.repliedToData; repliedToData = lastGroupedMessage.repliedToData
} }
const isSameGroup = Math.abs(timestamp - message.timestamp) < 600000 && sender === message.sender && !repliedToData; const isSameGroup = Math.abs(timestamp - message.timestamp) < 600000 && sender === message.sender && !repliedToData
if (isSameGroup) { if (isSameGroup) {
messageArray[messageArray.length - 1].messages = [ messageArray[messageArray.length - 1].messages = [
...(messageArray[messageArray.length - 1].messages || []), ...(messageArray[messageArray.length - 1].messages || []),
message message
]; ]
} else { } else {
messageArray.push({ messageArray.push({
messages: [message], messages: [message],
...message ...message
}); })
} }
return messageArray; return messageArray
}, []) }, [])
return html` return html`
${this.isLoadingMessages ? html` ${this.isLoadingMessages ? html`
<div class="spinnerContainer"> <div class="spinnerContainer">
@ -312,37 +320,72 @@ class ChatScroller extends LitElement {
return true return true
} }
// Only update element if prop1 changed. // Only update element if prop1 changed.
return changedProperties.has('messages'); return changedProperties.has('messages')
} }
async getUpdateComplete() { async getUpdateComplete() {
await super.getUpdateComplete(); await super.getUpdateComplete()
const marginElements = Array.from(this.shadowRoot.querySelectorAll('message-template')); const marginElements = Array.from(this.shadowRoot.querySelectorAll('message-template'))
await Promise.all(marginElements.map(el => el.updateComplete)); await Promise.all(marginElements.map(el => el.updateComplete))
return true; return true
} }
setToggledMessage(message) { setToggledMessage(message) {
toggledMessage = message; toggledMessage = message
} }
async firstUpdated() { async firstUpdated() {
this.emojiPicker.on('emoji', selection => { this.changeTheme()
window.addEventListener('storage', () => {
const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
})
this.emojiPicker.on('emoji', selection => {
this.sendMessage({ this.sendMessage({
type: 'reaction', type: 'reaction',
editedMessageObj: toggledMessage, editedMessageObj: toggledMessage,
reaction: selection.emoji, reaction: selection.emoji,
}) })
}); })
this.viewElement = this.shadowRoot.getElementById('viewElement'); this.viewElement = this.shadowRoot.getElementById('viewElement')
this.upObserverElement = this.shadowRoot.getElementById('upObserver'); this.upObserverElement = this.shadowRoot.getElementById('upObserver')
this.downObserverElement = this.shadowRoot.getElementById('downObserver'); this.downObserverElement = this.shadowRoot.getElementById('downObserver')
// Intialize Observers // Intialize Observers
this.upElementObserver(); this.upElementObserver()
this.downElementObserver(); this.downElementObserver()
await this.getUpdateComplete(); await this.getUpdateComplete()
this.viewElement.scrollTop = this.viewElement.scrollHeight + 50; this.viewElement.scrollTop = this.viewElement.scrollHeight + 50
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
}
changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
} }
_getOldMessage(_scrollElement) { _getOldMessage(_scrollElement) {
@ -358,19 +401,19 @@ class ChatScroller extends LitElement {
if (this.messages.length < 20) { if (this.messages.length < 20) {
return return
} }
this.setIsLoadingMessages(true); this.setIsLoadingMessages(true)
let _scrollElement = entries[0].target.nextElementSibling; let _scrollElement = entries[0].target.nextElementSibling
this._getOldMessage(_scrollElement); this._getOldMessage(_scrollElement)
} }
} }
_downObserverHandler(entries) { _downObserverHandler(entries) {
if (!entries[0].isIntersecting) { if (!entries[0].isIntersecting) {
let _scrollElement = entries[0].target.previousElementSibling; let _scrollElement = entries[0].target.previousElementSibling
// this._getOldMessageAfter(_scrollElement); // this._getOldMessageAfter(_scrollElement)
this.showLastMessageRefScroller(true); this.showLastMessageRefScroller(true)
} else { } else {
this.showLastMessageRefScroller(false); this.showLastMessageRefScroller(false)
} }
} }
@ -379,9 +422,9 @@ class ChatScroller extends LitElement {
root: this.viewElement, root: this.viewElement,
rootMargin: '0px', rootMargin: '0px',
threshold: 1 threshold: 1
}; }
const observer = new IntersectionObserver(this._upObserverhandler, options); const observer = new IntersectionObserver(this._upObserverhandler, options)
observer.observe(this.upObserverElement); observer.observe(this.upObserverElement)
} }
downElementObserver() { downElementObserver() {
@ -391,12 +434,12 @@ class ChatScroller extends LitElement {
threshold: 1 threshold: 1
} }
// identify an element to observe // identify an element to observe
const elementToObserve = this.downObserverElement; const elementToObserve = this.downObserverElement
// passing it a callback function // passing it a callback function
const observer = new IntersectionObserver(this._downObserverHandler, options); const observer = new IntersectionObserver(this._downObserverHandler, options)
// call `observe()` on that MutationObserver instance, // call `observe()` on that MutationObserver instance,
// passing it the element to observe, and the options object // passing it the element to observe, and the options object
observer.observe(elementToObserve); observer.observe(elementToObserve)
} }
} }
@ -437,12 +480,12 @@ class MessageTemplate extends LitElement {
goToRepliedMessage: { attribute: false }, goToRepliedMessage: { attribute: false },
listSeenMessages: { type: Array }, listSeenMessages: { type: Array },
addSeenMessage: { attribute: false }, addSeenMessage: { attribute: false },
chatId: { type: String }, chatId: { type: String }
} }
} }
constructor() { constructor() {
super(); super()
this.messageObj = {} this.messageObj = {}
this.openDialogPrivateMessage = false this.openDialogPrivateMessage = false
this.openDialogBlockUser = false this.openDialogBlockUser = false
@ -461,7 +504,7 @@ class MessageTemplate extends LitElement {
} }
static get styles() { static get styles() {
return [chatStyles]; return [chatStyles]
} }
@ -485,26 +528,26 @@ class MessageTemplate extends LitElement {
showBlockIconFunc(bool) { showBlockIconFunc(bool) {
if (bool) { if (bool) {
this.showBlockAddressIcon = true; this.showBlockAddressIcon = true
} else { } else {
this.showBlockAddressIcon = false; this.showBlockAddressIcon = false
} }
} }
async downloadAttachment(attachment) { async downloadAttachment(attachment) {
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
try { try {
axios.get(`${nodeUrl}/arbitrary/QCHAT_ATTACHMENT/${attachment.name}/${attachment.identifier}?apiKey=${myNode.apiKey}`, { responseType: 'blob' }) axios.get(`${nodeUrl}/arbitrary/QCHAT_ATTACHMENT/${attachment.name}/${attachment.identifier}?apiKey=${myNode.apiKey}`, { responseType: 'blob' })
.then(response => { .then(response => {
let filename = attachment.attachmentName; let filename = attachment.attachmentName
let blob = new Blob([response.data], { type: "application/octet-stream" }); let blob = new Blob([response.data], { type: "application/octet-stream" })
this.saveFileToDisk(blob, filename); this.saveFileToDisk(blob, filename)
}) })
} catch (error) { } catch (error) {
console.error(error); console.error(error)
} }
} }
@ -533,31 +576,43 @@ class MessageTemplate extends LitElement {
this.viewImage = true this.viewImage = true
} }
const tooltips = this.shadowRoot.querySelectorAll('vaadin-tooltip'); const tooltips = this.shadowRoot.querySelectorAll('vaadin-tooltip')
tooltips.forEach(tooltip => { tooltips.forEach(tooltip => {
const overlay = tooltip.shadowRoot.querySelector('vaadin-tooltip-overlay'); const overlay = tooltip.shadowRoot.querySelector('vaadin-tooltip-overlay')
overlay.shadowRoot.getElementById("overlay").style.cssText = "background-color: transparent; box-shadow: rgb(50 50 93 / 25%) 0px 2px 5px -1px, rgb(0 0 0 / 30%) 0px 1px 3px -1px"; overlay.shadowRoot.getElementById("overlay").style.cssText = "background-color: transparent; box-shadow: rgb(50 50 93 / 25%) 0px 2px 5px -1px, rgb(0 0 0 / 30%) 0px 1px 3px -1px"
overlay.shadowRoot.getElementById('content').style.cssText = "background-color: var(--reactions-tooltip-bg); color: var(--chat-bubble-msg-color); text-align: center; padding: 20px 10px; border-radius: 8px; font-family: Roboto, sans-serif; letter-spacing: 0.3px; font-weight: 300; font-size: 13.5px; transition: all 0.3s ease-in-out;"; overlay.shadowRoot.getElementById('content').style.cssText = "background-color: var(--reactions-tooltip-bg); color: var(--chat-bubble-msg-color); text-align: center; padding: 20px 10px; border-radius: 8px; font-family: Roboto, sans-serif; letter-spacing: 0.3px; font-weight: 300; font-size: 13.5px; transition: all 0.3s ease-in-out;"
}); })
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
render() { render() {
const hidemsg = this.hideMessages; const hidemsg = this.hideMessages
let message = ""; let message = ""
let messageVersion2 = "" let messageVersion2 = ""
let messageVersion2WithLink = null let messageVersion2WithLink = null
let reactions = []; let reactions = []
let repliedToData = null; let repliedToData = null
let image = null; let image = null
let gif = null; let gif = null
let isImageDeleted = false; let isImageDeleted = false
let isAttachmentDeleted = false; let isAttachmentDeleted = false
let version = 0; let version = 0
let isForwarded = false let isForwarded = false
let isEdited = false let isEdited = false
let attachment = null; let attachment = null
try { try {
const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage); const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage)
if (+parsedMessageObj.version > 1 && parsedMessageObj.messageText) { if (+parsedMessageObj.version > 1 && parsedMessageObj.messageText) {
messageVersion2 = generateHTML(parsedMessageObj.messageText, [ messageVersion2 = generateHTML(parsedMessageObj.messageText, [
StarterKit, StarterKit,
@ -568,121 +623,122 @@ class MessageTemplate extends LitElement {
messageVersion2WithLink = processText(messageVersion2) messageVersion2WithLink = processText(messageVersion2)
} }
message = parsedMessageObj.messageText; message = parsedMessageObj.messageText
repliedToData = this.messageObj.repliedToData; repliedToData = this.messageObj.repliedToData
isImageDeleted = parsedMessageObj.isImageDeleted; isImageDeleted = parsedMessageObj.isImageDeleted
isAttachmentDeleted = parsedMessageObj.isAttachmentDeleted; isAttachmentDeleted = parsedMessageObj.isAttachmentDeleted
// reactions = parsedMessageObj.reactions || []; // reactions = parsedMessageObj.reactions || []
version = parsedMessageObj.version; version = parsedMessageObj.version
isForwarded = parsedMessageObj.type === 'forward'; isForwarded = parsedMessageObj.type === 'forward'
isEdited = parsedMessageObj.isEdited && true; isEdited = parsedMessageObj.isEdited && true
if (parsedMessageObj.attachments && Array.isArray(parsedMessageObj.attachments) && parsedMessageObj.attachments.length > 0) { if (parsedMessageObj.attachments && Array.isArray(parsedMessageObj.attachments) && parsedMessageObj.attachments.length > 0) {
attachment = parsedMessageObj.attachments[0]; attachment = parsedMessageObj.attachments[0]
} }
if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) { if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) {
image = parsedMessageObj.images[0]; image = parsedMessageObj.images[0]
} }
if (parsedMessageObj.gifs && Array.isArray(parsedMessageObj.gifs) && parsedMessageObj.gifs.length > 0) { if (parsedMessageObj.gifs && Array.isArray(parsedMessageObj.gifs) && parsedMessageObj.gifs.length > 0) {
gif = parsedMessageObj.gifs[0]; gif = parsedMessageObj.gifs[0]
} }
} catch (error) { } catch (error) {
message = this.messageObj.decodedMessage; message = this.messageObj.decodedMessage
} }
let avatarImg = ''; let avatarImg = ''
let imageHTML = ''; let imageHTML = ''
let imageHTMLDialog = ''; let imageHTMLDialog = ''
let imageUrl = ''; let imageUrl = ''
let gifHTML = ''; let gifHTML = ''
let gifHTMLDialog = ''; let gifHTMLDialog = ''
let gifUrl = ''; let gifUrl = ''
let nameMenu = ''; let nameMenu = ''
let levelFounder = ''; let levelFounder = ''
let hideit = hidemsg.includes(this.messageObj.sender); let hideit = hidemsg.includes(this.messageObj.sender)
let forwarded = '' let forwarded = ''
let edited = '' let edited = ''
levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>`; levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>`
if (this.messageObj.senderName) { if (this.messageObj.senderName) {
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.messageObj.senderName}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`; const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.messageObj.senderName}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`
avatarImg = html`<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`; avatarImg = html`<img src="${avatarUrl}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`
} else { } else {
avatarImg = html`<img src='/img/incognito.png' style="max-width:100%; max-height:100%;" onerror="this.onerror=null;" />` avatarImg = html`<img src='/img/incognito.png' style="max-width:100%; max-height:100%;" onerror="this.onerror=null;" />`
} }
const createImage = (imageUrl) => { const createImage = (imageUrl) => {
const imageHTMLRes = new Image(); const imageHTMLRes = new Image()
imageHTMLRes.src = imageUrl; imageHTMLRes.src = imageUrl
imageHTMLRes.style = "max-width:45vh; max-height:40vh; border-radius: 5px; cursor: pointer"; imageHTMLRes.style = "max-width:45vh; max-height:40vh; border-radius: 5px; cursor: pointer;"
imageHTMLRes.onclick = () => { imageHTMLRes.onclick = () => {
this.openDialogImage = true; this.openDialogImage = true
} }
imageHTMLRes.onload = () => { imageHTMLRes.onload = () => {
this.isImageLoaded = true; this.isImageLoaded = true
} }
imageHTMLRes.onerror = () => { imageHTMLRes.onerror = () => {
if (this.imageFetches < 4) { if (this.imageFetches < 4) {
setTimeout(() => { setTimeout(() => {
this.imageFetches = this.imageFetches + 1; this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl; imageHTMLRes.src = imageUrl
}, 2000); }, 10000)
} else { } else {
setTimeout(() => { setTimeout(() => {
this.imageFetches = this.imageFetches + 1; this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl; imageHTMLRes.src = imageUrl
}, 6000); }, 15000)
} }
}; }
return imageHTMLRes; return imageHTMLRes
} }
const createGif = (gif) => { const createGif = (gif) => {
const gifHTMLRes = new Image(); const gifHTMLRes = new Image()
gifHTMLRes.src = gif; gifHTMLRes.src = gif
gifHTMLRes.style = "max-width:45vh; max-height:40vh; border-radius: 5px; cursor: pointer"; gifHTMLRes.style = "max-width:45vh; max-height:40vh; border-radius: 5px; cursor: pointer;"
gifHTMLRes.onclick = () => { gifHTMLRes.onclick = () => {
this.openDialogGif = true; this.openDialogGif = true
} }
gifHTMLRes.onload = () => { gifHTMLRes.onload = () => {
this.isGifLoaded = true; this.isGifLoaded = true
} }
gifHTMLRes.onerror = () => { gifHTMLRes.onerror = () => {
if (this.gifFetches < 4) { if (this.gifFetches < 4) {
setTimeout(() => { setTimeout(() => {
this.gifFetches = this.gifFetches + 1; this.gifFetches = this.gifFetches + 1
gifHTMLRes.src = gif; gifHTMLRes.src = gif
}, 500); }, 10000)
} else { } else {
gifHTMLRes.src = '/img/chain.png'; gifHTMLRes.src = '/img/chain.png'
gifHTMLRes.style = "max-width:45vh; max-height:20vh; border-radius: 5px; filter: opacity(0.5)"; gifHTMLRes.style = "max-width:45vh; max-height:20vh; border-radius: 5px; filter: opacity(0.5);"
gifHTMLRes.onclick = () => { } gifHTMLRes.onclick = () => { }
this.isGifLoaded = true this.isGifLoaded = true
} }
}; }
return gifHTMLRes; return gifHTMLRes
} }
if (image) { if (image) {
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
imageUrl = `${nodeUrl}/arbitrary/${image.service}/${image.name}/${image.identifier}?async=true&apiKey=${myNode.apiKey}`; imageUrl = `${nodeUrl}/arbitrary/${image.service}/${image.name}/${image.identifier}?async=true&apiKey=${myNode.apiKey}`
if (this.viewImage || this.myAddress === this.messageObj.sender) { if (this.viewImage || this.myAddress === this.messageObj.sender) {
imageHTML = createImage(imageUrl); imageHTML = createImage(imageUrl)
imageHTMLDialog = createImage(imageUrl) imageHTMLDialog = createImage(imageUrl)
imageHTMLDialog.style = "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px"; imageHTMLDialog.style = "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px;"
} }
} }
if (gif) { if (gif) {
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
gifUrl = `${nodeUrl}/arbitrary/${gif.service}/${gif.name}/${gif.identifier}?filepath=${gif.filePath}&apiKey=${myNode.apiKey}`; gifUrl = `${nodeUrl}/arbitrary/${gif.service}/${gif.name}/${gif.identifier}?filepath=${gif.filePath}&apiKey=${myNode.apiKey}`
if (this.viewImage || this.myAddress === this.messageObj.sender) { if (this.viewImage || this.myAddress === this.messageObj.sender) {
gifHTML = createGif(gifUrl); gifHTML = createGif(gifUrl)
gifHTMLDialog = createGif(gifUrl) gifHTMLDialog = createGif(gifUrl)
gifHTMLDialog.style = "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px"; gifHTMLDialog.style = "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px;"
} }
} }
@ -690,27 +746,29 @@ class MessageTemplate extends LitElement {
<span class="${this.messageObj.sender === this.myAddress && 'message-data-my-name'}"> <span class="${this.messageObj.sender === this.myAddress && 'message-data-my-name'}">
${this.messageObj.senderName ? this.messageObj.senderName : cropAddress(this.messageObj.sender)} ${this.messageObj.senderName ? this.messageObj.senderName : cropAddress(this.messageObj.sender)}
</span> </span>
`; `
forwarded = html` forwarded = html`
<span class="${this.messageObj.sender === this.myAddress && 'message-data-forward'}"> <span class="${this.messageObj.sender === this.myAddress && 'message-data-forward'}">
${translate("blockpage.bcchange17")} ${translate("blockpage.bcchange17")}
</span> </span>
`; `
edited = html` edited = html`
<span class="edited-message-style"> <span class="edited-message-style">
${translate("chatpage.cchange68")} ${translate("chatpage.cchange68")}
</span> </span>
`; `
if (repliedToData) { if (repliedToData) {
try { try {
const parsedMsg = JSON.parse(repliedToData.decodedMessage); const parsedMsg = JSON.parse(repliedToData.decodedMessage)
repliedToData.decodedMessage = parsedMsg; repliedToData.decodedMessage = parsedMsg
} catch (error) { } catch (error) {
} }
} }
let repliedToMessageText = '' let repliedToMessageText = ''
if (repliedToData && repliedToData.decodedMessage && repliedToData.decodedMessage.messageText) { if (repliedToData && repliedToData.decodedMessage && repliedToData.decodedMessage.messageText) {
try { try {
@ -724,16 +782,16 @@ class MessageTemplate extends LitElement {
} }
} }
let replacedMessage = '' let replacedMessage = ''
if (message && +version < 2) { if (message && +version < 2) {
const escapedMessage = this.escapeHTML(message) const escapedMessage = this.escapeHTML(message)
if (escapedMessage) { if (escapedMessage) {
replacedMessage = escapedMessage.replace(new RegExp('\r?\n', 'g'), '<br />'); replacedMessage = escapedMessage.replace(new RegExp('\r?\n', 'g'), '<br />')
} }
} }
return hideit ? html`<li class="clearfix"></li>` : html` return hideit ? html`<li class="clearfix"></li>` : html`
<li <li
class="clearfix message-parent" class="clearfix message-parent"
@ -753,9 +811,9 @@ class MessageTemplate extends LitElement {
<div <div
style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"} style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"}
@click=${() => { @click=${() => {
if (this.myAddress === this.messageObj.sender) return; if (this.myAddress === this.messageObj.sender) return
this.setOpenUserInfo(true); this.setOpenUserInfo(true)
this.setUserName(this.messageObj); this.setUserName(this.messageObj)
}} class="message-data-avatar"> }} class="message-data-avatar">
${avatarImg} ${avatarImg}
</div> </div>
@ -789,9 +847,9 @@ class MessageTemplate extends LitElement {
<span <span
style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"} style=${this.myAddress === this.messageObj.sender ? "cursor: auto;" : "cursor: pointer;"}
@click=${() => { @click=${() => {
if (this.myAddress === this.messageObj.sender) return; if (this.myAddress === this.messageObj.sender) return
this.setOpenUserInfo(true); this.setOpenUserInfo(true)
this.setUserName(this.messageObj); this.setUserName(this.messageObj)
}} }}
class="message-data-name"> class="message-data-name">
${nameMenu} ${nameMenu}
@ -844,13 +902,13 @@ class MessageTemplate extends LitElement {
}} }}
class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')} class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')}
style=${this.isFirstMessage && "margin-top: 10px;"}> style=${this.isFirstMessage && "margin-top: 10px;"}>
<div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;cursor:pointer;color:var(--black)"> <div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;cursor:pointer;color:var(--black);">
${translate("chatpage.cchange40")} ${translate("chatpage.cchange40")}
</div> </div>
</div> </div>
` : html``} ` : html``}
${!this.isImageLoaded && image && this.viewImage ? html` ${!this.isImageLoaded && image && this.viewImage ? html`
<div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;position:absolute"> <div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;position:absolute;">
<div class=${`smallLoading`}></div> <div class=${`smallLoading`}></div>
</div> </div>
@ -863,7 +921,7 @@ class MessageTemplate extends LitElement {
${this.myAddress === this.messageObj.sender ? html` ${this.myAddress === this.messageObj.sender ? html`
<vaadin-icon <vaadin-icon
@click=${() => { @click=${() => {
this.openDeleteImage = true; this.openDeleteImage = true
}} }}
class="image-delete-icon" icon="vaadin:close" slot="icon"></vaadin-icon> class="image-delete-icon" icon="vaadin:close" slot="icon"></vaadin-icon>
` : ''} ` : ''}
@ -879,7 +937,7 @@ class MessageTemplate extends LitElement {
}} }}
class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')} class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')}
style=${this.isFirstMessage && "margin-top: 10px;"}> style=${this.isFirstMessage && "margin-top: 10px;"}>
<div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;cursor:pointer;color:var(--black)"> <div style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;cursor:pointer;color:var(--black);">
${translate("gifs.gchange25")} ${translate("gifs.gchange25")}
</div> </div>
</div> </div>
@ -917,8 +975,8 @@ class MessageTemplate extends LitElement {
? html` ? html`
<vaadin-icon <vaadin-icon
@click=${(e) => { @click=${(e) => {
e.stopPropagation(); e.stopPropagation()
this.openDeleteAttachment = true; this.openDeleteAttachment = true
}} }}
class="image-delete-icon" icon="vaadin:close" slot="icon"> class="image-delete-icon" icon="vaadin:close" slot="icon">
</vaadin-icon> </vaadin-icon>
@ -1128,7 +1186,7 @@ class MessageTemplate extends LitElement {
hideActions hideActions
?open=${this.openDeleteImage} ?open=${this.openDeleteImage}
@closed=${() => { @closed=${() => {
this.openDeleteImage = false; this.openDeleteImage = false
}}> }}>
<div class="delete-image-msg"> <div class="delete-image-msg">
<p>${translate("chatpage.cchange78")}</p> <p>${translate("chatpage.cchange78")}</p>
@ -1153,7 +1211,7 @@ class MessageTemplate extends LitElement {
hideActions hideActions
?open=${this.openDeleteAttachment} ?open=${this.openDeleteAttachment}
@closed=${() => { @closed=${() => {
this.openDeleteAttachment = false; this.openDeleteAttachment = false
}}> }}>
<div class="delete-image-msg"> <div class="delete-image-msg">
<p>${translate("chatpage.cchange79")}</p> <p>${translate("chatpage.cchange79")}</p>
@ -1182,7 +1240,7 @@ class MessageTemplate extends LitElement {
} }
} }
window.customElements.define('message-template', MessageTemplate); window.customElements.define('message-template', MessageTemplate)
class ChatMenu extends LitElement { class ChatMenu extends LitElement {
static get properties() { static get properties() {
@ -1207,18 +1265,18 @@ class ChatMenu extends LitElement {
setOpenPrivateMessage: { attribute: false }, setOpenPrivateMessage: { attribute: false },
setOpenTipUser: { attribute: false }, setOpenTipUser: { attribute: false },
setUserName: { attribute: false }, setUserName: { attribute: false },
gif: { type: Boolean }, gif: { type: Boolean }
} }
} }
constructor() { constructor() {
super(); super()
this.showPrivateMessageModal = () => { }; this.showPrivateMessageModal = () => { }
this.showBlockUserModal = () => { }; this.showBlockUserModal = () => { }
} }
static get styles() { static get styles() {
return [chatStyles]; return [chatStyles]
} }
// Copy address to clipboard // Copy address to clipboard
@ -1246,7 +1304,7 @@ class ChatMenu extends LitElement {
key: '' key: ''
} }
try { try {
parsedMessageObj = JSON.parse(this.originalMessage.decodedMessage); parsedMessageObj = JSON.parse(this.originalMessage.decodedMessage)
} catch (error) { } catch (error) {
parsedMessageObj = {} parsedMessageObj = {}
@ -1335,7 +1393,7 @@ class ChatMenu extends LitElement {
this.versionErrorSnack() this.versionErrorSnack()
return return
} }
this.setRepliedToMessageObj({ ...this.originalMessage, version: this.version }); this.setRepliedToMessageObj({ ...this.originalMessage, version: this.version })
}}"> }}">
<vaadin-icon icon="vaadin:reply" slot="icon"></vaadin-icon> <vaadin-icon icon="vaadin:reply" slot="icon"></vaadin-icon>
</div> </div>
@ -1351,7 +1409,7 @@ class ChatMenu extends LitElement {
this.versionErrorSnack() this.versionErrorSnack()
return return
} }
this.setEditedMessageObj(this.originalMessage); this.setEditedMessageObj(this.originalMessage)
}}> }}>
<vaadin-icon icon="vaadin:pencil" slot="icon"></vaadin-icon> <vaadin-icon icon="vaadin:pencil" slot="icon"></vaadin-icon>
</div> </div>
@ -1363,9 +1421,9 @@ class ChatMenu extends LitElement {
class=${`menu-icon ${!this.firstMessageInChat ? "tooltip" : ""}`} class=${`menu-icon ${!this.firstMessageInChat ? "tooltip" : ""}`}
data-text="${translate("blockpage.bcchange18")}" data-text="${translate("blockpage.bcchange18")}"
@click=${(e) => { @click=${(e) => {
e.preventDefault(); e.preventDefault()
this.setUserName(this.originalMessage); this.setUserName(this.originalMessage)
this.setOpenTipUser(true); this.setOpenTipUser(true)
}}> }}>
<vaadin-icon icon="vaadin:dollar" slot="icon"></vaadin-icon> <vaadin-icon icon="vaadin:dollar" slot="icon"></vaadin-icon>
</div> </div>

View File

@ -0,0 +1,72 @@
import { LitElement, html } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js'
import { chatSearchResultsStyles } from './ChatSearchResults-css.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@vaadin/icon'
import '@vaadin/icons'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
export class ChatSearchResults extends LitElement {
static get properties() {
return {
onClickFunc: { attribute: false },
closeFunc: { attribute: false },
searchResults: { type: Array },
isOpen: { type: Boolean },
loading: { type: Boolean }
}
}
static styles = [chatSearchResultsStyles]
render() {
return html`
<div class="chat-results-card" style=${this.isOpen ? "display: block;" : "display: none;"}>
<vaadin-icon
@click=${() => this.closeFunc()}
icon="vaadin:close-small"
slot="icon"
class="close-icon"
>
</vaadin-icon>
${this.loading ? (
html`
<div class="spinner-container">
<paper-spinner-lite active></paper-spinner-lite>
</div>
`
) : (
html`
<p class="chat-result-header">${translate("chatpage.cchange36")}</p>
<div class="divider"></div>
<div class="chat-result-container">
${this.searchResults.length === 0 ? (
html`<p class="no-results">${translate("chatpage.cchange37")}</p>`
) : (
html`
${this.searchResults.map((result) => {
return (
html`
<div class="chat-result-card" @click=${() => {
this.shadowRoot.querySelector(".chat-result-card").classList.add("active");
this.onClickFunc(result);
}}>
<p class="chat-result">
${result.name}
</p>
</div>
`
)}
)}
`
)}
</div>
`
)}
</div>
`
}
}
customElements.define('chat-search-results', ChatSearchResults)

View File

@ -1,4 +1,5 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import '@material/mwc-icon' import '@material/mwc-icon'

View File

@ -1,6 +1,7 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@material/mwc-icon' import '@material/mwc-icon'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -176,7 +177,7 @@ class ChatSideNavHeads extends LitElement {
this.config = JSON.parse(c) this.config = JSON.parse(c)
}) })
}) })
parentEpml.imReady(); parentEpml.imReady()
} }
shouldUpdate(changedProperties) { shouldUpdate(changedProperties) {

View File

@ -1,11 +1,12 @@
import { LitElement, html, css } from "lit"; import { LitElement, html, css } from "lit"
import { get } from 'lit-translate'; import { escape, unescape } from 'html-escaper'
import { escape, unescape } from 'html-escaper'; import { EmojiPicker } from 'emoji-picker-js'
import { EmojiPicker } from 'emoji-picker-js'; import { inputKeyCodes } from '../../utils/keyCodes.js'
import { inputKeyCodes } from '../../utils/keyCodes.js'; import { Epml } from '../../../epml.js'
import { Epml } from '../../../epml.js'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class ChatTextEditor extends LitElement { class ChatTextEditor extends LitElement {
static get properties() { static get properties() {
return { return {
@ -298,13 +299,13 @@ class ChatTextEditor extends LitElement {
} }
window.addEventListener('storage', () => { window.addEventListener('storage', () => {
const checkTheme = localStorage.getItem('qortalTheme'); const checkTheme = localStorage.getItem('qortalTheme')
const chatbar = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('chatbarId'); const chatbar = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('chatbarId')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
chatbar.style.cssText = "color:#ffffff;" chatbar.style.cssText = "color:#ffffff;"
} else { } else {
this.theme = 'light'; this.theme = 'light'
chatbar.style.cssText = "color:#080808;" chatbar.style.cssText = "color:#080808;"
} }
}) })
@ -323,18 +324,18 @@ class ChatTextEditor extends LitElement {
boxShadow: 'rgba(4, 4, 5, 0.15) 0px 0px 0px 1px, rgba(0, 0, 0, 0.24) 0px 8px 16px 0px', boxShadow: 'rgba(4, 4, 5, 0.15) 0px 0px 0px 1px, rgba(0, 0, 0, 0.24) 0px 8px 16px 0px',
zIndex: 100 zIndex: 100
}); })
this.emojiPicker.on('emoji', selection => { this.emojiPicker.on('emoji', selection => {
const emojiHtmlString = `<img class="emoji" draggable="false" alt="${selection.emoji}" src="${selection.url}">`; const emojiHtmlString = `<img class="emoji" draggable="false" alt="${selection.emoji}" src="${selection.url}">`
this.chatEditor.insertEmoji(emojiHtmlString); this.chatEditor.insertEmoji(emojiHtmlString);
}); })
this.emojiPickerHandler.addEventListener('click', () => this.emojiPicker.togglePicker(this.emojiPickerHandler)); this.emojiPickerHandler.addEventListener('click', () => this.emojiPicker.togglePicker(this.emojiPickerHandler))
await this.updateComplete; await this.updateComplete
this.initChatEditor(); this.initChatEditor()
} }
async updated(changedProperties) { async updated(changedProperties) {
@ -348,12 +349,12 @@ class ChatTextEditor extends LitElement {
} }
} }
if (changedProperties && changedProperties.has('placeholder')) { if (changedProperties && changedProperties.has('placeholder')) {
const captionEditor = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('chatbarId'); const captionEditor = this.shadowRoot.getElementById(this.iframeId).contentWindow.document.getElementById('chatbarId')
captionEditor.setAttribute('data-placeholder', this.placeholder); captionEditor.setAttribute('data-placeholder', this.placeholder)
} }
if (changedProperties && changedProperties.has("imageFile")) { if (changedProperties && changedProperties.has("imageFile")) {
this.chatMessageInput = "newChat"; this.chatMessageInput = "newChat"
} }
} }
@ -365,12 +366,12 @@ class ChatTextEditor extends LitElement {
sendMessageFunc(props) { sendMessageFunc(props) {
if (this.chatMessageSize > 1000 ) { if (this.chatMessageSize > 1000 ) {
parentEpml.request('showSnackBar', get("chatpage.cchange29")); parentEpml.request('showSnackBar', get("chatpage.cchange29"))
return; return
}; };
this.chatMessageSize = 0; this.chatMessageSize = 0
this.chatEditor.updateMirror(); this.chatEditor.updateMirror()
this._sendMessage(props); this._sendMessage(props)
} }
getMessageSize(message){ getMessageSize(message){

View File

@ -1,13 +1,13 @@
import { LitElement, html, css } from "lit"; import { LitElement, html, css } from "lit";
import { get, translate } from 'lit-translate'; import { render } from 'lit/html.js'
import { EmojiPicker } from 'emoji-picker-js'
import { EmojiPicker } from 'emoji-picker-js'; import { Epml } from '../../../epml.js'
import { Epml } from '../../../epml.js';
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-checkbox' import '@material/mwc-checkbox'
// import { addAutoLoadImageChat } from "../../../../qortal-ui-core/src/redux/app/app-actions.js"; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class ChatTextEditor extends LitElement { class ChatTextEditor extends LitElement {
static get properties() { static get properties() {
return { return {
@ -589,11 +589,11 @@ mwc-checkbox::shadow .mdc-checkbox::after, mwc-checkbox::shadow .mdc-checkbox::b
const checkTheme = localStorage.getItem('qortalTheme'); const checkTheme = localStorage.getItem('qortalTheme');
const chatbar = this.shadowRoot.querySelector('.element') const chatbar = this.shadowRoot.querySelector('.element')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
chatbar.style.cssText = "color:#ffffff;" chatbar.style.cssText = "color:#ffffff;"
} else { } else {
this.theme = 'light'; this.theme = 'light'
chatbar.style.cssText = "color:#080808;" chatbar.style.cssText = "color:#080808;"
} }

View File

@ -2,10 +2,7 @@ import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import isElectron from 'is-electron'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '@material/mwc-icon' import '@material/mwc-icon'
import '@material/mwc-button' import '@material/mwc-button'
@ -13,6 +10,10 @@ import '@material/mwc-dialog'
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/grid' import '@vaadin/grid'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatWelcomePage extends LitElement { class ChatWelcomePage extends LitElement {
@ -258,10 +259,16 @@ class ChatWelcomePage extends LitElement {
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
const stopKeyEventPropagation = (e) => { const stopKeyEventPropagation = (e) => {
e.stopPropagation(); e.stopPropagation()
return false; return false
} }
this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation); this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation);
@ -290,8 +297,6 @@ class ChatWelcomePage extends LitElement {
document.querySelector('html').setAttribute('theme', this.theme) document.querySelector('html').setAttribute('theme', this.theme)
}) })
let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {} this.selectedAddress = {}
@ -309,19 +314,26 @@ class ChatWelcomePage extends LitElement {
parentEpml.imReady() parentEpml.imReady()
} }
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
}
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
} else { } else {
this.theme = 'light'; this.theme = 'light'
} }
document.querySelector('html').setAttribute('theme', this.theme); document.querySelector('html').setAttribute('theme', this.theme)
} }
changeLanguage() { changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage') const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) { if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us') localStorage.setItem('qortalLanguage', 'us')
use('us') use('us')
@ -343,7 +355,7 @@ class ChatWelcomePage extends LitElement {
} else { } else {
this.sendMessage(); this.sendMessage();
} }
}; }
async sendMessage() { async sendMessage() {
this.isLoading = true; this.isLoading = true;

View File

@ -1,6 +1,6 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { translate, get } from 'lit-translate'; import { render } from 'lit/html.js'
import { render } from 'lit/html.js'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
export class ImageComponent extends LitElement { export class ImageComponent extends LitElement {
@ -48,52 +48,51 @@ border: 1px solid var(--mdc-theme-primary );
} }
constructor() { constructor() {
super(); super()
this.attempts = 0; this.attempts = 0
this.maxAttempts = 5; this.maxAttempts = 5
} }
getApiKey() { 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
return apiKey; return apiKey
} }
async _fetchImage() { async _fetchImage() {
this.attempts++; this.attempts++;
if (this.attempts > this.maxAttempts) return; if (this.attempts > this.maxAttempts) return
await new Promise((res) => { await new Promise((res) => {
setTimeout(() => { setTimeout(() => {
res(); res()
}, 1000) }, 1000)
}); })
try { try {
const response = await fetch(this.gif.url); const response = await fetch(this.gif.url)
const data = await response.json(); const data = await response.json()
console.log({data});
if (data.ok) { if (data.ok) {
this.error = false; this.error = false
this.gif = { this.gif = {
...this.gif, ...this.gif,
url: data.src url: data.src
}; };
this.requestUpdate(); this.requestUpdate();
} else if (!data.ok || data.error) { } else if (!data.ok || data.error) {
this.error = true; this.error = true
} else { } else {
this.error = false; this.error = false
} }
} catch (error) { } catch (error) {
this.error = true; this.error = true
console.error(error); console.error(error)
this._fetchImage(); this._fetchImage()
} }
} }
render() { render() {
if (this.error && this.attempts <= this.maxAttempts) { if (this.error && this.attempts <= this.maxAttempts) {
setTimeout(() => { setTimeout(() => {
this._fetchImage(); this._fetchImage()
}, 1000); }, 1000)
} }
return html` return html`
${this.gif && !this.error ${this.gif && !this.error
@ -124,4 +123,4 @@ alt=${this.alt}
} }
} }
customElements.define('image-component', ImageComponent); customElements.define('image-component', ImageComponent)

View File

@ -3,11 +3,6 @@ import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '@polymer/paper-tooltip/paper-tooltip.js' import '@polymer/paper-tooltip/paper-tooltip.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
@ -15,8 +10,8 @@ const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class LevelFounder extends LitElement { class LevelFounder extends LitElement {
static get properties() { static get properties() {
return { return {
checkleveladdress: { type: String, attribute: true }, checkleveladdress: { type: String },
selectedAddress: { type: Object }, selectedAddress: { type: String },
config: { type: Object }, config: { type: Object },
memberInfo: { type: Array } memberInfo: { type: Array }
} }
@ -106,16 +101,8 @@ class LevelFounder extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeLanguage()
this.checkAddressInfo() this.checkAddressInfo()
window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage')
use(checkLanguage)
})
let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => { parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {} this.selectedAddress = {}
@ -127,17 +114,6 @@ class LevelFounder extends LitElement {
parentEpml.imReady() parentEpml.imReady()
} }
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
}
}
async checkAddressInfo() { async checkAddressInfo() {
let toCheck = this.checkleveladdress let toCheck = this.checkleveladdress
const memberInfo = await parentEpml.request('apiCall', { const memberInfo = await parentEpml.request('apiCall', {
@ -147,23 +123,23 @@ class LevelFounder extends LitElement {
} }
renderFounder() { renderFounder() {
let adressfounder = this.memberInfo.flags; let adressfounder = this.memberInfo.flags
if (adressfounder === 1) { if (adressfounder === 1) {
return html ` return html `
<span id="founderTooltip" class="badge">F</span> <span id="founderTooltip" class="badge">F</span>
<paper-tooltip class="custom" for="founderTooltip" position="top">FOUNDER</paper-tooltip> <paper-tooltip class="custom" for="founderTooltip" position="top">FOUNDER</paper-tooltip>
` `
} else { } else {
return null; return html ``
} }
} }
renderLevel() { renderLevel() {
let adresslevel = this.memberInfo.level; let adresslevel = this.memberInfo.level
return adresslevel ? html ` return adresslevel ? html `
<img id="level-img" src=${`/img/badges/level-${adresslevel}.png`} alt=${`badge-${adresslevel}`} class="message-data-level" /> <img id="level-img" src=${`/img/badges/level-${adresslevel}.png`} alt=${`badge-${adresslevel}`} class="message-data-level" />
<paper-tooltip class="level-img-tooltip" for="level-img" position="top" > <paper-tooltip class="level-img-tooltip" for="level-img" position="top" >
${translate("mintingpage.mchange27")} ${adresslevel} ${translate("mintingpage.mchange27")} ${adresslevel}
</paper-tooltip> </paper-tooltip>
` : '' ` : ''
} }
@ -174,9 +150,9 @@ class LevelFounder extends LitElement {
} }
getApiKey() { 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
return apiKey; return apiKey
} }
} }

View File

@ -3,11 +3,6 @@ import { render } from 'lit/html.js'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import snackbar from './snackbar.js' import snackbar from './snackbar.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '@material/mwc-snackbar' import '@material/mwc-snackbar'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-dialog' import '@material/mwc-dialog'
@ -250,17 +245,12 @@ class NameMenu extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.getChatBlockedAdresses(); this.getChatBlockedAdresses()
setInterval(() => { setInterval(() => {
this.getChatBlockedAdresses(); this.getChatBlockedAdresses()
}, 60000) }, 60000)
window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage');
use(checkLanguage);
})
window.onclick = function(event) { window.onclick = function(event) {
if (!event.target.matches('.block')) { if (!event.target.matches('.block')) {
var dropdowns = document.getElementsByClassName('dropdown-content'); var dropdowns = document.getElementsByClassName('dropdown-content');
@ -275,12 +265,12 @@ class NameMenu extends LitElement {
} }
const stopKeyEventPropagation = (e) => { const stopKeyEventPropagation = (e) => {
e.stopPropagation(); e.stopPropagation()
return false; return false
} }
this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation); this.shadowRoot.getElementById('sendTo').addEventListener('keydown', stopKeyEventPropagation)
this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation); this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation)
const getDataFromURL = () => { const getDataFromURL = () => {
let tempUrl = document.location.href let tempUrl = document.location.href
@ -309,17 +299,6 @@ class NameMenu extends LitElement {
parentEpml.imReady() parentEpml.imReady()
} }
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
}
}
myMenu() { myMenu() {
this.shadowRoot.getElementById('myDropdown').classList.toggle('showList') this.shadowRoot.getElementById('myDropdown').classList.toggle('showList')
this.shadowRoot.querySelector('#blockNameDialog').close() this.shadowRoot.querySelector('#blockNameDialog').close()

View File

@ -24,11 +24,11 @@ class TimeAgo extends LitElement {
} }
}); });
this.shadowRoot.querySelector('time-ago').setAttribute('title', ''); this.shadowRoot.querySelector('time-ago').setAttribute('title', '')
} }
constructor() { constructor() {
super(); super()
this.timestamp = 0 this.timestamp = 0
this.timeIso = '' this.timeIso = ''
this.format = '' this.format = ''
@ -41,7 +41,7 @@ class TimeAgo extends LitElement {
} }
renderTime(timestamp) { renderTime(timestamp) {
timestamp === undefined ? this.timeIso = '' : this.timeIso = new Date(timestamp).toISOString(); timestamp === undefined ? this.timeIso = '' : this.timeIso = new Date(timestamp).toISOString()
} }
firstUpdated() { firstUpdated() {

View File

@ -1,10 +1,10 @@
import { LitElement, html } from 'lit'; import { LitElement, html } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { get, translate } from 'lit-translate'; import { tipUserStyles } from './TipUser-css.js'
import { tipUserStyles } from './TipUser-css.js'; import { Epml } from '../../../epml'
import { Epml } from '../../../epml'; import '@vaadin/button'
import '@vaadin/button'; import '@polymer/paper-progress/paper-progress.js'
import '@polymer/paper-progress/paper-progress.js'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: "WINDOW", source: window.parent }); const parentEpml = new Epml({ type: "WINDOW", source: window.parent });
@ -34,15 +34,15 @@ export class TipUser extends LitElement {
static styles = [tipUserStyles] static styles = [tipUserStyles]
async firstUpdated() { async firstUpdated() {
await this.fetchWalletDetails(); await this.fetchWalletDetails()
} }
updated(changedProperties) { updated(changedProperties) {
if (changedProperties && changedProperties.has("closeTipUser")) { if (changedProperties && changedProperties.has("closeTipUser")) {
if (this.closeTipUser) { if (this.closeTipUser) {
this.shadowRoot.getElementById("amountInput").value = ""; this.shadowRoot.getElementById("amountInput").value = ""
this.errorMessage = ""; this.errorMessage = ""
this.successMessage = ""; this.successMessage = ""
} }
} }
} }
@ -52,7 +52,7 @@ export class TipUser extends LitElement {
type: "api", type: "api",
url: `/addresses/lastreference/${this.myAddress.address}`, url: `/addresses/lastreference/${this.myAddress.address}`,
}) })
return myRef; return myRef
} }
renderSuccessText() { renderSuccessText() {
@ -64,9 +64,9 @@ export class TipUser extends LitElement {
} }
getApiKey() { 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
return apiKey; return apiKey
} }
async fetchWalletDetails() { async fetchWalletDetails() {
@ -78,85 +78,85 @@ export class TipUser extends LitElement {
let snack4string = get("chatpage.cchange48") let snack4string = get("chatpage.cchange48")
parentEpml.request('showSnackBar', `${snack4string}`) parentEpml.request('showSnackBar', `${snack4string}`)
} else { } else {
this.walletBalance = Number(res).toFixed(8); this.walletBalance = Number(res).toFixed(8)
} }
}) })
} }
async sendQort() { async sendQort() {
const amount = this.shadowRoot.getElementById("amountInput").value; const amount = this.shadowRoot.getElementById("amountInput").value
let recipient = this.userName; let recipient = this.userName
this.sendMoneyLoading = true; this.sendMoneyLoading = true
this.btnDisable = true; this.btnDisable = true
if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) { if (parseFloat(amount) + parseFloat(0.001) > parseFloat(this.walletBalance)) {
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
let snack1string = get("chatpage.cchange51"); let snack1string = get("chatpage.cchange51")
parentEpml.request('showSnackBar', `${snack1string}`); parentEpml.request('showSnackBar', `${snack1string}`)
return false; return false
} }
if (parseFloat(amount) <= 0) { if (parseFloat(amount) <= 0) {
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
let snack2string = get("chatpage.cchange52"); let snack2string = get("chatpage.cchange52")
parentEpml.request('showSnackBar', `${snack2string}`); parentEpml.request('showSnackBar', `${snack2string}`)
return false; return false
} }
if (recipient.length === 0) { if (recipient.length === 0) {
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
let snack3string = get("chatpage.cchange53"); let snack3string = get("chatpage.cchange53")
parentEpml.request('showSnackBar', `${snack3string}`); parentEpml.request('showSnackBar', `${snack3string}`)
return false; return false
} }
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let myRes; let myRes
let myNameRes = await parentEpml.request('apiCall', { let myNameRes = await parentEpml.request('apiCall', {
type: 'api', type: 'api',
url: `/names/${receiverName}`, url: `/names/${receiverName}`,
}) })
if (myNameRes.error === 401) { if (myNameRes.error === 401) {
myRes = false; myRes = false
} else { } else {
myRes = myNameRes; myRes = myNameRes
} }
return myRes; return myRes;
} }
const validateAddress = async (receiverAddress) => { const validateAddress = async (receiverAddress) => {
let myAddress = await window.parent.validateAddress(receiverAddress); let myAddress = await window.parent.validateAddress(receiverAddress)
return myAddress; return myAddress
} }
const validateReceiver = async (recipient) => { const validateReceiver = async (recipient) => {
let lastRef = await this.getLastRef(); let lastRef = await this.getLastRef()
let isAddress; let isAddress
try { try {
isAddress = await validateAddress(recipient); isAddress = await validateAddress(recipient)
} catch (err) { } catch (err) {
isAddress = false; isAddress = false
} }
if (isAddress) { if (isAddress) {
let myTransaction = await makeTransactionRequest(recipient, lastRef); let myTransaction = await makeTransactionRequest(recipient, lastRef)
getTxnRequestResponse(myTransaction); getTxnRequestResponse(myTransaction)
} else { } else {
let myNameRes = await validateName(recipient); let myNameRes = await validateName(recipient)
if (myNameRes !== false) { if (myNameRes !== false) {
let myNameAddress = myNameRes.owner let myNameAddress = myNameRes.owner
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef) let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
getTxnRequestResponse(myTransaction) getTxnRequestResponse(myTransaction)
} else { } else {
console.error(this.renderReceiverText()) console.error(this.renderReceiverText())
this.errorMessage = this.renderReceiverText(); this.errorMessage = this.renderReceiverText()
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
} }
} }
} }
@ -169,23 +169,23 @@ export class TipUser extends LitElement {
}); });
if (getNames?.length > 0 ) { if (getNames?.length > 0 ) {
return getNames[0].name; return getNames[0].name
} else { } else {
return ''; return ''
} }
} catch (error) { } catch (error) {
return ""; return ""
} }
} }
const makeTransactionRequest = async (receiver, lastRef) => { const makeTransactionRequest = async (receiver, lastRef) => {
let myReceiver = receiver; let myReceiver = receiver
let mylastRef = lastRef; let mylastRef = lastRef
let dialogamount = get("transactions.amount"); let dialogamount = get("transactions.amount")
let dialogAddress = get("login.address"); let dialogAddress = get("login.address")
let dialogName = get("login.name"); let dialogName = get("login.name")
let dialogto = get("transactions.to"); let dialogto = get("transactions.to")
let recipientName = await getName(myReceiver); let recipientName = await getName(myReceiver)
let myTxnrequest = await parentEpml.request('transaction', { let myTxnrequest = await parentEpml.request('transaction', {
type: 2, type: 2,
nonce: this.myAddress.nonce, nonce: this.myAddress.nonce,
@ -201,33 +201,33 @@ export class TipUser extends LitElement {
dialogName dialogName
}, },
}) })
return myTxnrequest; return myTxnrequest
} }
const getTxnRequestResponse = (txnResponse) => { const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) { if (txnResponse.success === false && txnResponse.message) {
this.errorMessage = txnResponse.message; this.errorMessage = txnResponse.message
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
throw new Error(txnResponse); throw new Error(txnResponse)
} else if (txnResponse.success === true && !txnResponse.data.error) { } else if (txnResponse.success === true && !txnResponse.data.error) {
this.shadowRoot.getElementById('amountInput').value = ''; this.shadowRoot.getElementById('amountInput').value = ''
this.errorMessage = ''; this.errorMessage = ''
this.successMessage = this.renderSuccessText(); this.successMessage = this.renderSuccessText()
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
setTimeout(() => { setTimeout(() => {
this.setOpenTipUser(false); this.setOpenTipUser(false)
this.successMessage = ""; this.successMessage = ""
}, 3000); }, 3000)
} else { } else {
this.errorMessage = txnResponse.data.message; this.errorMessage = txnResponse.data.message
this.sendMoneyLoading = false; this.sendMoneyLoading = false
this.btnDisable = false; this.btnDisable = false
throw new Error(txnResponse); throw new Error(txnResponse)
} }
} }
validateReceiver(recipient); validateReceiver(recipient)
} }
render() { render() {
@ -274,4 +274,4 @@ export class TipUser extends LitElement {
`; `;
} }
} }
customElements.define('tip-user', TipUser); customElements.define('tip-user', TipUser)

View File

@ -1,5 +1,6 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })

View File

@ -1,119 +1,110 @@
import { LitElement, html } from 'lit'; import { LitElement, html } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { translate } from 'lit-translate'; import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import { userInfoStyles } from './UserInfo-css.js'; import { userInfoStyles } from './UserInfo-css.js'
import { Epml } from '../../../../epml'; import { Epml } from '../../../../epml'
import '@vaadin/button'; import { cropAddress } from '../../../utils/cropAddress.js'
import '@polymer/paper-progress/paper-progress.js';
import { cropAddress } from '../../../utils/cropAddress.js'; import '@polymer/paper-progress/paper-progress.js'
import '@vaadin/button'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
export class UserInfo extends LitElement { export class UserInfo extends LitElement {
static get properties() { static get properties() {
return { return {
setOpenUserInfo: { attribute: false }, setOpenUserInfo: { attribute: false },
setOpenTipUser: { attribute: false }, setOpenTipUser: { attribute: false },
setOpenPrivateMessage: { attribute: false }, setOpenPrivateMessage: { attribute: false },
userName: { type: String }, userName: { type: String },
selectedHead: { type: Object }, selectedHead: { type: Object },
isImageLoaded: { type: Boolean } isImageLoaded: { type: Boolean }
} }
} }
constructor() { constructor() {
super() super()
this.isImageLoaded = false this.isImageLoaded = false
this.selectedHead = {} this.selectedHead = {}
this.imageFetches = 0 this.imageFetches = 0
}
static styles = [userInfoStyles]
createImage(imageUrl) {
const imageHTMLRes = new Image()
imageHTMLRes.src = imageUrl
imageHTMLRes.classList.add("user-info-avatar")
imageHTMLRes.onload = () => {
this.isImageLoaded = true
}
imageHTMLRes.onerror = () => {
if (this.imageFetches < 4) {
setTimeout(() => {
this.imageFetches = this.imageFetches + 1
imageHTMLRes.src = imageUrl;
}, 10000)
} else {
this.isImageLoaded = false
}
}
return imageHTMLRes
}
render() {
let avatarImg = ""
if (this.selectedHead && this.selectedHead.name) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.selectedHead.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`
avatarImg = this.createImage(avatarUrl)
}
return html`
<div style="position: relative;">
<vaadin-icon
class="close-icon"
icon="vaadin:close-big"
slot="icon"
@click=${() => {
this.setOpenUserInfo(false)
}}
>
</vaadin-icon>
${this.isImageLoaded ? html`<div class="avatar-container">${avatarImg}</div>` : html``}
${!this.isImageLoaded && this.selectedHead && this.selectedHead.name ? html`
<div class="avatar-container">
<div class="user-info-no-avatar">
${this.selectedHead.name.charAt(0)}
</div>
</div>
` : ""}
${!this.isImageLoaded && this.selectedHead && !this.selectedHead.name ? html`
<div class="avatar-container">
<img src="/img/incognito.png" alt="avatar" />
</div>`
: ""}
<div class="user-info-header">
${this.selectedHead && this.selectedHead.name ? this.selectedHead.name : this.selectedHead ? cropAddress(this.selectedHead.address) : null}
</div>
<div class="send-message-button" @click="${() => {
this.setOpenPrivateMessage({
name: this.userName,
open: true
})
this.setOpenUserInfo(false)
}}">
${translate("chatpage.cchange58")}
</div>
<div style="margin-top: 5px;" class="send-message-button" @click=${() => {
this.setOpenTipUser(true)
this.setOpenUserInfo(false)
}}>
${translate("chatpage.cchange59")}
</div>
</div>
`
}
} }
static styles = [userInfoStyles] customElements.define('user-info', UserInfo)
createImage(imageUrl) {
const imageHTMLRes = new Image();
imageHTMLRes.src = imageUrl;
imageHTMLRes.classList.add("user-info-avatar");
imageHTMLRes.onload = () => {
this.isImageLoaded = true;
}
imageHTMLRes.onerror = () => {
if (this.imageFetches < 4) {
setTimeout(() => {
this.imageFetches = this.imageFetches + 1;
imageHTMLRes.src = imageUrl;
}, 500);
} else {
this.isImageLoaded = false
}
};
return imageHTMLRes;
}
render() {
let avatarImg = "";
if (this.selectedHead && this.selectedHead.name) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.selectedHead.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`;
avatarImg = this.createImage(avatarUrl);
}
return html`
<div style=${"position: relative;"}>
<vaadin-icon
class="close-icon"
icon="vaadin:close-big"
slot="icon"
@click=${() => {
this.setOpenUserInfo(false)
}}>
</vaadin-icon>
${this.isImageLoaded ?
html`
<div class="avatar-container">
${avatarImg}
</div>` :
html``}
${!this.isImageLoaded && this.selectedHead && this.selectedHead.name ?
html`
<div class="avatar-container">
<div class="user-info-no-avatar">
${this.selectedHead.name.charAt(0)}
</div>
</div>
`
: ""}
${!this.isImageLoaded && this.selectedHead && !this.selectedHead.name ?
html`
<div class="avatar-container">
<img src="/img/incognito.png" alt="avatar" />
</div>`
: ""}
<div class="user-info-header">
${this.selectedHead && this.selectedHead.name ? this.selectedHead.name : this.selectedHead ? cropAddress(this.selectedHead.address) : null}
</div>
<div
class="send-message-button"
@click="${() => {
this.setOpenPrivateMessage({
name: this.userName,
open: true
})
this.setOpenUserInfo(false);
}
}">
${translate("chatpage.cchange58")}
</div>
<div
style=${"margin-top: 5px;"}
class="send-message-button"
@click=${() => {
this.setOpenTipUser(true);
this.setOpenUserInfo(false);
}}>
${translate("chatpage.cchange59")}
</div>
</div>
`
}
}
customElements.define('user-info', UserInfo);

View File

@ -1,33 +1,32 @@
import { LitElement, html } from 'lit'; import { LitElement, html } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { wrapperModalStyles } from './WrapperModal-css.js' import { wrapperModalStyles } from './WrapperModal-css.js'
export class WrapperModal extends LitElement { export class WrapperModal extends LitElement {
static get properties() { static get properties() {
return { return {
customStyle: {type: String}, customStyle: {type: String},
onClickFunc: { attribute: false }, onClickFunc: { attribute: false },
zIndex: {type: Number} zIndex: {type: Number}
}
} }
}
static styles = [wrapperModalStyles] static styles = [wrapperModalStyles]
render() { render() {
return html` return html`
<div> <div>
<div <div
style="z-index: ${this.zIndex || 50}" style="z-index: ${this.zIndex || 50}"
class="backdrop" class="backdrop"
@click=${() => { @click=${() => { this.onClickFunc() }}
this.onClickFunc(); >
}}> </div>
</div> <div class="modal-body" style=${this.customStyle ? this.customStyle : ""}>
<div class="modal-body" style=${this.customStyle ? this.customStyle : ""}> <slot></slot>
<slot></slot> </div>
</div> </div>
</div> `
`; }
}
} }
customElements.define('wrapper-modal', WrapperModal); customElements.define('wrapper-modal', WrapperModal)

View File

@ -107,7 +107,217 @@ export const encryptData = ({ data64, recipientPublicKey }) => {
recipientPublicKey recipientPublicKey
} }
} catch (error) { } catch (error) {
console.log({ error })
throw new Error("Error in encrypting data") throw new Error("Error in encrypting data")
} }
} }
export const encryptDataGroup = ({ data64, publicKeys }) => {
const userPublicKey = window.parent.reduxStore.getState().app.selectedAddress.base58PublicKey
let combinedPublicKeys = publicKeys
if (userPublicKey) {
combinedPublicKeys = [...publicKeys, userPublicKey]
}
const publicKeysDuplicateFree = [...new Set(combinedPublicKeys)];
const Uint8ArrayData = base64ToUint8Array(data64)
if (!(Uint8ArrayData instanceof Uint8Array)) {
throw new Error("The Uint8ArrayData you've submitted is invalid")
}
try {
const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey
if (!privateKey) {
throw new Error("Unable to retrieve keys")
}
// Generate a random symmetric key for the message.
const messageKey = new Uint8Array(32);
window.crypto.getRandomValues(messageKey);
const nonce = new Uint8Array(24);
window.crypto.getRandomValues(nonce);
// Encrypt the data with the symmetric key.
const encryptedData = nacl.secretbox(Uint8ArrayData, nonce, messageKey);
// Generate a keyNonce outside of the loop.
const keyNonce = new Uint8Array(24);
window.crypto.getRandomValues(keyNonce);
// Encrypt the symmetric key for each recipient.
let encryptedKeys = [];
publicKeysDuplicateFree.forEach((recipientPublicKey) => {
const publicKeyUnit8Array = window.parent.Base58.decode(recipientPublicKey)
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
const convertedPublicKey = ed2curve.convertPublicKey(publicKeyUnit8Array)
const sharedSecret = new Uint8Array(32)
// the length of the sharedSecret will be 32 + 16
// When you're encrypting data using nacl.secretbox, it's adding an authentication tag to the result, which is 16 bytes long. This tag is used for verifying the integrity and authenticity of the data when it is decrypted
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
// Encrypt the symmetric key with the shared secret.
const encryptedKey = nacl.secretbox(messageKey, keyNonce, sharedSecret);
encryptedKeys.push(encryptedKey);
});
const str = "qortalGroupEncryptedData";
const strEncoder = new TextEncoder();
const strUint8Array = strEncoder.encode(str);
// Convert sender's public key to Uint8Array and add to the message
const senderPublicKeyUint8Array = window.parent.Base58.decode(userPublicKey);
// Combine all data into a single Uint8Array.
// Calculate size of combinedData
let combinedDataSize = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length + 4;
let encryptedKeysSize = 0;
encryptedKeys.forEach((key) => {
encryptedKeysSize += key.length;
});
combinedDataSize += encryptedKeysSize;
let combinedData = new Uint8Array(combinedDataSize);
combinedData.set(strUint8Array);
combinedData.set(nonce, strUint8Array.length);
combinedData.set(keyNonce, strUint8Array.length + nonce.length);
combinedData.set(senderPublicKeyUint8Array, strUint8Array.length + nonce.length + keyNonce.length);
combinedData.set(encryptedData, strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length);
// Initialize offset for encryptedKeys
let encryptedKeysOffset = strUint8Array.length + nonce.length + keyNonce.length + senderPublicKeyUint8Array.length + encryptedData.length;
encryptedKeys.forEach((key) => {
combinedData.set(key, encryptedKeysOffset);
encryptedKeysOffset += key.length;
});
const countArray = new Uint8Array(new Uint32Array([publicKeysDuplicateFree.length]).buffer);
combinedData.set(countArray, combinedData.length - 4);
const uint8arrayToData64 = uint8ArrayToBase64(combinedData)
return uint8arrayToData64;
} catch (error) {
throw new Error("Error in encrypting data")
}
}
export function uint8ArrayStartsWith(uint8Array, string) {
const stringEncoder = new TextEncoder();
const stringUint8Array = stringEncoder.encode(string);
if (uint8Array.length < stringUint8Array.length) {
return false;
}
for (let i = 0; i < stringUint8Array.length; i++) {
if (uint8Array[i] !== stringUint8Array[i]) {
return false;
}
}
return true;
}
export function decryptDeprecatedSingle(uint8Array, publicKey) {
const combinedData = uint8Array
const str = "qortalEncryptedData";
const strEncoder = new TextEncoder();
const strUint8Array = strEncoder.encode(str);
const strData = combinedData.slice(0, strUint8Array.length);
const nonce = combinedData.slice(strUint8Array.length, strUint8Array.length + 24);
const _encryptedData = combinedData.slice(strUint8Array.length + 24);
const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey
const _publicKey = window.parent.Base58.decode(publicKey)
if (!privateKey || !_publicKey) {
throw new Error("Unable to retrieve keys")
}
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
const convertedPublicKey = ed2curve.convertPublicKey(_publicKey)
const sharedSecret = new Uint8Array(32);
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
const _chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result
const _decryptedData = nacl.secretbox.open(_encryptedData, nonce, _chatEncryptionSeed)
if (!_decryptedData) {
throw new Error("Unable to decrypt")
}
const decryptedDataToBase64 = uint8ArrayToBase64(_decryptedData)
return decryptedDataToBase64
}
export function decryptGroupData(data64EncryptedData) {
const allCombined = base64ToUint8Array(data64EncryptedData);
const str = "qortalGroupEncryptedData";
const strEncoder = new TextEncoder();
const strUint8Array = strEncoder.encode(str);
// Extract the nonce
const nonceStartPosition = strUint8Array.length;
const nonceEndPosition = nonceStartPosition + 24; // Nonce is 24 bytes
const nonce = allCombined.slice(nonceStartPosition, nonceEndPosition);
// Extract the shared keyNonce
const keyNonceStartPosition = nonceEndPosition;
const keyNonceEndPosition = keyNonceStartPosition + 24; // Nonce is 24 bytes
const keyNonce = allCombined.slice(keyNonceStartPosition, keyNonceEndPosition);
// Extract the sender's public key
const senderPublicKeyStartPosition = keyNonceEndPosition;
const senderPublicKeyEndPosition = senderPublicKeyStartPosition + 32; // Public keys are 32 bytes
const senderPublicKey = allCombined.slice(senderPublicKeyStartPosition, senderPublicKeyEndPosition);
// Calculate count first
const countStartPosition = allCombined.length - 4; // 4 bytes before the end, since count is stored in Uint32 (4 bytes)
const countArray = allCombined.slice(countStartPosition, countStartPosition + 4);
const count = new Uint32Array(countArray.buffer)[0];
// Then use count to calculate encryptedData
const encryptedDataStartPosition = senderPublicKeyEndPosition; // start position of encryptedData
const encryptedDataEndPosition = allCombined.length - ((count * (32 + 16)) + 4);
const encryptedData = allCombined.slice(encryptedDataStartPosition, encryptedDataEndPosition);
// Extract the encrypted keys
// 32+16 = 48
const combinedKeys = allCombined.slice(encryptedDataEndPosition, encryptedDataEndPosition + (count * 48));
const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey
if (!privateKey) {
throw new Error("Unable to retrieve keys")
}
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
const convertedSenderPublicKey = ed2curve.convertPublicKey(senderPublicKey)
const sharedSecret = new Uint8Array(32)
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedSenderPublicKey)
for (let i = 0; i < count; i++) {
const encryptedKey = combinedKeys.slice(i * 48, (i + 1) * 48);
// Decrypt the symmetric key.
const decryptedKey = nacl.secretbox.open(encryptedKey, keyNonce, sharedSecret);
// If decryption was successful, decryptedKey will not be null.
if (decryptedKey) {
// Decrypt the data using the symmetric key.
const decryptedData = nacl.secretbox.open(encryptedData, nonce, decryptedKey);
// If decryption was successful, decryptedData will not be null.
if (decryptedData) {
return decryptedData
}
}
}
throw new Error("Unable to decrypt data")
}

View File

@ -43,6 +43,9 @@ export const ENCRYPT_DATA = 'ENCRYPT_DATA'
// DECRYPT_DATA // DECRYPT_DATA
export const DECRYPT_DATA = 'DECRYPT_DATA' export const DECRYPT_DATA = 'DECRYPT_DATA'
// DECRYPT_DATA_GROUP
export const DECRYPT_DATA_GROUP = 'DECRYPT_DATA_GROUP'
// SAVE_FILE // SAVE_FILE
export const SAVE_FILE = 'SAVE_FILE' export const SAVE_FILE = 'SAVE_FILE'

View File

@ -1,7 +1,6 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js' import { render } from 'lit/html.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@polymer/paper-dialog/paper-dialog.js' import '@polymer/paper-dialog/paper-dialog.js'
import '@material/mwc-button' import '@material/mwc-button'
import '@material/mwc-icon' import '@material/mwc-icon'

View File

@ -1849,6 +1849,18 @@ class GroupManagement extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -1,8 +1,8 @@
import { parentEpml } from './connect.js'; import { parentEpml } from './connect.js';
import './streams/streams.js'; import './streams/streams.js';
let config = {}; let config = {}
let haveRegisteredNodeManagement = false; let haveRegisteredNodeManagement = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
// pluginUrlsConf // pluginUrlsConf
@ -186,20 +186,20 @@ parentEpml.ready().then(() => {
]; ];
const registerPlugins = (pluginInfo) => { const registerPlugins = (pluginInfo) => {
parentEpml.request('registerUrl', pluginInfo); parentEpml.request('registerUrl', pluginInfo)
}; };
const checkNode = const checkNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
window.parent.reduxStore.getState().app.nodeConfig.node window.parent.reduxStore.getState().app.nodeConfig.node
]; ]
parentEpml.subscribe('config', (c) => { parentEpml.subscribe('config', (c) => {
config = JSON.parse(c); config = JSON.parse(c)
// Only register node management if node management is enabled and it hasn't already been registered // Only register node management if node management is enabled and it hasn't already been registered
if (!haveRegisteredNodeManagement && checkNode.enableManagement) { if (!haveRegisteredNodeManagement && checkNode.enableManagement) {
haveRegisteredNodeManagement = true; haveRegisteredNodeManagement = true
let nodeManagementConf = { let nodeManagementConf = {
url: 'node-management', url: 'node-management',
@ -213,10 +213,10 @@ parentEpml.ready().then(() => {
parent: false, parent: false,
}; };
let _pluginUrlsConf = [...pluginUrlsConf, nodeManagementConf]; let _pluginUrlsConf = [...pluginUrlsConf, nodeManagementConf]
registerPlugins(_pluginUrlsConf); registerPlugins(_pluginUrlsConf)
} else { } else {
registerPlugins(pluginUrlsConf); registerPlugins(pluginUrlsConf)
} }
}); })
}); })

View File

@ -1,6 +1,10 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'
import { Epml } from '../../../../epml.js'
import isElectron from 'is-electron' import isElectron from 'is-electron'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChainMessaging extends LitElement { class ChainMessaging extends LitElement {
static get properties() { static get properties() {
return { return {
@ -44,12 +48,18 @@ class ChainMessaging extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
setInterval(() => { window.addEventListener('storage', () => {
this.changeTheme(); const checkTheme = localStorage.getItem('qortalTheme')
}, 100)
if (checkTheme === 'dark') {
this.theme = 'dark'
} else {
this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme)
})
if (!isElectron()) { if (!isElectron()) {
} else { } else {
@ -60,6 +70,14 @@ class ChainMessaging extends LitElement {
} }
} }
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
}
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {

View File

@ -138,13 +138,8 @@ class Messaging extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
setInterval(() => {
this.changeTheme();
}, 100)
if (!isElectron()) { if (!isElectron()) {
} else { } else {
window.addEventListener('contextmenu', (event) => { window.addEventListener('contextmenu', (event) => {
@ -170,6 +165,18 @@ class Messaging extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

File diff suppressed because one or more lines are too long

View File

@ -1,38 +1,34 @@
import { LitElement, html, css } from 'lit'; import { LitElement, html, css } from 'lit'
import { render } from 'lit/html.js'; import { render } from 'lit/html.js'
import { passiveSupport } from 'passive-events-support/src/utils' import { passiveSupport } from 'passive-events-support/src/utils'
passiveSupport({ import { Epml } from '../../../../epml.js'
events: ['touchstart'] import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
})
import { Epml } from '../../../../epml.js';
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate';
import { qchatStyles } from './q-chat-css.src.js' import { qchatStyles } from './q-chat-css.src.js'
import WebWorker from 'web-worker:./computePowWorker.src.js'; import { repeat } from 'lit/directives/repeat.js'
import {repeat} from 'lit/directives/repeat.js'; import { Editor, Extension } from '@tiptap/core'
import isElectron from 'is-electron' import isElectron from 'is-electron'
import WebWorker from 'web-worker:./computePowWorker.src.js'
registerTranslateConfig({
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
})
import '../../components/ChatWelcomePage.js'
import '../../components/ChatHead.js'
import '../../components/ChatPage.js'
import '../../components/WrapperModal.js';
import '../../components/ChatSeachResults.js';
import snackbar from '../../components/snackbar.js'
import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@material/mwc-snackbar'
import '@vaadin/grid'
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 Placeholder from '@tiptap/extension-placeholder' import Placeholder from '@tiptap/extension-placeholder'
import Highlight from '@tiptap/extension-highlight' import Highlight from '@tiptap/extension-highlight'
import snackbar from '../../components/snackbar.js'
import '../../components/ChatWelcomePage.js'
import '../../components/ChatHead.js'
import '../../components/ChatPage.js'
import '../../components/WrapperModal.js'
import '../../components/ChatSearchResults.js'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
import '@material/mwc-snackbar'
import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/grid'
passiveSupport({ events: ['touchstart'] })
import { Editor, Extension } from '@tiptap/core'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class Chat extends LitElement { class Chat extends LitElement {
@ -58,11 +54,11 @@ class Chat extends LitElement {
userFoundModalOpen: { type: Boolean }, userFoundModalOpen: { type: Boolean },
userSelected: { type: Object }, userSelected: { type: Object },
editor: {type: Object}, editor: {type: Object},
groupInvites: { type: Array }, groupInvites: { type: Array }
} }
} }
static styles = [qchatStyles] static styles = [qchatStyles]
constructor() { constructor() {
super() super()
@ -70,7 +66,6 @@ class Chat extends LitElement {
this.config = { this.config = {
user: { user: {
node: { node: {
} }
} }
} }
@ -100,30 +95,28 @@ class Chat extends LitElement {
this.groupInvites = [] this.groupInvites = []
} }
async setActiveChatHeadUrl(url) { async setActiveChatHeadUrl(url) {
this.activeChatHeadUrl = '' this.activeChatHeadUrl = ''
await this.updateComplete; await this.updateComplete;
this.activeChatHeadUrl = url this.activeChatHeadUrl = url
} }
resetChatEditor(){ resetChatEditor(){
this.editor.commands.setContent('')
this.editor.commands.setContent('')
} }
async getUpdateCompleteTextEditor() { async getUpdateCompleteTextEditor() {
await super.getUpdateComplete(); await super.getUpdateComplete()
const marginElements = Array.from(this.shadowRoot.querySelectorAll('chat-text-editor')); const marginElements = Array.from(this.shadowRoot.querySelectorAll('chat-text-editor'))
await Promise.all(marginElements.map(el => el.updateComplete)); await Promise.all(marginElements.map(el => el.updateComplete))
const marginElements2 = Array.from(this.shadowRoot.querySelectorAll('wrapper-modal')); const marginElements2 = Array.from(this.shadowRoot.querySelectorAll('wrapper-modal'))
await Promise.all(marginElements2.map(el => el.updateComplete)); await Promise.all(marginElements2.map(el => el.updateComplete))
return true; return true
} }
async connectedCallback() { async connectedCallback() {
super.connectedCallback()
super.connectedCallback(); await this.getUpdateCompleteTextEditor()
await this.getUpdateCompleteTextEditor();
const elementChatId = this.shadowRoot.getElementById('messageBox').shadowRoot.getElementById('privateMessage') const elementChatId = this.shadowRoot.getElementById('messageBox').shadowRoot.getElementById('privateMessage')
this.editor = new Editor({ this.editor = new Editor({
@ -152,43 +145,38 @@ class Chat extends LitElement {
] ]
}) })
this.unsubscribeStore = window.parent.reduxStore.subscribe(() => { this.unsubscribeStore = window.parent.reduxStore.subscribe(() => {
try { try {
if(window.parent.location && window.parent.location.search) {
if(window.parent.location && window.parent.location.search){ const queryString = window.parent.location.search
const queryString = window.parent.location.search; const params = new URLSearchParams(queryString)
const params = new URLSearchParams(queryString);
const chat = params.get("chat") const chat = params.get("chat")
if(chat && chat !== this.activeChatHeadUrl){ if(chat && chat !== this.activeChatHeadUrl){
let url = window.parent.location.href; let url = window.parent.location.href
let newUrl = url.split("?")[0]; let newUrl = url.split("?")[0]
window.parent.history.pushState({}, "", newUrl); window.parent.history.pushState({}, "", newUrl)
this.setActiveChatHeadUrl(chat) this.setActiveChatHeadUrl(chat)
} }
} }
} catch (error) { } catch (error) {
console.error(error)
} }
})
});
} }
disconnectedCallback() { disconnectedCallback() {
super.disconnectedCallback(); super.disconnectedCallback()
this.editor.destroy(); this.editor.destroy()
this.unsubscribeStore(); this.unsubscribeStore()
} }
updatePlaceholder(editor, text) {
updatePlaceholder(editor, text){
editor.extensionManager.extensions.forEach((extension) => { editor.extensionManager.extensions.forEach((extension) => {
if (extension.name === "placeholder") { if (extension.name === "placeholder") {
extension.options["placeholder"] = text extension.options["placeholder"] = text
editor.commands.focus('end') editor.commands.focus('end')
} }
}) })
} }
render() { render() {
@ -196,9 +184,8 @@ class Chat extends LitElement {
<div class="container clearfix"> <div class="container clearfix">
<div class="people-list" id="people-list"> <div class="people-list" id="people-list">
<div class="search"> <div class="search">
<div class="create-chat" @click=${() => { <div class="create-chat" @click=${() => { this.openPrivateMessage = true }}>
this.openPrivateMessage = true; ${translate("chatpage.cchange1")}
}}>${translate("chatpage.cchange1")}
</div> </div>
</div> </div>
<ul class="list"> <ul class="list">
@ -207,9 +194,7 @@ class Chat extends LitElement {
<div class="blockedusers"> <div class="blockedusers">
<!-- <div class="groups-button-container"> <!-- <div class="groups-button-container">
<button <button
@click=${() => { @click=${() => { this.redirectToGroups() }}
this.redirectToGroups();
}}
class="groups-button"> class="groups-button">
<mwc-icon>groups</mwc-icon> <mwc-icon>groups</mwc-icon>
${translate("sidemenu.groupmanagement")} ${translate("sidemenu.groupmanagement")}
@ -246,11 +231,11 @@ class Chat extends LitElement {
<!-- Start Chatting Dialog --> <!-- Start Chatting Dialog -->
<wrapper-modal <wrapper-modal
.onClickFunc=${() => { .onClickFunc=${() => {
this.resetChatEditor(); this.resetChatEditor()
this.openPrivateMessage = false; this.openPrivateMessage = false
this.shadowRoot.getElementById('sendTo').value = ""; this.shadowRoot.getElementById('sendTo').value = ""
this.userFoundModalOpen = false; this.userFoundModalOpen = false;
this.userFound = []; this.userFound = []
} } } }
style=${this.openPrivateMessage ? "visibility:visible;z-index:50" : "visibility: hidden;z-index:-100;position: relative"}> style=${this.openPrivateMessage ? "visibility:visible;z-index:50" : "visibility: hidden;z-index:-100;position: relative"}>
<div style=${"position: relative"}> <div style=${"position: relative"}>
@ -269,9 +254,9 @@ class Chat extends LitElement {
placeholder="${translate("chatpage.cchange7")}" placeholder="${translate("chatpage.cchange7")}"
value=${this.userSelected.name ? this.userSelected.name: ''} value=${this.userSelected.name ? this.userSelected.name: ''}
@keypress=${() => { @keypress=${() => {
this.userSelected = {}; this.userSelected = {}
this.requestUpdate(); this.requestUpdate()
}} }}
/> />
${this.userSelected.name ? ( ${this.userSelected.name ? (
html` html`
@ -321,10 +306,8 @@ class Chat extends LitElement {
class="modal-button" class="modal-button"
@click=${()=> { @click=${()=> {
const chatTextEditor = this.shadowRoot.getElementById('messageBox') const chatTextEditor = this.shadowRoot.getElementById('messageBox')
chatTextEditor.sendMessageFunc({ chatTextEditor.sendMessageFunc({
}) })
}} }}
?disabled="${this.isLoading}"> ?disabled="${this.isLoading}">
${this.isLoading === false ${this.isLoading === false
@ -364,9 +347,9 @@ class Chat extends LitElement {
<vaadin-grid theme="compact" id="blockedGrid" ?hidden="${this.isEmptyArray(this.blockedUserList)}" aria-label="Blocked List" .items="${this.blockedUserList}" all-rows-visible> <vaadin-grid theme="compact" id="blockedGrid" ?hidden="${this.isEmptyArray(this.blockedUserList)}" aria-label="Blocked List" .items="${this.blockedUserList}" all-rows-visible>
<vaadin-grid-column auto-width header="${translate("chatpage.cchange11")}" .renderer=${(root, column, data) => { <vaadin-grid-column auto-width header="${translate("chatpage.cchange11")}" .renderer=${(root, column, data) => {
if (data.item.name === "No registered name") { if (data.item.name === "No registered name") {
render(html`${translate("chatpage.cchange15")}`, root); render(html`${translate("chatpage.cchange15")}`, root)
} else { } else {
render(html`${data.item.name}`, root); render(html`${data.item.name}`, root)
} }
}}> }}>
</vaadin-grid-column> </vaadin-grid-column>
@ -392,14 +375,11 @@ class Chat extends LitElement {
` `
} }
async firstUpdated() {
this.changeTheme()
async firstUpdated() { this.getChatBlockedList()
this.changeLanguage(); this.getLocalBlockedList()
this.changeTheme(); // await this.getPendingGroupInvites()
this.getChatBlockedList();
this.getLocalBlockedList();
// await this.getPendingGroupInvites();
const getBlockedUsers = async () => { const getBlockedUsers = async () => {
let blockedUsers = await parentEpml.request('apiCall', { let blockedUsers = await parentEpml.request('apiCall', {
@ -410,15 +390,15 @@ class Chat extends LitElement {
} }
const stopKeyEventPropagation = (e) => { const stopKeyEventPropagation = (e) => {
e.stopPropagation(); e.stopPropagation()
return false; return false
} }
const nameInput = this.shadowRoot.getElementById('sendTo'); const nameInput = this.shadowRoot.getElementById('sendTo')
nameInput.addEventListener('keydown', stopKeyEventPropagation); nameInput.addEventListener('keydown', stopKeyEventPropagation)
this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation); this.shadowRoot.getElementById('messageBox').addEventListener('keydown', stopKeyEventPropagation)
const runFunctionsAfterPageLoad = () => { const runFunctionsAfterPageLoad = () => {
// Functions to exec after render while waiting for page info... // Functions to exec after render while waiting for page info...
@ -440,14 +420,11 @@ class Chat extends LitElement {
} }
} }
let runFunctionsAfterPageLoadInterval = setInterval(runFunctionsAfterPageLoad, 100); let runFunctionsAfterPageLoadInterval = setInterval(runFunctionsAfterPageLoad, 100)
window.addEventListener('storage', () => { window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage')
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
use(checkLanguage)
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark' this.theme = 'dark'
} else { } else {
@ -491,7 +468,18 @@ class Chat extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
setOpenPrivateMessage(props) { setOpenPrivateMessage(props) {
@ -500,10 +488,10 @@ class Chat extends LitElement {
} }
async userSearch() { async userSearch() {
const nameValue = this.shadowRoot.getElementById('sendTo').value; const nameValue = this.shadowRoot.getElementById('sendTo').value
if(!nameValue) { if(!nameValue) {
this.userFound = []; this.userFound = []
this.userFoundModalOpen = true; this.userFoundModalOpen = true
return; return;
} }
try { try {
@ -512,7 +500,7 @@ class Chat extends LitElement {
url: `/names/${nameValue}` url: `/names/${nameValue}`
}) })
if (result.error === 401) { if (result.error === 401) {
this.userFound = []; this.userFound = []
} else { } else {
this.userFound = [ this.userFound = [
...this.userFound, ...this.userFound,
@ -535,7 +523,7 @@ class Chat extends LitElement {
const trimmedMessage = msg const trimmedMessage = msg
if (/^\s*$/.test(trimmedMessage)) { if (/^\s*$/.test(trimmedMessage)) {
this.isLoading = false; this.isLoading = false
} else { } else {
const messageObject = { const messageObject = {
messageText: trimmedMessage, messageText: trimmedMessage,
@ -544,19 +532,19 @@ class Chat extends LitElement {
version: 3 version: 3
} }
const stringifyMessageObject = JSON.stringify(messageObject) const stringifyMessageObject = JSON.stringify(messageObject)
this.sendMessage(stringifyMessageObject); this.sendMessage(stringifyMessageObject)
} }
} }
async sendMessage(messageText) { async sendMessage(messageText) {
this.isLoading = true; this.isLoading = true
const _recipient = this.shadowRoot.getElementById('sendTo').value; const _recipient = this.shadowRoot.getElementById('sendTo').value
let recipient; let recipient
const validateName = async (receiverName) => { const validateName = async (receiverName) => {
let myRes; let myRes
try { try {
let myNameRes = await parentEpml.request('apiCall', { let myNameRes = await parentEpml.request('apiCall', {
type: 'api', type: 'api',
@ -565,19 +553,19 @@ class Chat extends LitElement {
if (myNameRes.error === 401) { if (myNameRes.error === 401) {
myRes = false; myRes = false;
} else { } else {
myRes = myNameRes; myRes = myNameRes
} }
return myRes; return myRes;
} catch (error) { } catch (error) {
return ""; return ""
} }
}; };
const myNameRes = await validateName(_recipient); const myNameRes = await validateName(_recipient)
if (!myNameRes) { if (!myNameRes) {
recipient = _recipient; recipient = _recipient
} else { } else {
recipient = myNameRes.owner; recipient = myNameRes.owner
}; };
const getAddressPublicKey = async () => { const getAddressPublicKey = async () => {
@ -590,23 +578,23 @@ class Chat extends LitElement {
}) })
if (addressPublicKey.error === 102) { if (addressPublicKey.error === 102) {
_publicKey = false; _publicKey = false
let err4string = get("chatpage.cchange19"); let err4string = get("chatpage.cchange19")
parentEpml.request('showSnackBar', `${err4string}`); parentEpml.request('showSnackBar', `${err4string}`)
this.isLoading = false; this.isLoading = false
} else if (addressPublicKey !== false) { } else if (addressPublicKey !== false) {
isEncrypted = 1; isEncrypted = 1
_publicKey = addressPublicKey; _publicKey = addressPublicKey
sendMessageRequest(isEncrypted, _publicKey); sendMessageRequest(isEncrypted, _publicKey)
} else { } else {
let err4string = get("chatpage.cchange39"); let err4string = get("chatpage.cchange39")
parentEpml.request('showSnackBar', `${err4string}`); parentEpml.request('showSnackBar', `${err4string}`)
this.isLoading = false; this.isLoading = false
} }
}; };
let _reference = new Uint8Array(64); let _reference = new Uint8Array(64)
window.crypto.getRandomValues(_reference); window.crypto.getRandomValues(_reference);
let reference = window.parent.Base58.encode(_reference); let reference = window.parent.Base58.encode(_reference)
const sendMessageRequest = async (isEncrypted, _publicKey) => { const sendMessageRequest = async (isEncrypted, _publicKey) => {
let chatResponse = await parentEpml.request('chat', { let chatResponse = await parentEpml.request('chat', {
type: 18, type: 18,
@ -622,26 +610,26 @@ class Chat extends LitElement {
isEncrypted: 1, isEncrypted: 1,
isText: 1 isText: 1
} }
}); })
_computePow(chatResponse); _computePow(chatResponse);
}; };
const _computePow = async (chatBytes) => { const _computePow = async (chatBytes) => {
const difficulty = this.balance < 4 ? 18 : 8 const difficulty = this.balance < 4 ? 18 : 8
const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'; const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
const worker = new WebWorker(); const worker = new WebWorker()
let nonce = null; let nonce = null
let chatBytesArray = null; let chatBytesArray = null;
await new Promise((res, rej) => { await new Promise((res, rej) => {
worker.postMessage({chatBytes, path, difficulty}); worker.postMessage({chatBytes, path, difficulty})
worker.onmessage = e => { worker.onmessage = e => {
worker.terminate(); worker.terminate()
chatBytesArray = e.data.chatBytesArray; chatBytesArray = e.data.chatBytesArray
nonce = e.data.nonce; nonce = e.data.nonce
res(); res()
} }
}); })
let _response = await parentEpml.request('sign_chat', { let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce, nonce: this.selectedAddress.nonce,
@ -649,36 +637,36 @@ class Chat extends LitElement {
chatNonce: nonce chatNonce: nonce
}); });
getSendChatResponse(_response); getSendChatResponse(_response)
}; };
const getSendChatResponse = (response) => { const getSendChatResponse = (response) => {
if (response === true) { if (response === true) {
this.setActiveChatHeadUrl(`direct/${recipient}`); this.setActiveChatHeadUrl(`direct/${recipient}`)
this.shadowRoot.getElementById('sendTo').value = ""; this.shadowRoot.getElementById('sendTo').value = ""
this.openPrivateMessage = false; this.openPrivateMessage = false
this.resetChatEditor(); this.resetChatEditor();
} else if (response.error) { } else if (response.error) {
parentEpml.request('showSnackBar', response.message); parentEpml.request('showSnackBar', response.message)
} else { } else {
let err2string = get("chatpage.cchange21"); let err2string = get("chatpage.cchange21")
parentEpml.request('showSnackBar', `${err2string}`); parentEpml.request('showSnackBar', `${err2string}`)
} }
this.isLoading = false; this.isLoading = false
}; }
// Exec.. // Exec..
getAddressPublicKey(); getAddressPublicKey()
} }
insertImage(file) { insertImage(file) {
if (file.type.includes('image')) { if (file.type.includes('image')) {
this.imageFile = file; this.imageFile = file
return; return
} }
parentEpml.request('showSnackBar', get("chatpage.cchange28")); parentEpml.request('showSnackBar', get("chatpage.cchange28"))
} }
renderLoadingText() { renderLoadingText() {
@ -724,7 +712,7 @@ class Chat extends LitElement {
localStorage.removeItem("ChatBlockedAddresses") localStorage.removeItem("ChatBlockedAddresses")
var obj = []; var obj = []
fetch(blockedAddressesUrl).then(response => { fetch(blockedAddressesUrl).then(response => {
return response.json() return response.json()
@ -751,7 +739,7 @@ class Chat extends LitElement {
}) })
} }
async getPendingGroupInvites() { async getPendingGroupInvites() {
const myAddress = window.parent.reduxStore.getState().app.selectedAddress.address const myAddress = window.parent.reduxStore.getState().app.selectedAddress.address
try { try {
let pendingGroupInvites = await parentEpml.request('apiCall', { let pendingGroupInvites = await parentEpml.request('apiCall', {
@ -810,91 +798,86 @@ class Chat extends LitElement {
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
} else { } else {
this.theme = 'light'; this.theme = 'light'
}
document.querySelector('html').setAttribute('theme', this.theme);
}
changeLanguage() {
const checkLanguage = localStorage.getItem('qortalLanguage')
if (checkLanguage === null || checkLanguage.length === 0) {
localStorage.setItem('qortalLanguage', 'us')
use('us')
} else {
use(checkLanguage)
} }
document.querySelector('html').setAttribute('theme', this.theme)
} }
renderChatWelcomePage() { renderChatWelcomePage() {
return html` return html`
<chat-welcome-page <chat-welcome-page
myAddress=${JSON.stringify(this.selectedAddress)} myAddress=${JSON.stringify(this.selectedAddress)}
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}> .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
>
</chat-welcome-page>` </chat-welcome-page>`
} }
renderChatHead(chatHeadArr) { renderChatHead(chatHeadArr) {
return chatHeadArr.map(eachChatHead => { return chatHeadArr.map(eachChatHead => {
return html`<chat-head activeChatHeadUrl=${this.activeChatHeadUrl} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)} chatInfo=${JSON.stringify(eachChatHead)}></chat-head>` return html`<chat-head activeChatHeadUrl=${this.activeChatHeadUrl} .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)} chatInfo=${JSON.stringify(eachChatHead)}></chat-head>`
}) })
} }
renderChatPage() { renderChatPage() {
// Check for the chat ID from and render chat messages // Check for the chat ID from and render chat messages
// Else render Welcome to Q-CHat // Else render Welcome to Q-CHat
// TODO: DONE: Do the above in the ChatPage // TODO: DONE: Do the above in the ChatPage
return html` return html`
<chat-page <chat-page
.chatHeads=${this.chatHeads} .chatHeads=${this.chatHeads}
.hideNewMessageBar=${this.hideNewMessageBar} .hideNewMessageBar=${this.hideNewMessageBar}
.showNewMessageBar=${this.showNewMessageBar} .showNewMessageBar=${this.showNewMessageBar}
myAddress=${window.parent.reduxStore.getState().app.selectedAddress.address} myAddress=${window.parent.reduxStore.getState().app.selectedAddress.address}
chatId=${this.activeChatHeadUrl} chatId=${this.activeChatHeadUrl}
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
.setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}> .setActiveChatHeadUrl=${(val)=> this.setActiveChatHeadUrl(val)}
</chat-page> >
</chat-page>
` `
} }
setChatHeads(chatObj) { setChatHeads(chatObj) {
const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : []; const chatObjGroups = Array.isArray(chatObj.groups) ? chatObj.groups : []
const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : []; const chatObjDirect = Array.isArray(chatObj.direct) ? chatObj.direct : []
let groupList = chatObjGroups.map(group => group.groupId === 0 ? { groupId: group.groupId, url: `group/${group.groupId}`, groupName: "Qortal General Chat", timestamp: group.timestamp === undefined ? 2 : group.timestamp, sender: group.sender } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}` })
let groupList = chatObjGroups.map(group => group.groupId === 0 ? {
groupId: group.groupId, url: `group/${group.groupId}`,
groupName: "Qortal General Chat",
timestamp: group.timestamp === undefined ? 2 : group.timestamp,
sender: group.sender } : { ...group, timestamp: group.timestamp === undefined ? 1 : group.timestamp, url: `group/${group.groupId}`
})
let directList = chatObjDirect.map(dc => { let directList = chatObjDirect.map(dc => {
return { ...dc, url: `direct/${dc.address}` } return { ...dc, url: `direct/${dc.address}` }
}) })
const compareNames = (a, b) => { const compareNames = (a, b) => {
return a.groupName.localeCompare(b.groupName) return a.groupName.localeCompare(b.groupName)
} }
groupList.sort(compareNames) groupList.sort(compareNames)
let chatHeadMasterList = [...groupList, ...directList] let chatHeadMasterList = [...groupList, ...directList]
const compareArgs = (a, b) => { const compareArgs = (a, b) => {
return b.timestamp - a.timestamp return b.timestamp - a.timestamp
} }
this.chatHeads = chatHeadMasterList.sort(compareArgs) this.chatHeads = chatHeadMasterList.sort(compareArgs)
} }
getChatHeadFromState(chatObj) { getChatHeadFromState(chatObj) {
if (chatObj === undefined) { if (chatObj === undefined) {
return return
} else { } else {
this.chatHeadsObj = chatObj this.chatHeadsObj = chatObj
this.setChatHeads(chatObj) this.setChatHeads(chatObj)
} }
} }
_textArea(e) { _textArea(e) {
if (e.keyCode === 13 && !e.shiftKey) this._sendMessage() if (e.keyCode === 13 && !e.shiftKey) this._sendMessage()
} }
@ -908,13 +891,13 @@ class Chat extends LitElement {
} }
getApiKey() { 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
return apiKey; return apiKey
} }
scrollToBottom() { scrollToBottom() {
const viewElement = this.shadowRoot.querySelector('chat-page').shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement'); const viewElement = this.shadowRoot.querySelector('chat-page').shadowRoot.querySelector('chat-scroller').shadowRoot.getElementById('viewElement')
viewElement.scroll({ top: viewElement.scrollHeight, left: 0, behavior: 'smooth' }) viewElement.scroll({ top: viewElement.scrollHeight, left: 0, behavior: 'smooth' })
} }

View File

@ -347,7 +347,6 @@ class MintingInfo extends LitElement {
} }
async firstUpdated() { async firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -429,6 +428,18 @@ class MintingInfo extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
async getAddressLevel() { async getAddressLevel() {

View File

@ -537,7 +537,6 @@ class NameRegistration extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.unitFee() this.unitFee()
@ -604,6 +603,18 @@ class NameRegistration extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -609,6 +609,18 @@ class NamesMarket extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
displayTabContent(tab) { displayTabContent(tab) {

View File

@ -34,10 +34,8 @@ class NodeManagement extends LitElement {
confPeerMessage: { type: String }, confPeerMessage: { type: String },
addMintingAccountMessage: { type: String }, addMintingAccountMessage: { type: String },
removeMintingAccountMessage: { type: String }, removeMintingAccountMessage: { type: String },
tempMintingAccount: { type: Object },
nodeConfig: { type: Object }, nodeConfig: { type: Object },
nodeDomain: { type: String }, nodeDomain: { type: String },
myElementId: { type: String },
theme: { type: String, reflect: true } theme: { type: String, reflect: true }
} }
} }
@ -138,15 +136,13 @@ class NodeManagement extends LitElement {
this.addPeerMessage = "" this.addPeerMessage = ""
this.confPeerMessage = "" this.confPeerMessage = ""
this.addMintingAccountMessage = "" this.addMintingAccountMessage = ""
this.tempMintingAccount = {}
this.config = { this.config = {
user: { user: {
node: {}, node: {},
}, },
}; }
this.nodeConfig = {} this.nodeConfig = {}
this.nodeDomain = "" this.nodeDomain = ""
this.myElementId = ''
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
} }
@ -278,11 +274,10 @@ class NodeManagement extends LitElement {
<br /> <br />
</div> </div>
</div> </div>
`; `
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.updateMintingAccounts() this.updateMintingAccounts()
@ -311,86 +306,84 @@ class NodeManagement extends LitElement {
// Calculate HH MM SS from Milliseconds... // Calculate HH MM SS from Milliseconds...
const convertMsToTime = (milliseconds) => { const convertMsToTime = (milliseconds) => {
let day, hour, minute, seconds; let day, hour, minute, seconds
seconds = Math.floor(milliseconds / 1000); seconds = Math.floor(milliseconds / 1000)
minute = Math.floor(seconds / 60); minute = Math.floor(seconds / 60)
seconds = seconds % 60; seconds = seconds % 60
hour = Math.floor(minute / 60); hour = Math.floor(minute / 60)
minute = minute % 60; minute = minute % 60
day = Math.floor(hour / 24); day = Math.floor(hour / 24)
hour = hour % 24; hour = hour % 24
if (isNaN(day)) { if (isNaN(day)) {
return "offline"; return "offline"
} }
return day + "d " + hour + "h " + minute + "m"; return day + "d " + hour + "h " + minute + "m"
}; }
const getNodeUpTime = () => { const getNodeUpTime = () => {
parentEpml this.upTime = ""
.request("apiCall", { parentEpml.request("apiCall", { url: `/admin/uptime` }).then((res) => {
url: `/admin/uptime`, this.upTime = convertMsToTime(res)
}) })
.then((res) => { setTimeout(getNodeUpTime, 60000)
this.upTime = ""; }
setTimeout(() => {
this.upTime = convertMsToTime(res);
}, 1);
});
setTimeout(getNodeUpTime, this.config.user.nodeSettings.pingInterval);
};
const updatePeers = () => { const updatePeers = () => {
parentEpml this.peers = []
.request("apiCall", { parentEpml.request("apiCall", { url: `/peers` }).then((res) => {
url: `/peers`, this.peers = res
}) })
.then((res) => { setTimeout(updatePeers, 60000)
setTimeout(() => { }
this.peers = res;
}, 1);
});
setTimeout(updatePeers, this.config.user.nodeSettings.pingInterval);
};
const getNodeConfig = () => { const getNodeConfig = () => {
this.nodeConfig = {}
this.nodeDomain = ""
parentEpml.request("getNodeConfig").then((res) => { parentEpml.request("getNodeConfig").then((res) => {
setTimeout(() => { this.nodeConfig = res
this.nodeConfig = res; const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
}, 1); this.nodeDomain = myNode.domain + ":" + myNode.port
let myNode = window.parent.reduxStore.getState().app.nodeConfig })
.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; setTimeout(getNodeConfig, 60000)
this.nodeDomain = myNode.domain + ":" + myNode.port; }
});
setTimeout(getNodeConfig, 1000);
};
let configLoaded = false let configLoaded = false
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe("config", async c => { parentEpml.subscribe("config", async c => {
if (!configLoaded) { if (!configLoaded) {
setTimeout(getNodeUpTime, 1); setTimeout(getNodeUpTime, 1)
setTimeout(updatePeers, 1); setTimeout(updatePeers, 1)
setTimeout(this.updateMintingAccounts, 1); setTimeout(this.updateMintingAccounts, 1)
setTimeout(getNodeConfig, 1); setTimeout(getNodeConfig, 1)
configLoaded = true; configLoaded = true
} }
this.config = JSON.parse(c); this.config = JSON.parse(c)
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
} else { } else {
this.theme = 'light'; this.theme = 'light'
} }
document.querySelector('html').setAttribute('theme', this.theme); document.querySelector('html').setAttribute('theme', this.theme)
} }
changeLanguage() { changeLanguage() {
@ -421,8 +414,8 @@ class NodeManagement extends LitElement {
}) })
.then((res) => { .then((res) => {
let err3string = get("nodepage.nchange25") let err3string = get("nodepage.nchange25")
parentEpml.request('showSnackBar', `${err3string}` + peerAddress); parentEpml.request('showSnackBar', `${err3string}` + peerAddress)
}); })
} }
removePeer(peerAddress, rowIndex) { removePeer(peerAddress, rowIndex) {
@ -434,9 +427,9 @@ class NodeManagement extends LitElement {
}) })
.then((res) => { .then((res) => {
let err4string = get("nodepage.nchange26") let err4string = get("nodepage.nchange26")
parentEpml.request('showSnackBar', `${err4string}` + peerAddress); parentEpml.request('showSnackBar', `${err4string}` + peerAddress)
this.peers.splice(rowIndex, 1); this.peers.splice(rowIndex, 1)
}); })
} }
stopNode() { stopNode() {
@ -446,9 +439,9 @@ class NodeManagement extends LitElement {
method: "GET" method: "GET"
}) })
.then((res) => { .then((res) => {
let err7string = get("nodepage.nchange32") let err7string = get("nodepage.nchange32")
parentEpml.request('showSnackBar', `${err7string}`); parentEpml.request('showSnackBar', `${err7string}`)
}); })
} }
restartNode() { restartNode() {
@ -458,19 +451,18 @@ class NodeManagement extends LitElement {
method: "GET" method: "GET"
}) })
.then((res) => { .then((res) => {
let err7string = get("nodepage.nchange34") let err7string = get("nodepage.nchange34")
parentEpml.request('showSnackBar', `${err7string}`); parentEpml.request('showSnackBar', `${err7string}`)
}); })
} }
onPageNavigation(pageUrl) { onPageNavigation(pageUrl) {
parentEpml.request("setPageUrl", pageUrl); parentEpml.request("setPageUrl", pageUrl)
} }
addPeer(e) { addPeer(e) {
this.addPeerLoading = true; this.addPeerLoading = true
const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress") const addPeerAddress = this.shadowRoot.querySelector("#addPeerAddress").value
.value;
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
@ -479,18 +471,16 @@ class NodeManagement extends LitElement {
body: addPeerAddress, body: addPeerAddress,
}) })
.then((res) => { .then((res) => {
this.addPeerMessage = res.message; this.addPeerMessage = res.message
this.addPeerLoading = false; this.addPeerLoading = false
}); })
} }
addMintingAccount(e) { addMintingAccount(e) {
this.addMintingAccountLoading = true; this.addMintingAccountLoading = true
this.addMintingAccountMessage = "Loading..."; this.addMintingAccountMessage = "Loading..."
this.addMintingAccountKey = this.shadowRoot.querySelector( this.addMintingAccountKey = this.shadowRoot.querySelector("#addMintingAccountKey").value
"#addMintingAccountKey"
).value;
parentEpml parentEpml
.request("apiCall", { .request("apiCall", {
@ -500,28 +490,28 @@ class NodeManagement extends LitElement {
}) })
.then((res) => { .then((res) => {
if (res === true) { if (res === true) {
this.updateMintingAccounts(); this.updateMintingAccounts()
this.addMintingAccountKey = ""; this.addMintingAccountKey = ""
this.addMintingAccountMessage = this.renderErr1Text(); this.addMintingAccountMessage = this.renderErr1Text()
this.addMintingAccountLoading = false; this.addMintingAccountLoading = false
} else { } else {
this.addMintingAccountKey = ""; this.addMintingAccountKey = ""
this.addMintingAccountMessage = this.renderErr2Text(); // Corrected an error here thanks to crow (-_-) this.addMintingAccountMessage = this.renderErr2Text() // Corrected an error here thanks to crow (-_-)
this.addMintingAccountLoading = false; this.addMintingAccountLoading = false
} }
}); })
} }
updateMintingAccounts() { updateMintingAccounts() {
parentEpml.request("apiCall", { this.mintingAccounts = []
url: `/admin/mintingaccounts`, parentEpml.request("apiCall", { url: `/admin/mintingaccounts` }).then((res) => {
}).then((res) => { this.mintingAccounts = res
setTimeout(() => this.mintingAccounts = res, 1); })
}); console.clear()
} }
removeMintingAccount(publicKey) { removeMintingAccount(publicKey) {
this.removeMintingAccountLoading = true; this.removeMintingAccountLoading = true
parentEpml.request("apiCall", { parentEpml.request("apiCall", {
url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`, url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`,
@ -529,28 +519,28 @@ class NodeManagement extends LitElement {
body: publicKey, body: publicKey,
}).then((res) => { }).then((res) => {
if (res === true) { if (res === true) {
this.updateMintingAccounts(); this.updateMintingAccounts()
this.removeMintingAccountLoading = false; this.removeMintingAccountLoading = false
let err5string = get("nodepage.nchange29") let err5string = get("nodepage.nchange29")
parentEpml.request('showSnackBar', `${err5string}`); parentEpml.request('showSnackBar', `${err5string}`)
} else { } else {
this.removeMintingAccountLoading = false; this.removeMintingAccountLoading = false
let err6string = get("nodepage.nchange30") let err6string = get("nodepage.nchange30")
parentEpml.request('showSnackBar', `${err6string}`); parentEpml.request('showSnackBar', `${err6string}`)
} }
}); })
} }
getApiKey() { 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
return apiKey; return apiKey
} }
isEmptyArray(arr) { isEmptyArray(arr) {
if (!arr) return true; if (!arr) return true
return arr.length === 0; return arr.length === 0
} }
} }
window.customElements.define("node-management", NodeManagement); window.customElements.define("node-management", NodeManagement)

View File

@ -79,6 +79,8 @@ a:not([href]):not([tabindex]):focus {
img { img {
vertical-align: middle; vertical-align: middle;
border-style: none; border-style: none;
height: 128px;
width: 128px;
} }
caption { caption {

View File

@ -1,22 +1,23 @@
import { LitElement, html, css } from 'lit' import { LitElement, html, css } from 'lit'
import { Epml } from '../../../epml.js' import { Epml } from '../../../epml.js'
import { use, get, translate, registerTranslateConfig } from 'lit-translate' import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import isElectron from 'is-electron'
import { overviewStyle } from './overview-page-css.js' import { overviewStyle } from './overview-page-css.js'
import { asyncReplace } from 'lit/directives/async-replace.js' import { asyncReplace } from 'lit/directives/async-replace.js'
import isElectron from 'is-electron'
import "@material/mwc-button" import "@material/mwc-button"
import '@material/mwc-dialog' import '@material/mwc-dialog'
import '@vaadin/button';
import '@polymer/paper-spinner/paper-spinner-lite.js' import '@polymer/paper-spinner/paper-spinner-lite.js'
import '@vaadin/button'
registerTranslateConfig({ registerTranslateConfig({
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json()), loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
}) })
async function* countDown(count, callback) { async function* countDown(count, callback) {
while (count > 0) { while (count > 0) {
yield count--; yield count--
await new Promise((r) => setTimeout(r, 1000)); await new Promise((r) => setTimeout(r, 1000))
if (count === 0) { if (count === 0) {
callback() callback()
} }
@ -34,7 +35,10 @@ class OverviewPage extends LitElement {
nodeInfo: { type: Array }, nodeInfo: { type: Array },
coreInfo: { type: Array }, coreInfo: { type: Array },
imageUrl: { type: String }, imageUrl: { type: String },
myBalance: { type: Number } myBalance: { type: Number },
listAccounts: { type: Array },
check1: { type: Boolean },
check2: { type: Boolean }
} }
} }
@ -52,6 +56,9 @@ class OverviewPage extends LitElement {
this.coreInfo = [] this.coreInfo = []
this.imageUrl = '' this.imageUrl = ''
this.myBalance = 0 this.myBalance = 0
this.listAccounts = []
this.check1 = false
this.check2 = false
} }
render() { render() {
@ -114,7 +121,7 @@ class OverviewPage extends LitElement {
</div> </div>
<div> <div>
<span class="heading"><span class="${this.cssStatus2}">${this.renderSyncStatus()}</span></span> <span class="heading"><span class="${this.cssStatus2}">${this.renderSyncStatus()}</span></span>
<span class="description">${translate("walletpage.wchange41")}</span> <span class="description">${translate("walletprofile.wp5")}</span>
</div> </div>
</div> </div>
</div> </div>
@ -132,7 +139,7 @@ class OverviewPage extends LitElement {
` `
} }
firstUpdated() { async firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -142,6 +149,7 @@ class OverviewPage extends LitElement {
this.getNodeInfo() this.getNodeInfo()
this.getCoreInfo() this.getCoreInfo()
this.getBalanceInfo() this.getBalanceInfo()
await this.getMintingKeysList()
window.addEventListener('storage', () => { window.addEventListener('storage', () => {
const checkLanguage = localStorage.getItem('qortalLanguage') const checkLanguage = localStorage.getItem('qortalLanguage')
@ -168,14 +176,31 @@ class OverviewPage extends LitElement {
setInterval(() => { setInterval(() => {
this.refreshItems() this.refreshItems()
}, 60000) }, 60000)
setInterval(() => {
this.getAvatar()
}, 180000)
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme') const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') { if (checkTheme === 'dark') {
this.theme = 'dark'; this.theme = 'dark'
} else { } else {
this.theme = 'light'; this.theme = 'light'
} }
document.querySelector('html').setAttribute('theme', this.theme) document.querySelector('html').setAttribute('theme', this.theme)
} }
@ -191,22 +216,87 @@ class OverviewPage extends LitElement {
} }
} }
refreshItems() { renderMyErrorMsg1() {
return html`${translate("startminting.smchange1")}`
}
async refreshItems() {
this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig this.nodeConfig = window.parent.reduxStore.getState().app.nodeConfig
this.accountInfo = window.parent.reduxStore.getState().app.accountInfo this.accountInfo = window.parent.reduxStore.getState().app.accountInfo
this.getNodeInfo() this.getNodeInfo()
this.getCoreInfo() this.getCoreInfo()
this.getBalanceInfo() this.getBalanceInfo()
await this.getMintingKeysList()
}
async getMintingKeysList() {
this.check1 = false
this.check2 = false
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeStatus = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const statusUrl = `${nodeStatus}/admin/mintingaccounts`
try {
const res = await fetch(statusUrl)
const listAccounts = await res.json()
this.listAccounts = listAccounts
const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo
const address = window.parent.reduxStore.getState().app.selectedAddress.address
const findMyMintingAccount = this.listAccounts.find((myKey) => myKey.mintingAccount === address)
const findMyMintingRecipient = this.listAccounts.find((myKey) => myKey.recipientAccount === address)
const findRemovedSponsorsKey = this.listAccounts.filter((my) => my.address)
if (findMyMintingAccount === undefined) {
this.check1 = false
} else {
this.check1 = true
}
if (findMyMintingRecipient === undefined) {
this.check2 = false
} else {
this.check2 = true
}
if (findRemovedSponsorsKey.length > 0) {
this.removeBlankKey(findRemovedSponsorsKey.publicKey)
} else {
}
} catch (error) {
this.errorMsg = this.renderMyErrorMsg1()
}
}
removeBlankKey(myPublicKey) {
parentEpml.request("apiCall", {
url: `/admin/mintingaccounts?apiKey=${this.getApiKey()}`,
method: "DELETE",
body: myPublicKey,
}).then((res) => {
if (res === true) {
console.log('REMOVED BLANK KEY')
} else {
}
})
} }
renderMintingStatus() { renderMintingStatus() {
if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === true) { const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo
const myMintingKey = addressInfo?.error !== 124 && +addressInfo?.level > 0
if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === true && this.check1 === true && this.check2 === true && addressInfo.level > 0) {
this.cssStatus = '' this.cssStatus = ''
return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>` return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>`
} else if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === false) { } else if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === false && this.check1 === true && this.check2 === true && addressInfo.level > 0) {
this.cssStatus = '' this.cssStatus = ''
return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>` return html`<span class="btn btn-sm btn-info float-right">${translate("walletprofile.wp1")}</span>`
} else if (this.nodeInfo.isMintingPossible === false) { } else if (this.nodeInfo.isMintingPossible === true && this.nodeInfo.isSynchronizing === false && this.check1 === false && this.check2 === true && addressInfo.level == 0 && addressInfo.blocksMinted < 7200) {
this.cssStatus = ''
return html`<span class="btn btn-sm btn-info float-right">${translate("becomeMinterPage.bchange12")}</span>`
} else if (this.check1 === false && this.check2 === false && myMintingKey === true) {
return html`<span class="float-right"><start-minting-now></start-minting-now></span>`
} else if (myMintingKey === false) {
return html`<span class="float-right"><start-minting-now></start-minting-now></span>` return html`<span class="float-right"><start-minting-now></start-minting-now></span>`
} }
} }
@ -258,7 +348,6 @@ class OverviewPage extends LitElement {
this.coreInfo = data this.coreInfo = data
}) })
.catch(err => { .catch(err => {
console.error('Request failed', err)
}) })
} }
@ -273,9 +362,14 @@ class OverviewPage extends LitElement {
this.myBalance = data this.myBalance = data
}) })
.catch(err => { .catch(err => {
console.error('Request failed', err)
}) })
} }
getApiKey() {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let apiKey = myNode.apiKey
return apiKey
}
} }
window.customElements.define('overview-page', OverviewPage) window.customElements.define('overview-page', OverviewPage)
@ -288,12 +382,11 @@ class StartMintingNow extends LitElement {
status: { type: Number }, status: { type: Number },
timer: { type: Number }, timer: { type: Number },
privateRewardShareKey: { type: String } privateRewardShareKey: { type: String }
}; }
} }
static get styles() { static get styles() {
return [ return [css`
css`
p, h1 { p, h1 {
color: var(--black) color: var(--black)
} }
@ -423,25 +516,24 @@ class StartMintingNow extends LitElement {
.message-error { .message-error {
color: var(--error); color: var(--error);
} }
`, `]
];
} }
constructor() { constructor() {
super(); super()
this.mintingAccountData = []; this.mintingAccountData = []
this.errorMsg = ''; this.errorMsg = ''
this.openDialogRewardShare = false; this.openDialogRewardShare = false
this.status = 0; this.status = 0
this.privateRewardShareKey = ""; this.privateRewardShareKey = ""
} }
render() { render() {
return html` ${this.renderStartMintingButton()} `; return html`${this.renderStartMintingButton()}`
} }
firstUpdated() { firstUpdated() {
this.getMintingAcccounts(); this.getMintingAcccounts()
} }
renderErrorMsg1() { renderErrorMsg1() {
@ -465,16 +557,15 @@ class StartMintingNow extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const url = `${nodeUrl}/admin/mintingaccounts` const url = `${nodeUrl}/admin/mintingaccounts`
try { try {
const res = await fetch(url); const res = await fetch(url)
const mintingAccountData = await res.json() const mintingAccountData = await res.json()
this.mintingAccountData = mintingAccountData this.mintingAccountData = mintingAccountData
} catch (error) { } catch (error) {
this.errorMsg = this.renderErrorMsg1() this.errorMsg = this.renderErrorMsg1()
} }
} }
async changeStatus(value){ async changeStatus(value) {
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]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
this.status = value this.status = value
@ -509,7 +600,7 @@ class StartMintingNow extends LitElement {
} }
} catch (error) { } catch (error) {
this.errorMsg = this.renderErrorMsg2() this.errorMsg = this.renderErrorMsg2()
return; return
} }
try { try {
@ -540,7 +631,7 @@ class StartMintingNow extends LitElement {
} }
if (!stop) { if (!stop) {
stop = true; stop = true
try { try {
const address = window.parent.reduxStore.getState().app?.selectedAddress?.address const address = window.parent.reduxStore.getState().app?.selectedAddress?.address
const myRewardShareArray = await rewardShares(address) const myRewardShareArray = await rewardShares(address)
@ -554,7 +645,7 @@ class StartMintingNow extends LitElement {
} }
stop = false stop = false
} }
}; }
interval = setInterval(getAnswer, 5000) interval = setInterval(getAnswer, 5000)
} }
@ -563,14 +654,14 @@ class StartMintingNow extends LitElement {
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
const mintingAccountData = this.mintingAccountData const mintingAccountData = this.mintingAccountData
const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo const addressInfo = window.parent.reduxStore.getState().app.accountInfo.addressInfo
const address = window.parent.reduxStore.getState().app?.selectedAddress?.address const address = window.parent.reduxStore.getState().app.selectedAddress.address
const nonce = window.parent.reduxStore.getState().app?.selectedAddress?.nonce const nonce = window.parent.reduxStore.getState().app.selectedAddress.nonce
const publicAddress = window.parent.reduxStore.getState().app?.selectedAddress ?.base58PublicKey const publicAddress = window.parent.reduxStore.getState().app.selectedAddress.base58PublicKey
const findMintingAccount = mintingAccountData.find((ma) => ma.mintingAccount === address) const findMintingAccount = mintingAccountData.find((ma) => ma.mintingAccount === address)
const isMinterButKeyMintingKeyNotAssigned = addressInfo?.error !== 124 && addressInfo?.level >= 1 && !findMintingAccount const isMinterButKeyMintingKeyNotAssigned = addressInfo.error !== 124 && addressInfo.level >= 1 && !findMintingAccount
const makeTransactionRequest = async (lastRef) => { const makeTransactionRequest = async (lastRef) => {
let mylastRef = lastRef; let mylastRef = lastRef
let rewarddialog1 = get('transactions.rewarddialog1') let rewarddialog1 = get('transactions.rewarddialog1')
let rewarddialog2 = get('transactions.rewarddialog2') let rewarddialog2 = get('transactions.rewarddialog2')
let rewarddialog3 = get('transactions.rewarddialog3') let rewarddialog3 = get('transactions.rewarddialog3')
@ -586,26 +677,22 @@ class StartMintingNow extends LitElement {
rewarddialog1: rewarddialog1, rewarddialog1: rewarddialog1,
rewarddialog2: rewarddialog2, rewarddialog2: rewarddialog2,
rewarddialog3: rewarddialog3, rewarddialog3: rewarddialog3,
rewarddialog4: rewarddialog4, rewarddialog4: rewarddialog4
}, },
disableModal: true, disableModal: true
}) })
return myTxnrequest return myTxnrequest
} }
const getTxnRequestResponse = (txnResponse) => { const getTxnRequestResponse = (txnResponse) => {
let err6string = get('rewardsharepage.rchange21'); let err6string = get('rewardsharepage.rchange21')
if (txnResponse?.extraData?.rewardSharePrivateKey && (txnResponse?.data?.message?.includes('multiple') || txnResponse?.data?.message?.includes('SELF_SHARE_EXISTS'))) { if (txnResponse.extraData.rewardSharePrivateKey && (txnResponse.data.message.includes('multiple') || txnResponse.data.message.includes('SELF_SHARE_EXISTS'))) {
return err6string return err6string
} }
if (txnResponse.success === false && txnResponse.message) { if (txnResponse.success === false && txnResponse.message) {
throw (txnResponse); throw (txnResponse)
} else if ( } else if (txnResponse.success === true && !txnResponse.data.error) {
txnResponse.success === true && return err6string
!txnResponse.data.error
) {
return err6string;
} else { } else {
throw (txnResponse) throw (txnResponse)
} }
@ -617,36 +704,35 @@ class StartMintingNow extends LitElement {
let myTransaction = await makeTransactionRequest(lastRef) let myTransaction = await makeTransactionRequest(lastRef)
getTxnRequestResponse(myTransaction); getTxnRequestResponse(myTransaction)
return myTransaction?.extraData?.rewardSharePrivateKey return myTransaction.extraData.rewardSharePrivateKey
} }
const getLastRef = async () => { const getLastRef = async () => {
const url = `${nodeUrl}/addresses/lastreference/${address}` let myRef = await parentEpml.request('apiCall', {
const res = await fetch(url) type: 'api',
const data = await res.text() url: `/addresses/lastreference/${address}`
return data })
return myRef
} }
const startMinting = async () => { const startMinting = async () => {
this.openDialogRewardShare = true this.openDialogRewardShare = true
this.errorMsg = '' this.errorMsg = ''
const address = window.parent.reduxStore.getState().app?.selectedAddress?.address
const findMintingAccountsFromUser = this.mintingAccountData.filter((ma) => ma.recipientAccount === address && ma.mintingAccount === address) const findMintingAccountsFromUser = this.mintingAccountData.filter((ma) => ma.recipientAccount === address && ma.mintingAccount === address)
if(findMintingAccountsFromUser.length > 2){ if(findMintingAccountsFromUser.length > 2) {
this.errorMsg = translate("startminting.smchange10") this.errorMsg = translate("startminting.smchange10")
return; return
} }
try { try {
this.privateRewardShareKey = await createSponsorshipKey() this.privateRewardShareKey = await createSponsorshipKey()
this.confirmRelationship(publicAddress) this.confirmRelationship(publicAddress)
} catch (error) { } catch (error) {
console.log({ error }) this.errorMsg = error.data.message || this.renderErrorMsg4()
this.errorMsg = error?.data?.message || this.renderErrorMsg4() return
return;
} }
} }
@ -670,7 +756,7 @@ class StartMintingNow extends LitElement {
${this.openDialogRewardShare ? html` ${this.openDialogRewardShare ? html`
<div class="dialogCustom"> <div class="dialogCustom">
<div class="dialogCustomInner"> <div class="dialogCustomInner">
<div class="dialog-header" > <div class="dialog-header">
<div class="row"> <div class="row">
<h1>In progress</h1> <h1>In progress</h1>
<div class=${`smallLoading marginLoader ${this.status > 3 && 'hide'}`}></div> <div class=${`smallLoading marginLoader ${this.status > 3 && 'hide'}`}></div>
@ -724,24 +810,28 @@ class StartMintingNow extends LitElement {
</div> </div>
<div class="modalFooter"> <div class="modalFooter">
${this.errorMsg || this.status === 5 ? html` ${this.errorMsg || this.status === 5 ? html`
<mwc-button <mwc-button
slot="primaryAction" slot="primaryAction"
@click=${() => { @click=${() => {
this.openDialogRewardShare = false this.openDialogRewardShare = false
this.errorMsg = '' this.errorMsg = ''
}} }}
class="red" class="red"
> >
${translate("general.close")} ${translate("general.close")}
</mwc-button> </mwc-button>
` : '' } ` : '' }
</div>
</div> </div>
` : ""}
` : html`
<div class="start-minting-wrapper">
<a href="../become-minter/index.html">
<my-button label="${translate('tabmenu.tm2')}"></my-button>
</a>
</div> </div>
</div> `}
`
` : ""}
` : ''}
`;
} }
} }
window.customElements.define('start-minting-now', StartMintingNow) window.customElements.define('start-minting-now', StartMintingNow)
@ -750,8 +840,8 @@ class MyButton extends LitElement {
static properties = { static properties = {
onClick: { type: Function }, onClick: { type: Function },
isLoading: { type: Boolean }, isLoading: { type: Boolean },
label: { type: String }, label: { type: String }
}; }
static styles = css` static styles = css`
vaadin-button { vaadin-button {
@ -769,13 +859,13 @@ class MyButton extends LitElement {
vaadin-button:hover { vaadin-button:hover {
opacity: 0.9; opacity: 0.9;
} }
`; `
constructor() { constructor() {
super(); super()
this.onClick = () => {}; this.onClick = () => {}
this.isLoading = false; this.isLoading = false
this.label = ''; this.label = ''
} }
render() { render() {
@ -788,7 +878,7 @@ class MyButton extends LitElement {
? html`${this.label}` ? html`${this.label}`
: html`<paper-spinner-lite active></paper-spinner-lite>`} : html`<paper-spinner-lite active></paper-spinner-lite>`}
</vaadin-button> </vaadin-button>
`; `
} }
} }
customElements.define('my-button', MyButton) customElements.define('my-button', MyButton)

View File

@ -180,7 +180,6 @@ class Puzzles extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -308,7 +307,7 @@ class Puzzles extends LitElement {
this.puzzles = _puzzles; this.puzzles = _puzzles;
setTimeout(updatePuzzles, 20000) setTimeout(updatePuzzles, 60000)
} }
let configLoaded = false let configLoaded = false
@ -330,6 +329,18 @@ class Puzzles extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -544,7 +544,6 @@ class QApps extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.showapps() this.showapps()
@ -624,6 +623,18 @@ class QApps extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -20,10 +20,9 @@ import { Loader } from '../../../utils/loader.js';
import { QORT_DECIMALS } from '../../../../../crypto/api/constants' import { QORT_DECIMALS } from '../../../../../crypto/api/constants'
import nacl from '../../../../../crypto/api/deps/nacl-fast.js' import nacl from '../../../../../crypto/api/deps/nacl-fast.js'
import ed2curve from '../../../../../crypto/api/deps/ed2curve.js' import ed2curve from '../../../../../crypto/api/deps/ed2curve.js'
import { mimeToExtensionMap } from '../../components/qdn-action-constants' import { mimeToExtensionMap } from '../../components/qdn-action-constants';
import { base64ToUint8Array, encryptData, fileToBase64, uint8ArrayToBase64 } from '../../components/qdn-action-encryption' import { base64ToUint8Array, decryptDeprecatedSingle, decryptGroupData, encryptDataGroup, fileToBase64, uint8ArrayStartsWith, uint8ArrayToBase64 } from '../../components/qdn-action-encryption';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class WebBrowser extends LitElement { class WebBrowser extends LitElement {
static get properties() { static get properties() {
@ -630,57 +629,52 @@ class WebBrowser extends LitElement {
} }
case actions.DECRYPT_DATA: { case actions.DECRYPT_DATA: {
const requiredFields = ['encryptedData', 'publicKey'];
const missingFields = [];
requiredFields.forEach((field) => { const { encryptedData, publicKey } = data
if (!data[field]) {
missingFields.push(field);
}
});
if (missingFields.length > 0) { try {
const missingFieldsString = missingFields.join(', ');
const errorMsg = `Missing fields: ${missingFieldsString}`
let data = {}; let data = {};
if (!encryptedData) {
const errorMsg = `Missing fields: encryptedData`
data['error'] = errorMsg;
response = JSON.stringify(data);
break
}
const uint8Array = base64ToUint8Array(encryptedData)
const startsWithQortalEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalEncryptedData");
if (startsWithQortalEncryptedData) {
if (!publicKey) {
const errorMsg = `Missing fields: publicKey`
data['error'] = errorMsg;
response = JSON.stringify(data);
break
}
const decryptedDataToBase64 = decryptDeprecatedSingle(uint8Array, publicKey)
response = JSON.stringify(decryptedDataToBase64);
break;
}
const startsWithQortalGroupEncryptedData = uint8ArrayStartsWith(uint8Array, "qortalGroupEncryptedData");
if (startsWithQortalGroupEncryptedData) {
const decryptedData = decryptGroupData(encryptedData)
const decryptedDataToBase64 = uint8ArrayToBase64(decryptedData)
response = JSON.stringify(decryptedDataToBase64);
break;
}
const errorMsg = "Unable to decrypt"
data['error'] = errorMsg; data['error'] = errorMsg;
response = JSON.stringify(data); response = JSON.stringify(data);
break break
}
const { encryptedData, publicKey } = data
try {
const uint8Array = base64ToUint8Array(encryptedData)
const combinedData = uint8Array
const str = "qortalEncryptedData";
const strEncoder = new TextEncoder();
const strUint8Array = strEncoder.encode(str);
const strData = combinedData.slice(0, strUint8Array.length);
const nonce = combinedData.slice(strUint8Array.length, strUint8Array.length + 24);
const _encryptedData = combinedData.slice(strUint8Array.length + 24);
const privateKey = window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey
const _publicKey = window.parent.Base58.decode(publicKey)
if (!privateKey || !_publicKey) {
data['error'] = "Unable to retrieve keys"
response = JSON.stringify(data);
break
}
const convertedPrivateKey = ed2curve.convertSecretKey(privateKey)
const convertedPublicKey = ed2curve.convertPublicKey(_publicKey)
const sharedSecret = new Uint8Array(32);
nacl.lowlevel.crypto_scalarmult(sharedSecret, convertedPrivateKey, convertedPublicKey)
const _chatEncryptionSeed = new window.parent.Sha256().process(sharedSecret).finish().result
const _decryptedData = nacl.secretbox.open(_encryptedData, nonce, _chatEncryptionSeed)
const decryptedDataToBase64 = uint8ArrayToBase64(_decryptedData)
response = JSON.stringify(decryptedDataToBase64);
break;
} catch (error) { } catch (error) {
const data = {}; const data = {};
@ -690,6 +684,7 @@ class WebBrowser extends LitElement {
break break
} }
} }
case actions.GET_LIST_ITEMS: { case actions.GET_LIST_ITEMS: {
const requiredFields = ['list_name']; const requiredFields = ['list_name'];
const missingFields = []; const missingFields = [];
@ -984,9 +979,9 @@ class WebBrowser extends LitElement {
identifier = 'default'; identifier = 'default';
} }
if (data.encrypt && !data.recipientPublicKey) { if (data.encrypt && (!data.publicKeys || (Array.isArray(data.publicKeys) && data.publicKeys.length === 0))) {
let data = {}; let data = {};
data['error'] = "Encrypting data requires the recipient's public key"; data['error'] = "Encrypting data requires public keys";
response = JSON.stringify(data); response = JSON.stringify(data);
break break
} }
@ -996,14 +991,17 @@ class WebBrowser extends LitElement {
response = JSON.stringify(data); response = JSON.stringify(data);
break break
} }
if (data.file) {
data64 = await fileToBase64(data.file)
}
if (data.encrypt) { if (data.encrypt) {
try { try {
const encryptDataResponse = encryptData({ const encryptDataResponse = encryptDataGroup({
data64, recipientPublicKey: data.recipientPublicKey data64, publicKeys: data.publicKeys
}) })
if (encryptDataResponse.encryptedData) { if (encryptDataResponse) {
data64 = encryptDataResponse.encryptedData data64 = encryptDataResponse
} }
} catch (error) { } catch (error) {
@ -1017,6 +1015,7 @@ class WebBrowser extends LitElement {
} }
const res2 = await showModalAndWait( const res2 = await showModalAndWait(
actions.PUBLISH_QDN_RESOURCE, actions.PUBLISH_QDN_RESOURCE,
{ {
@ -1109,9 +1108,9 @@ class WebBrowser extends LitElement {
response = JSON.stringify(data); response = JSON.stringify(data);
break break
} }
if (data.encrypt && !data.recipientPublicKey) { if (data.encrypt && (!data.publicKeys || (Array.isArray(data.publicKeys) && data.publicKeys.length === 0))) {
let data = {}; let data = {};
data['error'] = "Encrypting data requires the recipient's public key"; data['error'] = "Encrypting data requires public keys";
response = JSON.stringify(data); response = JSON.stringify(data);
break break
} }
@ -1169,14 +1168,19 @@ class WebBrowser extends LitElement {
if (!data.encrypt && service.endsWith("_PRIVATE")) { if (!data.encrypt && service.endsWith("_PRIVATE")) {
throw new Error("Only encrypted data can go into private services") throw new Error("Only encrypted data can go into private services")
} }
if (data.file) {
data64 = await fileToBase64(data.file)
}
if (data.encrypt) { if (data.encrypt) {
try { try {
const encryptDataResponse = encryptData({
data64, recipientPublicKey: data.recipientPublicKey const encryptDataResponse = encryptDataGroup({
data64, publicKeys: data.publicKeys
}) })
if (encryptDataResponse.encryptedData) { if (encryptDataResponse) {
data64 = encryptDataResponse.encryptedData data64 = encryptDataResponse
} }
} catch (error) { } catch (error) {
@ -2669,6 +2673,18 @@ class WebBrowser extends LitElement {
}); });
} }
}); });
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -441,7 +441,6 @@ class DataManagement extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.showManagement() this.showManagement()
@ -494,6 +493,18 @@ class DataManagement extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -318,7 +318,6 @@ class PublishData extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -343,6 +342,18 @@ class PublishData extends LitElement {
window.parent.electronAPI.showMyMenu() window.parent.electronAPI.showMyMenu()
}) })
} }
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -398,7 +398,6 @@ class Websites extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
this.showWebsites() this.showWebsites()
@ -478,6 +477,18 @@ class Websites extends LitElement {
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

View File

@ -211,7 +211,6 @@ class RewardShare extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -238,12 +237,13 @@ class RewardShare extends LitElement {
} }
const updateRewardshares = () => { const updateRewardshares = () => {
this.rewardShares = []
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: `/addresses/rewardshares?involving=${this.selectedAddress.address}` url: `/addresses/rewardshares?involving=${this.selectedAddress.address}`
}).then(res => { }).then(res => {
setTimeout(() => { this.rewardShares = res }, 1) this.rewardShares = res
}) })
setTimeout(updateRewardshares, this.config.user.nodeSettings.pingInterval) setTimeout(updateRewardshares, 60000)
} }
let configLoaded = false let configLoaded = false
@ -266,6 +266,18 @@ class RewardShare extends LitElement {
}) })
parentEpml.imReady() parentEpml.imReady()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
changeTheme() { changeTheme() {

File diff suppressed because it is too large Load Diff

View File

@ -7,20 +7,16 @@ let closeGracefully = false
let isCalled = false let isCalled = false
let retryOnClose = false let retryOnClose = false
let blockFirstCall = true let blockFirstCall = true
let nodeStatusSocketObject let nodeStatusSocketObject
let nodeStatusSocketTimeout let nodeStatusSocketTimeout
let nodeStatusSocketcloseGracefully = false let nodeStatusSocketcloseGracefully = false
let nodeStatusCount = 0 let nodeStatusCount = 0
let nodeStatusRetryOnClose = false let nodeStatusRetryOnClose = false
let nodeStateCall = false let nodeStateCall = false
let isLoggedIn = false let isLoggedIn = false
let oldAccountInfo let oldAccountInfo
parentEpml.subscribe('logged_in', loggedIn => { parentEpml.subscribe('logged_in', loggedIn => {
if (loggedIn === 'true') { if (loggedIn === 'true') {
isLoggedIn = true isLoggedIn = true
} else { } else {
@ -29,35 +25,28 @@ parentEpml.subscribe('logged_in', loggedIn => {
}) })
const setAccountInfo = async (addr) => { const setAccountInfo = async (addr) => {
const names = await parentEpml.request('apiCall', { const names = await parentEpml.request('apiCall', {
url: `/names/address/${addr}` url: `/names/address/${addr}`
}) })
const addressInfo = await parentEpml.request('apiCall', { const addressInfo = await parentEpml.request('apiCall', {
url: `/addresses/${addr}` url: `/addresses/${addr}`
}) })
let accountInfo = { let accountInfo = {
names: names, names: names,
addressInfo: addressInfo addressInfo: addressInfo
} }
if (window.parent._.isEqual(oldAccountInfo, accountInfo) === true) { if (window.parent._.isEqual(oldAccountInfo, accountInfo) === true) {
return return
} else { } else {
parentEpml.request('setAccountInfo', accountInfo) parentEpml.request('setAccountInfo', accountInfo)
oldAccountInfo = accountInfo oldAccountInfo = accountInfo
} }
} }
const doNodeInfo = async () => { const doNodeInfo = async () => {
const nodeInfo = await parentEpml.request('apiCall', { const nodeInfo = await parentEpml.request('apiCall', {
url: '/admin/info' url: '/admin/info'
}) })
parentEpml.request('updateNodeInfo', nodeInfo) parentEpml.request('updateNodeInfo', nodeInfo)
} }
@ -65,71 +54,57 @@ let initStateCount = 0
let oldState let oldState
const closeSockets = () => { const closeSockets = () => {
socketObject.close()
socketObject.close();
closeGracefully = true closeGracefully = true
nodeStatusSocketObject.close()
nodeStatusSocketObject.close();
nodeStatusSocketcloseGracefully = true nodeStatusSocketcloseGracefully = true
} }
export const startConfigWatcher = () => { export const startConfigWatcher = () => {
parentEpml.ready().then(() => { parentEpml.ready().then(() => {
parentEpml.subscribe('node_config', c => { parentEpml.subscribe('node_config', c => {
if (initStateCount === 0) { if (initStateCount === 0) {
let _oldState = JSON.parse(c) let _oldState = JSON.parse(c)
oldState = { node: _oldState.node, knownNodes: _oldState.knownNodes } oldState = { node: _oldState.node, knownNodes: _oldState.knownNodes }
initStateCount = initStateCount + 1 initStateCount = initStateCount + 1
nodeStateCall = true nodeStateCall = true
isCalled = true isCalled = true
socketObject !== undefined ? closeSockets() : undefined; socketObject !== undefined ? closeSockets() : undefined
nodeStatusSocketObject !== undefined ? closeSockets() : undefined; nodeStatusSocketObject !== undefined ? closeSockets() : undefined
initNodeStatusCall(oldState) initNodeStatusCall(oldState)
pingactiveBlockSocket() pingactiveBlockSocket()
// Call doNodeInfo // Call doNodeInfo
doNodeInfo() doNodeInfo()
} }
let _newState = JSON.parse(c)
let _newState = JSON.parse(c);
let newState = { node: _newState.node, knownNodes: _newState.knownNodes } let newState = { node: _newState.node, knownNodes: _newState.knownNodes }
if (window.parent._.isEqual(oldState, newState) === true) { if (window.parent._.isEqual(oldState, newState) === true) {
return return
} else { } else {
oldState = newState oldState = newState
nodeStateCall = true nodeStateCall = true
isCalled = true isCalled = true
socketObject !== undefined ? closeSockets() : undefined; socketObject !== undefined ? closeSockets() : undefined
nodeStatusSocketObject !== undefined ? closeSockets() : undefined; nodeStatusSocketObject !== undefined ? closeSockets() : undefined
initNodeStatusCall(newState) initNodeStatusCall(newState)
pingactiveBlockSocket() pingactiveBlockSocket()
// Call doNodeInfo // Call doNodeInfo
doNodeInfo() doNodeInfo()
} }
}) })
}) })
parentEpml.imReady() parentEpml.imReady()
} }
const processBlock = (blockObject) => { const processBlock = (blockObject) => {
parentEpml.request('updateBlockInfo', blockObject) parentEpml.request('updateBlockInfo', blockObject)
} }
const doNodeStatus = async (nodeStatusObject) => { const doNodeStatus = async (nodeStatusObject) => {
parentEpml.request('updateNodeStatus', nodeStatusObject) parentEpml.request('updateNodeStatus', nodeStatusObject)
} }
const initNodeStatusCall = (nodeConfig) => { const initNodeStatusCall = (nodeConfig) => {
if (nodeConfig.node == 0) { if (nodeConfig.node == 0) {
pingNodeStatusSocket() pingNodeStatusSocket()
} else if (nodeConfig.node == 1) { } else if (nodeConfig.node == 1) {
@ -143,193 +118,131 @@ const initNodeStatusCall = (nodeConfig) => {
} }
const initBlockSocket = () => { const initBlockSocket = () => {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let activeBlockSocketLink let activeBlockSocketLink
if (window.parent.location.protocol === "https:") { if (window.parent.location.protocol === "https:") {
activeBlockSocketLink = `wss://${nodeUrl}/websockets/blocks`
activeBlockSocketLink = `wss://${nodeUrl}/websockets/blocks`;
} else { } else {
activeBlockSocketLink = `ws://${nodeUrl}/websockets/blocks`
activeBlockSocketLink = `ws://${nodeUrl}/websockets/blocks`;
} }
const activeBlockSocket = new WebSocket(activeBlockSocketLink)
const activeBlockSocket = new WebSocket(activeBlockSocketLink);
// Open Connection // Open Connection
activeBlockSocket.onopen = (e) => { activeBlockSocket.onopen = (e) => {
console.log(`[SOCKET-BLOCKS]: Connected.`);
closeGracefully = false closeGracefully = false
socketObject = activeBlockSocket socketObject = activeBlockSocket
initial = initial + 1 initial = initial + 1
} }
// Message Event // Message Event
activeBlockSocket.onmessage = (e) => { activeBlockSocket.onmessage = (e) => {
processBlock(JSON.parse(e.data))
processBlock(JSON.parse(e.data));
if (isLoggedIn) { if (isLoggedIn) {
// Call Set Account Info... // Call Set Account Info...
setAccountInfo(window.parent.reduxStore.getState().app.selectedAddress.address) setAccountInfo(window.parent.reduxStore.getState().app.selectedAddress.address)
} }
} }
// Closed Event // Closed Event
activeBlockSocket.onclose = () => { activeBlockSocket.onclose = () => {
processBlock({})
console.log(`[SOCKET-BLOCKS]: CLOSED`);
processBlock({});
blockFirstCall = true blockFirstCall = true
clearInterval(activeBlockSocketTimeout) clearInterval(activeBlockSocketTimeout)
if (closeGracefully === false && initial <= 52) { if (closeGracefully === false && initial <= 52) {
if (initial <= 52) { if (initial <= 52) {
retryOnClose = true retryOnClose = true
setTimeout(pingactiveBlockSocket, 10000) setTimeout(pingactiveBlockSocket, 10000)
initial = initial + 1 initial = initial + 1
} else { } else {
// ... Stop retrying... // ... Stop retrying...
retryOnClose = false retryOnClose = false
} }
} }
} }
// Error Event // Error Event
activeBlockSocket.onerror = (e) => { activeBlockSocket.onerror = (e) => {
console.log(`[SOCKET-BLOCKS]: ${e.type}`);
blockFirstCall = true blockFirstCall = true
processBlock({}); processBlock({})
} }
if (blockFirstCall) { if (blockFirstCall) {
parentEpml.request('apiCall', { parentEpml.request('apiCall', {
url: '/blocks/last' url: '/blocks/last'
}).then(res => { }).then(res => {
processBlock(res) processBlock(res)
blockFirstCall = false blockFirstCall = false
}) })
} }
} }
const pingactiveBlockSocket = () => { const pingactiveBlockSocket = () => {
if (isCalled) { if (isCalled) {
isCalled = false isCalled = false
initBlockSocket() initBlockSocket()
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000) activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
} else if (retryOnClose) { } else if (retryOnClose) {
retryOnClose = false retryOnClose = false
clearTimeout(activeBlockSocketTimeout) clearTimeout(activeBlockSocketTimeout)
initBlockSocket() initBlockSocket()
isCalled = true isCalled = true
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000) activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
} else { } else {
socketObject.send("non-integer ping") socketObject.send("non-integer ping")
activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000) activeBlockSocketTimeout = setTimeout(pingactiveBlockSocket, 295000)
} }
} }
const initNodeStatusSocket = () => { const initNodeStatusSocket = () => {
let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] let myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
let nodeUrl = myNode.domain + ":" + myNode.port let nodeUrl = myNode.domain + ":" + myNode.port
let activeNodeStatusSocketLink let activeNodeStatusSocketLink
if (window.parent.location.protocol === "https:") { if (window.parent.location.protocol === "https:") {
activeNodeStatusSocketLink = `wss://${nodeUrl}/websockets/admin/status`
activeNodeStatusSocketLink = `wss://${nodeUrl}/websockets/admin/status`;
} else { } else {
activeNodeStatusSocketLink = `ws://${nodeUrl}/websockets/admin/status`
activeNodeStatusSocketLink = `ws://${nodeUrl}/websockets/admin/status`;
} }
const activeNodeStatusSocket = new WebSocket(activeNodeStatusSocketLink)
const activeNodeStatusSocket = new WebSocket(activeNodeStatusSocketLink);
// Open Connection // Open Connection
activeNodeStatusSocket.onopen = (e) => { activeNodeStatusSocket.onopen = (e) => {
console.log(`[SOCKET-NODE-STATUS]: Connected.`);
nodeStatusSocketcloseGracefully = false nodeStatusSocketcloseGracefully = false
nodeStatusSocketObject = activeNodeStatusSocket nodeStatusSocketObject = activeNodeStatusSocket
nodeStatusCount = nodeStatusCount + 1 nodeStatusCount = nodeStatusCount + 1
} }
// Message Event // Message Event
activeNodeStatusSocket.onmessage = (e) => { activeNodeStatusSocket.onmessage = (e) => {
doNodeStatus(JSON.parse(e.data)) doNodeStatus(JSON.parse(e.data))
} }
// Closed Event // Closed Event
activeNodeStatusSocket.onclose = () => { activeNodeStatusSocket.onclose = () => {
doNodeStatus({})
console.log(`[SOCKET-NODE-STATUS]: CLOSED`);
doNodeStatus({});
clearInterval(nodeStatusSocketTimeout) clearInterval(nodeStatusSocketTimeout)
if (nodeStatusSocketcloseGracefully === false && nodeStatusCount <= 52) { if (nodeStatusSocketcloseGracefully === false && nodeStatusCount <= 52) {
if (nodeStatusCount <= 52) { if (nodeStatusCount <= 52) {
nodeStatusRetryOnClose = true nodeStatusRetryOnClose = true
setTimeout(pingNodeStatusSocket, 10000) setTimeout(pingNodeStatusSocket, 10000)
nodeStatusCount = nodeStatusCount + 1 nodeStatusCount = nodeStatusCount + 1
} else { } else {
// ... Stop retrying... // ... Stop retrying...
nodeStatusRetryOnClose = false nodeStatusRetryOnClose = false
} }
} }
} }
// Error Event // Error Event
activeNodeStatusSocket.onerror = (e) => { activeNodeStatusSocket.onerror = (e) => {
doNodeStatus({})
console.log(`[SOCKET-NODE-STATUS]: ${e.type}`);
doNodeStatus({});
} }
} }
const pingNodeStatusSocket = () => { const pingNodeStatusSocket = () => {
if (nodeStateCall) { if (nodeStateCall) {
clearTimeout(nodeStatusSocketTimeout) clearTimeout(nodeStatusSocketTimeout)
initNodeStatusSocket() initNodeStatusSocket()
nodeStateCall = false nodeStateCall = false
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000) nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
} else if (nodeStatusRetryOnClose) { } else if (nodeStatusRetryOnClose) {
nodeStatusRetryOnClose = false nodeStatusRetryOnClose = false
clearTimeout(nodeStatusSocketTimeout) clearTimeout(nodeStatusSocketTimeout)
initNodeStatusSocket() initNodeStatusSocket()
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000) nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
} else { } else {
nodeStatusSocketObject.send("non-integer ping") nodeStatusSocketObject.send("non-integer ping")
nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000) nodeStatusSocketTimeout = setTimeout(pingNodeStatusSocket, 295000)
} }

View File

@ -45,7 +45,7 @@ const sortActiveChat = (activeChatObject, localChatHeads) => {
let results = newActiveChats.filter(newChat => { let results = newActiveChats.filter(newChat => {
let value = oldActiveChats.some(oldChat => newChat.timestamp === oldChat.timestamp) let value = oldActiveChats.some(oldChat => newChat.timestamp === oldChat.timestamp)
return !value return !value
}); })
results.forEach(chat => { results.forEach(chat => {
@ -103,8 +103,6 @@ const chatHeadWatcher = (activeChats) => {
} }
} catch (e) { } catch (e) {
console.error(e)
} }
} }
@ -128,13 +126,13 @@ 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}?encoding=BASE64`; 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}?encoding=BASE64`; 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 = () => {
@ -147,16 +145,14 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
// Message Event // Message Event
activeChatSocket.onmessage = (e) => { activeChatSocket.onmessage = (e) => {
if (e.data === 'pong') { if (e.data === 'pong') {
clearTimeout(timeoutId); clearTimeout(timeoutId)
activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 45000) activeChatSocketTimeout = setTimeout(pingActiveChatSocket, 45000)
return return
} }
try { try {
chatHeadWatcher(JSON.parse(e.data)) chatHeadWatcher(JSON.parse(e.data))
} catch (error) { } catch (error) {
} }
} }
// Closed Event // Closed Event
@ -171,8 +167,6 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
// Error Event // Error Event
activeChatSocket.onerror = (e) => { activeChatSocket.onerror = (e) => {
console.log(`[SOCKET]: ${e.type}`);
} }
} }
@ -197,9 +191,9 @@ parentEpml.subscribe('logged_in', async isLoggedIn => {
socketObject.send('ping') socketObject.send('ping')
timeoutId = setTimeout(() => { timeoutId = setTimeout(() => {
socketObject.close(); socketObject.close()
clearTimeout(activeChatSocketTimeout) clearTimeout(activeChatSocketTimeout)
}, 5000); }, 5000)
} }
} else { } else {

View File

@ -2100,7 +2100,6 @@ class TradeBotPortal extends LitElement {
} }
firstUpdated() { firstUpdated() {
let _this = this let _this = this
this.changeTheme() this.changeTheme()
@ -2281,6 +2280,18 @@ class TradeBotPortal extends LitElement {
this.dgbTradebook() this.dgbTradebook()
this.rvnTradebook() this.rvnTradebook()
this.arrrTradebook() this.arrrTradebook()
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
renderAutoLockButton() { renderAutoLockButton() {

View File

@ -1417,7 +1417,6 @@ class TradePortal extends LitElement {
} }
firstUpdated() { firstUpdated() {
let _this = this let _this = this
this.changeTheme() this.changeTheme()
@ -1505,42 +1504,42 @@ class TradePortal extends LitElement {
const getQortBtcPrice = () => { const getQortBtcPrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/BITCOIN?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/BITCOIN?inverse=true` }).then((res) => {
setTimeout(() => { this.qortbtc = (Number(res) / 1e8).toFixed(8) }, 1) this.qortbtc = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortBtcPrice, 300000) setTimeout(getQortBtcPrice, 300000)
} }
const getQortLtcPrice = () => { const getQortLtcPrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/LITECOIN?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/LITECOIN?inverse=true` }).then((res) => {
setTimeout(() => { this.qortltc = (Number(res) / 1e8).toFixed(8) }, 1) this.qortltc = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortLtcPrice, 300000) setTimeout(getQortLtcPrice, 300000)
} }
const getQortDogePrice = () => { const getQortDogePrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/DOGECOIN?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/DOGECOIN?inverse=true` }).then((res) => {
setTimeout(() => { this.qortdoge = (Number(res) / 1e8).toFixed(8) }, 1) this.qortdoge = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortDogePrice, 300000) setTimeout(getQortDogePrice, 300000)
} }
const getQortDgbPrice = () => { const getQortDgbPrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/DIGIBYTE?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/DIGIBYTE?inverse=true` }).then((res) => {
setTimeout(() => { this.qortdgb = (Number(res) / 1e8).toFixed(8) }, 1) this.qortdgb = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortDgbPrice, 300000) setTimeout(getQortDgbPrice, 300000)
} }
const getQortRvnPrice = () => { const getQortRvnPrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/RAVENCOIN?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/RAVENCOIN?inverse=true` }).then((res) => {
setTimeout(() => { this.qortrvn = (Number(res) / 1e8).toFixed(8) }, 1) this.qortrvn = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortRvnPrice, 300000) setTimeout(getQortRvnPrice, 300000)
} }
const getQortArrrPrice = () => { const getQortArrrPrice = () => {
parentEpml.request("apiCall", { url: `/crosschain/price/PIRATECHAIN?inverse=true` }).then((res) => { parentEpml.request("apiCall", { url: `/crosschain/price/PIRATECHAIN?inverse=true` }).then((res) => {
setTimeout(() => { this.qortarrr = (Number(res) / 1e8).toFixed(8) }, 1) this.qortarrr = (Number(res) / 1e8).toFixed(8)
}) })
setTimeout(getQortArrrPrice, 300000) setTimeout(getQortArrrPrice, 300000)
} }
@ -1614,6 +1613,18 @@ class TradePortal extends LitElement {
parentEpml.imReady() parentEpml.imReady()
setTimeout(() => this.shadowRoot.querySelector('[slot="vaadin-grid-cell-content-3"]').setAttribute('title', 'Last Seen'), 3000) setTimeout(() => this.shadowRoot.querySelector('[slot="vaadin-grid-cell-content-3"]').setAttribute('title', 'Last Seen'), 3000)
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
renderTradeLockButton() { renderTradeLockButton() {

View File

@ -2819,7 +2819,6 @@ class MultiWallet extends LitElement {
} }
firstUpdated() { firstUpdated() {
this.changeTheme() this.changeTheme()
this.changeLanguage() this.changeLanguage()
@ -2902,6 +2901,19 @@ class MultiWallet extends LitElement {
window.parent.electronAPI.showMyMenu() window.parent.electronAPI.showMyMenu()
}) })
} }
this.clearConsole()
setInterval(() => {
this.clearConsole()
}, 60000)
}
clearConsole() {
if (!isElectron()) {
} else {
console.clear()
window.parent.electronAPI.clearCache()
}
} }
renderWalletLockButton() { renderWalletLockButton() {