Update UI
Refactor and added new functioms
This commit is contained in:
parent
940f9f82f8
commit
fa29ff4c43
@ -26,8 +26,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.17.1 ``` (LTS: Hydrogen supported by Electron V27) <br/>
|
``` nvm install v20.11.1 ``` (LTS: Iron supported by Electron V30) <br/>
|
||||||
``` npm --location=global install npm@10.5.0 ``` <br/>
|
``` npm --location=global install npm@10.7.0 ``` <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.
|
||||||
|
|
||||||
|
17
build.js
17
build.js
@ -1,28 +1,23 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const uiCore = require('./core/ui-core.js')
|
const uiCore = require('./core/ui-core.js')
|
||||||
|
const config = require('./config/config.js')
|
||||||
|
const pluginsController = require('./plugins/default-plugins.js')
|
||||||
const generateBuildConfig = uiCore('generate_build_config')
|
const generateBuildConfig = uiCore('generate_build_config')
|
||||||
const build = uiCore('build')
|
const build = uiCore('build')
|
||||||
|
|
||||||
const config = require('./config/config.js')
|
|
||||||
|
|
||||||
const pluginsController = require('./plugins/default-plugins.js')
|
|
||||||
const buildDefalutPlugins = pluginsController('build')
|
const buildDefalutPlugins = pluginsController('build')
|
||||||
|
|
||||||
|
|
||||||
srcConfig = {
|
srcConfig = {
|
||||||
...config.build,
|
...config.build,
|
||||||
options: {
|
options: {
|
||||||
...config.build.options,
|
...config.build.options,
|
||||||
outputDir: path.join(__dirname, '/builtWWW'),
|
outputDir: path.join(__dirname, '/builtWWW'),
|
||||||
sassOutputDir: path.join(__dirname, '/builtWWW/styles.bundle.css'),
|
sassOutputDir: path.join(__dirname, '/builtWWW/styles.bundle.css')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { buildConfig, inlineConfigs } = generateBuildConfig(srcConfig)
|
const { buildConfig, inlineConfigs } = generateBuildConfig(srcConfig)
|
||||||
|
|
||||||
build(buildConfig.options, buildConfig.outputs, buildConfig.outputOptions, buildConfig.inputOptions, inlineConfigs)
|
build(buildConfig.options, buildConfig.outputs, buildConfig.outputOptions, buildConfig.inputOptions, inlineConfigs).then(() => {
|
||||||
.then(() => {
|
console.log("Building and Bundling Plugins")
|
||||||
console.log("Building and Bundling Plugins");
|
|
||||||
buildDefalutPlugins()
|
buildDefalutPlugins()
|
||||||
})
|
})
|
@ -1,14 +1,19 @@
|
|||||||
let config = require('./default.config.js')
|
let config = require('./default.config.js')
|
||||||
|
|
||||||
let userConfig = {}
|
let userConfig = {}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
userConfig = require('./customConfig.js')
|
userConfig = require('./customConfig.js')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(e)
|
console.warn(e)
|
||||||
console.warn('Error loading user config')
|
console.warn('Error loading user config')
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkKeys = (storeObj, newObj) => {
|
const checkKeys = (storeObj, newObj) => {
|
||||||
for (const key in newObj) {
|
for (const key in newObj) {
|
||||||
if (!Object.prototype.hasOwnProperty.call(storeObj, key)) return
|
if (!Object.prototype.hasOwnProperty.call(storeObj, key)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof newObj[key] === 'object') {
|
if (typeof newObj[key] === 'object') {
|
||||||
storeObj[key] = checkKeys(storeObj[key], newObj[key])
|
storeObj[key] = checkKeys(storeObj[key], newObj[key])
|
||||||
@ -16,6 +21,7 @@ const checkKeys = (storeObj, newObj) => {
|
|||||||
storeObj[key] = newObj[key]
|
storeObj[key] = newObj[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeObj
|
return storeObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,4 @@ const styles = require('./styles.config.js')
|
|||||||
const build = require('./build.config.js')
|
const build = require('./build.config.js')
|
||||||
const user = require('./user.config.js')
|
const user = require('./user.config.js')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = { coin, styles, build, user, crypto }
|
||||||
coin,
|
|
||||||
styles,
|
|
||||||
build,
|
|
||||||
user,
|
|
||||||
crypto
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
const uiCore = require('../core/ui-core.js')
|
const uiCore = require('../core/ui-core.js')
|
||||||
const defaultConfig = uiCore('default_config')
|
const defaultConfig = uiCore('default_config')
|
||||||
|
|
||||||
|
|
||||||
module.exports = defaultConfig
|
module.exports = defaultConfig
|
@ -1,10 +1,11 @@
|
|||||||
const user = require('./default.config.js').user
|
const user = require('./default.config.js').user
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
node: 0, // set to mainnet
|
node: 0, // set to mainnet
|
||||||
server: {
|
server: {
|
||||||
primary: {
|
primary: {
|
||||||
port: 12388, // set as default UI port
|
port: 12388, // set as default UI port
|
||||||
address: '0.0.0.0', // can specify an IP for a fixed bind
|
address: '0.0.0.0' // can specify an IP for a fixed bind
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@ const crypto = {
|
|||||||
staticSalt: '4ghkVQExoneGqZqHTMMhhFfxXsVg2A75QeS1HCM5KAih', // Base58 encoded
|
staticSalt: '4ghkVQExoneGqZqHTMMhhFfxXsVg2A75QeS1HCM5KAih', // Base58 encoded
|
||||||
bcryptRounds: 11, // Note it's kinda bcryptRounds * log.2.16, cause it runs on all 16 threads
|
bcryptRounds: 11, // Note it's kinda bcryptRounds * log.2.16, cause it runs on all 16 threads
|
||||||
bcryptVersion: '2a',
|
bcryptVersion: '2a',
|
||||||
get staticBcryptSalt () {
|
get staticBcryptSalt() {
|
||||||
return `$${this.bcryptVersion}$${this.bcryptRounds}$IxVE941tXVUD4cW0TNVm.O`
|
return `$${this.bcryptVersion}$${this.bcryptRounds}$IxVE941tXVUD4cW0TNVm.O`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,4 +37,5 @@ const styles = {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = styles
|
module.exports = styles
|
@ -3,11 +3,11 @@ const path = require('path')
|
|||||||
const user = {
|
const user = {
|
||||||
node: 0,
|
node: 0,
|
||||||
nodeSettings: {
|
nodeSettings: {
|
||||||
pingInterval: 30 * 1000,
|
pingInterval: 30 * 1000
|
||||||
},
|
},
|
||||||
server: {
|
server: {
|
||||||
writeHosts: {
|
writeHosts: {
|
||||||
enabled: true,
|
enabled: true
|
||||||
},
|
},
|
||||||
relativeTo: path.join(__dirname, '../'),
|
relativeTo: path.join(__dirname, '../'),
|
||||||
primary: {
|
primary: {
|
||||||
@ -16,27 +16,28 @@ const user = {
|
|||||||
port: 12388,
|
port: 12388,
|
||||||
directory: './src/',
|
directory: './src/',
|
||||||
page404: './src/404.html',
|
page404: './src/404.html',
|
||||||
host: '0.0.0.0',
|
host: '0.0.0.0'
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
tls: {
|
tls: {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
options: {
|
options: {
|
||||||
key: '',
|
key: '',
|
||||||
cert: '',
|
cert: ''
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
constants: {
|
constants: {
|
||||||
pollingInterval: 30 * 1000, // How long between checking for new unconfirmed transactions and new blocks (in milliseconds).
|
pollingInterval: 30 * 1000, // How long between checking for new unconfirmed transactions and new blocks (in milliseconds).
|
||||||
workerURL: '/build/worker.js',
|
workerURL: '/build/worker.js'
|
||||||
},
|
},
|
||||||
|
|
||||||
// Notification Settings (All defaults to true)
|
// Notification Settings (All defaults to true)
|
||||||
notifications: {
|
notifications: {
|
||||||
q_chat: {
|
q_chat: {
|
||||||
playSound: true,
|
playSound: true,
|
||||||
showNotification: true,
|
showNotification: true
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = user
|
module.exports = user
|
@ -10,6 +10,7 @@ const checkKeys = (storeObj, newObj) => {
|
|||||||
storeObj[key] = newObj[key]
|
storeObj[key] = newObj[key]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeObj
|
return storeObj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ html {
|
|||||||
--plugback: #ffffff;
|
--plugback: #ffffff;
|
||||||
--border: #d0d6de;
|
--border: #d0d6de;
|
||||||
--border2: #dde2e8;
|
--border2: #dde2e8;
|
||||||
|
--border3: #080808;
|
||||||
--copybutton: #707584;
|
--copybutton: #707584;
|
||||||
--chat-group: #080808;
|
--chat-group: #080808;
|
||||||
--chat-bubble: #9f9f9f0a;
|
--chat-bubble: #9f9f9f0a;
|
||||||
@ -83,6 +84,7 @@ html[theme="dark"] {
|
|||||||
--plugback: #0f1a2e;
|
--plugback: #0f1a2e;
|
||||||
--border: #0b305e;
|
--border: #0b305e;
|
||||||
--border2: #0b305e;
|
--border2: #0b305e;
|
||||||
|
--border3: #767676;
|
||||||
--copybutton: #d0d6de;
|
--copybutton: #d0d6de;
|
||||||
--chat-group: #ffffff;
|
--chat-group: #ffffff;
|
||||||
--chat-bubble: #9694941a;
|
--chat-bubble: #9694941a;
|
||||||
|
@ -945,7 +945,16 @@
|
|||||||
"gchange56": "Group Name To Search",
|
"gchange56": "Group Name To Search",
|
||||||
"gchange57": "Private Group Name Not Found",
|
"gchange57": "Private Group Name Not Found",
|
||||||
"gchange58": "Note that group name must be an exact match.",
|
"gchange58": "Note that group name must be an exact match.",
|
||||||
"gchange59": "Show / Hide Ticker"
|
"gchange59": "Show / Hide Ticker",
|
||||||
|
"gchange60": "Please enter an group name",
|
||||||
|
"gchange61": "Please enter an description",
|
||||||
|
"gchange62": "Are you sure to update this group?",
|
||||||
|
"gchange63": "On pressing confirm, the update group request will be sent!",
|
||||||
|
"gchange64": "Current Owner / New Owner",
|
||||||
|
"gchange65": "Only replace this address if you want to transfer the group!",
|
||||||
|
"gchange66": "Invalid Owner / New Owner Address",
|
||||||
|
"gchange67": "Group Update Successful!",
|
||||||
|
"gchange68": "Set Group Avatar"
|
||||||
},
|
},
|
||||||
"puzzlepage": {
|
"puzzlepage": {
|
||||||
"pchange1": "Puzzles",
|
"pchange1": "Puzzles",
|
||||||
|
@ -1,11 +1,9 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en-us">
|
<html lang="en-us">
|
||||||
|
<head>
|
||||||
<head>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="Description" content="Qortal Platform UI">
|
<meta name="Description" content="Qortal Platform UI">
|
||||||
|
|
||||||
<link rel="apple-touch-icon" sizes="57x57" href="/img/favicon/apple-icon-57x57.png">
|
<link rel="apple-touch-icon" sizes="57x57" href="/img/favicon/apple-icon-57x57.png">
|
||||||
<link rel="apple-touch-icon" sizes="60x60" href="/img/favicon/apple-icon-60x60.png">
|
<link rel="apple-touch-icon" sizes="60x60" href="/img/favicon/apple-icon-60x60.png">
|
||||||
<link rel="apple-touch-icon" sizes="72x72" href="/img/favicon/apple-icon-72x72.png">
|
<link rel="apple-touch-icon" sizes="72x72" href="/img/favicon/apple-icon-72x72.png">
|
||||||
@ -20,37 +18,30 @@
|
|||||||
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon/favicon-96x96.png">
|
<link rel="icon" type="image/png" sizes="96x96" href="/img/favicon/favicon-96x96.png">
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16.png">
|
<link rel="icon" type="image/png" sizes="16x16" href="/img/favicon/favicon-16x16.png">
|
||||||
<link rel="manifest" href="/img/favicon/manifest.json">
|
<link rel="manifest" href="/img/favicon/manifest.json">
|
||||||
|
|
||||||
<meta name="msapplication-TileColor" content="var(--white)">
|
<meta name="msapplication-TileColor" content="var(--white)">
|
||||||
<meta name="msapplication-TileImage" content="/img/favicon/ms-icon-144x144.png">
|
<meta name="msapplication-TileImage" content="/img/favicon/ms-icon-144x144.png">
|
||||||
<meta name="theme-color" content="var(--white)">
|
<meta name="theme-color" content="var(--white)">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
html {
|
html {
|
||||||
--scrollbarBG: #a1a1a1;
|
--scrollbarBG: #a1a1a1;
|
||||||
--thumbBG: #6a6c75;
|
--thumbBG: #6a6c75;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
width: 11px;
|
width: 11px;
|
||||||
}
|
}
|
||||||
|
|
||||||
* {
|
* {
|
||||||
scrollbar-width: thin;
|
scrollbar-width: thin;
|
||||||
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
|
scrollbar-color: var(--thumbBG) var(--scrollbarBG);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-track {
|
*::-webkit-scrollbar-track {
|
||||||
background: var(--scrollbarBG);
|
background: var(--scrollbarBG);
|
||||||
}
|
}
|
||||||
|
|
||||||
*::-webkit-scrollbar-thumb {
|
*::-webkit-scrollbar-thumb {
|
||||||
background-color: var(--thumbBG);
|
background-color: var(--thumbBG);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
border: 3px solid var(--scrollbarBG);
|
border: 3px solid var(--scrollbarBG);
|
||||||
}
|
}
|
||||||
|
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -63,8 +54,6 @@
|
|||||||
<link rel="stylesheet" href="/font/material-icons.css">
|
<link rel="stylesheet" href="/font/material-icons.css">
|
||||||
<link rel="stylesheet" href="/font/switch-theme.css">
|
<link rel="stylesheet" href="/font/switch-theme.css">
|
||||||
<title>Qortal UI</title>
|
<title>Qortal UI</title>
|
||||||
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
const checkTheme = localStorage.getItem('qortalTheme')
|
const checkTheme = localStorage.getItem('qortalTheme')
|
||||||
if (checkTheme === 'dark') {
|
if (checkTheme === 'dark') {
|
||||||
@ -118,22 +107,15 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
<body>
|
||||||
<body>
|
|
||||||
<app-styles></app-styles>
|
<app-styles></app-styles>
|
||||||
<main>
|
<main>
|
||||||
|
|
||||||
<noscript>
|
<noscript>
|
||||||
You need to enable JavaScript to run this app. 😞
|
You need to enable JavaScript to run this app. 😞
|
||||||
</noscript>
|
</noscript>
|
||||||
|
|
||||||
<main-app id="main-app"></main-app>
|
<main-app id="main-app"></main-app>
|
||||||
|
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<script type="module" src="/build/es6/main.js"></script>
|
<script type="module" src="/build/es6/main.js"></script>
|
||||||
|
</body>
|
||||||
</body>
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
@ -23,6 +23,7 @@ function serverFactory(routes, address, port, tls) {
|
|||||||
await this.server.start()
|
await this.server.start()
|
||||||
|
|
||||||
delete this.startServer
|
delete this.startServer
|
||||||
|
|
||||||
return this.server
|
return this.server
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
@ -12,7 +12,6 @@ const routesOptions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const createRoutes = config => [
|
const createRoutes = config => [
|
||||||
|
|
||||||
{
|
{
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
path: '/img/{param*}',
|
path: '/img/{param*}',
|
||||||
@ -97,6 +96,7 @@ const createRoutes = config => [
|
|||||||
|
|
||||||
delete response.config.user.tls
|
delete response.config.user.tls
|
||||||
delete response.config.build
|
delete response.config.build
|
||||||
|
|
||||||
return JSON.stringify(response)
|
return JSON.stringify(response)
|
||||||
},
|
},
|
||||||
options: routesOptions
|
options: routesOptions
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const createCommonRoutes = require('./createCommonRoutes.js')
|
const createCommonRoutes = require('./createCommonRoutes.js')
|
||||||
|
|
||||||
const createPrimaryRoutes = (config, plugins) => {
|
const createPrimaryRoutes = (config, plugins) => {
|
||||||
@ -131,7 +130,7 @@ const createPrimaryRoutes = (config, plugins) => {
|
|||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
options: routesOptions
|
options: routesOptions
|
||||||
},
|
}
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -5,18 +5,16 @@ const createPrimaryRoutes = require('./routes/createPrimaryRoutes.js')
|
|||||||
const createServer = (config, plugins) => {
|
const createServer = (config, plugins) => {
|
||||||
this.start = async function () {
|
this.start = async function () {
|
||||||
const primaryServer = new ServerFactory(createPrimaryRoutes(config, plugins), config.user.server.primary.host, config.user.server.primary.port, config.user.tls.enabled ? config.user.tls.options : void 0)
|
const primaryServer = new ServerFactory(createPrimaryRoutes(config, plugins), config.user.server.primary.host, config.user.server.primary.port, config.user.tls.enabled ? config.user.tls.options : void 0)
|
||||||
primaryServer.startServer()
|
primaryServer.startServer().then(server => {
|
||||||
.then(server => {
|
|
||||||
console.log(`Qortal UI Server started at ${server.info.uri} and listening on ${server.info.address}`)
|
console.log(`Qortal UI Server started at ${server.info.uri} and listening on ${server.info.address}`)
|
||||||
})
|
}).catch(e => {
|
||||||
.catch(e => {
|
|
||||||
console.error(e)
|
console.error(e)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const serverExports = {
|
const serverExports = {
|
||||||
createServer
|
createServer
|
||||||
}
|
}
|
||||||
|
@ -1,54 +1,55 @@
|
|||||||
import * as api from 'qortal-ui-crypto'
|
import * as api from 'qortal-ui-crypto'
|
||||||
import mykey from './functional-components/mykey-page.js'
|
import mykey from './functional-components/mykey-page'
|
||||||
|
|
||||||
'use strict'
|
|
||||||
|
|
||||||
export const checkApiKey = async (nodeConfig) => {
|
export const checkApiKey = async (nodeConfig) => {
|
||||||
|
let selectedNode = nodeConfig.knownNodes[nodeConfig.node]
|
||||||
let selectedNode = nodeConfig.knownNodes[nodeConfig.node];
|
let apiKey = selectedNode.apiKey
|
||||||
let apiKey = selectedNode.apiKey;
|
|
||||||
|
|
||||||
// Attempt to generate an API key
|
// Attempt to generate an API key
|
||||||
const generateUrl = "/admin/apikey/generate";
|
const generateUrl = '/admin/apikey/generate'
|
||||||
|
|
||||||
let generateRes = await api.request(generateUrl, {
|
let generateRes = await api.request(generateUrl, {
|
||||||
method: "POST"
|
method: 'POST'
|
||||||
});
|
})
|
||||||
|
|
||||||
if (generateRes != null && generateRes.error == null && generateRes.length >= 8) {
|
if (generateRes != null && generateRes.error == null && generateRes.length >= 8) {
|
||||||
console.log("Generated API key");
|
console.log('Generated API key')
|
||||||
apiKey = generateRes;
|
|
||||||
|
apiKey = generateRes
|
||||||
|
|
||||||
// Store the generated API key
|
// Store the generated API key
|
||||||
selectedNode.apiKey = apiKey;
|
selectedNode.apiKey = apiKey
|
||||||
nodeConfig.knownNodes[nodeConfig.node] = selectedNode;
|
nodeConfig.knownNodes[nodeConfig.node] = selectedNode
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(nodeConfig.knownNodes));
|
localStorage.setItem('myQortalNodes', JSON.stringify(nodeConfig.knownNodes))
|
||||||
}
|
} else {
|
||||||
else {
|
console.log("Unable to generate API key")
|
||||||
console.log("Unable to generate API key");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now test the API key
|
// Now test the API key
|
||||||
let testResult = await testApiKey(apiKey);
|
let testResult = await testApiKey(apiKey)
|
||||||
|
|
||||||
if (testResult === true) {
|
if (testResult === true) {
|
||||||
console.log("API key test passed");
|
console.log('API key test passed')
|
||||||
}
|
} else {
|
||||||
else {
|
console.log('API key test failed')
|
||||||
console.log("API key test failed");
|
|
||||||
mykey.show();
|
mykey.show()
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('disable-tour', {
|
new CustomEvent('disable-tour', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
}),
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const testApiKey = async (apiKey) => {
|
export const testApiKey = async (apiKey) => {
|
||||||
const testUrl = "/admin/apikey/test?apiKey=" + apiKey;
|
const testUrl = '/admin/apikey/test?apiKey=' + apiKey
|
||||||
let testRes = await api.request(testUrl, {
|
|
||||||
method: "GET"
|
|
||||||
});
|
|
||||||
return testRes === true;
|
|
||||||
|
|
||||||
|
let testRes = await api.request(testUrl, {
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
|
|
||||||
|
return testRes === true
|
||||||
}
|
}
|
@ -1,5 +1,3 @@
|
|||||||
import WebWorker from 'web-worker:./computePowWorkerFile.js';
|
import WebWorker from 'web-worker:./computePowWorkerFile.js'
|
||||||
|
|
||||||
// You can add any initialization or configuration for the Web Worker here
|
export default WebWorker
|
||||||
|
|
||||||
export default WebWorker;
|
|
@ -1,7 +1,10 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {translate} from '../../translate'
|
import { appInfoStyles } from '../styles/core-css'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../translate'
|
||||||
|
|
||||||
class AppInfo extends connect(store)(LitElement) {
|
class AppInfo extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -14,49 +17,7 @@ class AppInfo extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [appInfoStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--paper-input-container-focus-color: var(--mdc-theme-primary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.normal {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
}
|
|
||||||
|
|
||||||
#profileInMenu {
|
|
||||||
flex: 0 0 100px;
|
|
||||||
padding:12px;
|
|
||||||
border-top: 1px solid var(--border);
|
|
||||||
background: var(--sidetopbar);
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 100;
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.blue {
|
|
||||||
color: #03a9f4;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 200;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.black {
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 200;
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -74,7 +35,6 @@ class AppInfo extends connect(store)(LitElement) {
|
|||||||
${this._renderCoreVersion()}
|
${this._renderCoreVersion()}
|
||||||
<span class="info">${translate("appinfo.blockheight")}: ${this.nodeInfo.height ? this.nodeInfo.height : ''} <span class=${this.cssStatus}>${this._renderStatus()}</span></span>
|
<span class="info">${translate("appinfo.blockheight")}: ${this.nodeInfo.height ? this.nodeInfo.height : ''} <span class=${this.cssStatus}>${this._renderStatus()}</span></span>
|
||||||
<span class="info">${translate("appinfo.peers")}: ${this.nodeInfo.numberOfConnections ? this.nodeInfo.numberOfConnections : ''}
|
<span class="info">${translate("appinfo.peers")}: ${this.nodeInfo.numberOfConnections ? this.nodeInfo.numberOfConnections : ''}
|
||||||
<a id="pageLink"></a>
|
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,25 +1,10 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
|
|
||||||
class MyElement extends connect(store)(LitElement) {
|
class MyElement extends connect(store)(LitElement) {
|
||||||
static get properties () {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles () {
|
|
||||||
return css``
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return html`
|
return html`<style></style>`
|
||||||
<style>
|
|
||||||
</style>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged (state) {
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {store} from '../../store'
|
import { connect } from 'pwa-helpers'
|
||||||
import {connect} from 'pwa-helpers'
|
import { store } from '../../store'
|
||||||
import {translate} from '../../../translate'
|
import { parentEpml } from '../show-plugin'
|
||||||
import {parentEpml} from '../show-plugin'
|
import { syncIndicator2Styles } from '../../styles/core-css'
|
||||||
|
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import {translate} from '../../../translate'
|
||||||
|
|
||||||
class SyncIndicator extends connect(store)(LitElement) {
|
class SyncIndicator extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -18,6 +20,10 @@ class SyncIndicator extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [syncIndicator2Styles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.blocksBehind = 0
|
this.blocksBehind = 0
|
||||||
@ -32,64 +38,6 @@ class SyncIndicator extends connect(store)(LitElement) {
|
|||||||
this.hasOpened = false
|
this.hasOpened = false
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-text-primary-on-background: var(--black);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 50px;
|
|
||||||
right: 25px;
|
|
||||||
z-index: 50000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parent {
|
|
||||||
width: 360px;
|
|
||||||
padding: 10px;
|
|
||||||
border-radius: 8px;
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
user-select: none;
|
|
||||||
background: var(--white);
|
|
||||||
}
|
|
||||||
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
gap: 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bootstrap-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.bootstrap-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #03a8f475;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
${!this.hasCoreRunning ? html`
|
${!this.hasCoreRunning ? html`
|
||||||
@ -225,7 +173,7 @@ class SyncIndicator extends connect(store)(LitElement) {
|
|||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('open-welcome-modal-sync', {
|
new CustomEvent('open-welcome-modal-sync', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -257,4 +205,4 @@ class SyncIndicator extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('sync-indicator', SyncIndicator)
|
window.customElements.define('sync-indicator', SyncIndicator)
|
@ -1,16 +1,19 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {driver} from 'driver.js';
|
import { connect } from 'pwa-helpers'
|
||||||
import 'driver.js/dist/driver.css';
|
import { store } from '../../store'
|
||||||
import '@material/mwc-icon';
|
import { setNewTab } from '../../redux/app/app-actions'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import { tourComponentStyles } from '../../styles/core-css'
|
||||||
import '@vaadin/tooltip';
|
import { driver } from 'driver.js'
|
||||||
import '@material/mwc-button';
|
import 'driver.js/dist/driver.css'
|
||||||
import {get, translate} from '../../../translate';
|
import './tour.css'
|
||||||
import '@polymer/paper-dialog/paper-dialog.js';
|
import '@material/mwc-button'
|
||||||
import {setNewTab} from '../../redux/app/app-actions.js';
|
import '@material/mwc-icon'
|
||||||
import {store} from '../../store.js';
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
import {connect} from 'pwa-helpers';
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
import './tour.css';
|
import '@vaadin/tooltip'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
class TourComponent extends connect(store)(LitElement) {
|
class TourComponent extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -18,219 +21,87 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
getElements: { attribute: false },
|
getElements: { attribute: false },
|
||||||
dialogOpenedCongrats: { type: Boolean },
|
dialogOpenedCongrats: { type: Boolean },
|
||||||
hasViewedTour: { type: Boolean },
|
hasViewedTour: { type: Boolean },
|
||||||
disableTour: {type: Boolean}
|
disableTour: { type: Boolean },
|
||||||
};
|
nodeUrl: { type: String },
|
||||||
|
address: { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [tourComponentStyles]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.dialogOpenedCongrats = false;
|
this.dialogOpenedCongrats = false
|
||||||
this._controlOpenWelcomeModal =
|
this._controlOpenWelcomeModal = this._controlOpenWelcomeModal.bind(this)
|
||||||
this._controlOpenWelcomeModal.bind(this);
|
this.hasName = false
|
||||||
this.hasName = false;
|
this.nodeUrl = ''
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.address = ''
|
||||||
this.myNode = this.getMyNode();
|
|
||||||
this._disableTour = this._disableTour.bind(this)
|
this._disableTour = this._disableTour.bind(this)
|
||||||
this.disableTour = false
|
this.disableTour = false
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
render() {
|
||||||
return css`
|
return html`
|
||||||
* {
|
<!-- Profile read-view -->
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
${this.dialogOpenedCongrats && this.hasViewedTour ? html`
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
<paper-dialog class="full-info-wrapper" ?opened="${this.dialogOpenedCongrats}">
|
||||||
--mdc-theme-surface: var(--white);
|
<h3>Congratulations!</h3>
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
<div style="display:flex;gap:15px;justify-content:center;margin-top:10px">
|
||||||
box-sizing: border-box;
|
${translate("tour.tour13")}
|
||||||
color: var(--black);
|
</div>
|
||||||
background: var(--white);
|
<div style="display:flex;gap:15px;justify-content:center;margin-top:10px">
|
||||||
|
${translate("tour.tour14")}
|
||||||
|
</div>
|
||||||
|
<div class="accept-button" @click=${this.visitQtube}>
|
||||||
|
${translate("tour.tour15")}
|
||||||
|
</div>
|
||||||
|
<div style="width:100%;display:flex;justify-content:center;margin-top:10px">
|
||||||
|
<div class="close-button" @click=${() => { this.onClose() }}>
|
||||||
|
${translate("general.close")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</paper-dialog>
|
||||||
|
` : ''}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
:host {
|
|
||||||
box-sizing: border-box;
|
|
||||||
position: fixed;
|
|
||||||
bottom: 25px;
|
|
||||||
right: 25px;
|
|
||||||
z-index: 50000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-info-wrapper {
|
|
||||||
width: 100%;
|
|
||||||
min-width: 600px;
|
|
||||||
max-width: 600px;
|
|
||||||
text-align: center;
|
|
||||||
background: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 15px;
|
|
||||||
padding: 25px;
|
|
||||||
box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.1);
|
|
||||||
display: block !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
display: inline;
|
|
||||||
}
|
|
||||||
.accept-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
font-weight: 300;
|
|
||||||
padding: 8px 5px;
|
|
||||||
border-radius: 3px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--black);
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
font-size: 18px;
|
|
||||||
justify-content: center;
|
|
||||||
outline: 1px solid var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.accept-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #03a8f485;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
font-weight: 300;
|
|
||||||
padding: 8px 5px;
|
|
||||||
border-radius: 3px;
|
|
||||||
text-align: center;
|
|
||||||
color: #f44336;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
font-size: 18px;
|
|
||||||
width:auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #f4433663;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
_controlOpenWelcomeModal() {
|
|
||||||
this.isSynced = true
|
|
||||||
|
|
||||||
const seenWelcomeSync = JSON.parse(
|
|
||||||
localStorage.getItem('welcome-sync') || 'false'
|
|
||||||
);
|
|
||||||
if (this.hasName) return;
|
|
||||||
if (seenWelcomeSync) return;
|
|
||||||
if(!this.hasViewedTour) return
|
|
||||||
this.dialogOpenedCongrats = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
openWelcomeModal() {
|
|
||||||
this.dispatchEvent(
|
|
||||||
new CustomEvent('send-tour-finished', {
|
|
||||||
bubbles: true,
|
|
||||||
composed: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
const seenWelcomeSync = JSON.parse(
|
|
||||||
localStorage.getItem('welcome-sync') || 'false'
|
|
||||||
);
|
|
||||||
if (this.hasName) return;
|
|
||||||
if (seenWelcomeSync) return;
|
|
||||||
if(!this.isSynced) return
|
|
||||||
this.dialogOpenedCongrats = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
_disableTour(){
|
|
||||||
this.disableTour = true
|
|
||||||
driver.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
window.addEventListener(
|
|
||||||
'open-welcome-modal-sync',
|
|
||||||
this._controlOpenWelcomeModal
|
|
||||||
);
|
|
||||||
window.addEventListener(
|
|
||||||
'disable-tour',
|
|
||||||
this._disableTour
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
window.removeEventListener(
|
|
||||||
'open-welcome-modal-sync',
|
|
||||||
this._controlOpenWelcomeModal
|
|
||||||
);
|
|
||||||
window.addEventListener(
|
|
||||||
'disable-tour',
|
|
||||||
this._disableTour
|
|
||||||
);
|
|
||||||
super.disconnectedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
async getName(recipient) {
|
|
||||||
try {
|
|
||||||
const endpoint = `${this.nodeUrl}/names/address/${recipient}`;
|
|
||||||
const res = await fetch(endpoint);
|
|
||||||
const getNames = await res.json();
|
|
||||||
|
|
||||||
if (Array.isArray(getNames) && getNames.length > 0) {
|
|
||||||
return getNames[0].name;
|
|
||||||
} else {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
async firstUpdated() {
|
async firstUpdated() {
|
||||||
|
this.getNodeUrl()
|
||||||
this.address = store.getState().app.selectedAddress.address
|
this.address = store.getState().app.selectedAddress.address
|
||||||
const hasViewedTour = JSON.parse(
|
|
||||||
localStorage.getItem(`hasViewedTour-${this.address}`) || 'false'
|
const hasViewedTour = JSON.parse(localStorage.getItem(`hasViewedTour-${this.address}`) || 'false')
|
||||||
);
|
const name = await this.getName(this.address)
|
||||||
const name = await this.getName(this.address);
|
|
||||||
if (name) {
|
if (name) {
|
||||||
this.hasName = true;
|
this.hasName = true
|
||||||
}
|
}
|
||||||
this.hasViewedTour = hasViewedTour;
|
|
||||||
|
this.hasViewedTour = hasViewedTour
|
||||||
|
|
||||||
if (!hasViewedTour) {
|
if (!hasViewedTour) {
|
||||||
try {
|
try {
|
||||||
if (name) {
|
if (name) {
|
||||||
this.hasViewedTour = true;
|
this.hasViewedTour = true
|
||||||
this.hasName = true;
|
this.hasName = true
|
||||||
localStorage.setItem(`hasViewedTour-${this.address}`, JSON.stringify(true))
|
localStorage.setItem(`hasViewedTour-${this.address}`, JSON.stringify(true))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log({ error });
|
console.log({ error })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await new Promise((res) => {
|
await new Promise((res) => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
res();
|
res()
|
||||||
}, 1000);
|
}, 1000)
|
||||||
});
|
})
|
||||||
|
|
||||||
if (!this.hasViewedTour && this.disableTour !== true) {
|
if (!this.hasViewedTour && this.disableTour !== true) {
|
||||||
const elements = this.getElements();
|
const elements = this.getElements()
|
||||||
let steps = [
|
|
||||||
{
|
let steps = [{
|
||||||
popover: {
|
popover: {
|
||||||
title: get("tour.tour6"),
|
title: get("tour.tour6"),
|
||||||
description: `
|
description: `
|
||||||
@ -238,22 +109,24 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
<img style="height:40px;width:auto;margin:15px 0px;" src="/img/qort.png" />
|
<img style="height:40px;width:auto;margin:15px 0px;" src="/img/qort.png" />
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
||||||
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div> <p style="margin:0px;padding:0px">${get("tour.tour7")}</p>
|
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div>
|
||||||
|
<p style="margin:0px;padding:0px">${get("tour.tour7")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
||||||
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div> <p style="margin:0px;padding:0px">${get("tour.tour8")}</p>
|
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div>
|
||||||
|
<p style="margin:0px;padding:0px">${get("tour.tour8")}</p>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;margin-bottom:30px">
|
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;margin-bottom:30px">
|
||||||
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div> <p style="margin:0px;padding:0px">${get("tour.tour9")}</p>
|
<div style="height:6px;width:6px;border-radius:50%;background:var(--black)"></div>
|
||||||
|
<p style="margin:0px;padding:0px">${get("tour.tour9")}</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
// ... other options
|
}
|
||||||
},
|
}]
|
||||||
},
|
|
||||||
];
|
const step2 = elements['core-sync-status-id']
|
||||||
const step2 = elements['core-sync-status-id'];
|
const step3 = elements['tab']
|
||||||
const step3 = elements['tab'];
|
const step4 = elements['checklist']
|
||||||
const step4 = elements['checklist'];
|
|
||||||
|
|
||||||
if (step2) {
|
if (step2) {
|
||||||
steps.push({
|
steps.push({
|
||||||
@ -277,10 +150,11 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
<p style="margin:0px;padding:0px">${get("tour.tour4")}</p>
|
<p style="margin:0px;padding:0px">${get("tour.tour4")}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
`,
|
`
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (step3) {
|
if (step3) {
|
||||||
steps.push({
|
steps.push({
|
||||||
element: step3,
|
element: step3,
|
||||||
@ -288,31 +162,26 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
title: 'Tab View',
|
title: 'Tab View',
|
||||||
description: `
|
description: `
|
||||||
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;margin-bottom:30px">
|
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;margin-bottom:30px">
|
||||||
<p style="margin:0px;padding:0px">${get("tour.tour10")}
|
<p style="margin:0px;padding:0px">${get("tour.tour10")}</p>
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
<div style="display:flex;gap:15px;align-items:center;margin-top:15px;">
|
||||||
<span><img src="/img/addplugin.webp" style="height: 36px; width: 36px; padding-top: 4px;" /></span>
|
<span><img src="/img/addplugin.webp" style="height: 36px; width: 36px; padding-top: 4px;" /></span>
|
||||||
<p style="margin:0px;padding:0px">You can also bookmark other Q-Apps and Plugins by clicking on the ${get(
|
<p style="margin:0px;padding:0px">
|
||||||
'tabmenu.tm19'
|
You can also bookmark other Q-Apps and Plugins by clicking on the ${get('tabmenu.tm19')} button
|
||||||
)} button</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
`,
|
`
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (step4) {
|
if (step4) {
|
||||||
steps.push(
|
steps.push({ element: step4, popover: { title: get("tour.tour11"), description: get("tour.tour12")}})
|
||||||
{
|
this.hasViewedTour
|
||||||
element: step4,
|
|
||||||
popover: {
|
|
||||||
title: get("tour.tour11"),
|
|
||||||
description: get("tour.tour12"),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
);this.hasViewedTour
|
|
||||||
}
|
let currentStepIndex = 0
|
||||||
let currentStepIndex = 0;
|
|
||||||
const driverObj = driver({
|
const driverObj = driver({
|
||||||
popoverClass: 'driverjs-theme',
|
popoverClass: 'driverjs-theme',
|
||||||
showProgress: true,
|
showProgress: true,
|
||||||
@ -321,25 +190,93 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
allowClose: false,
|
allowClose: false,
|
||||||
onDestroyed: () => {
|
onDestroyed: () => {
|
||||||
localStorage.setItem(`hasViewedTour-${this.address}`, JSON.stringify(true))
|
localStorage.setItem(`hasViewedTour-${this.address}`, JSON.stringify(true))
|
||||||
this.hasViewedTour = true;
|
this.hasViewedTour = true
|
||||||
this.openWelcomeModal();
|
this.openWelcomeModal()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
driverObj.drive();
|
driverObj.drive()
|
||||||
} else {
|
} else {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('send-tour-finished', {
|
new CustomEvent('send-tour-finished', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlOpenWelcomeModal() {
|
||||||
|
this.isSynced = true
|
||||||
|
|
||||||
|
const seenWelcomeSync = JSON.parse(localStorage.getItem('welcome-sync') || 'false')
|
||||||
|
|
||||||
|
if (this.hasName) return
|
||||||
|
if (seenWelcomeSync) return
|
||||||
|
if (!this.hasViewedTour) return
|
||||||
|
|
||||||
|
this.dialogOpenedCongrats = true
|
||||||
|
}
|
||||||
|
|
||||||
|
openWelcomeModal() {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent('send-tour-finished', {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const seenWelcomeSync = JSON.parse(localStorage.getItem('welcome-sync') || 'false')
|
||||||
|
|
||||||
|
if (this.hasName) return
|
||||||
|
if (seenWelcomeSync) return
|
||||||
|
if (!this.isSynced) return
|
||||||
|
|
||||||
|
this.dialogOpenedCongrats = true
|
||||||
|
}
|
||||||
|
|
||||||
|
_disableTour() {
|
||||||
|
this.disableTour = true
|
||||||
|
driver.reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback()
|
||||||
|
window.addEventListener('open-welcome-modal-sync', this._controlOpenWelcomeModal)
|
||||||
|
window.addEventListener('disable-tour', this._disableTour)
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
window.removeEventListener('open-welcome-modal-sync', this._controlOpenWelcomeModal)
|
||||||
|
window.addEventListener('disable-tour', this._disableTour)
|
||||||
|
super.disconnectedCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
const myNodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
this.nodeUrl = myNodeUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
async getName(recipient) {
|
||||||
|
try {
|
||||||
|
const endpoint = `${this.nodeUrl}/names/address/${recipient}`
|
||||||
|
const res = await fetch(endpoint)
|
||||||
|
const getNames = await res.json()
|
||||||
|
|
||||||
|
if (Array.isArray(getNames) && getNames.length > 0) {
|
||||||
|
return getNames[0].name
|
||||||
|
} else {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visitQtube() {
|
visitQtube() {
|
||||||
this.onClose();
|
this.onClose()
|
||||||
const query = `?service=APP&name=Q-Tube`;
|
const query = `?service=APP&name=Q-Tube`
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
setNewTab({
|
setNewTab({
|
||||||
url: `qdn/browser/index.html${query}`,
|
url: `qdn/browser/index.html${query}`,
|
||||||
@ -350,59 +287,16 @@ class TourComponent extends connect(store)(LitElement) {
|
|||||||
page: `qdn/browser/index.html${query}`,
|
page: `qdn/browser/index.html${query}`,
|
||||||
title: 'Q-Tube',
|
title: 'Q-Tube',
|
||||||
menus: [],
|
menus: [],
|
||||||
parent: false,
|
parent: false
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose() {
|
onClose() {
|
||||||
localStorage.setItem(`welcome-sync-${this.address}`, JSON.stringify(true))
|
localStorage.setItem(`welcome-sync-${this.address}`, JSON.stringify(true))
|
||||||
this.dialogOpenedCongrats = false;
|
this.dialogOpenedCongrats = false
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html`
|
|
||||||
<!-- Profile read-view -->
|
|
||||||
${this.dialogOpenedCongrats && this.hasViewedTour
|
|
||||||
? html`
|
|
||||||
<paper-dialog
|
|
||||||
class="full-info-wrapper"
|
|
||||||
?opened="${this.dialogOpenedCongrats}"
|
|
||||||
>
|
|
||||||
<h3>Congratulations!</h3>
|
|
||||||
<div
|
|
||||||
style="display:flex;gap:15px;justify-content:center;margin-top:10px"
|
|
||||||
>
|
|
||||||
${translate("tour.tour13")}
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style="display:flex;gap:15px;justify-content:center;margin-top:10px"
|
|
||||||
>
|
|
||||||
${translate("tour.tour14")}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
|
||||||
class="accept-button"
|
|
||||||
@click=${this.visitQtube}
|
|
||||||
>
|
|
||||||
${translate("tour.tour15")}
|
|
||||||
</div>
|
|
||||||
<div style="width:100%;display:flex;justify-content:center;margin-top:10px">
|
|
||||||
<div
|
|
||||||
class="close-button"
|
|
||||||
@click=${()=> {
|
|
||||||
this.onClose()
|
|
||||||
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
${translate("general.close")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</paper-dialog>
|
|
||||||
`
|
|
||||||
: ''}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('tour-component', TourComponent);
|
|
||||||
|
window.customElements.define('tour-component', TourComponent)
|
@ -1,10 +1,11 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {translate} from '../../translate'
|
|
||||||
import isElectron from 'is-electron'
|
import isElectron from 'is-electron'
|
||||||
|
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
import '@polymer/iron-icons/iron-icons.js'
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../translate'
|
||||||
|
|
||||||
class CheckForUpdate extends LitElement {
|
class CheckForUpdate extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -17,11 +18,6 @@ class CheckForUpdate extends LitElement {
|
|||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
|
||||||
css`
|
|
||||||
`
|
|
||||||
]
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
${this.renderUpdateButton()}
|
${this.renderUpdateButton()}
|
||||||
@ -29,6 +25,7 @@ class CheckForUpdate extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUpdateButton() {
|
renderUpdateButton() {
|
||||||
|
@ -1,14 +1,10 @@
|
|||||||
import {Sha256} from 'asmcrypto.js'
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
|
||||||
|
function sbrk(size, heap) {
|
||||||
function sbrk(size, heap){
|
|
||||||
let brk = 512 * 1024 // stack top
|
let brk = 512 * 1024 // stack top
|
||||||
let old = brk
|
let old = brk
|
||||||
brk += size
|
brk += size
|
||||||
|
if (brk > heap.length) throw new Error('heap exhausted')
|
||||||
if (brk > heap.length)
|
|
||||||
throw new Error('heap exhausted')
|
|
||||||
|
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -20,63 +16,43 @@ self.addEventListener('message', async e => {
|
|||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||||
const heap = new Uint8Array(memory.buffer)
|
const heap = new Uint8Array(memory.buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const computePow = async (chatBytes, path, difficulty) => {
|
const computePow = async (chatBytes, path, difficulty) => {
|
||||||
|
|
||||||
let response = null
|
let response = null
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
await new Promise((resolve, reject)=> {
|
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; })
|
||||||
|
const chatBytesArray = new Uint8Array(_chatBytesArray)
|
||||||
const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; });
|
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result
|
||||||
const chatBytesArray = new Uint8Array(_chatBytesArray);
|
const hashPtr = sbrk(32, heap)
|
||||||
const chatBytesHash = new Sha256().process(chatBytesArray).finish().result;
|
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32)
|
||||||
const hashPtr = sbrk(32, heap);
|
hashAry.set(chatBytesHash)
|
||||||
const hashAry = new Uint8Array(memory.buffer, hashPtr, 32);
|
const workBufferLength = 8 * 1024 * 1024
|
||||||
hashAry.set(chatBytesHash);
|
const workBufferPtr = sbrk(workBufferLength, heap)
|
||||||
|
|
||||||
|
|
||||||
const workBufferLength = 8 * 1024 * 1024;
|
|
||||||
const workBufferPtr = sbrk(workBufferLength, heap);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const importObject = {
|
const importObject = {
|
||||||
env: {
|
env: {
|
||||||
memory: memory
|
memory: memory
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function loadWebAssembly(filename, imports) {
|
function loadWebAssembly(filename, imports) {
|
||||||
// Fetch the file and compile it
|
// Fetch the file and compile it
|
||||||
return fetch(filename)
|
return fetch(filename)
|
||||||
.then(response => response.arrayBuffer())
|
.then(response => response.arrayBuffer())
|
||||||
.then(buffer => WebAssembly.compile(buffer))
|
.then(buffer => WebAssembly.compile(buffer))
|
||||||
.then(module => {
|
.then(module => {
|
||||||
|
|
||||||
// Create the instance.
|
// Create the instance.
|
||||||
return new WebAssembly.Instance(module, importObject);
|
return new WebAssembly.Instance(module, importObject)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
loadWebAssembly(path)
|
||||||
|
|
||||||
loadWebAssembly(path)
|
|
||||||
.then(wasmModule => {
|
.then(wasmModule => {
|
||||||
response = {
|
response = {
|
||||||
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
nonce: wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||||
chatBytesArray
|
chatBytesArray
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve()
|
resolve()
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
@ -1,92 +1,68 @@
|
|||||||
import { Sha256 } from 'asmcrypto.js'
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
|
||||||
|
function sbrk(size, heap) {
|
||||||
|
|
||||||
function sbrk(size, heap){
|
|
||||||
let brk = 512 * 1024 // stack top
|
let brk = 512 * 1024 // stack top
|
||||||
let old = brk
|
let old = brk
|
||||||
brk += size
|
brk += size
|
||||||
|
if (brk > heap.length) throw new Error('heap exhausted')
|
||||||
if (brk > heap.length)
|
|
||||||
throw new Error('heap exhausted')
|
|
||||||
|
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener('message', async e => {
|
self.addEventListener('message', async e => {
|
||||||
const response = await computePow(e.data.convertedBytes, e.data.path)
|
const response = await computePow(e.data.convertedBytes, e.data.path)
|
||||||
postMessage(response)
|
postMessage(response)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||||
const heap = new Uint8Array(memory.buffer)
|
const heap = new Uint8Array(memory.buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const computePow = async (convertedBytes, path) => {
|
const computePow = async (convertedBytes, path) => {
|
||||||
|
|
||||||
|
|
||||||
let response = null
|
let response = null
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
await new Promise((resolve, reject)=> {
|
|
||||||
|
|
||||||
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
||||||
function (key) {
|
function (key) {
|
||||||
return convertedBytes[key]
|
return convertedBytes[key]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
||||||
const convertedBytesHash = new Sha256()
|
const convertedBytesHash = new Sha256()
|
||||||
.process(convertedBytesArray)
|
.process(convertedBytesArray)
|
||||||
.finish().result
|
.finish().result
|
||||||
const hashPtr = sbrk(32, heap)
|
const hashPtr = sbrk(32, heap)
|
||||||
const hashAry = new Uint8Array(
|
const hashAry = new Uint8Array(
|
||||||
memory.buffer,
|
memory.buffer,
|
||||||
hashPtr,
|
hashPtr,
|
||||||
32
|
32
|
||||||
)
|
)
|
||||||
|
hashAry.set(convertedBytesHash)
|
||||||
hashAry.set(convertedBytesHash)
|
const difficulty = 14
|
||||||
const difficulty = 14
|
const workBufferLength = 8 * 1024 * 1024
|
||||||
const workBufferLength = 8 * 1024 * 1024
|
const workBufferPtr = sbrk(
|
||||||
const workBufferPtr = sbrk(
|
|
||||||
workBufferLength,
|
workBufferLength,
|
||||||
heap
|
heap
|
||||||
)
|
)
|
||||||
|
|
||||||
const importObject = {
|
const importObject = {
|
||||||
env: {
|
env: {
|
||||||
memory: memory
|
memory: memory
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function loadWebAssembly(filename, imports) {
|
function loadWebAssembly(filename, imports) {
|
||||||
return fetch(filename)
|
return fetch(filename)
|
||||||
.then(response => response.arrayBuffer())
|
.then(response => response.arrayBuffer())
|
||||||
.then(buffer => WebAssembly.compile(buffer))
|
.then(buffer => WebAssembly.compile(buffer))
|
||||||
.then(module => {
|
.then(module => {
|
||||||
return new WebAssembly.Instance(module, importObject);
|
return new WebAssembly.Instance(module, importObject)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
loadWebAssembly(path)
|
||||||
|
|
||||||
loadWebAssembly(path)
|
|
||||||
.then(wasmModule => {
|
.then(wasmModule => {
|
||||||
response = {
|
response = {
|
||||||
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
nonce: wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||||
|
|
||||||
}
|
}
|
||||||
resolve()
|
resolve()
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
@ -1,42 +1,182 @@
|
|||||||
import {html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import '@material/mwc-icon';
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store';
|
import { store } from '../../store'
|
||||||
import {connect} from 'pwa-helpers';
|
import { parentEpml } from '../show-plugin'
|
||||||
import '@vaadin/tooltip';
|
import { setCoinBalances } from '../../redux/app/app-actions'
|
||||||
import {parentEpml} from '../show-plugin';
|
|
||||||
import {setCoinBalances} from '../../redux/app/app-actions';
|
|
||||||
|
|
||||||
class CoinBalancesController extends connect(store)(LitElement) {
|
class CoinBalancesController extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
coinList: { type: Object },
|
coinList: { type: Object }
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.coinList = {}
|
this.coinList = {}
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.myNode = this.getMyNode();
|
this.myNode = this.getMyNode()
|
||||||
this.fetchBalance = this.fetchBalance.bind(this)
|
this.fetchBalance = this.fetchBalance.bind(this)
|
||||||
this._updateCoinList = this._updateCoinList.bind(this)
|
this._updateCoinList = this._updateCoinList.bind(this)
|
||||||
this.stop = false
|
this.stop = false
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeUrl() {
|
render() {
|
||||||
const myNode =
|
return html``
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
}
|
||||||
store.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
}
|
}
|
||||||
|
|
||||||
getMyNode() {
|
getMyNode() {
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
store.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateQortWalletBalance() {
|
||||||
|
let qortAddress = store.getState().app.selectedAddress.address
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: `/addresses/balance/${qortAddress}?apiKey=${this.myNode.apiKey}`,
|
||||||
|
}).then((res) => {
|
||||||
|
this.qortWalletBalance = res
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'qort',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateBtcWalletBalance() {
|
||||||
|
let _url = `/crosschain/btc/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
|
let _body = store.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: _url,
|
||||||
|
method: 'POST',
|
||||||
|
body: _body
|
||||||
|
}).then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
this.btcWalletBalance = (Number(res) / 1e8).toFixed(8)
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'btc',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateLtcWalletBalance() {
|
||||||
|
let _url = `/crosschain/ltc/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
|
let _body = store.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: _url,
|
||||||
|
method: 'POST',
|
||||||
|
body: _body
|
||||||
|
}).then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
this.ltcWalletBalance = (Number(res) / 1e8).toFixed(8)
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'ltc',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDogeWalletBalance() {
|
||||||
|
let _url = `/crosschain/doge/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
|
let _body = store.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: _url,
|
||||||
|
method: 'POST',
|
||||||
|
body: _body
|
||||||
|
}).then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
this.dogeWalletBalance = (Number(res) / 1e8).toFixed(8)
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'doge',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateDgbWalletBalance() {
|
||||||
|
let _url = `/crosschain/dgb/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
|
let _body = store.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: _url,
|
||||||
|
method: 'POST',
|
||||||
|
body: _body
|
||||||
|
}).then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
this.dgbWalletBalance = (Number(res) / 1e8).toFixed(8)
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'dgb',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateRvnWalletBalance() {
|
||||||
|
let _url = `/crosschain/rvn/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
|
let _body = store.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
|
||||||
|
|
||||||
|
await parentEpml.request('apiCall', {
|
||||||
|
url: _url,
|
||||||
|
method: 'POST',
|
||||||
|
body: _body
|
||||||
|
}).then((res) => {
|
||||||
|
if (isNaN(Number(res))) {
|
||||||
|
//...
|
||||||
|
} else {
|
||||||
|
this.rvnWalletBalance = (Number(res) / 1e8).toFixed(8)
|
||||||
|
store.dispatch(
|
||||||
|
setCoinBalances({
|
||||||
|
type: 'rvn',
|
||||||
|
fullValue: Number(res)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}).catch(() => {
|
||||||
|
console.log('error')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
async updateArrrWalletBalance() {
|
async updateArrrWalletBalance() {
|
||||||
let _url = `/crosschain/arrr/walletbalance?apiKey=${this.myNode.apiKey}`
|
let _url = `/crosschain/arrr/walletbalance?apiKey=${this.myNode.apiKey}`
|
||||||
@ -56,231 +196,91 @@ class CoinBalancesController extends connect(store)(LitElement) {
|
|||||||
type: 'arrr',
|
type: 'arrr',
|
||||||
fullValue: Number(res)
|
fullValue: Number(res)
|
||||||
})
|
})
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
}).catch(()=> {
|
}).catch(() => {
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
async updateQortWalletBalance() {
|
|
||||||
let qortAddress = store.getState().app.selectedAddress.address
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: `/addresses/balance/${qortAddress}?apiKey=${this.myNode.apiKey}`,
|
|
||||||
}).then((res) => {
|
|
||||||
this.qortWalletBalance = res
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'qort',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateRvnWalletBalance() {
|
|
||||||
let _url = `/crosschain/rvn/walletbalance?apiKey=${this.myNode.apiKey}`
|
|
||||||
let _body = store.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: _url,
|
|
||||||
method: 'POST',
|
|
||||||
body: _body,
|
|
||||||
}).then((res) => {
|
|
||||||
if (isNaN(Number(res))) {
|
|
||||||
//...
|
|
||||||
} else {
|
|
||||||
this.rvnWalletBalance = (Number(res) / 1e8).toFixed(8)
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'rvn',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateDgbWalletBalance() {
|
|
||||||
let _url = `/crosschain/dgb/walletbalance?apiKey=${this.myNode.apiKey}`
|
|
||||||
let _body = store.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: _url,
|
|
||||||
method: 'POST',
|
|
||||||
body: _body,
|
|
||||||
}).then((res) => {
|
|
||||||
if (isNaN(Number(res))) {
|
|
||||||
//...
|
|
||||||
} else {
|
|
||||||
this.dgbWalletBalance = (Number(res) / 1e8).toFixed(8)
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'dgb',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateDogeWalletBalance() {
|
|
||||||
let _url = `/crosschain/doge/walletbalance?apiKey=${this.myNode.apiKey}`
|
|
||||||
let _body = store.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: _url,
|
|
||||||
method: 'POST',
|
|
||||||
body: _body,
|
|
||||||
}).then((res) => {
|
|
||||||
if (isNaN(Number(res))) {
|
|
||||||
//...
|
|
||||||
} else {
|
|
||||||
this.dogeWalletBalance = (Number(res) / 1e8).toFixed(8)
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'doge',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateBtcWalletBalance() {
|
|
||||||
let _url = `/crosschain/btc/walletbalance?apiKey=${this.myNode.apiKey}`
|
|
||||||
let _body = store.getState().app.selectedAddress.btcWallet.derivedMasterPublicKey
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: _url,
|
|
||||||
method: 'POST',
|
|
||||||
body: _body,
|
|
||||||
}).then((res) => {
|
|
||||||
if (isNaN(Number(res))) {
|
|
||||||
//...
|
|
||||||
} else {
|
|
||||||
this.btcWalletBalance = (Number(res) / 1e8).toFixed(8)
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'btc',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
async updateLtcWalletBalance() {
|
|
||||||
let _url = `/crosschain/ltc/walletbalance?apiKey=${this.myNode.apiKey}`
|
|
||||||
let _body = store.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
|
|
||||||
|
|
||||||
await parentEpml.request('apiCall', {
|
|
||||||
url: _url,
|
|
||||||
method: 'POST',
|
|
||||||
body: _body,
|
|
||||||
}).then((res) => {
|
|
||||||
if (isNaN(Number(res))) {
|
|
||||||
//...
|
|
||||||
} else {
|
|
||||||
this.ltcWalletBalance = (Number(res) / 1e8).toFixed(8)
|
|
||||||
store.dispatch(
|
|
||||||
setCoinBalances({
|
|
||||||
type: 'ltc',
|
|
||||||
fullValue: Number(res)
|
|
||||||
})
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
}).catch(()=> {
|
|
||||||
console.log('error')
|
console.log('error')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateCoinList(event) {
|
_updateCoinList(event) {
|
||||||
const copyCoinList = {...this.coinList}
|
const copyCoinList = { ...this.coinList }
|
||||||
const coin = event.detail
|
const coin = event.detail
|
||||||
if(!copyCoinList[coin]){
|
|
||||||
|
if (!copyCoinList[coin]) {
|
||||||
try {
|
try {
|
||||||
if(coin === 'ltc'){
|
if (coin === 'qort') {
|
||||||
this.updateLtcWalletBalance()
|
|
||||||
} else if(coin === 'qort'){
|
|
||||||
this.updateQortWalletBalance()
|
this.updateQortWalletBalance()
|
||||||
} else if(coin === 'doge'){
|
} else if (coin === 'btc') {
|
||||||
this.updateDogeWalletBalance()
|
|
||||||
} else if(coin === 'btc'){
|
|
||||||
this.updateBtcWalletBalance()
|
this.updateBtcWalletBalance()
|
||||||
} else if(coin === 'dgb'){
|
} else if (coin === 'ltc') {
|
||||||
|
this.updateLtcWalletBalance()
|
||||||
|
} else if (coin === 'doge') {
|
||||||
|
this.updateDogeWalletBalance()
|
||||||
|
} else if (coin === 'dgb') {
|
||||||
this.updateDgbWalletBalance()
|
this.updateDgbWalletBalance()
|
||||||
} else if(coin === 'rvn'){
|
} else if (coin === 'rvn') {
|
||||||
this.updateRvnWalletBalance()
|
this.updateRvnWalletBalance()
|
||||||
}else if(coin === 'arrr'){
|
} else if (coin === 'arrr') {
|
||||||
this.updateArrrWalletBalance()
|
this.updateArrrWalletBalance()
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
copyCoinList[coin] = Date.now() + 120000
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
copyCoinList[coin] = Date.now() + 120000;
|
|
||||||
this.coinList = copyCoinList
|
this.coinList = copyCoinList
|
||||||
|
|
||||||
this.requestUpdate()
|
this.requestUpdate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchCoins(arrayOfCoins) {
|
||||||
async fetchCoins(arrayOfCoins){
|
const getCoinBalances = (arrayOfCoins || []).map(async (coin) => {
|
||||||
const getCoinBalances = (arrayOfCoins || []).map(
|
if (coin === 'qort') {
|
||||||
async (coin) => {
|
|
||||||
if(coin === 'ltc'){
|
|
||||||
await this.updateLtcWalletBalance()
|
|
||||||
} else if(coin === 'qort'){
|
|
||||||
await this.updateQortWalletBalance()
|
await this.updateQortWalletBalance()
|
||||||
} else if(coin === 'doge'){
|
} else if (coin === 'btc') {
|
||||||
await this.updateDogeWalletBalance()
|
|
||||||
} else if(coin === 'btc'){
|
|
||||||
await this.updateBtcWalletBalance()
|
await this.updateBtcWalletBalance()
|
||||||
} else if(coin === 'dgb'){
|
} else if (coin === 'ltc') {
|
||||||
|
await this.updateLtcWalletBalance()
|
||||||
|
} else if (coin === 'doge') {
|
||||||
|
await this.updateDogeWalletBalance()
|
||||||
|
} else if (coin === 'dgb') {
|
||||||
await this.updateDgbWalletBalance()
|
await this.updateDgbWalletBalance()
|
||||||
} else if(coin === 'rvn'){
|
} else if (coin === 'rvn') {
|
||||||
await this.updateRvnWalletBalance()
|
await this.updateRvnWalletBalance()
|
||||||
}else if(coin === 'arrr'){
|
} else if (coin === 'arrr') {
|
||||||
await this.updateArrrWalletBalance()
|
await this.updateArrrWalletBalance()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
await Promise.all(getCoinBalances);
|
await Promise.all(getCoinBalances)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchBalance(){
|
async fetchBalance() {
|
||||||
try {
|
try {
|
||||||
let arrayOfCoins = []
|
let arrayOfCoins = []
|
||||||
const copyObject = {...this.coinList}
|
|
||||||
|
const copyObject = { ...this.coinList }
|
||||||
const currentDate = Date.now()
|
const currentDate = Date.now()
|
||||||
const array = Object.keys(this.coinList)
|
const array = Object.keys(this.coinList)
|
||||||
|
|
||||||
for (const key of array) {
|
for (const key of array) {
|
||||||
const item = this.coinList[key]
|
const item = this.coinList[key]
|
||||||
|
|
||||||
if(item < currentDate){
|
if (item < currentDate) {
|
||||||
delete copyObject[key]
|
delete copyObject[key]
|
||||||
} else {
|
} else {
|
||||||
arrayOfCoins.push(key)
|
arrayOfCoins.push(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!this.stop){
|
|
||||||
|
if (!this.stop) {
|
||||||
this.stop = true
|
this.stop = true
|
||||||
|
|
||||||
await this.fetchCoins(arrayOfCoins)
|
await this.fetchCoins(arrayOfCoins)
|
||||||
|
|
||||||
this.stop = false
|
this.stop = false
|
||||||
}
|
}
|
||||||
|
|
||||||
this.coinList = copyObject
|
this.coinList = copyObject
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.stop = false
|
this.stop = false
|
||||||
@ -288,33 +288,16 @@ class CoinBalancesController extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback();
|
super.connectedCallback()
|
||||||
this.intervalID = setInterval(this.fetchBalance, 45000);
|
this.intervalID = setInterval(this.fetchBalance, 45000)
|
||||||
window.addEventListener(
|
window.addEventListener('ping-coin-controller-with-coin', this._updateCoinList)
|
||||||
'ping-coin-controller-with-coin',
|
|
||||||
this._updateCoinList
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
|
if (this.intervalID) { clearInterval(this.intervalID) }
|
||||||
super.disconnectedCallback();
|
window.removeEventListener('ping-coin-controller-with-coin', this._updateCoinList)
|
||||||
window.removeEventListener(
|
super.disconnectedCallback()
|
||||||
'ping-coin-controller-with-coin',
|
|
||||||
this._updateCoinList
|
|
||||||
);
|
|
||||||
if(this.intervalID){
|
|
||||||
clearInterval(this.intervalID);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return html``;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('coin-balances-controller', CoinBalancesController);
|
window.customElements.define('coin-balances-controller', CoinBalancesController)
|
@ -1,11 +1,13 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {get} from '../../../translate'
|
import { connect } from 'pwa-helpers'
|
||||||
import '@material/mwc-icon'
|
import { store } from '../../store'
|
||||||
import '@vaadin/tooltip';
|
import { get } from '../../../translate'
|
||||||
|
import { chatSideNavHeadsStyles } from '../../styles/core-css'
|
||||||
import './friend-item-actions'
|
import './friend-item-actions'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import '@vaadin/tooltip'
|
||||||
|
|
||||||
class ChatSideNavHeads extends LitElement {
|
class ChatSideNavHeads extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
selectedAddress: { type: Object },
|
selectedAddress: { type: Object },
|
||||||
@ -14,62 +16,14 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
iconName: { type: String },
|
iconName: { type: String },
|
||||||
activeChatHeadUrl: { type: String },
|
activeChatHeadUrl: { type: String },
|
||||||
isImageLoaded: { type: Boolean },
|
isImageLoaded: { type: Boolean },
|
||||||
setActiveChatHeadUrl: {attribute: false},
|
setActiveChatHeadUrl: { attribute: false },
|
||||||
openEditFriend: {attribute: false},
|
openEditFriend: { attribute: false },
|
||||||
closeSidePanel: {attribute: false, type: Object}
|
closeSidePanel: { attribute: false, type: Object }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [chatSideNavHeadsStyles]
|
||||||
:host {
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
ul {
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
li {
|
|
||||||
padding: 10px 2px 10px 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 14px;
|
|
||||||
transition: 0.2s background-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
li:hover {
|
|
||||||
background-color: var(--lightChatHeadHover);
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
background: var(--menuactive);
|
|
||||||
border-left: 4px solid #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-icon {
|
|
||||||
font-size:40px;
|
|
||||||
color: var(--chat-group);
|
|
||||||
}
|
|
||||||
|
|
||||||
.status {
|
|
||||||
color: #92959e;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.clearfix:after {
|
|
||||||
visibility: hidden;
|
|
||||||
display: block;
|
|
||||||
font-size: 0;
|
|
||||||
content: " ";
|
|
||||||
clear: both;
|
|
||||||
height: 0;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -78,7 +32,6 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
this.config = {
|
this.config = {
|
||||||
user: {
|
user: {
|
||||||
node: {
|
node: {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -89,66 +42,52 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
this.imageFetches = 0
|
this.imageFetches = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
createImage(imageUrl) {
|
|
||||||
const imageHTMLRes = new Image();
|
|
||||||
imageHTMLRes.src = imageUrl;
|
|
||||||
imageHTMLRes.style= "width:30px; height:30px; float: left; border-radius:50%; font-size:14px";
|
|
||||||
imageHTMLRes.onclick= () => {
|
|
||||||
this.openDialogImage = true;
|
|
||||||
}
|
|
||||||
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() {
|
render() {
|
||||||
let avatarImg = ""
|
let avatarImg = ''
|
||||||
|
|
||||||
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 = store.getState().app.nodeConfig.knownNodes[store.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`
|
||||||
avatarImg = this.createImage(avatarUrl)
|
avatarImg = this.createImage(avatarUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<li style="display:flex; justify-content: space-between; align-items: center" @click=${(e) => {
|
<li
|
||||||
|
style="display:flex; justify-content: space-between; align-items: center"
|
||||||
|
@click=${(e) => {
|
||||||
const target = e.target
|
const target = e.target
|
||||||
const popover =
|
const popover = this.shadowRoot.querySelector('friend-item-actions');
|
||||||
this.shadowRoot.querySelector('friend-item-actions');
|
|
||||||
if (popover) {
|
if (popover) {
|
||||||
popover.openPopover(target);
|
popover.openPopover(target);
|
||||||
}
|
}
|
||||||
}} class="clearfix" id=${`friend-item-parent-${this.chatInfo.name}`}>
|
}}
|
||||||
|
class="clearfix" id=${`friend-item-parent-${this.chatInfo.name}`}
|
||||||
|
>
|
||||||
<div style="display:flex; flex-grow: 1; align-items: center">
|
<div style="display:flex; flex-grow: 1; align-items: center">
|
||||||
${this.isImageLoaded ? html`${avatarImg}` : html``}
|
${this.isImageLoaded ? html`${avatarImg}` : html``}
|
||||||
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName
|
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ?
|
||||||
? html`<mwc-icon class="img-icon">account_circle</mwc-icon>`
|
html`
|
||||||
: html``}
|
<mwc-icon class="img-icon">account_circle</mwc-icon>
|
||||||
${!this.isImageLoaded && this.chatInfo.name
|
`
|
||||||
? html`<div
|
: html``
|
||||||
|
}
|
||||||
|
${!this.isImageLoaded && this.chatInfo.name ?
|
||||||
|
html`
|
||||||
|
<div
|
||||||
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
? "var(--chatHeadBgActive)"
|
? "var(--chatHeadBgActive)"
|
||||||
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl ===
|
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
this.chatInfo.url
|
|
||||||
? "var(--chatHeadTextActive)"
|
? "var(--chatHeadTextActive)"
|
||||||
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
||||||
>
|
>
|
||||||
${this.chatInfo.name.charAt(0)}
|
${this.chatInfo.name.charAt(0)}
|
||||||
</div>`
|
</div>
|
||||||
: ""}
|
` : ''
|
||||||
${!this.isImageLoaded && this.chatInfo.groupName
|
}
|
||||||
? html`<div
|
${!this.isImageLoaded && this.chatInfo.groupName ?
|
||||||
|
html`
|
||||||
|
<div
|
||||||
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
style="width:30px; height:30px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
? "var(--chatHeadBgActive)"
|
? "var(--chatHeadBgActive)"
|
||||||
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl === this.chatInfo.url
|
: "var(--chatHeadBg)"}; color: ${this.activeChatHeadUrl === this.chatInfo.url
|
||||||
@ -156,8 +95,9 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
: "var(--chatHeadText)"}; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize"
|
||||||
>
|
>
|
||||||
${this.chatInfo.groupName.charAt(0)}
|
${this.chatInfo.groupName.charAt(0)}
|
||||||
</div>`
|
</div>
|
||||||
: ""}
|
` : ''
|
||||||
|
}
|
||||||
<div>
|
<div>
|
||||||
<div class="name">
|
<div class="name">
|
||||||
<span style="float:left; padding-left: 8px; color: var(--chat-group);">
|
<span style="float:left; padding-left: 8px; color: var(--chat-group);">
|
||||||
@ -165,30 +105,31 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
? this.chatInfo.groupName
|
? this.chatInfo.groupName
|
||||||
: this.chatInfo.name !== undefined
|
: this.chatInfo.name !== undefined
|
||||||
? (this.chatInfo.alias || this.chatInfo.name)
|
? (this.chatInfo.alias || this.chatInfo.name)
|
||||||
: this.chatInfo.address.substr(0, 15)}
|
: this.chatInfo.address.substr(0, 15)
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex; align-items: center">
|
<div style="display:flex; align-items: center">
|
||||||
${this.chatInfo.willFollow ? html`
|
${this.chatInfo.willFollow ?
|
||||||
|
html`
|
||||||
<mwc-icon id="willFollowIcon" style="color: var(--black)">connect_without_contact</mwc-icon>
|
<mwc-icon id="willFollowIcon" style="color: var(--black)">connect_without_contact</mwc-icon>
|
||||||
<vaadin-tooltip
|
<vaadin-tooltip
|
||||||
|
|
||||||
for="willFollowIcon"
|
for="willFollowIcon"
|
||||||
position="top"
|
position="top"
|
||||||
hover-delay=${200}
|
hover-delay=${200}
|
||||||
hide-delay=${1}
|
hide-delay=${1}
|
||||||
text=${get('friends.friend11')}>
|
text=${get('friends.friend11')}
|
||||||
</vaadin-tooltip>
|
></vaadin-tooltip>
|
||||||
` : ''}
|
` : ''
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<friend-item-actions
|
<friend-item-actions
|
||||||
for=${`friend-item-parent-${this.chatInfo.name}`}
|
for=${`friend-item-parent-${this.chatInfo.name}`}
|
||||||
message=${get('notifications.explanation')}
|
message=${get('notifications.explanation')}
|
||||||
.openEditFriend=${()=> {
|
.openEditFriend=${() => {
|
||||||
this.openEditFriend(this.chatInfo)
|
this.openEditFriend(this.chatInfo)
|
||||||
}}
|
}}
|
||||||
name=${this.chatInfo.name}
|
name=${this.chatInfo.name}
|
||||||
@ -197,25 +138,67 @@ class ChatSideNavHeads extends LitElement {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
createImage(imageUrl) {
|
||||||
|
const imageHTMLRes = new Image()
|
||||||
|
imageHTMLRes.src = imageUrl
|
||||||
|
imageHTMLRes.style = "width:30px; height:30px; float: left; border-radius:50%; font-size:14px"
|
||||||
|
|
||||||
|
imageHTMLRes.onclick = () => {
|
||||||
|
this.openDialogImage = true
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
shouldUpdate(changedProperties) {
|
shouldUpdate(changedProperties) {
|
||||||
if(changedProperties.has('activeChatHeadUrl')){
|
if (changedProperties.has('activeChatHeadUrl')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
if(changedProperties.has('chatInfo')){
|
|
||||||
|
if (changedProperties.has('chatInfo')) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return !!changedProperties.has('isImageLoaded');
|
|
||||||
|
|
||||||
|
|
||||||
|
return !!changedProperties.has('isImageLoaded')
|
||||||
}
|
}
|
||||||
|
|
||||||
getUrl(chatUrl) {
|
getUrl(chatUrl) {
|
||||||
this.setActiveChatHeadUrl(chatUrl)
|
this.setActiveChatHeadUrl(chatUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('chat-side-nav-heads', ChatSideNavHeads)
|
window.customElements.define('chat-side-nav-heads', ChatSideNavHeads)
|
@ -1,10 +1,11 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {translate,} from '../../../translate'
|
import { connect } from 'pwa-helpers'
|
||||||
import '@material/mwc-button';
|
import { store } from '../../store'
|
||||||
import '@material/mwc-dialog';
|
import { translate, } from '../../../translate'
|
||||||
import '@material/mwc-checkbox';
|
import { addFriendsModalStyles } from '../../styles/core-css'
|
||||||
import {connect} from 'pwa-helpers';
|
import '@material/mwc-button'
|
||||||
import {store} from '../../store';
|
import '@material/mwc-checkbox'
|
||||||
|
import '@material/mwc-dialog'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
|
|
||||||
class AddFriendsModal extends connect(store)(LitElement) {
|
class AddFriendsModal extends connect(store)(LitElement) {
|
||||||
@ -21,275 +22,32 @@ class AddFriendsModal extends connect(store)(LitElement) {
|
|||||||
editContent: { type: Object },
|
editContent: { type: Object },
|
||||||
onClose: { attribute: false },
|
onClose: { attribute: false },
|
||||||
mySelectedFeeds: { type: Array },
|
mySelectedFeeds: { type: Array },
|
||||||
availableFeeedSchemas: {type: Array},
|
availableFeeedSchemas: { type: Array },
|
||||||
isLoadingSchemas: {type: Boolean}
|
isLoadingSchemas: { type: Boolean }
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.isOpen = false;
|
|
||||||
this.isLoading = false;
|
|
||||||
this.alias = '';
|
|
||||||
this.willFollow = true;
|
|
||||||
this.notes = '';
|
|
||||||
this.nodeUrl = this.getNodeUrl();
|
|
||||||
this.myNode = this.getMyNode();
|
|
||||||
this.mySelectedFeeds = [];
|
|
||||||
this.availableFeeedSchemas = [];
|
|
||||||
this.isLoadingSchemas= false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [addFriendsModalStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-dialog-min-width: 400px;
|
|
||||||
--mdc-dialog-max-width: 1024px;
|
|
||||||
box-sizing:border-box;
|
|
||||||
}
|
|
||||||
.input {
|
|
||||||
width: 90%;
|
|
||||||
outline: 0;
|
|
||||||
border-width: 0 0 2px;
|
|
||||||
border-color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.input::selection {
|
constructor() {
|
||||||
background-color: var(--mdc-theme-primary);
|
super()
|
||||||
color: white;
|
this.isOpen = false
|
||||||
}
|
this.isLoading = false
|
||||||
|
this.alias = ''
|
||||||
.input::placeholder {
|
this.willFollow = true
|
||||||
opacity: 0.6;
|
this.notes = ''
|
||||||
color: var(--black);
|
this.nodeUrl = this.getNodeUrl()
|
||||||
}
|
this.myNode = this.getMyNode()
|
||||||
|
this.mySelectedFeeds = []
|
||||||
.modal-button {
|
this.availableFeeedSchemas = []
|
||||||
font-family: Roboto, sans-serif;
|
this.isLoadingSchemas = false
|
||||||
font-size: 16px;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button-red {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #f44336;
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button-red:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #f4433663;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #03a8f475;
|
|
||||||
}
|
|
||||||
.checkbox-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
.modal-overlay {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
background-color: rgba(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0.5
|
|
||||||
); /* Semi-transparent backdrop */
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
position: fixed;
|
|
||||||
top: 50vh;
|
|
||||||
left: 50vw;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
background-color: var(--mdc-theme-surface);
|
|
||||||
width: 80vw;
|
|
||||||
max-width: 600px;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;
|
|
||||||
z-index: 1001;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction:column;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.modal-overlay.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-name {
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.inner-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: 75vh;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar-track {
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar {
|
|
||||||
width: 12px;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(180, 176, 176);
|
|
||||||
border-radius: 7px;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {}
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
clearFields() {
|
|
||||||
this.alias = '';
|
|
||||||
this.willFollow = true;
|
|
||||||
this.notes = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
addFriend() {
|
|
||||||
this.onSubmit({
|
|
||||||
name: this.userSelected.name,
|
|
||||||
alias: this.alias,
|
|
||||||
notes: this.notes,
|
|
||||||
willFollow: this.willFollow,
|
|
||||||
mySelectedFeeds: this.mySelectedFeeds
|
|
||||||
|
|
||||||
});
|
|
||||||
this.clearFields();
|
|
||||||
this.onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
removeFriend() {
|
|
||||||
this.onSubmit(
|
|
||||||
{
|
|
||||||
name: this.userSelected.name,
|
|
||||||
alias: this.alias,
|
|
||||||
notes: this.notes,
|
|
||||||
willFollow: this.willFollow,
|
|
||||||
mySelectedFeeds: this.mySelectedFeeds
|
|
||||||
},
|
|
||||||
true
|
|
||||||
);
|
|
||||||
this.clearFields();
|
|
||||||
this.onClose();
|
|
||||||
}
|
|
||||||
|
|
||||||
async updated(changedProperties) {
|
|
||||||
if (
|
|
||||||
changedProperties &&
|
|
||||||
changedProperties.has('editContent') &&
|
|
||||||
this.editContent
|
|
||||||
) {
|
|
||||||
this.userSelected = {
|
|
||||||
name: this.editContent.name ?? '',
|
|
||||||
};
|
|
||||||
this.notes = this.editContent.notes ?? '';
|
|
||||||
this.willFollow = this.editContent.willFollow ?? true;
|
|
||||||
this.alias = this.editContent.alias ?? '';
|
|
||||||
this.requestUpdate()
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
changedProperties &&
|
|
||||||
changedProperties.has('isOpen') && this.isOpen
|
|
||||||
) {
|
|
||||||
await this.getAvailableFeedSchemas()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async getAvailableFeedSchemas() {
|
|
||||||
try {
|
|
||||||
this.isLoadingSchemas= true
|
|
||||||
const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT&identifier=ui_schema_feed&prefix=true`;
|
|
||||||
const res = await fetch(url);
|
|
||||||
const data = await res.json();
|
|
||||||
if (data.error === 401) {
|
|
||||||
this.availableFeeedSchemas = [];
|
|
||||||
} else {
|
|
||||||
this.availableFeeedSchemas = data.filter(
|
|
||||||
(item) => item.identifier === 'ui_schema_feed'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.userFoundModalOpen = true;
|
|
||||||
} catch (error) {} finally {
|
|
||||||
this.isLoadingSchemas= false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="modal-overlay ${this.isOpen ? '' : 'hidden'}">
|
<div class="modal-overlay ${this.isOpen ? '' : 'hidden'}">
|
||||||
|
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
<div class="inner-content">
|
<div class="inner-content">
|
||||||
<div style="text-align:center">
|
<div style="text-align:center">
|
||||||
@ -331,9 +89,7 @@ class AddFriendsModal extends connect(store)(LitElement) {
|
|||||||
id="name"
|
id="name"
|
||||||
class="input"
|
class="input"
|
||||||
?disabled=${true}
|
?disabled=${true}
|
||||||
value=${this.userSelected
|
value=${this.userSelected ? this.userSelected.name : ''}
|
||||||
? this.userSelected.name
|
|
||||||
: ''}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div style="height:15px"></div>
|
<div style="height:15px"></div>
|
||||||
@ -375,67 +131,42 @@ class AddFriendsModal extends connect(store)(LitElement) {
|
|||||||
<p>${translate('friends.friend16')}</p>
|
<p>${translate('friends.friend16')}</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
${this.isLoadingSchemas ? html`
|
${this.isLoadingSchemas ?
|
||||||
|
html`
|
||||||
<div style="width:100%;display: flex; justify-content:center">
|
<div style="width:100%;display: flex; justify-content:center">
|
||||||
<paper-spinner-lite active></paper-spinner-lite>
|
<paper-spinner-lite active></paper-spinner-lite>
|
||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''
|
||||||
|
}
|
||||||
${this.availableFeeedSchemas.map((schema) => {
|
${this.availableFeeedSchemas.map((schema) => {
|
||||||
const isAlreadySelected = this.mySelectedFeeds.find(
|
const isAlreadySelected = this.mySelectedFeeds.find((item) => item.name === schema.name);
|
||||||
(item) => item.name === schema.name
|
|
||||||
);
|
|
||||||
let avatarImgApp;
|
let avatarImgApp;
|
||||||
const avatarUrl2 = `${this.nodeUrl}/arbitrary/THUMBNAIL/${schema.name}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
const avatarUrl2 = `${this.nodeUrl}/arbitrary/THUMBNAIL/${schema.name}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
||||||
avatarImgApp = html`<img
|
avatarImgApp = html`<img src="${avatarUrl2}" style="max-width:100%; max-height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';"/>`;
|
||||||
src="${avatarUrl2}"
|
|
||||||
style="max-width:100%; max-height:100%;"
|
|
||||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
|
||||||
/>`;
|
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div
|
||||||
class="app-name"
|
class="app-name"
|
||||||
style="background:${isAlreadySelected ? 'lightblue': ''}"
|
style="background:${isAlreadySelected ? 'lightblue' : ''}"
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
const copymySelectedFeeds = [
|
const copymySelectedFeeds = [...this.mySelectedFeeds];
|
||||||
...this.mySelectedFeeds,
|
const findIndex = copymySelectedFeeds.findIndex((item) => item.name === schema.name);
|
||||||
];
|
|
||||||
const findIndex =
|
|
||||||
copymySelectedFeeds.findIndex(
|
|
||||||
(item) =>
|
|
||||||
item.name === schema.name
|
|
||||||
);
|
|
||||||
if (findIndex === -1) {
|
if (findIndex === -1) {
|
||||||
if(this.mySelectedFeeds.length > 4) return
|
if (this.mySelectedFeeds.length > 4) return
|
||||||
copymySelectedFeeds.push({
|
copymySelectedFeeds.push({name: schema.name, identifier: schema.identifier, service: schema.service});
|
||||||
name: schema.name,
|
this.mySelectedFeeds = copymySelectedFeeds;
|
||||||
identifier: schema.identifier,
|
|
||||||
service: schema.service,
|
|
||||||
});
|
|
||||||
this.mySelectedFeeds =
|
|
||||||
copymySelectedFeeds;
|
|
||||||
} else {
|
} else {
|
||||||
this.mySelectedFeeds =
|
this.mySelectedFeeds = copymySelectedFeeds.filter((item) => item.name !== schema.name);
|
||||||
copymySelectedFeeds.filter(
|
|
||||||
(item) =>
|
|
||||||
item.name !==
|
|
||||||
schema.name
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div class="avatar">${avatarImgApp}</div>
|
<div class="avatar">${avatarImgApp}</div>
|
||||||
<span
|
<span style="color:${isAlreadySelected ? 'var(--white)' : 'var(--black)'};font-size:16px">${schema.name}</span>
|
||||||
style="color:${isAlreadySelected ? 'var(--white)': 'var(--black)'};font-size:16px"
|
|
||||||
>${schema.name}</span
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:20px">
|
||||||
style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="modal-button-red"
|
class="modal-button-red"
|
||||||
?disabled="${this.isLoading}"
|
?disabled="${this.isLoading}"
|
||||||
@ -447,36 +178,118 @@ class AddFriendsModal extends connect(store)(LitElement) {
|
|||||||
>
|
>
|
||||||
${translate('general.close')}
|
${translate('general.close')}
|
||||||
</button>
|
</button>
|
||||||
${this.editContent
|
${this.editContent ?
|
||||||
? html`
|
html`
|
||||||
<button
|
<button ?disabled="${this.isLoading}" class="modal-button-red" @click=${() => {this.removeFriend();}}>
|
||||||
?disabled="${this.isLoading}"
|
|
||||||
class="modal-button-red"
|
|
||||||
@click=${() => {
|
|
||||||
this.removeFriend();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
${translate('friends.friend14')}
|
${translate('friends.friend14')}
|
||||||
</button>
|
</button>
|
||||||
`
|
` : ''
|
||||||
: ''}
|
}
|
||||||
|
<button ?disabled="${this.isLoading}" class="modal-button" @click=${() => {this.addFriend();}}>
|
||||||
<button
|
${this.editContent ? translate('friends.friend10') : translate('friends.friend2')}
|
||||||
?disabled="${this.isLoading}"
|
|
||||||
class="modal-button"
|
|
||||||
@click=${() => {
|
|
||||||
this.addFriend();
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
${this.editContent
|
|
||||||
? translate('friends.friend10')
|
|
||||||
: translate('friends.friend2')}
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyNode() {
|
||||||
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFields() {
|
||||||
|
this.alias = ''
|
||||||
|
this.willFollow = true
|
||||||
|
this.notes = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
addFriend() {
|
||||||
|
this.onSubmit({
|
||||||
|
name: this.userSelected.name,
|
||||||
|
alias: this.alias,
|
||||||
|
notes: this.notes,
|
||||||
|
willFollow: this.willFollow,
|
||||||
|
mySelectedFeeds: this.mySelectedFeeds
|
||||||
|
})
|
||||||
|
|
||||||
|
this.clearFields()
|
||||||
|
this.onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
removeFriend() {
|
||||||
|
this.onSubmit(
|
||||||
|
{
|
||||||
|
name: this.userSelected.name,
|
||||||
|
alias: this.alias,
|
||||||
|
notes: this.notes,
|
||||||
|
willFollow: this.willFollow,
|
||||||
|
mySelectedFeeds: this.mySelectedFeeds
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
this.clearFields()
|
||||||
|
this.onClose()
|
||||||
|
}
|
||||||
|
|
||||||
|
async updated(changedProperties) {
|
||||||
|
if (changedProperties && changedProperties.has('editContent') && this.editContent) {
|
||||||
|
this.userSelected = { name: this.editContent.name ?? '' }
|
||||||
|
this.notes = this.editContent.notes ?? ''
|
||||||
|
this.willFollow = this.editContent.willFollow ?? true
|
||||||
|
this.alias = this.editContent.alias ?? ''
|
||||||
|
this.requestUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (changedProperties && changedProperties.has('isOpen') && this.isOpen) {
|
||||||
|
await this.getAvailableFeedSchemas()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getAvailableFeedSchemas() {
|
||||||
|
try {
|
||||||
|
this.isLoadingSchemas = true
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT&identifier=ui_schema_feed&prefix=true`
|
||||||
|
const res = await fetch(url)
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
if (data.error === 401) {
|
||||||
|
this.availableFeeedSchemas = []
|
||||||
|
} else {
|
||||||
|
this.availableFeeedSchemas = data.filter((item) => item.identifier === 'ui_schema_feed')
|
||||||
|
}
|
||||||
|
|
||||||
|
this.userFoundModalOpen = true
|
||||||
|
} catch (error) {
|
||||||
|
} finally {
|
||||||
|
this.isLoadingSchemas = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('add-friends-modal', AddFriendsModal);
|
window.customElements.define('add-friends-modal', AddFriendsModal)
|
@ -1,16 +1,17 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import axios from 'axios';
|
import { connect } from 'pwa-helpers'
|
||||||
import '@material/mwc-menu';
|
import { store } from '../../store'
|
||||||
import '@material/mwc-list/mwc-list-item.js';
|
import { RequestQueueWithPromise } from '../../../../plugins/plugins/utils/classes'
|
||||||
import {RequestQueueWithPromise} from '../../../../plugins/plugins/utils/queue';
|
import { avatarComponentStyles } from '../../styles/core-css'
|
||||||
import '../../../../plugins/plugins/core/components/TimeAgo';
|
import axios from 'axios'
|
||||||
import {connect} from 'pwa-helpers';
|
import ShortUniqueId from 'short-unique-id'
|
||||||
import {store} from '../../store';
|
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import '@material/mwc-menu'
|
||||||
|
import '@material/mwc-list/mwc-list-item.js'
|
||||||
|
|
||||||
const requestQueue = new RequestQueueWithPromise(3);
|
const requestQueue = new RequestQueueWithPromise(3)
|
||||||
const requestQueueRawData = new RequestQueueWithPromise(3);
|
const requestQueueRawData = new RequestQueueWithPromise(3)
|
||||||
const requestQueueStatus = new RequestQueueWithPromise(3);
|
const requestQueueStatus = new RequestQueueWithPromise(3)
|
||||||
|
|
||||||
export class AvatarComponent extends connect(store)(LitElement) {
|
export class AvatarComponent extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -18,284 +19,210 @@ export class AvatarComponent extends connect(store)(LitElement) {
|
|||||||
resource: { type: Object },
|
resource: { type: Object },
|
||||||
isReady: { type: Boolean },
|
isReady: { type: Boolean },
|
||||||
status: { type: Object },
|
status: { type: Object },
|
||||||
name: { type: String },
|
name: { type: String }
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [avatarComponentStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-text-primary-on-background: var(--black);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
:host {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
width: 100%;
|
|
||||||
max-height: 30vh;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.smallLoading,
|
|
||||||
.smallLoading:after {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 2px;
|
|
||||||
height: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.defaultSize {
|
|
||||||
width: 100%;
|
|
||||||
height: 160px;
|
|
||||||
}
|
|
||||||
.parent-feed-item {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
background-color: var(--chat-bubble-bg);
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 12px 15px 4px 15px;
|
|
||||||
min-width: 150px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius: 50%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.avatarApp {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius: 50%;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.feed-item-name {
|
|
||||||
user-select: none;
|
|
||||||
color: #03a9f4;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-name {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-menu {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.resource = {
|
this.resource = {
|
||||||
identifier: '',
|
identifier: '',
|
||||||
name: '',
|
name: '',
|
||||||
service: '',
|
service: ''
|
||||||
};
|
}
|
||||||
this.status = {
|
this.status = {
|
||||||
status: '',
|
status: ''
|
||||||
};
|
|
||||||
this.isReady = false;
|
|
||||||
this.nodeUrl = this.getNodeUrl();
|
|
||||||
this.myNode = this.getMyNode();
|
|
||||||
this.isFetching = false;
|
|
||||||
this.uid = new ShortUniqueId();
|
|
||||||
}
|
}
|
||||||
getNodeUrl() {
|
this.isReady = false
|
||||||
const myNode =
|
this.nodeUrl = this.getNodeUrl()
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
this.myNode = this.getMyNode()
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
this.isFetching = false
|
||||||
];
|
this.uid = new ShortUniqueId()
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
getApiKey() {
|
|
||||||
const myNode =
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
return myNode.apiKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchResource() {
|
|
||||||
try {
|
|
||||||
if (this.isFetching) return;
|
|
||||||
this.isFetching = true;
|
|
||||||
await axios.get(
|
|
||||||
`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
|
||||||
);
|
|
||||||
this.isFetching = false;
|
|
||||||
} catch (error) {
|
|
||||||
this.isFetching = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchVideoUrl() {
|
|
||||||
await this.fetchResource();
|
|
||||||
}
|
|
||||||
|
|
||||||
async getRawData() {
|
|
||||||
const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`;
|
|
||||||
return await requestQueueRawData.enqueue(() => {
|
|
||||||
return axios.get(url);
|
|
||||||
});
|
|
||||||
// const response2 = await fetch(url, {
|
|
||||||
// method: 'GET',
|
|
||||||
// headers: {
|
|
||||||
// 'Content-Type': 'application/json'
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
// const responseData2 = await response2.json()
|
|
||||||
// return responseData2
|
|
||||||
}
|
|
||||||
|
|
||||||
updateDisplayWithPlaceholders(display, resource, rawdata) {
|
|
||||||
const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g;
|
|
||||||
|
|
||||||
for (const key in display) {
|
|
||||||
const value = display[key];
|
|
||||||
|
|
||||||
display[key] = value.replace(pattern, (match, p1) => {
|
|
||||||
if (p1.startsWith('rawdata.')) {
|
|
||||||
const dataKey = p1.split('.')[1];
|
|
||||||
if (rawdata[dataKey] === undefined) {
|
|
||||||
console.error('rawdata key not found:', dataKey);
|
|
||||||
}
|
|
||||||
return rawdata[dataKey] || match;
|
|
||||||
} else if (p1.startsWith('resource.')) {
|
|
||||||
const resourceKey = p1.split('.')[1];
|
|
||||||
if (resource[resourceKey] === undefined) {
|
|
||||||
console.error('resource key not found:', resourceKey);
|
|
||||||
}
|
|
||||||
return resource[resourceKey] || match;
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchStatus() {
|
|
||||||
let isCalling = false;
|
|
||||||
let percentLoaded = 0;
|
|
||||||
let timer = 24;
|
|
||||||
const response = await requestQueueStatus.enqueue(() => {
|
|
||||||
return axios.get(
|
|
||||||
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
if (response && response.data && response.data.status === 'READY') {
|
|
||||||
this.status = response.data;
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const intervalId = setInterval(async () => {
|
|
||||||
if (isCalling) return;
|
|
||||||
isCalling = true;
|
|
||||||
|
|
||||||
const data = await requestQueue.enqueue(() => {
|
|
||||||
return axios.get(
|
|
||||||
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const res = data.data;
|
|
||||||
|
|
||||||
isCalling = false;
|
|
||||||
if (res.localChunkCount) {
|
|
||||||
if (res.percentLoaded) {
|
|
||||||
if (
|
|
||||||
res.percentLoaded === percentLoaded &&
|
|
||||||
res.percentLoaded !== 100
|
|
||||||
) {
|
|
||||||
timer = timer - 5;
|
|
||||||
} else {
|
|
||||||
timer = 24;
|
|
||||||
}
|
|
||||||
if (timer < 0) {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
}
|
|
||||||
percentLoaded = res.percentLoaded;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.status = res;
|
|
||||||
if (this.status.status === 'DOWNLOADED') {
|
|
||||||
await this.fetchResource();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if progress is 100% and clear interval if true
|
|
||||||
if (res.status === 'READY') {
|
|
||||||
clearInterval(intervalId);
|
|
||||||
this.status = res;
|
|
||||||
this.isReady = true;
|
|
||||||
}
|
|
||||||
}, 5000); // 1 second interval
|
|
||||||
}
|
|
||||||
|
|
||||||
async _fetchImage() {
|
|
||||||
try {
|
|
||||||
await this.fetchVideoUrl();
|
|
||||||
await this.fetchStatus();
|
|
||||||
} catch (error) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this._fetchImage();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div>
|
<div>
|
||||||
${this.status.status !== 'READY'
|
${this.status.status !== 'READY' ?
|
||||||
? html`
|
html`
|
||||||
<mwc-icon style="user-select:none;"
|
<mwc-icon style="user-select:none;">account_circle</mwc-icon>
|
||||||
>account_circle</mwc-icon
|
` : ''
|
||||||
>
|
}
|
||||||
`
|
${this.status.status === 'READY' ?
|
||||||
: ''}
|
html`
|
||||||
${this.status.status === 'READY'
|
<div style="height: 24px;width: 24px;overflow: hidden;">
|
||||||
? html`
|
|
||||||
<div
|
|
||||||
style="height: 24px;width: 24px;overflow: hidden;"
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
src="${this
|
src="${this.nodeUrl}/arbitrary/THUMBNAIL/${this.name}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}"
|
||||||
.nodeUrl}/arbitrary/THUMBNAIL/${this
|
|
||||||
.name}/qortal_avatar?async=true&apiKey=${this
|
|
||||||
.myNode.apiKey}"
|
|
||||||
style="width:100%; height:100%;border-radius:50%"
|
style="width:100%; height:100%;border-radius:50%"
|
||||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
`
|
` : ''
|
||||||
: ''}
|
}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this._fetchImage()
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyNode() {
|
||||||
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchResource() {
|
||||||
|
try {
|
||||||
|
if (this.isFetching) return
|
||||||
|
|
||||||
|
this.isFetching = true
|
||||||
|
|
||||||
|
await axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
)
|
||||||
|
|
||||||
|
this.isFetching = false
|
||||||
|
} catch (error) {
|
||||||
|
this.isFetching = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchVideoUrl() {
|
||||||
|
await this.fetchResource()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getRawData() {
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
|
||||||
|
return await requestQueueRawData.enqueue(() => {
|
||||||
|
return axios.get(url)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
updateDisplayWithPlaceholders(display, resource, rawdata) {
|
||||||
|
const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g
|
||||||
|
|
||||||
|
for (const key in display) {
|
||||||
|
const value = display[key]
|
||||||
|
|
||||||
|
display[key] = value.replace(pattern, (match, p1) => {
|
||||||
|
if (p1.startsWith('rawdata.')) {
|
||||||
|
const dataKey = p1.split('.')[1]
|
||||||
|
|
||||||
|
if (rawdata[dataKey] === undefined) {
|
||||||
|
console.error('rawdata key not found:', dataKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawdata[dataKey] || match
|
||||||
|
} else if (p1.startsWith('resource.')) {
|
||||||
|
const resourceKey = p1.split('.')[1]
|
||||||
|
|
||||||
|
if (resource[resourceKey] === undefined) {
|
||||||
|
console.error('resource key not found:', resourceKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return resource[resourceKey] || match
|
||||||
|
}
|
||||||
|
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchStatus() {
|
||||||
|
let isCalling = false
|
||||||
|
let percentLoaded = 0
|
||||||
|
let timer = 24
|
||||||
|
|
||||||
|
const response = await requestQueueStatus.enqueue(() => {
|
||||||
|
return axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (response && response.data && response.data.status === 'READY') {
|
||||||
|
this.status = response.data
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const intervalId = setInterval(async () => {
|
||||||
|
if (isCalling) return
|
||||||
|
|
||||||
|
isCalling = true
|
||||||
|
|
||||||
|
const data = await requestQueue.enqueue(() => {
|
||||||
|
return axios.get(
|
||||||
|
`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
const res = data.data
|
||||||
|
|
||||||
|
isCalling = false
|
||||||
|
|
||||||
|
if (res.localChunkCount) {
|
||||||
|
if (res.percentLoaded) {
|
||||||
|
if (res.percentLoaded === percentLoaded && res.percentLoaded !== 100) {
|
||||||
|
timer = timer - 5
|
||||||
|
} else {
|
||||||
|
timer = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timer < 0) {
|
||||||
|
clearInterval(intervalId)
|
||||||
|
}
|
||||||
|
|
||||||
|
percentLoaded = res.percentLoaded
|
||||||
|
}
|
||||||
|
|
||||||
|
this.status = res
|
||||||
|
|
||||||
|
if (this.status.status === 'DOWNLOADED') {
|
||||||
|
await this.fetchResource()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if progress is 100% and clear interval if true
|
||||||
|
if (res.status === 'READY') {
|
||||||
|
clearInterval(intervalId)
|
||||||
|
this.status = res
|
||||||
|
this.isReady = true
|
||||||
|
}
|
||||||
|
}, 5000) // 5 second interval
|
||||||
|
}
|
||||||
|
|
||||||
|
async _fetchImage() {
|
||||||
|
try {
|
||||||
|
await this.fetchVideoUrl()
|
||||||
|
await this.fetchStatus()
|
||||||
|
} catch (error) {
|
||||||
|
/* empty */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('avatar-component', AvatarComponent);
|
window.customElements.define('avatar-component', AvatarComponent)
|
@ -1,196 +1,76 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers';
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store'
|
||||||
import '@vaadin/item';
|
import { setNewTab } from '../../redux/app/app-actions'
|
||||||
import '@vaadin/list-box';
|
import { get } from '../../../translate'
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js';
|
import { beginnerChecklistStyles } from '../../styles/core-css'
|
||||||
import '@polymer/iron-icons/iron-icons.js';
|
import ShortUniqueId from 'short-unique-id'
|
||||||
import {store} from '../../store.js';
|
import '../notification-view/popover'
|
||||||
import {setNewTab} from '../../redux/app/app-actions.js';
|
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||||
import '@material/mwc-icon';
|
import '@material/mwc-icon'
|
||||||
import {get} from '../../../translate';
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
import '../../../../plugins/plugins/core/components/TimeAgo.js';
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
import '../notification-view/popover.js';
|
import '@vaadin/item'
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import '@vaadin/list-box'
|
||||||
|
|
||||||
class BeginnerChecklist extends connect(store)(LitElement) {
|
class BeginnerChecklist extends connect(store)(LitElement) {
|
||||||
static properties = {
|
static get properties() {
|
||||||
|
return {
|
||||||
notifications: { type: Array },
|
notifications: { type: Array },
|
||||||
showChecklist: { type: Boolean },
|
showChecklist: { type: Boolean },
|
||||||
theme: { type: String, reflect: true },
|
|
||||||
isSynced: { type: Boolean },
|
isSynced: { type: Boolean },
|
||||||
hasName: { type: Boolean },
|
hasName: { type: Boolean },
|
||||||
hasTourFinished: { type: Boolean },
|
hasTourFinished: { type: Boolean },
|
||||||
};
|
theme: { type: String, reflect: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [beginnerChecklistStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.showChecklist = false;
|
this.showChecklist = false
|
||||||
this.initialFetch = false;
|
this.initialFetch = false
|
||||||
this.theme = localStorage.getItem('qortalTheme')
|
this.isSynced = false
|
||||||
? localStorage.getItem('qortalTheme')
|
this.hasName = null
|
||||||
: 'light';
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.isSynced = false;
|
this.myNode = this.getMyNode()
|
||||||
this.hasName = null;
|
this.hasTourFinished = null
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this._controlTourFinished = this._controlTourFinished.bind(this)
|
||||||
this.myNode = this.getMyNode();
|
this.uid = new ShortUniqueId()
|
||||||
this.hasTourFinished = null;
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
this._controlTourFinished = this._controlTourFinished.bind(this);
|
|
||||||
this.uid = new ShortUniqueId();
|
|
||||||
}
|
|
||||||
|
|
||||||
_controlTourFinished() {
|
|
||||||
this.hasTourFinished = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this.address = store.getState().app.selectedAddress.address;
|
|
||||||
this.hasTourFinished = JSON.parse(
|
|
||||||
localStorage.getItem(`hasViewedTour-${this.address}`) || 'null'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback();
|
|
||||||
window.addEventListener(
|
|
||||||
'send-tour-finished',
|
|
||||||
this._controlTourFinished
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
window.removeEventListener(
|
|
||||||
'send-tour-finished',
|
|
||||||
this._controlTourFinished
|
|
||||||
);
|
|
||||||
|
|
||||||
super.disconnectedCallback();
|
|
||||||
}
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
async getName(recipient) {
|
|
||||||
try {
|
|
||||||
if (!recipient) return '';
|
|
||||||
const endpoint = `${this.nodeUrl}/names/address/${recipient}`;
|
|
||||||
const res = await fetch(endpoint);
|
|
||||||
const getNames = await res.json();
|
|
||||||
|
|
||||||
this.hasName = Array.isArray(getNames) && getNames.length > 0;
|
|
||||||
} catch (error) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged(state) {
|
|
||||||
if (
|
|
||||||
state.app.nodeStatus &&
|
|
||||||
state.app.nodeStatus.syncPercent !== this.syncPercentage
|
|
||||||
) {
|
|
||||||
this.syncPercentage = state.app.nodeStatus.syncPercent;
|
|
||||||
|
|
||||||
if (
|
|
||||||
!this.hasAttempted &&
|
|
||||||
state.app.selectedAddress &&
|
|
||||||
state.app.nodeStatus.syncPercent === 100
|
|
||||||
) {
|
|
||||||
this.hasAttempted = true;
|
|
||||||
this.getName(state.app.selectedAddress.address);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
state.app.accountInfo &&
|
|
||||||
state.app.accountInfo.names.length &&
|
|
||||||
state.app.nodeStatus &&
|
|
||||||
state.app.nodeStatus.syncPercent === 100 &&
|
|
||||||
this.hasName === false &&
|
|
||||||
this.hasAttempted &&
|
|
||||||
state.app.accountInfo &&
|
|
||||||
state.app.accountInfo.names &&
|
|
||||||
state.app.accountInfo.names.length > 0
|
|
||||||
) {
|
|
||||||
this.hasName = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBlur() {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.shadowRoot.contains(document.activeElement)) {
|
|
||||||
this.showChecklist = false;
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return this.hasName === false || this.hasTourFinished === false
|
return this.hasName === false || this.hasTourFinished === false ?
|
||||||
? html`
|
html`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<popover-component
|
<popover-component for="popover-checklist" message=${get('tour.tour16')}></popover-component>
|
||||||
for="popover-checklist"
|
<div id="popover-checklist" @click=${() => this._toggleChecklist()}>
|
||||||
message=${get('tour.tour16')}
|
<mwc-icon id="checklist-general-icon" style=${`color: ${!this.hasName ? 'red' : 'var(--black)'}; cursor:pointer;user-select:none`}>
|
||||||
></popover-component>
|
checklist
|
||||||
<div
|
</mwc-icon>
|
||||||
id="popover-checklist"
|
<vaadin-tooltip for="checklist-general-icon" position="bottom" hover-delay=${400} hide-delay=${1} text=${get('tour.tour16')}></vaadin-tooltip>
|
||||||
@click=${() => this._toggleChecklist()}
|
|
||||||
>
|
|
||||||
<mwc-icon
|
|
||||||
id="checklist-general-icon"
|
|
||||||
style=${`color: ${
|
|
||||||
!this.hasName ? 'red' : 'var(--black)'
|
|
||||||
}; cursor:pointer;user-select:none`}
|
|
||||||
>checklist</mwc-icon
|
|
||||||
>
|
|
||||||
<vaadin-tooltip
|
|
||||||
for="checklist-general-icon"
|
|
||||||
position="bottom"
|
|
||||||
hover-delay=${400}
|
|
||||||
hide-delay=${1}
|
|
||||||
text=${get('tour.tour16')}
|
|
||||||
>
|
|
||||||
</vaadin-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
|
<div id="checklist-panel" class="popover-panel" style="visibility:${this.showChecklist ? 'visibile' : 'hidden'}" tabindex="0" @blur=${this.handleBlur}>
|
||||||
<div
|
|
||||||
id="checklist-panel"
|
|
||||||
class="popover-panel"
|
|
||||||
style="visibility:${this.showChecklist
|
|
||||||
? 'visibile'
|
|
||||||
: 'hidden'}"
|
|
||||||
tabindex="0"
|
|
||||||
@blur=${this.handleBlur}
|
|
||||||
>
|
|
||||||
<div class="list">
|
<div class="list">
|
||||||
<div class="task-list-item">
|
<div class="task-list-item">
|
||||||
<p>Are you synced?</p>
|
<p>Are you synced?</p>
|
||||||
${this.syncPercentage === 100
|
${this.syncPercentage === 100 ?
|
||||||
? html`
|
html`
|
||||||
<mwc-icon
|
<mwc-icon id="checklist-general-icon" style="color: green; user-select:none">
|
||||||
id="checklist-general-icon"
|
task_alt
|
||||||
style="color: green; user-select:none"
|
</mwc-icon>
|
||||||
>task_alt</mwc-icon
|
|
||||||
>
|
|
||||||
`
|
`
|
||||||
: html`
|
: html`
|
||||||
<mwc-icon
|
<mwc-icon id="checklist-general-icon" style="color: red; user-select:none">
|
||||||
id="checklist-general-icon"
|
radio_button_unchecked
|
||||||
style="color: red; user-select:none"
|
</mwc-icon>
|
||||||
>radio_button_unchecked</mwc-icon
|
`
|
||||||
>
|
}
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="task-list-item"
|
class="task-list-item"
|
||||||
style="cursor:pointer"
|
style="cursor:pointer"
|
||||||
@ -206,139 +86,129 @@ class BeginnerChecklist extends connect(store)(LitElement) {
|
|||||||
title: 'Name Registration',
|
title: 'Name Registration',
|
||||||
icon: 'vaadin:user-check',
|
icon: 'vaadin:user-check',
|
||||||
mwcicon: 'manage_accounts',
|
mwcicon: 'manage_accounts',
|
||||||
pluginNumber:
|
pluginNumber: 'plugin-qCmtXAQmtu',
|
||||||
'plugin-qCmtXAQmtu',
|
|
||||||
menus: [],
|
menus: [],
|
||||||
parent: false,
|
parent: false
|
||||||
},
|
},
|
||||||
openExisting: true,
|
openExisting: true
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.handleBlur();
|
this.handleBlur();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<p>Do you have a name registered?</p>
|
<p>Do you have a name registered?</p>
|
||||||
${this.hasName
|
${this.hasName ?
|
||||||
? html`
|
html`
|
||||||
<mwc-icon
|
<mwc-icon id="checklist-general-icon" style="color: green; user-select:none">
|
||||||
id="checklist-general-icon"
|
task_alt
|
||||||
style="color: green; user-select:none"
|
</mwc-icon>
|
||||||
>task_alt</mwc-icon
|
` : html`
|
||||||
>
|
<mwc-icon id="checklist-general-icon" style="color: red; user-select:none">
|
||||||
|
radio_button_unchecked
|
||||||
|
</mwc-icon>
|
||||||
`
|
`
|
||||||
: html`
|
}
|
||||||
<mwc-icon
|
|
||||||
id="checklist-general-icon"
|
|
||||||
style="color: red; user-select:none"
|
|
||||||
>radio_button_unchecked</mwc-icon
|
|
||||||
>
|
|
||||||
`}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: '';
|
: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.address = store.getState().app.selectedAddress.address
|
||||||
|
this.hasTourFinished = JSON.parse(localStorage.getItem(`hasViewedTour-${this.address}`) || 'null')
|
||||||
|
}
|
||||||
|
|
||||||
|
_controlTourFinished() {
|
||||||
|
this.hasTourFinished = true
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback()
|
||||||
|
window.addEventListener('send-tour-finished', this._controlTourFinished)
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
window.removeEventListener('send-tour-finished', this._controlTourFinished)
|
||||||
|
super.disconnectedCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyNode() {
|
||||||
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
}
|
||||||
|
|
||||||
|
async getName(recipient) {
|
||||||
|
try {
|
||||||
|
if (!recipient) return ''
|
||||||
|
|
||||||
|
const endpoint = `${this.nodeUrl}/names/address/${recipient}`
|
||||||
|
const res = await fetch(endpoint)
|
||||||
|
const getNames = await res.json()
|
||||||
|
|
||||||
|
this.hasName = Array.isArray(getNames) && getNames.length > 0
|
||||||
|
} catch (error) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
if (state.app.nodeStatus && state.app.nodeStatus.syncPercent !== this.syncPercentage) {
|
||||||
|
this.syncPercentage = state.app.nodeStatus.syncPercent
|
||||||
|
|
||||||
|
if (!this.hasAttempted && state.app.selectedAddress && state.app.nodeStatus.syncPercent === 100) {
|
||||||
|
this.hasAttempted = true
|
||||||
|
this.getName(state.app.selectedAddress.address)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state.app.accountInfo &&
|
||||||
|
state.app.accountInfo.names.length && state.app.nodeStatus && state.app.nodeStatus.syncPercent === 100 &&
|
||||||
|
this.hasName === false && this.hasAttempted && state.app.accountInfo && state.app.accountInfo.names &&
|
||||||
|
state.app.accountInfo.names.length > 0
|
||||||
|
) {
|
||||||
|
this.hasName = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.shadowRoot.contains(document.activeElement)) {
|
||||||
|
this.showChecklist = false
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleChecklist() {
|
_toggleChecklist() {
|
||||||
this.showChecklist = !this.showChecklist;
|
this.showChecklist = !this.showChecklist
|
||||||
|
|
||||||
if (this.showChecklist) {
|
if (this.showChecklist) {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
this.shadowRoot.getElementById('checklist-panel').focus();
|
this.shadowRoot.getElementById('checklist-panel').focus()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
// Standard functions
|
||||||
.layout {
|
getApiKey() {
|
||||||
display: flex;
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
flex-direction: column;
|
return coreNode.apiKey
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.count {
|
isEmptyArray(arr) {
|
||||||
position: absolute;
|
if (!arr) { return true }
|
||||||
top: -5px;
|
return arr.length === 0
|
||||||
right: -5px;
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.nocount {
|
round(number) {
|
||||||
display: none;
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
|
|
||||||
.popover-panel {
|
|
||||||
position: absolute;
|
|
||||||
width: 200px;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
top: 40px;
|
|
||||||
max-height: 350px;
|
|
||||||
overflow: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #6a6c75 #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar {
|
|
||||||
width: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-track {
|
|
||||||
background: #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #6a6c75;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 3px solid #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.task-list-item {
|
|
||||||
display: flex;
|
|
||||||
gap: 15px;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checklist-item {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checklist-item:hover {
|
|
||||||
background: var(--nav-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('beginner-checklist', BeginnerChecklist);
|
window.customElements.define('beginner-checklist', BeginnerChecklist)
|
@ -1,91 +1,67 @@
|
|||||||
import {Sha256} from 'asmcrypto.js'
|
import { Sha256 } from 'asmcrypto.js'
|
||||||
|
|
||||||
|
function sbrk(size, heap) {
|
||||||
function sbrk(size, heap){
|
|
||||||
let brk = 512 * 1024 // stack top
|
let brk = 512 * 1024 // stack top
|
||||||
let old = brk
|
let old = brk
|
||||||
brk += size
|
brk += size
|
||||||
|
if (brk > heap.length) throw new Error('heap exhausted')
|
||||||
if (brk > heap.length)
|
|
||||||
throw new Error('heap exhausted')
|
|
||||||
|
|
||||||
return old
|
return old
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.addEventListener('message', async e => {
|
self.addEventListener('message', async e => {
|
||||||
const response = await computePow(e.data.convertedBytes, e.data.path)
|
const response = await computePow(e.data.convertedBytes, e.data.path)
|
||||||
postMessage(response)
|
postMessage(response)
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
|
||||||
const heap = new Uint8Array(memory.buffer)
|
const heap = new Uint8Array(memory.buffer)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const computePow = async (convertedBytes, path) => {
|
const computePow = async (convertedBytes, path) => {
|
||||||
|
|
||||||
|
|
||||||
let response = null
|
let response = null
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
await new Promise((resolve, reject)=> {
|
|
||||||
|
|
||||||
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
const _convertedBytesArray = Object.keys(convertedBytes).map(
|
||||||
function (key) {
|
function (key) {
|
||||||
return convertedBytes[key]
|
return convertedBytes[key]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
|
||||||
const convertedBytesHash = new Sha256()
|
const convertedBytesHash = new Sha256()
|
||||||
.process(convertedBytesArray)
|
.process(convertedBytesArray)
|
||||||
.finish().result
|
.finish().result
|
||||||
const hashPtr = sbrk(32, heap)
|
const hashPtr = sbrk(32, heap)
|
||||||
const hashAry = new Uint8Array(
|
const hashAry = new Uint8Array(
|
||||||
memory.buffer,
|
memory.buffer,
|
||||||
hashPtr,
|
hashPtr,
|
||||||
32
|
32
|
||||||
)
|
)
|
||||||
|
hashAry.set(convertedBytesHash)
|
||||||
hashAry.set(convertedBytesHash)
|
const difficulty = 14
|
||||||
const difficulty = 14
|
const workBufferLength = 8 * 1024 * 1024
|
||||||
const workBufferLength = 8 * 1024 * 1024
|
const workBufferPtr = sbrk(
|
||||||
const workBufferPtr = sbrk(
|
|
||||||
workBufferLength,
|
workBufferLength,
|
||||||
heap
|
heap
|
||||||
)
|
)
|
||||||
|
|
||||||
const importObject = {
|
const importObject = {
|
||||||
env: {
|
env: {
|
||||||
memory: memory
|
memory: memory
|
||||||
},
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
function loadWebAssembly(filename, imports) {
|
function loadWebAssembly(filename, imports) {
|
||||||
return fetch(filename)
|
return fetch(filename)
|
||||||
.then(response => response.arrayBuffer())
|
.then(response => response.arrayBuffer())
|
||||||
.then(buffer => WebAssembly.compile(buffer))
|
.then(buffer => WebAssembly.compile(buffer))
|
||||||
.then(module => {
|
.then(module => {
|
||||||
return new WebAssembly.Instance(module, importObject);
|
return new WebAssembly.Instance(module, importObject)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
loadWebAssembly(path)
|
||||||
|
|
||||||
loadWebAssembly(path)
|
|
||||||
.then(wasmModule => {
|
.then(wasmModule => {
|
||||||
response = {
|
response = {
|
||||||
nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
nonce: wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
|
||||||
|
|
||||||
}
|
}
|
||||||
resolve()
|
resolve()
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
|
})
|
||||||
return response
|
return response
|
||||||
}
|
}
|
@ -1,7 +1,8 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {store} from '../../store'
|
import { connect } from 'pwa-helpers'
|
||||||
import {connect} from 'pwa-helpers'
|
import { store } from '../../store'
|
||||||
import {translate} from '../../../translate'
|
import { translate } from '../../../translate'
|
||||||
|
import { coreSyncStatusStyles } from '../../styles/core-css'
|
||||||
|
|
||||||
class CoreSyncStatus extends connect(store)(LitElement) {
|
class CoreSyncStatus extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -12,6 +13,10 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [coreSyncStatusStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.nodeInfos = []
|
this.nodeInfos = []
|
||||||
@ -19,69 +24,6 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
.lineHeight {
|
|
||||||
line-height: 33%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .bottom {
|
|
||||||
min-width: 200px;
|
|
||||||
max-width: 250px;
|
|
||||||
top: 35px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0);
|
|
||||||
padding: 10px 10px;
|
|
||||||
color: var(--black);
|
|
||||||
background-color: var(--white);
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 13px;
|
|
||||||
border-radius: 8px;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99999999;
|
|
||||||
box-sizing: border-box;
|
|
||||||
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
visibility: hidden;
|
|
||||||
opacity: 0;
|
|
||||||
transition: opacity 0.8s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip:hover .bottom {
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .bottom i {
|
|
||||||
position: absolute;
|
|
||||||
bottom: 100%;
|
|
||||||
left: 50%;
|
|
||||||
margin-left: -12px;
|
|
||||||
width: 24px;
|
|
||||||
height: 12px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tooltip .bottom i::after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
width: 12px;
|
|
||||||
height: 12px;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%,50%) rotate(45deg);
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
box-shadow: 0 1px 8px rgba(0,0,0,0.5);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div id="core-sync-status-id">
|
<div id="core-sync-status-id">
|
||||||
@ -136,7 +78,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/syncing.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/syncing.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -150,7 +92,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
|
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -164,7 +106,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/synced.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
|
<h4 class="lineHeight">${translate("walletprofile.wp4")} ${translate("walletprofile.wp2")}</h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -178,7 +120,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
|
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -192,7 +134,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/synced_minting.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
|
<h4 class="lineHeight">${translate("walletprofile.wp4")} <span style="color: #03a9f4">( ${translate("walletprofile.wp1")} )</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -206,7 +148,7 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
<span><img src="/img/syncing.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
<span><img src="/img/syncing.png" style="height: 24px; width: 24px; padding-top: 4px;"></span>
|
||||||
<div class="bottom">
|
<div class="bottom">
|
||||||
<h3>${translate("walletprofile.wp3")}</h3>
|
<h3>${translate("walletprofile.wp3")}</h3>
|
||||||
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0,12) : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.coreversion")}: <span style="color: #03a9f4">${this.coreInfos.buildVersion ? (this.coreInfos.buildVersion).substring(0, 12) : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.synchronizing")}... <span style="color: #03a9f4">${this.nodeInfos.syncPercent !== undefined ? this.nodeInfos.syncPercent + '%' : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.blockheight")}: <span style="color: #03a9f4">${this.nodeInfos.height ? this.nodeInfos.height : ''}</span></h4>
|
||||||
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
<h4 class="lineHeight">${translate("appinfo.peers")}: <span style="color: #03a9f4">${this.nodeInfos.numberOfConnections ? this.nodeInfos.numberOfConnections : ''}</span></h4>
|
||||||
@ -221,6 +163,20 @@ class CoreSyncStatus extends connect(store)(LitElement) {
|
|||||||
// ...
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('core-sync-status', CoreSyncStatus)
|
window.customElements.define('core-sync-status', CoreSyncStatus)
|
@ -1,150 +1,38 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {translate,} from '../../../translate'
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store'
|
||||||
|
import { setNewTab } from '../../redux/app/app-actions'
|
||||||
|
import { RequestQueueWithPromise } from '../../../../plugins/plugins/utils/classes'
|
||||||
|
import { translate, } from '../../../translate'
|
||||||
|
import { feedItemStyles } from '../../styles/core-css'
|
||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
import '@material/mwc-menu';
|
import ShortUniqueId from 'short-unique-id'
|
||||||
import '@material/mwc-list/mwc-list-item.js'
|
|
||||||
import {RequestQueueWithPromise} from '../../../../plugins/plugins/utils/queue';
|
|
||||||
import '../../../../plugins/plugins/core/components/TimeAgo'
|
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||||
import {connect} from 'pwa-helpers';
|
import '@material/mwc-menu'
|
||||||
import {store} from '../../store';
|
import '@material/mwc-list/mwc-list-item.js'
|
||||||
import {setNewTab} from '../../redux/app/app-actions';
|
|
||||||
import ShortUniqueId from 'short-unique-id';
|
|
||||||
|
|
||||||
const requestQueue = new RequestQueueWithPromise(3);
|
|
||||||
const requestQueueRawData = new RequestQueueWithPromise(3);
|
|
||||||
const requestQueueStatus = new RequestQueueWithPromise(3);
|
|
||||||
|
|
||||||
|
const requestQueue = new RequestQueueWithPromise(3)
|
||||||
|
const requestQueueRawData = new RequestQueueWithPromise(3)
|
||||||
|
const requestQueueStatus = new RequestQueueWithPromise(3)
|
||||||
|
|
||||||
export class FeedItem extends connect(store)(LitElement) {
|
export class FeedItem extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
resource: { type: Object },
|
resource: { type: Object },
|
||||||
isReady: { type: Boolean},
|
isReady: { type: Boolean },
|
||||||
status: {type: Object},
|
status: { type: Object },
|
||||||
feedItem: {type: Object},
|
feedItem: { type: Object },
|
||||||
appName: {type: String},
|
appName: { type: String },
|
||||||
link: {type: String}
|
link: { type: String }
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [feedItemStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-text-primary-on-background: var(--black);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
:host {
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
img {
|
|
||||||
width:100%;
|
|
||||||
max-height:30vh;
|
|
||||||
border-radius: 5px;
|
|
||||||
cursor: pointer;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.smallLoading,
|
|
||||||
.smallLoading:after {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 2px;
|
|
||||||
height: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.smallLoading {
|
|
||||||
border-width: 0.8em;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2)
|
|
||||||
rgba(3, 169, 244, 0.2) rgb(3, 169, 244);
|
|
||||||
font-size: 30px;
|
|
||||||
position: relative;
|
|
||||||
text-indent: -9999em;
|
|
||||||
transform: translateZ(0px);
|
|
||||||
animation: 1.1s linear 0s infinite normal none running loadingAnimation;
|
|
||||||
}
|
|
||||||
|
|
||||||
.defaultSize {
|
|
||||||
width: 100%;
|
|
||||||
height: 160px;
|
|
||||||
}
|
|
||||||
.parent-feed-item {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
background-color: var(--chat-bubble-bg);
|
|
||||||
flex-grow: 0;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: flex-start;
|
|
||||||
justify-content: center;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 12px 15px 4px 15px;
|
|
||||||
min-width: 150px;
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
.avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
border-radius:50%;
|
|
||||||
overflow: hidden;
|
|
||||||
display:flex;
|
|
||||||
align-items:center;
|
|
||||||
}
|
|
||||||
.avatarApp {
|
|
||||||
width: 30px;
|
|
||||||
height: 30px;
|
|
||||||
border-radius:50%;
|
|
||||||
overflow: hidden;
|
|
||||||
display:flex;
|
|
||||||
align-items:center;
|
|
||||||
}
|
|
||||||
.feed-item-name {
|
|
||||||
user-select: none;
|
|
||||||
color: #03a9f4;
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-name {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-menu {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@-webkit-keyframes loadingAnimation {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes loadingAnimation {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.resource = {
|
this.resource = {
|
||||||
identifier: "",
|
identifier: "",
|
||||||
name: "",
|
name: "",
|
||||||
@ -159,38 +47,81 @@ export class FeedItem extends connect(store)(LitElement) {
|
|||||||
this.hasCalledWhenDownloaded = false
|
this.hasCalledWhenDownloaded = false
|
||||||
this.isFetching = false
|
this.isFetching = false
|
||||||
this.uid = new ShortUniqueId()
|
this.uid = new ShortUniqueId()
|
||||||
|
|
||||||
this.observer = new IntersectionObserver(entries => {
|
this.observer = new IntersectionObserver(entries => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
if (entry.isIntersecting && this.status.status !== 'READY') {
|
if (entry.isIntersecting && this.status.status !== 'READY') {
|
||||||
this._fetchImage();
|
this._fetchImage()
|
||||||
// Stop observing after the image has started loading
|
// Stop observing after the image has started loading
|
||||||
this.observer.unobserve(this);
|
this.observer.unobserve(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
this.feedItem = null
|
this.feedItem = null
|
||||||
}
|
}
|
||||||
getNodeUrl(){
|
|
||||||
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
let avatarImg
|
||||||
|
const avatarUrl = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.resource.name}/qortal_avatar?async=true`
|
||||||
|
avatarImg = html`<img src="${avatarUrl}" style="width:100%; height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`
|
||||||
|
|
||||||
|
let avatarImgApp
|
||||||
|
const avatarUrl2 = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.appName}/qortal_avatar?async=true`
|
||||||
|
avatarImgApp = html`<img src="${avatarUrl2}" style="width:100%; height:100%;" onerror="this.onerror=null; this.src='/img/incognito.png';" />`
|
||||||
|
|
||||||
|
return html`
|
||||||
|
<div
|
||||||
|
class=${[`image-container`, this.status.status !== 'READY' ? 'defaultSize' : '', this.status.status !== 'READY' ? 'hideImg' : '',].join(' ')}
|
||||||
|
style=" box-sizing: border-box;"
|
||||||
|
>
|
||||||
|
${this.status.status !== 'READY' ?
|
||||||
|
html`
|
||||||
|
<div style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:center;align-items:center; box-sizing: border-box;">
|
||||||
|
<div class=${`smallLoading`}></div>
|
||||||
|
<p style="color: var(--black)">
|
||||||
|
${`${Math.round(this.status.percentLoaded || 0).toFixed(0)}% `}${translate('chatpage.cchange94')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
${this.status.status === 'READY' && this.feedItem ?
|
||||||
|
html`
|
||||||
|
<div class="parent-feed-item" style="position:relative" @click=${this.goToFeedLink}>
|
||||||
|
<div style="display:flex;gap:10px;margin-bottom:5px">
|
||||||
|
<div class="avatar">${avatarImg}</div>
|
||||||
|
<span class="feed-item-name">${this.resource.name}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p>${this.feedItem.title}</p>
|
||||||
|
</div>
|
||||||
|
<div class="app-name">
|
||||||
|
<div class="avatarApp">${avatarImgApp}</div>
|
||||||
|
<message-time timestamp=${this.resource.created}></message-time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
: ''
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.observer.observe(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
}
|
}
|
||||||
getMyNode(){
|
|
||||||
return window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
|
||||||
}
|
|
||||||
|
|
||||||
getApiKey() {
|
getMyNode() {
|
||||||
const myNode =
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
return myNode.apiKey;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fetchResource() {
|
async fetchResource() {
|
||||||
try {
|
try {
|
||||||
if(this.isFetching) return
|
if (this.isFetching) return
|
||||||
this.isFetching = true
|
this.isFetching = true
|
||||||
await axios.get(`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
await axios.get(`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
||||||
this.isFetching = false
|
this.isFetching = false
|
||||||
@ -201,89 +132,79 @@ getMyNode(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fetchVideoUrl() {
|
async fetchVideoUrl() {
|
||||||
|
|
||||||
await this.fetchResource()
|
await this.fetchResource()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async getRawData(){
|
async getRawData() {
|
||||||
const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
|
||||||
return await requestQueueRawData.enqueue(()=> {
|
|
||||||
|
return await requestQueueRawData.enqueue(() => {
|
||||||
return axios.get(url)
|
return axios.get(url)
|
||||||
})
|
})
|
||||||
// const response2 = await fetch(url, {
|
|
||||||
// method: 'GET',
|
|
||||||
// headers: {
|
|
||||||
// 'Content-Type': 'application/json'
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
|
|
||||||
// const responseData2 = await response2.json()
|
|
||||||
// return responseData2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateDisplayWithPlaceholders(display, resource, rawdata) {
|
updateDisplayWithPlaceholders(display, resource, rawdata) {
|
||||||
const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g;
|
const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g
|
||||||
|
|
||||||
for (const key in display) {
|
for (const key in display) {
|
||||||
const value = display[key];
|
const value = display[key]
|
||||||
|
|
||||||
display[key] = value.replace(pattern, (match, p1) => {
|
display[key] = value.replace(pattern, (match, p1) => {
|
||||||
if (p1.startsWith('rawdata.')) {
|
if (p1.startsWith('rawdata.')) {
|
||||||
const dataKey = p1.split('.')[1];
|
const dataKey = p1.split('.')[1]
|
||||||
if (rawdata[dataKey] === undefined) {
|
if (rawdata[dataKey] === undefined) {
|
||||||
console.error("rawdata key not found:", dataKey);
|
console.error("rawdata key not found:", dataKey)
|
||||||
}
|
}
|
||||||
return rawdata[dataKey] || match;
|
return rawdata[dataKey] || match
|
||||||
} else if (p1.startsWith('resource.')) {
|
} else if (p1.startsWith('resource.')) {
|
||||||
const resourceKey = p1.split('.')[1];
|
const resourceKey = p1.split('.')[1]
|
||||||
if (resource[resourceKey] === undefined) {
|
if (resource[resourceKey] === undefined) {
|
||||||
console.error("resource key not found:", resourceKey);
|
console.error("resource key not found:", resourceKey)
|
||||||
}
|
}
|
||||||
return resource[resourceKey] || match;
|
return resource[resourceKey] || match
|
||||||
|
}
|
||||||
|
return match
|
||||||
|
})
|
||||||
}
|
}
|
||||||
return match;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
async fetchStatus() {
|
||||||
|
|
||||||
|
|
||||||
async fetchStatus(){
|
|
||||||
let isCalling = false
|
let isCalling = false
|
||||||
let percentLoaded = 0
|
let percentLoaded = 0
|
||||||
let timer = 24
|
let timer = 24
|
||||||
const response = await requestQueueStatus.enqueue(()=> {
|
|
||||||
|
const response = await requestQueueStatus.enqueue(() => {
|
||||||
return axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
return axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
||||||
})
|
})
|
||||||
if(response && response.data && response.data.status === 'READY'){
|
|
||||||
|
if (response && response.data && response.data.status === 'READY') {
|
||||||
const rawData = await this.getRawData()
|
const rawData = await this.getRawData()
|
||||||
|
|
||||||
const object = {
|
const object = {
|
||||||
...this.resource.schema.display
|
...this.resource.schema.display
|
||||||
}
|
}
|
||||||
this.updateDisplayWithPlaceholders(object, {},rawData.data)
|
|
||||||
|
this.updateDisplayWithPlaceholders(object, {}, rawData.data)
|
||||||
this.feedItem = object
|
this.feedItem = object
|
||||||
this.status = response.data
|
this.status = response.data
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const intervalId = setInterval(async () => {
|
const intervalId = setInterval(async () => {
|
||||||
if (isCalling) return
|
if (isCalling) return
|
||||||
isCalling = true
|
isCalling = true
|
||||||
|
|
||||||
const data = await requestQueue.enqueue(() => {
|
const data = await requestQueue.enqueue(() => {
|
||||||
return axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
return axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`)
|
||||||
});
|
})
|
||||||
|
|
||||||
const res = data.data
|
const res = data.data
|
||||||
|
|
||||||
isCalling = false
|
isCalling = false
|
||||||
if (res.localChunkCount) {
|
if (res.localChunkCount) {
|
||||||
if (res.percentLoaded) {
|
if (res.percentLoaded) {
|
||||||
if (
|
if (res.percentLoaded === percentLoaded && res.percentLoaded !== 100) {
|
||||||
res.percentLoaded === percentLoaded &&
|
|
||||||
res.percentLoaded !== 100
|
|
||||||
) {
|
|
||||||
timer = timer - 5
|
timer = timer - 5
|
||||||
} else {
|
} else {
|
||||||
timer = 24
|
timer = 24
|
||||||
@ -300,13 +221,15 @@ getMyNode(){
|
|||||||
isCalling = false
|
isCalling = false
|
||||||
this.fetchResource()
|
this.fetchResource()
|
||||||
}, 25000)
|
}, 25000)
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
percentLoaded = res.percentLoaded
|
percentLoaded = res.percentLoaded
|
||||||
}
|
}
|
||||||
|
|
||||||
this.status = res
|
this.status = res
|
||||||
if(this.status.status === 'DOWNLOADED'){
|
|
||||||
|
if (this.status.status === 'DOWNLOADED') {
|
||||||
await this.fetchResource()
|
await this.fetchResource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -317,13 +240,13 @@ getMyNode(){
|
|||||||
const object = {
|
const object = {
|
||||||
...this.resource.schema.display
|
...this.resource.schema.display
|
||||||
}
|
}
|
||||||
this.updateDisplayWithPlaceholders(object, {},rawData.data)
|
this.updateDisplayWithPlaceholders(object, {}, rawData.data)
|
||||||
this.feedItem = object
|
this.feedItem = object
|
||||||
clearInterval(intervalId)
|
clearInterval(intervalId)
|
||||||
this.status = res
|
this.status = res
|
||||||
this.isReady = true
|
this.isReady = true
|
||||||
}
|
}
|
||||||
}, 5000) // 1 second interval
|
}, 5000) // 5 second interval
|
||||||
}
|
}
|
||||||
|
|
||||||
async _fetchImage() {
|
async _fetchImage() {
|
||||||
@ -333,14 +256,7 @@ getMyNode(){
|
|||||||
} catch (error) { /* empty */ }
|
} catch (error) { /* empty */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated(){
|
async goToFeedLink() {
|
||||||
this.observer.observe(this);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async goToFeedLink(){
|
|
||||||
try {
|
try {
|
||||||
let newQuery = this.link
|
let newQuery = this.link
|
||||||
if (newQuery.endsWith('/')) {
|
if (newQuery.endsWith('/')) {
|
||||||
@ -376,18 +292,17 @@ getMyNode(){
|
|||||||
openExisting: true
|
openExisting: true
|
||||||
}))
|
}))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log({error})
|
console.log({ error })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async extractComponents(url) {
|
async extractComponents(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()
|
||||||
@ -424,86 +339,22 @@ getMyNode(){
|
|||||||
return components
|
return components
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let avatarImg
|
|
||||||
const avatarUrl = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.resource.name}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
|
||||||
avatarImg = html`<img
|
|
||||||
src="${avatarUrl}"
|
|
||||||
style="width:100%; height:100%;"
|
|
||||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
|
||||||
/>`;
|
|
||||||
let avatarImgApp
|
|
||||||
const avatarUrl2 = `${this.nodeUrl}/arbitrary/THUMBNAIL/${this.appName}/qortal_avatar?async=true&apiKey=${this.myNode.apiKey}`;
|
|
||||||
avatarImgApp = html`<img
|
|
||||||
src="${avatarUrl2}"
|
|
||||||
style="width:100%; height:100%;"
|
|
||||||
onerror="this.onerror=null; this.src='/img/incognito.png';"
|
|
||||||
/>`;
|
|
||||||
return html`
|
|
||||||
<div
|
|
||||||
class=${[
|
|
||||||
`image-container`,
|
|
||||||
this.status.status !== 'READY'
|
|
||||||
? 'defaultSize'
|
|
||||||
: '',
|
|
||||||
this.status.status !== 'READY'
|
|
||||||
? 'hideImg'
|
|
||||||
: '',
|
|
||||||
].join(' ')}
|
|
||||||
style=" box-sizing: border-box;"
|
|
||||||
>
|
|
||||||
${
|
|
||||||
this.status.status !== 'READY'
|
|
||||||
? html`
|
|
||||||
<div
|
|
||||||
style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:center;align-items:center; box-sizing: border-box;"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
class=${`smallLoading`}
|
|
||||||
></div>
|
|
||||||
<p style="color: var(--black)">${`${Math.round(this.status.percentLoaded || 0
|
|
||||||
).toFixed(0)}% `}${translate('chatpage.cchange94')}</p>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
: ''
|
|
||||||
}
|
}
|
||||||
${this.status.status === 'READY' && this.feedItem ? html`
|
|
||||||
<div class="parent-feed-item" style="position:relative" @click=${this.goToFeedLink}>
|
|
||||||
<div style="display:flex;gap:10px;margin-bottom:5px">
|
|
||||||
<div class="avatar">
|
|
||||||
${avatarImg}</div> <span class="feed-item-name">${this.resource.name}</span>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p>${this.feedItem.title}</p>
|
|
||||||
</div>
|
|
||||||
<div class="app-name">
|
|
||||||
<div class="avatarApp">
|
|
||||||
${avatarImgApp}
|
|
||||||
</div>
|
|
||||||
<message-time
|
|
||||||
timestamp=${this
|
|
||||||
.resource
|
|
||||||
.created}
|
|
||||||
></message-time>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
` : ''}
|
|
||||||
|
|
||||||
</div>
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
`
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('feed-item', FeedItem);
|
window.customElements.define('feed-item', FeedItem)
|
@ -1,146 +1,42 @@
|
|||||||
// popover-component.js
|
import { html, LitElement } from 'lit'
|
||||||
import {css, html, LitElement} from 'lit';
|
import { connect } from 'pwa-helpers'
|
||||||
import {createPopper} from '@popperjs/core';
|
import { store } from '../../store'
|
||||||
import '@material/mwc-icon';
|
import { createPopper } from '@popperjs/core'
|
||||||
import {translate} from '../../../translate'
|
import { setNewTab, setSideEffectAction } from '../../redux/app/app-actions'
|
||||||
import {store} from '../../store';
|
import { translate } from '../../../translate'
|
||||||
import {connect} from 'pwa-helpers';
|
import { friendItemActionsStyles } from '../../styles/core-css'
|
||||||
import {setNewTab, setSideEffectAction} from '../../redux/app/app-actions';
|
import ShortUniqueId from 'short-unique-id'
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
export class FriendItemActions extends connect(store)(LitElement) {
|
export class FriendItemActions extends connect(store)(LitElement) {
|
||||||
static styles = css`
|
|
||||||
:host {
|
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 8px;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
color: var(--black);
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
margin-left: 10px;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-message-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
font-weight: 300;
|
|
||||||
padding: 8px 5px;
|
|
||||||
border-radius: 3px;
|
|
||||||
text-align: center;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-message-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #03a8f485;
|
|
||||||
}
|
|
||||||
.action-parent {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
div[tabindex='0']:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
for: { type: String, reflect: true },
|
for: { type: String, reflect: true },
|
||||||
message: { type: String },
|
message: { type: String },
|
||||||
openEditFriend: { attribute: false },
|
openEditFriend: { attribute: false },
|
||||||
name: { type: String },
|
name: { type: String },
|
||||||
closeSidePanel: { attribute: false, type: Object },
|
closeSidePanel: { attribute: false, type: Object }
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [friendItemActionsStyles]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.message = '';
|
this.message = ''
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.uid = new ShortUniqueId();
|
this.uid = new ShortUniqueId()
|
||||||
this.getUserAddress = this.getUserAddress.bind(this);
|
this.getUserAddress = this.getUserAddress.bind(this)
|
||||||
}
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
// We'll defer the popper attachment to the openPopover() method to ensure target availability
|
|
||||||
}
|
|
||||||
|
|
||||||
attachToTarget(target) {
|
|
||||||
if (!this.popperInstance && target) {
|
|
||||||
this.popperInstance = createPopper(target, this, {
|
|
||||||
placement: 'bottom',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
openPopover(target) {
|
|
||||||
this.attachToTarget(target);
|
|
||||||
this.style.display = 'block';
|
|
||||||
setTimeout(() => {
|
|
||||||
this.shadowRoot.getElementById('parent-div').focus();
|
|
||||||
}, 50);
|
|
||||||
}
|
|
||||||
|
|
||||||
closePopover() {
|
|
||||||
this.style.display = 'none';
|
|
||||||
if (this.popperInstance) {
|
|
||||||
this.popperInstance.destroy();
|
|
||||||
this.popperInstance = null;
|
|
||||||
}
|
|
||||||
this.requestUpdate();
|
|
||||||
}
|
|
||||||
handleBlur() {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.closePopover();
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getUserAddress() {
|
|
||||||
try {
|
|
||||||
const url = `${this.nodeUrl}/names/${this.name}`;
|
|
||||||
const res = await fetch(url);
|
|
||||||
const result = await res.json();
|
|
||||||
if (result.error === 401) {
|
|
||||||
return '';
|
|
||||||
} else {
|
|
||||||
return result.owner;
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
return '';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div id="parent-div" tabindex="0" @blur=${this.handleBlur}>
|
<div id="parent-div" tabindex="0" @blur=${this.handleBlur}>
|
||||||
<span class="close-icon" @click="${this.closePopover}"
|
<span class="close-icon" @click="${this.closePopover}">
|
||||||
><mwc-icon style="color: var(--black)"
|
<mwc-icon style="color: var(--black)">close</mwc-icon>
|
||||||
>close</mwc-icon
|
</span>
|
||||||
></span
|
|
||||||
>
|
|
||||||
<div class="action-parent">
|
<div class="action-parent">
|
||||||
<div
|
<div
|
||||||
class="send-message-button"
|
class="send-message-button"
|
||||||
@ -164,16 +60,15 @@ export class FriendItemActions extends connect(store)(LitElement) {
|
|||||||
myPlugObj: {
|
myPlugObj: {
|
||||||
url: 'q-chat',
|
url: 'q-chat',
|
||||||
domain: 'core',
|
domain: 'core',
|
||||||
page: 'messaging/q-chat/index.html',
|
page: 'q-chat/index.html',
|
||||||
title: 'Q-Chat',
|
title: 'Q-Chat',
|
||||||
icon: 'vaadin:chat',
|
icon: 'vaadin:chat',
|
||||||
mwcicon: 'forum',
|
mwcicon: 'forum',
|
||||||
pluginNumber: 'plugin-qhsyOnpRhT',
|
pluginNumber: 'plugin-qhsyOnpRhT',
|
||||||
menus: [],
|
menus: [],
|
||||||
parent: false,
|
parent: false
|
||||||
},
|
},
|
||||||
|
openExisting: true
|
||||||
openExisting: true,
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
@ -181,8 +76,8 @@ export class FriendItemActions extends connect(store)(LitElement) {
|
|||||||
type: 'openPrivateChat',
|
type: 'openPrivateChat',
|
||||||
data: {
|
data: {
|
||||||
address,
|
address,
|
||||||
name: this.name,
|
name: this.name
|
||||||
},
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.closePopover();
|
this.closePopover();
|
||||||
@ -208,9 +103,9 @@ export class FriendItemActions extends connect(store)(LitElement) {
|
|||||||
icon: 'vaadin:mailbox',
|
icon: 'vaadin:mailbox',
|
||||||
mwcicon: 'mail_outline',
|
mwcicon: 'mail_outline',
|
||||||
menus: [],
|
menus: [],
|
||||||
parent: false,
|
parent: false
|
||||||
},
|
},
|
||||||
openExisting: true,
|
openExisting: true
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
this.closePopover();
|
this.closePopover();
|
||||||
@ -223,26 +118,89 @@ export class FriendItemActions extends connect(store)(LitElement) {
|
|||||||
<div
|
<div
|
||||||
class="send-message-button"
|
class="send-message-button"
|
||||||
@click="${() => {
|
@click="${() => {
|
||||||
const customEvent = new CustomEvent(
|
const customEvent = new CustomEvent('open-visiting-profile', { detail: this.name });
|
||||||
'open-visiting-profile',
|
|
||||||
{
|
|
||||||
detail: this.name,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
window.dispatchEvent(customEvent);
|
window.dispatchEvent(customEvent);
|
||||||
this.closePopover();
|
this.closePopover();
|
||||||
this.closeSidePanel();
|
this.closeSidePanel();
|
||||||
}}"
|
}}"
|
||||||
>
|
>
|
||||||
<mwc-icon style="color: var(--black)"
|
<mwc-icon style="color: var(--black)">person</mwc-icon>
|
||||||
>person</mwc-icon
|
|
||||||
>
|
|
||||||
${translate('profile.profile18')}
|
${translate('profile.profile18')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
attachToTarget(target) {
|
||||||
|
if (!this.popperInstance && target) {
|
||||||
|
this.popperInstance = createPopper(target, this, {
|
||||||
|
placement: 'bottom'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openPopover(target) {
|
||||||
|
this.attachToTarget(target)
|
||||||
|
this.style.display = 'block'
|
||||||
|
setTimeout(() => {
|
||||||
|
this.shadowRoot.getElementById('parent-div').focus()
|
||||||
|
}, 50)
|
||||||
|
}
|
||||||
|
|
||||||
|
closePopover() {
|
||||||
|
this.style.display = 'none'
|
||||||
|
if (this.popperInstance) {
|
||||||
|
this.popperInstance.destroy()
|
||||||
|
this.popperInstance = null
|
||||||
|
}
|
||||||
|
this.requestUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.closePopover()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getUserAddress() {
|
||||||
|
try {
|
||||||
|
const url = `${this.nodeUrl}/names/${this.name}`
|
||||||
|
const res = await fetch(url)
|
||||||
|
const result = await res.json()
|
||||||
|
if (result.error === 401) {
|
||||||
|
return ''
|
||||||
|
} else {
|
||||||
|
return result.owner
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('friend-item-actions', FriendItemActions);
|
window.customElements.define('friend-item-actions', FriendItemActions)
|
||||||
|
@ -1,399 +1,50 @@
|
|||||||
import {html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import '@material/mwc-icon';
|
import { store } from '../../store'
|
||||||
import './friends-view'
|
import { connect } from 'pwa-helpers'
|
||||||
import {friendsViewStyles} from './friends-view-css';
|
import { translate } from '../../../translate'
|
||||||
import {connect} from 'pwa-helpers';
|
import { friendsViewStyles } from '../../styles/core-css'
|
||||||
import {store} from '../../store';
|
|
||||||
import './feed-item'
|
import './feed-item'
|
||||||
import {translate} from '../../../translate'
|
import './friends-view'
|
||||||
|
import '@material/mwc-icon'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
|
|
||||||
|
const perEndpointCount = 20
|
||||||
|
const totalDesiredCount = 100
|
||||||
|
const maxResultsInMemory = 300
|
||||||
|
|
||||||
const perEndpointCount = 20;
|
|
||||||
const totalDesiredCount = 100;
|
|
||||||
const maxResultsInMemory = 300;
|
|
||||||
class FriendsFeed extends connect(store)(LitElement) {
|
class FriendsFeed extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
feed: {type: Array},
|
feed: { type: Array },
|
||||||
setHasNewFeed: {attribute:false},
|
setHasNewFeed: { attribute: false },
|
||||||
isLoading: {type: Boolean},
|
isLoading: { type: Boolean },
|
||||||
hasFetched: {type: Boolean},
|
hasFetched: { type: Boolean },
|
||||||
mySelectedFeeds: {type: Array}
|
mySelectedFeeds: { type: Array }
|
||||||
};
|
|
||||||
}
|
}
|
||||||
constructor(){
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [friendsViewStyles]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.feed = []
|
this.feed = []
|
||||||
this.feedToRender = []
|
this.feedToRender = []
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.myNode = this.getMyNode();
|
this.myNode = this.getMyNode()
|
||||||
this.endpoints = []
|
this.endpoints = []
|
||||||
this.endpointOffsets = [] // Initialize offsets for each endpoint to 0
|
this.endpointOffsets = [] // Initialize offsets for each endpoint to 0
|
||||||
|
|
||||||
this.loadAndMergeData = this.loadAndMergeData.bind(this)
|
this.loadAndMergeData = this.loadAndMergeData.bind(this)
|
||||||
this.hasInitialFetch = false
|
this.hasInitialFetch = false
|
||||||
this.observerHandler = this.observerHandler.bind(this);
|
this.observerHandler = this.observerHandler.bind(this)
|
||||||
this.elementObserver = this.elementObserver.bind(this)
|
this.elementObserver = this.elementObserver.bind(this)
|
||||||
this.mySelectedFeeds = []
|
this.mySelectedFeeds = []
|
||||||
this.getSchemas = this.getSchemas.bind(this)
|
this.getSchemas = this.getSchemas.bind(this)
|
||||||
this.hasFetched = false
|
this.hasFetched = false
|
||||||
this._updateFeeds = this._updateFeeds.bind(this)
|
this._updateFeeds = this._updateFeeds.bind(this)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return [friendsViewStyles];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateFeeds(event) {
|
|
||||||
this.mySelectedFeeds = event.detail
|
|
||||||
this.reFetchFeedData()
|
|
||||||
this.requestUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
|
||||||
super.connectedCallback()
|
|
||||||
window.addEventListener('friends-my-selected-feeds-event', this._updateFeeds) }
|
|
||||||
|
|
||||||
disconnectedCallback() {
|
|
||||||
window.removeEventListener('friends-my-selected-feeds-event', this._updateFeeds)
|
|
||||||
super.disconnectedCallback()
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSchemas(){
|
|
||||||
this.mySelectedFeeds = JSON.parse(localStorage.getItem('friends-my-selected-feeds') || "[]")
|
|
||||||
const schemas = this.mySelectedFeeds
|
|
||||||
const getAllSchemas = (schemas || []).map(
|
|
||||||
async (schema) => {
|
|
||||||
try {
|
|
||||||
const url = `${this.nodeUrl}/arbitrary/${schema.service}/${schema.name}/${schema.identifier}`;
|
|
||||||
const res = await fetch(url)
|
|
||||||
const data = await res.json()
|
|
||||||
if(data.error) return false
|
|
||||||
return data
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
const res = await Promise.all(getAllSchemas);
|
|
||||||
return res.filter((item)=> !!item)
|
|
||||||
}
|
|
||||||
|
|
||||||
getFeedOnInterval(){
|
|
||||||
let interval = null;
|
|
||||||
let stop = false;
|
|
||||||
const getAnswer = async () => {
|
|
||||||
|
|
||||||
if (!stop) {
|
|
||||||
stop = true;
|
|
||||||
try {
|
|
||||||
await this.reFetchFeedData()
|
|
||||||
} catch (error) {}
|
|
||||||
stop = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
interval = setInterval(getAnswer, 900000);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async getEndpoints(){
|
|
||||||
const dynamicVars = {
|
|
||||||
|
|
||||||
}
|
|
||||||
const schemas = await this.getSchemas()
|
|
||||||
const friendList = JSON.parse(localStorage.getItem('friends-my-friend-list') || "[]")
|
|
||||||
const names = friendList.map(friend => `name=${friend.name}`).join('&');
|
|
||||||
if(names.length === 0){
|
|
||||||
this.endpoints= []
|
|
||||||
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
|
||||||
return
|
|
||||||
}
|
|
||||||
const baseurl = `${this.nodeUrl}/arbitrary/resources/search?reverse=true&mode=ALL&exactmatchnames=true&${names}`
|
|
||||||
let formEndpoints = []
|
|
||||||
schemas.forEach((schema)=> {
|
|
||||||
const feedData = schema.feed[0]
|
|
||||||
if(feedData){
|
|
||||||
const copyFeedData = {...feedData}
|
|
||||||
const fullUrl = constructUrl(baseurl, copyFeedData.search, dynamicVars);
|
|
||||||
if(fullUrl){
|
|
||||||
formEndpoints.push({
|
|
||||||
url: fullUrl, schemaName: schema.name, schema: copyFeedData
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
})
|
|
||||||
this.endpoints= formEndpoints
|
|
||||||
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
async firstUpdated(){
|
|
||||||
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
|
||||||
this.downObserverElement =
|
|
||||||
this.shadowRoot.getElementById('downObserver');
|
|
||||||
this.elementObserver();
|
|
||||||
|
|
||||||
|
|
||||||
try {
|
|
||||||
await new Promise((res)=> {
|
|
||||||
setTimeout(() => {
|
|
||||||
res()
|
|
||||||
}, 5000);
|
|
||||||
})
|
|
||||||
if(this.mySelectedFeeds.length === 0){
|
|
||||||
await this.getEndpoints()
|
|
||||||
|
|
||||||
await this.loadAndMergeData();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getFeedOnInterval()
|
|
||||||
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getMoreFeed(){
|
|
||||||
if(!this.hasInitialFetch) return
|
|
||||||
if(this.feedToRender.length === this.feed.length ) return
|
|
||||||
this.feedToRender = this.feed.slice(0, this.feedToRender.length + 20)
|
|
||||||
this.requestUpdate()
|
|
||||||
}
|
|
||||||
|
|
||||||
async refresh(){
|
|
||||||
try {
|
|
||||||
await this.getEndpoints()
|
|
||||||
await this.reFetchFeedData()
|
|
||||||
} catch (error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
elementObserver() {
|
|
||||||
const options = {
|
|
||||||
rootMargin: '0px',
|
|
||||||
threshold: 1,
|
|
||||||
};
|
|
||||||
// identify an element to observe
|
|
||||||
const elementToObserve = this.downObserverElement;
|
|
||||||
// passing it a callback function
|
|
||||||
const observer = new IntersectionObserver(
|
|
||||||
this.observerHandler,
|
|
||||||
options
|
|
||||||
);
|
|
||||||
// call `observe()` on that MutationObserver instance,
|
|
||||||
// passing it the element to observe, and the options object
|
|
||||||
observer.observe(elementToObserve);
|
|
||||||
}
|
|
||||||
|
|
||||||
observerHandler(entries) {
|
|
||||||
if (!entries[0].isIntersecting) {
|
|
||||||
|
|
||||||
} else {
|
|
||||||
if (this.feedToRender.length < 20) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.getMoreFeed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchDataFromEndpoint(endpointIndex, count) {
|
|
||||||
const offset = this.endpointOffsets[endpointIndex];
|
|
||||||
const url = `${this.endpoints[endpointIndex].url}&limit=${count}&offset=${offset}`;
|
|
||||||
const res = await fetch(url)
|
|
||||||
const data = await res.json()
|
|
||||||
return data.map((i)=> {
|
|
||||||
return {
|
|
||||||
...this.endpoints[endpointIndex],
|
|
||||||
...i
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async initialLoad() {
|
|
||||||
let results = [];
|
|
||||||
let totalFetched = 0;
|
|
||||||
let i = 0;
|
|
||||||
let madeProgress = true;
|
|
||||||
let exhaustedEndpoints = new Set();
|
|
||||||
|
|
||||||
while (totalFetched < totalDesiredCount && madeProgress) {
|
|
||||||
madeProgress = false;
|
|
||||||
this.isLoading = true
|
|
||||||
for (i = 0; i < this.endpoints.length; i++) {
|
|
||||||
if (exhaustedEndpoints.has(i)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const remainingCount = totalDesiredCount - totalFetched;
|
|
||||||
|
|
||||||
// If we've already reached the desired count, break
|
|
||||||
if (remainingCount <= 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let fetchCount = Math.min(perEndpointCount, remainingCount);
|
|
||||||
let data = await this.fetchDataFromEndpoint(i, fetchCount);
|
|
||||||
|
|
||||||
// Increment the offset for this endpoint by the number of items fetched
|
|
||||||
this.endpointOffsets[i] += data.length;
|
|
||||||
|
|
||||||
if (data.length > 0) {
|
|
||||||
madeProgress = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.length < fetchCount) {
|
|
||||||
exhaustedEndpoints.add(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
results = results.concat(data);
|
|
||||||
totalFetched += data.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (exhaustedEndpoints.size === this.endpoints.length) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.isLoading = false
|
|
||||||
this.hasFetched = true;
|
|
||||||
// Trim the results if somehow they are over the totalDesiredCount
|
|
||||||
return results.slice(0, totalDesiredCount);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
trimDataToLimit(data, limit) {
|
|
||||||
return data.slice(0, limit);
|
|
||||||
}
|
|
||||||
|
|
||||||
mergeData(newData, existingData) {
|
|
||||||
const existingIds = new Set(existingData.map(item => item.identifier)); // Assume each item has a unique 'id'
|
|
||||||
const uniqueNewData = newData.filter(item => !existingIds.has(item.identifier));
|
|
||||||
return uniqueNewData.concat(existingData);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async addExtraData(data){
|
|
||||||
let newData = []
|
|
||||||
for (let item of data) {
|
|
||||||
let newItem = {
|
|
||||||
...item,
|
|
||||||
schema: {
|
|
||||||
...item.schema,
|
|
||||||
customParams: {...item.schema.customParams}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let newResource = {
|
|
||||||
identifier: newItem.identifier,
|
|
||||||
service: newItem.service,
|
|
||||||
name: newItem.name
|
|
||||||
}
|
|
||||||
if(newItem.schema){
|
|
||||||
const resource = newItem
|
|
||||||
|
|
||||||
let clickValue1 = newItem.schema.click;
|
|
||||||
|
|
||||||
newItem.link = replacePlaceholders(clickValue1, resource, newItem.schema.customParams)
|
|
||||||
newData.push(newItem)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return newData
|
|
||||||
|
|
||||||
}
|
|
||||||
async reFetchFeedData() {
|
|
||||||
// Resetting offsets to start fresh.
|
|
||||||
this.endpointOffsets = Array(this.endpoints.length).fill(0);
|
|
||||||
await this.getEndpoints()
|
|
||||||
const oldIdentifiers = new Set(this.feed.map(item => item.identifier));
|
|
||||||
const newData = await this.initialLoad();
|
|
||||||
|
|
||||||
// Filter out items that are already in the feed
|
|
||||||
const trulyNewData = newData.filter(item => !oldIdentifiers.has(item.identifier));
|
|
||||||
|
|
||||||
if (trulyNewData.length > 0) {
|
|
||||||
// Adding extra data and merging with old data
|
|
||||||
const enhancedNewData = await this.addExtraData(trulyNewData);
|
|
||||||
|
|
||||||
// Merge new data with old data immutably
|
|
||||||
this.feed = [...enhancedNewData, ...this.feed];
|
|
||||||
this.feed = this.removeDuplicates(this.feed)
|
|
||||||
this.feed.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
|
||||||
this.feed = this.trimDataToLimit(this.feed, maxResultsInMemory); // Trim to the maximum allowed in memory
|
|
||||||
this.feedToRender = this.feed.slice(0, 20);
|
|
||||||
this.hasInitialFetch = true;
|
|
||||||
|
|
||||||
const created = trulyNewData[0].created;
|
|
||||||
let value = localStorage.getItem('lastSeenFeed');
|
|
||||||
if (((+value || 0) < created)) {
|
|
||||||
this.setHasNewFeed(true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
removeDuplicates(array) {
|
|
||||||
const seenIds = new Set();
|
|
||||||
return array.filter(item => {
|
|
||||||
if (!seenIds.has(item.identifier)) {
|
|
||||||
seenIds.add(item.identifier);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async loadAndMergeData() {
|
|
||||||
let allData = this.feed
|
|
||||||
const newData = await this.initialLoad();
|
|
||||||
allData = await this.addExtraData(newData)
|
|
||||||
allData = this.mergeData(newData, allData);
|
|
||||||
allData.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
|
||||||
allData = this.trimDataToLimit(allData, maxResultsInMemory); // Trim to the maximum allowed in memory
|
|
||||||
allData = this.removeDuplicates(allData)
|
|
||||||
this.feed = [...allData]
|
|
||||||
this.feedToRender = this.feed.slice(0,20)
|
|
||||||
this.hasInitialFetch = true
|
|
||||||
if(allData.length > 0){
|
|
||||||
const created = allData[0].created
|
|
||||||
let value = localStorage.getItem('lastSeenFeed')
|
|
||||||
if (((+value || 0) < created)) {
|
|
||||||
this.setHasNewFeed(true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="container">
|
<div class="container">
|
||||||
@ -409,68 +60,402 @@ this.getFeedOnInterval()
|
|||||||
</div>
|
</div>
|
||||||
` : ''}
|
` : ''}
|
||||||
${this.feedToRender.map((item) => {
|
${this.feedToRender.map((item) => {
|
||||||
return html`<feed-item
|
return html`
|
||||||
|
<feed-item
|
||||||
.resource=${item}
|
.resource=${item}
|
||||||
appName=${'Q-Blog'}
|
appName=${'Q-Blog'}
|
||||||
link=${item.link}
|
link=${item.link}
|
||||||
></feed-item>`;
|
>
|
||||||
|
</feed-item>
|
||||||
|
`
|
||||||
})}
|
})}
|
||||||
<div id="downObserver"></div>
|
<div id="downObserver"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
this.viewElement = this.shadowRoot.getElementById('viewElement')
|
||||||
|
this.downObserverElement = this.shadowRoot.getElementById('downObserver')
|
||||||
|
this.elementObserver()
|
||||||
|
|
||||||
|
try {
|
||||||
|
await new Promise((res) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
res()
|
||||||
|
}, 5000)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (this.mySelectedFeeds.length === 0) {
|
||||||
|
await this.getEndpoints()
|
||||||
|
await this.loadAndMergeData()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getFeedOnInterval()
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyNode() {
|
||||||
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateFeeds(event) {
|
||||||
|
this.mySelectedFeeds = event.detail
|
||||||
|
this.reFetchFeedData()
|
||||||
|
this.requestUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedCallback() {
|
||||||
|
super.connectedCallback()
|
||||||
|
window.addEventListener('friends-my-selected-feeds-event', this._updateFeeds)
|
||||||
|
}
|
||||||
|
|
||||||
|
disconnectedCallback() {
|
||||||
|
window.removeEventListener('friends-my-selected-feeds-event', this._updateFeeds)
|
||||||
|
super.disconnectedCallback()
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSchemas() {
|
||||||
|
this.mySelectedFeeds = JSON.parse(localStorage.getItem('friends-my-selected-feeds') || "[]")
|
||||||
|
const schemas = this.mySelectedFeeds
|
||||||
|
|
||||||
|
const getAllSchemas = (schemas || []).map(
|
||||||
|
async (schema) => {
|
||||||
|
try {
|
||||||
|
const url = `${this.nodeUrl}/arbitrary/${schema.service}/${schema.name}/${schema.identifier}`
|
||||||
|
const res = await fetch(url)
|
||||||
|
const data = await res.json()
|
||||||
|
if (data.error) return false
|
||||||
|
return data
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const res = await Promise.all(getAllSchemas)
|
||||||
|
return res.filter((item) => !!item)
|
||||||
|
}
|
||||||
|
|
||||||
|
getFeedOnInterval() {
|
||||||
|
let interval = null
|
||||||
|
let stop = false
|
||||||
|
|
||||||
|
const getAnswer = async () => {
|
||||||
|
if (!stop) {
|
||||||
|
stop = true
|
||||||
|
try {
|
||||||
|
await this.reFetchFeedData()
|
||||||
|
} catch (error) { }
|
||||||
|
stop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interval = setInterval(getAnswer, 900000)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getEndpoints() {
|
||||||
|
const dynamicVars = { }
|
||||||
|
const schemas = await this.getSchemas()
|
||||||
|
const friendList = JSON.parse(localStorage.getItem('friends-my-friend-list') || "[]")
|
||||||
|
const names = friendList.map(friend => `name=${friend.name}`).join('&')
|
||||||
|
|
||||||
|
if (names.length === 0) {
|
||||||
|
this.endpoints = []
|
||||||
|
this.endpointOffsets = Array(this.endpoints.length).fill(0)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const baseurl = `${this.nodeUrl}/arbitrary/resources/search?reverse=true&mode=ALL&exactmatchnames=true&${names}`
|
||||||
|
let formEndpoints = []
|
||||||
|
|
||||||
|
schemas.forEach((schema) => {
|
||||||
|
const feedData = schema.feed[0]
|
||||||
|
if (feedData) {
|
||||||
|
const copyFeedData = { ...feedData }
|
||||||
|
const fullUrl = constructUrl(baseurl, copyFeedData.search, dynamicVars)
|
||||||
|
if (fullUrl) {
|
||||||
|
formEndpoints.push({
|
||||||
|
url: fullUrl, schemaName: schema.name, schema: copyFeedData
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
this.endpoints = formEndpoints
|
||||||
|
this.endpointOffsets = Array(this.endpoints.length).fill(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
getMoreFeed() {
|
||||||
|
if (!this.hasInitialFetch) return
|
||||||
|
if (this.feedToRender.length === this.feed.length) return
|
||||||
|
this.feedToRender = this.feed.slice(0, this.feedToRender.length + 20)
|
||||||
|
this.requestUpdate()
|
||||||
|
}
|
||||||
|
|
||||||
|
async refresh() {
|
||||||
|
try {
|
||||||
|
await this.getEndpoints()
|
||||||
|
await this.reFetchFeedData()
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
elementObserver() {
|
||||||
|
const options = {
|
||||||
|
rootMargin: '0px',
|
||||||
|
threshold: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// identify an element to observe
|
||||||
|
const elementToObserve = this.downObserverElement
|
||||||
|
|
||||||
|
// passing it a callback function
|
||||||
|
const observer = new IntersectionObserver(
|
||||||
|
this.observerHandler,
|
||||||
|
options
|
||||||
|
)
|
||||||
|
|
||||||
|
// call `observe()` on that MutationObserver instance,
|
||||||
|
// passing it the element to observe, and the options object
|
||||||
|
observer.observe(elementToObserve)
|
||||||
|
}
|
||||||
|
|
||||||
|
observerHandler(entries) {
|
||||||
|
if (!entries[0].isIntersecting) {
|
||||||
|
} else {
|
||||||
|
if (this.feedToRender.length < 20) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.getMoreFeed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchDataFromEndpoint(endpointIndex, count) {
|
||||||
|
const offset = this.endpointOffsets[endpointIndex]
|
||||||
|
const url = `${this.endpoints[endpointIndex].url}&limit=${count}&offset=${offset}`
|
||||||
|
const res = await fetch(url)
|
||||||
|
const data = await res.json()
|
||||||
|
|
||||||
|
return data.map((i) => {
|
||||||
|
return {
|
||||||
|
...this.endpoints[endpointIndex],
|
||||||
|
...i
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async initialLoad() {
|
||||||
|
let results = []
|
||||||
|
let totalFetched = 0
|
||||||
|
let i = 0
|
||||||
|
let madeProgress = true
|
||||||
|
let exhaustedEndpoints = new Set()
|
||||||
|
|
||||||
|
while (totalFetched < totalDesiredCount && madeProgress) {
|
||||||
|
madeProgress = false
|
||||||
|
this.isLoading = true
|
||||||
|
for (i = 0; i < this.endpoints.length; i++) {
|
||||||
|
if (exhaustedEndpoints.has(i)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const remainingCount = totalDesiredCount - totalFetched
|
||||||
|
|
||||||
|
// If we've already reached the desired count, break
|
||||||
|
if (remainingCount <= 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let fetchCount = Math.min(perEndpointCount, remainingCount)
|
||||||
|
let data = await this.fetchDataFromEndpoint(i, fetchCount)
|
||||||
|
|
||||||
|
// Increment the offset for this endpoint by the number of items fetched
|
||||||
|
this.endpointOffsets[i] += data.length
|
||||||
|
|
||||||
|
if (data.length > 0) {
|
||||||
|
madeProgress = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.length < fetchCount) {
|
||||||
|
exhaustedEndpoints.add(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
results = results.concat(data)
|
||||||
|
totalFetched += data.length
|
||||||
|
}
|
||||||
|
|
||||||
|
if (exhaustedEndpoints.size === this.endpoints.length) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isLoading = false
|
||||||
|
this.hasFetched = true
|
||||||
|
|
||||||
|
// Trim the results if somehow they are over the totalDesiredCount
|
||||||
|
return results.slice(0, totalDesiredCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
trimDataToLimit(data, limit) {
|
||||||
|
return data.slice(0, limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
mergeData(newData, existingData) {
|
||||||
|
const existingIds = new Set(existingData.map(item => item.identifier)) // Assume each item has a unique 'id'
|
||||||
|
const uniqueNewData = newData.filter(item => !existingIds.has(item.identifier))
|
||||||
|
return uniqueNewData.concat(existingData)
|
||||||
|
}
|
||||||
|
|
||||||
|
async addExtraData(data) {
|
||||||
|
let newData = []
|
||||||
|
for (let item of data) {
|
||||||
|
let newItem = {
|
||||||
|
...item,
|
||||||
|
schema: {
|
||||||
|
...item.schema,
|
||||||
|
customParams: { ...item.schema.customParams }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let newResource = {
|
||||||
|
identifier: newItem.identifier,
|
||||||
|
service: newItem.service,
|
||||||
|
name: newItem.name
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newItem.schema) {
|
||||||
|
const resource = newItem
|
||||||
|
|
||||||
|
let clickValue1 = newItem.schema.click;
|
||||||
|
|
||||||
|
newItem.link = replacePlaceholders(clickValue1, resource, newItem.schema.customParams)
|
||||||
|
newData.push(newItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newData
|
||||||
|
}
|
||||||
|
|
||||||
|
async reFetchFeedData() {
|
||||||
|
// Resetting offsets to start fresh.
|
||||||
|
this.endpointOffsets = Array(this.endpoints.length).fill(0)
|
||||||
|
await this.getEndpoints()
|
||||||
|
const oldIdentifiers = new Set(this.feed.map(item => item.identifier))
|
||||||
|
const newData = await this.initialLoad()
|
||||||
|
|
||||||
|
// Filter out items that are already in the feed
|
||||||
|
const trulyNewData = newData.filter(item => !oldIdentifiers.has(item.identifier))
|
||||||
|
|
||||||
|
if (trulyNewData.length > 0) {
|
||||||
|
// Adding extra data and merging with old data
|
||||||
|
const enhancedNewData = await this.addExtraData(trulyNewData)
|
||||||
|
|
||||||
|
// Merge new data with old data immutably
|
||||||
|
this.feed = [...enhancedNewData, ...this.feed]
|
||||||
|
this.feed = this.removeDuplicates(this.feed)
|
||||||
|
this.feed.sort((a, b) => new Date(b.created) - new Date(a.created)) // Sort by timestamp, most recent first
|
||||||
|
this.feed = this.trimDataToLimit(this.feed, maxResultsInMemory) // Trim to the maximum allowed in memory
|
||||||
|
this.feedToRender = this.feed.slice(0, 20)
|
||||||
|
this.hasInitialFetch = true
|
||||||
|
|
||||||
|
const created = trulyNewData[0].created
|
||||||
|
let value = localStorage.getItem('lastSeenFeed')
|
||||||
|
if (((+value || 0) < created)) {
|
||||||
|
this.setHasNewFeed(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeDuplicates(array) {
|
||||||
|
const seenIds = new Set()
|
||||||
|
return array.filter(item => {
|
||||||
|
if (!seenIds.has(item.identifier)) {
|
||||||
|
seenIds.add(item.identifier)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async loadAndMergeData() {
|
||||||
|
let allData = this.feed
|
||||||
|
const newData = await this.initialLoad();
|
||||||
|
allData = await this.addExtraData(newData)
|
||||||
|
allData = this.mergeData(newData, allData);
|
||||||
|
allData.sort((a, b) => new Date(b.created) - new Date(a.created)); // Sort by timestamp, most recent first
|
||||||
|
allData = this.trimDataToLimit(allData, maxResultsInMemory); // Trim to the maximum allowed in memory
|
||||||
|
allData = this.removeDuplicates(allData)
|
||||||
|
this.feed = [...allData]
|
||||||
|
this.feedToRender = this.feed.slice(0, 20)
|
||||||
|
this.hasInitialFetch = true
|
||||||
|
if (allData.length > 0) {
|
||||||
|
const created = allData[0].created
|
||||||
|
let value = localStorage.getItem('lastSeenFeed')
|
||||||
|
if (((+value || 0) < created)) {
|
||||||
|
this.setHasNewFeed(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('friends-feed', FriendsFeed);
|
window.customElements.define('friends-feed', FriendsFeed)
|
||||||
|
|
||||||
export function substituteDynamicVar(value, dynamicVars) {
|
export function substituteDynamicVar(value, dynamicVars) {
|
||||||
if (typeof value !== 'string') return value;
|
if (typeof value !== 'string') return value
|
||||||
|
const pattern = /\$\$\{([a-zA-Z0-9_]+)\}\$\$/g // Adjusted pattern to capture $${name}$$ with curly braces
|
||||||
const pattern = /\$\$\{([a-zA-Z0-9_]+)\}\$\$/g; // Adjusted pattern to capture $${name}$$ with curly braces
|
|
||||||
|
|
||||||
return value.replace(pattern, (match, p1) => {
|
return value.replace(pattern, (match, p1) => {
|
||||||
return dynamicVars[p1] !== undefined ? dynamicVars[p1] : match;
|
return dynamicVars[p1] !== undefined ? dynamicVars[p1] : match
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export function constructUrl(base, search, dynamicVars) {
|
export function constructUrl(base, search, dynamicVars) {
|
||||||
let queryStrings = [];
|
let queryStrings = []
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(search)) {
|
for (const [key, value] of Object.entries(search)) {
|
||||||
const substitutedValue = substituteDynamicVar(value, dynamicVars);
|
const substitutedValue = substituteDynamicVar(value, dynamicVars)
|
||||||
queryStrings.push(`${key}=${encodeURIComponent(substitutedValue)}`);
|
queryStrings.push(`${key}=${encodeURIComponent(substitutedValue)}`)
|
||||||
}
|
}
|
||||||
|
return queryStrings.length > 0 ? `${base}&${queryStrings.join('&')}` : base
|
||||||
return queryStrings.length > 0 ? `${base}&${queryStrings.join('&')}` : base;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function replacePlaceholders(template, resource, customParams) {
|
export function replacePlaceholders(template, resource, customParams) {
|
||||||
const dataSource = { resource, customParams };
|
const dataSource = { resource, customParams }
|
||||||
|
|
||||||
return template.replace(/\$\$\{(.*?)\}\$\$/g, (match, p1) => {
|
return template.replace(/\$\$\{(.*?)\}\$\$/g, (match, p1) => {
|
||||||
const keys = p1.split('.');
|
const keys = p1.split('.')
|
||||||
let value = dataSource;
|
let value = dataSource
|
||||||
|
|
||||||
for (let key of keys) {
|
for (let key of keys) {
|
||||||
if (value[key] !== undefined) {
|
if (value[key] !== undefined) {
|
||||||
value = value[key];
|
value = value[key]
|
||||||
} else {
|
} else {
|
||||||
return match; // Return placeholder unchanged
|
return match // Return placeholder unchanged
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return value;
|
return value
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,68 +1,43 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store'
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
import { friendsSidePanelParentStyles } from '../../styles/core-css'
|
||||||
|
import './friends-side-panel'
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
import './friends-side-panel.js'
|
|
||||||
import '@vaadin/tooltip'
|
import '@vaadin/tooltip'
|
||||||
import {translate} from '../../../translate'
|
|
||||||
|
|
||||||
class FriendsSidePanelParent extends LitElement {
|
class FriendsSidePanelParent extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
isOpen: {type: Boolean},
|
isOpen: { type: Boolean },
|
||||||
hasNewFeed: {type: Boolean}
|
hasNewFeed: { type: Boolean }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [friendsSidePanelParentStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.isOpen = false
|
this.isOpen = false
|
||||||
this.hasNewFeed = false
|
this.hasNewFeed = false
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: 16px;
|
|
||||||
}
|
|
||||||
.close {
|
|
||||||
visibility: hidden;
|
|
||||||
position: fixed;
|
|
||||||
z-index: -100;
|
|
||||||
right: -1000px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.parent-side-panel {
|
|
||||||
transform: translateX(100%); /* start from outside the right edge */
|
|
||||||
transition: transform 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
.parent-side-panel.open {
|
|
||||||
transform: translateX(0); /* slide in to its original position */
|
|
||||||
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
setHasNewFeed(val){
|
|
||||||
this.hasNewFeed = val
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
id="friends-icon"
|
id="friends-icon"
|
||||||
@click=${()=> {
|
@click=${() => {
|
||||||
this.isOpen = !this.isOpen
|
this.isOpen = !this.isOpen
|
||||||
if(this.isOpen && this.hasNewFeed) {
|
if (this.isOpen && this.hasNewFeed) {
|
||||||
localStorage.setItem('lastSeenFeed', Date.now())
|
localStorage.setItem('lastSeenFeed', Date.now())
|
||||||
this.hasNewFeed = false
|
this.hasNewFeed = false
|
||||||
this.shadowRoot.querySelector("friends-side-panel").selected = 'feed'
|
this.shadowRoot.querySelector("friends-side-panel").selected = 'feed'
|
||||||
}
|
}
|
||||||
}} style="color: ${this.hasNewFeed ? 'green' : 'var(--black)'}; cursor:pointer;user-select:none"
|
}}
|
||||||
|
style="color: ${this.hasNewFeed ? 'green' : 'var(--black)'}; cursor:pointer;user-select:none"
|
||||||
>
|
>
|
||||||
group
|
group
|
||||||
</mwc-icon>
|
</mwc-icon>
|
||||||
@ -72,12 +47,33 @@ class FriendsSidePanelParent extends LitElement {
|
|||||||
hover-delay=${400}
|
hover-delay=${400}
|
||||||
hide-delay=${1}
|
hide-delay=${1}
|
||||||
text=${translate('friends.friend12')}
|
text=${translate('friends.friend12')}
|
||||||
>
|
></vaadin-tooltip>
|
||||||
</vaadin-tooltip>
|
<friends-side-panel .setHasNewFeed=${(val) => this.setHasNewFeed(val)} ?isOpen=${this.isOpen} .setIsOpen=${(val) => this.isOpen = val}></friends-side-panel>
|
||||||
<friends-side-panel .setHasNewFeed=${(val)=> this.setHasNewFeed(val)} ?isOpen=${this.isOpen} .setIsOpen=${(val)=> this.isOpen = val}></friends-side-panel>
|
|
||||||
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
setHasNewFeed(val) {
|
||||||
|
this.hasNewFeed = val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('friends-side-panel-parent', FriendsSidePanelParent)
|
window.customElements.define('friends-side-panel-parent', FriendsSidePanelParent)
|
@ -1,122 +1,33 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import '@material/mwc-icon';
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store'
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
import { friendsSidePanelStyles } from '../../styles/core-css'
|
||||||
import './friends-view'
|
import './friends-view'
|
||||||
import './friends-feed'
|
import './friends-feed'
|
||||||
import {translate} from '../../../translate'
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
class FriendsSidePanel extends LitElement {
|
class FriendsSidePanel extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
setIsOpen: { attribute: false},
|
setIsOpen: { attribute: false },
|
||||||
isOpen: {type: Boolean},
|
isOpen: { type: Boolean },
|
||||||
selected: {type: String},
|
selected: { type: String },
|
||||||
setHasNewFeed: {attribute: false},
|
setHasNewFeed: { attribute: false },
|
||||||
closeSidePanel: {attribute: false, type: Object},
|
closeSidePanel: { attribute: false, type: Object },
|
||||||
openSidePanel: {attribute: false, type: Object}
|
openSidePanel: { attribute: false, type: Object }
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(){
|
static get styles() {
|
||||||
|
return [friendsSidePanelStyles]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.selected = 'friends'
|
this.selected = 'friends'
|
||||||
this.closeSidePanel = this.closeSidePanel.bind(this)
|
this.closeSidePanel = this.closeSidePanel.bind(this)
|
||||||
this.openSidePanel = this.openSidePanel.bind(this)
|
this.openSidePanel = this.openSidePanel.bind(this)
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
:host {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
top: 55px;
|
|
||||||
right: 0px;
|
|
||||||
width: 420px;
|
|
||||||
max-width: 95%;
|
|
||||||
height: calc(100vh - 55px);
|
|
||||||
background-color: var(--white);
|
|
||||||
border-left: 1px solid rgb(224, 224, 224);
|
|
||||||
z-index: 1;
|
|
||||||
transform: translateX(100%); /* start from outside the right edge */
|
|
||||||
transition: transform 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
:host([isOpen]) {
|
|
||||||
transform: unset; /* slide in to its original position */
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 16px;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content {
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
.content::-webkit-scrollbar-track {
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content::-webkit-scrollbar {
|
|
||||||
width: 12px;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(180, 176, 176);
|
|
||||||
border-radius: 7px;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
.parent {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.active {
|
|
||||||
font-size: 16px;
|
|
||||||
background: var(--black);
|
|
||||||
color: var(--white);
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.default {
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--black);
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.default-content {
|
|
||||||
visibility: hidden;
|
|
||||||
position: absolute;
|
|
||||||
z-index: -50;
|
|
||||||
}
|
|
||||||
|
|
||||||
`;
|
|
||||||
|
|
||||||
refreshFeed(){
|
|
||||||
|
|
||||||
this.shadowRoot.querySelector('friends-feed').refresh()
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
closeSidePanel(){
|
|
||||||
this.setIsOpen(false)
|
|
||||||
}
|
|
||||||
openSidePanel(){
|
|
||||||
this.setIsOpen(true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -124,35 +35,60 @@ class FriendsSidePanel extends LitElement {
|
|||||||
<div class="parent">
|
<div class="parent">
|
||||||
<div class="header">
|
<div class="header">
|
||||||
<div style="display:flex;align-items:center;gap:10px">
|
<div style="display:flex;align-items:center;gap:10px">
|
||||||
<span @click=${()=> this.selected = 'friends'} class="${this.selected === 'friends' ? 'active' : 'default'}">${translate('friends.friend12')}</span>
|
<span @click=${() => this.selected = 'friends'} class="${this.selected === 'friends' ? 'active' : 'default'}">${translate('friends.friend12')}</span>
|
||||||
<span @click=${()=> this.selected = 'feed'} class="${this.selected === 'feed' ? 'active' : 'default'}">${translate('friends.friend13')}</span>
|
<span @click=${() => this.selected = 'feed'} class="${this.selected === 'feed' ? 'active' : 'default'}">${translate('friends.friend13')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div style="display:flex;gap:15px;align-items:center">
|
<div style="display:flex;gap:15px;align-items:center">
|
||||||
<mwc-icon @click=${()=> {
|
<mwc-icon @click=${() => { this.refreshFeed(); }} style="color: var(--black); cursor:pointer;">
|
||||||
this.refreshFeed()
|
refresh
|
||||||
}} style="color: var(--black); cursor:pointer;">refresh</mwc-icon>
|
</mwc-icon>
|
||||||
<mwc-icon style="cursor:pointer" @click=${()=> {
|
<mwc-icon style="cursor:pointer" @click=${() => { this.setIsOpen(false); }}>
|
||||||
this.setIsOpen(false)
|
close
|
||||||
}}>close</mwc-icon>
|
</mwc-icon>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<div class="${this.selected === 'friends' ? 'active-content' : 'default-content'}">
|
<div class="${this.selected === 'friends' ? 'active-content' : 'default-content'}">
|
||||||
<friends-view .openSidePanel=${this.openSidePanel} .closeSidePanel=${this.closeSidePanel} .refreshFeed=${()=>this.refreshFeed()}></friends-view>
|
<friends-view .openSidePanel=${this.openSidePanel} .closeSidePanel=${this.closeSidePanel} .refreshFeed=${() => this.refreshFeed()}></friends-view>
|
||||||
</div>
|
</div>
|
||||||
<div class="${this.selected === 'feed' ? 'active-content' : 'default-content'}">
|
<div class="${this.selected === 'feed' ? 'active-content' : 'default-content'}">
|
||||||
<friends-feed .setHasNewFeed=${(val)=> this.setHasNewFeed(val)}></friends-feed>
|
<friends-feed .setHasNewFeed=${(val) => this.setHasNewFeed(val)}></friends-feed>
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshFeed() {
|
||||||
|
this.shadowRoot.querySelector('friends-feed').refresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
closeSidePanel() {
|
||||||
|
this.setIsOpen(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
openSidePanel() {
|
||||||
|
this.setIsOpen(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('friends-side-panel', FriendsSidePanel);
|
window.customElements.define('friends-side-panel', FriendsSidePanel)
|
@ -1,182 +0,0 @@
|
|||||||
import {css} from 'lit'
|
|
||||||
|
|
||||||
export const friendsViewStyles = css`
|
|
||||||
* {
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.top-bar-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
height: 18px;
|
|
||||||
width: 18px;
|
|
||||||
transition: 0.2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.top-bar-icon:hover {
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-row {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 50px;
|
|
||||||
flex:0
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-body {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex-grow: 1;
|
|
||||||
margin-top: 5px;
|
|
||||||
padding: 0px 6px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
align-items: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-body::-webkit-scrollbar-track {
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-body::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-body::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(180, 176, 176);
|
|
||||||
border-radius: 7px;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container-body::-webkit-scrollbar-thumb:hover {
|
|
||||||
background-color: rgb(148, 146, 146);
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-right-panel-label {
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
color: var(--group-header);
|
|
||||||
padding: 5px;
|
|
||||||
font-size: 13px;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-info {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: flex-start;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-name {
|
|
||||||
font-family: Raleway, sans-serif;
|
|
||||||
font-size: 20px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
text-align: center;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-description {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
font-weight: 300;
|
|
||||||
font-size: 14px;
|
|
||||||
margin-top: 15px;
|
|
||||||
word-break: break-word;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-subheader {
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.group-data {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
letter-spacing: 0.3px;
|
|
||||||
font-weight: 300;
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
}
|
|
||||||
.search-results-div {
|
|
||||||
position: absolute;
|
|
||||||
top: 25px;
|
|
||||||
right: 25px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-input {
|
|
||||||
width: 100%;
|
|
||||||
outline: 0;
|
|
||||||
border-width: 0 0 2px;
|
|
||||||
border-color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-input::selection {
|
|
||||||
background-color: var(--mdc-theme-primary);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.name-input::placeholder {
|
|
||||||
opacity: 0.9;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-field {
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-icon {
|
|
||||||
position: absolute;
|
|
||||||
right: 3px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
transition: hover 0.3s ease-in-out;
|
|
||||||
background: none;
|
|
||||||
border-radius: 50%;
|
|
||||||
padding: 6px 3px;
|
|
||||||
font-size: 21px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.search-icon:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background: #d7d7d75c;
|
|
||||||
}
|
|
||||||
`
|
|
@ -1,22 +1,20 @@
|
|||||||
import {html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers';
|
import { store } from '../../store'
|
||||||
|
import { connect } from 'pwa-helpers'
|
||||||
import '@material/mwc-button';
|
import { parentEpml } from '../show-plugin'
|
||||||
import '@material/mwc-dialog';
|
import { translate } from '../../../translate'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import { friendsViewStyles } from '../../styles/core-css'
|
||||||
import '@polymer/paper-progress/paper-progress.js';
|
import './add-friends-modal'
|
||||||
import '@material/mwc-icon';
|
import './ChatSideNavHeads'
|
||||||
|
import '../../../../plugins/plugins/core/components/ChatSearchResults'
|
||||||
|
import '@material/mwc-button'
|
||||||
|
import '@material/mwc-dialog'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
|
import '@polymer/paper-progress/paper-progress.js'
|
||||||
import '@vaadin/icon'
|
import '@vaadin/icon'
|
||||||
import '@vaadin/icons'
|
import '@vaadin/icons'
|
||||||
import '@vaadin/button';
|
import '@vaadin/button'
|
||||||
import './ChatSideNavHeads';
|
|
||||||
import '../../../../plugins/plugins/core/components/ChatSearchResults'
|
|
||||||
import './add-friends-modal'
|
|
||||||
|
|
||||||
import {translate,} from '../../../translate'
|
|
||||||
import {store} from '../../store';
|
|
||||||
import {friendsViewStyles} from './friends-view-css';
|
|
||||||
import {parentEpml} from '../show-plugin';
|
|
||||||
|
|
||||||
class FriendsView extends connect(store)(LitElement) {
|
class FriendsView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -29,94 +27,159 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
setUserName: { attribute: false },
|
setUserName: { attribute: false },
|
||||||
friendList: { type: Array },
|
friendList: { type: Array },
|
||||||
userSelected: { type: Object },
|
userSelected: { type: Object },
|
||||||
isLoading: {type: Boolean},
|
isLoading: { type: Boolean },
|
||||||
userFoundModalOpen: {type: Boolean},
|
userFoundModalOpen: { type: Boolean },
|
||||||
userFound: { type: Array},
|
userFound: { type: Array },
|
||||||
isOpenAddFriendsModal: {type: Boolean},
|
isOpenAddFriendsModal: { type: Boolean },
|
||||||
editContent: {type: Object},
|
editContent: { type: Object },
|
||||||
mySelectedFeeds: {type: Array},
|
mySelectedFeeds: { type: Array },
|
||||||
refreshFeed: {attribute: false},
|
refreshFeed: { attribute: false },
|
||||||
closeSidePanel: {attribute: false, type: Object},
|
closeSidePanel: { attribute: false, type: Object },
|
||||||
openSidePanel: {attribute:false, type: Object}
|
openSidePanel: { attribute: false, type: Object }
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [friendsViewStyles];
|
return [friendsViewStyles]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.error = false;
|
this.error = false
|
||||||
this.observerHandler = this.observerHandler.bind(this);
|
this.observerHandler = this.observerHandler.bind(this)
|
||||||
this.viewElement = '';
|
this.viewElement = ''
|
||||||
this.downObserverElement = '';
|
this.downObserverElement = ''
|
||||||
this.myAddress =
|
this.myAddress = store.getState().app.selectedAddress.address
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.address;
|
this.errorMessage = ''
|
||||||
this.errorMessage = '';
|
this.successMessage = ''
|
||||||
this.successMessage = '';
|
this.friendList = []
|
||||||
this.friendList = [];
|
this.userSelected = {}
|
||||||
this.userSelected = {};
|
this.isLoading = false
|
||||||
this.isLoading = false;
|
|
||||||
this.userFoundModalOpen = false
|
this.userFoundModalOpen = false
|
||||||
this.userFound = [];
|
this.userFound = []
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.myNode = this.getMyNode();
|
this.myNode = this.getMyNode()
|
||||||
this.isOpenAddFriendsModal = false
|
this.isOpenAddFriendsModal = false
|
||||||
this.editContent = null
|
this.editContent = null
|
||||||
this.addToFriendList = this.addToFriendList.bind(this)
|
this.addToFriendList = this.addToFriendList.bind(this)
|
||||||
this._updateFriends = this._updateFriends.bind(this)
|
this._updateFriends = this._updateFriends.bind(this)
|
||||||
this._updateFeed = this._updateFeed.bind(this)
|
this._updateFeed = this._updateFeed.bind(this)
|
||||||
this._addFriend = this._addFriend.bind(this)
|
this._addFriend = this._addFriend.bind(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div class="container">
|
||||||
|
<div id="viewElement" class="container-body" style=${"position: relative"}>
|
||||||
|
<p class="group-name">My Friends</p>
|
||||||
|
<div class="search-field">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="name-input"
|
||||||
|
?disabled=${this.isLoading}
|
||||||
|
id="sendTo"
|
||||||
|
placeholder="${translate("friends.friend1")}"
|
||||||
|
value=${this.userSelected.name ? this.userSelected.name : ''}
|
||||||
|
@keypress=${(e) => {
|
||||||
|
if (e.key === 'Enter') {
|
||||||
|
this.userSearch()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<vaadin-icon
|
||||||
|
@click=${this.userSearch}
|
||||||
|
slot="icon"
|
||||||
|
icon="vaadin:search"
|
||||||
|
class="search-icon"
|
||||||
|
>
|
||||||
|
</vaadin-icon>
|
||||||
|
</div>
|
||||||
|
<div class="search-results-div">
|
||||||
|
<chat-search-results
|
||||||
|
.onClickFunc=${(result) => {
|
||||||
|
this.userSelected = result;
|
||||||
|
this.isOpenAddFriendsModal = true
|
||||||
|
this.userFound = [];
|
||||||
|
this.userFoundModalOpen = false;
|
||||||
|
}}
|
||||||
|
.closeFunc=${() => {
|
||||||
|
this.userFoundModalOpen = false;
|
||||||
|
this.userFound = [];
|
||||||
|
}}
|
||||||
|
.searchResults=${this.userFound}
|
||||||
|
?isOpen=${this.userFoundModalOpen}
|
||||||
|
?loading=${this.isLoading}
|
||||||
|
>
|
||||||
|
</chat-search-results>
|
||||||
|
</div>
|
||||||
|
${this.friendList.map((item) => {
|
||||||
|
return html`
|
||||||
|
<chat-side-nav-heads
|
||||||
|
activeChatHeadUrl=""
|
||||||
|
.setActiveChatHeadUrl=${(val) => { }}
|
||||||
|
.chatInfo=${item}
|
||||||
|
.openEditFriend=${(val) => this.openEditFriend(val)}
|
||||||
|
.closeSidePanel=${this.closeSidePanel}
|
||||||
|
>
|
||||||
|
</chat-side-nav-heads>
|
||||||
|
`
|
||||||
|
})}
|
||||||
|
<div id="downObserver"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<add-friends-modal
|
||||||
|
?isOpen=${this.isOpenAddFriendsModal}
|
||||||
|
.setIsOpen=${(val) => {
|
||||||
|
this.isOpenAddFriendsModal = val
|
||||||
|
}}
|
||||||
|
.userSelected=${this.userSelected}
|
||||||
|
.onSubmit=${(val, isRemove) => this.addToFriendList(val, isRemove)}
|
||||||
|
.editContent=${this.editContent}
|
||||||
|
.onClose=${() => this.onClose()}
|
||||||
|
.mySelectedFeeds=${this.mySelectedFeeds}
|
||||||
|
>
|
||||||
|
</add-friends-modal>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.viewElement = this.shadowRoot.getElementById('viewElement')
|
||||||
|
this.downObserverElement = this.shadowRoot.getElementById('downObserver')
|
||||||
|
this.elementObserver()
|
||||||
|
this.mySelectedFeeds = JSON.parse(localStorage.getItem('friends-my-selected-feeds') || "[]")
|
||||||
|
this.friendList = JSON.parse(localStorage.getItem('friends-my-friend-list') || "[]")
|
||||||
}
|
}
|
||||||
|
|
||||||
getNodeUrl() {
|
getNodeUrl() {
|
||||||
const myNode =
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
}
|
}
|
||||||
|
|
||||||
getMyNode() {
|
getMyNode() {
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getMoreFriends() {}
|
getMoreFriends() { }
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this.viewElement = this.shadowRoot.getElementById('viewElement');
|
|
||||||
this.downObserverElement =
|
|
||||||
this.shadowRoot.getElementById('downObserver');
|
|
||||||
this.elementObserver();
|
|
||||||
this.mySelectedFeeds = JSON.parse(localStorage.getItem('friends-my-selected-feeds') || "[]")
|
|
||||||
this.friendList = JSON.parse(localStorage.getItem('friends-my-friend-list') || "[]")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
_updateFriends(event) {
|
_updateFriends(event) {
|
||||||
this.friendList = event.detail
|
this.friendList = event.detail
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateFeed(event) {
|
_updateFeed(event) {
|
||||||
this.mySelectedFeeds = event.detail
|
this.mySelectedFeeds = event.detail
|
||||||
this.requestUpdate()
|
this.requestUpdate()
|
||||||
}
|
}
|
||||||
_addFriend(event){
|
|
||||||
const name = event.detail;
|
|
||||||
const findFriend = this.friendList.find((friend)=> friend.name === name)
|
|
||||||
if(findFriend){
|
|
||||||
this.editContent = {...findFriend, mySelectedFeeds: this.mySelectedFeeds}
|
|
||||||
this.userSelected = findFriend;
|
|
||||||
|
|
||||||
|
_addFriend(event) {
|
||||||
|
const name = event.detail;
|
||||||
|
const findFriend = this.friendList.find((friend) => friend.name === name)
|
||||||
|
if (findFriend) {
|
||||||
|
this.editContent = { ...findFriend, mySelectedFeeds: this.mySelectedFeeds }
|
||||||
|
this.userSelected = findFriend
|
||||||
} else {
|
} else {
|
||||||
this.userSelected = {
|
this.userSelected = {
|
||||||
name
|
name
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isOpenAddFriendsModal = true
|
this.isOpenAddFriendsModal = true
|
||||||
@ -134,7 +197,6 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
window.removeEventListener('friends-my-friend-list-event', this._updateFriends)
|
window.removeEventListener('friends-my-friend-list-event', this._updateFriends)
|
||||||
window.removeEventListener('friends-my-selected-feeds-event', this._updateFeed)
|
window.removeEventListener('friends-my-selected-feeds-event', this._updateFeed)
|
||||||
window.removeEventListener('add-friend', this._addFriend)
|
window.removeEventListener('add-friend', this._addFriend)
|
||||||
|
|
||||||
super.disconnectedCallback()
|
super.disconnectedCallback()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,18 +204,21 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
const options = {
|
const options = {
|
||||||
root: this.viewElement,
|
root: this.viewElement,
|
||||||
rootMargin: '0px',
|
rootMargin: '0px',
|
||||||
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(
|
const observer = new IntersectionObserver(
|
||||||
this.observerHandler,
|
this.observerHandler,
|
||||||
options
|
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)
|
||||||
}
|
}
|
||||||
|
|
||||||
observerHandler(entries) {
|
observerHandler(entries) {
|
||||||
@ -163,44 +228,45 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
if (this.friendList.length < 20) {
|
if (this.friendList.length < 20) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.getMoreFriends();
|
|
||||||
|
this.getMoreFriends()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
||||||
const url = `${this.nodeUrl}/names/${nameValue}`
|
const url = `${this.nodeUrl}/names/${nameValue}`
|
||||||
const res = await fetch(url)
|
const res = await fetch(url)
|
||||||
const result = await res.json()
|
const result = await res.json()
|
||||||
|
|
||||||
if (result.error === 401) {
|
if (result.error === 401) {
|
||||||
this.userFound = []
|
this.userFound = []
|
||||||
} else {
|
} else {
|
||||||
this.userFound = [
|
this.userFound = [
|
||||||
result
|
result
|
||||||
];
|
]
|
||||||
}
|
|
||||||
this.userFoundModalOpen = true;
|
|
||||||
} catch (error) {
|
|
||||||
// let err4string = get("chatpage.cchange35");
|
|
||||||
// parentEpml.request('showSnackBar', `${err4string}`)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getApiKey() {
|
this.userFoundModalOpen = true;
|
||||||
const apiNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
} catch (error) {
|
||||||
return apiNode.apiKey
|
// let err4string = get("chatpage.cchange35")
|
||||||
|
// parentEpml.request('showSnackBar', `${err4string}`)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async myFollowName(name) {
|
async myFollowName(name) {
|
||||||
let items = [
|
let items = [
|
||||||
name
|
name
|
||||||
]
|
]
|
||||||
|
|
||||||
let namesJsonString = JSON.stringify({ "items": items })
|
let namesJsonString = JSON.stringify({ "items": items })
|
||||||
|
|
||||||
return await parentEpml.request('apiCall', {
|
return await parentEpml.request('apiCall', {
|
||||||
@ -217,6 +283,7 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
let items = [
|
let items = [
|
||||||
name
|
name
|
||||||
]
|
]
|
||||||
|
|
||||||
let namesJsonString = JSON.stringify({ "items": items })
|
let namesJsonString = JSON.stringify({ "items": items })
|
||||||
|
|
||||||
return await parentEpml.request('apiCall', {
|
return await parentEpml.request('apiCall', {
|
||||||
@ -228,47 +295,54 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
body: `${namesJsonString}`
|
body: `${namesJsonString}`
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
async addToFriendList(val, isRemove){
|
|
||||||
const copyVal = {...val}
|
async addToFriendList(val, isRemove) {
|
||||||
|
const copyVal = { ...val }
|
||||||
delete copyVal.mySelectedFeeds
|
delete copyVal.mySelectedFeeds
|
||||||
if(isRemove){
|
|
||||||
this.friendList = this.friendList.filter((item)=> item.name !== copyVal.name)
|
if (isRemove) {
|
||||||
}else if(this.editContent){
|
this.friendList = this.friendList.filter((item) => item.name !== copyVal.name)
|
||||||
const findFriend = this.friendList.findIndex(item=> item.name === copyVal.name)
|
} else if (this.editContent) {
|
||||||
if(findFriend !== -1){
|
const findFriend = this.friendList.findIndex(item => item.name === copyVal.name)
|
||||||
|
if (findFriend !== -1) {
|
||||||
const copyList = [...this.friendList]
|
const copyList = [...this.friendList]
|
||||||
copyList[findFriend] = copyVal
|
copyList[findFriend] = copyVal
|
||||||
this.friendList = copyList
|
this.friendList = copyList
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
this.friendList = [...this.friendList, copyVal]
|
this.friendList = [...this.friendList, copyVal]
|
||||||
}
|
}
|
||||||
if(!copyVal.willFollow || isRemove) {
|
|
||||||
|
if (!copyVal.willFollow || isRemove) {
|
||||||
await this.unFollowName(copyVal.name)
|
await this.unFollowName(copyVal.name)
|
||||||
} else if(copyVal.willFollow){
|
} else if (copyVal.willFollow) {
|
||||||
await this.myFollowName(copyVal.name)
|
await this.myFollowName(copyVal.name)
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setMySelectedFeeds(val.mySelectedFeeds)
|
this.setMySelectedFeeds(val.mySelectedFeeds)
|
||||||
await new Promise((res)=> {
|
|
||||||
setTimeout(()=> {
|
await new Promise((res) => {
|
||||||
|
setTimeout(() => {
|
||||||
res()
|
res()
|
||||||
},50)
|
}, 50)
|
||||||
})
|
})
|
||||||
this.userSelected = {};
|
|
||||||
|
this.userSelected = {}
|
||||||
this.shadowRoot.getElementById('sendTo').value = ''
|
this.shadowRoot.getElementById('sendTo').value = ''
|
||||||
this.isLoading = false;
|
this.isLoading = false
|
||||||
this.isOpenAddFriendsModal = false
|
this.isOpenAddFriendsModal = false
|
||||||
this.editContent = null
|
this.editContent = null
|
||||||
this.setMyFriends(this.friendList)
|
this.setMyFriends(this.friendList)
|
||||||
if(!isRemove && this.friendList.length === 1){
|
|
||||||
|
if (!isRemove && this.friendList.length === 1) {
|
||||||
this.refreshFeed()
|
this.refreshFeed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setMyFriends(friendList){
|
|
||||||
|
setMyFriends(friendList) {
|
||||||
localStorage.setItem('friends-my-friend-list', JSON.stringify(friendList));
|
localStorage.setItem('friends-my-friend-list', JSON.stringify(friendList));
|
||||||
const tempSettingsData= JSON.parse(localStorage.getItem('temp-settings-data') || "{}")
|
const tempSettingsData = JSON.parse(localStorage.getItem('temp-settings-data') || "{}")
|
||||||
const newTemp = {
|
const newTemp = {
|
||||||
...tempSettingsData,
|
...tempSettingsData,
|
||||||
userLists: {
|
userLists: {
|
||||||
@ -277,18 +351,20 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem('temp-settings-data', JSON.stringify(newTemp));
|
localStorage.setItem('temp-settings-data', JSON.stringify(newTemp))
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('temp-settings-data-event', {
|
new CustomEvent('temp-settings-data-event', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true
|
composed: true
|
||||||
}),
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
setMySelectedFeeds(mySelectedFeeds){
|
|
||||||
|
setMySelectedFeeds(mySelectedFeeds) {
|
||||||
this.mySelectedFeeds = mySelectedFeeds
|
this.mySelectedFeeds = mySelectedFeeds
|
||||||
const tempSettingsData= JSON.parse(localStorage.getItem('temp-settings-data') || "{}")
|
const tempSettingsData = JSON.parse(localStorage.getItem('temp-settings-data') || "{}")
|
||||||
|
|
||||||
const newTemp = {
|
const newTemp = {
|
||||||
...tempSettingsData,
|
...tempSettingsData,
|
||||||
friendsFeed: {
|
friendsFeed: {
|
||||||
@ -297,98 +373,37 @@ class FriendsView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
localStorage.setItem('temp-settings-data', JSON.stringify(newTemp));
|
localStorage.setItem('temp-settings-data', JSON.stringify(newTemp))
|
||||||
localStorage.setItem('friends-my-selected-feeds', JSON.stringify(mySelectedFeeds));
|
localStorage.setItem('friends-my-selected-feeds', JSON.stringify(mySelectedFeeds))
|
||||||
}
|
|
||||||
openEditFriend(val){
|
|
||||||
this.isOpenAddFriendsModal = true
|
|
||||||
this.userSelected = val
|
|
||||||
this.editContent = {...val, mySelectedFeeds: this.mySelectedFeeds}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose(){
|
openEditFriend(val) {
|
||||||
|
this.isOpenAddFriendsModal = true
|
||||||
|
this.userSelected = val
|
||||||
|
this.editContent = { ...val, mySelectedFeeds: this.mySelectedFeeds }
|
||||||
|
}
|
||||||
|
|
||||||
|
onClose() {
|
||||||
this.isLoading = false;
|
this.isLoading = false;
|
||||||
this.isOpenAddFriendsModal = false
|
this.isOpenAddFriendsModal = false
|
||||||
this.editContent = null
|
this.editContent = null
|
||||||
this.userSelected = {}
|
this.userSelected = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
// Standard functions
|
||||||
return html`
|
getApiKey() {
|
||||||
<div class="container">
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
<div id="viewElement" class="container-body" style=${"position: relative"}>
|
return coreNode.apiKey
|
||||||
<p class="group-name">My Friends</p>
|
|
||||||
<div class="search-field">
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
class="name-input"
|
|
||||||
?disabled=${this.isLoading}
|
|
||||||
id="sendTo"
|
|
||||||
placeholder="${translate("friends.friend1")}"
|
|
||||||
value=${this.userSelected.name ? this.userSelected.name: ''}
|
|
||||||
@keypress=${(e) => {
|
|
||||||
if(e.key === 'Enter'){
|
|
||||||
this.userSearch()
|
|
||||||
}
|
}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<vaadin-icon
|
isEmptyArray(arr) {
|
||||||
@click=${this.userSearch}
|
if (!arr) { return true }
|
||||||
slot="icon"
|
return arr.length === 0
|
||||||
icon="vaadin:search"
|
}
|
||||||
class="search-icon">
|
|
||||||
</vaadin-icon>
|
|
||||||
|
|
||||||
</div>
|
round(number) {
|
||||||
<div class="search-results-div">
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
<chat-search-results
|
|
||||||
.onClickFunc=${(result) => {
|
|
||||||
this.userSelected = result;
|
|
||||||
this.isOpenAddFriendsModal = true
|
|
||||||
|
|
||||||
this.userFound = [];
|
|
||||||
this.userFoundModalOpen = false;
|
|
||||||
}}
|
|
||||||
.closeFunc=${() => {
|
|
||||||
this.userFoundModalOpen = false;
|
|
||||||
this.userFound = [];
|
|
||||||
}}
|
|
||||||
.searchResults=${this.userFound}
|
|
||||||
?isOpen=${this.userFoundModalOpen}
|
|
||||||
?loading=${this.isLoading}>
|
|
||||||
</chat-search-results>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
${this.friendList.map((item) => {
|
|
||||||
return html`<chat-side-nav-heads
|
|
||||||
activeChatHeadUrl=""
|
|
||||||
.setActiveChatHeadUrl=${(val) => {
|
|
||||||
|
|
||||||
}}
|
|
||||||
.chatInfo=${item}
|
|
||||||
.openEditFriend=${(val)=> this.openEditFriend(val)}
|
|
||||||
.closeSidePanel=${this.closeSidePanel}
|
|
||||||
></chat-side-nav-heads>`;
|
|
||||||
})}
|
|
||||||
<div id="downObserver"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<add-friends-modal
|
|
||||||
?isOpen=${this.isOpenAddFriendsModal}
|
|
||||||
.setIsOpen=${(val)=> {
|
|
||||||
this.isOpenAddFriendsModal = val
|
|
||||||
}}
|
|
||||||
.userSelected=${this.userSelected}
|
|
||||||
.onSubmit=${(val, isRemove)=> this.addToFriendList(val, isRemove)}
|
|
||||||
.editContent=${this.editContent}
|
|
||||||
.onClose=${()=> this.onClose()}
|
|
||||||
.mySelectedFeeds=${this.mySelectedFeeds}
|
|
||||||
>
|
|
||||||
</add-friends-modal>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('friends-view', FriendsView);
|
window.customElements.define('friends-view', FriendsView)
|
@ -1,14 +1,15 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {get, translate} from '../../../translate'
|
import { connect } from 'pwa-helpers'
|
||||||
import '@material/mwc-button';
|
import { store } from '../../store'
|
||||||
import '@material/mwc-icon';
|
import { parentEpml } from '../show-plugin'
|
||||||
import '@vaadin/tooltip';
|
import { get, translate } from '../../../translate'
|
||||||
import '@material/mwc-dialog';
|
import { profileModalUpdateStyles } from '../../styles/core-css'
|
||||||
import '@material/mwc-checkbox';
|
import '@material/mwc-button'
|
||||||
import {connect} from 'pwa-helpers';
|
import '@material/mwc-checkbox'
|
||||||
import {store} from '../../store';
|
import '@material/mwc-dialog'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import '@material/mwc-icon'
|
||||||
import {parentEpml} from '../show-plugin';
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
|
import '@vaadin/tooltip'
|
||||||
|
|
||||||
class ProfileModalUpdate extends connect(store)(LitElement) {
|
class ProfileModalUpdate extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -25,418 +26,55 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
hasFetchedArrr: { type: Boolean },
|
hasFetchedArrr: { type: Boolean },
|
||||||
isOpenCustomDataModal: { type: Boolean },
|
isOpenCustomDataModal: { type: Boolean },
|
||||||
customData: { type: Object },
|
customData: { type: Object },
|
||||||
newCustomDataField: {type: Object},
|
newCustomDataField: { type: Object },
|
||||||
newFieldName: {type: String},
|
newFieldName: { type: String },
|
||||||
qortalRequestCustomData: {type: Object},
|
qortalRequestCustomData: { type: Object },
|
||||||
newCustomDataKey: {type: String},
|
newCustomDataKey: { type: String },
|
||||||
newCustomDataValue: {type: String},
|
newCustomDataValue: { type: String },
|
||||||
isSaving: {type: Boolean}
|
isSaving: { type: Boolean }
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [profileModalUpdateStyles]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.isOpen = false;
|
this.isOpen = false
|
||||||
this.isLoading = false;
|
this.isLoading = false
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.myNode = this.getMyNode();
|
this.myNode = this.getMyNode()
|
||||||
this.tagline = '';
|
this.tagline = ''
|
||||||
this.bio = '';
|
this.bio = ''
|
||||||
this.walletList = ['btc', 'ltc', 'doge', 'dgb', 'rvn', 'arrr'];
|
this.walletList = ['btc', 'ltc', 'doge', 'dgb', 'rvn', 'arrr']
|
||||||
let wallets = {};
|
let wallets = {}
|
||||||
this.walletList.forEach((item) => {
|
this.walletList.forEach((item) => {
|
||||||
wallets[item] = '';
|
wallets[item] = ''
|
||||||
});
|
|
||||||
this.wallets = wallets;
|
|
||||||
this.walletsUi = new Map();
|
|
||||||
let coinProp = {
|
|
||||||
wallet: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.walletList.forEach((c, i) => {
|
|
||||||
this.walletsUi.set(c, { ...coinProp });
|
|
||||||
});
|
|
||||||
this.walletsUi.get('btc').wallet =
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.btcWallet;
|
|
||||||
this.walletsUi.get('ltc').wallet =
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.ltcWallet;
|
|
||||||
this.walletsUi.get('doge').wallet =
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.dogeWallet;
|
|
||||||
this.walletsUi.get('dgb').wallet =
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.dgbWallet;
|
|
||||||
this.walletsUi.get('rvn').wallet =
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress.rvnWallet;
|
|
||||||
this.hasFetchedArrr = false;
|
|
||||||
this.isOpenCustomDataModal = false;
|
|
||||||
this.customData = {};
|
|
||||||
this.newCustomDataKey = "";
|
|
||||||
this.newCustomDataValue = "";
|
|
||||||
this.newCustomDataField = {};
|
|
||||||
this.newFieldName = '';
|
|
||||||
this.isSaving = false;
|
|
||||||
this.addPrivate = this.addPrivate.bind(this);
|
|
||||||
this.checkForPrivate = this.checkForPrivate.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-dialog-min-width: 400px;
|
|
||||||
--mdc-dialog-max-width: 1024px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.input {
|
|
||||||
width: 90%;
|
|
||||||
outline: 0;
|
|
||||||
border-width: 0 0 2px;
|
|
||||||
border-color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
color: var(--chat-bubble-msg-color);
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.input::selection {
|
|
||||||
background-color: var(--mdc-theme-primary);
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input::placeholder {
|
|
||||||
opacity: 0.6;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button-red {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #f44336;
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button-red:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #f4433663;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-button:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
background-color: #03a8f475;
|
|
||||||
}
|
|
||||||
.checkbox-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
.modal-overlay {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100vw;
|
|
||||||
height: 100vh;
|
|
||||||
background-color: rgba(
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
0.5
|
|
||||||
); /* Semi-transparent backdrop */
|
|
||||||
z-index: 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-content {
|
|
||||||
position: fixed;
|
|
||||||
top: 50vh;
|
|
||||||
left: 50vw;
|
|
||||||
transform: translate(-50%, -50%);
|
|
||||||
background-color: var(--mdc-theme-surface);
|
|
||||||
width: 80vw;
|
|
||||||
padding: 20px;
|
|
||||||
box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;
|
|
||||||
z-index: 1001;
|
|
||||||
border-radius: 5px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.modal-overlay.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar {
|
|
||||||
width: 36px;
|
|
||||||
height: 36px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.app-name {
|
|
||||||
display: flex;
|
|
||||||
gap: 20px;
|
|
||||||
align-items: center;
|
|
||||||
width: 100%;
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.inner-content {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
max-height: 75vh;
|
|
||||||
flex-grow: 1;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar-track {
|
|
||||||
background-color: whitesmoke;
|
|
||||||
border-radius: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar {
|
|
||||||
width: 12px;
|
|
||||||
border-radius: 7px;
|
|
||||||
background-color: whitesmoke;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inner-content::-webkit-scrollbar-thumb {
|
|
||||||
background-color: rgb(180, 176, 176);
|
|
||||||
border-radius: 7px;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
async updated(changedProperties) {
|
|
||||||
if (
|
|
||||||
changedProperties &&
|
|
||||||
changedProperties.has('editContent') &&
|
|
||||||
this.editContent
|
|
||||||
) {
|
|
||||||
const {bio, tagline, wallets, customData} = this.editContent
|
|
||||||
this.bio = bio ?? '';
|
|
||||||
this.tagline = tagline ?? '';
|
|
||||||
let formWallets = {...this.wallets}
|
|
||||||
if(wallets && Object.keys(wallets).length){
|
|
||||||
Object.keys(formWallets).forEach((key)=> {
|
|
||||||
if(wallets[key]){
|
|
||||||
formWallets[key] = wallets[key]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
this.wallets = wallets
|
||||||
|
this.walletsUi = new Map()
|
||||||
|
let coinProp = {
|
||||||
|
wallet: null
|
||||||
}
|
}
|
||||||
this.wallets = formWallets
|
this.walletList.forEach((c, i) => {
|
||||||
|
this.walletsUi.set(c, { ...coinProp })
|
||||||
this.customData = {...customData}
|
})
|
||||||
this.requestUpdate();
|
this.walletsUi.get('btc').wallet = store.getState().app.selectedAddress.btcWallet
|
||||||
}
|
this.walletsUi.get('ltc').wallet = store.getState().app.selectedAddress.ltcWallet
|
||||||
if (
|
this.walletsUi.get('doge').wallet = store.getState().app.selectedAddress.dogeWallet
|
||||||
changedProperties &&
|
this.walletsUi.get('dgb').wallet = store.getState().app.selectedAddress.dgbWallet
|
||||||
changedProperties.has('qortalRequestCustomData') &&
|
this.walletsUi.get('rvn').wallet = store.getState().app.selectedAddress.rvnWallet
|
||||||
this.qortalRequestCustomData
|
this.hasFetchedArrr = false
|
||||||
) {
|
this.isOpenCustomDataModal = false
|
||||||
this.isOpenCustomDataModal = true
|
this.customData = {}
|
||||||
this.newCustomDataField = {...this.qortalRequestCustomData.payload.customData}
|
|
||||||
this.newCustomDataKey = this.qortalRequestCustomData.property
|
|
||||||
this.requestUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
async firstUpdated() {
|
|
||||||
try {
|
|
||||||
await this.fetchWalletAddress('arrr');
|
|
||||||
} catch (error) {
|
|
||||||
console.log({ error });
|
|
||||||
} finally {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchWalletAddress(coin) {
|
|
||||||
switch (coin) {
|
|
||||||
case 'arrr':
|
|
||||||
const arrrWalletName = `${coin}Wallet`;
|
|
||||||
|
|
||||||
let res = await parentEpml.request('apiCall', {
|
|
||||||
url: `/crosschain/${coin}/walletaddress?apiKey=${this.myNode.apiKey}`,
|
|
||||||
method: 'POST',
|
|
||||||
body: `${
|
|
||||||
window.parent.reduxStore.getState().app.selectedAddress[
|
|
||||||
arrrWalletName
|
|
||||||
].seed58
|
|
||||||
}`,
|
|
||||||
});
|
|
||||||
if (res != null && res.error != 1201 && res.length === 78) {
|
|
||||||
this.arrrWalletAddress = res;
|
|
||||||
this.hasFetchedArrr = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Not used for other coins yet
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getSelectedWalletAddress(wallet) {
|
|
||||||
switch (wallet) {
|
|
||||||
case 'arrr':
|
|
||||||
if(!this.arrrWalletAddress){
|
|
||||||
try {
|
|
||||||
await this.fetchWalletAddress('arrr');
|
|
||||||
} catch (error) {
|
|
||||||
console.log({error})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Use address returned by core API
|
|
||||||
return this.arrrWalletAddress;
|
|
||||||
|
|
||||||
default:
|
|
||||||
// Use locally derived address
|
|
||||||
return this.walletsUi.get(wallet).wallet.address;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
clearFields() {
|
|
||||||
this.bio = '';
|
|
||||||
this.tagline = '';
|
|
||||||
}
|
|
||||||
|
|
||||||
async fillAddress(coin) {
|
|
||||||
const address = await this.getSelectedWalletAddress(coin);
|
|
||||||
if (address) {
|
|
||||||
this.wallets = {
|
|
||||||
...this.wallets,
|
|
||||||
[coin]: address,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveProfile() {
|
|
||||||
try {
|
|
||||||
const data = {
|
|
||||||
version: 1,
|
|
||||||
tagline: this.tagline,
|
|
||||||
bio: this.bio,
|
|
||||||
wallets: this.wallets,
|
|
||||||
customData: this.customData
|
|
||||||
};
|
|
||||||
this.isSaving = true
|
|
||||||
await this.onSubmit(data);
|
|
||||||
this.setIsOpen(false);
|
|
||||||
this.clearFields();
|
|
||||||
this.onClose('success');
|
|
||||||
} catch (error) {} finally {
|
|
||||||
this.isSaving = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
removeField(key){
|
|
||||||
const copyObj = {...this.newCustomDataField}
|
|
||||||
delete copyObj[key]
|
|
||||||
this.newCustomDataField = copyObj
|
|
||||||
}
|
|
||||||
|
|
||||||
addField(){
|
|
||||||
if (!this.newFieldName || !this.newCustomDataValue) {
|
|
||||||
let snack5string = get("profile.profile24");
|
|
||||||
parentEpml.request('showSnackBar', `${snack5string}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const copyObj = {...this.newCustomDataField}
|
|
||||||
copyObj[this.newFieldName] = this.newCustomDataValue
|
|
||||||
this.newCustomDataField = copyObj
|
|
||||||
this.newFieldName = ""
|
|
||||||
this.newCustomDataValue = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
addCustomData(){
|
|
||||||
const copyObj = {...this.customData}
|
|
||||||
copyObj[this.newCustomDataKey] = this.newCustomDataField
|
|
||||||
this.customData = copyObj
|
|
||||||
this.newCustomDataKey = ""
|
this.newCustomDataKey = ""
|
||||||
this.newCustomDataField = {};
|
this.newCustomDataValue = ""
|
||||||
|
this.newCustomDataField = {}
|
||||||
this.newFieldName = ''
|
this.newFieldName = ''
|
||||||
this.newCustomDataValue = ''
|
this.isSaving = false
|
||||||
this.isOpenCustomDataModal = false;
|
this.addPrivate = this.addPrivate.bind(this)
|
||||||
}
|
this.checkForPrivate = this.checkForPrivate.bind(this)
|
||||||
|
|
||||||
updateCustomData(key, data){
|
|
||||||
this.isOpenCustomDataModal = true
|
|
||||||
this.newCustomDataField = data
|
|
||||||
this.newCustomDataKey = key
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
removeCustomData(key){
|
|
||||||
const copyObj = {...this.customData}
|
|
||||||
delete copyObj[key]
|
|
||||||
this.customData = copyObj
|
|
||||||
}
|
|
||||||
|
|
||||||
checkForPrivate(){
|
|
||||||
let isPrivate = false
|
|
||||||
if(this.newCustomDataKey.includes('-private')) isPrivate = true
|
|
||||||
return isPrivate
|
|
||||||
}
|
|
||||||
|
|
||||||
addPrivate(e){
|
|
||||||
if (e.target.checked) {
|
|
||||||
if(this.newCustomDataKey.includes('-private')){
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.newCustomDataKey = this.newCustomDataKey + '-private'
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.newCustomDataKey = this.newCustomDataKey.replace('-private', '');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -491,9 +129,7 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
<div style="display: flex;flex-direction: column;">
|
<div style="display: flex;flex-direction: column;">
|
||||||
${Object.keys(this.wallets).map((key) => {
|
${Object.keys(this.wallets).map((key) => {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div style="display:flex;justify-content:center;flex-direction:column">
|
||||||
style="display:flex;justify-content:center;flex-direction:column"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
for=${key}
|
for=${key}
|
||||||
id="taglineLabel"
|
id="taglineLabel"
|
||||||
@ -501,9 +137,7 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
>
|
>
|
||||||
${key}
|
${key}
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div style="display:flex;gap:15px;align-items:center">
|
||||||
style="display:flex;gap:15px;align-items:center"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
id=${key}
|
id=${key}
|
||||||
placeholder=${key + ' ' + get('settings.address')}
|
placeholder=${key + ' ' + get('settings.address')}
|
||||||
@ -516,65 +150,51 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
id=${`${key}-upload`}
|
id=${`${key}-upload`}
|
||||||
@click=${() =>
|
@click=${() =>
|
||||||
this.fillAddress(key)}
|
this.fillAddress(key)}
|
||||||
style="color:var(--black);cursor:pointer"
|
style="color:var(--black);cursor:pointer"
|
||||||
>upload_2</mwc-icon
|
|
||||||
>
|
>
|
||||||
|
upload_2
|
||||||
|
</mwc-icon>
|
||||||
<vaadin-tooltip
|
<vaadin-tooltip
|
||||||
for=${`${key}-upload`}
|
for=${`${key}-upload`}
|
||||||
position="bottom"
|
position="bottom"
|
||||||
hover-delay=${200}
|
hover-delay=${200}
|
||||||
hide-delay=${1}
|
hide-delay=${1}
|
||||||
text=${translate('profile.profile21')}
|
text=${translate('profile.profile21')}
|
||||||
>
|
></vaadin-tooltip>
|
||||||
</vaadin-tooltip>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div style="display: flex;flex-direction: column;">
|
<div style="display: flex;flex-direction: column;">
|
||||||
${Object.keys(this.customData).map((key) => {
|
${Object.keys(this.customData).map((key) => {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div style="display:flex;justify-content:center;flex-direction:column;gap:25px">
|
||||||
style="display:flex;justify-content:center;flex-direction:column;gap:25px"
|
<div style="display:flex;gap:15px;align-items:center">
|
||||||
>
|
<p style="color: var(--black);font-size:16px">${key}</p>
|
||||||
|
|
||||||
<div
|
|
||||||
style="display:flex;gap:15px;align-items:center"
|
|
||||||
>
|
|
||||||
<p
|
|
||||||
|
|
||||||
style="color: var(--black);font-size:16px"
|
|
||||||
>
|
|
||||||
${key}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
@click=${() =>
|
@click=${() => this.updateCustomData(key, this.customData[key])}
|
||||||
this.updateCustomData(key,this.customData[key])}
|
|
||||||
style="color:var(--black);cursor:pointer"
|
style="color:var(--black);cursor:pointer"
|
||||||
>edit</mwc-icon
|
|
||||||
>
|
>
|
||||||
|
edit
|
||||||
|
</mwc-icon>
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
@click=${() =>
|
@click=${() => this.removeCustomData(key)}
|
||||||
this.removeCustomData(key)}
|
|
||||||
style="color:var(--black);cursor:pointer"
|
style="color:var(--black);cursor:pointer"
|
||||||
>remove</mwc-icon
|
|
||||||
>
|
>
|
||||||
|
remove
|
||||||
|
</mwc-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:20px">
|
||||||
style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="modal-button-red"
|
class="modal-button-red"
|
||||||
?disabled="${this.isLoading}"
|
?disabled="${this.isLoading}"
|
||||||
@ -586,9 +206,7 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
>
|
>
|
||||||
${translate('general.close')}
|
${translate('general.close')}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div style="display:flex;gap:10px;align-items:center">
|
<div style="display:flex;gap:10px;align-items:center">
|
||||||
|
|
||||||
<button
|
<button
|
||||||
?disabled="${this.isLoading}"
|
?disabled="${this.isLoading}"
|
||||||
class="modal-button"
|
class="modal-button"
|
||||||
@ -602,20 +220,19 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
?disabled="${this.isLoading}"
|
?disabled="${this.isLoading}"
|
||||||
class="modal-button"
|
class="modal-button"
|
||||||
@click=${() => {
|
@click=${() => {
|
||||||
if(this.isSaving) return
|
if (this.isSaving) return
|
||||||
this.saveProfile();
|
this.saveProfile();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
${this.isSaving ? html`
|
${this.isSaving ? html`
|
||||||
<paper-spinner-lite active></paper-spinner-lite>
|
<paper-spinner-lite active></paper-spinner-lite>
|
||||||
` : ''}
|
` : ''}
|
||||||
${this.isSaving ? '' : translate('profile.profile3') }
|
${this.isSaving ? '' : translate('profile.profile3')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- add custom vars -->
|
<!-- add custom vars -->
|
||||||
<div
|
<div
|
||||||
class="modal-overlay ${this.isOpenCustomDataModal
|
class="modal-overlay ${this.isOpenCustomDataModal
|
||||||
@ -627,17 +244,12 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
<div class="inner-content">
|
<div class="inner-content">
|
||||||
<div style="display:flex; justify-content:flex-end">
|
<div style="display:flex; justify-content:flex-end">
|
||||||
<div class="checkbox-row" style="font-size:16px">
|
<div class="checkbox-row" style="font-size:16px">
|
||||||
<label for="isPrivate" style="color: var(--black);">
|
<label for="isPrivate" style="color: var(--black);">${get('profile.profile23')}</label>
|
||||||
${get('profile.profile23')}
|
<mwc-checkbox id="isPrivate" @change=${(e) => this.addPrivate(e)} ?checked=${this.checkForPrivate()}></mwc-checkbox>
|
||||||
</label>
|
|
||||||
<mwc-checkbox id="isPrivate" @change=${(e) => this.addPrivate(e)} ?checked=${this.checkForPrivate()}>
|
|
||||||
</mwc-checkbox>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="height:15px"></div>
|
<div style="height:15px"></div>
|
||||||
<div
|
<div style="display:flex;justify-content:center;flex-direction:column">
|
||||||
style="display:flex;justify-content:center;flex-direction:column"
|
|
||||||
>
|
|
||||||
<label
|
<label
|
||||||
for="key-name"
|
for="key-name"
|
||||||
id="taglineLabel"
|
id="taglineLabel"
|
||||||
@ -645,9 +257,7 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
>
|
>
|
||||||
${translate('profile.profile9')}
|
${translate('profile.profile9')}
|
||||||
</label>
|
</label>
|
||||||
<div
|
<div style="display:flex;gap:15px;align-items:center">
|
||||||
style="display:flex;gap:15px;align-items:center"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
id="key-name"
|
id="key-name"
|
||||||
placeholder=${translate(
|
placeholder=${translate(
|
||||||
@ -668,19 +278,9 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
<div style="display: flex;flex-direction: column;">
|
<div style="display: flex;flex-direction: column;">
|
||||||
${Object.keys(this.newCustomDataField).map((key) => {
|
${Object.keys(this.newCustomDataField).map((key) => {
|
||||||
return html`
|
return html`
|
||||||
<div
|
<div style="display:flex;justify-content:center;flex-direction:column">
|
||||||
style="display:flex;justify-content:center;flex-direction:column"
|
<label for=${key} id="taglineLabel" style="color: var(--black);font-size:16px">${key}</label>
|
||||||
>
|
<div style="display:flex;gap:15px;align-items:center">
|
||||||
<label
|
|
||||||
for=${key}
|
|
||||||
id="taglineLabel"
|
|
||||||
style="color: var(--black);font-size:16px"
|
|
||||||
>
|
|
||||||
${key}
|
|
||||||
</label>
|
|
||||||
<div
|
|
||||||
style="display:flex;gap:15px;align-items:center"
|
|
||||||
>
|
|
||||||
<input
|
<input
|
||||||
id=${key}
|
id=${key}
|
||||||
placeholder=${translate('profile.profile13')}
|
placeholder=${translate('profile.profile13')}
|
||||||
@ -693,16 +293,15 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
};
|
};
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<mwc-icon
|
<mwc-icon
|
||||||
@click=${() =>
|
@click=${() => this.removeField(key)}
|
||||||
this.removeField(key)}
|
|
||||||
style="color:var(--black);cursor:pointer"
|
style="color:var(--black);cursor:pointer"
|
||||||
>remove</mwc-icon
|
|
||||||
>
|
>
|
||||||
|
remove
|
||||||
|
</mwc-icon>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div style=${`display: flex; flex-direction: row; align-items: center;justify-content:space-between; ${Object.keys(this.newCustomDataField).length ? "margin-top: 10px" : ""}`}>
|
<div style=${`display: flex; flex-direction: row; align-items: center;justify-content:space-between; ${Object.keys(this.newCustomDataField).length ? "margin-top: 10px" : ""}`}>
|
||||||
@ -736,9 +335,7 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-top:20px">
|
||||||
style="display:flex;justify-content:space-between;align-items:center;margin-top:20px"
|
|
||||||
>
|
|
||||||
<button
|
<button
|
||||||
class="modal-button-red"
|
class="modal-button-red"
|
||||||
?disabled="${this.isLoading}"
|
?disabled="${this.isLoading}"
|
||||||
@ -750,7 +347,6 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
>
|
>
|
||||||
${translate('general.close')}
|
${translate('general.close')}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
?disabled="${this.isSaving}"
|
?disabled="${this.isSaving}"
|
||||||
class="modal-button"
|
class="modal-button"
|
||||||
@ -763,8 +359,204 @@ class ProfileModalUpdate extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async firstUpdated() {
|
||||||
|
try {
|
||||||
|
await this.fetchWalletAddress('arrr')
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error })
|
||||||
|
} finally {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async updated(changedProperties) {
|
||||||
|
if (changedProperties && changedProperties.has('editContent') && this.editContent) {
|
||||||
|
const { bio, tagline, wallets, customData } = this.editContent
|
||||||
|
this.bio = bio ?? ''
|
||||||
|
this.tagline = tagline ?? ''
|
||||||
|
let formWallets = { ...this.wallets }
|
||||||
|
if (wallets && Object.keys(wallets).length) {
|
||||||
|
Object.keys(formWallets).forEach((key) => {
|
||||||
|
if (wallets[key]) {
|
||||||
|
formWallets[key] = wallets[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
this.wallets = formWallets
|
||||||
|
|
||||||
|
this.customData = { ...customData }
|
||||||
|
this.requestUpdate();
|
||||||
|
}
|
||||||
|
if (changedProperties && changedProperties.has('qortalRequestCustomData') && this.qortalRequestCustomData) {
|
||||||
|
this.isOpenCustomDataModal = true
|
||||||
|
this.newCustomDataField = { ...this.qortalRequestCustomData.payload.customData }
|
||||||
|
this.newCustomDataKey = this.qortalRequestCustomData.property
|
||||||
|
this.requestUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetchWalletAddress(coin) {
|
||||||
|
switch (coin) {
|
||||||
|
case 'arrr':
|
||||||
|
const arrrWalletName = `${coin}Wallet`;
|
||||||
|
|
||||||
|
let res = await parentEpml.request('apiCall', {
|
||||||
|
url: `/crosschain/${coin}/walletaddress?apiKey=${this.myNode.apiKey}`,
|
||||||
|
method: 'POST',
|
||||||
|
body: `${store.getState().app.selectedAddress[arrrWalletName].seed58}`
|
||||||
|
})
|
||||||
|
if (res != null && res.error != 1201 && res.length === 78) {
|
||||||
|
this.arrrWalletAddress = res
|
||||||
|
this.hasFetchedArrr = true
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Not used for other coins yet
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async getSelectedWalletAddress(wallet) {
|
||||||
|
switch (wallet) {
|
||||||
|
case 'arrr':
|
||||||
|
if (!this.arrrWalletAddress) {
|
||||||
|
try {
|
||||||
|
await this.fetchWalletAddress('arrr')
|
||||||
|
} catch (error) {
|
||||||
|
console.log({ error })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Use address returned by core API
|
||||||
|
return this.arrrWalletAddress
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Use locally derived address
|
||||||
|
return this.walletsUi.get(wallet).wallet.address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getNodeUrl() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
}
|
||||||
|
|
||||||
|
getMyNode() {
|
||||||
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
}
|
||||||
|
|
||||||
|
clearFields() {
|
||||||
|
this.bio = ''
|
||||||
|
this.tagline = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
async fillAddress(coin) {
|
||||||
|
const address = await this.getSelectedWalletAddress(coin)
|
||||||
|
|
||||||
|
if (address) {
|
||||||
|
this.wallets = {
|
||||||
|
...this.wallets,
|
||||||
|
[coin]: address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async saveProfile() {
|
||||||
|
try {
|
||||||
|
const data = {
|
||||||
|
version: 1,
|
||||||
|
tagline: this.tagline,
|
||||||
|
bio: this.bio,
|
||||||
|
wallets: this.wallets,
|
||||||
|
customData: this.customData
|
||||||
|
}
|
||||||
|
this.isSaving = true
|
||||||
|
await this.onSubmit(data)
|
||||||
|
this.setIsOpen(false)
|
||||||
|
this.clearFields()
|
||||||
|
this.onClose('success')
|
||||||
|
} catch (error) { } finally {
|
||||||
|
this.isSaving = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
removeField(key) {
|
||||||
|
const copyObj = { ...this.newCustomDataField }
|
||||||
|
delete copyObj[key]
|
||||||
|
this.newCustomDataField = copyObj
|
||||||
|
}
|
||||||
|
|
||||||
|
addField() {
|
||||||
|
if (!this.newFieldName || !this.newCustomDataValue) {
|
||||||
|
let snack5string = get("profile.profile24")
|
||||||
|
parentEpml.request('showSnackBar', `${snack5string}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const copyObj = { ...this.newCustomDataField }
|
||||||
|
copyObj[this.newFieldName] = this.newCustomDataValue
|
||||||
|
this.newCustomDataField = copyObj
|
||||||
|
this.newFieldName = ''
|
||||||
|
this.newCustomDataValue = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
addCustomData() {
|
||||||
|
const copyObj = { ...this.customData }
|
||||||
|
copyObj[this.newCustomDataKey] = this.newCustomDataField
|
||||||
|
this.customData = copyObj
|
||||||
|
this.newCustomDataKey = ''
|
||||||
|
this.newCustomDataField = {}
|
||||||
|
this.newFieldName = ''
|
||||||
|
this.newCustomDataValue = ''
|
||||||
|
this.isOpenCustomDataModal = false
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCustomData(key, data) {
|
||||||
|
this.isOpenCustomDataModal = true
|
||||||
|
this.newCustomDataField = data
|
||||||
|
this.newCustomDataKey = key
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
removeCustomData(key) {
|
||||||
|
const copyObj = { ...this.customData }
|
||||||
|
delete copyObj[key]
|
||||||
|
this.customData = copyObj
|
||||||
|
}
|
||||||
|
|
||||||
|
checkForPrivate() {
|
||||||
|
let isPrivate = false
|
||||||
|
if (this.newCustomDataKey.includes('-private')) isPrivate = true
|
||||||
|
return isPrivate
|
||||||
|
}
|
||||||
|
|
||||||
|
addPrivate(e) {
|
||||||
|
if (e.target.checked) {
|
||||||
|
if (this.newCustomDataKey.includes('-private')) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
this.newCustomDataKey = this.newCustomDataKey + '-private'
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.newCustomDataKey = this.newCustomDataKey.replace('-private', '')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Standard functions
|
||||||
|
getApiKey() {
|
||||||
|
const coreNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return coreNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
isEmptyArray(arr) {
|
||||||
|
if (!arr) { return true }
|
||||||
|
return arr.length === 0
|
||||||
|
}
|
||||||
|
|
||||||
|
round(number) {
|
||||||
|
return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('profile-modal-update', ProfileModalUpdate);
|
window.customElements.define('profile-modal-update', ProfileModalUpdate)
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,8 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {registerTranslateConfig, translate, use} from '../../translate'
|
import { languageSelectorStyles } from '../styles/core-css'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { registerTranslateConfig, translate, use } from '../../translate'
|
||||||
|
|
||||||
registerTranslateConfig({
|
registerTranslateConfig({
|
||||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
@ -22,47 +25,7 @@ class LanguageSelector extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [languageSelectorStyles]
|
||||||
css`
|
|
||||||
select {
|
|
||||||
width: 175px;
|
|
||||||
height: 34px;
|
|
||||||
padding: 5px 0px 5px 5px;
|
|
||||||
font-size: 16px;
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 3px;
|
|
||||||
color: var(--black);
|
|
||||||
background:
|
|
||||||
linear-gradient(45deg, transparent 50%, white 50%),
|
|
||||||
linear-gradient(135deg, white 50%, transparent 50%),
|
|
||||||
linear-gradient(to right, #03a9f4, #03a9f4);
|
|
||||||
background-position:
|
|
||||||
calc(100% - 17px) calc(0.5em + 4px),
|
|
||||||
calc(100% - 7px) calc(0.5em + 4px),
|
|
||||||
100% 0;
|
|
||||||
background-size:
|
|
||||||
10px 10px,
|
|
||||||
10px 10px,
|
|
||||||
2.2em 2.2em;
|
|
||||||
background-repeat: no-repeat;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
-webkit-appearance:none;
|
|
||||||
-moz-appearance:none;
|
|
||||||
}
|
|
||||||
|
|
||||||
*:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
select option {
|
|
||||||
color: var(--black);
|
|
||||||
background: var(--white);
|
|
||||||
line-height: 34px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -103,7 +66,7 @@ class LanguageSelector extends LitElement {
|
|||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
const myElement = this.shadowRoot.getElementById('languageSelect')
|
const myElement = this.shadowRoot.getElementById('languageSelect')
|
||||||
|
|
||||||
myElement.addEventListener("change", () => {
|
myElement.addEventListener('change', () => {
|
||||||
this.selectElement()
|
this.selectElement()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,29 +1,31 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {get, translate} from '../../../translate'
|
import { createWallet } from '../../../../crypto/api/createWallet'
|
||||||
|
import { doLogin, doLogout, doSelectAddress } from '../../redux/app/app-actions'
|
||||||
import {createWallet} from '../../../../crypto/api/createWallet.js'
|
import { doStoreWallet } from '../../redux/user/user-actions'
|
||||||
import {doLogin, doLogout, doSelectAddress} from '../../redux/app/app-actions.js'
|
import { checkApiKey } from '../../apiKeyUtils'
|
||||||
import {doStoreWallet} from '../../redux/user/user-actions.js'
|
import { createAccountSectionStyles } from '../../styles/core-css'
|
||||||
import {checkApiKey} from '../../apiKeyUtils.js'
|
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
import ripple from '../../functional-components/loading-ripple.js'
|
import ripple from '../../functional-components/loading-ripple'
|
||||||
import snackbar from '../../functional-components/snackbar.js'
|
import snackbar from '../../functional-components/snackbar'
|
||||||
import '../../functional-components/random-sentence-generator.js'
|
import '../../functional-components/random-sentence-generator'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-checkbox'
|
import '@material/mwc-checkbox'
|
||||||
import '@material/mwc-textfield'
|
|
||||||
import '@material/mwc-icon'
|
|
||||||
import '@material/mwc-dialog'
|
import '@material/mwc-dialog'
|
||||||
import '@material/mwc-formfield'
|
import '@material/mwc-formfield'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import '@material/mwc-textfield'
|
||||||
import '@polymer/iron-pages'
|
import '@polymer/iron-pages'
|
||||||
import '@polymer/paper-button/paper-button.js'
|
import '@polymer/paper-button/paper-button.js'
|
||||||
import '@polymer/paper-input/paper-input-container.js'
|
import '@polymer/paper-input/paper-input-container.js'
|
||||||
import '@polymer/paper-input/paper-input.js'
|
import '@polymer/paper-input/paper-input.js'
|
||||||
import '@polymer/paper-tooltip/paper-tooltip.js'
|
import '@polymer/paper-tooltip/paper-tooltip.js'
|
||||||
import '@vaadin/text-field/vaadin-text-field.js'
|
|
||||||
import '@vaadin/password-field/vaadin-password-field.js'
|
import '@vaadin/password-field/vaadin-password-field.js'
|
||||||
|
import '@vaadin/text-field/vaadin-text-field.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
let lastPassword = ''
|
let lastPassword = ''
|
||||||
|
|
||||||
@ -54,32 +56,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [createAccountSectionStyles]
|
||||||
css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-primary: var(--login-button);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--paper-input-container-focus-color: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-checkbox-unchecked-color: var(--black);
|
|
||||||
--lumo-primary-text-color: var(--login-border);
|
|
||||||
--lumo-primary-color-50pct: var(--login-border-50pct);
|
|
||||||
--lumo-primary-color-10pct: var(--login-border-10pct);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
--_lumo-grid-border-color: var(--border);
|
|
||||||
--_lumo-grid-secondary-border-color: var(--border2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
--mdc-theme-primary: red;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -116,44 +93,54 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
next: e => {
|
next: e => {
|
||||||
// Create account and login :)
|
// Create account and login :)
|
||||||
this.createAccountLoading = true
|
this.createAccountLoading = true
|
||||||
|
|
||||||
const nameInput = this.shadowRoot.getElementById('nameInput').value
|
const nameInput = this.shadowRoot.getElementById('nameInput').value
|
||||||
const password = this.shadowRoot.getElementById('password').value
|
const password = this.shadowRoot.getElementById('password').value
|
||||||
const rePassword = this.shadowRoot.getElementById('rePassword').value
|
const rePassword = this.shadowRoot.getElementById('rePassword').value
|
||||||
|
|
||||||
if (password === '') {
|
if (password === '') {
|
||||||
let snackbar1string = get("login.pleaseenter")
|
let snackbar1string = get("login.pleaseenter")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar1string}`,
|
labelText: `${snackbar1string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password != rePassword) {
|
if (password != rePassword) {
|
||||||
let snackbar2string = get("login.notmatch")
|
let snackbar2string = get("login.notmatch")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar2string}`,
|
labelText: `${snackbar2string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length < 8 && lastPassword !== password) {
|
if (password.length < 8 && lastPassword !== password) {
|
||||||
let snackbar3string = get("login.lessthen8")
|
let snackbar3string = get("login.lessthen8")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar3string}`,
|
labelText: `${snackbar3string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
lastPassword = password
|
lastPassword = password
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.saveAccount === true && nameInput === '') {
|
if (this.saveAccount === true && nameInput === '') {
|
||||||
let snackbar4string = get("login.entername")
|
let snackbar4string = get("login.entername")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar4string}`,
|
labelText: `${snackbar4string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,32 +148,31 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
this._pass = password
|
this._pass = password
|
||||||
|
|
||||||
let seedObj = {}
|
let seedObj = {}
|
||||||
|
|
||||||
const seedPhrase = this.shadowRoot.getElementById('randSentence').parsedString
|
const seedPhrase = this.shadowRoot.getElementById('randSentence').parsedString
|
||||||
|
|
||||||
seedObj = { seedPhrase: seedPhrase }
|
seedObj = { seedPhrase: seedPhrase }
|
||||||
|
|
||||||
ripple.welcomeMessage = welcomeMessage
|
ripple.welcomeMessage = welcomeMessage
|
||||||
ripple.open({
|
|
||||||
x: e.clientX,
|
ripple.open({ x: e.clientX, y: e.clientY }).then(() => createWallet('phrase', seedObj, status => {
|
||||||
y: e.clientY
|
|
||||||
})
|
|
||||||
.then(() => createWallet('phrase', seedObj, status => {
|
|
||||||
ripple.loadingMessage = status
|
ripple.loadingMessage = status
|
||||||
}))
|
})).then(wallet => {
|
||||||
.then(wallet => {
|
|
||||||
this._wallet = wallet
|
this._wallet = wallet
|
||||||
return ripple.fade()
|
return ripple.fade()
|
||||||
})
|
}).then(() => {
|
||||||
.then(() => {
|
|
||||||
this.selectPage('backup')
|
this.selectPage('backup')
|
||||||
this.updateNext()
|
this.updateNext()
|
||||||
})
|
}).catch(e => {
|
||||||
.catch(e => {
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: e,
|
labelText: e,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
console.error('== Error == \n', e)
|
console.error('== Error == \n', e)
|
||||||
|
|
||||||
store.dispatch(doLogout())
|
store.dispatch(doLogout())
|
||||||
|
|
||||||
ripple.close()
|
ripple.close()
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
@ -199,6 +185,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
next: e => {
|
next: e => {
|
||||||
if (!this.isDownloadedBackup) {
|
if (!this.isDownloadedBackup) {
|
||||||
let snackbar5string = get("login.downloaded")
|
let snackbar5string = get("login.downloaded")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar5string}`,
|
labelText: `${snackbar5string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -206,29 +193,28 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
} else {
|
} else {
|
||||||
if (this.saveAccount) {
|
if (this.saveAccount) {
|
||||||
ripple.welcomeMessage = this.renderPrepareText()
|
ripple.welcomeMessage = this.renderPrepareText()
|
||||||
ripple.open({
|
|
||||||
x: e.clientX,
|
ripple.open({ x: e.clientX, y: e.clientY}).then(() => {
|
||||||
y: e.clientY
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
store.dispatch(doStoreWallet(this._wallet, this._pass, this._name, () => {
|
store.dispatch(doStoreWallet(this._wallet, this._pass, this._name, () => {
|
||||||
ripple.loadingMessage = this.renderLoadingText()
|
ripple.loadingMessage = this.renderLoadingText()
|
||||||
}))
|
})).then(() => {
|
||||||
.then(() => {
|
|
||||||
store.dispatch(doLogin(this._wallet))
|
store.dispatch(doLogin(this._wallet))
|
||||||
store.dispatch(doSelectAddress(this._wallet.addresses[0]))
|
store.dispatch(doSelectAddress(this._wallet.addresses[0]))
|
||||||
checkApiKey(this.nodeConfig);
|
checkApiKey(this.nodeConfig);
|
||||||
this.cleanup()
|
this.cleanup()
|
||||||
return ripple.fade()
|
return ripple.fade()
|
||||||
|
}).catch(err => {
|
||||||
|
console.error(err)
|
||||||
})
|
})
|
||||||
.catch(err => console.error(err))
|
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
store.dispatch(doLogin(this._wallet))
|
store.dispatch(doLogin(this._wallet))
|
||||||
store.dispatch(doSelectAddress(this._wallet.addresses[0]))
|
store.dispatch(doSelectAddress(this._wallet.addresses[0]))
|
||||||
|
|
||||||
checkApiKey()
|
checkApiKey()
|
||||||
|
|
||||||
this.cleanup()
|
this.cleanup()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -238,6 +224,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.pageIndexes = {
|
this.pageIndexes = {
|
||||||
info: 0,
|
info: 0,
|
||||||
password: 1,
|
password: 1,
|
||||||
@ -252,7 +239,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
div[hidden] {
|
div[hidden] {
|
||||||
display:none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.flex {
|
.flex {
|
||||||
@ -274,26 +261,26 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
#createAccountSection {
|
#createAccountSection {
|
||||||
max-height: calc(var(--window-height) - 56px);
|
max-height: calc(var(--window-height) - 56px);
|
||||||
max-width: 440px;
|
max-width: 440px;
|
||||||
max-height:calc(100% - 100px);
|
max-height: calc(100% - 100px);
|
||||||
padding: 0 12px;
|
padding: 0 12px;
|
||||||
overflow-y:auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
#createAccountPages {
|
#createAccountPages {
|
||||||
flex-shrink:1;
|
flex-shrink: 1;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
left:0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#createAccountPages [page] {
|
#createAccountPages [page] {
|
||||||
flex-shrink:1;
|
flex-shrink: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.section-content {
|
.section-content {
|
||||||
padding:0 24px;
|
padding: 0 24px;
|
||||||
padding-bottom:0;
|
padding-bottom: 0;
|
||||||
overflow:auto;
|
overflow: auto;
|
||||||
flex-shrink:1;
|
flex-shrink: 1;
|
||||||
max-height: calc(100vh - 296px);
|
max-height: calc(100vh - 296px);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,23 +294,27 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
mwc-checkbox::shadow .mdc-checkbox::after, mwc-checkbox::shadow .mdc-checkbox::before {
|
mwc-checkbox::shadow .mdc-checkbox::after,
|
||||||
background-color:var(--mdc-theme-primary)
|
mwc-checkbox::shadow .mdc-checkbox::before {
|
||||||
|
background-color: var(--mdc-theme-primary)
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
||||||
|
|
||||||
/* Mobile */
|
/* Mobile */
|
||||||
#createAccountSection {
|
#createAccountSection {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: calc(var(--window-height) - 56px);
|
height: calc(var(--window-height) - 56px);
|
||||||
}
|
}
|
||||||
#infoContent{
|
|
||||||
height:auto;
|
#infoContent {
|
||||||
|
height: auto;
|
||||||
min-height: calc(var(--window-height) - 96px)
|
min-height: calc(var(--window-height) - 96px)
|
||||||
}
|
}
|
||||||
|
|
||||||
#nav {
|
#nav {
|
||||||
flex-shrink:0;
|
flex-shrink: 0;
|
||||||
padding-top:8px;
|
padding-top: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,6 +326,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
from {
|
from {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
@ -360,7 +352,6 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<div id="createAccountSection" class="flex column">
|
<div id="createAccountSection" class="flex column">
|
||||||
<iron-pages selected="${this.selectedPage}" attr-for-selected="page" id="createAccountPages">
|
<iron-pages selected="${this.selectedPage}" attr-for-selected="page" id="createAccountPages">
|
||||||
<div page="info">
|
<div page="info">
|
||||||
@ -371,11 +362,15 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
${translate("login.createwelcome")}
|
${translate("login.createwelcome")}
|
||||||
</p>
|
</p>
|
||||||
<p style="color: var(--black); margin-bottom:0;">
|
<p style="color: var(--black); margin-bottom:0;">
|
||||||
${translate("login.createa")} ‘<paper-button id="myseedshow" @click=${() => this.shadowRoot.querySelector('#mySeedDialog').show()}>${translate("login.seedphrase")}</paper-button><paper-tooltip for="myseedshow" position="top" animation-delay="0">${translate("login.click")}</paper-tooltip>’ ${translate("login.willbe")}
|
${translate("login.createa")} ‘
|
||||||
|
<paper-button id="myseedshow" @click=${() => this.shadowRoot.querySelector('#mySeedDialog').show()}>${translate("login.seedphrase")}</paper-button>
|
||||||
|
<paper-tooltip for="myseedshow" position="top" animation-delay="0">${translate("login.click")}</paper-tooltip>
|
||||||
|
’ ${translate("login.willbe")}
|
||||||
</p>
|
</p>
|
||||||
<p style="color: var(--black); margin-bottom: 0; text-align: center;">
|
<p style="color: var(--black); margin-bottom: 0; text-align: center;">
|
||||||
${translate("login.clicknext")}
|
${translate("login.clicknext")}
|
||||||
</p><br>
|
</p>
|
||||||
|
<br>
|
||||||
</div>
|
</div>
|
||||||
<mwc-dialog id="mySeedDialog">
|
<mwc-dialog id="mySeedDialog">
|
||||||
<div style="min-height:250px; min-width: 300px; box-sizing: border-box; position: relative;">
|
<div style="min-height:250px; min-width: 300px; box-sizing: border-box; position: relative;">
|
||||||
@ -389,8 +384,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
<random-sentence-generator
|
<random-sentence-generator
|
||||||
template="adverb verb noun adjective noun adverb verb noun adjective noun adjective verbed adjective noun"
|
template="adverb verb noun adjective noun adverb verb noun adjective noun adjective verbed adjective noun"
|
||||||
id="randSentence"
|
id="randSentence"
|
||||||
>
|
></random-sentence-generator>
|
||||||
</random-sentence-generator>
|
|
||||||
</div>
|
</div>
|
||||||
<!--
|
<!--
|
||||||
--- --- --- --- --- --- --- --- --- --- --- --- --- -
|
--- --- --- --- --- --- --- --- --- --- --- --- --- -
|
||||||
@ -405,7 +399,8 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
sooo 243*3387*403*2353*3387*403*2353*403*2353 ~ 2^92
|
sooo 243*3387*403*2353*3387*403*2353*403*2353 ~ 2^92
|
||||||
--- --- --- --- --- --- --- --- --- --- --- --- --- -
|
--- --- --- --- --- --- --- --- --- --- --- --- --- -
|
||||||
-->
|
-->
|
||||||
</div><br>
|
</div>
|
||||||
|
<br>
|
||||||
<div class="horizontal-center">
|
<div class="horizontal-center">
|
||||||
<mwc-button raised label="${translate("login.saveseed")}" icon="save" @click=${() => this.downloadSeedphrase()}></mwc-button>
|
<mwc-button raised label="${translate("login.saveseed")}" icon="save" @click=${() => this.downloadSeedphrase()}></mwc-button>
|
||||||
</div>
|
</div>
|
||||||
@ -413,7 +408,6 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
<mwc-button slot="primaryAction" dialogAction="cancel" class="red">${translate("general.close")}</mwc-button>
|
<mwc-button slot="primaryAction" dialogAction="cancel" class="red">${translate("general.close")}</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="password">
|
<div page="password">
|
||||||
<div id="saveContent" class="section-content">
|
<div id="saveContent" class="section-content">
|
||||||
<h3 style="color: var(--black); text-align: center;">${translate("login.savein")}</h3>
|
<h3 style="color: var(--black); text-align: center;">${translate("login.savein")}</h3>
|
||||||
@ -438,19 +432,21 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="backup">
|
<div page="backup">
|
||||||
<div id="downloadBackup" class="section-content">
|
<div id="downloadBackup" class="section-content">
|
||||||
<h3 style="color: var(--black); text-align: center;">${translate("login.savewallet")}</h3>
|
<h3 style="color: var(--black); text-align: center;">${translate("login.savewallet")}</h3>
|
||||||
<p style="color: var(--black); text-align: justify;">${translate("login.created1")}${this.saveAccount ? this.renderCreateSaveText() : '.'}</p>
|
<p style="color: var(--black); text-align: justify;">${translate("login.created1")}${this.saveAccount ? this.renderCreateSaveText() : '.'}</p>
|
||||||
<p style="color: var(--black); margin: 0;">
|
<p style="color: var(--black); margin: 0;">${translate("login.backup")}</p>
|
||||||
${translate("login.backup")}
|
<br>
|
||||||
</p><br>
|
|
||||||
<div id="download-area">
|
<div id="download-area">
|
||||||
<div style="line-height: 40px;">
|
<div style="line-height: 40px;">
|
||||||
<span style="color: var(--black); padding-top: 6px; margin-right: 10px; text-align: center;">${translate("login.downloadbackup")}</span>
|
<span style="color: var(--black); padding-top: 6px; margin-right: 10px; text-align: center;">${translate("login.downloadbackup")}</span>
|
||||||
<slot id="trigger" name="inputTrigger" @click=${() => this.downloadBackup(this._wallet)} style="dispay: inline; text-align: center;">
|
<slot id="trigger" name="inputTrigger" @click=${() =>
|
||||||
<mwc-button><mwc-icon>cloud_download</mwc-icon> ${translate("general.save")}</mwc-button>
|
this.downloadBackup(this._wallet)} style="dispay: inline; text-align: center;">
|
||||||
|
<mwc-button>
|
||||||
|
<mwc-icon>cloud_download</mwc-icon>
|
||||||
|
${translate("general.save")}
|
||||||
|
</mwc-button>
|
||||||
</slot>
|
</slot>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -519,15 +515,19 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
if (!this.shadowRoot.querySelector('#createAccountPages') || !newPage) {
|
if (!this.shadowRoot.querySelector('#createAccountPages') || !newPage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const pages = this.shadowRoot.querySelector('#createAccountPages').children
|
const pages = this.shadowRoot.querySelector('#createAccountPages').children
|
||||||
|
|
||||||
// Run the animation on the newly selected page
|
// Run the animation on the newly selected page
|
||||||
const newIndex = this.pageIndexes[newPage]
|
const newIndex = this.pageIndexes[newPage]
|
||||||
|
|
||||||
if (!pages[newIndex].className.includes('animated')) {
|
if (!pages[newIndex].className.includes('animated')) {
|
||||||
pages[newIndex].className += ' animated'
|
pages[newIndex].className += ' animated'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof oldPage !== 'undefined') {
|
if (typeof oldPage !== 'undefined') {
|
||||||
const oldIndex = this.pageIndexes[oldPage]
|
const oldIndex = this.pageIndexes[oldPage]
|
||||||
|
|
||||||
// Stop the animation of hidden pages
|
// Stop the animation of hidden pages
|
||||||
pages[oldIndex].classList.remove('animated')
|
pages[oldIndex].classList.remove('animated')
|
||||||
}
|
}
|
||||||
@ -535,6 +535,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
selectPage(newPage) {
|
selectPage(newPage) {
|
||||||
const oldPage = this.selectedPage
|
const oldPage = this.selectedPage
|
||||||
|
|
||||||
this.selectedPage = newPage
|
this.selectedPage = newPage
|
||||||
this._pageChange(newPage, oldPage)
|
this._pageChange(newPage, oldPage)
|
||||||
}
|
}
|
||||||
@ -552,6 +553,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
this.backHidden = true
|
this.backHidden = true
|
||||||
this.nextText = this.renderContinueText()
|
this.nextText = this.renderContinueText()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updatedProperty()
|
this.updatedProperty()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -583,24 +585,27 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
this.nodeConfig = state.app.nodeConfig
|
this.nodeConfig = state.app.nodeConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
createAccount() {
|
|
||||||
}
|
|
||||||
|
|
||||||
async downloadBackup(wallet) {
|
async downloadBackup(wallet) {
|
||||||
let backupname = ""
|
let backupname = ""
|
||||||
|
|
||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
const data = await wallet.generateSaveWalletData(this._pass, state.config.crypto.kdfThreads, () => { })
|
const data = await wallet.generateSaveWalletData(this._pass, state.config.crypto.kdfThreads, () => { })
|
||||||
const dataString = JSON.stringify(data)
|
const dataString = JSON.stringify(data)
|
||||||
const blob = new Blob([dataString], { type: 'text/plain;charset=utf-8' })
|
const blob = new Blob([dataString], { type: 'text/plain;charset=utf-8' })
|
||||||
|
|
||||||
backupname = "qortal_backup_" + wallet.addresses[0].address + ".json"
|
backupname = "qortal_backup_" + wallet.addresses[0].address + ".json"
|
||||||
|
|
||||||
await this.saveFileToDisk(blob, backupname)
|
await this.saveFileToDisk(blob, backupname)
|
||||||
}
|
}
|
||||||
|
|
||||||
async downloadSeedphrase() {
|
async downloadSeedphrase() {
|
||||||
let seedname = ""
|
let seedname = ""
|
||||||
|
|
||||||
const seed = this.shadowRoot.getElementById('randSentence').parsedString
|
const seed = this.shadowRoot.getElementById('randSentence').parsedString
|
||||||
const blob = new Blob([seed], { type: 'text/plain;charset=utf-8' })
|
const blob = new Blob([seed], { type: 'text/plain;charset=utf-8' })
|
||||||
|
|
||||||
seedname = "qortal_seedphrase.txt"
|
seedname = "qortal_seedphrase.txt"
|
||||||
|
|
||||||
await this.saveFileToDisk(blob, seedname)
|
await this.saveFileToDisk(blob, seedname)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -609,16 +614,21 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
const fileHandle = await self.showSaveFilePicker({
|
const fileHandle = await self.showSaveFilePicker({
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
types: [{
|
types: [{
|
||||||
description: "File",
|
description: "File"
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
const writeFile = async (fileHandle, contents) => {
|
const writeFile = async (fileHandle, contents) => {
|
||||||
const writable = await fileHandle.createWritable()
|
const writable = await fileHandle.createWritable()
|
||||||
|
|
||||||
await writable.write(contents)
|
await writable.write(contents)
|
||||||
await writable.close()
|
await writable.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
||||||
|
|
||||||
let snack4string = get("general.save")
|
let snack4string = get("general.save")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack4string} ${fileName} ✅`,
|
labelText: `${snack4string} ${fileName} ✅`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -627,6 +637,7 @@ class CreateAccountSection extends connect(store)(LitElement) {
|
|||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSaver.saveAs(blob, fileName)
|
FileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {checkApiKey} from '../../apiKeyUtils.js'
|
import { checkApiKey } from '../../apiKeyUtils'
|
||||||
import {translate} from '../../../translate'
|
import { doLogin, doSelectAddress } from '../../redux/app/app-actions'
|
||||||
import {doLogin, doSelectAddress} from '../../redux/app/app-actions.js'
|
import { doRemoveWallet, doStoreWallet } from '../../redux/user/user-actions'
|
||||||
import {doRemoveWallet, doStoreWallet} from '../../redux/user/user-actions.js'
|
import { createWallet } from '../../../../crypto/api/createWallet'
|
||||||
import {createWallet} from '../../../../crypto/api/createWallet.js'
|
import { createAccountSectionStyles } from '../../styles/core-css'
|
||||||
import snackbar from '../../functional-components/snackbar.js'
|
import ripple from '../../functional-components/loading-ripple'
|
||||||
import '../../custom-elements/frag-file-input.js'
|
import snackbar from '../../functional-components/snackbar'
|
||||||
import ripple from '../../functional-components/loading-ripple.js'
|
import '../../functional-components/frag-file-input'
|
||||||
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-checkbox'
|
import '@material/mwc-checkbox'
|
||||||
import '@material/mwc-dialog'
|
import '@material/mwc-dialog'
|
||||||
@ -26,6 +25,9 @@ import '@polymer/paper-spinner/paper-spinner-lite.js'
|
|||||||
import '@vaadin/text-field/vaadin-text-field.js'
|
import '@vaadin/text-field/vaadin-text-field.js'
|
||||||
import '@vaadin/password-field/vaadin-password-field.js'
|
import '@vaadin/password-field/vaadin-password-field.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
|
||||||
class LoginSection extends connect(store)(LitElement) {
|
class LoginSection extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -51,36 +53,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [createAccountSectionStyles]
|
||||||
css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-primary: var(--login-button);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--paper-input-container-focus-color: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-checkbox-unchecked-color: var(--black);
|
|
||||||
--lumo-primary-text-color: var(--login-border);
|
|
||||||
--lumo-primary-color-50pct: var(--login-border-50pct);
|
|
||||||
--lumo-primary-color-10pct: var(--login-border-10pct);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
--_lumo-grid-border-color: var(--border);
|
|
||||||
--_lumo-grid-secondary-border-color: var(--border2);
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-formfield {
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
--mdc-theme-primary: red;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -132,12 +105,11 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
--paper-spinner-stroke-width: 2px;
|
--paper-spinner-stroke-width: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginPages{
|
#loginPages {
|
||||||
overflow: visible;
|
overflow: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
#walletsPage {
|
#walletsPage {}
|
||||||
}
|
|
||||||
|
|
||||||
#wallets {
|
#wallets {
|
||||||
max-height: 50vh;
|
max-height: 50vh;
|
||||||
@ -236,10 +208,11 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#unlockStoredPage mwc-icon {
|
#unlockStoredPage mwc-icon {
|
||||||
font-size:48px;
|
font-size: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
||||||
|
|
||||||
/* Mobile */
|
/* Mobile */
|
||||||
#wallets {
|
#wallets {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -278,16 +251,11 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
${this.loginOptions.map(({ page, linkText, icon }) => html`
|
${this.loginOptions.map(({ page, linkText, icon }) => html`
|
||||||
<div class="login-option" @click=${() => { this.selectedPage = page }}>
|
<div class="login-option" @click=${() => { this.selectedPage = page }}>
|
||||||
<paper-ripple></paper-ripple>
|
<paper-ripple></paper-ripple>
|
||||||
<div>
|
<div><mwc-icon class='loginIcon'>${icon}</mwc-icon></div>
|
||||||
<mwc-icon class='loginIcon'>${icon}</mwc-icon>
|
<div><span style="color: var(--black)">${linkText}</span></div>
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span style="color: var(--black)">${linkText}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="storedWallet" id="walletsPage">
|
<div page="storedWallet" id="walletsPage">
|
||||||
<div style="text-align: center; padding-left:0;">
|
<div style="text-align: center; padding-left:0;">
|
||||||
<h1 style="padding:0; color: var(--black);">${translate("login.youraccounts")}</h1>
|
<h1 style="padding:0; color: var(--black);">${translate("login.youraccounts")}</h1>
|
||||||
@ -314,17 +282,10 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<p>${translate("login.areyousure")}</p>
|
<p>${translate("login.areyousure")}</p>
|
||||||
<mwc-button
|
<mwc-button slot="primaryAction" @click="${(e) => this.removeWallet(this.myToDeleteWallet)}">
|
||||||
slot="primaryAction"
|
|
||||||
@click="${(e) => this.removeWallet(this.myToDeleteWallet)}"
|
|
||||||
>
|
|
||||||
${translate("general.yes")}
|
${translate("general.yes")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
<mwc-button
|
<mwc-button slot="secondaryAction" dialogAction="cancel" class="red">
|
||||||
slot="secondaryAction"
|
|
||||||
dialogAction="cancel"
|
|
||||||
class="red"
|
|
||||||
>
|
|
||||||
${translate("general.no")}
|
${translate("general.no")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
@ -332,7 +293,6 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
`)}
|
`)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="phrase" id="phrasePage">
|
<div page="phrase" id="phrasePage">
|
||||||
<div style="padding:0;">
|
<div style="padding:0;">
|
||||||
<div style="display:flex;">
|
<div style="display:flex;">
|
||||||
@ -341,7 +301,6 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="seed" id="seedPage">
|
<div page="seed" id="seedPage">
|
||||||
<div>
|
<div>
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
@ -350,7 +309,6 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="unlockStored" id="unlockStoredPage">
|
<div page="unlockStored" id="unlockStoredPage">
|
||||||
<div style="text-align:center;">
|
<div style="text-align:center;">
|
||||||
<mwc-icon id='accountIcon' style="padding-bottom: 24px; color: var(--black);">account_circle</mwc-icon>
|
<mwc-icon id='accountIcon' style="padding-bottom: 24px; color: var(--black);">account_circle</mwc-icon>
|
||||||
@ -358,7 +316,6 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
<span style="font-size:14px; font-weight: 100; font-family: 'Roboto Mono', monospace; color: var(--black);">${this.selectedWallet.address0}</span>
|
<span style="font-size:14px; font-weight: 100; font-family: 'Roboto Mono', monospace; color: var(--black);">${this.selectedWallet.address0}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="backedUpSeed">
|
<div page="backedUpSeed">
|
||||||
${!this.backedUpSeedLoading ? html`
|
${!this.backedUpSeedLoading ? html`
|
||||||
<h3 style="color: var(--black);">${translate("login.upload")}</h3>
|
<h3 style="color: var(--black);">${translate("login.upload")}</h3>
|
||||||
@ -367,26 +324,22 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
<paper-spinner-lite active style="display: block; margin: 0 auto;"></paper-spinner-lite>
|
<paper-spinner-lite active style="display: block; margin: 0 auto;"></paper-spinner-lite>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div page="unlockBackedUpSeed">
|
<div page="unlockBackedUpSeed">
|
||||||
<h3 style="text-align: center; color: var(--black);">${translate("login.decrypt")}</h3>
|
<h3 style="text-align: center; color: var(--black);">${translate("login.decrypt")}</h3>
|
||||||
</div>
|
</div>
|
||||||
</iron-pages>
|
</iron-pages>
|
||||||
|
|
||||||
<iron-collapse style="" ?opened=${this.showName(this.selectedPage)} id="passwordCollapse">
|
<iron-collapse style="" ?opened=${this.showName(this.selectedPage)} id="passwordCollapse">
|
||||||
<div style="display:flex;">
|
<div style="display:flex;">
|
||||||
<mwc-icon style="padding: 10px; padding-left: 0; padding-top: 42px; color: var(--black);">perm_identity</mwc-icon>
|
<mwc-icon style="padding: 10px; padding-left: 0; padding-top: 42px; color: var(--black);">perm_identity</mwc-icon>
|
||||||
<vaadin-text-field style="width:100%;" label="${translate("login.name")}" id="nameInput"></vaadin-text-field>
|
<vaadin-text-field style="width:100%;" label="${translate("login.name")}" id="nameInput"></vaadin-text-field>
|
||||||
</div>
|
</div>
|
||||||
</iron-collapse>
|
</iron-collapse>
|
||||||
|
|
||||||
<iron-collapse style="" ?opened=${this.showPassword(this.selectedPage)} id="passwordCollapse">
|
<iron-collapse style="" ?opened=${this.showPassword(this.selectedPage)} id="passwordCollapse">
|
||||||
<div style="display:flex;">
|
<div style="display:flex;">
|
||||||
<mwc-icon style="padding: 10px; padding-left: 0; padding-top: 42px; color: var(--black);">password</mwc-icon>
|
<mwc-icon style="padding: 10px; padding-left: 0; padding-top: 42px; color: var(--black);">password</mwc-icon>
|
||||||
<vaadin-password-field style="width:100%;" label="${translate("login.password")}" id="password" @keyup=${e => this.keyupEnter(e, e => this.emitNext(e))} autofocus></vaadin-password-field>
|
<vaadin-password-field style="width:100%;" label="${translate("login.password")}" id="password" @keyup=${e => this.keyupEnter(e, e => this.emitNext(e))} autofocus></vaadin-password-field>
|
||||||
</div>
|
</div>
|
||||||
</iron-collapse>
|
</iron-collapse>
|
||||||
|
|
||||||
<div style="text-align: right; color: var(--mdc-theme-error)">
|
<div style="text-align: right; color: var(--mdc-theme-error)">
|
||||||
${this.loginErrorMessage}
|
${this.loginErrorMessage}
|
||||||
</div>
|
</div>
|
||||||
@ -400,13 +353,14 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
` : ''}
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.loadingRipple = ripple
|
this.loadingRipple = ripple
|
||||||
|
|
||||||
const pages = this.shadowRoot.querySelector('#loginPages')
|
const pages = this.shadowRoot.querySelector('#loginPages')
|
||||||
|
|
||||||
pages.addEventListener('selected-item-changed', () => {
|
pages.addEventListener('selected-item-changed', () => {
|
||||||
if (!pages.selectedItem) {
|
if (!pages.selectedItem) {
|
||||||
// ...
|
// ...
|
||||||
@ -475,10 +429,13 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
removeWallet(walletAddress) {
|
removeWallet(walletAddress) {
|
||||||
delete store.getState().user.storedWallets[walletAddress]
|
delete store.getState().user.storedWallets[walletAddress]
|
||||||
|
|
||||||
this.wallets = store.getState().user.storedWallets
|
this.wallets = store.getState().user.storedWallets
|
||||||
|
|
||||||
store.dispatch(
|
store.dispatch(
|
||||||
doRemoveWallet(walletAddress)
|
doRemoveWallet(walletAddress)
|
||||||
)
|
)
|
||||||
|
|
||||||
this.cleanup()
|
this.cleanup()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,14 +460,13 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
emitNext(e) {
|
emitNext(e) {
|
||||||
this.dispatchEvent(new CustomEvent('next', {
|
this.dispatchEvent(new CustomEvent('next', { detail: {} }))
|
||||||
detail: {}
|
|
||||||
}))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadBackup(file) {
|
loadBackup(file) {
|
||||||
let error = ''
|
let error = ''
|
||||||
let pf
|
let pf
|
||||||
|
|
||||||
this.selectedPage = 'unlockBackedUpSeed'
|
this.selectedPage = 'unlockBackedUpSeed'
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -521,6 +477,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const requiredFields = ['address0', 'salt', 'iv', 'version', 'encryptedSeed', 'mac', 'kdfThreads']
|
const requiredFields = ['address0', 'salt', 'iv', 'version', 'encryptedSeed', 'mac', 'kdfThreads']
|
||||||
|
|
||||||
for (const field of requiredFields) {
|
for (const field of requiredFields) {
|
||||||
if (!(field in pf)) throw new Error(field + ' not found in JSON')
|
if (!(field in pf)) throw new Error(field + ' not found in JSON')
|
||||||
}
|
}
|
||||||
@ -532,38 +489,23 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: error
|
labelText: error
|
||||||
})
|
})
|
||||||
|
|
||||||
this.selectedPage = 'backedUpSeed'
|
this.selectedPage = 'backedUpSeed'
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.backedUpWalletJSON = pf
|
this.backedUpWalletJSON = pf
|
||||||
}
|
}
|
||||||
|
|
||||||
showName(selectedPage) {
|
showName(selectedPage) {
|
||||||
return (
|
return (this.saveInBrowser && ['unlockBackedUpSeed', 'seed', 'phrase'].includes(selectedPage)) || ([''].includes(selectedPage))
|
||||||
this.saveInBrowser && [
|
|
||||||
'unlockBackedUpSeed',
|
|
||||||
'seed',
|
|
||||||
'phrase'
|
|
||||||
].includes(selectedPage)
|
|
||||||
) ||
|
|
||||||
(
|
|
||||||
[
|
|
||||||
''
|
|
||||||
].includes(selectedPage)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showPassword(selectedPage) {
|
showPassword(selectedPage) {
|
||||||
let willBeShown = (
|
let willBeShown = (this.saveInBrowser && ['unlockBackedUpSeed', 'seed', 'phrase'].includes(selectedPage)) || (['unlockBackedUpSeed', 'unlockStored'].includes(selectedPage))
|
||||||
this.saveInBrowser && [
|
|
||||||
'unlockBackedUpSeed',
|
|
||||||
'seed',
|
|
||||||
'phrase'
|
|
||||||
].includes(selectedPage)
|
|
||||||
) || (['unlockBackedUpSeed', 'unlockStored'].includes(selectedPage))
|
|
||||||
|
|
||||||
if (willBeShown)
|
if (willBeShown) this.shadowRoot.getElementById('password').focus()
|
||||||
this.shadowRoot.getElementById('password').focus()
|
|
||||||
|
|
||||||
return willBeShown
|
return willBeShown
|
||||||
}
|
}
|
||||||
@ -574,6 +516,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
const seed = this.shadowRoot.querySelector('#v1SeedInput').value
|
const seed = this.shadowRoot.querySelector('#v1SeedInput').value
|
||||||
const name = this.shadowRoot.getElementById('nameInput').value
|
const name = this.shadowRoot.getElementById('nameInput').value
|
||||||
const password = this.shadowRoot.getElementById('password').value
|
const password = this.shadowRoot.getElementById('password').value
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seed,
|
seed,
|
||||||
password,
|
password,
|
||||||
@ -583,6 +526,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
storedWallet: () => {
|
storedWallet: () => {
|
||||||
const wallet = this.selectedWallet
|
const wallet = this.selectedWallet
|
||||||
const password = this.shadowRoot.getElementById('password').value
|
const password = this.shadowRoot.getElementById('password').value
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wallet,
|
wallet,
|
||||||
password
|
password
|
||||||
@ -590,12 +534,15 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
},
|
},
|
||||||
phrase: () => {
|
phrase: () => {
|
||||||
const seedPhrase = this.shadowRoot.querySelector('#existingSeedPhraseInput').value
|
const seedPhrase = this.shadowRoot.querySelector('#existingSeedPhraseInput').value
|
||||||
if (seedPhrase == "") {
|
|
||||||
|
if (seedPhrase == '') {
|
||||||
throw new Error('Please enter a seedphrase')
|
throw new Error('Please enter a seedphrase')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const name = this.shadowRoot.getElementById('nameInput').value
|
const name = this.shadowRoot.getElementById('nameInput').value
|
||||||
const password = this.shadowRoot.getElementById('password').value
|
const password = this.shadowRoot.getElementById('password').value
|
||||||
|
|
||||||
return {
|
return {
|
||||||
seedPhrase,
|
seedPhrase,
|
||||||
name,
|
name,
|
||||||
@ -606,6 +553,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
const wallet = this.backedUpWalletJSON
|
const wallet = this.backedUpWalletJSON
|
||||||
const name = this.shadowRoot.getElementById('nameInput').value
|
const name = this.shadowRoot.getElementById('nameInput').value
|
||||||
const password = this.shadowRoot.getElementById('password').value
|
const password = this.shadowRoot.getElementById('password').value
|
||||||
|
|
||||||
return {
|
return {
|
||||||
password,
|
password,
|
||||||
wallet,
|
wallet,
|
||||||
@ -621,6 +569,7 @@ class LoginSection extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
login(e) {
|
login(e) {
|
||||||
let type = this.selectedPage === 'unlockStored' ? 'storedWallet' : this.selectedPage
|
let type = this.selectedPage === 'unlockStored' ? 'storedWallet' : this.selectedPage
|
||||||
|
|
||||||
type = type === 'unlockBackedUpSeed' ? 'backedUpSeed' : type
|
type = type === 'unlockBackedUpSeed' ? 'backedUpSeed' : type
|
||||||
|
|
||||||
if (!this.loginOptionIsSelected(type)) {
|
if (!this.loginOptionIsSelected(type)) {
|
||||||
|
@ -1,20 +1,7 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {stateAwait} from '../../stateAwait.js'
|
import { stateAwait } from '../../stateAwait'
|
||||||
import {get} from '../../../translate'
|
|
||||||
|
|
||||||
import '@material/mwc-button'
|
|
||||||
import '@material/mwc-icon'
|
|
||||||
import '@material/mwc-fab'
|
|
||||||
import '@polymer/iron-pages'
|
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
|
||||||
import './welcome-page.js'
|
|
||||||
import './create-account-section.js'
|
|
||||||
import './login-section.js'
|
|
||||||
import '../qort-theme-toggle.js'
|
|
||||||
|
|
||||||
import settings from '../../functional-components/settings-page.js'
|
|
||||||
import {
|
import {
|
||||||
addAutoLoadImageChat,
|
addAutoLoadImageChat,
|
||||||
addChatLastSeen,
|
addChatLastSeen,
|
||||||
@ -32,9 +19,23 @@ import {
|
|||||||
setNewTab,
|
setNewTab,
|
||||||
setSideEffectAction,
|
setSideEffectAction,
|
||||||
setTabNotifications
|
setTabNotifications
|
||||||
} from '../../redux/app/app-actions.js'
|
} from '../../redux/app/app-actions'
|
||||||
|
import settings from '../../functional-components/settings-page'
|
||||||
|
import './welcome-page'
|
||||||
|
import './create-account-section'
|
||||||
|
import './login-section'
|
||||||
|
import '../qort-theme-toggle'
|
||||||
|
import '@material/mwc-button'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import '@material/mwc-fab'
|
||||||
|
import '@polymer/iron-pages'
|
||||||
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get } from '../../../translate'
|
||||||
|
|
||||||
window.reduxStore = store
|
window.reduxStore = store
|
||||||
|
|
||||||
window.reduxAction = {
|
window.reduxAction = {
|
||||||
addAutoLoadImageChat: addAutoLoadImageChat,
|
addAutoLoadImageChat: addAutoLoadImageChat,
|
||||||
removeAutoLoadImageChat: removeAutoLoadImageChat,
|
removeAutoLoadImageChat: removeAutoLoadImageChat,
|
||||||
@ -71,16 +72,6 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return [
|
|
||||||
css``
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
getPreSelectedPage() {
|
|
||||||
return 'welcome'
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.selectedPage = this.getPreSelectedPage()
|
this.selectedPage = this.getPreSelectedPage()
|
||||||
@ -95,50 +86,10 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
|
|
||||||
stateAwait(state => {
|
|
||||||
return 'primary' in state.config.styles.theme.colors
|
|
||||||
}).catch(e => console.error(e))
|
|
||||||
|
|
||||||
const loginContainerPages = this.shadowRoot.querySelector('#loginContainerPages')
|
|
||||||
const loginCard = this.shadowRoot.querySelector('#login-card')
|
|
||||||
const navigate = e => {
|
|
||||||
this.selectPage(e.detail.page)
|
|
||||||
}
|
|
||||||
const updatedProperty = e => {
|
|
||||||
// ...
|
|
||||||
const selectedPageElement = this.selectedPageElement
|
|
||||||
this.selectedPageElement = {}
|
|
||||||
setTimeout(() => { this.selectedPageElement = selectedPageElement }, 1) // Yuck
|
|
||||||
}
|
|
||||||
loginContainerPages.addEventListener('selected-item-changed', () => {
|
|
||||||
|
|
||||||
if (!loginContainerPages.selectedItem) {
|
|
||||||
|
|
||||||
if (this.selectedPageElement.removeEventListener) {
|
|
||||||
this.selectedPageElement.removeEventListener('navigate', navigate)
|
|
||||||
this.selectedPageElement.removeEventListener('updatedProperty', updatedProperty)
|
|
||||||
}
|
|
||||||
this.selectedPageElement = {}
|
|
||||||
loginCard.classList.remove('animated')
|
|
||||||
loginCard.className += ' animated'
|
|
||||||
} else {
|
|
||||||
setTimeout(() => {
|
|
||||||
|
|
||||||
this.selectedPageElement = loginContainerPages.selectedItem
|
|
||||||
|
|
||||||
this.selectedPageElement.addEventListener('navigate', navigate)
|
|
||||||
this.selectedPageElement.addEventListener('updatedProperty', updatedProperty)
|
|
||||||
setTimeout(() => loginCard.classList.remove('animated'), animationDuration * 1000)
|
|
||||||
}, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
display: block;
|
display: block;
|
||||||
vertical-align: bottom;
|
vertical-align: bottom;
|
||||||
@ -150,18 +101,18 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
height: var(--window-height);
|
height: var(--window-height);
|
||||||
width:100vw;
|
width: 100vw;
|
||||||
max-width:100vw;
|
max-width: 100vw;
|
||||||
max-height:var(--window-height);
|
max-height: var(--window-height);
|
||||||
position:absolute;
|
position: absolute;
|
||||||
top:0;
|
top: 0;
|
||||||
left:0;
|
left: 0;
|
||||||
z-index:1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card-container {
|
.login-card-container {
|
||||||
max-width:1240px;
|
max-width: 1240px;
|
||||||
max-height:var(--window-height);
|
max-height: var(--window-height);
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
width: calc(100vw);
|
width: calc(100vw);
|
||||||
@ -170,37 +121,37 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
.qortal-logo {
|
.qortal-logo {
|
||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
width:200px;
|
width: 200px;
|
||||||
max-width:40%;
|
max-width: 40%;
|
||||||
z-index:1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card-center-container {
|
.login-card-center-container {
|
||||||
max-width:100%;
|
max-width: 100%;
|
||||||
max-height:var(--window-height);
|
max-height: var(--window-height);
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
height: var(--window-height);
|
height: var(--window-height);
|
||||||
overflow:hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginContainerPages {
|
#loginContainerPages {
|
||||||
display:inline;
|
display: inline;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginContainerPages [page] {
|
#loginContainerPages [page] {
|
||||||
background: none;
|
background: none;
|
||||||
padding:0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
min-width: 340px;
|
min-width: 340px;
|
||||||
border-bottom: 2px solid var(--mdc-theme-primary);
|
border-bottom: 2px solid var(--mdc-theme-primary);
|
||||||
border-top: 2px solid var(--mdc-theme-primary);
|
border-top: 2px solid var(--mdc-theme-primary);
|
||||||
text-align:center;
|
text-align: center;
|
||||||
z-index:0;
|
z-index: 0;
|
||||||
padding:0;
|
padding: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
@ -212,8 +163,8 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-card h1 {
|
.login-card h1 {
|
||||||
margin-bottom:12px;
|
margin-bottom: 12px;
|
||||||
font-size:64px;
|
font-size: 64px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card h5 {
|
.login-card h5 {
|
||||||
@ -229,13 +180,13 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.login-card iron-pages {
|
.login-card iron-pages {
|
||||||
height:100%;
|
height: 100%;
|
||||||
margin-top: -16px;
|
margin-top: -16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backButton {
|
.backButton {
|
||||||
padding-top:18px;
|
padding-top: 18px;
|
||||||
text-align:center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
#login-pages-nav {
|
#login-pages-nav {
|
||||||
@ -248,33 +199,39 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (min-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
@media only screen and (min-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
||||||
|
|
||||||
/* Desktop/tablet */
|
/* Desktop/tablet */
|
||||||
.login-card {
|
.login-card {
|
||||||
max-width:460px;
|
max-width: 460px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#loginContainerPages [page] {
|
#loginContainerPages [page] {
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
#loginContainerPages [page="welcome"] {
|
|
||||||
}
|
#loginContainerPages [page="welcome"] {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
@media only screen and (max-width: ${getComputedStyle(document.body).getPropertyValue('--layout-breakpoint-tablet')}) {
|
||||||
|
|
||||||
/* Mobile */
|
/* Mobile */
|
||||||
.qortal-logo {
|
.qortal-logo {
|
||||||
display:none;
|
display: none;
|
||||||
visibility:hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card {
|
.login-card {
|
||||||
width:100%;
|
width: 100%;
|
||||||
margin:0;
|
margin: 0;
|
||||||
top:0;
|
top: 0;
|
||||||
max-width:100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.backButton {
|
.backButton {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding-left:12px;
|
padding-left: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.login-card h5 {
|
.login-card h5 {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
margin-left: 0px;
|
margin-left: 0px;
|
||||||
@ -288,6 +245,7 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
opacity: 0;
|
opacity: 0;
|
||||||
transform: translateX(-20%);
|
transform: translateX(-20%);
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transform: translateX(0);
|
transform: translateX(0);
|
||||||
@ -296,22 +254,24 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
@keyframes grow-up {
|
@keyframes grow-up {
|
||||||
from {
|
from {
|
||||||
overflow:hidden;
|
overflow: hidden;
|
||||||
max-height:0;
|
max-height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
to {
|
to {
|
||||||
overflow:hidden;
|
overflow: hidden;
|
||||||
max-height:var(--window-height);
|
max-height: var(--window-height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
iron-pages .animated, .animated {
|
iron-pages .animated,
|
||||||
|
.animated {
|
||||||
animation-duration: ${animationDuration}s;
|
animation-duration: ${animationDuration}s;
|
||||||
animation-name: grow-up;
|
animation-name: grow-up;
|
||||||
}
|
}
|
||||||
|
|
||||||
div[page] > paper-icon-button {
|
div[page]>paper-icon-button {
|
||||||
margin:12px;
|
margin: 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.corner-box {
|
.corner-box {
|
||||||
@ -325,7 +285,9 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
</style>
|
</style>
|
||||||
<div class="login-page" ?hidden=${this.loggedIn}>
|
<div class="login-page" ?hidden=${this.loggedIn}>
|
||||||
<mwc-fab icon="settings" style="position:fixed; right:24px; bottom:24px;" @click=${() => settings.show()}></mwc-fab>
|
<mwc-fab icon="settings" style="position:fixed; right:24px; bottom:24px;" @click=${() => settings.show()}></mwc-fab>
|
||||||
<span style="position:fixed; left:24px; bottom:24px;"><qort-theme-toggle></qort-theme-toggle></span>
|
<span style="position:fixed; left:24px; bottom:24px;">
|
||||||
|
<qort-theme-toggle></qort-theme-toggle>
|
||||||
|
</span>
|
||||||
<div class="login-card-container">
|
<div class="login-card-container">
|
||||||
<div class="login-card-center-container">
|
<div class="login-card-center-container">
|
||||||
<div class="login-card" id="login-card">
|
<div class="login-card" id="login-card">
|
||||||
@ -338,11 +300,23 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
<login-section @next=${e => this.selectedPageElement.next(e)} page="login"></login-section>
|
<login-section @next=${e => this.selectedPageElement.next(e)} page="login"></login-section>
|
||||||
</iron-pages>
|
</iron-pages>
|
||||||
<div id="login-pages-nav" ?hidden="${this.selectedPageElement.hideNav}">
|
<div id="login-pages-nav" ?hidden="${this.selectedPageElement.hideNav}">
|
||||||
<mwc-button @click=${e => this.selectedPageElement.back(e)} id="nav-back" ?hidden="${this.selectedPageElement.backHidden}" ?disabled="${this.selectedPageElement.backDisabled}">
|
<mwc-button
|
||||||
<mwc-icon>keyboard_arrow_left</mwc-icon>${this.selectedPageElement.backText}
|
@click=${e => this.selectedPageElement.back(e)}
|
||||||
|
id="nav-back"
|
||||||
|
?hidden="${this.selectedPageElement.backHidden}"
|
||||||
|
?disabled="${this.selectedPageElement.backDisabled}"
|
||||||
|
>
|
||||||
|
<mwc-icon>keyboard_arrow_left</mwc-icon>
|
||||||
|
${this.selectedPageElement.backText}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
<mwc-button @click=${e => this.selectedPageElement.next(e)} id="nav-next" ?hidden="${this.selectedPageElement.nextHidden}" ?disabled="${this.selectedPageElement.nextDisabled}">
|
<mwc-button
|
||||||
${this.selectedPageElement.nextText}<mwc-icon>keyboard_arrow_right</mwc-icon>
|
@click=${e => this.selectedPageElement.next(e)}
|
||||||
|
id="nav-next"
|
||||||
|
?hidden="${this.selectedPageElement.nextHidden}"
|
||||||
|
?disabled="${this.selectedPageElement.nextDisabled}"
|
||||||
|
>
|
||||||
|
${this.selectedPageElement.nextText}
|
||||||
|
<mwc-icon>keyboard_arrow_right</mwc-icon>
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -352,12 +326,60 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
stateAwait(state => {
|
||||||
|
return 'primary' in state.config.styles.theme.colors
|
||||||
|
}).catch(e => console.error(e))
|
||||||
|
|
||||||
|
const loginContainerPages = this.shadowRoot.querySelector('#loginContainerPages')
|
||||||
|
const loginCard = this.shadowRoot.querySelector('#login-card')
|
||||||
|
|
||||||
|
const navigate = e => {
|
||||||
|
this.selectPage(e.detail.page)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedProperty = e => {
|
||||||
|
const selectedPageElement = this.selectedPageElement
|
||||||
|
|
||||||
|
this.selectedPageElement = {}
|
||||||
|
|
||||||
|
setTimeout(() => { this.selectedPageElement = selectedPageElement }, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
loginContainerPages.addEventListener('selected-item-changed', () => {
|
||||||
|
if (!loginContainerPages.selectedItem) {
|
||||||
|
|
||||||
|
if (this.selectedPageElement.removeEventListener) {
|
||||||
|
this.selectedPageElement.removeEventListener('navigate', navigate)
|
||||||
|
this.selectedPageElement.removeEventListener('updatedProperty', updatedProperty)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.selectedPageElement = {}
|
||||||
|
|
||||||
|
loginCard.classList.remove('animated')
|
||||||
|
loginCard.className += ' animated'
|
||||||
|
} else {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.selectedPageElement = loginContainerPages.selectedItem
|
||||||
|
this.selectedPageElement.addEventListener('navigate', navigate)
|
||||||
|
this.selectedPageElement.addEventListener('updatedProperty', updatedProperty)
|
||||||
|
|
||||||
|
setTimeout(() => loginCard.classList.remove('animated'), animationDuration * 1000)
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreSelectedPage() {
|
||||||
|
return 'welcome'
|
||||||
|
}
|
||||||
|
|
||||||
renderSelectedNodeOnStart() {
|
renderSelectedNodeOnStart() {
|
||||||
const selectedNodeIndexOnStart = localStorage.getItem('mySelectedNode')
|
const selectedNodeIndexOnStart = localStorage.getItem('mySelectedNode')
|
||||||
const catchSavedNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
const catchSavedNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
const selectedNodeOnStart = catchSavedNodes[selectedNodeIndexOnStart]
|
const selectedNodeOnStart = catchSavedNodes[selectedNodeIndexOnStart]
|
||||||
const selectedNameOnStart = `${selectedNodeOnStart.name}`
|
const selectedNameOnStart = `${selectedNodeOnStart.name}`
|
||||||
const selectedNodeUrlOnStart = `${selectedNodeOnStart.protocol + '://' + selectedNodeOnStart.domain +':' + selectedNodeOnStart.port}`
|
const selectedNodeUrlOnStart = `${selectedNodeOnStart.protocol + '://' + selectedNodeOnStart.domain + ':' + selectedNodeOnStart.port}`
|
||||||
|
|
||||||
let connectString = get('settings.snack2')
|
let connectString = get('settings.snack2')
|
||||||
|
|
||||||
@ -370,6 +392,7 @@ class LoginView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
stateChanged(state) {
|
stateChanged(state) {
|
||||||
if (this.loggedIn && !state.app.loggedIn) this.cleanup()
|
if (this.loggedIn && !state.app.loggedIn) this.cleanup()
|
||||||
|
|
||||||
this.loggedIn = state.app.loggedIn
|
this.loggedIn = state.app.loggedIn
|
||||||
this.config = state.config
|
this.config = state.config
|
||||||
this.nodeConfig = state.app.nodeConfig
|
this.nodeConfig = state.app.nodeConfig
|
||||||
|
@ -1,56 +1,28 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {translate} from '../../../translate'
|
import { welcomePageStyles } from '../../styles/core-css'
|
||||||
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
|
||||||
class WelcomePage extends LitElement {
|
class WelcomePage extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
nextHidden: { type: Boolean, notify: true },
|
|
||||||
nextEnabled: { type: Boolean, notify: true },
|
|
||||||
nextText: { type: String, notify: true },
|
|
||||||
backHidden: { type: Boolean, notify: true },
|
|
||||||
backDisabled: { type: Boolean, notify: true },
|
|
||||||
backText: { type: String, notify: true },
|
|
||||||
hideNav: { type: Boolean, notify: true },
|
hideNav: { type: Boolean, notify: true },
|
||||||
welcomeMessage: { type: String },
|
|
||||||
theme: { type: String, reflect: true }
|
theme: { type: String, reflect: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [welcomePageStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: var(--login-button);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-button-outline-color: var(--general-color-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-outline {
|
|
||||||
margin: 6px;
|
|
||||||
width: 90%;
|
|
||||||
max-width:90vw;
|
|
||||||
border-top: 0;
|
|
||||||
border-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.welcome-page {
|
|
||||||
padding: 12px 0;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.hideNav = true
|
this.hideNav = true
|
||||||
this.nextText = ''
|
|
||||||
this.welcomeMessage = 'Welcome to Qortal'
|
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="welcome-page">
|
<div class="welcome-page">
|
||||||
@ -60,10 +32,6 @@ class WelcomePage extends LitElement {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
back() {}
|
|
||||||
|
|
||||||
next() {}
|
|
||||||
|
|
||||||
navigate(page) {
|
navigate(page) {
|
||||||
this.dispatchEvent(new CustomEvent('navigate', {
|
this.dispatchEvent(new CustomEvent('navigate', {
|
||||||
detail: { page },
|
detail: { page },
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store.js'
|
||||||
import {doLogout} from '../../redux/app/app-actions.js'
|
import { doLogout } from '../../redux/app/app-actions.js'
|
||||||
import {translate} from '../../../translate'
|
import { logoutViewStyles } from '../../styles/core-css'
|
||||||
|
|
||||||
import '@polymer/paper-dialog/paper-dialog.js'
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
|
||||||
class LogoutView extends connect(store)(LitElement) {
|
class LogoutView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -15,22 +17,7 @@ class LogoutView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [logoutViewStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.decline {
|
|
||||||
--mdc-theme-primary: var(--mdc-theme-error)
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -49,7 +36,7 @@ class LogoutView extends connect(store)(LitElement) {
|
|||||||
<h2 style="color: var(--black);">${translate("logout.confirmlogout")}</h2>
|
<h2 style="color: var(--black);">${translate("logout.confirmlogout")}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="buttons">
|
<div class="buttons">
|
||||||
<mwc-button class='decline' @click=${e => this.decline(e)} dialog-dismiss>${translate("general.no")}</mwc-button>
|
<mwc-button class='decline' @click=${() => this.decline()} dialog-dismiss>${translate("general.no")}</mwc-button>
|
||||||
<mwc-button class='confirm' @click=${e => this.confirm(e)} dialog-confirm autofocus>${translate("general.yes")}</mwc-button>
|
<mwc-button class='confirm' @click=${e => this.confirm(e)} dialog-confirm autofocus>${translate("general.yes")}</mwc-button>
|
||||||
</div>
|
</div>
|
||||||
</paper-dialog>
|
</paper-dialog>
|
||||||
@ -62,10 +49,12 @@ class LogoutView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
async confirm(e) {
|
async confirm(e) {
|
||||||
store.dispatch(doLogout())
|
store.dispatch(doLogout())
|
||||||
|
e.stopPropagation()
|
||||||
}
|
}
|
||||||
|
|
||||||
decline(e) {
|
decline() {
|
||||||
this.shadowRoot.getElementById('userLogoutDialog').close()
|
this.shadowRoot.getElementById('userLogoutDialog').close()
|
||||||
|
this.requestUpdate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,16 +1,14 @@
|
|||||||
import {html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {installRouter} from 'pwa-helpers/router.js'
|
import { connect } from 'pwa-helpers'
|
||||||
import {connect} from 'pwa-helpers'
|
import { store } from '../store'
|
||||||
import {store} from '../store.js'
|
import { installRouter } from 'pwa-helpers/router'
|
||||||
import {doNavigate} from '../redux/app/app-actions.js'
|
import { doNavigate } from '../redux/app/app-actions'
|
||||||
|
import { loadPlugins } from '../plugins/load-plugins'
|
||||||
import isElectron from 'is-electron'
|
import isElectron from 'is-electron'
|
||||||
import '../plugins/streams.js'
|
import './login-view/login-view'
|
||||||
|
import './app-view'
|
||||||
import {loadPlugins} from '../plugins/load-plugins.js'
|
import '../plugins/streams'
|
||||||
|
import '../styles/app-styles'
|
||||||
import '../styles/app-styles.js'
|
|
||||||
import './login-view/login-view.js'
|
|
||||||
import './app-view.js'
|
|
||||||
|
|
||||||
installRouter((location) => store.dispatch(doNavigate(location)))
|
installRouter((location) => store.dispatch(doNavigate(location)))
|
||||||
|
|
||||||
@ -22,44 +20,10 @@ class MainApp extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return []
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`${this.renderViews(this.loggedIn)}`
|
return html`${this.renderViews(this.loggedIn)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Dynamic renderViews method to introduce conditional rendering of views based on user's logged in state.
|
|
||||||
* @param {Boolean} isLoggedIn
|
|
||||||
*/
|
|
||||||
|
|
||||||
renderViews(isLoggedIn) {
|
|
||||||
if (isLoggedIn) {
|
|
||||||
return html`
|
|
||||||
<app-view></app-view>
|
|
||||||
`
|
|
||||||
} else {
|
|
||||||
return html`
|
|
||||||
<login-view></login-view>
|
|
||||||
`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged(state) {
|
|
||||||
this.loggedIn = state.app.loggedIn
|
|
||||||
if (this.loggedIn === true && this.initial === 0) {
|
|
||||||
this.initial = this.initial + 1
|
|
||||||
this._loadPlugins()
|
|
||||||
}
|
|
||||||
document.title = state.config.coin.name
|
|
||||||
}
|
|
||||||
|
|
||||||
_loadPlugins() {
|
|
||||||
loadPlugins()
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
super.connectedCallback()
|
super.connectedCallback()
|
||||||
this.initial = 0
|
this.initial = 0
|
||||||
@ -72,6 +36,31 @@ class MainApp extends connect(store)(LitElement) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic renderViews method to introduce conditional rendering of views based on user's logged in state.
|
||||||
|
* @param {Boolean} isLoggedIn
|
||||||
|
*/
|
||||||
|
renderViews(isLoggedIn) {
|
||||||
|
if (isLoggedIn) {
|
||||||
|
return html`<app-view></app-view>`
|
||||||
|
} else {
|
||||||
|
return html`<login-view></login-view>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadPlugins() {
|
||||||
|
loadPlugins()
|
||||||
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
this.loggedIn = state.app.loggedIn
|
||||||
|
if (this.loggedIn === true && this.initial === 0) {
|
||||||
|
this.initial = this.initial + 1
|
||||||
|
this._loadPlugins()
|
||||||
|
}
|
||||||
|
document.title = state.config.coin.name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('main-app', MainApp)
|
window.customElements.define('main-app', MainApp)
|
@ -1,5 +1,8 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {registerTranslateConfig, translate, use} from '../../translate'
|
import { newSelectorStyles } from '../styles/core-css'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { registerTranslateConfig, translate, use } from '../../translate'
|
||||||
|
|
||||||
registerTranslateConfig({
|
registerTranslateConfig({
|
||||||
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
|
||||||
@ -22,40 +25,7 @@ class NewSelector extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return [
|
return [newSelectorStyles]
|
||||||
css`
|
|
||||||
select {
|
|
||||||
width: auto;
|
|
||||||
height: auto;
|
|
||||||
position: absolute;
|
|
||||||
top: 50px;
|
|
||||||
padding: 5px 5px 5px 5px;
|
|
||||||
font-size: 16px;
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 3px;
|
|
||||||
color: var(--black);
|
|
||||||
background: var(--white);
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
*:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
select option {
|
|
||||||
color: var(--black);
|
|
||||||
background: var(--white);
|
|
||||||
line-height: 34px;
|
|
||||||
}
|
|
||||||
|
|
||||||
select option:hover {
|
|
||||||
color: var(--white);
|
|
||||||
background: var(--black);
|
|
||||||
line-height: 34px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -100,15 +70,16 @@ class NewSelector extends LitElement {
|
|||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
const myElement = this.shadowRoot.getElementById('languageNew')
|
const myElement = this.shadowRoot.getElementById('languageNew')
|
||||||
|
|
||||||
myElement.addEventListener("change", () => {
|
myElement.addEventListener('change', () => {
|
||||||
this.selectElement()
|
this.selectElement()
|
||||||
})
|
})
|
||||||
|
|
||||||
myElement.addEventListener("click", () => {
|
myElement.addEventListener('click', () => {
|
||||||
const element1 = localStorage.getItem('qortalLanguage')
|
const element1 = localStorage.getItem('qortalLanguage')
|
||||||
const element2 = this.shadowRoot.getElementById('languageNew').value
|
const element2 = this.shadowRoot.getElementById('languageNew').value
|
||||||
|
|
||||||
if (element1 === element2) {
|
if (element1 === element2) {
|
||||||
myElement.style.display = "none"
|
myElement.style.display = 'none'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -117,9 +88,11 @@ class NewSelector extends LitElement {
|
|||||||
|
|
||||||
selectElement() {
|
selectElement() {
|
||||||
const selectedLanguage = localStorage.getItem('qortalLanguage')
|
const selectedLanguage = localStorage.getItem('qortalLanguage')
|
||||||
|
|
||||||
let element = this.shadowRoot.getElementById('languageNew')
|
let element = this.shadowRoot.getElementById('languageNew')
|
||||||
|
|
||||||
element.value = selectedLanguage
|
element.value = selectedLanguage
|
||||||
element.style.display = "none"
|
element.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
changeLanguage(event) {
|
changeLanguage(event) {
|
||||||
@ -129,10 +102,11 @@ class NewSelector extends LitElement {
|
|||||||
|
|
||||||
toggleMenu() {
|
toggleMenu() {
|
||||||
let mySwitchDisplay = this.shadowRoot.getElementById('languageNew')
|
let mySwitchDisplay = this.shadowRoot.getElementById('languageNew')
|
||||||
if(mySwitchDisplay.style.display == "none") {
|
|
||||||
mySwitchDisplay.style.display = "block"
|
if (mySwitchDisplay.style.display == 'none') {
|
||||||
|
mySwitchDisplay.style.display = 'block'
|
||||||
} else {
|
} else {
|
||||||
mySwitchDisplay.style.display = "none"
|
mySwitchDisplay.style.display = 'none'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,160 +1,68 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers';
|
import { repeat } from 'lit/directives/repeat.js'
|
||||||
|
import { connect } from 'pwa-helpers'
|
||||||
import '@vaadin/item';
|
import { store } from '../../store'
|
||||||
import '@vaadin/list-box';
|
import { setNewNotification } from '../../redux/app/app-actions'
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js';
|
import { notificationBellGeneralStyles, notificationItemTxStyles } from '../../styles/core-css'
|
||||||
import '@polymer/iron-icons/iron-icons.js';
|
import './popover.js'
|
||||||
import {store} from '../../store.js';
|
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||||
import {setNewNotification} from '../../redux/app/app-actions.js';
|
import '@material/mwc-icon'
|
||||||
import '@material/mwc-icon';
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
import {get, translate} from '../../../translate'
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
import {repeat} from 'lit/directives/repeat.js';
|
import '@vaadin/item'
|
||||||
import '../../../../plugins/plugins/core/components/TimeAgo.js';
|
import '@vaadin/list-box'
|
||||||
import './popover.js';
|
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
class NotificationBellGeneral extends connect(store)(LitElement) {
|
class NotificationBellGeneral extends connect(store)(LitElement) {
|
||||||
static properties = {
|
static get properties() {
|
||||||
|
return {
|
||||||
notifications: { type: Array },
|
notifications: { type: Array },
|
||||||
showNotifications: { type: Boolean },
|
showNotifications: { type: Boolean },
|
||||||
notificationCount: { type: Boolean },
|
notificationCount: { type: Boolean },
|
||||||
theme: { type: String, reflect: true },
|
|
||||||
currentNotification: { type: Object },
|
currentNotification: { type: Object },
|
||||||
};
|
theme: { type: String, reflect: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [notificationBellGeneralStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.notifications = [];
|
this.notifications = []
|
||||||
this.showNotifications = false;
|
this.showNotifications = false
|
||||||
this.notificationCount = false;
|
this.notificationCount = false
|
||||||
this.initialFetch = false;
|
this.initialFetch = false
|
||||||
this.theme = localStorage.getItem('qortalTheme')
|
this.currentNotification = null
|
||||||
? localStorage.getItem('qortalTheme')
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
: 'light';
|
|
||||||
this.currentNotification = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
try {
|
|
||||||
let value = JSON.parse(localStorage.getItem('isFirstTimeUser'));
|
|
||||||
if (!value && value !== false) {
|
|
||||||
value = true;
|
|
||||||
}
|
|
||||||
this.isFirstTimeUser = value;
|
|
||||||
} catch (error) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
async stateChanged(state) {
|
|
||||||
if (state.app.newNotification) {
|
|
||||||
const newNotification = state.app.newNotification;
|
|
||||||
this.notifications = [newNotification, ...this.notifications];
|
|
||||||
store.dispatch(setNewNotification(null));
|
|
||||||
if (this.isFirstTimeUser) {
|
|
||||||
const target = this.shadowRoot.getElementById(
|
|
||||||
'popover-notification'
|
|
||||||
);
|
|
||||||
const popover =
|
|
||||||
this.shadowRoot.querySelector('popover-component');
|
|
||||||
if (popover) {
|
|
||||||
popover.openPopover(target);
|
|
||||||
}
|
|
||||||
|
|
||||||
localStorage.setItem('isFirstTimeUser', JSON.stringify(false));
|
|
||||||
this.isFirstTimeUser = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleBlur() {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (!this.shadowRoot.contains(document.activeElement)) {
|
|
||||||
this.showNotifications = false;
|
|
||||||
}
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeStatus(signature, statusTx) {
|
|
||||||
const copyNotifications = [...this.notifications];
|
|
||||||
const findNotification = this.notifications.findIndex(
|
|
||||||
(notification) => notification.reference.signature === signature
|
|
||||||
);
|
|
||||||
if (findNotification !== -1) {
|
|
||||||
copyNotifications[findNotification] = {
|
|
||||||
...copyNotifications[findNotification],
|
|
||||||
status: statusTx,
|
|
||||||
};
|
|
||||||
this.notifications = copyNotifications;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const hasOngoing = this.notifications.find(
|
const hasOngoing = this.notifications.find(
|
||||||
(notification) => notification.status !== 'confirmed'
|
(notification) => notification.status !== 'confirmed'
|
||||||
);
|
)
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
<popover-component
|
<popover-component for="popover-notification" message=${get('notifications.explanation')}></popover-component>
|
||||||
for="popover-notification"
|
<div id="popover-notification" @click=${() => this._toggleNotifications()}>
|
||||||
message=${get('notifications.explanation')}
|
${hasOngoing ? html`
|
||||||
></popover-component>
|
<mwc-icon id="notification-general-icon" style="color: green;cursor:pointer;user-select:none">notifications</mwc-icon>
|
||||||
<div
|
<vaadin-tooltip for="notification-general-icon" position="bottom" hover-delay=${400} hide-delay=${1} text=${get('notifications.notify4')}></vaadin-tooltip>
|
||||||
id="popover-notification"
|
` : html`
|
||||||
@click=${() => this._toggleNotifications()}
|
<mwc-icon id="notification-general-icon" style="color: var(--black); cursor:pointer;user-select:none">notifications</mwc-icon>
|
||||||
>
|
<vaadin-tooltip for="notification-general-icon" position="bottom" hover-delay=${400} hide-delay=${1}text=${get('notifications.notify4')}></vaadin-tooltip>
|
||||||
${hasOngoing
|
|
||||||
? html`
|
|
||||||
<mwc-icon id="notification-general-icon" style="color: green;cursor:pointer;user-select:none"
|
|
||||||
>notifications</mwc-icon
|
|
||||||
>
|
|
||||||
<vaadin-tooltip
|
|
||||||
for="notification-general-icon"
|
|
||||||
position="bottom"
|
|
||||||
hover-delay=${400}
|
|
||||||
hide-delay=${1}
|
|
||||||
text=${get('notifications.notify4')}>
|
|
||||||
</vaadin-tooltip>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<mwc-icon
|
|
||||||
id="notification-general-icon"
|
|
||||||
style="color: var(--black); cursor:pointer;user-select:none"
|
|
||||||
>notifications</mwc-icon
|
|
||||||
>
|
|
||||||
<vaadin-tooltip
|
|
||||||
for="notification-general-icon"
|
|
||||||
position="bottom"
|
|
||||||
hover-delay=${400}
|
|
||||||
hide-delay=${1}
|
|
||||||
text=${get('notifications.notify4')}>
|
|
||||||
</vaadin-tooltip>
|
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${hasOngoing
|
${hasOngoing ? html`
|
||||||
? html`
|
<span class="count" style="cursor:pointer" @click=${() => this._toggleNotifications()}>
|
||||||
<span
|
<mwc-icon style="color: var(--black);font-size:18px">pending</mwc-icon>
|
||||||
class="count"
|
|
||||||
style="cursor:pointer"
|
|
||||||
@click=${() => this._toggleNotifications()}
|
|
||||||
>
|
|
||||||
<mwc-icon
|
|
||||||
style="color: var(--black);font-size:18px"
|
|
||||||
>pending</mwc-icon
|
|
||||||
>
|
|
||||||
</span>
|
</span>
|
||||||
`
|
` : ''}
|
||||||
: ''}
|
<div id="notification-panel" class="popover-panel" style="visibility:${this.showNotifications ? 'visibile' : 'hidden'}" tabindex="0" @blur=${this.handleBlur}>
|
||||||
|
|
||||||
<div
|
|
||||||
id="notification-panel"
|
|
||||||
class="popover-panel"
|
|
||||||
style="visibility:${this.showNotifications
|
|
||||||
? 'visibile'
|
|
||||||
: 'hidden'}"
|
|
||||||
tabindex="0"
|
|
||||||
@blur=${this.handleBlur}
|
|
||||||
>
|
|
||||||
<div class="notifications-list">
|
<div class="notifications-list">
|
||||||
${this.notifications.length === 0 ? html`
|
${this.notifications.length === 0 ? html`
|
||||||
<p style="font-size: 16px; width: 100%; text-align:center;margin-top:20px;">${translate('notifications.notify3')}</p>
|
<p style="font-size: 16px; width: 100%; text-align:center;margin-top:20px;">${translate('notifications.notify3')}</p>
|
||||||
@ -170,14 +78,78 @@ class NotificationBellGeneral extends connect(store)(LitElement) {
|
|||||||
timestamp=${notification.timestamp}
|
timestamp=${notification.timestamp}
|
||||||
type=${notification.type}
|
type=${notification.type}
|
||||||
signature=${notification.reference
|
signature=${notification.reference
|
||||||
.signature}
|
.signature
|
||||||
|
}
|
||||||
></notification-item-tx>
|
></notification-item-tx>
|
||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
try {
|
||||||
|
let value = JSON.parse(localStorage.getItem('isFirstTimeUser'))
|
||||||
|
|
||||||
|
if (!value && value !== false) {
|
||||||
|
value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isFirstTimeUser = value
|
||||||
|
} catch (error) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
async stateChanged(state) {
|
||||||
|
if (state.app.newNotification) {
|
||||||
|
const newNotification = state.app.newNotification
|
||||||
|
|
||||||
|
this.notifications = [newNotification, ...this.notifications]
|
||||||
|
|
||||||
|
store.dispatch(setNewNotification(null))
|
||||||
|
|
||||||
|
if (this.isFirstTimeUser) {
|
||||||
|
const target = this.shadowRoot.getElementById(
|
||||||
|
'popover-notification'
|
||||||
|
)
|
||||||
|
|
||||||
|
const popover = this.shadowRoot.querySelector('popover-component')
|
||||||
|
|
||||||
|
if (popover) {
|
||||||
|
popover.openPopover(target)
|
||||||
|
}
|
||||||
|
|
||||||
|
localStorage.setItem('isFirstTimeUser', JSON.stringify(false))
|
||||||
|
|
||||||
|
this.isFirstTimeUser = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBlur() {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (!this.shadowRoot.contains(document.activeElement)) {
|
||||||
|
this.showNotifications = false
|
||||||
|
}
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
changeStatus(signature, statusTx) {
|
||||||
|
const copyNotifications = [...this.notifications]
|
||||||
|
|
||||||
|
const findNotification = this.notifications.findIndex(
|
||||||
|
(notification) => notification.reference.signature === signature
|
||||||
|
)
|
||||||
|
|
||||||
|
if (findNotification !== -1) {
|
||||||
|
copyNotifications[findNotification] = {
|
||||||
|
...copyNotifications[findNotification],
|
||||||
|
status: statusTx
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notifications = copyNotifications
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleNotifications() {
|
_toggleNotifications() {
|
||||||
@ -188,153 +160,34 @@ class NotificationBellGeneral extends connect(store)(LitElement) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.layout {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.count {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nocount {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel {
|
|
||||||
position: absolute;
|
|
||||||
width: 200px;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
top: 40px;
|
|
||||||
max-height: 350px;
|
|
||||||
overflow: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #6a6c75 #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar {
|
|
||||||
width: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-track {
|
|
||||||
background: #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #6a6c75;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 3px solid #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notifications-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item:hover {
|
|
||||||
background: var(--nav-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('notification-bell-general', NotificationBellGeneral);
|
window.customElements.define('notification-bell-general', NotificationBellGeneral)
|
||||||
|
|
||||||
class NotificationItemTx extends connect(store)(LitElement) {
|
class NotificationItemTx extends connect(store)(LitElement) {
|
||||||
static properties = {
|
static get properties() {
|
||||||
|
return {
|
||||||
status: { type: String },
|
status: { type: String },
|
||||||
type: { type: String },
|
type: { type: String },
|
||||||
timestamp: { type: Number },
|
timestamp: { type: Number },
|
||||||
signature: { type: String },
|
signature: { type: String },
|
||||||
changeStatus: { attribute: false },
|
changeStatus: { attribute: false }
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [notificationItemTxStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.nodeUrl = this.getNodeUrl();
|
this.nodeUrl = this.getNodeUrl()
|
||||||
this.myNode = this.getMyNode();
|
this.myNode = this.getMyNode()
|
||||||
}
|
|
||||||
|
|
||||||
getNodeUrl() {
|
|
||||||
const myNode =
|
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
|
|
||||||
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
}
|
|
||||||
getMyNode() {
|
|
||||||
return store.getState().app.nodeConfig.knownNodes[
|
|
||||||
window.parent.reduxStore.getState().app.nodeConfig.node
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
async getStatus() {
|
|
||||||
let interval = null;
|
|
||||||
let stop = false;
|
|
||||||
const getAnswer = async () => {
|
|
||||||
const getTx = async (minterAddr) => {
|
|
||||||
const url = `${this.nodeUrl}/transactions/signature/${this.signature}`
|
|
||||||
const res = await fetch(url)
|
|
||||||
return await res.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stop) {
|
|
||||||
stop = true;
|
|
||||||
try {
|
|
||||||
const txTransaction = await getTx();
|
|
||||||
if (!txTransaction.error && txTransaction.signature && txTransaction.blockHeight) {
|
|
||||||
clearInterval(interval);
|
|
||||||
this.changeStatus(this.signature, 'confirmed');
|
|
||||||
}
|
|
||||||
} catch (error) {}
|
|
||||||
stop = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
interval = setInterval(getAnswer, 20000);
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this.getStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="notification-item" @click=${() => {}}>
|
<div class="notification-item" @click=${() => { }}>
|
||||||
<div>
|
<div>
|
||||||
<p style="margin-bottom:10px; font-weight:bold">
|
<p style="margin-bottom:10px; font-weight:bold">
|
||||||
${translate('transpage.tchange1')}
|
${translate('transpage.tchange1')}
|
||||||
@ -345,187 +198,66 @@ class NotificationItemTx extends connect(store)(LitElement) {
|
|||||||
${translate('walletpage.wchange35')}: ${this.type}
|
${translate('walletpage.wchange35')}: ${this.type}
|
||||||
</p>
|
</p>
|
||||||
<p style="margin-bottom:5px">
|
<p style="margin-bottom:5px">
|
||||||
${translate('tubespage.schange28')}:
|
${translate('tubespage.schange28')}: ${this.status === 'confirming' ? translate('notifications.notify1') : translate('notifications.notify2')}
|
||||||
${this.status === 'confirming'
|
|
||||||
? translate('notifications.notify1')
|
|
||||||
: translate('notifications.notify2')}
|
|
||||||
</p>
|
</p>
|
||||||
${this.status !== 'confirmed'
|
${this.status !== 'confirmed' ? html`<div class="centered"><div class="loader">Loading...</div></div>` : ''}
|
||||||
? html`
|
<div style="display:flex;justify-content:space-between;align-items:center">
|
||||||
<div class="centered">
|
<message-time timestamp=${this.timestamp} style="color:red;font-size:12px"></message-time>
|
||||||
<div class="loader">Loading...</div>
|
${this.status === 'confirmed' ? html`<mwc-icon style="color: green;">done</mwc-icon>` : ''}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
: ''}
|
}
|
||||||
<div
|
|
||||||
style="display:flex;justify-content:space-between;align-items:center"
|
firstUpdated() {
|
||||||
>
|
this.getStatus()
|
||||||
<message-time
|
}
|
||||||
timestamp=${this.timestamp}
|
|
||||||
style="color:red;font-size:12px"
|
getNodeUrl() {
|
||||||
></message-time>
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
${this.status === 'confirmed'
|
return myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
? html`
|
}
|
||||||
<mwc-icon style="color: green;"
|
|
||||||
>done</mwc-icon
|
getMyNode() {
|
||||||
>
|
return store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
`
|
}
|
||||||
: ''}
|
|
||||||
</div>
|
async getStatus() {
|
||||||
</div>
|
let interval = null
|
||||||
</div>
|
let stop = false
|
||||||
`;
|
|
||||||
|
const getAnswer = async () => {
|
||||||
|
const getTx = async (minterAddr) => {
|
||||||
|
const url = `${this.nodeUrl}/transactions/signature/${this.signature}`
|
||||||
|
const res = await fetch(url)
|
||||||
|
|
||||||
|
return await res.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stop) {
|
||||||
|
stop = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const txTransaction = await getTx()
|
||||||
|
|
||||||
|
if (!txTransaction.error && txTransaction.signature && txTransaction.blockHeight) {
|
||||||
|
clearInterval(interval)
|
||||||
|
this.changeStatus(this.signature, 'confirmed')
|
||||||
|
}
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
|
stop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
interval = setInterval(getAnswer, 20000)
|
||||||
}
|
}
|
||||||
|
|
||||||
_toggleNotifications() {
|
_toggleNotifications() {
|
||||||
if (this.notifications.length === 0) return;
|
if (this.notifications.length === 0) return
|
||||||
this.showNotifications = !this.showNotifications;
|
this.showNotifications = !this.showNotifications
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.centered {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.layout {
|
|
||||||
width: 100px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.count {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nocount {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel {
|
|
||||||
position: absolute;
|
|
||||||
width: 200px;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
top: 40px;
|
|
||||||
max-height: 350px;
|
|
||||||
overflow: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #6a6c75 #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar {
|
|
||||||
width: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-track {
|
|
||||||
background: #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #6a6c75;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 3px solid #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notifications-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item:hover {
|
|
||||||
background: var(--nav-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.loader,
|
|
||||||
.loader:before,
|
|
||||||
.loader:after {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
-webkit-animation-fill-mode: both;
|
|
||||||
animation-fill-mode: both;
|
|
||||||
-webkit-animation: load7 1.8s infinite ease-in-out;
|
|
||||||
animation: load7 1.8s infinite ease-in-out;
|
|
||||||
}
|
|
||||||
.loader {
|
|
||||||
color: var(--black);
|
|
||||||
font-size: 5px;
|
|
||||||
margin-bottom: 20px;
|
|
||||||
position: relative;
|
|
||||||
text-indent: -9999em;
|
|
||||||
-webkit-transform: translateZ(0);
|
|
||||||
-ms-transform: translateZ(0);
|
|
||||||
transform: translateZ(0);
|
|
||||||
-webkit-animation-delay: -0.16s;
|
|
||||||
animation-delay: -0.16s;
|
|
||||||
}
|
|
||||||
.loader:before,
|
|
||||||
.loader:after {
|
|
||||||
content: '';
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.loader:before {
|
|
||||||
left: -3.5em;
|
|
||||||
-webkit-animation-delay: -0.32s;
|
|
||||||
animation-delay: -0.32s;
|
|
||||||
}
|
|
||||||
.loader:after {
|
|
||||||
left: 3.5em;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes load7 {
|
|
||||||
0%,
|
|
||||||
80%,
|
|
||||||
100% {
|
|
||||||
box-shadow: 0 2.5em 0 -1.3em;
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
box-shadow: 0 2.5em 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes load7 {
|
|
||||||
0%,
|
|
||||||
80%,
|
|
||||||
100% {
|
|
||||||
box-shadow: 0 2.5em 0 -1.3em;
|
|
||||||
}
|
|
||||||
40% {
|
|
||||||
box-shadow: 0 2.5em 0 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('notification-item-tx', NotificationItemTx);
|
window.customElements.define('notification-item-tx', NotificationItemTx)
|
@ -1,25 +1,29 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { css, html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
|
import { store } from '../../store'
|
||||||
|
import { setNewTab } from '../../redux/app/app-actions'
|
||||||
|
import { routes } from '../../plugins/routes'
|
||||||
|
import { notificationBellStyles } from '../../styles/core-css'
|
||||||
|
import config from '../../notifications/config'
|
||||||
|
import '../../../../plugins/plugins/core/components/TimeAgo'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
import '@polymer/paper-icon-button/paper-icon-button'
|
||||||
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
import '@vaadin/item'
|
import '@vaadin/item'
|
||||||
import '@vaadin/list-box'
|
import '@vaadin/list-box'
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
|
||||||
import '@polymer/iron-icons/iron-icons.js'
|
|
||||||
import {store} from '../../store.js'
|
|
||||||
import {setNewTab} from '../../redux/app/app-actions.js'
|
|
||||||
import {routes} from '../../plugins/routes.js'
|
|
||||||
import '@material/mwc-icon';
|
|
||||||
|
|
||||||
import config from '../../notifications/config.js'
|
|
||||||
import '../../../../plugins/plugins/core/components/TimeAgo.js'
|
|
||||||
|
|
||||||
class NotificationBell extends connect(store)(LitElement) {
|
class NotificationBell extends connect(store)(LitElement) {
|
||||||
|
static get properties() {
|
||||||
static properties = {
|
return {
|
||||||
notifications: { type: Array },
|
notifications: { type: Array },
|
||||||
showNotifications: { type: Boolean },
|
showNotifications: { type: Boolean },
|
||||||
notificationCount: { type: Boolean },
|
notificationCount: { type: Boolean },
|
||||||
theme: { type: String, reflect: true },
|
theme: { type: String, reflect: true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [notificationBellStyles]
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -31,132 +35,13 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
|
||||||
this.getNotifications();
|
|
||||||
document.addEventListener('click', (event) => {
|
|
||||||
const path = event.composedPath()
|
|
||||||
if (!path.includes(this)) {
|
|
||||||
this.showNotifications = false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
getApiKey() {
|
|
||||||
const apiNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
|
|
||||||
return apiNode.apiKey
|
|
||||||
}
|
|
||||||
|
|
||||||
async getNotifications() {
|
|
||||||
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
|
||||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
|
||||||
|
|
||||||
let interval = null
|
|
||||||
let stop = false
|
|
||||||
|
|
||||||
const getNewMail = async () => {
|
|
||||||
|
|
||||||
const getMail = async (recipientName, recipientAddress) => {
|
|
||||||
const query = `qortal_qmail_${recipientName.slice(
|
|
||||||
0,
|
|
||||||
20
|
|
||||||
)}_${recipientAddress.slice(-6)}_mail_`
|
|
||||||
const url = `${nodeUrl}/arbitrary/resources/search?service=MAIL_PRIVATE&query=${query}&limit=10&includemetadata=false&offset=0&reverse=true&excludeblocked=true`
|
|
||||||
const response = await fetch(url, {
|
|
||||||
method: 'GET',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return await response.json()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stop && !this.showNotifications) {
|
|
||||||
stop = true
|
|
||||||
try {
|
|
||||||
const address = window.parent.reduxStore.getState().app?.selectedAddress?.address;
|
|
||||||
const name = window.parent.reduxStore.getState().app?.accountInfo?.names[0]?.name
|
|
||||||
|
|
||||||
if (!name || !address) return
|
|
||||||
const mailArray = await getMail(name, address)
|
|
||||||
let notificationsToShow = []
|
|
||||||
if (mailArray.length > 0) {
|
|
||||||
const lastVisited = localStorage.getItem("Q-Mail-last-visited")
|
|
||||||
|
|
||||||
if (lastVisited) {
|
|
||||||
mailArray.forEach((mail) => {
|
|
||||||
if (mail.created > lastVisited) notificationsToShow.push(mail)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
notificationsToShow = mailArray
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (!this.initialFetch && notificationsToShow.length > 0) {
|
|
||||||
const mail = notificationsToShow[0]
|
|
||||||
const urlPic = `${nodeUrl}/arbitrary/THUMBNAIL/${mail.name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
|
|
||||||
await routes.showNotification({
|
|
||||||
data: {
|
|
||||||
title: "New Q-Mail",
|
|
||||||
type: "qapp",
|
|
||||||
sound: config.messageAlert,
|
|
||||||
url: "",
|
|
||||||
options: {
|
|
||||||
body: `You have an unread mail from ${mail.name}`,
|
|
||||||
icon: urlPic,
|
|
||||||
badge: urlPic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
} else if (notificationsToShow.length > 0) {
|
|
||||||
if (notificationsToShow[0].created > (this.notifications[0]?.created || 0)) {
|
|
||||||
const mail = notificationsToShow[0]
|
|
||||||
const urlPic = `${nodeUrl}/arbitrary/THUMBNAIL/${mail.name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
|
|
||||||
await routes.showNotification({
|
|
||||||
data: {
|
|
||||||
title: "New Q-Mail",
|
|
||||||
type: "qapp",
|
|
||||||
sound: config.messageAlert,
|
|
||||||
url: "",
|
|
||||||
options: {
|
|
||||||
body: `You have an unread mail from ${mail.name}`,
|
|
||||||
icon: urlPic,
|
|
||||||
badge: urlPic
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.notifications = notificationsToShow
|
|
||||||
|
|
||||||
this.notificationCount = this.notifications.length !== 0;
|
|
||||||
|
|
||||||
if (!this.initialFetch) this.initialFetch = true
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
stop = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
getNewMail()
|
|
||||||
}, 5000)
|
|
||||||
|
|
||||||
interval = setInterval(getNewMail, 60000)
|
|
||||||
} catch (error) {
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="layout">
|
<div class="layout">
|
||||||
${this.notificationCount ? html`
|
${this.notificationCount ? html`
|
||||||
<mwc-icon @click=${() => this._toggleNotifications()} id="notification-mail-icon" style="color: green;cursor:pointer;user-select:none"
|
<mwc-icon @click=${() => this._toggleNotifications()} id="notification-mail-icon" style="color: green;cursor:pointer;user-select:none">
|
||||||
>mail</mwc-icon
|
mail
|
||||||
>
|
</mwc-icon>
|
||||||
<vaadin-tooltip
|
<vaadin-tooltip
|
||||||
for="notification-mail-icon"
|
for="notification-mail-icon"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
@ -164,11 +49,10 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
hide-delay=${1}
|
hide-delay=${1}
|
||||||
text="Q-Mail">
|
text="Q-Mail">
|
||||||
</vaadin-tooltip>
|
</vaadin-tooltip>
|
||||||
|
|
||||||
` : html`
|
` : html`
|
||||||
<mwc-icon @click=${() => this._openTabQmail()} id="notification-mail-icon" style="color: var(--black); cursor:pointer;user-select:none"
|
<mwc-icon @click=${() => this._openTabQmail()} id="notification-mail-icon" style="color: var(--black); cursor:pointer;user-select:none">
|
||||||
>mail</mwc-icon
|
mail
|
||||||
>
|
</mwc-icon>
|
||||||
<vaadin-tooltip
|
<vaadin-tooltip
|
||||||
for="notification-mail-icon"
|
for="notification-mail-icon"
|
||||||
position="bottom"
|
position="bottom"
|
||||||
@ -176,17 +60,16 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
hide-delay=${1}
|
hide-delay=${1}
|
||||||
text="Q-Mail">
|
text="Q-Mail">
|
||||||
</vaadin-tooltip>
|
</vaadin-tooltip>
|
||||||
|
|
||||||
`}
|
`}
|
||||||
|
|
||||||
${this.notificationCount ? html`
|
${this.notificationCount ? html`
|
||||||
<span class="count">${this.notifications.length}</span>
|
<span class="count">${this.notifications.length}</span>
|
||||||
` : ''}
|
` : ''}
|
||||||
|
|
||||||
<div class="popover-panel" ?hidden=${!this.showNotifications}>
|
<div class="popover-panel" ?hidden=${!this.showNotifications}>
|
||||||
<div class="notifications-list">
|
<div class="notifications-list">
|
||||||
${this.notifications.map(notification => html`
|
${this.notifications.map(notification => html`
|
||||||
<div class="notification-item" @click=${() => {
|
<div
|
||||||
|
class="notification-item"
|
||||||
|
@click=${() => {
|
||||||
const query = `?service=APP&name=Q-Mail`
|
const query = `?service=APP&name=Q-Mail`
|
||||||
store.dispatch(setNewTab({
|
store.dispatch(setNewTab({
|
||||||
url: `qdn/browser/index.html${query}`,
|
url: `qdn/browser/index.html${query}`,
|
||||||
@ -204,7 +87,8 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
}))
|
}))
|
||||||
this.showNotifications = false
|
this.showNotifications = false
|
||||||
this.notifications = []
|
this.notifications = []
|
||||||
}}>
|
}}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<p>Q-Mail</p>
|
<p>Q-Mail</p>
|
||||||
<message-time timestamp=${notification.created} style="color:red;font-size:12px"></message-time>
|
<message-time timestamp=${notification.created} style="color:red;font-size:12px"></message-time>
|
||||||
@ -220,12 +104,144 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this.getNotifications()
|
||||||
|
|
||||||
|
document.addEventListener('click', (event) => {
|
||||||
|
const path = event.composedPath()
|
||||||
|
if (!path.includes(this)) {
|
||||||
|
this.showNotifications = false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getApiKey() {
|
||||||
|
const apiNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
return apiNode.apiKey
|
||||||
|
}
|
||||||
|
|
||||||
|
async getNotifications() {
|
||||||
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
|
|
||||||
|
let interval = null
|
||||||
|
let stop = false
|
||||||
|
|
||||||
|
const getNewMail = async () => {
|
||||||
|
const getMail = async (recipientName, recipientAddress) => {
|
||||||
|
const query = `qortal_qmail_${recipientName.slice(
|
||||||
|
0,
|
||||||
|
20
|
||||||
|
)}_${recipientAddress.slice(-6)}_mail_`
|
||||||
|
|
||||||
|
const url = `${nodeUrl}/arbitrary/resources/search?service=MAIL_PRIVATE&query=${query}&limit=10&includemetadata=false&offset=0&reverse=true&excludeblocked=true`
|
||||||
|
|
||||||
|
const response = await fetch(url, {
|
||||||
|
method: 'GET',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return await response.json()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stop && !this.showNotifications) {
|
||||||
|
stop = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
const address = window.parent.reduxStore.getState().app?.selectedAddress?.address;
|
||||||
|
const name = window.parent.reduxStore.getState().app?.accountInfo?.names[0]?.name
|
||||||
|
|
||||||
|
if (!name || !address) return
|
||||||
|
|
||||||
|
const mailArray = await getMail(name, address)
|
||||||
|
|
||||||
|
let notificationsToShow = []
|
||||||
|
|
||||||
|
if (mailArray.length > 0) {
|
||||||
|
const lastVisited = localStorage.getItem("Q-Mail-last-visited")
|
||||||
|
|
||||||
|
if (lastVisited) {
|
||||||
|
mailArray.forEach((mail) => {
|
||||||
|
if (mail.created > lastVisited) notificationsToShow.push(mail)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notificationsToShow = mailArray
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.initialFetch && notificationsToShow.length > 0) {
|
||||||
|
const mail = notificationsToShow[0]
|
||||||
|
const urlPic = `${nodeUrl}/arbitrary/THUMBNAIL/${mail.name}/qortal_avatar?async=true}`
|
||||||
|
|
||||||
|
await routes.showNotification({
|
||||||
|
data: {
|
||||||
|
title: 'New Q-Mail',
|
||||||
|
type: 'qapp',
|
||||||
|
sound: config.messageAlert,
|
||||||
|
url: '',
|
||||||
|
options: {
|
||||||
|
body: `You have an unread mail from ${mail.name}`,
|
||||||
|
icon: urlPic,
|
||||||
|
badge: urlPic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else if (notificationsToShow.length > 0) {
|
||||||
|
if (notificationsToShow[0].created > (this.notifications[0]?.created || 0)) {
|
||||||
|
const mail = notificationsToShow[0]
|
||||||
|
const urlPic = `${nodeUrl}/arbitrary/THUMBNAIL/${mail.name}/qortal_avatar?async=true}`
|
||||||
|
|
||||||
|
await routes.showNotification({
|
||||||
|
data: {
|
||||||
|
title: 'New Q-Mail',
|
||||||
|
type: 'qapp',
|
||||||
|
sound: config.messageAlert,
|
||||||
|
url: '',
|
||||||
|
options: {
|
||||||
|
body: `You have an unread mail from ${mail.name}`,
|
||||||
|
icon: urlPic,
|
||||||
|
badge: urlPic
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.notifications = notificationsToShow
|
||||||
|
|
||||||
|
this.notificationCount = this.notifications.length !== 0
|
||||||
|
|
||||||
|
if (!this.initialFetch) this.initialFetch = true
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
stop = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
setTimeout(() => {
|
||||||
|
getNewMail()
|
||||||
|
}, 5000)
|
||||||
|
|
||||||
|
interval = setInterval(getNewMail, 60000)
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_toggleNotifications() {
|
_toggleNotifications() {
|
||||||
if (this.notifications.length === 0) return
|
if (this.notifications.length === 0) return
|
||||||
this.showNotifications = !this.showNotifications
|
this.showNotifications = !this.showNotifications
|
||||||
}
|
}
|
||||||
|
|
||||||
_openTabQmail() {
|
_openTabQmail() {
|
||||||
const query = `?service=APP&name=Q-Mail`
|
const query = `?service=APP&name=Q-Mail`
|
||||||
|
|
||||||
store.dispatch(setNewTab({
|
store.dispatch(setNewTab({
|
||||||
url: `qdn/browser/index.html${query}`,
|
url: `qdn/browser/index.html${query}`,
|
||||||
id: 'q-mail-notification',
|
id: 'q-mail-notification',
|
||||||
@ -241,89 +257,6 @@ class NotificationBell extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
.layout {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.count {
|
|
||||||
position: absolute;
|
|
||||||
top: -5px;
|
|
||||||
right: -5px;
|
|
||||||
font-size: 12px;
|
|
||||||
background-color: red;
|
|
||||||
color: white;
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
user-select: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.nocount {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel {
|
|
||||||
position: absolute;
|
|
||||||
width: 200px;
|
|
||||||
padding: 10px;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 4px;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
top: 40px;
|
|
||||||
max-height: 350px;
|
|
||||||
overflow: auto;
|
|
||||||
scrollbar-width: thin;
|
|
||||||
scrollbar-color: #6a6c75 #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar {
|
|
||||||
width: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-track {
|
|
||||||
background: #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.popover-panel::-webkit-scrollbar-thumb {
|
|
||||||
background-color: #6a6c75;
|
|
||||||
border-radius: 6px;
|
|
||||||
border: 3px solid #a1a1a1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notifications-list {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item {
|
|
||||||
padding: 5px;
|
|
||||||
border-bottom: 1px solid;
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: 0.2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-item:hover {
|
|
||||||
background: var(--nav-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
color: var(--black);
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('notification-bell', NotificationBell)
|
window.customElements.define('notification-bell', NotificationBell)
|
@ -1,44 +1,30 @@
|
|||||||
// popover-component.js
|
import { css, html, LitElement } from 'lit'
|
||||||
import {css, html, LitElement} from 'lit';
|
import { createPopper } from '@popperjs/core'
|
||||||
import {createPopper} from '@popperjs/core';
|
import { popoverComponentStyles } from '../../styles/core-css'
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
export class PopoverComponent extends LitElement {
|
export class PopoverComponent extends LitElement {
|
||||||
static styles = css`
|
static get properties() {
|
||||||
:host {
|
return {
|
||||||
display: none;
|
|
||||||
position: absolute;
|
|
||||||
background-color: var(--white);
|
|
||||||
border: 1px solid #ddd;
|
|
||||||
padding: 8px;
|
|
||||||
z-index: 10;
|
|
||||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
||||||
color: var(--black);
|
|
||||||
max-width: 250px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-icon {
|
|
||||||
cursor: pointer;
|
|
||||||
float: right;
|
|
||||||
margin-left: 10px;
|
|
||||||
color: var(--black)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
`;
|
|
||||||
|
|
||||||
static properties = {
|
|
||||||
for: { type: String, reflect: true },
|
for: { type: String, reflect: true },
|
||||||
message: { type: String }
|
message: { type: String }
|
||||||
};
|
}
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.message = '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
static get styles() {
|
||||||
// We'll defer the popper attachment to the openPopover() method to ensure target availability
|
return [popoverComponentStyles]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.message = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<span class="close-icon" @click="${this.closePopover}"><mwc-icon style="color: var(--black)">close</mwc-icon></span>
|
||||||
|
<div><mwc-icon style="color: var(--black)">info</mwc-icon> ${this.message} <slot></slot></div>
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
attachToTarget(target) {
|
attachToTarget(target) {
|
||||||
@ -46,31 +32,25 @@ export class PopoverComponent extends LitElement {
|
|||||||
this.popperInstance = createPopper(target, this, {
|
this.popperInstance = createPopper(target, this, {
|
||||||
placement: 'bottom',
|
placement: 'bottom',
|
||||||
strategy: 'fixed'
|
strategy: 'fixed'
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
openPopover(target) {
|
openPopover(target) {
|
||||||
this.attachToTarget(target);
|
this.attachToTarget(target)
|
||||||
this.style.display = 'block';
|
this.style.display = 'block'
|
||||||
}
|
}
|
||||||
|
|
||||||
closePopover() {
|
closePopover() {
|
||||||
this.style.display = 'none';
|
this.style.display = 'none'
|
||||||
|
|
||||||
if (this.popperInstance) {
|
if (this.popperInstance) {
|
||||||
this.popperInstance.destroy();
|
this.popperInstance.destroy()
|
||||||
this.popperInstance = null;
|
this.popperInstance = null
|
||||||
}
|
|
||||||
this.requestUpdate();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
this.requestUpdate()
|
||||||
return html`
|
|
||||||
<span class="close-icon" @click="${this.closePopover}"><mwc-icon style="color: var(--black)">close</mwc-icon></span>
|
|
||||||
<div><mwc-icon style="color: var(--black)">info</mwc-icon> ${this.message} <slot></slot>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('popover-component', PopoverComponent);
|
window.customElements.define('popover-component', PopoverComponent)
|
@ -1,97 +1,23 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {svgMoon, svgSun} from '../../assets/js/svg.js'
|
import { svgMoon, svgSun } from '../../assets/js/svg'
|
||||||
|
import { qortThemeToggleStyles } from '../styles/core-css'
|
||||||
|
|
||||||
class QortThemeToggle extends LitElement {
|
class QortThemeToggle extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
theme: {
|
theme: { type: String, reflect: true }
|
||||||
type: String,
|
|
||||||
reflect: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light';
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
static get styles() {
|
||||||
css`
|
return [qortThemeToggleStyles]
|
||||||
:host {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 54px;
|
|
||||||
height: 32px;
|
|
||||||
transform: translateY(-2px);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
svg {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
input {
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
opacity: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.slider {
|
|
||||||
position: absolute;
|
|
||||||
cursor: pointer;
|
|
||||||
width: 100%;
|
|
||||||
height: 16px;
|
|
||||||
top: 50%;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
background-color: var(--switchbackground);
|
|
||||||
border: 2px solid var(--switchborder);
|
|
||||||
border-radius: 1rem;
|
|
||||||
transition: all .4s ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
display: inline-block;
|
|
||||||
position: absolute;
|
|
||||||
top: 50%;
|
|
||||||
background: var(--switchbackground);
|
|
||||||
border: 2px solid var(--switchborder);
|
|
||||||
border-radius: 50%;
|
|
||||||
transition: transform 300ms ease;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="light"]) .icon {
|
|
||||||
transform: translate(0, -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
input:checked ~ .icon,
|
|
||||||
:host([theme="dark"]) .icon {
|
|
||||||
transform: translate(calc(100% - 12px), -50%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.moon {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.moon svg {
|
|
||||||
transform: scale(0.6);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="dark"]) .sun {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="dark"]) .moon {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
];
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<input type="checkbox" @change=${() => this.toggleTheme()}/>
|
<input type="checkbox" @change=${() => this.toggleTheme()}/>
|
||||||
@ -100,35 +26,37 @@ class QortThemeToggle extends LitElement {
|
|||||||
<span class="sun">${svgSun}</span>
|
<span class="sun">${svgSun}</span>
|
||||||
<span class="moon">${svgMoon}</span>
|
<span class="moon">${svgMoon}</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.initTheme();
|
this.initTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
toggleTheme() {
|
toggleTheme() {
|
||||||
if (this.theme === 'light') {
|
if (this.theme === 'light') {
|
||||||
this.theme = 'dark';
|
this.theme = 'dark'
|
||||||
} else {
|
} else {
|
||||||
this.theme = 'light';
|
this.theme = 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('qort-theme-change', {
|
new CustomEvent('qort-theme-change', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: this.theme,
|
detail: this.theme
|
||||||
}),
|
})
|
||||||
);
|
)
|
||||||
|
|
||||||
window.localStorage.setItem('qortalTheme', this.theme);
|
window.localStorage.setItem('qortalTheme', this.theme)
|
||||||
this.initTheme();
|
|
||||||
|
this.initTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
initTheme() {
|
initTheme() {
|
||||||
document.querySelector('html').setAttribute('theme', this.theme);
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('qort-theme-toggle', QortThemeToggle);
|
window.customElements.define('qort-theme-toggle', QortThemeToggle)
|
@ -1,12 +1,14 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {get, translate} from '../../translate'
|
import { searchModalStyles } from '../styles/core-css'
|
||||||
import snackbar from '../functional-components/snackbar.js'
|
import snackbar from '../functional-components/snackbar'
|
||||||
|
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
import '@polymer/iron-icons/iron-icons.js'
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
import '@polymer/paper-dialog/paper-dialog.js'
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
import '@vaadin/text-field'
|
import '@vaadin/text-field'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../translate'
|
||||||
|
|
||||||
class SearchModal extends LitElement {
|
class SearchModal extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -15,56 +17,16 @@ class SearchModal extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [searchModalStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.searchContentString = ''
|
this.searchContentString = ''
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
* {
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
--item-selected-color: var(--nav-selected-color);
|
|
||||||
--item-selected-color-text: var(--nav-selected-color-text);
|
|
||||||
--item-color-active: var(--nav-color-active);
|
|
||||||
--item-color-hover: var(--nav-color-hover);
|
|
||||||
--item-text-color: var(--nav-text-color);
|
|
||||||
--item-icon-color: var(--nav-icon-color);
|
|
||||||
--item-border-color: var(--nav-border-color);
|
|
||||||
--item-border-selected-color: var(--nav-border-selected-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-dialog.searchSettings {
|
|
||||||
min-width: 525px;
|
|
||||||
max-width: 525px;
|
|
||||||
min-height: auto;
|
|
||||||
max-height: 150px;
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--black);
|
|
||||||
line-height: 1.6;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 1px solid var(--black);
|
|
||||||
border-radius: 10px;
|
|
||||||
padding: 15px;
|
|
||||||
box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.search {
|
|
||||||
display: inline;
|
|
||||||
width: 50%;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div style="display: inline;">
|
<div style="display: inline;">
|
||||||
@ -92,6 +54,7 @@ class SearchModal extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
openSearch() {
|
openSearch() {
|
||||||
@ -110,19 +73,24 @@ class SearchModal extends LitElement {
|
|||||||
|
|
||||||
openUserInfo() {
|
openUserInfo() {
|
||||||
const checkvalue = this.shadowRoot.getElementById('searchContent').value
|
const checkvalue = this.shadowRoot.getElementById('searchContent').value
|
||||||
|
|
||||||
if (checkvalue.length < 3) {
|
if (checkvalue.length < 3) {
|
||||||
let snackbar1string = get("publishpage.pchange20")
|
let snackbar1string = get("publishpage.pchange20")
|
||||||
let snackbar2string = get("welcomepage.wcchange4")
|
let snackbar2string = get("welcomepage.wcchange4")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar1string} ${snackbar2string}`,
|
labelText: `${snackbar1string} ${snackbar2string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
this.shadowRoot.getElementById('searchContent').value = this.searchContentString
|
|
||||||
|
|
||||||
|
this.shadowRoot.getElementById('searchContent').value = this.searchContentString
|
||||||
} else {
|
} else {
|
||||||
let sendInfoAddress = this.shadowRoot.getElementById('searchContent').value
|
let sendInfoAddress = this.shadowRoot.getElementById('searchContent').value
|
||||||
|
|
||||||
const infoDialog = document.getElementById('main-app').shadowRoot.querySelector('app-view').shadowRoot.querySelector('user-info-view')
|
const infoDialog = document.getElementById('main-app').shadowRoot.querySelector('app-view').shadowRoot.querySelector('user-info-view')
|
||||||
|
|
||||||
infoDialog.openUserInfo(sendInfoAddress)
|
infoDialog.openUserInfo(sendInfoAddress)
|
||||||
|
|
||||||
this.shadowRoot.getElementById('searchContent').value = this.searchContentString
|
this.shadowRoot.getElementById('searchContent').value = this.searchContentString
|
||||||
this.shadowRoot.getElementById('searchSettingsDialog').close()
|
this.shadowRoot.getElementById('searchSettingsDialog').close()
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,29 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {get, translate} from '../../../translate'
|
import { accountViewStyles } from '../../styles/core-css'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
class AccountView extends connect(store)(LitElement) {
|
class AccountView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
accountInfo: { type: Object },
|
accountInfo: { type: Object },
|
||||||
theme: { type: String, reflect: true },
|
switchAvatar: { type: String },
|
||||||
switchAvatar: { type: String }
|
theme: { type: String, reflect: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [accountViewStyles]
|
||||||
|
|
||||||
.sub-main {
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-box {
|
|
||||||
position: relative;
|
|
||||||
top: 45%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0%);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.img-icon {
|
|
||||||
display: block;
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-box {
|
|
||||||
border: 1px solid #a1a1a1;
|
|
||||||
padding: 10px 25px;
|
|
||||||
text-align: left;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 15px;
|
|
||||||
display: block;
|
|
||||||
line-height: 32px;
|
|
||||||
opacity: 0.66;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
font-size: 16px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#accountName {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight:500;
|
|
||||||
display: inline-block;
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.accountInfo = store.getState().app.accountInfo
|
this.accountInfo = store.getState().app.accountInfo
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
|
||||||
this.switchAvatar = ''
|
this.switchAvatar = ''
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -92,9 +48,10 @@ class AccountView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.getSwitchAvatar()
|
this.getSwitchAvatar()
|
||||||
|
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.getSwitchAvatar()
|
this.getSwitchAvatar()
|
||||||
}, 2000)
|
}, 10000)
|
||||||
}
|
}
|
||||||
|
|
||||||
getAvatar() {
|
getAvatar() {
|
||||||
@ -105,7 +62,8 @@ class AccountView extends connect(store)(LitElement) {
|
|||||||
const avatarName = this.accountInfo.names[0].name
|
const avatarName = this.accountInfo.names[0].name
|
||||||
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
||||||
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${avatarName}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
|
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${avatarName}/qortal_avatar?async=true`
|
||||||
|
|
||||||
return html`<img src="${url}" style="width:150px; height:150px; border-radius: 25%;" onerror="this.src='/img/noavatar_light.png';">`
|
return html`<img src="${url}" style="width:150px; height:150px; border-radius: 25%;" onerror="this.src='/img/noavatar_light.png';">`
|
||||||
}
|
}
|
||||||
} else if (this.switchAvatar === 'dark') {
|
} else if (this.switchAvatar === 'dark') {
|
||||||
@ -115,7 +73,8 @@ class AccountView extends connect(store)(LitElement) {
|
|||||||
const avatarName = this.accountInfo.names[0].name
|
const avatarName = this.accountInfo.names[0].name
|
||||||
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
||||||
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${avatarName}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
|
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${avatarName}/qortal_avatar?async=true`
|
||||||
|
|
||||||
return html`<img src="${url}" style="width:150px; height:150px; border-radius: 25%;" onerror="this.src='/img/noavatar_dark.png';">`
|
return html`<img src="${url}" style="width:150px; height:150px; border-radius: 25%;" onerror="this.src='/img/noavatar_dark.png';">`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,11 +84,6 @@ class AccountView extends connect(store)(LitElement) {
|
|||||||
this.switchAvatar = localStorage.getItem('qortalTheme')
|
this.switchAvatar = localStorage.getItem('qortalTheme')
|
||||||
}
|
}
|
||||||
|
|
||||||
getApiKey() {
|
|
||||||
const apiNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
|
||||||
return apiNode.apiKey
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged(state) {
|
stateChanged(state) {
|
||||||
this.accountInfo = state.app.accountInfo
|
this.accountInfo = state.app.accountInfo
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {Epml} from '../../epml.js'
|
import { Epml } from '../../epml'
|
||||||
import {addTradeBotRoutes} from '../../tradebot/addTradeBotRoutes.js'
|
import { addTradeBotRoutes } from '../../tradebot/addTradeBotRoutes'
|
||||||
import {get, translate} from '../../../translate'
|
import { exportKeysStyles } from '../../styles/core-css'
|
||||||
import snackbar from '../../functional-components/snackbar.js'
|
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
|
import snackbar from '../../functional-components/snackbar'
|
||||||
import '@material/mwc-dialog'
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
|
import '@material/mwc-dialog'
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
|
||||||
|
|
||||||
class ExportKeys extends connect(store)(LitElement) {
|
class ExportKeys extends connect(store)(LitElement) {
|
||||||
@ -51,211 +53,7 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [exportKeysStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-dialog-min-width: 500px;
|
|
||||||
--mdc-dialog-max-width: 750px;
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-box {
|
|
||||||
position: relative;
|
|
||||||
top: 45%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0%);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sub-main {
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
height: auto;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-box {
|
|
||||||
text-align: center;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 400px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
margin-left: 10px;
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.export-button {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding-left: 10px;
|
|
||||||
padding-right: 10px;
|
|
||||||
color: white;
|
|
||||||
background: #03a9f4;
|
|
||||||
width: 75%;
|
|
||||||
font-size: 16px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 40px;
|
|
||||||
margin-top: 1rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all .2s;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
--mdc-theme-primary: #F44336;
|
|
||||||
}
|
|
||||||
|
|
||||||
.green {
|
|
||||||
--mdc-theme-primary: #198754;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.repair-button {
|
|
||||||
height: 40px;
|
|
||||||
padding: 10px 10px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 500;
|
|
||||||
background-color: #03a9f4;
|
|
||||||
color: white;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 20px;
|
|
||||||
text-decoration: none;
|
|
||||||
text-transform: uppercase;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.repair-button:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller {
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
width: 80px;
|
|
||||||
height: 80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div {
|
|
||||||
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
|
||||||
transform-origin: 40px 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:after {
|
|
||||||
content: " ";
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
width: 7px;
|
|
||||||
height: 7px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background: var(--black);
|
|
||||||
margin: -4px 0 0 -4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(1) {
|
|
||||||
animation-delay: -0.036s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(1):after {
|
|
||||||
top: 63px;
|
|
||||||
left: 63px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(2) {
|
|
||||||
animation-delay: -0.072s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(2):after {
|
|
||||||
top: 68px;
|
|
||||||
left: 56px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(3) {
|
|
||||||
animation-delay: -0.108s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(3):after {
|
|
||||||
top: 71px;
|
|
||||||
left: 48px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(4) {
|
|
||||||
animation-delay: -0.144s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(4):after {
|
|
||||||
top: 72px;
|
|
||||||
left: 40px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(5) {
|
|
||||||
animation-delay: -0.18s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(5):after {
|
|
||||||
top: 71px;
|
|
||||||
left: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(6) {
|
|
||||||
animation-delay: -0.216s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(6):after {
|
|
||||||
top: 68px;
|
|
||||||
left: 24px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(7) {
|
|
||||||
animation-delay: -0.252s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(7):after {
|
|
||||||
top: 63px;
|
|
||||||
left: 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(8) {
|
|
||||||
animation-delay: -0.288s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lds-roller div:nth-child(8):after {
|
|
||||||
top: 56px;
|
|
||||||
left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes lds-roller {
|
|
||||||
0% {
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -405,7 +203,16 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
<mwc-dialog id="pleaseWaitDialog" scrimClickAction="" escapeKeyAction="">
|
<mwc-dialog id="pleaseWaitDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
<div class="lds-roller"><div></div><div></div><div></div><div></div><div></div><div></div><div></div><div></div></div>
|
<div class="lds-roller">
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
<div></div>
|
||||||
|
</div>
|
||||||
<h2>${translate("nodepage.nchange41")}</h2>
|
<h2>${translate("nodepage.nchange41")}</h2>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
<mwc-dialog id="okDialog" scrimClickAction="" escapeKeyAction="">
|
<mwc-dialog id="okDialog" scrimClickAction="" escapeKeyAction="">
|
||||||
@ -426,6 +233,7 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
async firstUpdated() {
|
async firstUpdated() {
|
||||||
addTradeBotRoutes(parentEpml)
|
addTradeBotRoutes(parentEpml)
|
||||||
parentEpml.imReady()
|
parentEpml.imReady()
|
||||||
|
|
||||||
await this.fetchArrrWalletAddress()
|
await this.fetchArrrWalletAddress()
|
||||||
await this.checkArrrWalletPrivateKey()
|
await this.checkArrrWalletPrivateKey()
|
||||||
}
|
}
|
||||||
@ -510,6 +318,7 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
async repairLtcWallet() {
|
async repairLtcWallet() {
|
||||||
this.shadowRoot.querySelector('#repairLTCDialog').close()
|
this.shadowRoot.querySelector('#repairLTCDialog').close()
|
||||||
this.shadowRoot.querySelector('#pleaseWaitDialog').show()
|
this.shadowRoot.querySelector('#pleaseWaitDialog').show()
|
||||||
|
|
||||||
let resRepair = await parentEpml.request('apiCall', {
|
let resRepair = await parentEpml.request('apiCall', {
|
||||||
url: `/crosschain/ltc/repair?apiKey=${this.getApiKey()}`,
|
url: `/crosschain/ltc/repair?apiKey=${this.getApiKey()}`,
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -518,24 +327,32 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
if (resRepair != null && resRepair.error != 128) {
|
if (resRepair != null && resRepair.error != 128) {
|
||||||
this.shadowRoot.querySelector('#pleaseWaitDialog').close()
|
this.shadowRoot.querySelector('#pleaseWaitDialog').close()
|
||||||
|
|
||||||
await this.openOkDialog()
|
await this.openOkDialog()
|
||||||
} else {
|
} else {
|
||||||
this.shadowRoot.querySelector('#pleaseWaitDialog').close()
|
this.shadowRoot.querySelector('#pleaseWaitDialog').close()
|
||||||
|
|
||||||
await this.openErrorDialog()
|
await this.openErrorDialog()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async openOkDialog() {
|
async openOkDialog() {
|
||||||
const okDelay = ms => new Promise(res => setTimeout(res, ms))
|
const okDelay = ms => new Promise(res => setTimeout(res, ms))
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#okDialog').show()
|
this.shadowRoot.querySelector('#okDialog').show()
|
||||||
|
|
||||||
await okDelay(3000)
|
await okDelay(3000)
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#okDialog').close()
|
this.shadowRoot.querySelector('#okDialog').close()
|
||||||
}
|
}
|
||||||
|
|
||||||
async openErrorDialog() {
|
async openErrorDialog() {
|
||||||
const errorDelay = ms => new Promise(res => setTimeout(res, ms))
|
const errorDelay = ms => new Promise(res => setTimeout(res, ms))
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#errorDialog').show()
|
this.shadowRoot.querySelector('#errorDialog').show()
|
||||||
|
|
||||||
await errorDelay(3000)
|
await errorDelay(3000)
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#errorDialog').close()
|
this.shadowRoot.querySelector('#errorDialog').close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,12 +369,15 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async exportKey(cMasterKey, cName, cAddress) {
|
async exportKey(cMasterKey, cName, cAddress) {
|
||||||
let exportname = ""
|
let exportname = ''
|
||||||
|
|
||||||
const myPrivateMasterKey = cMasterKey
|
const myPrivateMasterKey = cMasterKey
|
||||||
const myCoinName = cName
|
const myCoinName = cName
|
||||||
const myCoinAddress = cAddress
|
const myCoinAddress = cAddress
|
||||||
const blob = new Blob([`${myPrivateMasterKey}`], { type: 'text/plain;charset=utf-8' })
|
const blob = new Blob([`${myPrivateMasterKey}`], { type: 'text/plain;charset=utf-8' })
|
||||||
exportname = "Private_Master_Key_" + myCoinName + "_" + myCoinAddress + ".txt"
|
|
||||||
|
exportname = 'Private_Master_Key_' + myCoinName + '_' + myCoinAddress + '.txt'
|
||||||
|
|
||||||
await this.saveFileToDisk(blob, exportname)
|
await this.saveFileToDisk(blob, exportname)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -566,16 +386,21 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
const fileHandle = await self.showSaveFilePicker({
|
const fileHandle = await self.showSaveFilePicker({
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
types: [{
|
types: [{
|
||||||
description: "File",
|
description: "File"
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
const writeFile = async (fileHandle, contents) => {
|
const writeFile = async (fileHandle, contents) => {
|
||||||
const writable = await fileHandle.createWritable()
|
const writable = await fileHandle.createWritable()
|
||||||
|
|
||||||
await writable.write(contents)
|
await writable.write(contents)
|
||||||
await writable.close()
|
await writable.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
||||||
|
|
||||||
let snack4string = get("general.save")
|
let snack4string = get("general.save")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack4string} ${fileName} ✅`,
|
labelText: `${snack4string} ${fileName} ✅`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -584,6 +409,7 @@ class ExportKeys extends connect(store)(LitElement) {
|
|||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSaver.saveAs(blob, fileName)
|
FileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {allowShowSyncIndicator, removeShowSyncIndicator} from '../../redux/app/app-actions.js'
|
import { allowShowSyncIndicator, removeShowSyncIndicator } from '../../redux/app/app-actions'
|
||||||
import {doSetQChatNotificationConfig} from '../../redux/user/user-actions.js'
|
import { doSetQChatNotificationConfig } from '../../redux/user/user-actions'
|
||||||
import {translate} from '../../../translate'
|
import { notificationsViewStyles } from '../../styles/core-css'
|
||||||
import isElectron from 'is-electron'
|
import isElectron from 'is-electron'
|
||||||
|
|
||||||
import '@material/mwc-checkbox'
|
import '@material/mwc-checkbox'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
|
||||||
class NotificationsView extends connect(store)(LitElement) {
|
class NotificationsView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -18,130 +20,28 @@ class NotificationsView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [notificationsViewStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.notificationConfig = {}
|
this.notificationConfig = {}
|
||||||
this.q_chatConfig = {}
|
this.q_chatConfig = {}
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
this.appNotificationList = [] // Fetch the list of apps from local storage
|
this.appNotificationList = []
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.appNotificationList = this.getAppsFromStorage()
|
this.appNotificationList = this.getAppsFromStorage()
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css`
|
|
||||||
.sub-main {
|
|
||||||
position: relative;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.notification-box {
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
top: 45%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0%);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media(min-width: 1400px) {
|
|
||||||
.notification-box {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
grid-gap: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.content-box {
|
|
||||||
border: 1px solid #a1a1a1;
|
|
||||||
padding: 10px 25px;
|
|
||||||
text-align: left;
|
|
||||||
display: inline-block;
|
|
||||||
min-width: 350px;
|
|
||||||
min-height: 150px;
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mwc-checkbox::shadow .mdc-checkbox::after, mwc-checkbox::shadow .mdc-checkbox::before {
|
|
||||||
background-color:var(--mdc-theme-primary)
|
|
||||||
}
|
|
||||||
|
|
||||||
label:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.title {
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 15px;
|
|
||||||
display: block;
|
|
||||||
line-height: 32px;
|
|
||||||
opacity: 0.66;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
font-size: 16px;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-button {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding-left: 25px;
|
|
||||||
padding-right: 25px;
|
|
||||||
color: white;
|
|
||||||
background: #03a9f4;
|
|
||||||
width: 50%;
|
|
||||||
font-size: 17px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 50px;
|
|
||||||
margin-top: 1rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all .2s;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.remove-button {
|
|
||||||
font-family: Roboto, sans-serif;
|
|
||||||
font-size: 16px;
|
|
||||||
color: var(--mdc-theme-primary);
|
|
||||||
background-color: transparent;
|
|
||||||
padding: 8px 10px;
|
|
||||||
border-radius: 5px;
|
|
||||||
border: none;
|
|
||||||
transition: all 0.3s ease-in-out;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div class="sub-main">
|
<div class="sub-main">
|
||||||
<div class="notification-box">
|
<div class="notification-box">
|
||||||
<div class="content-box">
|
<div class="content-box">
|
||||||
<h4> Q-Chat ${translate("settings.notifications")} </h4>
|
<h4>Q-Chat ${translate("settings.notifications")}</h4>
|
||||||
|
|
||||||
<div style="line-height: 3rem;">
|
<div style="line-height: 3rem;">
|
||||||
<mwc-checkbox id="qChatPlaySound" @click=${e => this.setQChatNotificationConfig({ type: 'PLAY_SOUND', value: e.target.checked })} ?checked=${this.q_chatConfig.playSound}></mwc-checkbox>
|
<mwc-checkbox id="qChatPlaySound" @click=${e => this.setQChatNotificationConfig({ type: 'PLAY_SOUND', value: e.target.checked })} ?checked=${this.q_chatConfig.playSound}></mwc-checkbox>
|
||||||
<label
|
<label
|
||||||
@ -151,7 +51,6 @@ class NotificationsView extends connect(store)(LitElement) {
|
|||||||
${translate("settings.playsound")}
|
${translate("settings.playsound")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="line-height: 3rem;">
|
<div style="line-height: 3rem;">
|
||||||
<mwc-checkbox id="qChatShowNotification" @click=${e => this.setQChatNotificationConfig({ type: 'SHOW_NOTIFICATION', value: e.target.checked })} ?checked=${this.q_chatConfig.showNotification}></mwc-checkbox>
|
<mwc-checkbox id="qChatShowNotification" @click=${e => this.setQChatNotificationConfig({ type: 'SHOW_NOTIFICATION', value: e.target.checked })} ?checked=${this.q_chatConfig.showNotification}></mwc-checkbox>
|
||||||
<label
|
<label
|
||||||
@ -184,27 +83,29 @@ class NotificationsView extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAppsFromStorage() {
|
getAppsFromStorage() {
|
||||||
// Your method to fetch the list of apps from local storage
|
|
||||||
// Example:
|
|
||||||
const address = store.getState().app.selectedAddress.address
|
const address = store.getState().app.selectedAddress.address
|
||||||
const id = `appNotificationList-${address}`
|
const id = `appNotificationList-${address}`
|
||||||
const data = localStorage.getItem(id)
|
const data = localStorage.getItem(id)
|
||||||
|
|
||||||
return data ? Object.keys(JSON.parse(data)) : []
|
return data ? Object.keys(JSON.parse(data)) : []
|
||||||
}
|
}
|
||||||
|
|
||||||
removeApp(appName) {
|
removeApp(appName) {
|
||||||
// Remove the app from local storage
|
// Remove the app from local storage
|
||||||
this.removeAppFromStorage(appName);
|
this.removeAppFromStorage(appName)
|
||||||
|
|
||||||
// Update the apps list in the component
|
// Update the apps list in the component
|
||||||
this.appNotificationList = this.appNotificationList.filter(app => app !== appName);
|
this.appNotificationList = this.appNotificationList.filter(app => app !== appName)
|
||||||
}
|
}
|
||||||
|
|
||||||
removeAppFromStorage(appName) {
|
removeAppFromStorage(appName) {
|
||||||
// Your method to remove the app from local storage
|
// Your method to remove the app from local storage
|
||||||
const address= store.getState().app.selectedAddress.address
|
const address = store.getState().app.selectedAddress.address
|
||||||
const id = `appNotificationList-${address}`;
|
const id = `appNotificationList-${address}`
|
||||||
const data = JSON.parse(localStorage.getItem(id) || '{}');
|
const data = JSON.parse(localStorage.getItem(id) || '{}')
|
||||||
delete data[appName];
|
|
||||||
|
delete data[appName]
|
||||||
|
|
||||||
localStorage.setItem(id, JSON.stringify(data));
|
localStorage.setItem(id, JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +115,7 @@ class NotificationsView extends connect(store)(LitElement) {
|
|||||||
} else {
|
} else {
|
||||||
return html`
|
return html`
|
||||||
<div style="max-width: 500px; display: flex; justify-content: center; margin: auto;">
|
<div style="max-width: 500px; display: flex; justify-content: center; margin: auto;">
|
||||||
<div @click=${() => this.checkCoreSettings()} class="q-button"> ${translate("settings.core")} </div>
|
<div @click=${() => this.checkCoreSettings()} class="q-button">${translate("settings.core")}</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
@ -243,13 +144,14 @@ class NotificationsView extends connect(store)(LitElement) {
|
|||||||
playSound: !valueObject.value,
|
playSound: !valueObject.value,
|
||||||
showNotification: this.q_chatConfig.showNotification
|
showNotification: this.q_chatConfig.showNotification
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(doSetQChatNotificationConfig(data))
|
store.dispatch(doSetQChatNotificationConfig(data))
|
||||||
} if (valueObject.type === 'SHOW_NOTIFICATION') {
|
} if (valueObject.type === 'SHOW_NOTIFICATION') {
|
||||||
|
|
||||||
let data = {
|
let data = {
|
||||||
playSound: this.q_chatConfig.playSound,
|
playSound: this.q_chatConfig.playSound,
|
||||||
showNotification: !valueObject.value
|
showNotification: !valueObject.value
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(doSetQChatNotificationConfig(data))
|
store.dispatch(doSetQChatNotificationConfig(data))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,83 +1,27 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {translate} from '../../../translate'
|
import { qrLoginViewStyles } from '../../styles/core-css'
|
||||||
|
import '../../../../plugins/plugins/core/components/QortalQrcodeGenerator'
|
||||||
import '@material/mwc-textfield'
|
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
import '@material/mwc-textfield'
|
||||||
import '@vaadin/password-field/vaadin-password-field.js'
|
import '@vaadin/password-field/vaadin-password-field.js'
|
||||||
import '../../../../plugins/plugins/core/components/QortalQrcodeGenerator.js'
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../../translate'
|
||||||
|
|
||||||
class QRLoginView extends connect(store)(LitElement) {
|
class QRLoginView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
theme: { type: String, reflect: true },
|
theme: { type: String, reflect: true },
|
||||||
savedWalletDataJson: { type: String },
|
savedWalletDataJson: { type: String },
|
||||||
translateDescriptionKey: { type: String }, // Description text
|
translateDescriptionKey: { type: String },
|
||||||
translateButtonKey: { type: String }, // Button text
|
translateButtonKey: { type: String }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [qrLoginViewStyles]
|
||||||
* {
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-box {
|
|
||||||
position: relative;
|
|
||||||
top: 45%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0%);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-button {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding-left: 25px;
|
|
||||||
padding-right: 25px;
|
|
||||||
color: white;
|
|
||||||
background: #03a9f4;
|
|
||||||
width: 50%;
|
|
||||||
font-size: 17px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 50px;
|
|
||||||
margin-top: 1rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all .2s;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-button.outlined {
|
|
||||||
background: unset;
|
|
||||||
border: 1px solid #03a9f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="light"]) .q-button.outlined {
|
|
||||||
color: #03a9f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#qr-toggle-button {
|
|
||||||
margin-left: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#login-qr-code {
|
|
||||||
margin: auto;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -94,14 +38,13 @@ class QRLoginView extends connect(store)(LitElement) {
|
|||||||
<p>
|
<p>
|
||||||
${translate(this.translateDescriptionKey)}
|
${translate(this.translateDescriptionKey)}
|
||||||
</p>
|
</p>
|
||||||
<div style="max-width: 500px; justify-content: center; margin: auto; display: ${this.isWalletStored() ? 'none' : 'flex' }">
|
<div style="max-width: 500px; justify-content: center; margin: auto; display: ${this.isWalletStored() ? 'none' : 'flex'}">
|
||||||
<mwc-icon style="padding: 10px; padding-left:0; padding-top: 42px;">password</mwc-icon>
|
<mwc-icon style="padding: 10px; padding-left:0; padding-top: 42px;">password</mwc-icon>
|
||||||
<vaadin-password-field id="newWalletPassword" style="width: 100%; color: var(--black);" label="${translate("settings.password")}" autofocus></vaadin-password-field>
|
<vaadin-password-field id="newWalletPassword" style="width: 100%; color: var(--black);" label="${translate("settings.password")}" autofocus></vaadin-password-field>
|
||||||
</div>
|
</div>
|
||||||
<div style="max-width: 600px; display: flex; justify-content: center; margin: auto;">
|
<div style="max-width: 600px; display: flex; justify-content: center; margin: auto;">
|
||||||
<div id="qr-toggle-button" @click=${() => this.showQRCode()} class="q-button outlined"> ${translate(this.translateButtonKey)} </div>
|
<div id="qr-toggle-button" @click=${() => this.showQRCode()} class="q-button outlined"> ${translate(this.translateButtonKey)} </div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="login-qr-code" style="display: none;">
|
<div id="login-qr-code" style="display: none;">
|
||||||
<qortal-qrcode-generator id="login-qr-code" data="${this.savedWalletDataJson}" mode="octet" format="html" auto></qortal-qrcode-generator>
|
<qortal-qrcode-generator id="login-qr-code" data="${this.savedWalletDataJson}" mode="octet" format="html" auto></qortal-qrcode-generator>
|
||||||
</div>
|
</div>
|
||||||
@ -114,25 +57,33 @@ class QRLoginView extends connect(store)(LitElement) {
|
|||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
const address0 = state.app.wallet._addresses[0].address
|
const address0 = state.app.wallet._addresses[0].address
|
||||||
const savedWalletData = state.user.storedWallets && state.user.storedWallets[address0]
|
const savedWalletData = state.user.storedWallets && state.user.storedWallets[address0]
|
||||||
|
|
||||||
return !!savedWalletData
|
return !!savedWalletData
|
||||||
}
|
}
|
||||||
|
|
||||||
async setSavedWalletDataJson() {
|
async setSavedWalletDataJson() {
|
||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
|
|
||||||
let data
|
let data
|
||||||
if (this.isWalletStored()) { // if the wallet is stored, we use the existing encrypted backup
|
|
||||||
|
if (this.isWalletStored()) {
|
||||||
const address0 = state.app.wallet._addresses[0].address
|
const address0 = state.app.wallet._addresses[0].address
|
||||||
|
|
||||||
data = state.user.storedWallets[address0]
|
data = state.user.storedWallets[address0]
|
||||||
} else { // if the wallet is not stored, we generate new `saveWalletData` backup encrypted with the new password
|
} else {
|
||||||
const password = this.shadowRoot.getElementById('newWalletPassword').value
|
const password = this.shadowRoot.getElementById('newWalletPassword').value
|
||||||
|
|
||||||
data = await state.app.wallet.generateSaveWalletData(password, state.config.crypto.kdfThreads, () => { })
|
data = await state.app.wallet.generateSaveWalletData(password, state.config.crypto.kdfThreads, () => { })
|
||||||
}
|
}
|
||||||
|
|
||||||
this.savedWalletDataJson = JSON.stringify(data)
|
this.savedWalletDataJson = JSON.stringify(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
async showQRCode() {
|
async showQRCode() {
|
||||||
await this.setSavedWalletDataJson()
|
await this.setSavedWalletDataJson()
|
||||||
|
|
||||||
let el = this.shadowRoot.getElementById('login-qr-code')
|
let el = this.shadowRoot.getElementById('login-qr-code')
|
||||||
|
|
||||||
el.style.display = 'flex'
|
el.style.display = 'flex'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {
|
import {
|
||||||
allowQAPPAutoAuth,
|
allowQAPPAutoAuth,
|
||||||
allowQAPPAutoFriendsList,
|
allowQAPPAutoFriendsList,
|
||||||
@ -9,99 +9,29 @@ import {
|
|||||||
removeQAPPAutoFriendsList,
|
removeQAPPAutoFriendsList,
|
||||||
removeQAPPAutoLists,
|
removeQAPPAutoLists,
|
||||||
setIsOpenDevDialog
|
setIsOpenDevDialog
|
||||||
} from '../../redux/app/app-actions.js'
|
} from '../../redux/app/app-actions'
|
||||||
import {get, translate} from '../../../translate'
|
import { securityViewStyles } from '../../styles/core-css'
|
||||||
import snackbar from '../../functional-components/snackbar.js'
|
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
|
import snackbar from '../../functional-components/snackbar'
|
||||||
import '@material/mwc-checkbox'
|
import '@material/mwc-checkbox'
|
||||||
import '@material/mwc-textfield'
|
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
import '@material/mwc-textfield'
|
||||||
import '@vaadin/password-field/vaadin-password-field.js'
|
import '@vaadin/password-field/vaadin-password-field.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../../translate'
|
||||||
|
|
||||||
class SecurityView extends connect(store)(LitElement) {
|
class SecurityView extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
theme: { type: String, reflect: true },
|
theme: { type: String, reflect: true },
|
||||||
backupErrorMessage: { type: String },
|
backupErrorMessage: { type: String },
|
||||||
closeSettings: {attribute: false}
|
closeSettings: { attribute: false }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [securityViewStyles]
|
||||||
* {
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
--mdc-checkbox-unchecked-color: var(--black);
|
|
||||||
--mdc-theme-on-surface: var(--black);
|
|
||||||
--mdc-checkbox-disabled-color: var(--black);
|
|
||||||
--mdc-checkbox-ink-color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.center-box {
|
|
||||||
position: relative;
|
|
||||||
top: 45%;
|
|
||||||
left: 50%;
|
|
||||||
transform: translate(-50%, 0%);
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox-row {
|
|
||||||
position: relative;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
align-content: center;
|
|
||||||
font-family: Montserrat, sans-serif;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.q-button {
|
|
||||||
display: inline-flex;
|
|
||||||
flex-direction: column;
|
|
||||||
justify-content: center;
|
|
||||||
align-content: center;
|
|
||||||
border: none;
|
|
||||||
border-radius: 20px;
|
|
||||||
padding-left: 25px;
|
|
||||||
padding-right: 25px;
|
|
||||||
color: white;
|
|
||||||
background: #03a9f4;
|
|
||||||
width: 50%;
|
|
||||||
font-size: 17px;
|
|
||||||
cursor: pointer;
|
|
||||||
height: 50px;
|
|
||||||
margin-top: 1rem;
|
|
||||||
text-transform: uppercase;
|
|
||||||
text-decoration: none;
|
|
||||||
transition: all .2s;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-dev-button {
|
|
||||||
margin-top: 4px;
|
|
||||||
max-height: 28px;
|
|
||||||
padding: 5px 5px;
|
|
||||||
font-size: 14px;
|
|
||||||
background-color: #03a9f4;
|
|
||||||
color: white;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 3px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-dev-button:hover {
|
|
||||||
opacity: 0.8;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -125,8 +55,7 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
id="downloadBackupPassword"
|
id="downloadBackupPassword"
|
||||||
helper-text="${translate("login.passwordhint")}"
|
helper-text="${translate("login.passwordhint")}"
|
||||||
autofocus
|
autofocus
|
||||||
>
|
></vaadin-password-field>
|
||||||
</vaadin-password-field>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="max-width: 500px; display: flex; justify-content: center; margin: auto;">
|
<div style="max-width: 500px; display: flex; justify-content: center; margin: auto;">
|
||||||
<mwc-icon style="padding: 10px; padding-left:0; padding-top: 42px;">password</mwc-icon>
|
<mwc-icon style="padding: 10px; padding-left:0; padding-top: 42px;">password</mwc-icon>
|
||||||
@ -134,8 +63,7 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
style="width: 100%; color: var(--black);"
|
style="width: 100%; color: var(--black);"
|
||||||
label="${translate("login.confirmpass")}"
|
label="${translate("login.confirmpass")}"
|
||||||
id="rePassword"
|
id="rePassword"
|
||||||
>
|
></vaadin-password-field>
|
||||||
</vaadin-password-field>
|
|
||||||
</div>
|
</div>
|
||||||
<div style="text-align: center; color: var(--mdc-theme-error); text-transform: uppercase; font-size: 15px;">
|
<div style="text-align: center; color: var(--mdc-theme-error); text-transform: uppercase; font-size: 15px;">
|
||||||
${this.backupErrorMessage}
|
${this.backupErrorMessage}
|
||||||
@ -164,11 +92,7 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
<mwc-checkbox style="margin-right: -15px;" id="authButton" @click=${(e) => this.checkForFriends(e)} ?checked=${store.getState().app.qAPPFriendsList}></mwc-checkbox>
|
<mwc-checkbox style="margin-right: -15px;" id="authButton" @click=${(e) => this.checkForFriends(e)} ?checked=${store.getState().app.qAPPFriendsList}></mwc-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="checkbox-row">
|
<div class="checkbox-row">
|
||||||
<button
|
<button class="add-dev-button" title="${translate('tabmenu.tm18')}" @click=${this.openDevDialog}>
|
||||||
class="add-dev-button"
|
|
||||||
title="${translate('tabmenu.tm18')}"
|
|
||||||
@click=${this.openDevDialog}
|
|
||||||
>
|
|
||||||
${translate('tabmenu.tm38')}
|
${translate('tabmenu.tm38')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@ -176,9 +100,6 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
stateChanged(state) {
|
|
||||||
}
|
|
||||||
|
|
||||||
checkForAuth(e) {
|
checkForAuth(e) {
|
||||||
if (e.target.checked) {
|
if (e.target.checked) {
|
||||||
store.dispatch(removeQAPPAutoAuth(false))
|
store.dispatch(removeQAPPAutoAuth(false))
|
||||||
@ -225,13 +146,17 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
async downloadBackup() {
|
async downloadBackup() {
|
||||||
let backupname = ''
|
let backupname = ''
|
||||||
|
|
||||||
this.backupErrorMessage = ''
|
this.backupErrorMessage = ''
|
||||||
|
|
||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
const password = this.shadowRoot.getElementById('downloadBackupPassword').value
|
const password = this.shadowRoot.getElementById('downloadBackupPassword').value
|
||||||
const data = await state.app.wallet.generateSaveWalletData(password, state.config.crypto.kdfThreads, () => { })
|
const data = await state.app.wallet.generateSaveWalletData(password, state.config.crypto.kdfThreads, () => { })
|
||||||
const dataString = JSON.stringify(data)
|
const dataString = JSON.stringify(data)
|
||||||
const blob = new Blob([dataString], { type: 'text/plain;charset=utf-8' })
|
const blob = new Blob([dataString], { type: 'text/plain;charset=utf-8' })
|
||||||
backupname = "qortal_backup_" + state.app.selectedAddress.address + ".json"
|
|
||||||
|
backupname = 'qortal_backup_' + state.app.selectedAddress.address + '.json'
|
||||||
|
|
||||||
await this.saveFileToDisk(blob, backupname)
|
await this.saveFileToDisk(blob, backupname)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -240,26 +165,33 @@ class SecurityView extends connect(store)(LitElement) {
|
|||||||
const fileHandle = await self.showSaveFilePicker({
|
const fileHandle = await self.showSaveFilePicker({
|
||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
types: [{
|
types: [{
|
||||||
description: "File",
|
description: "File"
|
||||||
}]
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
const writeFile = async (fileHandle, contents) => {
|
const writeFile = async (fileHandle, contents) => {
|
||||||
const writable = await fileHandle.createWritable()
|
const writable = await fileHandle.createWritable()
|
||||||
|
|
||||||
await writable.write(contents)
|
await writable.write(contents)
|
||||||
await writable.close()
|
await writable.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
writeFile(fileHandle, blob).then(() => console.log("FILE SAVED"))
|
||||||
|
|
||||||
let snack4string = get("general.save")
|
let snack4string = get("general.save")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack4string} ${fileName} ✅`,
|
labelText: `${snack4string} ${fileName} ✅`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
this.shadowRoot.getElementById('downloadBackupPassword').value = ''
|
this.shadowRoot.getElementById('downloadBackupPassword').value = ''
|
||||||
this.shadowRoot.getElementById('rePassword').value = ''
|
this.shadowRoot.getElementById('rePassword').value = ''
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSaver.saveAs(blob, fileName)
|
FileSaver.saveAs(blob, fileName)
|
||||||
this.shadowRoot.getElementById('downloadBackupPassword').value = ''
|
this.shadowRoot.getElementById('downloadBackupPassword').value = ''
|
||||||
this.shadowRoot.getElementById('rePassword').value = ''
|
this.shadowRoot.getElementById('rePassword').value = ''
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {translate} from '../../../translate'
|
import { userSettingsStyles } from '../../styles/core-css'
|
||||||
|
import './account-view'
|
||||||
import '@polymer/paper-dialog/paper-dialog.js'
|
import './export-keys'
|
||||||
|
import './notifications-view'
|
||||||
|
import './qr-login-view'
|
||||||
|
import './security-view'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
|
||||||
import './account-view.js'
|
// Multi language support
|
||||||
import './security-view.js'
|
import { translate } from '../../../translate'
|
||||||
import './notifications-view.js'
|
|
||||||
import './qr-login-view.js'
|
|
||||||
import './export-keys.js'
|
|
||||||
|
|
||||||
class UserSettings extends connect(store)(LitElement) {
|
class UserSettings extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -23,189 +24,7 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [userSettingsStyles]
|
||||||
:host {
|
|
||||||
margin: 0;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100vw;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 100vh;
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--black);
|
|
||||||
line-height: 1.6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.decline {
|
|
||||||
--mdc-theme-primary: var(--mdc-theme-error)
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-dialog.userSettings {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100vw;
|
|
||||||
height: 100%;
|
|
||||||
max-height: 100vh;
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--black);
|
|
||||||
line-height: 1.6;
|
|
||||||
overflow-y: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display:flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0 4em;
|
|
||||||
margin: 15px 0 -2px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-icon {
|
|
||||||
font-size: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.close-icon:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
opacity: .6;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
max-width: 90vw;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-top: 20px;
|
|
||||||
padding: .6em;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: none;
|
|
||||||
padding: 0;
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar {
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--black);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
padding: 20px 0 0 0;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar img {
|
|
||||||
margin: 0 auto;
|
|
||||||
width: 75%;
|
|
||||||
height: 75%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar .slug {
|
|
||||||
text-align: center;
|
|
||||||
margin-top: 20px;
|
|
||||||
color: var(--black);
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 600;
|
|
||||||
margin-bottom: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li {
|
|
||||||
border-bottom: 1px solid var(--border);
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li a {
|
|
||||||
color: var(--black);
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: 400;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: .9em;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li a i {
|
|
||||||
margin-right: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li a:hover {
|
|
||||||
background-color: var(--menuhover);
|
|
||||||
color: #515151;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li:active {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar ul li a.active {
|
|
||||||
color: #515151;
|
|
||||||
background-color: var(--menuactive);
|
|
||||||
border-left: 2px solid #515151;
|
|
||||||
margin-left: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainPage {
|
|
||||||
background-color: var(--white);
|
|
||||||
color: var(--black);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
padding: 20px 0 10px 0;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-size: 16px;
|
|
||||||
text-align: center;
|
|
||||||
min-height: 460px;
|
|
||||||
height: auto;
|
|
||||||
overflow: auto;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@media(max-width:700px) {
|
|
||||||
.mainPage {
|
|
||||||
margin-top: 30px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media(min-width:765px) {
|
|
||||||
* {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
.actions {
|
|
||||||
display:flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 0 4em;
|
|
||||||
margin: 15px 0 -25px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.container {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 3fr;
|
|
||||||
grid-gap: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.wrapper > .mainPage {
|
|
||||||
padding: 2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.leftBar {
|
|
||||||
text-align: left;
|
|
||||||
max-height: 403px;
|
|
||||||
max-width: 400px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mainPage {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -219,18 +38,18 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
<paper-dialog id="userSettingsDialog" class="userSettings" modal>
|
<paper-dialog id="userSettingsDialog" class="userSettings" modal>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<h2></h2>
|
<h2></h2>
|
||||||
<mwc-icon class="close-icon" @click=${ () => this.closeSettings()} title="Close Settings" >highlight_off</mwc-icon>
|
<mwc-icon class="close-icon" @click=${() => this.closeSettings()} title="Close Settings" >highlight_off</mwc-icon>
|
||||||
</div>
|
</div>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
<div class="leftBar" style="display: table; width: 100%;">
|
<div class="leftBar" style="display: table; width: 100%;">
|
||||||
<div class="slug">Qortal UI ${translate("settings.settings")}</div>
|
<div class="slug">Qortal UI ${translate("settings.settings")}</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li @click=${ () => this.setSettingsView('info')} ><a class=${this.selectedView.id === 'info' ? 'active' : ''} href="javascript:void(0)">${translate("settings.account")}</a></li>
|
<li @click=${() => this.setSettingsView('info')} ><a class=${this.selectedView.id === 'info' ? 'active' : ''} href="javascript:void(0)">${translate("settings.account")}</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('security')} ><a class=${this.selectedView.id === 'security' ? 'active' : ''} href="javascript:void(0)">${translate("settings.security")}</a></li>
|
<li @click=${() => this.setSettingsView('security')} ><a class=${this.selectedView.id === 'security' ? 'active' : ''} href="javascript:void(0)">${translate("settings.security")}</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('export')} ><a class=${this.selectedView.id === 'export' ? 'active' : ''} href="javascript:void(0)">${translate("settings.exp1") }</a></li>
|
<li @click=${() => this.setSettingsView('export')} ><a class=${this.selectedView.id === 'export' ? 'active' : ''} href="javascript:void(0)">${translate("settings.exp1")}</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('qr-login')} ><a class=${this.selectedView.id === 'qr-login' ? 'active' : ''} href="javascript:void(0)">${translate("settings.qr_login_menu_item") }</a></li>
|
<li @click=${() => this.setSettingsView('qr-login')} ><a class=${this.selectedView.id === 'qr-login' ? 'active' : ''} href="javascript:void(0)">${translate("settings.qr_login_menu_item")}</a></li>
|
||||||
<li @click=${ () => this.setSettingsView('notification')} ><a class=${this.selectedView.id === 'notification' ? 'active' : ''} href="javascript:void(0)">${translate("settings.notifications")}</a></li>
|
<li @click=${() => this.setSettingsView('notification')} ><a class=${this.selectedView.id === 'notification' ? 'active' : ''} href="javascript:void(0)">${translate("settings.notifications")}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="mainPage">
|
<div class="mainPage">
|
||||||
@ -252,7 +71,7 @@ class UserSettings extends connect(store)(LitElement) {
|
|||||||
if (selectedView.id === 'info') {
|
if (selectedView.id === 'info') {
|
||||||
return html`<account-view></account-view>`
|
return html`<account-view></account-view>`
|
||||||
} else if (selectedView.id === 'security') {
|
} else if (selectedView.id === 'security') {
|
||||||
return html`<security-view .closeSettings=${()=> this.closeSettings()}></security-view>`
|
return html`<security-view .closeSettings=${() => this.closeSettings()}></security-view>`
|
||||||
} else if (selectedView.id === 'export') {
|
} else if (selectedView.id === 'export') {
|
||||||
return html`<export-keys></export-keys>`
|
return html`<export-keys></export-keys>`
|
||||||
} else if (selectedView.id === 'notification') {
|
} else if (selectedView.id === 'notification') {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,20 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers';
|
import { asyncReplace } from 'lit/directives/async-replace.js'
|
||||||
import {store} from '../store.js';
|
import { connect } from 'pwa-helpers'
|
||||||
import {get, translate} from '../../translate'
|
import { store } from '../store.js'
|
||||||
import {asyncReplace} from 'lit/directives/async-replace.js';
|
import { routes } from '../plugins/routes'
|
||||||
|
import { startMintingStyles } from '../styles/core-css'
|
||||||
import '../functional-components/my-button.js';
|
import '../functional-components/my-button'
|
||||||
import {routes} from '../plugins/routes.js';
|
|
||||||
import "@material/mwc-button"
|
import "@material/mwc-button"
|
||||||
import '@material/mwc-dialog'
|
import '@material/mwc-dialog'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../translate'
|
||||||
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
@ -30,187 +31,56 @@ class StartMinting extends connect(store)(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 [startMintingStyles]
|
||||||
css`
|
|
||||||
p, h1 {
|
|
||||||
color: var(--black)
|
|
||||||
}
|
|
||||||
.dialogCustom {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10000;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
width: 100vw;
|
|
||||||
}
|
|
||||||
.dialogCustomInner {
|
|
||||||
width: 300px;
|
|
||||||
min-height: 400px;
|
|
||||||
background-color: var(--white);
|
|
||||||
box-shadow: var(--mdc-dialog-box-shadow, 0px 11px 15px -7px rgba(0, 0, 0, 0.2), 0px 24px 38px 3px rgba(0, 0, 0, 0.14), 0px 9px 46px 8px rgba(0, 0, 0, 0.12));
|
|
||||||
padding: 20px 24px;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
.dialogCustomInner ul {
|
|
||||||
padding-left: 0px
|
|
||||||
}
|
|
||||||
.dialogCustomInner li {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
.start-minting-wrapper {
|
|
||||||
position: absolute;
|
|
||||||
transform: translate(50%, 20px);
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
.dialog-header h1 {
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
.row {
|
|
||||||
display: flex;
|
|
||||||
width: 100%;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
.modalFooter {
|
|
||||||
width: 100%;
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
}
|
|
||||||
.hide {
|
|
||||||
visibility: hidden
|
|
||||||
}
|
|
||||||
.inactiveText {
|
|
||||||
opacity: .60
|
|
||||||
}
|
|
||||||
.column {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
.smallLoading,
|
|
||||||
.smallLoading:after {
|
|
||||||
border-radius: 50%;
|
|
||||||
width: 2px;
|
|
||||||
height: 2px;
|
|
||||||
}
|
|
||||||
.smallLoading {
|
|
||||||
border-width: 0.6em;
|
|
||||||
border-style: solid;
|
|
||||||
border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2)
|
|
||||||
rgba(3, 169, 244, 0.2) rgb(3, 169, 244);
|
|
||||||
font-size: 10px;
|
|
||||||
position: relative;
|
|
||||||
text-indent: -9999em;
|
|
||||||
transform: translateZ(0px);
|
|
||||||
animation: 1.1s linear 0s infinite normal none running loadingAnimation;
|
|
||||||
}
|
|
||||||
@-webkit-keyframes loadingAnimation {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@keyframes loadingAnimation {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: rotate(0deg);
|
|
||||||
transform: rotate(0deg);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: rotate(360deg);
|
|
||||||
transform: rotate(360deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.word-break {
|
|
||||||
word-break:break-all;
|
|
||||||
}
|
|
||||||
.dialog-container {
|
|
||||||
width: 300px;
|
|
||||||
min-height: 300px;
|
|
||||||
max-height: 75vh;
|
|
||||||
padding: 5px;
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-start;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.between {
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
.no-width {
|
|
||||||
width: auto
|
|
||||||
}
|
|
||||||
.between p {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
.marginLoader {
|
|
||||||
margin-left: 10px;
|
|
||||||
}
|
|
||||||
.marginRight {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.warning{
|
|
||||||
display: flex;
|
|
||||||
flex-grow: 1
|
|
||||||
}
|
|
||||||
.message-error {
|
|
||||||
color: var(--error);
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.addressInfo = {};
|
this.addressInfo = {}
|
||||||
this.mintingAccountData = [];
|
this.mintingAccountData = []
|
||||||
this.errorMsg = '';
|
this.errorMsg = ''
|
||||||
this.openDialogRewardShare = false;
|
this.openDialogRewardShare = false
|
||||||
this.status = 0;
|
this.status = 0
|
||||||
this.privateRewardShareKey = "";
|
this.privateRewardShareKey = ''
|
||||||
this.address = this.getAddress();
|
this.address = this.getAddress()
|
||||||
this.nonce = this.getNonce();
|
this.nonce = this.getNonce()
|
||||||
this.base58PublicKey = this.getBase58PublicKey()
|
this.base58PublicKey = this.getBase58PublicKey()
|
||||||
}
|
}
|
||||||
getBase58PublicKey(){
|
|
||||||
const appState = window.parent.reduxStore.getState().app;
|
|
||||||
const selectedAddress = appState && appState.selectedAddress;
|
|
||||||
const base58PublicKey = selectedAddress && selectedAddress.base58PublicKey;
|
|
||||||
return base58PublicKey || ""
|
|
||||||
}
|
|
||||||
|
|
||||||
getAddress(){
|
|
||||||
const appState = window.parent.reduxStore.getState().app;
|
|
||||||
const selectedAddress = appState && appState.selectedAddress;
|
|
||||||
const address = selectedAddress && selectedAddress.address;
|
|
||||||
return address || ""
|
|
||||||
|
|
||||||
}
|
|
||||||
getNonce(){
|
|
||||||
const appState = window.parent.reduxStore.getState().app;
|
|
||||||
const selectedAddress = appState && appState.selectedAddress;
|
|
||||||
const nonce = selectedAddress && selectedAddress.nonce;
|
|
||||||
return nonce || ""
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html` ${this.renderStartMintingButton()} `;
|
return html`${this.renderStartMintingButton()}`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
this.getMintingAcccounts();
|
this.getMintingAcccounts()
|
||||||
|
}
|
||||||
|
|
||||||
|
getBase58PublicKey() {
|
||||||
|
const appState = window.parent.reduxStore.getState().app
|
||||||
|
const selectedAddress = appState && appState.selectedAddress
|
||||||
|
const base58PublicKey = selectedAddress && selectedAddress.base58PublicKey
|
||||||
|
|
||||||
|
return base58PublicKey || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
getAddress() {
|
||||||
|
const appState = window.parent.reduxStore.getState().app
|
||||||
|
const selectedAddress = appState && appState.selectedAddress
|
||||||
|
const address = selectedAddress && selectedAddress.address
|
||||||
|
|
||||||
|
return address || ''
|
||||||
|
}
|
||||||
|
|
||||||
|
getNonce() {
|
||||||
|
const appState = window.parent.reduxStore.getState().app
|
||||||
|
const selectedAddress = appState && appState.selectedAddress
|
||||||
|
const nonce = selectedAddress && selectedAddress.nonce
|
||||||
|
|
||||||
|
return nonce || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
renderErrorMsg1() {
|
renderErrorMsg1() {
|
||||||
@ -230,124 +100,130 @@ const nonce = selectedAddress && selectedAddress.nonce;
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMintingAcccounts() {
|
async getMintingAcccounts() {
|
||||||
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node];
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
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)
|
||||||
this.mintingAccountData = await res.json();
|
|
||||||
|
this.mintingAccountData = await res.json()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.errorMsg = this.renderErrorMsg1();
|
this.errorMsg = this.renderErrorMsg1()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async changeStatus(value){
|
async changeStatus(value) {
|
||||||
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node];
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
this.status = value
|
|
||||||
const address = this.address
|
const address = this.address
|
||||||
|
|
||||||
|
this.status = value
|
||||||
|
|
||||||
// Check to see if a sponsorship key on a newly-level 1 minter exists. If it does, remove it.
|
// Check to see if a sponsorship key on a newly-level 1 minter exists. If it does, remove it.
|
||||||
const findMintingAccountFromOtherUser = this.mintingAccountData.find((ma) => ma.recipientAccount === address && ma.mintingAccount !== address);
|
const findMintingAccountFromOtherUser = this.mintingAccountData.find((ma) => ma.recipientAccount === address && ma.mintingAccount !== address)
|
||||||
|
|
||||||
const removeMintingAccount = async (publicKey) => {
|
const removeMintingAccount = async (publicKey) => {
|
||||||
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
|
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`
|
||||||
return await fetch(url, {
|
return await fetch(url, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
body: publicKey,
|
body: publicKey
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
const addMintingAccount = async (sponsorshipKeyValue) => {
|
const addMintingAccount = async (sponsorshipKeyValue) => {
|
||||||
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`;
|
const url = `${nodeUrl}/admin/mintingaccounts?apiKey=${myNode.apiKey}`
|
||||||
|
|
||||||
return await fetch(url, {
|
return await fetch(url, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: sponsorshipKeyValue,
|
body: sponsorshipKeyValue
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (
|
if (findMintingAccountFromOtherUser && findMintingAccountFromOtherUser.publicKey && findMintingAccountFromOtherUser.publicKey[0]) {
|
||||||
findMintingAccountFromOtherUser &&
|
|
||||||
findMintingAccountFromOtherUser.publicKey &&
|
|
||||||
findMintingAccountFromOtherUser.publicKey[0]
|
|
||||||
) {
|
|
||||||
await removeMintingAccount(
|
await removeMintingAccount(
|
||||||
findMintingAccountFromOtherUser.publicKey[0]
|
findMintingAccountFromOtherUser.publicKey[0]
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.errorMsg = this.renderErrorMsg2();
|
this.errorMsg = this.renderErrorMsg2()
|
||||||
return;
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await addMintingAccount(this.privateRewardShareKey);
|
await addMintingAccount(this.privateRewardShareKey)
|
||||||
|
|
||||||
await routes.showSnackBar({
|
await routes.showSnackBar({
|
||||||
data: translate('becomeMinterPage.bchange19'),
|
data: translate('becomeMinterPage.bchange19')
|
||||||
});
|
})
|
||||||
this.status = 5;
|
|
||||||
await this.getMintingAcccounts();
|
this.status = 5
|
||||||
|
|
||||||
|
await this.getMintingAcccounts()
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.errorMsg = this.renderErrorMsg3();
|
this.errorMsg = this.renderErrorMsg3()
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async confirmRelationship() {
|
async confirmRelationship() {
|
||||||
const myNode =
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
store.getState().app.nodeConfig.knownNodes[
|
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
|
||||||
store.getState().app.nodeConfig.node
|
|
||||||
];
|
|
||||||
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
|
|
||||||
|
|
||||||
let interval = null
|
let interval = null
|
||||||
let stop = false
|
let stop = false
|
||||||
|
|
||||||
this.status = 2
|
this.status = 2
|
||||||
|
|
||||||
const getAnswer = async () => {
|
const getAnswer = async () => {
|
||||||
const rewardShares = async (minterAddr) => {
|
const rewardShares = async (minterAddr) => {
|
||||||
const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}`;
|
const url = `${nodeUrl}/addresses/rewardshares?minters=${minterAddr}&recipients=${minterAddr}`
|
||||||
const res = await fetch(url);
|
const res = await fetch(url)
|
||||||
return await res.json();
|
|
||||||
};
|
return await res.json()
|
||||||
|
}
|
||||||
|
|
||||||
if (!stop) {
|
if (!stop) {
|
||||||
stop = true;
|
stop = true
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const address = this.address
|
const address = this.address
|
||||||
const myRewardShareArray = await rewardShares(address);
|
const myRewardShareArray = await rewardShares(address)
|
||||||
|
|
||||||
if (myRewardShareArray.length > 0) {
|
if (myRewardShareArray.length > 0) {
|
||||||
clearInterval(interval)
|
clearInterval(interval)
|
||||||
this.status = 3
|
|
||||||
this.timer = countDown(180, () => this.changeStatus(4));
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (error) {
|
this.status = 3
|
||||||
|
this.timer = countDown(180, () => this.changeStatus(4))
|
||||||
}
|
}
|
||||||
|
} catch (error) { }
|
||||||
|
|
||||||
stop = false
|
stop = false
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
interval = setInterval(getAnswer, 5000);
|
|
||||||
|
interval = setInterval(getAnswer, 5000)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderStartMintingButton() {
|
renderStartMintingButton() {
|
||||||
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node];
|
const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
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 = this.address
|
const address = this.address
|
||||||
const nonce = this.nonce
|
const nonce = this.nonce
|
||||||
const publicAddress = this.base58PublicKey
|
const publicAddress = this.base58PublicKey
|
||||||
const findMintingAccount = mintingAccountData.find((ma) => ma.mintingAccount === address);
|
const findMintingAccount = mintingAccountData.find((ma) => ma.mintingAccount === address)
|
||||||
const isMinterButKeyMintingKeyNotAssigned = addressInfo && addressInfo.error !== 124 && addressInfo.level >= 1 && !findMintingAccount;
|
const isMinterButKeyMintingKeyNotAssigned = addressInfo && 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')
|
||||||
let rewarddialog4 = get('transactions.rewarddialog4');
|
let rewarddialog4 = get('transactions.rewarddialog4')
|
||||||
|
|
||||||
return await routes.transaction({
|
return await routes.transaction({
|
||||||
data: {
|
data: {
|
||||||
@ -360,90 +236,93 @@ const nonce = selectedAddress && selectedAddress.nonce;
|
|||||||
rewarddialog1: rewarddialog1,
|
rewarddialog1: rewarddialog1,
|
||||||
rewarddialog2: rewarddialog2,
|
rewarddialog2: rewarddialog2,
|
||||||
rewarddialog3: rewarddialog3,
|
rewarddialog3: rewarddialog3,
|
||||||
rewarddialog4: rewarddialog4,
|
rewarddialog4: rewarddialog4
|
||||||
|
}
|
||||||
},
|
},
|
||||||
},
|
disableModal: true
|
||||||
disableModal: true,
|
})
|
||||||
});
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const getTxnRequestResponse = (txnResponse) => {
|
const getTxnRequestResponse = (txnResponse) => {
|
||||||
let err6string = get('rewardsharepage.rchange21');
|
let err6string = get('rewardsharepage.rchange21')
|
||||||
|
|
||||||
if (txnResponse && txnResponse.extraData && txnResponse.extraData.rewardSharePrivateKey &&
|
if (txnResponse && txnResponse.extraData && txnResponse.extraData.rewardSharePrivateKey &&
|
||||||
txnResponse.data && (txnResponse.data.message && (txnResponse.data.message.includes('multiple') || txnResponse.data.message.includes('SELF_SHARE_EXISTS')))) {
|
txnResponse.data && (txnResponse.data.message && (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 (txnResponse.success === true && txnResponse.data && !txnResponse.data.error) {
|
} else if (txnResponse.success === true && txnResponse.data && !txnResponse.data.error) {
|
||||||
return err6string;
|
return err6string
|
||||||
} else {
|
} else {
|
||||||
throw txnResponse;
|
throw txnResponse
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const createSponsorshipKey = async () => {
|
const createSponsorshipKey = async () => {
|
||||||
this.status = 1;
|
this.status = 1
|
||||||
let lastRef = await getLastRef();
|
|
||||||
let myTransaction = await makeTransactionRequest(lastRef);
|
let lastRef = await getLastRef()
|
||||||
getTxnRequestResponse(myTransaction);
|
let myTransaction = await makeTransactionRequest(lastRef)
|
||||||
|
|
||||||
|
getTxnRequestResponse(myTransaction)
|
||||||
|
|
||||||
if (myTransaction && myTransaction.extraData) {
|
if (myTransaction && myTransaction.extraData) {
|
||||||
return myTransaction.extraData.rewardSharePrivateKey;
|
return myTransaction.extraData.rewardSharePrivateKey
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
const getLastRef = async () => {
|
const getLastRef = async () => {
|
||||||
const url = `${nodeUrl}/addresses/lastreference/${address}`;
|
const url = `${nodeUrl}/addresses/lastreference/${address}`
|
||||||
const res = await fetch(url);
|
const res = await fetch(url)
|
||||||
return await res.text();
|
|
||||||
};
|
return await res.text()
|
||||||
|
}
|
||||||
|
|
||||||
const startMinting = async () => {
|
const startMinting = async () => {
|
||||||
this.openDialogRewardShare = true
|
this.openDialogRewardShare = true
|
||||||
this.errorMsg = '';
|
this.errorMsg = ''
|
||||||
|
|
||||||
const address = this.address
|
const address = this.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()
|
||||||
|
|
||||||
await this.confirmRelationship(publicAddress)
|
await this.confirmRelationship(publicAddress)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log({ error })
|
console.log({ error })
|
||||||
this.errorMsg = (error && error.data && error.data.message) ? error.data.message : this.renderErrorMsg4();
|
|
||||||
|
|
||||||
|
this.errorMsg = (error && error.data && error.data.message) ? error.data.message : this.renderErrorMsg4()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
${isMinterButKeyMintingKeyNotAssigned ? html`
|
${isMinterButKeyMintingKeyNotAssigned ? html`
|
||||||
<div class="start-minting-wrapper">
|
<div class="start-minting-wrapper">
|
||||||
<my-button label="${translate('becomeMinterPage.bchange18')}"
|
<my-button
|
||||||
|
label="${translate('becomeMinterPage.bchange18')}"
|
||||||
?isLoading=${false}
|
?isLoading=${false}
|
||||||
.onClick=${async () => {
|
.onClick=${async () => {
|
||||||
await startMinting();
|
await startMinting();
|
||||||
if (this.errorMsg) {
|
if (this.errorMsg) {
|
||||||
await routes.showSnackBar({
|
await routes.showSnackBar({
|
||||||
data: this.errorMsg,
|
data: this.errorMsg
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
></my-button>
|
||||||
</my-button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Dialog for tracking the progress of starting minting -->
|
<!-- Dialog for tracking the progress of starting minting -->
|
||||||
|
|
||||||
${this.openDialogRewardShare ? html`
|
${this.openDialogRewardShare ? html`
|
||||||
<div class="dialogCustom">
|
<div class="dialogCustom">
|
||||||
<div class="dialogCustomInner">
|
<div class="dialogCustomInner">
|
||||||
@ -457,73 +336,50 @@ const nonce = selectedAddress && selectedAddress.nonce;
|
|||||||
<div class="dialog-container">
|
<div class="dialog-container">
|
||||||
<ul>
|
<ul>
|
||||||
<li class="row between">
|
<li class="row between">
|
||||||
<p>
|
<p>1. ${translate("startminting.smchange5")}</p>
|
||||||
1. ${translate("startminting.smchange5")}
|
|
||||||
</p>
|
|
||||||
<div class=${`smallLoading marginLoader ${this.status !== 1 && 'hide'}`}></div>
|
<div class=${`smallLoading marginLoader ${this.status !== 1 && 'hide'}`}></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class=${`row between ${this.status < 2 && 'inactiveText'}`}>
|
<li class=${`row between ${this.status < 2 && 'inactiveText'}`}>
|
||||||
<p>
|
<p>2. ${translate("startminting.smchange6")}</p>
|
||||||
2. ${translate("startminting.smchange6")}
|
|
||||||
</p>
|
|
||||||
<div class=${`smallLoading marginLoader ${this.status !== 2 && 'hide'}`}></div>
|
<div class=${`smallLoading marginLoader ${this.status !== 2 && 'hide'}`}></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class=${`row between ${this.status < 3 && 'inactiveText'}`}>
|
<li class=${`row between ${this.status < 3 && 'inactiveText'}`}>
|
||||||
<p>
|
<p>3. ${translate("startminting.smchange7")}</p>
|
||||||
3. ${translate("startminting.smchange7")}
|
|
||||||
</p>
|
|
||||||
<div class="row no-width">
|
<div class="row no-width">
|
||||||
<div class=${`smallLoading marginLoader marginRight ${this.status !== 3 && 'hide'}`} ></div> <p>${asyncReplace(this.timer)}</p>
|
<div class=${`smallLoading marginLoader marginRight ${this.status !== 3 && 'hide'}`} ></div>
|
||||||
|
<p>${asyncReplace(this.timer)}</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class=${`row between ${this.status < 4 && 'inactiveText'}`}>
|
<li class=${`row between ${this.status < 4 && 'inactiveText'}`}>
|
||||||
<p>
|
<p>4. ${translate("startminting.smchange8")}</p>
|
||||||
4. ${translate("startminting.smchange8")}
|
|
||||||
</p>
|
|
||||||
<div class=${`smallLoading marginLoader ${this.status !== 4 && 'hide'}`}></div>
|
<div class=${`smallLoading marginLoader ${this.status !== 4 && 'hide'}`}></div>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class=${`row between ${this.status < 5 && 'inactiveText'}`}>
|
<li class=${`row between ${this.status < 5 && 'inactiveText'}`}>
|
||||||
<p>
|
<p>5. ${translate("startminting.smchange9")}</p>
|
||||||
5. ${translate("startminting.smchange9")}
|
|
||||||
</p>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="warning column">
|
<div class="warning column">
|
||||||
<p>
|
<p>Warning: do not close the Qortal UI until completion!</p>
|
||||||
Warning: do not close the Qortal UI until completion!
|
|
||||||
</p>
|
|
||||||
<p class="message-error">${this.errorMsg}</p>
|
<p class="message-error">${this.errorMsg}</p>
|
||||||
</div>
|
</div>
|
||||||
</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" @click=${() => { this.openDialogRewardShare = false; this.errorMsg = '';}} class="red">
|
||||||
slot="primaryAction"
|
|
||||||
@click=${() => {
|
|
||||||
this.openDialogRewardShare = false
|
|
||||||
this.errorMsg = ''
|
|
||||||
}}
|
|
||||||
class="red"
|
|
||||||
>
|
|
||||||
${translate("general.close")}
|
${translate("general.close")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
` : '' }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
` : ""}
|
|
||||||
` : ''}
|
` : ''}
|
||||||
`;
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
|
` : ''}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
stateChanged(state) {
|
stateChanged(state) {
|
||||||
this.addressInfo = state.app.accountInfo.addressInfo;
|
this.addressInfo = state.app.accountInfo.addressInfo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('start-minting', StartMinting);
|
window.customElements.define('start-minting', StartMinting)
|
@ -1,9 +1,12 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {translate} from '../../translate'
|
import { themeToggleStyles } from '../styles/core-css'
|
||||||
import '@polymer/paper-icon-button/paper-icon-button.js'
|
import '@polymer/paper-icon-button/paper-icon-button.js'
|
||||||
import '@polymer/iron-icons/image-icons.js'
|
import '@polymer/iron-icons/image-icons.js'
|
||||||
import '@polymer/iron-icons/iron-icons.js'
|
import '@polymer/iron-icons/iron-icons.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../translate'
|
||||||
|
|
||||||
class ThemeToggle extends LitElement {
|
class ThemeToggle extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
@ -11,58 +14,15 @@ class ThemeToggle extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [themeToggleStyles]
|
||||||
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
static styles = [
|
|
||||||
css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-error: rgb(255, 89, 89);
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--lumo-secondary-text-color: var(--sectxt);
|
|
||||||
--lumo-contrast-60pct: var(--vdicon);
|
|
||||||
--item-selected-color: var(--nav-selected-color);
|
|
||||||
--item-selected-color-text: var(--nav-selected-color-text);
|
|
||||||
--item-color-active: var(--nav-color-active);
|
|
||||||
--item-color-hover: var(--nav-color-hover);
|
|
||||||
--item-text-color: var(--nav-text-color);
|
|
||||||
--item-icon-color: var(--nav-icon-color);
|
|
||||||
--item-border-color: var(--nav-border-color);
|
|
||||||
--item-border-selected-color: var(--nav-border-selected-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
paper-icon-button {
|
|
||||||
-ms-transform: rotate(120deg);
|
|
||||||
transform: rotate(120deg);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="light"]) .light-mode {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="light"]) .dark-mode {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="dark"]) .light-mode {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([theme="dark"]) .dark-mode {
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
]
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<div style="display: inline;">
|
<div style="display: inline;">
|
||||||
@ -87,16 +47,17 @@ class ThemeToggle extends LitElement {
|
|||||||
this.dispatchEvent(new CustomEvent('qort-theme-change', {
|
this.dispatchEvent(new CustomEvent('qort-theme-change', {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
detail: this.theme,
|
detail: this.theme
|
||||||
}))
|
}))
|
||||||
|
|
||||||
window.localStorage.setItem('qortalTheme', this.theme)
|
window.localStorage.setItem('qortalTheme', this.theme)
|
||||||
|
|
||||||
this.initTheme()
|
this.initTheme()
|
||||||
}
|
}
|
||||||
|
|
||||||
initTheme() {
|
initTheme() {
|
||||||
document.querySelector('html').setAttribute('theme', this.theme);
|
document.querySelector('html').setAttribute('theme', this.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('theme-toggle', ThemeToggle);
|
window.customElements.define('theme-toggle', ThemeToggle)
|
File diff suppressed because it is too large
Load Diff
@ -1,7 +1,10 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {translate} from '../../translate'
|
import { walletProfileStyles } from '../styles/core-css'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../translate'
|
||||||
|
|
||||||
class WalletProfile extends connect(store)(LitElement) {
|
class WalletProfile extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -14,56 +17,7 @@ class WalletProfile extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [walletProfileStyles]
|
||||||
#profileInMenu {
|
|
||||||
padding: 12px;
|
|
||||||
border-top: var(--border);
|
|
||||||
background: var(--sidetopbar);
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
#accountName {
|
|
||||||
margin: 0;
|
|
||||||
font-size: 18px;
|
|
||||||
font-weight: 500;
|
|
||||||
width: 100%;
|
|
||||||
padding-bottom: 8px;
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
#blocksMinted {
|
|
||||||
margin:0;
|
|
||||||
margin-top: 0;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #03a9f4;
|
|
||||||
}
|
|
||||||
|
|
||||||
#address {
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
margin:0;
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.round-fullinfo {
|
|
||||||
position: relative;
|
|
||||||
width: 68px;
|
|
||||||
height: 68px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.full-info-logo {
|
|
||||||
width: 68px;
|
|
||||||
height: 68px;
|
|
||||||
border-radius: 50%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.inline-block-child {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -85,8 +39,16 @@ class WalletProfile extends connect(store)(LitElement) {
|
|||||||
<div id="child inline-block-child" class="full-info-logo">${this.getAvatar()}</div>
|
<div id="child inline-block-child" class="full-info-logo">${this.getAvatar()}</div>
|
||||||
|
|
||||||
<div id="inline-block-child">
|
<div id="inline-block-child">
|
||||||
<div>${this.accountInfo.names.length !== 0 ? this.accountInfo.names[0].name : ''}</div>
|
<div>
|
||||||
<div>${this.accountInfo.addressInfo ? html`<span style="margin-bottom: 8px; display: inline-block; font-size: 14px;">${translate("walletprofile.minterlevel")} - <span style="color: #03a9f4;">${this.accountInfo.addressInfo.level} ${this.accountInfo.addressInfo.flags === 1 ? html`<strong>(F)</strong>` : ''}</span>` : ''}</div>
|
${this.accountInfo.names.length !== 0 ? this.accountInfo.names[0].name : ''}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
${this.accountInfo.addressInfo ? html`
|
||||||
|
<span style="margin-bottom: 8px; display: inline-block; font-size: 14px;">
|
||||||
|
${translate("walletprofile.minterlevel")} - <span style="color: #03a9f4;">${this.accountInfo.addressInfo.level} ${this.accountInfo.addressInfo.flags === 1 ? html`<strong>(F)</strong>` : ''}
|
||||||
|
</span>
|
||||||
|
` : ''}
|
||||||
|
</div>
|
||||||
<p id="blocksMinted">${translate("walletprofile.blocksminted")} - ${this.accountInfo.addressInfo.blocksMinted + this.accountInfo.addressInfo.blocksMintedAdjustment}</p>
|
<p id="blocksMinted">${translate("walletprofile.blocksminted")} - ${this.accountInfo.addressInfo.blocksMinted + this.accountInfo.addressInfo.blocksMintedAdjustment}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -96,7 +58,9 @@ class WalletProfile extends connect(store)(LitElement) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated() {}
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
getAvatar() {
|
getAvatar() {
|
||||||
if (this.accountInfo.names.length === 0) {
|
if (this.accountInfo.names.length === 0) {
|
||||||
@ -104,16 +68,12 @@ class WalletProfile extends connect(store)(LitElement) {
|
|||||||
} else {
|
} else {
|
||||||
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
const avatarNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
||||||
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
const avatarUrl = avatarNode.protocol + '://' + avatarNode.domain + ':' + avatarNode.port
|
||||||
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${this.accountInfo.names[0].name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
|
const url = `${avatarUrl}/arbitrary/THUMBNAIL/${this.accountInfo.names[0].name}/qortal_avatar?async=true`
|
||||||
|
|
||||||
return html`<img class="round-fullinfo" src="${url}" onerror="this.src='/img/incognito.png';" />`
|
return html`<img class="round-fullinfo" src="${url}" onerror="this.src='/img/incognito.png';" />`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getApiKey() {
|
|
||||||
const apiNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]
|
|
||||||
return apiNode.apiKey
|
|
||||||
}
|
|
||||||
|
|
||||||
stateChanged(state) {
|
stateChanged(state) {
|
||||||
this.wallet = state.app.wallet
|
this.wallet = state.app.wallet
|
||||||
this.nodeConfig = state.app.nodeConfig
|
this.nodeConfig = state.app.nodeConfig
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
'use strict'
|
|
||||||
const utils = {
|
const utils = {
|
||||||
int32ToBytes (word) {
|
int32ToBytes(word) {
|
||||||
var byteArray = []
|
var byteArray = []
|
||||||
for (var b = 0; b < 32; b += 8) {
|
for (var b = 0; b < 32; b += 8) {
|
||||||
byteArray.push((word >>> (24 - b % 32)) & 0xFF)
|
byteArray.push((word >>> (24 - b % 32)) & 0xFF)
|
||||||
@ -8,7 +7,7 @@ const utils = {
|
|||||||
return byteArray
|
return byteArray
|
||||||
},
|
},
|
||||||
|
|
||||||
stringtoUTF8Array (message) {
|
stringtoUTF8Array(message) {
|
||||||
if (typeof message === 'string') {
|
if (typeof message === 'string') {
|
||||||
var s = unescape(encodeURIComponent(message)) // UTF-8
|
var s = unescape(encodeURIComponent(message)) // UTF-8
|
||||||
message = new Uint8Array(s.length)
|
message = new Uint8Array(s.length)
|
||||||
@ -16,19 +15,24 @@ const utils = {
|
|||||||
message[i] = s.charCodeAt(i) & 0xff
|
message[i] = s.charCodeAt(i) & 0xff
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return message
|
return message
|
||||||
},
|
},
|
||||||
|
|
||||||
// ...buffers then buffers.foreach and append to buffer1
|
// ...buffers then buffers.foreach and append to buffer1
|
||||||
appendBuffer (buffer1, buffer2) {
|
appendBuffer(buffer1, buffer2) {
|
||||||
buffer1 = new Uint8Array(buffer1)
|
buffer1 = new Uint8Array(buffer1)
|
||||||
buffer2 = new Uint8Array(buffer2)
|
buffer2 = new Uint8Array(buffer2)
|
||||||
|
|
||||||
const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
|
const tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength)
|
||||||
|
|
||||||
tmp.set(buffer1, 0)
|
tmp.set(buffer1, 0)
|
||||||
tmp.set(buffer2, buffer1.byteLength)
|
tmp.set(buffer2, buffer1.byteLength)
|
||||||
|
|
||||||
return tmp
|
return tmp
|
||||||
},
|
},
|
||||||
|
|
||||||
int64ToBytes (int64) {
|
int64ToBytes(int64) {
|
||||||
// we want to represent the input as a 8-bytes array
|
// we want to represent the input as a 8-bytes array
|
||||||
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]
|
var byteArray = [0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
|
||||||
@ -41,13 +45,16 @@ const utils = {
|
|||||||
return byteArray
|
return byteArray
|
||||||
},
|
},
|
||||||
|
|
||||||
equal (buf1, buf2) {
|
equal(buf1, buf2) {
|
||||||
if (buf1.byteLength != buf2.byteLength) return false
|
if (buf1.byteLength != buf2.byteLength) return false
|
||||||
|
|
||||||
var dv1 = new Uint8Array(buf1)
|
var dv1 = new Uint8Array(buf1)
|
||||||
var dv2 = new Uint8Array(buf2)
|
var dv2 = new Uint8Array(buf2)
|
||||||
|
|
||||||
for (var i = 0; i != buf1.byteLength; i++) {
|
for (var i = 0; i != buf1.byteLength; i++) {
|
||||||
if (dv1[i] != dv2[i]) return false
|
if (dv1[i] != dv2[i]) return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,115 +0,0 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
|
||||||
|
|
||||||
import '@material/mwc-button'
|
|
||||||
import '@material/mwc-icon'
|
|
||||||
|
|
||||||
import {translate} from '../../translate'
|
|
||||||
|
|
||||||
class FragFileInput extends LitElement {
|
|
||||||
static get properties () {
|
|
||||||
return {
|
|
||||||
accept: { type: String },
|
|
||||||
readAs: { type: String }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles () {
|
|
||||||
return css`
|
|
||||||
#drop-area {
|
|
||||||
border: 2px dashed #ccc;
|
|
||||||
font-family: "Roboto", sans-serif;
|
|
||||||
padding: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#trigger:hover {
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
#drop-area.highlight {
|
|
||||||
border-color: var(--mdc-theme-primary, #000);
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-top: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
form {
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#fileInput {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor () {
|
|
||||||
super()
|
|
||||||
this.readAs = this.readAs || 'Text'
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return html`
|
|
||||||
<div id="drop-area">
|
|
||||||
<slot name="info-text"></slot>
|
|
||||||
<div style="line-height: 40px; text-align: center;">
|
|
||||||
<slot id="trigger" name="inputTrigger" @click=${() => this.shadowRoot.getElementById('fileInput').click()} style="dispay:inline;">
|
|
||||||
<mwc-button><mwc-icon>cloud_upload</mwc-icon><span style="color: var(--black);"> ${translate("fragfile.selectfile")}</span></mwc-button>
|
|
||||||
</slot><br>
|
|
||||||
<span style="text-align: center; padding-top: 4px; color: var(--black);">${translate("fragfile.dragfile")}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input type="file" id="fileInput" accept="${this.accept}" @change="${e => this.readFile(e.target.files[0])}">
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
readFile (file) {
|
|
||||||
const fr = new FileReader()
|
|
||||||
fr.onload = () => {
|
|
||||||
this.dispatchEvent(new CustomEvent('file-read-success', {
|
|
||||||
detail: { result: fr.result },
|
|
||||||
bubbles: true,
|
|
||||||
composed: true
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
fr['readAs' + this.readAs](file)
|
|
||||||
}
|
|
||||||
|
|
||||||
firstUpdated () {
|
|
||||||
this._dropArea = this.shadowRoot.getElementById('drop-area')
|
|
||||||
|
|
||||||
const preventDefaults = e => {
|
|
||||||
e.preventDefault()
|
|
||||||
e.stopPropagation()
|
|
||||||
}
|
|
||||||
|
|
||||||
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
|
||||||
this._dropArea.addEventListener(eventName, preventDefaults, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
const highlight = e => {
|
|
||||||
this._dropArea.classList.add('highlight')
|
|
||||||
}
|
|
||||||
|
|
||||||
const unhighlight = e => {
|
|
||||||
this._dropArea.classList.remove('highlight')
|
|
||||||
}
|
|
||||||
|
|
||||||
;['dragenter', 'dragover'].forEach(eventName => {
|
|
||||||
this._dropArea.addEventListener(eventName, highlight, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
;['dragleave', 'drop'].forEach(eventName => {
|
|
||||||
this._dropArea.addEventListener(eventName, unhighlight, false)
|
|
||||||
})
|
|
||||||
|
|
||||||
this._dropArea.addEventListener('drop', e => {
|
|
||||||
const dt = e.dataTransfer
|
|
||||||
const file = dt.files[0]
|
|
||||||
|
|
||||||
this.readFile(file)
|
|
||||||
}, false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.customElements.define('frag-file-input', FragFileInput)
|
|
@ -1,4 +1,15 @@
|
|||||||
export const defaultQappsTabs = [
|
export const defaultQappsTabs = [
|
||||||
|
{
|
||||||
|
"url": "myapp",
|
||||||
|
"domain": "core",
|
||||||
|
"page": "qdn/browser/index.html?name=Q-Support&service=APP",
|
||||||
|
"title": "Q-Support",
|
||||||
|
"icon": "vaadin:external-browser",
|
||||||
|
"mwcicon": "apps",
|
||||||
|
"pluginNumber": "plugin-04tlGdLkkd",
|
||||||
|
"menus": [],
|
||||||
|
"parent": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"url": "myapp",
|
"url": "myapp",
|
||||||
"domain": "core",
|
"domain": "core",
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { css, html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {get, translate} from '../../translate'
|
import { listenForRequest } from '../transactionRequest'
|
||||||
|
import { confirmTransactionDialogStyles } from '../styles/core-css'
|
||||||
import {listenForRequest} from '../transactionRequest.js'
|
|
||||||
|
|
||||||
import '@polymer/paper-dialog/paper-dialog.js'
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
|
import '@polymer/paper-dialog/paper-dialog.js'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, translate } from '../../translate'
|
||||||
|
|
||||||
class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
@ -17,35 +18,7 @@ class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [confirmTransactionDialogStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.decline {
|
|
||||||
--mdc-theme-primary: var(--mdc-theme-error)
|
|
||||||
}
|
|
||||||
|
|
||||||
#txInfo {
|
|
||||||
text-align: left;
|
|
||||||
max-width: 520px;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttons {
|
|
||||||
text-align:right;
|
|
||||||
}
|
|
||||||
|
|
||||||
table td, th{
|
|
||||||
padding:4px;
|
|
||||||
text-align:left;
|
|
||||||
font-size:14px;
|
|
||||||
color: var(--black);
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -55,7 +28,7 @@ class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
this.txInfo = html``
|
this.txInfo = html``
|
||||||
listenForRequest(args => this.requestTransaction(args))
|
listenForRequest(args => this.requestTransaction(args))
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light';
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -73,8 +46,8 @@ class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
stateChanged(state) {
|
firstUpdated() {
|
||||||
this.loggedIn = state.app.loggedIn
|
// ...
|
||||||
}
|
}
|
||||||
|
|
||||||
requestTransaction(transaction) {
|
requestTransaction(transaction) {
|
||||||
@ -98,6 +71,10 @@ class ConfirmTransactionDialog extends connect(store)(LitElement) {
|
|||||||
const rejecterror = get("transactions.declined")
|
const rejecterror = get("transactions.declined")
|
||||||
this._reject(new Error(rejecterror))
|
this._reject(new Error(rejecterror))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
this.loggedIn = state.app.loggedIn
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('confirm-transaction-dialog', ConfirmTransactionDialog)
|
window.customElements.define('confirm-transaction-dialog', ConfirmTransactionDialog)
|
||||||
|
93
core/src/functional-components/frag-file-input.js
Normal file
93
core/src/functional-components/frag-file-input.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
import { html, LitElement } from 'lit'
|
||||||
|
import { fragFileInputStyles } from '../styles/core-css'
|
||||||
|
import '@material/mwc-button'
|
||||||
|
import '@material/mwc-icon'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { translate } from '../../translate'
|
||||||
|
|
||||||
|
class FragFileInput extends LitElement {
|
||||||
|
static get properties() {
|
||||||
|
return {
|
||||||
|
accept: { type: String },
|
||||||
|
readAs: { type: String }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles() {
|
||||||
|
return [fragFileInputStyles]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
this.readAs = this.readAs || 'Text'
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<div id="drop-area">
|
||||||
|
<slot name="info-text"></slot>
|
||||||
|
<div style="line-height: 40px; text-align: center;">
|
||||||
|
<slot id="trigger" name="inputTrigger" @click=${() => this.shadowRoot.getElementById('fileInput').click()} style="dispay:inline;">
|
||||||
|
<mwc-button><mwc-icon>cloud_upload</mwc-icon><span style="color: var(--black);"> ${translate("fragfile.selectfile")}</span></mwc-button>
|
||||||
|
</slot>
|
||||||
|
<br>
|
||||||
|
<span style="text-align: center; padding-top: 4px; color: var(--black);">${translate("fragfile.dragfile")}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="file" id="fileInput" accept="${this.accept}" @change="${e => this.readFile(e.target.files[0])}">
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
this._dropArea = this.shadowRoot.getElementById('drop-area')
|
||||||
|
|
||||||
|
const preventDefaults = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
|
||||||
|
;['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
|
||||||
|
this._dropArea.addEventListener(eventName, preventDefaults, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
const highlight = e => {
|
||||||
|
this._dropArea.classList.add('highlight')
|
||||||
|
}
|
||||||
|
|
||||||
|
const unhighlight = e => {
|
||||||
|
this._dropArea.classList.remove('highlight')
|
||||||
|
}
|
||||||
|
|
||||||
|
;['dragenter', 'dragover'].forEach(eventName => {
|
||||||
|
this._dropArea.addEventListener(eventName, highlight, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
;['dragleave', 'drop'].forEach(eventName => {
|
||||||
|
this._dropArea.addEventListener(eventName, unhighlight, false)
|
||||||
|
})
|
||||||
|
|
||||||
|
this._dropArea.addEventListener('drop', e => {
|
||||||
|
const dt = e.dataTransfer
|
||||||
|
const file = dt.files[0]
|
||||||
|
|
||||||
|
this.readFile(file)
|
||||||
|
}, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
readFile(file) {
|
||||||
|
const fr = new FileReader()
|
||||||
|
|
||||||
|
fr.onload = () => {
|
||||||
|
this.dispatchEvent(new CustomEvent('file-read-success', {
|
||||||
|
detail: { result: fr.result },
|
||||||
|
bubbles: true,
|
||||||
|
composed: true
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fr['readAs' + this.readAs](file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.customElements.define('frag-file-input', FragFileInput)
|
@ -1,109 +1,29 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
|
import { loadingRippleStyles } from '../styles/core-css'
|
||||||
|
|
||||||
const TRANSITION_EVENT_NAMES = ['transitionend', 'webkitTransitionEnd', 'oTransitionEnd', 'MSTransitionEnd']
|
const TRANSITION_EVENT_NAMES = ['transitionend', 'webkitTransitionEnd', 'oTransitionEnd', 'MSTransitionEnd']
|
||||||
|
|
||||||
let rippleElement
|
let rippleElement
|
||||||
|
|
||||||
class LoadingRipple extends LitElement {
|
class LoadingRipple extends LitElement {
|
||||||
static get properties () {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
welcomeMessage: {
|
welcomeMessage: { type: String, attribute: 'welcome-message', reflectToAttribute: true },
|
||||||
type: String,
|
loadingMessage: { type: String, attribute: 'loading-message', reflectToAttribute: true}
|
||||||
attribute: 'welcome-message',
|
|
||||||
reflectToAttribute: true
|
|
||||||
},
|
|
||||||
loadingMessage: {
|
|
||||||
type: String,
|
|
||||||
attribute: 'loading-message',
|
|
||||||
reflectToAttribute: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor () {
|
static get styles() {
|
||||||
|
return [loadingRippleStyles]
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.welcomeMessage = ''
|
this.welcomeMessage = ''
|
||||||
this.loadingMessage = ''
|
this.loadingMessage = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles () {
|
render() {
|
||||||
return css`
|
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--paper-spinner-color: var(--mdc-theme-secondary);
|
|
||||||
}
|
|
||||||
|
|
||||||
#rippleWrapper{
|
|
||||||
position:fixed;
|
|
||||||
top:0;
|
|
||||||
left:0;
|
|
||||||
bottom:0;
|
|
||||||
right:0;
|
|
||||||
height:0;
|
|
||||||
width:0;
|
|
||||||
z-index:999;
|
|
||||||
overflow: visible;
|
|
||||||
--ripple-activating-transition: transform 0.3s cubic-bezier(0.6, 0.0, 1, 1), opacity 0.3s cubic-bezier(0.6, 0.0, 1, 1);
|
|
||||||
--ripple-disable-transition: opacity 0.5s ease;
|
|
||||||
}
|
|
||||||
#ripple {
|
|
||||||
border-radius:50%;
|
|
||||||
border-width:0;
|
|
||||||
margin-left:-100vmax;
|
|
||||||
margin-top: -100vmax;
|
|
||||||
height:200vmax;
|
|
||||||
width:200vmax;
|
|
||||||
overflow:hidden;
|
|
||||||
background: var(--black);
|
|
||||||
transform: scale(0);
|
|
||||||
overflow:hidden;
|
|
||||||
}
|
|
||||||
#ripple.error {
|
|
||||||
transition: var(--ripple-activating-transition);
|
|
||||||
background: var(--mdc-theme-error)
|
|
||||||
}
|
|
||||||
#rippleShader {
|
|
||||||
background: var(--white);
|
|
||||||
opacity:0;
|
|
||||||
height:100%;
|
|
||||||
width:100%;
|
|
||||||
}
|
|
||||||
#ripple.activating{
|
|
||||||
transition: var(--ripple-activating-transition);
|
|
||||||
transform: scale(1)
|
|
||||||
}
|
|
||||||
.activating #rippleShader {
|
|
||||||
transition: var(--ripple-activating-transition);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
#ripple.disabling{
|
|
||||||
transition: var(--ripple-disable-transition);
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
#rippleContentWrapper {
|
|
||||||
position: absolute;
|
|
||||||
top:100vmax;
|
|
||||||
left:100vmax;
|
|
||||||
height:var(--window-height);
|
|
||||||
width:100vw;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
}
|
|
||||||
#rippleContent {
|
|
||||||
opacity: 0;
|
|
||||||
text-align:center;
|
|
||||||
}
|
|
||||||
.activating-done #rippleContent {
|
|
||||||
opacity: 1;
|
|
||||||
transition: var(--ripple-activating-transition);
|
|
||||||
}
|
|
||||||
|
|
||||||
`
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
return html`
|
return html`
|
||||||
<div id="rippleWrapper">
|
<div id="rippleWrapper">
|
||||||
<div id="ripple">
|
<div id="ripple">
|
||||||
@ -120,14 +40,13 @@ class LoadingRipple extends LitElement {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
firstUpdated () {
|
firstUpdated() {
|
||||||
this._rippleWrapper = this.shadowRoot.getElementById('rippleWrapper')
|
this._rippleWrapper = this.shadowRoot.getElementById('rippleWrapper')
|
||||||
this._ripple = this.shadowRoot.getElementById('ripple')
|
this._ripple = this.shadowRoot.getElementById('ripple')
|
||||||
this._rippleContentWrapper = this.shadowRoot.getElementById('rippleContentWrapper')
|
this._rippleContentWrapper = this.shadowRoot.getElementById('rippleContentWrapper')
|
||||||
}
|
}
|
||||||
|
|
||||||
// duh
|
open(origin) {
|
||||||
open (origin) {
|
|
||||||
this._rippleWrapper.style.top = origin.y + 'px'
|
this._rippleWrapper.style.top = origin.y + 'px'
|
||||||
this._rippleWrapper.style.left = origin.x + 'px'
|
this._rippleWrapper.style.left = origin.x + 'px'
|
||||||
this._rippleContentWrapper.style.marginTop = -origin.y + 'px'
|
this._rippleContentWrapper.style.marginTop = -origin.y + 'px'
|
||||||
@ -135,53 +54,64 @@ class LoadingRipple extends LitElement {
|
|||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this._ripple.classList.add('activating')
|
this._ripple.classList.add('activating')
|
||||||
|
|
||||||
let isOpened = false
|
let isOpened = false
|
||||||
|
|
||||||
const doneOpeningEvent = () => {
|
const doneOpeningEvent = () => {
|
||||||
if (isOpened) return
|
if (isOpened) return
|
||||||
|
|
||||||
// Clear events
|
// Clear events
|
||||||
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, doneOpeningEvent))
|
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, doneOpeningEvent))
|
||||||
|
|
||||||
this._ripple.classList.add('activating-done')
|
this._ripple.classList.add('activating-done')
|
||||||
|
|
||||||
isOpened = true
|
isOpened = true
|
||||||
|
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, doneOpeningEvent))
|
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, doneOpeningEvent))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fades out
|
fade() {
|
||||||
fade () {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
// CAN'T FADE OUT CAUSE THE STUPID THING GETS KILLED CAUSE OF STATE.APP.LOGGEEDIN
|
|
||||||
// let rippleClosed = false
|
|
||||||
this._ripple.classList.remove('activating')
|
this._ripple.classList.remove('activating')
|
||||||
this._ripple.classList.remove('activating-done')
|
this._ripple.classList.remove('activating-done')
|
||||||
this._ripple.classList.remove('disabling')
|
this._ripple.classList.remove('disabling')
|
||||||
|
|
||||||
resolve()
|
resolve()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// un-ripples...
|
close() {
|
||||||
close () {
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let rippleClosed = false
|
let rippleClosed = false
|
||||||
|
|
||||||
this._ripple.classList.add('error')
|
this._ripple.classList.add('error')
|
||||||
this._ripple.classList.remove('activating')
|
this._ripple.classList.remove('activating')
|
||||||
this._ripple.classList.remove('activating-done')
|
this._ripple.classList.remove('activating-done')
|
||||||
|
|
||||||
const rippleClosedEvent = () => {
|
const rippleClosedEvent = () => {
|
||||||
if (rippleClosed) return
|
if (rippleClosed) return
|
||||||
|
|
||||||
rippleClosed = true
|
rippleClosed = true
|
||||||
|
|
||||||
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, rippleClosedEvent))
|
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.removeEventListener(name, rippleClosedEvent))
|
||||||
|
|
||||||
// Reset the ripple
|
// Reset the ripple
|
||||||
this._ripple.classList.remove('error')
|
this._ripple.classList.remove('error')
|
||||||
this.rippleIsOpen = false
|
this.rippleIsOpen = false
|
||||||
|
|
||||||
resolve()
|
resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, rippleClosedEvent))
|
TRANSITION_EVENT_NAMES.forEach(name => this._ripple.addEventListener(name, rippleClosedEvent))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
stateChanged (state) {
|
stateChanged(state) {
|
||||||
// this.loggedIn = state.app.loggedIn
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,7 +125,6 @@ setTimeout(() => {
|
|||||||
const ripple = document.getElementById('ripple-node')
|
const ripple = document.getElementById('ripple-node')
|
||||||
const mainApp = document.getElementById('main-app')
|
const mainApp = document.getElementById('main-app')
|
||||||
const shadow = mainApp.shadowRoot
|
const shadow = mainApp.shadowRoot
|
||||||
// console.log(shadow)
|
|
||||||
rippleElement = shadow.appendChild(ripple)
|
rippleElement = shadow.appendChild(ripple)
|
||||||
}, 500) // Should just keep checking for the main-app and it's shadow and then append once it's there
|
}, 500) // Should just keep checking for the main-app and it's shadow and then append once it's there
|
||||||
export default rippleElement
|
export default rippleElement
|
@ -1,47 +1,39 @@
|
|||||||
import {css, html, LitElement} from 'lit';
|
import { html, LitElement } from 'lit'
|
||||||
import '@vaadin/button';
|
import { myButtonStyles } from '../styles/core-css'
|
||||||
import '@polymer/paper-spinner/paper-spinner-lite.js';
|
import '@vaadin/button'
|
||||||
|
import '@polymer/paper-spinner/paper-spinner-lite.js'
|
||||||
|
|
||||||
export class MyButton extends LitElement {
|
export class MyButton extends LitElement {
|
||||||
static properties = {
|
static get properties() {
|
||||||
|
return {
|
||||||
onClick: { type: Function },
|
onClick: { type: Function },
|
||||||
isLoading: { type: Boolean },
|
isLoading: { type: Boolean },
|
||||||
label: { type: String },
|
label: { type: String }
|
||||||
};
|
}
|
||||||
|
|
||||||
static styles = css`
|
|
||||||
vaadin-button {
|
|
||||||
height: 100%;
|
|
||||||
margin: 0;
|
|
||||||
cursor: pointer;
|
|
||||||
min-width: 80px;
|
|
||||||
background-color: #03a9f4;
|
|
||||||
color: white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
vaadin-button:hover {
|
static get styles() {
|
||||||
opacity: 0.8;
|
return [myButtonStyles]
|
||||||
}
|
}
|
||||||
`;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super()
|
||||||
this.onClick = () => {};
|
this.onClick = () => { }
|
||||||
this.isLoading = false;
|
this.isLoading = false
|
||||||
this.label = '';
|
this.label = ''
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`
|
return html`
|
||||||
<vaadin-button
|
<vaadin-button ?disabled="${this.isLoading}" @click="${this.onClick}">
|
||||||
?disabled="${this.isLoading}"
|
${this.isLoading === false ? html`${this.label}` : html`<paper-spinner-lite active></paper-spinner-lite>`}
|
||||||
@click="${this.onClick}"
|
|
||||||
>
|
|
||||||
${this.isLoading === false
|
|
||||||
? html`${this.label}`
|
|
||||||
: html`<paper-spinner-lite active></paper-spinner-lite>`}
|
|
||||||
</vaadin-button>
|
</vaadin-button>
|
||||||
`;
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
customElements.define('my-button', MyButton);
|
|
||||||
|
window.customElements.define('my-button', MyButton)
|
@ -1,16 +1,16 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {testApiKey} from '../apiKeyUtils.js'
|
import { testApiKey } from '../apiKeyUtils'
|
||||||
import {get, translate} from '../../translate'
|
import { mykeyPageStyles } from '../styles/core-css'
|
||||||
|
import snackbar from './snackbar'
|
||||||
import '@material/mwc-dialog'
|
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-select'
|
import '@material/mwc-dialog'
|
||||||
import '@material/mwc-textfield'
|
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
|
import '@material/mwc-textfield'
|
||||||
|
|
||||||
import snackbar from './snackbar.js'
|
// Multi language support
|
||||||
|
import { get, translate } from '../../translate'
|
||||||
|
|
||||||
let mykeyDialog
|
let mykeyDialog
|
||||||
|
|
||||||
@ -23,34 +23,13 @@ class MykeyPage extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [mykeyPageStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: rgb(3, 169, 244);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--paper-input-container-focus-color: var(--mdc-theme-primary);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-dialog-heading-ink-color: var(--black);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--lumo-primary-text-color: rgb(0, 167, 245);
|
|
||||||
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
|
|
||||||
--lumo-primary-color-10pct: rgba(0, 167, 245, 0.1);
|
|
||||||
--lumo-primary-color: hsl(199, 100%, 48%);
|
|
||||||
--lumo-base-color: var(--white);
|
|
||||||
--lumo-body-text-color: var(--black);
|
|
||||||
--_lumo-grid-border-color: var(--border);
|
|
||||||
--_lumo-grid-secondary-border-color: var(--border2);
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
--mdc-theme-primary: red;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.nodeConfig = {}
|
this.nodeConfig = {}
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light';
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -60,26 +39,18 @@ class MykeyPage extends connect(store)(LitElement) {
|
|||||||
<mwc-textfield icon="fingerprint" id="mykeyInput" style="width:100%;" label="${translate("apipage.achange2")}"></mwc-textfield>
|
<mwc-textfield icon="fingerprint" id="mykeyInput" style="width:100%;" label="${translate("apipage.achange2")}"></mwc-textfield>
|
||||||
<p style="margin-top: 45px;">${translate("apipage.achange3")}</p>
|
<p style="margin-top: 45px;">${translate("apipage.achange3")}</p>
|
||||||
</div>
|
</div>
|
||||||
<mwc-button
|
<mwc-button slot="secondaryAction" dialogAction="close" class="red">
|
||||||
slot="secondaryAction"
|
|
||||||
dialogAction="close"
|
|
||||||
class="red"
|
|
||||||
>
|
|
||||||
${translate("apipage.achange4")}
|
${translate("apipage.achange4")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
<mwc-button
|
<mwc-button slot="primaryAction" @click="${this.addMykey}">
|
||||||
slot="primaryAction"
|
|
||||||
@click="${this.addMykey}"
|
|
||||||
>
|
|
||||||
${translate("apipage.achange5")}
|
${translate("apipage.achange5")}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
stateChanged(state) {
|
firstUpdated() {
|
||||||
this.config = state.config
|
// ...
|
||||||
this.nodeConfig = state.app.nodeConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
show() {
|
show() {
|
||||||
@ -88,35 +59,47 @@ class MykeyPage extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
async addMykey() {
|
async addMykey() {
|
||||||
const mykeyInput = this.shadowRoot.getElementById('mykeyInput').value
|
const mykeyInput = this.shadowRoot.getElementById('mykeyInput').value
|
||||||
let selectedNode = this.nodeConfig.knownNodes[this.nodeConfig.node];
|
|
||||||
let testResult = await testApiKey(mykeyInput);
|
let selectedNode = this.nodeConfig.knownNodes[this.nodeConfig.node]
|
||||||
|
let testResult = await testApiKey(mykeyInput)
|
||||||
|
|
||||||
if (testResult === true) {
|
if (testResult === true) {
|
||||||
selectedNode.apiKey = mykeyInput;
|
selectedNode.apiKey = mykeyInput
|
||||||
this.nodeConfig.knownNodes[this.nodeConfig.node] = selectedNode;
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(this.nodeConfig.knownNodes));
|
this.nodeConfig.knownNodes[this.nodeConfig.node] = selectedNode
|
||||||
|
|
||||||
|
localStorage.setItem('myQortalNodes', JSON.stringify(this.nodeConfig.knownNodes))
|
||||||
|
|
||||||
let snackbar1 = get("apipage.achange6")
|
let snackbar1 = get("apipage.achange6")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar1}`,
|
labelText: `${snackbar1}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
this.shadowRoot.getElementById('mykeyInput').value = ''
|
this.shadowRoot.getElementById('mykeyInput').value = ''
|
||||||
this.shadowRoot.querySelector('#mykeyDialog').close()
|
this.shadowRoot.querySelector('#mykeyDialog').close()
|
||||||
} else {
|
} else {
|
||||||
let snackbar2 = get("apipage.achange7")
|
let snackbar2 = get("apipage.achange7")
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snackbar2}`,
|
labelText: `${snackbar2}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
})
|
})
|
||||||
|
|
||||||
this.shadowRoot.getElementById('mykeyInput').value = ''
|
this.shadowRoot.getElementById('mykeyInput').value = ''
|
||||||
this.shadowRoot.querySelector('#mykeyDialog').close()
|
this.shadowRoot.querySelector('#mykeyDialog').close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stateChanged(state) {
|
||||||
|
this.config = state.config
|
||||||
|
this.nodeConfig = state.app.nodeConfig
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define('mykey-page', MykeyPage)
|
window.customElements.define('mykey-page', MykeyPage)
|
||||||
|
|
||||||
const mykey = document.createElement('mykey-page')
|
const mykey = document.createElement('mykey-page')
|
||||||
mykeyDialog = document.body.appendChild(mykey)
|
mykeyDialog = document.body.appendChild(mykey)
|
||||||
|
|
||||||
export default mykeyDialog
|
export default mykeyDialog
|
@ -1,38 +1,18 @@
|
|||||||
// Author: irontiga <irontiga@gmail.com>
|
// Author: irontiga <irontiga@gmail.com>
|
||||||
|
|
||||||
'use strict'
|
import { html, LitElement } from 'lit'
|
||||||
import {html, LitElement} from 'lit'
|
import * as WORDLISTS from './wordlists'
|
||||||
import * as WORDLISTS from './wordlists.js'
|
|
||||||
|
|
||||||
class RandomSentenceGenerator extends LitElement {
|
class RandomSentenceGenerator extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
template: {
|
template: { type: String, attribute: 'template' },
|
||||||
type: String,
|
parsedString: { type: String },
|
||||||
attribute: 'template'
|
fetchedWordlistCount: { type: Number, value: 0 },
|
||||||
},
|
capitalize: { type: Boolean },
|
||||||
parsedString: {
|
partsOfSpeechMap: { type: Object },
|
||||||
type: String
|
templateEntropy: { type: Number, reflect: true, attribute: 'template-entropy' },
|
||||||
},
|
maxWordLength: { type: Number, attribute: 'max-word-length' }
|
||||||
fetchedWordlistCount: {
|
|
||||||
type: Number,
|
|
||||||
value: 0
|
|
||||||
},
|
|
||||||
capitalize: {
|
|
||||||
type: Boolean
|
|
||||||
},
|
|
||||||
partsOfSpeechMap: {
|
|
||||||
type: Object
|
|
||||||
},
|
|
||||||
templateEntropy: {
|
|
||||||
type: Number,
|
|
||||||
reflect: true,
|
|
||||||
attribute: 'template-entropy'
|
|
||||||
},
|
|
||||||
maxWordLength: {
|
|
||||||
type: Number,
|
|
||||||
attribute: 'max-word-length'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,25 +37,42 @@ class RandomSentenceGenerator extends LitElement {
|
|||||||
this._wordlists = WORDLISTS
|
this._wordlists = WORDLISTS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
${this.parsedString}
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
firstUpdated() {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
let regen = false
|
let regen = false
|
||||||
|
|
||||||
if (changedProperties.has('template')) {
|
if (changedProperties.has('template')) {
|
||||||
regen = true
|
regen = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (changedProperties.has('maxWordLength')) {
|
if (changedProperties.has('maxWordLength')) {
|
||||||
console.dir(this.maxWordLength)
|
console.dir(this.maxWordLength)
|
||||||
|
|
||||||
if (this.maxWordLength) {
|
if (this.maxWordLength) {
|
||||||
const wl = { ...this._wordlists }
|
const wl = { ...this._wordlists }
|
||||||
|
|
||||||
for (const partOfSpeech in this._wordlists) {
|
for (const partOfSpeech in this._wordlists) {
|
||||||
console.log(this._wordlists[partOfSpeech])
|
console.log(this._wordlists[partOfSpeech])
|
||||||
if (Array.isArray(this._wordlists[partOfSpeech])) {
|
if (Array.isArray(this._wordlists[partOfSpeech])) {
|
||||||
wl[partOfSpeech] = this._wordlists[partOfSpeech].filter(word => word.length <= this.maxWordLength)
|
wl[partOfSpeech] = this._wordlists[partOfSpeech].filter(word => word.length <= this.maxWordLength)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._wordlists = wl
|
this._wordlists = wl
|
||||||
}
|
}
|
||||||
|
|
||||||
regen = true
|
regen = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regen) this.generate()
|
if (regen) this.generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,13 +80,16 @@ class RandomSentenceGenerator extends LitElement {
|
|||||||
if (entropy > 1074) {
|
if (entropy > 1074) {
|
||||||
throw new Error('Javascript can not handle that much entropy!')
|
throw new Error('Javascript can not handle that much entropy!')
|
||||||
}
|
}
|
||||||
|
|
||||||
let randNum = 0
|
let randNum = 0
|
||||||
|
|
||||||
const crypto = window.crypto || window.msCrypto
|
const crypto = window.crypto || window.msCrypto
|
||||||
|
|
||||||
if (crypto) {
|
if (crypto) {
|
||||||
const entropy256 = Math.ceil(entropy / 8)
|
const entropy256 = Math.ceil(entropy / 8)
|
||||||
|
|
||||||
let buffer = new Uint8Array(entropy256)
|
let buffer = new Uint8Array(entropy256)
|
||||||
|
|
||||||
crypto.getRandomValues(buffer)
|
crypto.getRandomValues(buffer)
|
||||||
|
|
||||||
randNum = buffer.reduce((num, value) => {
|
randNum = buffer.reduce((num, value) => {
|
||||||
@ -97,8 +97,10 @@ class RandomSentenceGenerator extends LitElement {
|
|||||||
}, 1) / Math.pow(256, entropy256)
|
}, 1) / Math.pow(256, entropy256)
|
||||||
} else {
|
} else {
|
||||||
console.warn('Secure RNG not found. Using Math.random')
|
console.warn('Secure RNG not found. Using Math.random')
|
||||||
|
|
||||||
randNum = Math.random()
|
randNum = Math.random()
|
||||||
}
|
}
|
||||||
|
|
||||||
return randNum
|
return randNum
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +129,9 @@ class RandomSentenceGenerator extends LitElement {
|
|||||||
|
|
||||||
parse(template) {
|
parse(template) {
|
||||||
const split = template.split(/[\s]/g)
|
const split = template.split(/[\s]/g)
|
||||||
|
|
||||||
let entropy = 1
|
let entropy = 1
|
||||||
|
|
||||||
const final = split.map(word => {
|
const final = split.map(word => {
|
||||||
const lower = word.toLowerCase()
|
const lower = word.toLowerCase()
|
||||||
|
|
||||||
@ -139,22 +143,20 @@ class RandomSentenceGenerator extends LitElement {
|
|||||||
const replacement = this.getWord(partOfSpeech)
|
const replacement = this.getWord(partOfSpeech)
|
||||||
word = replacement.word + word.slice(partOfSpeech.length) // Append the rest of the "word" (punctuation)
|
word = replacement.word + word.slice(partOfSpeech.length) // Append the rest of the "word" (punctuation)
|
||||||
entropy = entropy * replacement.entropy
|
entropy = entropy * replacement.entropy
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return word
|
return word
|
||||||
})
|
})
|
||||||
this.templateEntropy = Math.floor(Math.log(entropy) / Math.log(8))
|
|
||||||
return final.join(' ')
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
this.templateEntropy = Math.floor(Math.log(entropy) / Math.log(8))
|
||||||
return html`
|
|
||||||
${this.parsedString}
|
return final.join(' ')
|
||||||
`
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define('random-sentence-generator', RandomSentenceGenerator)
|
window.customElements.define('random-sentence-generator', RandomSentenceGenerator)
|
||||||
|
|
||||||
export default RandomSentenceGenerator
|
export default RandomSentenceGenerator
|
@ -1,19 +1,21 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {connect} from 'pwa-helpers'
|
import { connect } from 'pwa-helpers'
|
||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {doAddNode, doEditNode, doLoadNodeConfig, doRemoveNode, doSetNode} from '../redux/app/app-actions.js'
|
import { doAddNode, doEditNode, doLoadNodeConfig, doRemoveNode, doSetNode } from '../redux/app/app-actions'
|
||||||
import {get, registerTranslateConfig, translate, use} from '../../translate'
|
import { settingsPageStyles } from '../styles/core-css'
|
||||||
import snackbar from './snackbar.js'
|
|
||||||
import '../components/language-selector.js'
|
|
||||||
import '../custom-elements/frag-file-input.js'
|
|
||||||
import FileSaver from 'file-saver'
|
import FileSaver from 'file-saver'
|
||||||
|
import snackbar from './snackbar'
|
||||||
import '@material/mwc-dialog'
|
import './frag-file-input'
|
||||||
|
import '../components/language-selector'
|
||||||
import '@material/mwc-button'
|
import '@material/mwc-button'
|
||||||
import '@material/mwc-select'
|
import '@material/mwc-dialog'
|
||||||
import '@material/mwc-textfield'
|
|
||||||
import '@material/mwc-icon'
|
import '@material/mwc-icon'
|
||||||
import '@material/mwc-list/mwc-list-item.js'
|
import '@material/mwc-list/mwc-list-item.js'
|
||||||
|
import '@material/mwc-select'
|
||||||
|
import '@material/mwc-textfield'
|
||||||
|
|
||||||
|
// Multi language support
|
||||||
|
import { get, registerTranslateConfig, translate, use } from '../../translate'
|
||||||
|
|
||||||
registerTranslateConfig({
|
registerTranslateConfig({
|
||||||
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json())
|
loader: (lang) => fetch(`/language/${lang}.json`).then((res) => res.json())
|
||||||
@ -35,132 +37,23 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
return {
|
return {
|
||||||
lastSelected: { type: Number },
|
lastSelected: { type: Number },
|
||||||
nodeConfig: { type: Object },
|
nodeConfig: { type: Object },
|
||||||
theme: { type: String, reflect: true },
|
|
||||||
isBeingEdited: { type: Boolean },
|
isBeingEdited: { type: Boolean },
|
||||||
dropdownOpen: { type: Boolean }
|
dropdownOpen: { type: Boolean },
|
||||||
|
theme: { type: String, reflect: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [settingsPageStyles]
|
||||||
* {
|
|
||||||
--mdc-theme-primary: var(--login-button);
|
|
||||||
--mdc-theme-secondary: var(--mdc-theme-primary);
|
|
||||||
--mdc-dialog-content-ink-color: var(--black);
|
|
||||||
--mdc-theme-surface: var(--white);
|
|
||||||
--mdc-theme-text-primary-on-background: var(--black);
|
|
||||||
--mdc-dialog-min-width: 300px;
|
|
||||||
--mdc-dialog-max-width: 650px;
|
|
||||||
--mdc-dialog-max-height: 700px;
|
|
||||||
--mdc-list-item-text-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#main {
|
|
||||||
width: 210px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.globe {
|
|
||||||
color: var(--black);
|
|
||||||
--mdc-icon-size: 36px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.name {
|
|
||||||
display: inline-block;
|
|
||||||
width: 150px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: var(--general-color-blue);
|
|
||||||
border: 1px solid transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.red {
|
|
||||||
--mdc-theme-primary: red;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonred {
|
|
||||||
color: #f44336;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttongreen {
|
|
||||||
color: #03c851;
|
|
||||||
}
|
|
||||||
|
|
||||||
.buttonBlue {
|
|
||||||
color: var(--general-color-blue);
|
|
||||||
}
|
|
||||||
|
|
||||||
.floatleft {
|
|
||||||
float: left;
|
|
||||||
}
|
|
||||||
|
|
||||||
.floatright {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list-parent {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect {
|
|
||||||
position: relative;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
cursor: pointer;
|
|
||||||
background: var(--plugback);
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect .selected {
|
|
||||||
padding: 10px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect ul {
|
|
||||||
position: absolute;
|
|
||||||
top: 100%;
|
|
||||||
left: 0;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 1px solid #ccc;
|
|
||||||
display: none;
|
|
||||||
background: var(--plugback);
|
|
||||||
width: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect ul.open {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect ul li {
|
|
||||||
padding: 10px;
|
|
||||||
transition: 0.2s all;
|
|
||||||
}
|
|
||||||
|
|
||||||
#customSelect ul li:hover {
|
|
||||||
background-color: var(--graylight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.selected-left-side {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
|
||||||
this.nodeConfig = {}
|
this.nodeConfig = {}
|
||||||
this.isBeingEdited = false
|
this.isBeingEdited = false
|
||||||
this.isBeingEditedIndex = null
|
this.isBeingEditedIndex = null
|
||||||
this.dropdownOpen = false
|
this.dropdownOpen = false
|
||||||
|
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -176,20 +69,21 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
<div class="selected">
|
<div class="selected">
|
||||||
<div class="selected-left-side">
|
<div class="selected-left-side">
|
||||||
<mwc-icon style="margin-right: 10px">link</mwc-icon>
|
<mwc-icon style="margin-right: 10px">link</mwc-icon>
|
||||||
${this.selectedItem ? html
|
${this.selectedItem ?
|
||||||
`
|
html `
|
||||||
<div>
|
<div>
|
||||||
<span class="name">${this.selectedItem.name}</span>
|
<span class="name">${this.selectedItem.name}</span>
|
||||||
<span>${this.selectedItem.protocol + '://' + this.selectedItem.domain + ':' + this.selectedItem.port}</span>
|
<span>${this.selectedItem.protocol + '://' + this.selectedItem.domain + ':' + this.selectedItem.port}</span>
|
||||||
</div>
|
</div>
|
||||||
` : html`${translate('settings.selectnode')}`
|
` : html`
|
||||||
|
${translate('settings.selectnode')}
|
||||||
|
`
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<mwc-icon>expand_more</mwc-icon>
|
<mwc-icon>expand_more</mwc-icon>
|
||||||
</div>
|
</div>
|
||||||
<ul class="${this.dropdownOpen ? 'open' : ''}">
|
<ul class="${this.dropdownOpen ? 'open' : ''}">
|
||||||
${this.nodeConfig.knownNodes.map(
|
${this.nodeConfig.knownNodes.map((n, index) => html`
|
||||||
(n, index) => html`
|
|
||||||
<li @click="${(e) => this.handleSelection(e, n, index)}">
|
<li @click="${(e) => this.handleSelection(e, n, index)}">
|
||||||
<div class="list-parent">
|
<div class="list-parent">
|
||||||
<div>
|
<div>
|
||||||
@ -200,7 +94,7 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
<mwc-button
|
<mwc-button
|
||||||
outlined
|
outlined
|
||||||
@click="${(e) => {
|
@click="${(e) => {
|
||||||
e.stopPropagation();
|
e.stopPropagation()
|
||||||
const currentValues = this.nodeConfig.knownNodes[index]
|
const currentValues = this.nodeConfig.knownNodes[index]
|
||||||
const dialog = this.shadowRoot.querySelector('#addNodeDialog')
|
const dialog = this.shadowRoot.querySelector('#addNodeDialog')
|
||||||
|
|
||||||
@ -225,19 +119,15 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
`
|
`)}
|
||||||
)}
|
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<p style="margin-top: 30px; text-align: center;">
|
<p style="margin-top: 30px; text-align: center;">
|
||||||
${translate('settings.nodehint')}
|
${translate('settings.nodehint')}
|
||||||
</p>
|
</p>
|
||||||
<center>
|
<center>
|
||||||
<mwc-button
|
<mwc-button outlined @click="${() => this.shadowRoot.querySelector('#addNodeDialog').show()}">
|
||||||
outlined
|
<mwc-icon class="buttongreen">add</mwc-icon>
|
||||||
@click="${() => this.shadowRoot.querySelector('#addNodeDialog').show()}"
|
|
||||||
><mwc-icon class="buttongreen">add</mwc-icon
|
|
||||||
>
|
|
||||||
${translate('settings.addcustomnode')}
|
${translate('settings.addcustomnode')}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</center>
|
</center>
|
||||||
@ -261,8 +151,7 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
<br />
|
<br />
|
||||||
<center>
|
<center>
|
||||||
<div id="main">
|
<div id="main">
|
||||||
<mwc-icon class="globe">language</mwc-icon
|
<mwc-icon class="globe">language</mwc-icon> <language-selector></language-selector>
|
||||||
> <language-selector></language-selector>
|
|
||||||
</div>
|
</div>
|
||||||
</center>
|
</center>
|
||||||
</div>
|
</div>
|
||||||
@ -270,7 +159,6 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
${translate('general.close')}
|
${translate('general.close')}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
|
|
||||||
<mwc-dialog id="addNodeDialog">
|
<mwc-dialog id="addNodeDialog">
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
<h2>${translate('settings.addcustomnode')}</h2>
|
<h2>${translate('settings.addcustomnode')}</h2>
|
||||||
@ -293,7 +181,6 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
${translate('settings.addandsave')}
|
${translate('settings.addandsave')}
|
||||||
</mwc-button>
|
</mwc-button>
|
||||||
</mwc-dialog>
|
</mwc-dialog>
|
||||||
|
|
||||||
<mwc-dialog id="importQortalNodesListDialog">
|
<mwc-dialog id="importQortalNodesListDialog">
|
||||||
<div style="text-align:center">
|
<div style="text-align:center">
|
||||||
<h2>${translate('settings.import')}</h2>
|
<h2>${translate('settings.import')}</h2>
|
||||||
@ -326,6 +213,7 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
firstUpdated() {
|
firstUpdated() {
|
||||||
const checkNode = localStorage.getItem('mySelectedNode')
|
const checkNode = localStorage.getItem('mySelectedNode')
|
||||||
|
|
||||||
if (checkNode === null || checkNode.length === 0) {
|
if (checkNode === null || checkNode.length === 0) {
|
||||||
localStorage.setItem('mySelectedNode', 0)
|
localStorage.setItem('mySelectedNode', 0)
|
||||||
} else {
|
} else {
|
||||||
@ -364,13 +252,36 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
this.dropdownOpen = false
|
this.dropdownOpen = false
|
||||||
this.requestUpdate()
|
this.requestUpdate()
|
||||||
this.nodeSelected(index)
|
this.nodeSelected(index)
|
||||||
|
|
||||||
localStorage.setItem('mySelectedNode', index)
|
localStorage.setItem('mySelectedNode', index)
|
||||||
|
|
||||||
const selectedNodeIndexOnNewStart = localStorage.getItem('mySelectedNode')
|
const selectedNodeIndexOnNewStart = localStorage.getItem('mySelectedNode')
|
||||||
const catchSavedNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
const catchSavedNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
const selectedNodeOnNewStart = catchSavedNodes[selectedNodeIndexOnNewStart]
|
const selectedNodeOnNewStart = catchSavedNodes[selectedNodeIndexOnNewStart]
|
||||||
const selectedNameOnNewStart = `${selectedNodeOnNewStart.name}`
|
const selectedNameOnNewStart = `${selectedNodeOnNewStart.name}`
|
||||||
const selectedNodeUrlOnNewStart = `${selectedNodeOnNewStart.protocol + '://' + selectedNodeOnNewStart.domain +':' + selectedNodeOnNewStart.port}`
|
const selectedNodeUrlOnNewStart = `${selectedNodeOnNewStart.protocol + '://' + selectedNodeOnNewStart.domain + ':' + selectedNodeOnNewStart.port}`
|
||||||
|
|
||||||
|
let snack2string = get('settings.snack2')
|
||||||
|
|
||||||
|
snackbar.add({
|
||||||
|
labelText: `${snack2string} : ${selectedNameOnNewStart} ${selectedNodeUrlOnNewStart}`,
|
||||||
|
dismiss: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAddNodeSelection(node, index) {
|
||||||
|
this.selectedItem = node
|
||||||
|
this.dropdownOpen = false
|
||||||
|
this.requestUpdate()
|
||||||
|
this.nodeSelected(index)
|
||||||
|
|
||||||
|
localStorage.setItem('mySelectedNode', index)
|
||||||
|
|
||||||
|
const selectedNodeIndexOnNewStart = localStorage.getItem('mySelectedNode')
|
||||||
|
const catchSavedNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
|
const selectedNodeOnNewStart = catchSavedNodes[selectedNodeIndexOnNewStart]
|
||||||
|
const selectedNameOnNewStart = `${selectedNodeOnNewStart.name}`
|
||||||
|
const selectedNodeUrlOnNewStart = `${selectedNodeOnNewStart.protocol + '://' + selectedNodeOnNewStart.domain + ':' + selectedNodeOnNewStart.port}`
|
||||||
|
|
||||||
let snack2string = get('settings.snack2')
|
let snack2string = get('settings.snack2')
|
||||||
|
|
||||||
@ -408,10 +319,13 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var renewNodes = []
|
var renewNodes = []
|
||||||
|
|
||||||
renewNodes.push(obj1, obj2)
|
renewNodes.push(obj1, obj2)
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(renewNodes))
|
localStorage.setItem('myQortalNodes', JSON.stringify(renewNodes))
|
||||||
|
|
||||||
let snack1string = get('settings.snack1')
|
let snack1string = get('settings.snack1')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack1string}`,
|
labelText: `${snack1string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -426,9 +340,9 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
nodeSelected(selectedNodeIndex) {
|
nodeSelected(selectedNodeIndex) {
|
||||||
const selectedNode = this.nodeConfig.knownNodes[selectedNodeIndex]
|
const selectedNode = this.nodeConfig.knownNodes[selectedNodeIndex]
|
||||||
const selectedName = `${selectedNode.name}`
|
const selectedName = `${selectedNode.name}`
|
||||||
const selectedNodeUrl = `${selectedNode.protocol + '://' + selectedNode.domain +':' + selectedNode.port}`
|
const selectedNodeUrl = `${selectedNode.protocol + '://' + selectedNode.domain + ':' + selectedNode.port}`
|
||||||
|
|
||||||
const index = parseInt(selectedNodeIndex)
|
const index = parseInt(selectedNodeIndex)
|
||||||
|
|
||||||
if (isNaN(index)) return
|
if (isNaN(index)) return
|
||||||
|
|
||||||
store.dispatch(doSetNode(selectedNodeIndex))
|
store.dispatch(doSetNode(selectedNodeIndex))
|
||||||
@ -462,13 +376,23 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
store.dispatch(doAddNode(nodeObject))
|
store.dispatch(doAddNode(nodeObject))
|
||||||
|
|
||||||
const haveNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
const haveNodes = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
|
const indexLength = this.nodeConfig.knownNodes.length
|
||||||
|
|
||||||
|
let choosedIndex
|
||||||
|
let choosedNode
|
||||||
|
|
||||||
|
choosedIndex = indexLength -1
|
||||||
|
choosedNode = this.nodeConfig.knownNodes[this.nodeConfig.knownNodes.length - 1]
|
||||||
|
|
||||||
if (haveNodes === null || haveNodes.length === 0) {
|
if (haveNodes === null || haveNodes.length === 0) {
|
||||||
var savedNodes = []
|
var savedNodes = []
|
||||||
|
|
||||||
savedNodes.push(nodeObject)
|
savedNodes.push(nodeObject)
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(savedNodes))
|
localStorage.setItem('myQortalNodes', JSON.stringify(savedNodes))
|
||||||
|
|
||||||
let snack3string = get('settings.snack3')
|
let snack3string = get('settings.snack3')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack3string}`,
|
labelText: `${snack3string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -478,14 +402,16 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
this.shadowRoot.getElementById('protocolList').value = ''
|
this.shadowRoot.getElementById('protocolList').value = ''
|
||||||
this.shadowRoot.getElementById('domainInput').value = ''
|
this.shadowRoot.getElementById('domainInput').value = ''
|
||||||
this.shadowRoot.getElementById('portInput').value = ''
|
this.shadowRoot.getElementById('portInput').value = ''
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#addNodeDialog').close()
|
this.shadowRoot.querySelector('#addNodeDialog').close()
|
||||||
} else {
|
} else {
|
||||||
var stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
var stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
|
|
||||||
stored.push(nodeObject)
|
stored.push(nodeObject)
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(stored))
|
localStorage.setItem('myQortalNodes', JSON.stringify(stored))
|
||||||
|
|
||||||
let snack3string = get('settings.snack3');
|
let snack3string = get('settings.snack3')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack3string}`,
|
labelText: `${snack3string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -495,9 +421,10 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
this.shadowRoot.getElementById('protocolList').value = ''
|
this.shadowRoot.getElementById('protocolList').value = ''
|
||||||
this.shadowRoot.getElementById('domainInput').value = ''
|
this.shadowRoot.getElementById('domainInput').value = ''
|
||||||
this.shadowRoot.getElementById('portInput').value = ''
|
this.shadowRoot.getElementById('portInput').value = ''
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#addNodeDialog').close()
|
this.shadowRoot.querySelector('#addNodeDialog').close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.handleAddNodeSelection(choosedNode, choosedIndex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -505,11 +432,15 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
|
||||||
let stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
let stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
|
|
||||||
stored.splice(index, 1)
|
stored.splice(index, 1)
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(stored))
|
localStorage.setItem('myQortalNodes', JSON.stringify(stored))
|
||||||
|
|
||||||
store.dispatch(doRemoveNode(index))
|
store.dispatch(doRemoveNode(index))
|
||||||
|
|
||||||
let snack6string = get('settings.snack6')
|
let snack6string = get('settings.snack6')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack6string}`,
|
labelText: `${snack6string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -530,16 +461,21 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
protocol: protocolList,
|
protocol: protocolList,
|
||||||
domain: domainInput,
|
domain: domainInput,
|
||||||
port: portInput,
|
port: portInput,
|
||||||
enableManagement: true,
|
enableManagement: true
|
||||||
}
|
}
|
||||||
|
|
||||||
let stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
let stored = JSON.parse(localStorage.getItem('myQortalNodes'))
|
||||||
|
|
||||||
const copyStored = [...stored]
|
const copyStored = [...stored]
|
||||||
|
|
||||||
copyStored[index] = nodeObject
|
copyStored[index] = nodeObject
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(copyStored))
|
localStorage.setItem('myQortalNodes', JSON.stringify(copyStored))
|
||||||
|
|
||||||
store.dispatch(doEditNode(index, nodeObject))
|
store.dispatch(doEditNode(index, nodeObject))
|
||||||
|
|
||||||
let snack7string = get('settings.snack7')
|
let snack7string = get('settings.snack7')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack7string}`,
|
labelText: `${snack7string}`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -551,7 +487,6 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
this.shadowRoot.getElementById('portInput').value = ''
|
this.shadowRoot.getElementById('portInput').value = ''
|
||||||
this.isBeingEdited = false
|
this.isBeingEdited = false
|
||||||
this.isBeingEditedIndex = null
|
this.isBeingEditedIndex = null
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#addNodeDialog').close()
|
this.shadowRoot.querySelector('#addNodeDialog').close()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -566,26 +501,25 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
|
|
||||||
renderExportNodesListButton() {
|
renderExportNodesListButton() {
|
||||||
return html`
|
return html`
|
||||||
<mwc-button
|
<mwc-button dense unelevated label="${translate('settings.export')}" @click="${() => this.exportQortalNodesList()}"></mwc-button>
|
||||||
dense
|
|
||||||
unelevated
|
|
||||||
label="${translate('settings.export')}"
|
|
||||||
@click="${() => this.exportQortalNodesList()}"
|
|
||||||
>
|
|
||||||
</mwc-button>
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
exportQortalNodesList() {
|
exportQortalNodesList() {
|
||||||
let nodelist = ''
|
let nodelist = ''
|
||||||
|
|
||||||
const qortalNodesList = JSON.stringify(
|
const qortalNodesList = JSON.stringify(
|
||||||
localStorage.getItem('myQortalNodes')
|
localStorage.getItem('myQortalNodes')
|
||||||
);
|
)
|
||||||
|
|
||||||
const qortalNodesListSave = JSON.parse(qortalNodesList || '[]')
|
const qortalNodesListSave = JSON.parse(qortalNodesList || '[]')
|
||||||
|
|
||||||
const blob = new Blob([qortalNodesListSave], {
|
const blob = new Blob([qortalNodesListSave], {
|
||||||
type: 'text/plain;charset=utf-8',
|
type: 'text/plain;charset=utf-8'
|
||||||
})
|
})
|
||||||
|
|
||||||
nodelist = 'qortal.nodes'
|
nodelist = 'qortal.nodes'
|
||||||
|
|
||||||
this.saveFileToDisk(blob, nodelist)
|
this.saveFileToDisk(blob, nodelist)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,16 +529,20 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
suggestedName: fileName,
|
suggestedName: fileName,
|
||||||
types: [{
|
types: [{
|
||||||
description: 'File'
|
description: 'File'
|
||||||
}],
|
}]
|
||||||
})
|
})
|
||||||
|
|
||||||
const writeFile = async (fileHandle, contents) => {
|
const writeFile = async (fileHandle, contents) => {
|
||||||
const writable = await fileHandle.createWritable()
|
const writable = await fileHandle.createWritable()
|
||||||
|
|
||||||
await writable.write(contents)
|
await writable.write(contents)
|
||||||
await writable.close()
|
await writable.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
writeFile(fileHandle, blob).then(() => console.log('FILE SAVED'))
|
writeFile(fileHandle, blob).then(() => console.log('FILE SAVED'))
|
||||||
|
|
||||||
let snack4string = get('settings.snack4')
|
let snack4string = get('settings.snack4')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack4string} qortal.nodes`,
|
labelText: `${snack4string} qortal.nodes`,
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -613,29 +551,28 @@ class SettingsPage extends connect(store)(LitElement) {
|
|||||||
if (error.name === 'AbortError') {
|
if (error.name === 'AbortError') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
FileSaver.saveAs(blob, fileName)
|
FileSaver.saveAs(blob, fileName)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
renderImportNodesListButton() {
|
renderImportNodesListButton() {
|
||||||
return html`
|
return html`
|
||||||
<mwc-button
|
<mwc-button dense unelevated label="${translate('settings.import')}" @click="${() => this.openImportNodesDialog()}"></mwc-button>
|
||||||
dense
|
|
||||||
unelevated
|
|
||||||
label="${translate('settings.import')}"
|
|
||||||
@click="${() => this.openImportNodesDialog()}"
|
|
||||||
>
|
|
||||||
</mwc-button>
|
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
async importQortalNodesList(file) {
|
async importQortalNodesList(file) {
|
||||||
localStorage.removeItem('myQortalNodes')
|
localStorage.removeItem('myQortalNodes')
|
||||||
|
|
||||||
const newItems = JSON.parse(file || '[]')
|
const newItems = JSON.parse(file || '[]')
|
||||||
|
|
||||||
localStorage.setItem('myQortalNodes', JSON.stringify(newItems))
|
localStorage.setItem('myQortalNodes', JSON.stringify(newItems))
|
||||||
|
|
||||||
this.shadowRoot.querySelector('#importQortalNodesListDialog').close()
|
this.shadowRoot.querySelector('#importQortalNodesListDialog').close()
|
||||||
|
|
||||||
let snack5string = get('settings.snack5')
|
let snack5string = get('settings.snack5')
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: `${snack5string}`,
|
labelText: `${snack5string}`,
|
||||||
dismiss: true,
|
dismiss: true,
|
||||||
@ -657,5 +594,4 @@ window.customElements.define('settings-page', SettingsPage)
|
|||||||
|
|
||||||
const settings = document.createElement('settings-page')
|
const settings = document.createElement('settings-page')
|
||||||
settingsDialog = document.body.appendChild(settings)
|
settingsDialog = document.body.appendChild(settings)
|
||||||
|
|
||||||
export default settingsDialog
|
export default settingsDialog
|
@ -1,157 +0,0 @@
|
|||||||
import {css} from 'lit'
|
|
||||||
|
|
||||||
export const sideMenuItemStyle = css`
|
|
||||||
:host {
|
|
||||||
--font-family: "Roboto", sans-serif;
|
|
||||||
--item-font-size: 0.9375rem;
|
|
||||||
--sub-item-font-size: 0.75rem;
|
|
||||||
--item-padding: 0.875rem;
|
|
||||||
--item-content-padding: 0.875rem;
|
|
||||||
--icon-height: 1.125rem;
|
|
||||||
--icon-width: 1.125rem;
|
|
||||||
--item-border-radius: 5px;
|
|
||||||
--item-selected-color: #dddddd;
|
|
||||||
--item-selected-color-text: #333333;
|
|
||||||
--item-color-active: #d1d1d1;
|
|
||||||
--item-color-hover: #eeeeee;
|
|
||||||
--item-text-color: #080808;
|
|
||||||
--item-icon-color: #080808;
|
|
||||||
--item-border-color: #eeeeee;
|
|
||||||
--item-border-selected-color: #333333;
|
|
||||||
|
|
||||||
--overlay-box-shadow: 0 2px 4px -1px hsla(214, 53%, 23%, 0.16), 0 3px 12px -1px hsla(214, 50%, 22%, 0.26);
|
|
||||||
--overlay-background-color: #ffffff;
|
|
||||||
|
|
||||||
--spacing: 4px;
|
|
||||||
|
|
||||||
font-family: var(--font-family);
|
|
||||||
display: flex;
|
|
||||||
overflow: hidden;
|
|
||||||
flex-direction: column;
|
|
||||||
border-radius: var(--item-border-radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
#itemLink {
|
|
||||||
align-items: center;
|
|
||||||
font-size: var(--item-font-size);
|
|
||||||
font-weight: 400;
|
|
||||||
height: var(--icon-height);
|
|
||||||
transition: background-color 200ms;
|
|
||||||
padding: var(--item-padding);
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-flex;
|
|
||||||
flex-grow: 1;
|
|
||||||
align-items: center;
|
|
||||||
overflow: hidden;
|
|
||||||
text-decoration: none;
|
|
||||||
border-bottom: 1px solid var(--item-border-color);
|
|
||||||
text-transform: uppercase;
|
|
||||||
}
|
|
||||||
.hideItem {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
#itemLink:hover {
|
|
||||||
background-color: var(--item-color-hover);
|
|
||||||
}
|
|
||||||
|
|
||||||
#itemLink:active {
|
|
||||||
background-color: var(--item-color-active);
|
|
||||||
}
|
|
||||||
|
|
||||||
#content {
|
|
||||||
padding-left: var(--item-content-padding);
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([compact]) #content {
|
|
||||||
padding-left: 0;
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([selected]) #itemLink {
|
|
||||||
background-color: var(--item-selected-color);
|
|
||||||
color: var(--item-selected-color-text);
|
|
||||||
border-left: 3px solid var(--item-border-selected-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([selected]) slot[name="icon"]::slotted(*) {
|
|
||||||
color: var(--item-selected-color-text);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(:not([selected])) #itemLink{
|
|
||||||
color: var(--item-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([expanded]){
|
|
||||||
background-color: var(--item-selected-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([hasSelectedChild]){
|
|
||||||
background-color: var(--item-selected-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host span {
|
|
||||||
cursor: inherit;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
user-select: none;
|
|
||||||
-webkit-user-select: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
slot[name="icon"]::slotted(*) {
|
|
||||||
flex-shrink: 0;
|
|
||||||
color: var(--item-icon-color);
|
|
||||||
height: var(--icon-height);
|
|
||||||
width: var(--icon-width);
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
#collapse-button {
|
|
||||||
float: right;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([compact]) #itemLink[level]:not([level="0"]) {
|
|
||||||
padding: calc( var(--item-padding) / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
:host(:not([compact])) #itemLink[level]:not([level="0"]) {
|
|
||||||
padding-left: calc(var(--icon-width) + var(--item-content-padding));
|
|
||||||
}
|
|
||||||
|
|
||||||
#itemLink[level]:not([level="0"]) #content {
|
|
||||||
display: block;
|
|
||||||
visibility: visible;
|
|
||||||
width: auto;
|
|
||||||
font-weight: 400;
|
|
||||||
font-size: var(--sub-item-font-size)
|
|
||||||
}
|
|
||||||
|
|
||||||
#overlay {
|
|
||||||
display: block;
|
|
||||||
left: 101%;
|
|
||||||
min-width: 200px;
|
|
||||||
padding: 4px 2px;
|
|
||||||
background-color: var(--overlay-background-color);
|
|
||||||
background-image: var(--overlay-background-image, none);
|
|
||||||
box-shadow: var(--overlay-box-shadow);
|
|
||||||
border: 1px solid var(--overlay-background-color);
|
|
||||||
border-left: 0;
|
|
||||||
border-radius: 0 3px 3px 0;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
animation: pop 200ms forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes pop{
|
|
||||||
0% {
|
|
||||||
transform: translateX(-5px);
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
transform: translateX(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
@ -1,6 +1,6 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import {ifDefined} from 'lit/directives/if-defined.js'
|
import { ifDefined } from 'lit/directives/if-defined.js'
|
||||||
import {sideMenuItemStyle} from './side-menu-item-style.js'
|
import { sideMenuItemStyles } from '../styles/core-css'
|
||||||
import '@vaadin/icon'
|
import '@vaadin/icon'
|
||||||
import '@vaadin/icons'
|
import '@vaadin/icons'
|
||||||
import '@polymer/paper-tooltip'
|
import '@polymer/paper-tooltip'
|
||||||
@ -19,9 +19,7 @@ export class SideMenuItem extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [sideMenuItemStyles]
|
||||||
${sideMenuItemStyle}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -42,6 +40,7 @@ export class SideMenuItem extends LitElement {
|
|||||||
if (!this.hasChildren()) {
|
if (!this.hasChildren()) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.collapseExpandIcon = document.createElement("vaadin-icon")
|
this.collapseExpandIcon = document.createElement("vaadin-icon")
|
||||||
this.collapseExpandIcon.id = "collapse-button"
|
this.collapseExpandIcon.id = "collapse-button"
|
||||||
this.shadowRoot.getElementById("content").appendChild(this.collapseExpandIcon)
|
this.shadowRoot.getElementById("content").appendChild(this.collapseExpandIcon)
|
||||||
@ -67,26 +66,29 @@ export class SideMenuItem extends LitElement {
|
|||||||
|
|
||||||
_tooltipTemplate() {
|
_tooltipTemplate() {
|
||||||
return html`
|
return html`
|
||||||
${this._getLevel === 0 && this.compact ? html`
|
${this._getLevel === 0 && this.compact ?
|
||||||
|
html`
|
||||||
<paper-tooltip for="itemLink" position="right" animation-delay="0">
|
<paper-tooltip for="itemLink" position="right" animation-delay="0">
|
||||||
${this.label}
|
${this.label}
|
||||||
</paper-tooltip>
|
</paper-tooltip>
|
||||||
`
|
` : undefined
|
||||||
: undefined}
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
_childrenTemplate() {
|
_childrenTemplate() {
|
||||||
return html`
|
return html`
|
||||||
${this.expanded ? html`
|
${this.expanded ?
|
||||||
${this.compact ? html`
|
html`
|
||||||
|
${this.compact ?
|
||||||
|
html`
|
||||||
<div id="overlay"><slot></slot></div>
|
<div id="overlay"><slot></slot></div>
|
||||||
`
|
` : html`
|
||||||
: html`
|
|
||||||
<slot></slot>
|
<slot></slot>
|
||||||
`}
|
|
||||||
`
|
`
|
||||||
: undefined}
|
}
|
||||||
|
` : undefined
|
||||||
|
}
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,8 +102,8 @@ export class SideMenuItem extends LitElement {
|
|||||||
this._onExpandedChanged()
|
this._onExpandedChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propName === "selected"){
|
if (propName === "selected") {
|
||||||
if (oldValue === this.selected){
|
if (oldValue === this.selected) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,14 +112,14 @@ export class SideMenuItem extends LitElement {
|
|||||||
this._markParentWithSelectedChild()
|
this._markParentWithSelectedChild()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
_onCompactChanged() {
|
_onCompactChanged() {
|
||||||
this.expanded = false;
|
this.expanded = false
|
||||||
|
|
||||||
if (this.collapseExpandIcon == null) {
|
if (this.collapseExpandIcon == null) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.compact) {
|
if (!this.compact) {
|
||||||
@ -129,13 +131,13 @@ export class SideMenuItem extends LitElement {
|
|||||||
|
|
||||||
_onExpandedChanged() {
|
_onExpandedChanged() {
|
||||||
if (this.collapseExpandIcon == null) {
|
if (this.collapseExpandIcon == null) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.expanded) {
|
if (this.expanded) {
|
||||||
this._onHandleExpanded();
|
this._onHandleExpanded()
|
||||||
} else {
|
} else {
|
||||||
this._onHandleCollapsed();
|
this._onHandleCollapsed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -166,12 +168,14 @@ export class SideMenuItem extends LitElement {
|
|||||||
this.selected = true
|
this.selected = true
|
||||||
} else {
|
} else {
|
||||||
this.expanded = !this.expanded
|
this.expanded = !this.expanded
|
||||||
|
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_outsideClickListener(event) {
|
_outsideClickListener(event) {
|
||||||
const eventPath = event.composedPath()
|
const eventPath = event.composedPath()
|
||||||
|
|
||||||
if (eventPath.indexOf(this) < 0) {
|
if (eventPath.indexOf(this) < 0) {
|
||||||
this.expanded = false
|
this.expanded = false
|
||||||
}
|
}
|
||||||
@ -179,11 +183,13 @@ export class SideMenuItem extends LitElement {
|
|||||||
|
|
||||||
_changeSelectedState(selected, sourceEvent) {
|
_changeSelectedState(selected, sourceEvent) {
|
||||||
this.selected = selected
|
this.selected = selected
|
||||||
|
|
||||||
let evt = new CustomEvent("side-menu-item-select", {
|
let evt = new CustomEvent("side-menu-item-select", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true,
|
cancelable: true,
|
||||||
detail: { sourceEvent: sourceEvent }
|
detail: { sourceEvent: sourceEvent }
|
||||||
});
|
})
|
||||||
|
|
||||||
this.dispatchEvent(evt)
|
this.dispatchEvent(evt)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,19 +201,21 @@ export class SideMenuItem extends LitElement {
|
|||||||
let element = this.parentElement;
|
let element = this.parentElement;
|
||||||
while (element instanceof SideMenuItem) {
|
while (element instanceof SideMenuItem) {
|
||||||
element.setAttribute('hasSelectedChild', true)
|
element.setAttribute('hasSelectedChild', true)
|
||||||
element = element.parentElement;
|
element = element.parentElement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get _getLevel() {
|
get _getLevel() {
|
||||||
let level = 0
|
let level = 0
|
||||||
let element = this.parentElement
|
let element = this.parentElement
|
||||||
|
|
||||||
while (element instanceof SideMenuItem) {
|
while (element instanceof SideMenuItem) {
|
||||||
level++;
|
level++
|
||||||
element = element.parentElement
|
element = element.parentElement
|
||||||
}
|
}
|
||||||
|
|
||||||
return level
|
return level
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define("side-menu-item", SideMenuItem);
|
window.customElements.define("side-menu-item", SideMenuItem)
|
@ -1,30 +1,17 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
|
import { sideMenuStyles } from '../styles/core-css'
|
||||||
|
|
||||||
class SideMenu extends LitElement {
|
class SideMenu extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
items: {type: Array},
|
items: { type: Array },
|
||||||
selectedValue: {type: String, reflect: true},
|
selectedValue: { type: String, reflect: true },
|
||||||
compact: {type: Boolean, reflect: true}
|
compact: { type: Boolean, reflect: true }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
return css`
|
return [sideMenuStyles]
|
||||||
nav {
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host {
|
|
||||||
list-style: none;
|
|
||||||
width: 100%;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([compact]) {
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -56,23 +43,26 @@ class SideMenu extends LitElement {
|
|||||||
if (this.compact) {
|
if (this.compact) {
|
||||||
element.expanded = false
|
element.expanded = false
|
||||||
}
|
}
|
||||||
|
|
||||||
element.selected = false
|
element.selected = false
|
||||||
element.hasChildren() ? element.removeAttribute('hasSelectedChild') : undefined
|
element.hasChildren() ? element.removeAttribute('hasSelectedChild') : undefined
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
updated(changedProperties) {
|
updated(changedProperties) {
|
||||||
changedProperties.forEach((oldValue, propName) => {
|
changedProperties.forEach((oldValue, propName) => {
|
||||||
if (propName === "compact") {
|
if (propName === "compact") {
|
||||||
this.items.forEach(item => (item.compact = this.compact))
|
this.items.forEach(item => (item.compact = this.compact))
|
||||||
|
|
||||||
let evt = new CustomEvent("side-menu-compact-change", {
|
let evt = new CustomEvent("side-menu-compact-change", {
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
cancelable: true
|
cancelable: true
|
||||||
})
|
})
|
||||||
|
|
||||||
this.dispatchEvent(evt)
|
this.dispatchEvent(evt)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
window.customElements.define("side-menu", SideMenu);
|
window.customElements.define("side-menu", SideMenu)
|
@ -1,4 +1,4 @@
|
|||||||
import {css, html, LitElement} from 'lit'
|
import { html, LitElement } from 'lit'
|
||||||
import '@material/mwc-snackbar'
|
import '@material/mwc-snackbar'
|
||||||
|
|
||||||
let queueElement
|
let queueElement
|
||||||
@ -6,34 +6,20 @@ let queueElement
|
|||||||
class SnackQueue extends LitElement {
|
class SnackQueue extends LitElement {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
busy: {
|
busy: { type: Boolean, attribute: 'busy', reflectToAttribute: true },
|
||||||
type: Boolean,
|
currentSnack: { type: Object, attribute: 'current-snack', reflectToAttribute: true },
|
||||||
attribute: 'busy',
|
_queue: { type: Array },
|
||||||
reflectToAttribute: true
|
|
||||||
},
|
|
||||||
currentSnack: {
|
|
||||||
type: Object,
|
|
||||||
attribute: 'current-snack',
|
|
||||||
reflectToAttribute: true
|
|
||||||
},
|
|
||||||
_queue: {
|
|
||||||
type: Array
|
|
||||||
},
|
|
||||||
_labelText: { type: String },
|
_labelText: { type: String },
|
||||||
_stacked: { type: Boolean },
|
_stacked: { type: Boolean },
|
||||||
_leading: { type: Boolean },
|
_leading: { type: Boolean },
|
||||||
_closeOnEscape: { type: Boolean },
|
_closeOnEscape: { type: Boolean },
|
||||||
_timeoutMs: { type: Number },
|
_timeoutMs: { type: Number },
|
||||||
action: {},
|
|
||||||
_dismiss: {},
|
_dismiss: {},
|
||||||
_dismissIcon: { type: String }
|
_dismissIcon: { type: String },
|
||||||
|
action: {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles() {
|
|
||||||
return css``
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super()
|
super()
|
||||||
this._queue = []
|
this._queue = []
|
||||||
@ -45,9 +31,11 @@ class SnackQueue extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<mwc-snackbar id="snack" labelText="${this._labelText}" ?stacked=${this._stacked} ?leading=${this._leading} ?closeOnEscape=${this._closeOnEscape} timeoutMs=${this._timeoutMs}>
|
<mwc-snackbar id="snack" labelText="${this._labelText}" ?stacked=${this._stacked} ?leading=${this._leading} ?closeOnEscape=${this._closeOnEscape} timeoutMs=${this._timeoutMs}>
|
||||||
${this._action}
|
${this._action}
|
||||||
${this._dismiss ? html`
|
${this._dismiss ?
|
||||||
|
html`
|
||||||
<mwc-icon-button icon="${this._dismissIcon}" slot="dismiss"></mwc-icon-button>
|
<mwc-icon-button icon="${this._dismissIcon}" slot="dismiss"></mwc-icon-button>
|
||||||
` : ''}
|
` : ''
|
||||||
|
}
|
||||||
</mwc-snackbar>
|
</mwc-snackbar>
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
// Sourced from https://gist.github.com/letsgetrandy/1e05a68ea74ba6736eb5
|
|
||||||
|
|
||||||
export const EXCEPTIONS = {
|
export const EXCEPTIONS = {
|
||||||
'are': 'were',
|
'are': 'were',
|
||||||
'eat': 'ate',
|
'eat': 'ate',
|
||||||
@ -16,21 +14,27 @@ export const getPastTense = (verb, exceptions = EXCEPTIONS) => {
|
|||||||
if (exceptions[verb]) {
|
if (exceptions[verb]) {
|
||||||
return exceptions[verb]
|
return exceptions[verb]
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((/e$/i).test(verb)) {
|
if ((/e$/i).test(verb)) {
|
||||||
return verb + 'd'
|
return verb + 'd'
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((/[aeiou]c$/i).test(verb)) {
|
if ((/[aeiou]c$/i).test(verb)) {
|
||||||
return verb + 'ked'
|
return verb + 'ked'
|
||||||
}
|
}
|
||||||
|
|
||||||
// for american english only
|
// for american english only
|
||||||
if ((/el$/i).test(verb)) {
|
if ((/el$/i).test(verb)) {
|
||||||
return verb + 'ed'
|
return verb + 'ed'
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((/[aeio][aeiou][dlmnprst]$/).test(verb)) {
|
if ((/[aeio][aeiou][dlmnprst]$/).test(verb)) {
|
||||||
return verb + 'ed'
|
return verb + 'ed'
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((/[aeiou][bdglmnprst]$/i).test(verb)) {
|
if ((/[aeiou][bdglmnprst]$/i).test(verb)) {
|
||||||
return verb.replace(/(.+[aeiou])([bdglmnprst])/, '$1$2$2ed')
|
return verb.replace(/(.+[aeiou])([bdglmnprst])/, '$1$2$2ed')
|
||||||
}
|
}
|
||||||
|
|
||||||
return verb + 'ed'
|
return verb + 'ed'
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
@ -1,11 +1,9 @@
|
|||||||
import {store} from './store.js'
|
import { store } from './store'
|
||||||
import {doLoadConfigFromAPI} from './redux/config/config-actions.js'
|
import { doLoadConfigFromAPI } from './redux/config/config-actions'
|
||||||
import {doInitWorkers, doLoadNodeConfig} from './redux/app/app-actions.js'
|
import { doInitWorkers, doLoadNodeConfig } from './redux/app/app-actions'
|
||||||
import {doLoadNotificationConfig} from './redux/user/user-actions.js'
|
import { doLoadNotificationConfig } from './redux/user/user-actions'
|
||||||
|
import { initApi } from 'qortal-ui-crypto'
|
||||||
import './persistState.js'
|
import './persistState'
|
||||||
|
|
||||||
import {initApi} from 'qortal-ui-crypto'
|
|
||||||
|
|
||||||
initApi(store)
|
initApi(store)
|
||||||
|
|
||||||
@ -20,15 +18,15 @@ const workerInitChecker = () => {
|
|||||||
store.dispatch(doLoadNodeConfig())
|
store.dispatch(doLoadNodeConfig())
|
||||||
|
|
||||||
if (state.app.workers.ready) {
|
if (state.app.workers.ready) {
|
||||||
|
|
||||||
workerInitSubscription()
|
workerInitSubscription()
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (!state.app.workers.loading) store.dispatch(doInitWorkers(state.config.crypto.kdfThreads, state.config.user.constants.workerURL))
|
if (!state.app.workers.loading) store.dispatch(doInitWorkers(state.config.crypto.kdfThreads, state.config.user.constants.workerURL))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
workerInitChecker()
|
workerInitChecker()
|
||||||
|
|
||||||
const workerInitSubscription = store.subscribe(workerInitChecker)
|
const workerInitSubscription = store.subscribe(workerInitChecker)
|
||||||
|
|
||||||
if (!store.getState().config.loaded) {
|
if (!store.getState().config.loaded) {
|
||||||
|
@ -1,11 +1,13 @@
|
|||||||
import CryptoJS from 'crypto-js'
|
import CryptoJS from 'crypto-js'
|
||||||
|
|
||||||
export const encryptData = (data, salt) => CryptoJS.AES.encrypt(JSON.stringify(data), salt).toString()
|
export const encryptData = (data, salt) => CryptoJS.AES.encrypt(JSON.stringify(data), salt).toString()
|
||||||
|
|
||||||
export const decryptData = (ciphertext, salt) => {
|
export const decryptData = (ciphertext, salt) => {
|
||||||
const bytes = CryptoJS.AES.decrypt(ciphertext, salt)
|
const bytes = CryptoJS.AES.decrypt(ciphertext, salt)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
|
return JSON.parse(bytes.toString(CryptoJS.enc.Utf8))
|
||||||
} catch(err) {
|
} catch (err) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,2 +1,2 @@
|
|||||||
import './initStore.js'
|
import './initStore'
|
||||||
import './components/main-app.js'
|
import './components/main-app'
|
@ -1,23 +1,24 @@
|
|||||||
|
import { dispatcher } from './dispatcher'
|
||||||
|
import { NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP, NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL } from './types'
|
||||||
import config from './config'
|
import config from './config'
|
||||||
import {dispatcher} from './dispatcher'
|
import snackbar from '../functional-components/snackbar'
|
||||||
import snackbar from '../functional-components/snackbar.js'
|
|
||||||
import {NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP, NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL} from './types'
|
|
||||||
|
|
||||||
let initial = 0
|
let initial = 0
|
||||||
let _state
|
let _state
|
||||||
|
|
||||||
const notificationCheck = function () {
|
const notificationCheck = function () {
|
||||||
if (window.Notification && Notification.permission === 'granted') {
|
if (window.Notification && Notification.permission === 'granted') {
|
||||||
// ...
|
|
||||||
return true
|
return true
|
||||||
} else if (window.Notification && Notification.permission !== 'denied') {
|
} else if (window.Notification && Notification.permission !== 'denied') {
|
||||||
Notification.requestPermission().then(permission => {
|
Notification.requestPermission().then(permission => {
|
||||||
if (permission === 'granted') {
|
if (permission === 'granted') {
|
||||||
dispatcher(_state)
|
dispatcher(_state)
|
||||||
_state = ''
|
_state = ''
|
||||||
|
|
||||||
return true
|
return true
|
||||||
} else {
|
} else {
|
||||||
initial = initial + 1
|
initial = initial + 1
|
||||||
|
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: 'Notification is disabled, Enable it to recieve notifications.',
|
labelText: 'Notification is disabled, Enable it to recieve notifications.',
|
||||||
dismiss: true
|
dismiss: true
|
||||||
@ -41,21 +42,21 @@ const notificationCheck = function () {
|
|||||||
* @property notificationState = { type: NEW_MESSAGE, data }
|
* @property notificationState = { type: NEW_MESSAGE, data }
|
||||||
* @property data = { title: 'Qortal Chat', sound: config.messageAlert, options: { body: 'New Message', icon: config.default.icon, badge: config.default.icon }, req }
|
* @property data = { title: 'Qortal Chat', sound: config.messageAlert, options: { body: 'New Message', icon: config.default.icon, badge: config.default.icon }, req }
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const doNewMessage = function (req) {
|
export const doNewMessage = function (req) {
|
||||||
const newMessage = () => {
|
const newMessage = () => {
|
||||||
|
|
||||||
let data
|
let data
|
||||||
|
|
||||||
if (req.type && req.type === 'qapp') {
|
if (req.type && req.type === 'qapp') {
|
||||||
data = req
|
data = req
|
||||||
|
|
||||||
} else if (req.groupId) {
|
} else if (req.groupId) {
|
||||||
const title = `${req.groupName}`
|
const title = `${req.groupName}`
|
||||||
const body = `New Message from ${req.senderName === undefined ? req.sender : req.senderName}`
|
const body = `New Message from ${req.senderName === undefined ? req.sender : req.senderName}`
|
||||||
|
|
||||||
data = { title, sound: config.messageAlert, options: { body, icon: config.default.icon, badge: config.default.icon }, req }
|
data = { title, sound: config.messageAlert, options: { body, icon: config.default.icon, badge: config.default.icon }, req }
|
||||||
} else {
|
} else {
|
||||||
const title = `${req.senderName === undefined ? req.sender : req.senderName}`
|
const title = `${req.senderName === undefined ? req.sender : req.senderName}`
|
||||||
const body = 'New Message'
|
const body = 'New Message'
|
||||||
|
|
||||||
data = { title, sound: config.messageAlert, options: { body, icon: config.default.icon, badge: config.default.icon }, req }
|
data = { title, sound: config.messageAlert, options: { body, icon: config.default.icon, badge: config.default.icon }, req }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,20 +70,21 @@ export const doNewMessage = function (req) {
|
|||||||
} else {
|
} else {
|
||||||
dispatcher(notificationState)
|
dispatcher(notificationState)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
_state = notificationState
|
_state = notificationState
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const page = window.top.location.href
|
const page = window.top.location.href
|
||||||
if(req.type && req.type === 'qapp-local-notification'){
|
|
||||||
|
if (req.type && req.type === 'qapp-local-notification') {
|
||||||
try {
|
try {
|
||||||
dispatcher({ type: NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL, data: req })
|
dispatcher({ type: NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL, data: req })
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log('error', error)
|
console.log('error', error)
|
||||||
}
|
}
|
||||||
}else if (!document.hasFocus()) {
|
} else if (!document.hasFocus()) {
|
||||||
newMessage()
|
newMessage()
|
||||||
} else {
|
} else {
|
||||||
if (page.includes(req.url) === false) {
|
if (page.includes(req.url) === false) {
|
||||||
|
@ -2,14 +2,16 @@ import {NEW_MESSAGE, NEW_MESSAGE_NOTIFICATION_QAPP, NEW_MESSAGE_NOTIFICATION_QAP
|
|||||||
import {newMessage, newMessageNotificationQapp, newMessageNotificationQappLocal} from './notification-actions'
|
import {newMessage, newMessageNotificationQapp, newMessageNotificationQappLocal} from './notification-actions'
|
||||||
|
|
||||||
export const dispatcher = function (notificationState) {
|
export const dispatcher = function (notificationState) {
|
||||||
|
|
||||||
switch (notificationState.type) {
|
switch (notificationState.type) {
|
||||||
case NEW_MESSAGE:
|
case NEW_MESSAGE:
|
||||||
return newMessage(notificationState.data)
|
return newMessage(notificationState.data)
|
||||||
|
|
||||||
case NEW_MESSAGE_NOTIFICATION_QAPP:
|
case NEW_MESSAGE_NOTIFICATION_QAPP:
|
||||||
return newMessageNotificationQapp(notificationState.data)
|
return newMessageNotificationQapp(notificationState.data)
|
||||||
|
|
||||||
case NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL:
|
case NEW_MESSAGE_NOTIFICATION_QAPP_LOCAL:
|
||||||
return newMessageNotificationQappLocal(notificationState.data)
|
return newMessageNotificationQappLocal(notificationState.data)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
import {store} from '../../store.js'
|
import { store } from '../../store'
|
||||||
import {doPageUrl, setNewTab} from '../../redux/app/app-actions.js'
|
import { doPageUrl, setNewTab } from '../../redux/app/app-actions'
|
||||||
import isElectron from 'is-electron'
|
import isElectron from 'is-electron'
|
||||||
import ShortUniqueId from 'short-unique-id';
|
import ShortUniqueId from 'short-unique-id'
|
||||||
|
|
||||||
const uid = new ShortUniqueId()
|
const uid = new ShortUniqueId()
|
||||||
|
|
||||||
@ -10,10 +10,8 @@ export const newMessage = (data) => {
|
|||||||
|
|
||||||
// Should I show notification ?
|
// Should I show notification ?
|
||||||
if (store.getState().user.notifications.q_chat.showNotification) {
|
if (store.getState().user.notifications.q_chat.showNotification) {
|
||||||
|
|
||||||
// Yes, I can but should I play sound ?
|
// Yes, I can but should I play sound ?
|
||||||
if (store.getState().user.notifications.q_chat.playSound) {
|
if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onshow = (e) => {
|
notify.onshow = (e) => {
|
||||||
@ -25,7 +23,6 @@ export const newMessage = (data) => {
|
|||||||
store.dispatch(doPageUrl(pageUrl))
|
store.dispatch(doPageUrl(pageUrl))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onclick = (e) => {
|
notify.onclick = (e) => {
|
||||||
@ -37,18 +34,15 @@ export const newMessage = (data) => {
|
|||||||
} else if (store.getState().user.notifications.q_chat.playSound) {
|
} else if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
alert.play()
|
alert.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
export const newMessageNotificationQapp = (data) => {
|
|
||||||
|
|
||||||
|
export const newMessageNotificationQapp = (data) => {
|
||||||
const alert = playSound(data.sound)
|
const alert = playSound(data.sound)
|
||||||
|
|
||||||
// Should I show notification ?
|
// Should I show notification ?
|
||||||
if (store.getState().user.notifications.q_chat.showNotification) {
|
if (store.getState().user.notifications.q_chat.showNotification) {
|
||||||
|
|
||||||
// Yes, I can but should I play sound ?
|
// Yes, I can but should I play sound ?
|
||||||
if (store.getState().user.notifications.q_chat.playSound) {
|
if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onshow = (e) => {
|
notify.onshow = (e) => {
|
||||||
@ -71,15 +65,14 @@ export const newMessageNotificationQapp = (data) => {
|
|||||||
"parent": false
|
"parent": false
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (!isElectron()) {
|
if (!isElectron()) {
|
||||||
window.focus();
|
window.focus();
|
||||||
} else {
|
} else {
|
||||||
window.electronAPI.focusApp()
|
window.electronAPI.focusApp()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onclick = (e) => {
|
notify.onclick = (e) => {
|
||||||
@ -98,6 +91,7 @@ export const newMessageNotificationQapp = (data) => {
|
|||||||
"parent": false
|
"parent": false
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|
||||||
if (!isElectron()) {
|
if (!isElectron()) {
|
||||||
window.focus();
|
window.focus();
|
||||||
} else {
|
} else {
|
||||||
@ -109,25 +103,32 @@ export const newMessageNotificationQapp = (data) => {
|
|||||||
} else if (store.getState().user.notifications.q_chat.playSound) {
|
} else if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
alert.play()
|
alert.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
|
||||||
parts.shift();
|
const service = parts[0].toUpperCase()
|
||||||
const name = parts[0];
|
|
||||||
parts.shift();
|
parts.shift()
|
||||||
let identifier;
|
|
||||||
|
const name = parts[0]
|
||||||
|
|
||||||
|
parts.shift()
|
||||||
|
|
||||||
|
let identifier
|
||||||
|
|
||||||
if (parts.length > 0) {
|
if (parts.length > 0) {
|
||||||
identifier = parts[0]; // Do not shift yet
|
// Do not shift yet
|
||||||
|
identifier = parts[0]
|
||||||
|
|
||||||
// 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=${this.getApiKey()}`
|
url: `/arbitrary/resource/status/${service}/${name}/${identifier}?apiKey=${this.getApiKey()}`
|
||||||
@ -135,24 +136,24 @@ export const newMessageNotificationQapp = (data) => {
|
|||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
export const newMessageNotificationQappLocal = (data) => {
|
export const newMessageNotificationQappLocal = (data) => {
|
||||||
@ -160,34 +161,41 @@ export const newMessageNotificationQappLocal = (data) => {
|
|||||||
|
|
||||||
// Should I show notification ?
|
// Should I show notification ?
|
||||||
if (store.getState().user.notifications.q_chat.showNotification) {
|
if (store.getState().user.notifications.q_chat.showNotification) {
|
||||||
|
|
||||||
// Yes, I can but should I play sound ?
|
// Yes, I can but should I play sound ?
|
||||||
if (store.getState().user.notifications.q_chat.playSound) {
|
if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onshow = (e) => {
|
notify.onshow = (e) => {
|
||||||
alert.play()
|
alert.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
notify.onclick = async(e) => {
|
notify.onclick = async (e) => {
|
||||||
let newQuery = data?.url;
|
let newQuery = data?.url
|
||||||
|
|
||||||
if (newQuery.endsWith('/')) {
|
if (newQuery.endsWith('/')) {
|
||||||
newQuery = newQuery.slice(0, -1);
|
newQuery = newQuery.slice(0, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await extractComponents(newQuery)
|
const res = await extractComponents(newQuery)
|
||||||
|
|
||||||
if (!res) return
|
if (!res) return
|
||||||
|
|
||||||
const { service, name, identifier, path } = res
|
const { service, name, identifier, path } = res
|
||||||
|
|
||||||
let query = `?service=${service}`
|
let query = `?service=${service}`
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
query = query + `&name=${name}`
|
query = query + `&name=${name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
query = query + `&identifier=${identifier}`
|
query = query + `&identifier=${identifier}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
query = query + `&path=${path}`
|
query = query + `&path=${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const tab = {
|
const tab = {
|
||||||
url: `qdn/browser/index.html${query}`,
|
url: `qdn/browser/index.html${query}`,
|
||||||
id: uid.rnd(),
|
id: uid.rnd(),
|
||||||
@ -202,36 +210,45 @@ export const newMessageNotificationQappLocal = (data) => {
|
|||||||
"parent": false
|
"parent": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(setNewTab(tab))
|
store.dispatch(setNewTab(tab))
|
||||||
|
|
||||||
if (!isElectron()) {
|
if (!isElectron()) {
|
||||||
window.focus();
|
window.focus()
|
||||||
} else {
|
} else {
|
||||||
window.electronAPI.focusApp()
|
window.electronAPI.focusApp()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
const notify = new Notification(data.title, data.options)
|
const notify = new Notification(data.title, data.options)
|
||||||
|
|
||||||
notify.onclick = async(e) => {
|
notify.onclick = async (e) => {
|
||||||
let newQuery = data?.url;
|
let newQuery = data?.url
|
||||||
|
|
||||||
if (newQuery.endsWith('/')) {
|
if (newQuery.endsWith('/')) {
|
||||||
newQuery = newQuery.slice(0, -1);
|
newQuery = newQuery.slice(0, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
const res = await extractComponents(newQuery)
|
const res = await extractComponents(newQuery)
|
||||||
|
|
||||||
if (!res) return
|
if (!res) return
|
||||||
|
|
||||||
const { service, name, identifier, path } = res
|
const { service, name, identifier, path } = res
|
||||||
|
|
||||||
let query = `?service=${service}`
|
let query = `?service=${service}`
|
||||||
|
|
||||||
if (name) {
|
if (name) {
|
||||||
query = query + `&name=${name}`
|
query = query + `&name=${name}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (identifier) {
|
if (identifier) {
|
||||||
query = query + `&identifier=${identifier}`
|
query = query + `&identifier=${identifier}`
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path) {
|
if (path) {
|
||||||
query = query + `&path=${path}`
|
query = query + `&path=${path}`
|
||||||
}
|
}
|
||||||
|
|
||||||
const tab = {
|
const tab = {
|
||||||
url: `qdn/browser/index.html${query}`,
|
url: `qdn/browser/index.html${query}`,
|
||||||
id: uid.rnd(),
|
id: uid.rnd(),
|
||||||
@ -246,20 +263,20 @@ export const newMessageNotificationQappLocal = (data) => {
|
|||||||
"parent": false
|
"parent": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(setNewTab(tab))
|
store.dispatch(setNewTab(tab))
|
||||||
|
|
||||||
if (!isElectron()) {
|
if (!isElectron()) {
|
||||||
window.focus();
|
window.focus()
|
||||||
} else {
|
} else {
|
||||||
window.electronAPI.focusApp()
|
window.electronAPI.focusApp()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If sounds are enabled, but notifications are not
|
// If sounds are enabled, but notifications are not
|
||||||
} else if (store.getState().user.notifications.q_chat.playSound) {
|
} else if (store.getState().user.notifications.q_chat.playSound) {
|
||||||
alert.play()
|
alert.play()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const playSound = (soundUrl) => {
|
const playSound = (soundUrl) => {
|
||||||
|
@ -1,20 +1,17 @@
|
|||||||
import {store} from './store.js'
|
import { store } from './store'
|
||||||
import {saveStateToLocalStorage} from './localStorageHelpers.js'
|
import { saveStateToLocalStorage } from './localStorageHelpers'
|
||||||
|
|
||||||
const keys = [
|
|
||||||
'config',
|
|
||||||
'user'
|
|
||||||
]
|
|
||||||
|
|
||||||
|
const keys = ['config', 'user']
|
||||||
const oldReducers = {}
|
const oldReducers = {}
|
||||||
|
|
||||||
const oldState = store.getState()
|
const oldState = store.getState()
|
||||||
|
|
||||||
for (const key of keys) {
|
for (const key of keys) {
|
||||||
oldReducers[key] = oldState[key]
|
oldReducers[key] = oldState[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
store.subscribe(() => {
|
store.subscribe(() => {
|
||||||
const newState = store.getState()
|
const newState = store.getState()
|
||||||
|
|
||||||
keys.forEach(key => {
|
keys.forEach(key => {
|
||||||
if (newState[key] !== oldState[key]) {
|
if (newState[key] !== oldState[key]) {
|
||||||
saveStateToLocalStorage(key, store.getState()[key])
|
saveStateToLocalStorage(key, store.getState()[key])
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {routes} from './routes.js'
|
import { routes } from './routes'
|
||||||
|
|
||||||
export const addPluginRoutes = epmlInstance => {
|
export const addPluginRoutes = epmlInstance => {
|
||||||
Object.entries(routes).forEach(([route, handler]) => {
|
Object.entries(routes).forEach(([route, handler]) => {
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {Epml} from '../epml.js'
|
import { Epml } from '../epml'
|
||||||
import {addPluginRoutes} from './addPluginRoutes'
|
import { addPluginRoutes } from './addPluginRoutes'
|
||||||
import {doAddPlugin} from '../redux/app/app-actions.js'
|
import { doAddPlugin } from '../redux/app/app-actions'
|
||||||
|
|
||||||
let retryLoadPluginsInterval = 0
|
let retryLoadPluginsInterval = 0
|
||||||
|
|
||||||
export const loadPlugins = () => fetch('/getPlugins')
|
export const loadPlugins = () => fetch('/getPlugins')
|
||||||
.then(response => response.json())
|
.then(response => response.json()).then(response => {
|
||||||
.then(response => {
|
|
||||||
const plugins = response.plugins
|
const plugins = response.plugins
|
||||||
const config = store.getState().config
|
const config = store.getState().config
|
||||||
pluginLoader(plugins, config)
|
pluginLoader(plugins, config)
|
||||||
})
|
}).catch(err => {
|
||||||
.catch(err => {
|
|
||||||
retryLoadPluginsInterval += 1000
|
retryLoadPluginsInterval += 1000
|
||||||
console.error(err)
|
console.error(err)
|
||||||
console.error(`Could not load plugins. Retrying in ${retryLoadPluginsInterval / 1000} second(s)`)
|
console.error(`Could not load plugins. Retrying in ${retryLoadPluginsInterval / 1000} second(s)`)
|
||||||
@ -20,11 +19,12 @@ export const loadPlugins = () => fetch('/getPlugins')
|
|||||||
|
|
||||||
export const pluginLoader = (plugins, config) => {
|
export const pluginLoader = (plugins, config) => {
|
||||||
const pluginContentWindows = []
|
const pluginContentWindows = []
|
||||||
|
|
||||||
plugins.forEach(plugin => {
|
plugins.forEach(plugin => {
|
||||||
const frame = document.createElement('iframe')
|
const frame = document.createElement('iframe')
|
||||||
|
|
||||||
frame.className += 'pluginJSFrame'
|
frame.className += 'pluginJSFrame'
|
||||||
frame.sandbox = 'allow-scripts allow-same-origin'
|
frame.sandbox = 'allow-scripts allow-same-origin'
|
||||||
|
|
||||||
frame.src = window.location.origin + '/qortal-components/plugin-mainjs-loader.html#' + plugin + '/main.js'
|
frame.src = window.location.origin + '/qortal-components/plugin-mainjs-loader.html#' + plugin + '/main.js'
|
||||||
|
|
||||||
const insertedFrame = window.document.body.appendChild(frame)
|
const insertedFrame = window.document.body.appendChild(frame)
|
||||||
@ -37,6 +37,7 @@ export const pluginLoader = (plugins, config) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
addPluginRoutes(epmlInstance)
|
addPluginRoutes(epmlInstance)
|
||||||
|
|
||||||
epmlInstance.imReady()
|
epmlInstance.imReady()
|
||||||
|
|
||||||
Epml.registerProxyInstance(`${plugin}-plugin`, epmlInstance)
|
Epml.registerProxyInstance(`${plugin}-plugin`, epmlInstance)
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
<html>
|
<html>
|
||||||
|
<head></head>
|
||||||
<head></head>
|
<body>
|
||||||
|
|
||||||
<body>
|
|
||||||
<script src="/qortal-components/plugin-mainjs-loader.js" type="application/javascript"></script>
|
<script src="/qortal-components/plugin-mainjs-loader.js" type="application/javascript"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
@ -1,12 +1,15 @@
|
|||||||
'use strict'
|
import { Epml, EpmlStream } from '../epml'
|
||||||
import {Epml, EpmlStream} from '../epml.js'
|
|
||||||
|
|
||||||
window.Epml = Epml
|
window.Epml = Epml
|
||||||
window.EpmlStream = EpmlStream
|
window.EpmlStream = EpmlStream
|
||||||
|
|
||||||
const pluginScript = document.createElement('script')
|
const pluginScript = document.createElement('script')
|
||||||
|
|
||||||
pluginScript.async = false
|
pluginScript.async = false
|
||||||
pluginScript.type = 'module'
|
pluginScript.type = 'module'
|
||||||
|
|
||||||
const hash = window.location.hash
|
const hash = window.location.hash
|
||||||
|
|
||||||
pluginScript.src = '/plugin/' + hash.slice(1)
|
pluginScript.src = '/plugin/' + hash.slice(1)
|
||||||
|
|
||||||
document.body.appendChild(pluginScript)
|
document.body.appendChild(pluginScript)
|
@ -1,4 +1,4 @@
|
|||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {
|
import {
|
||||||
doAddPluginUrl,
|
doAddPluginUrl,
|
||||||
doPageUrl,
|
doPageUrl,
|
||||||
@ -7,13 +7,14 @@ import {
|
|||||||
doUpdateAccountInfo,
|
doUpdateAccountInfo,
|
||||||
doUpdateBlockInfo,
|
doUpdateBlockInfo,
|
||||||
doUpdateNodeInfo,
|
doUpdateNodeInfo,
|
||||||
doUpdateNodeStatus,
|
doUpdateNodeStatus
|
||||||
} from '../redux/app/app-actions.js'
|
} from '../redux/app/app-actions'
|
||||||
|
import { loadStateFromLocalStorage, saveStateToLocalStorage, } from '../localStorageHelpers'
|
||||||
|
import { requestTransactionDialog } from '../functional-components/confirm-transaction-dialog'
|
||||||
|
import { doNewMessage } from '../notifications/controller'
|
||||||
import * as api from 'qortal-ui-crypto'
|
import * as api from 'qortal-ui-crypto'
|
||||||
import {requestTransactionDialog} from '../functional-components/confirm-transaction-dialog.js'
|
import snackbar from '../functional-components/snackbar'
|
||||||
import {doNewMessage} from '../notifications/controller.js'
|
|
||||||
import snackbar from '../functional-components/snackbar.js'
|
|
||||||
import {loadStateFromLocalStorage, saveStateToLocalStorage,} from '../localStorageHelpers.js'
|
|
||||||
|
|
||||||
const createTransaction = api.createTransaction
|
const createTransaction = api.createTransaction
|
||||||
const processTransaction = api.processTransaction
|
const processTransaction = api.processTransaction
|
||||||
@ -119,19 +120,20 @@ export const routes = {
|
|||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(tx.signedBytes)
|
res = await processTransactionVersion2(tx.signedBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(tx.signedBytes)
|
res = await processTransaction(tx.signedBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
let extraData = {}
|
let extraData = {}
|
||||||
if(req.data.type === 38 && tx && tx._rewardShareKeyPair && tx._rewardShareKeyPair.secretKey){
|
|
||||||
|
if (req.data.type === 38 && tx && tx._rewardShareKeyPair && tx._rewardShareKeyPair.secretKey) {
|
||||||
extraData.rewardSharePrivateKey = Base58.encode(tx._rewardShareKeyPair.secretKey)
|
extraData.rewardSharePrivateKey = Base58.encode(tx._rewardShareKeyPair.secretKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
success: true,
|
success: true,
|
||||||
data: res,
|
data: res,
|
||||||
@ -140,70 +142,80 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
success: false,
|
success: false,
|
||||||
message: e.message,
|
message: e.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
standaloneTransaction: async (req) => {
|
standaloneTransaction: async (req) => {
|
||||||
const rebuildUint8Array = (obj) => {
|
const rebuildUint8Array = (obj) => {
|
||||||
let _array = new Uint8Array(Object.keys(obj).length)
|
let _array = new Uint8Array(Object.keys(obj).length)
|
||||||
|
|
||||||
for (let i = 0; i < _array.byteLength; ++i) {
|
for (let i = 0; i < _array.byteLength; ++i) {
|
||||||
_array.set([obj[i]], i)
|
_array.set([obj[i]], i)
|
||||||
}
|
}
|
||||||
|
|
||||||
return _array
|
return _array
|
||||||
}
|
}
|
||||||
|
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// req.data.keyPair unfortunately "prepared" into horrible object so we need to convert back
|
// req.data.keyPair unfortunately "prepared" into horrible object so we need to convert back
|
||||||
let _keyPair = {}
|
let _keyPair = {}
|
||||||
|
|
||||||
for (let _keyName in req.data.keyPair) {
|
for (let _keyName in req.data.keyPair) {
|
||||||
_keyPair[_keyName] = rebuildUint8Array(
|
_keyPair[_keyName] = rebuildUint8Array(
|
||||||
req.data.keyPair[_keyName]
|
req.data.keyPair[_keyName]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const tx = createTransaction(
|
const tx = createTransaction(
|
||||||
req.data.type,
|
req.data.type,
|
||||||
_keyPair,
|
_keyPair,
|
||||||
req.data.params
|
req.data.params
|
||||||
)
|
)
|
||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(tx.signedBytes)
|
res = await processTransactionVersion2(tx.signedBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(tx.signedBytes)
|
res = await processTransaction(tx.signedBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
success: true,
|
success: true,
|
||||||
data: res,
|
data: res
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = {
|
response = {
|
||||||
success: false,
|
success: false,
|
||||||
message: e.message,
|
message: e.message
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
username: async (req) => {
|
username: async (req) => {
|
||||||
const state = store.getState()
|
const state = store.getState()
|
||||||
return state.user.storedWallets[state.app.wallet.addresses[0].address]
|
return state.user.storedWallets[state.app.wallet.addresses[0].address].name
|
||||||
.name
|
|
||||||
},
|
},
|
||||||
|
|
||||||
chat: async (req) => {
|
chat: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const tx = createTransaction(
|
const tx = createTransaction(
|
||||||
req.data.type,
|
req.data.type,
|
||||||
@ -215,13 +227,16 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = false
|
response = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sign_chat: async (req) => {
|
sign_chat: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const signedChatBytes = await signChatTransaction(
|
const signedChatBytes = await signChatTransaction(
|
||||||
req.data.chatBytesArray,
|
req.data.chatBytesArray,
|
||||||
@ -231,10 +246,11 @@ export const routes = {
|
|||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(signedChatBytes)
|
res = await processTransactionVersion2(signedChatBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(signedChatBytes)
|
res = await processTransaction(signedChatBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,13 +258,16 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = false
|
response = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sign_arbitrary: async (req) => {
|
sign_arbitrary: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const signedArbitraryBytes = await signArbitraryTransaction(
|
const signedArbitraryBytes = await signArbitraryTransaction(
|
||||||
req.data.arbitraryBytesBase58,
|
req.data.arbitraryBytesBase58,
|
||||||
@ -256,12 +275,14 @@ export const routes = {
|
|||||||
req.data.arbitraryNonce,
|
req.data.arbitraryNonce,
|
||||||
store.getState().app.wallet._addresses[req.data.nonce].keyPair
|
store.getState().app.wallet._addresses[req.data.nonce].keyPair
|
||||||
)
|
)
|
||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(signedArbitraryBytes)
|
res = await processTransactionVersion2(signedArbitraryBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(signedArbitraryBytes)
|
res = await processTransaction(signedArbitraryBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,25 +290,30 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = false
|
response = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sign_arbitrary_with_fee: async (req) => {
|
sign_arbitrary_with_fee: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const signedArbitraryBytes = await signArbitraryWithFeeTransaction(
|
const signedArbitraryBytes = await signArbitraryWithFeeTransaction(
|
||||||
req.data.arbitraryBytesBase58,
|
req.data.arbitraryBytesBase58,
|
||||||
req.data.arbitraryBytesForSigningBase58,
|
req.data.arbitraryBytesForSigningBase58,
|
||||||
store.getState().app.wallet._addresses[req.data.nonce].keyPair
|
store.getState().app.wallet._addresses[req.data.nonce].keyPair
|
||||||
)
|
)
|
||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(signedArbitraryBytes)
|
res = await processTransactionVersion2(signedArbitraryBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(signedArbitraryBytes)
|
res = await processTransaction(signedArbitraryBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,8 +321,10 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = false
|
response = false
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -307,12 +335,13 @@ export const routes = {
|
|||||||
showSnackBar: async (req) => {
|
showSnackBar: async (req) => {
|
||||||
snackbar.add({
|
snackbar.add({
|
||||||
labelText: req.data,
|
labelText: req.data,
|
||||||
dismiss: true,
|
dismiss: true
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
tradeBotCreateRequest: async (req) => {
|
tradeBotCreateRequest: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unsignedTxn = await tradeBotCreateRequest(req.data)
|
const unsignedTxn = await tradeBotCreateRequest(req.data)
|
||||||
|
|
||||||
@ -320,37 +349,46 @@ export const routes = {
|
|||||||
unsignedTxn,
|
unsignedTxn,
|
||||||
store.getState().app.selectedAddress.keyPair
|
store.getState().app.selectedAddress.keyPair
|
||||||
)
|
)
|
||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(signedTxnBytes)
|
res = await processTransactionVersion2(signedTxnBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(signedTxnBytes)
|
res = await processTransaction(signedTxnBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
response = res
|
response = res
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
tradeBotRespondRequest: async (req) => {
|
tradeBotRespondRequest: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await tradeBotRespondRequest(req.data)
|
response = await tradeBotRespondRequest(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
deleteTradeOffer: async (req) => {
|
deleteTradeOffer: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const unsignedTxn = await deleteTradeOffer(req.data)
|
const unsignedTxn = await deleteTradeOffer(req.data)
|
||||||
|
|
||||||
@ -361,10 +399,11 @@ export const routes = {
|
|||||||
|
|
||||||
let res
|
let res
|
||||||
|
|
||||||
if(req.data.apiVersion && req.data.apiVersion === 2){
|
if (req.data.apiVersion && req.data.apiVersion === 2) {
|
||||||
res = await processTransactionVersion2(signedTxnBytes)
|
res = await processTransactionVersion2(signedTxnBytes)
|
||||||
}
|
}
|
||||||
if(!req.data.apiVersion){
|
|
||||||
|
if (!req.data.apiVersion) {
|
||||||
res = await processTransaction(signedTxnBytes)
|
res = await processTransaction(signedTxnBytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,94 +411,115 @@ export const routes = {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
cancelAllOffers: async (req) => {
|
cancelAllOffers: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await cancelAllOffers(
|
response = await cancelAllOffers(store.getState().app.selectedAddress)
|
||||||
store.getState().app.selectedAddress
|
|
||||||
)
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendBtc: async (req) => {
|
sendBtc: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendBtc(req.data)
|
response = await sendBtc(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendLtc: async (req) => {
|
sendLtc: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendLtc(req.data)
|
response = await sendLtc(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendDoge: async (req) => {
|
sendDoge: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendDoge(req.data)
|
response = await sendDoge(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendDgb: async (req) => {
|
sendDgb: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendDgb(req.data)
|
response = await sendDgb(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendRvn: async (req) => {
|
sendRvn: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendRvn(req.data)
|
response = await sendRvn(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
},
|
||||||
|
|
||||||
sendArrr: async (req) => {
|
sendArrr: async (req) => {
|
||||||
let response
|
let response
|
||||||
|
|
||||||
try {
|
try {
|
||||||
response = await sendArrr(req.data)
|
response = await sendArrr(req.data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
console.error(e.message)
|
console.error(e.message)
|
||||||
|
|
||||||
response = e.message
|
response = e.message
|
||||||
}
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
},
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import {store} from '../store.js'
|
import { store } from '../store'
|
||||||
import {EpmlStream} from 'epml'
|
import { EpmlStream } from 'epml'
|
||||||
|
|
||||||
const LOGIN_STREAM_NAME = 'logged_in'
|
const LOGIN_STREAM_NAME = 'logged_in'
|
||||||
const CONFIG_STREAM_NAME = 'config'
|
const CONFIG_STREAM_NAME = 'config'
|
||||||
@ -23,9 +23,6 @@ export const sideEffectActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => s
|
|||||||
export const profileDataActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.profileData)
|
export const profileDataActionStream = new EpmlStream(SIDE_EFFECT_ACTION, () => store.getState().app.profileData)
|
||||||
export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances)
|
export const coinBalancesActionStream = new EpmlStream(COIN_BALANCES_ACTION, () => store.getState().app.coinBalances)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let oldState = {
|
let oldState = {
|
||||||
app: {}
|
app: {}
|
||||||
}
|
}
|
||||||
@ -57,6 +54,7 @@ store.subscribe(() => {
|
|||||||
textColor: state.app.selectedAddress.textColor
|
textColor: state.app.selectedAddress.textColor
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldState.app.chatHeads !== state.app.chatHeads) {
|
if (oldState.app.chatHeads !== state.app.chatHeads) {
|
||||||
chatHeadsStateStream.emit(state.app.chatHeads)
|
chatHeadsStateStream.emit(state.app.chatHeads)
|
||||||
}
|
}
|
||||||
@ -67,13 +65,12 @@ store.subscribe(() => {
|
|||||||
if (oldState.app.sideEffectAction !== state.app.sideEffectAction) {
|
if (oldState.app.sideEffectAction !== state.app.sideEffectAction) {
|
||||||
sideEffectActionStream.emit(state.app.sideEffectAction)
|
sideEffectActionStream.emit(state.app.sideEffectAction)
|
||||||
}
|
}
|
||||||
if(oldState.app.profileDataActionStream !== state.app.profileDataActionStream){
|
if (oldState.app.profileDataActionStream !== state.app.profileDataActionStream) {
|
||||||
profileDataActionStream.emit(state.app.profileData)
|
profileDataActionStream.emit(state.app.profileData)
|
||||||
}
|
}
|
||||||
if (oldState.app.coinBalances !== state.app.coinBalances) {
|
if (oldState.app.coinBalances !== state.app.coinBalances) {
|
||||||
coinBalancesActionStream.emit(state.app.coinBalances)
|
coinBalancesActionStream.emit(state.app.coinBalances)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
oldState = state
|
oldState = state
|
||||||
})
|
})
|
@ -25,7 +25,7 @@ import {
|
|||||||
REMOVE_QAPP_FRIENDS_LIST,
|
REMOVE_QAPP_FRIENDS_LIST,
|
||||||
ALLOW_SHOW_SYNC_INDICATOR,
|
ALLOW_SHOW_SYNC_INDICATOR,
|
||||||
REMOVE_SHOW_SYNC_INDICATOR
|
REMOVE_SHOW_SYNC_INDICATOR
|
||||||
} from '../app-action-types.js'
|
} from '../app-action-types'
|
||||||
|
|
||||||
export const doUpdateBlockInfo = (blockObj) => {
|
export const doUpdateBlockInfo = (blockObj) => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
@ -119,6 +119,7 @@ export const removeQAPPAutoAuth = (payload) => {
|
|||||||
payload
|
payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const allowQAPPAutoLists = (payload) => {
|
export const allowQAPPAutoLists = (payload) => {
|
||||||
return {
|
return {
|
||||||
type: ALLOW_QAPP_AUTO_LISTS,
|
type: ALLOW_QAPP_AUTO_LISTS,
|
||||||
@ -153,6 +154,7 @@ export const setChatLastSeen = (payload) => {
|
|||||||
payload
|
payload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const addChatLastSeen = (payload) => {
|
export const addChatLastSeen = (payload) => {
|
||||||
return {
|
return {
|
||||||
type: ADD_CHAT_LAST_SEEN,
|
type: ADD_CHAT_LAST_SEEN,
|
||||||
@ -195,7 +197,7 @@ export const setTabNotifications = (payload) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const setSideEffectAction = (payload)=> {
|
export const setSideEffectAction = (payload) => {
|
||||||
return {
|
return {
|
||||||
type: SET_SIDE_EFFECT,
|
type: SET_SIDE_EFFECT,
|
||||||
payload
|
payload
|
||||||
|
@ -1,20 +1,21 @@
|
|||||||
import {Epml} from '../../../epml.js'
|
import { Epml } from '../../../epml'
|
||||||
import {EpmlWorkerPlugin} from 'epml'
|
import { EpmlWorkerPlugin } from 'epml'
|
||||||
|
import { INIT_WORKERS } from '../app-action-types'
|
||||||
import {INIT_WORKERS} from '../app-action-types.js'
|
|
||||||
|
|
||||||
Epml.registerPlugin(EpmlWorkerPlugin)
|
Epml.registerPlugin(EpmlWorkerPlugin)
|
||||||
|
|
||||||
export const doInitWorkers = (numberOfWorkers, workerURL) => {
|
export const doInitWorkers = (numberOfWorkers, workerURL) => {
|
||||||
const workers = []
|
const workers = []
|
||||||
|
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(initWorkers())
|
dispatch(initWorkers())
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (let i = 0; i < numberOfWorkers; i++) {
|
for (let i = 0; i < numberOfWorkers; i++) {
|
||||||
workers.push(new Epml({ type: 'WORKER', source: new Worker(workerURL) }))
|
workers.push(new Epml({ type: 'WORKER', source: new Worker(workerURL) }))
|
||||||
}
|
}
|
||||||
Promise.all(workers.map(workerEpml => workerEpml.ready()))
|
|
||||||
.then(() => {
|
Promise.all(workers.map(workerEpml => workerEpml.ready())).then(() => {
|
||||||
dispatch(initWorkers('success', workers))
|
dispatch(initWorkers('success', workers))
|
||||||
})
|
})
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -22,6 +23,7 @@ export const doInitWorkers = (numberOfWorkers, workerURL) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const initWorkers = (status, payload) => {
|
const initWorkers = (status, payload) => {
|
||||||
return {
|
return {
|
||||||
type: INIT_WORKERS,
|
type: INIT_WORKERS,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {LOG_IN, LOG_OUT, SELECT_ADDRESS} from '../app-action-types.js'
|
import { LOG_IN, LOG_OUT, SELECT_ADDRESS } from '../app-action-types'
|
||||||
|
|
||||||
export const doSelectAddress = address => {
|
export const doSelectAddress = address => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user