@@ -450,8 +450,7 @@ class WebBrowser extends LitElement {
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- console.log('case passed here');
- console.log(data.coin, "data coin here");
+ console.log({data});
const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE
);
@@ -535,10 +534,159 @@ class WebBrowser extends LitElement {
break;
case 'SEND_COIN':
+ console.log({data});
// Params: data.coin, data.destinationAddress, data.amount, data.fee
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ const amount = data.amount;
+ let recipient = data.destinationAddress;
+ const fee = data.fee
+ this.loader.show();
+
+ const walletBalance = await parentEpml.request('apiCall', {
+ url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
+ }).then((res) => {
+ if (isNaN(Number(res))) {
+ let snack4string = get("chatpage.cchange48")
+ parentEpml.request('showSnackBar', `${snack4string}`)
+ return;
+ } else {
+ return Number(res).toFixed(8);
+ }
+ })
+
+ const myRef = await parentEpml.request("apiCall", {
+ type: "api",
+ url: `/addresses/lastreference/${this.myAddress.address}`,
+ })
+
+ if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalance)) {
+ this.loader.hide();
+ let snack1string = get("chatpage.cchange51");
+ parentEpml.request('showSnackBar', `${snack1string}`);
+ return false;
+ }
+
+ if (parseFloat(amount) <= 0) {
+ this.loader.hide();
+ let snack2string = get("chatpage.cchange52");
+ parentEpml.request('showSnackBar', `${snack2string}`);
+ return false;
+ }
+
+ if (recipient.length === 0) {
+ this.loader.hide();
+ let snack3string = get("chatpage.cchange53");
+ parentEpml.request('showSnackBar', `${snack3string}`);
+ return false;
+ }
+
+ const validateName = async (receiverName) => {
+ let myRes;
+ let myNameRes = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/names/${receiverName}`,
+ })
+
+ if (myNameRes.error === 401) {
+ myRes = false;
+ } else {
+ myRes = myNameRes;
+ }
+ return myRes;
+ }
+
+ const validateAddress = async (receiverAddress) => {
+ let myAddress = await window.parent.validateAddress(receiverAddress);
+ return myAddress;
+ }
+
+ const validateReceiver = async (recipient) => {
+ let lastRef = myRef;
+ let isAddress;
+
+ try {
+ isAddress = await validateAddress(recipient);
+ } catch (err) {
+ isAddress = false;
+ }
+
+ if (isAddress) {
+ let myTransaction = await makeTransactionRequest(recipient, lastRef);
+ getTxnRequestResponse(myTransaction);
+ } else {
+ let myNameRes = await validateName(recipient);
+ if (myNameRes !== false) {
+ let myNameAddress = myNameRes.owner
+ let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
+ getTxnRequestResponse(myTransaction)
+ } else {
+ console.error(`${translate("chatpage.cchange54")}`)
+ parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
+ this.loader.hide();
+ }
+ }
+ }
+
+ const getName = async (recipient)=> {
+ try {
+ const getNames = await parentEpml.request("apiCall", {
+ type: "api",
+ url: `/names/address/${recipient}`,
+ });
+
+ if (getNames.length > 0 ) {
+ return getNames[0].name;
+ } else {
+ return '';
+ }
+ } catch (error) {
+ return "";
+ }
+ }
+
+ const makeTransactionRequest = async (receiver, lastRef) => {
+ let myReceiver = receiver;
+ let mylastRef = lastRef;
+ let dialogamount = get("transactions.amount");
+ let dialogAddress = get("login.address");
+ let dialogName = get("login.name");
+ let dialogto = get("transactions.to");
+ let recipientName = await getName(myReceiver);
+ let myTxnrequest = await parentEpml.request('transaction', {
+ type: 2,
+ nonce: this.myAddress.nonce,
+ params: {
+ recipient: myReceiver,
+ recipientName: recipientName,
+ amount: amount,
+ lastReference: mylastRef,
+ fee: fee,
+ dialogamount: dialogamount,
+ dialogto: dialogto,
+ dialogAddress,
+ dialogName
+ },
+ })
+ return myTxnrequest;
+ }
+
+ const getTxnRequestResponse = (txnResponse) => {
+ if (txnResponse.success === false && txnResponse.message) {
+ parentEpml.request('showSnackBar', `${txnResponse.message}`);
+ this.loader.hide();
+ throw new Error(txnResponse);
+ } else if (txnResponse.success === true && !txnResponse.data.error) {
+ parentEpml.request('showSnackBar', `${get("chatpage.cchange55")}`)
+ this.loader.hide();
+ } else {
+ parentEpml.request('showSnackBar', `${txnResponse.data.message}`);
+ this.loader.hide();
+ throw new Error(txnResponse);
+ }
+ }
+ validateReceiver(recipient);
break;
default:
From 2d276d583f5da6ce3ad622f223df7a908948ef89 Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Tue, 21 Feb 2023 13:32:24 -0500
Subject: [PATCH 13/83] Fixed SEND_COIN issue
---
.../plugins/core/qdn/browser/browser.src.js | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 5622772e..2664556a 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -614,13 +614,13 @@ class WebBrowser extends LitElement {
if (isAddress) {
let myTransaction = await makeTransactionRequest(recipient, lastRef);
- getTxnRequestResponse(myTransaction);
+ return getTxnRequestResponse(myTransaction);
} else {
let myNameRes = await validateName(recipient);
if (myNameRes !== false) {
let myNameAddress = myNameRes.owner
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
- getTxnRequestResponse(myTransaction)
+ return getTxnRequestResponse(myTransaction)
} else {
console.error(`${translate("chatpage.cchange54")}`)
parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
@@ -686,7 +686,17 @@ class WebBrowser extends LitElement {
throw new Error(txnResponse);
}
}
- validateReceiver(recipient);
+ try {
+ const result = await validateReceiver(recipient);
+ if (result) {
+ return result;
+ }
+ } catch (error) {
+ console.error(error);
+ return '{"error": "Request could not be fulfilled"}';
+ } finally {
+ console.log("Case completed.");
+ }
break;
default:
From 9a7cf9e4d4901c430dc7cee88f3b63ac589799dd Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Thu, 23 Feb 2023 12:52:51 -0500
Subject: [PATCH 14/83] Fixed SEND_CHAT_MESSAGE bugs
---
qortal-ui-core/language/us.json | 4 +-
.../plugins/core/qdn/browser/browser.src.js | 195 +++++++++++++++---
.../core/qdn/browser/computePowWorker.src.js | 82 ++++++++
3 files changed, 256 insertions(+), 25 deletions(-)
create mode 100644 qortal-ui-plugins/plugins/core/qdn/browser/computePowWorker.src.js
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 30320079..e0892920 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -498,7 +498,9 @@
"bchange18": "Do you give this application permission to get your user address?",
"bchange19": "Do you give this application permission to publish to QDN?",
"bchange20": "Do you give this application permission to get your wallet balance?",
- "bchange21": "Fetch Wallet Failed. Please try again!"
+ "bchange21": "Fetch Wallet Failed. Please try again!",
+ "bchange22": "Do you give this application permission to send a chat message?",
+ "bchange23": "Message Sent!"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 2664556a..862a5206 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -16,6 +16,7 @@ registerTranslateConfig({
import '@material/mwc-button';
import '@material/mwc-icon';
import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
+import WebWorkerChat from 'web-worker:./computePowWorker.src.js';
import { publishData } from '../../../utils/publish-image.js';
import { Loader } from '../../../utils/loader.js';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
@@ -108,7 +109,8 @@ class WebBrowser extends LitElement {
constructor() {
super();
this.url = 'about:blank';
- this.myAddress = window.parent.reduxStore.getState().app.selectedAddress;
+ this.myAddress = window.parent.reduxStore.getState().app.selectedAddress;
+ this._publicKey = { key: '', hasPubKey: false };
const urlParams = new URLSearchParams(window.location.search);
this.name = urlParams.get('name');
this.service = urlParams.get('service');
@@ -231,7 +233,6 @@ class WebBrowser extends LitElement {
}
render() {
- console.log(3, 'browser page here');
return html`
@@ -321,8 +322,8 @@ class WebBrowser extends LitElement {
console.log('UI received event: ' + JSON.stringify(data));
switch (data.action) {
- case 'GET_USER_ACCOUNT':
- case actions.GET_USER_ACCOUNT:
+ case 'GET_USER_ACCOUNT':
+ case actions.GET_USER_ACCOUNT:
const res1 = await showModalAndWait(
actions.GET_USER_ACCOUNT
);
@@ -418,12 +419,159 @@ class WebBrowser extends LitElement {
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
- case 'SEND_CHAT_MESSAGE':
+ case 'SEND_CHAT_MESSAGE': {
+ const message = data.message;
+ const recipient = data.destinationAddress;
+ const sendMessage = async (messageText, chatReference) => {
+ this.loader.show();
+ let _reference = new Uint8Array(64);
+ window.crypto.getRandomValues(_reference);
+ let reference = window.parent.Base58.encode(_reference);
+ const sendMessageRequest = async () => {
+ let chatResponse = await parentEpml.request('chat', {
+ type: 18,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ timestamp: Date.now(),
+ recipient: recipient,
+ recipientPublicKey: this._publicKey.key,
+ hasChatReference: 0,
+ chatReference: chatReference,
+ message: messageText,
+ lastReference: reference,
+ proofOfWorkNonce: 0,
+ isEncrypted: 1,
+ isText: 1
+ }
+ });
+ const msgResponse = await _computePow(chatResponse)
+ return msgResponse;
+ };
+
+ const _computePow = async (chatBytes) => {
+ const difficulty = 8;
+ const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
+ const worker = new WebWorkerChat();
+ let nonce = null;
+ let chatBytesArray = null;
+
+ await new Promise((res) => {
+ worker.postMessage({chatBytes, path, difficulty});
+ worker.onmessage = e => {
+ chatBytesArray = e.data.chatBytesArray;
+ nonce = e.data.nonce;
+ res();
+ }
+ });
+
+ let _response = await parentEpml.request('sign_chat', {
+ nonce: this.selectedAddress.nonce,
+ chatBytesArray: chatBytesArray,
+ chatNonce: nonce
+ });
+
+ const chatResponse = getSendChatResponse(_response);
+ return chatResponse;
+ };
+
+ const getSendChatResponse = (res) => {
+ if (res === true) {
+ let successString = get("browserpage.bchange23");
+ parentEpml.request('showSnackBar', `${successString}`);
+ } else if (res.error) {
+ parentEpml.request('showSnackBar', res.message);
+ }
+ this.loader.hide();
+ return res;
+ };
+
+ const chatResponse = await sendMessageRequest();
+ return chatResponse;
+ }
+
+ const result = await showModalAndWait(
+ actions.SEND_CHAT_MESSAGE
+ );
+ if (result.action === "accept") {
+ let hasPublicKey = true;
+ const res = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/addresses/publickey/${recipient}`
+ });
+
+ if (res.error === 102) {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ } else if (res !== false) {
+ this._publicKey.key = res
+ this._publicKey.hasPubKey = true
+ } else {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ }
+
+ if (!hasPublicKey) {
+ let err4string = get("chatpage.cchange39");
+ parentEpml.request('showSnackBar', `${err4string}`)
+ return
+ }
+
+ this.loader.show();
+
+ const tiptapJson = {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ content: [
+ {
+ type: 'text',
+ text: message,
+ },
+
+ ],
+ },
+ ],
+ }
+
+ const messageObject = {
+ messageText: tiptapJson,
+ images: [''],
+ repliedTo: '',
+ version: 2
+ };
+
+ const stringifyMessageObject = JSON.stringify(messageObject);
+ // if (this.balance < 4) {
+ // this.myTrimmedMeassage = ''
+ // this.myTrimmedMeassage = stringifyMessageObject
+ // this.shadowRoot.getElementById('confirmDialog').open()
+ // } else {
+ // this.sendMessage(stringifyMessageObject, typeMessage);
+ // }
+ try {
+ const msgResponse = await sendMessage(stringifyMessageObject);
+ response = msgResponse;
+ } catch (error) {
+ console.error(error);
+ return '{"error": "Request could not be fulfilled"}';
+ } finally {
+ this.loader.hide();
+ console.log("Case completed.");
+ }
+
+ } else {
+ response = '{"error": "User declined request"}';
+ }
+ // this.loader.show();
// Params: data.groupId, data.destinationAddress, data.message
// TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
+ }
case actions.JOIN_GROUP:
const groupId = data.groupId;
@@ -450,8 +598,7 @@ class WebBrowser extends LitElement {
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- console.log({data});
- const res3 = await showModalAndWait(
+ const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE
);
if (res3.action === 'accept') {
@@ -463,7 +610,6 @@ class WebBrowser extends LitElement {
const QORTBalance = await parentEpml.request('apiCall', {
url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
})
- console.log({QORTBalance})
return QORTBalance;
} catch (error) {
console.error(error);
@@ -504,19 +650,21 @@ class WebBrowser extends LitElement {
break
}
try {
- this.loader.show()
- await parentEpml.request('apiCall', {
+ this.loader.show();
+ const res = await parentEpml.request('apiCall', {
url: _url,
method: 'POST',
body: _body,
- }).then((res) => {
- if (isNaN(Number(res))) {
- throw new Error(get("browserpage.bchange21"));
- } else {
- console.log((Number(res) / 1e8).toFixed(8), "other wallet balance here");
- return (Number(res) / 1e8).toFixed(8)
- }
})
+ if (isNaN(Number(res))) {
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } else {
+ response = (Number(res) / 1e8).toFixed(8);
+ }
} catch (error) {
console.error(error);
const data = {};
@@ -534,7 +682,6 @@ class WebBrowser extends LitElement {
break;
case 'SEND_COIN':
- console.log({data});
// Params: data.coin, data.destinationAddress, data.amount, data.fee
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above)
@@ -697,12 +844,12 @@ class WebBrowser extends LitElement {
} finally {
console.log("Case completed.");
}
- break;
+ break;
- default:
- console.log('Unhandled message: ' + JSON.stringify(data));
- return;
- }
+ default:
+ console.log('Unhandled message: ' + JSON.stringify(data));
+ return;
+ }
// Parse response
let responseObj;
@@ -712,7 +859,6 @@ class WebBrowser extends LitElement {
// Not all responses will be JSON
responseObj = response;
}
-
// Respond to app
if (responseObj.error != null) {
event.ports[0].postMessage({
@@ -1050,6 +1196,7 @@ async function showModalAndWait(type, data) {
${type === actions.GET_USER_ACCOUNT ? `
${get("browserpage.bchange18")}
` : ''}
${type === actions.PUBLISH_QDN_RESOURCE ? `
${get("browserpage.bchange19")}
` : ''}
${type === actions.GET_WALLET_BALANCE ? `
${get("browserpage.bchange20")}
` : ''}
+ ${type === actions.SEND_CHAT_MESSAGE ? `
${get("browserpage.bchange22")}
` : ''}
+ ${this._groupdialog6}
+ `
+ }
+
+ set atDeployDialog1(atDeployDialog1) {
+ this._atDeployDialog1 = atDeployDialog1
+ }
+ set atDeployDialog2(atDeployDialog2) {
+ this._atDeployDialog2 = atDeployDialog2
+ }
+
+ set fee(fee) {
+ this._fee = fee
+ this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
+ }
+ set rAmount(rAmount) {
+ this._rAmount = rAmount
+ this._rAmountBytes = this.constructor.utils.int64ToBytes(this._rAmount)
+ }
+
+ set rName(rName) {
+ this._rName = rName
+ this._rNameBytes = this.constructor.utils.stringtoUTF8Array(this._rName.toLocaleLowerCase())
+ this._rNameLength = this.constructor.utils.int32ToBytes(this._rNameBytes.length)
+ }
+
+ set rDescription(rDescription) {
+ this._rDescription = rDescription
+ this._rDescriptionBytes = this.constructor.utils.stringtoUTF8Array(this._rDescription.toLocaleLowerCase())
+ this._rDescriptionLength = this.constructor.utils.int32ToBytes(this._rDescriptionBytes.length)
+ }
+ set atType(atType) {
+ this._atType = atType
+ this._atTypeBytes = this.constructor.utils.stringtoUTF8Array(this._atType)
+ this._atTypeLength = this.constructor.utils.int32ToBytes(this._atTypeBytes.length)
+ }
+ set rTags(rTags) {
+ this._rTags = rTags
+ this._rTagsBytes = this.constructor.utils.stringtoUTF8Array(this._rTags.toLocaleLowerCase())
+ this._rTagsLength = this.constructor.utils.int32ToBytes(this._rTagsBytes.length)
+ }
+ set rCreationBytes(rCreationBytes) {
+ const decode = this.constructor.Base58.decode(rCreationBytes)
+ console.log({decode})
+ this._rCreationBytes = this.constructor.utils.stringtoUTF8Array(decode)
+ this._rCreationBytesLength = this.constructor.utils.int32ToBytes(this._rCreationBytes.length)
+ }
+ set rAssetId(rAssetId) {
+ this._rAssetId = this.constructor.utils.int64ToBytes(rAssetId)
+ }
+
+
+ get params() {
+ const params = super.params
+ params.push(
+ this._rNameLength,
+ this._rNameBytes,
+ this._rDescriptionLength,
+ this._rDescriptionBytes,
+ this._atTypeLength,
+ this._atTypeBytes,
+ this._rTagsLength,
+ this._rTagsBytes,
+ this._rCreationBytesLength,
+ this._rCreationBytes,
+ this._rAmountBytes,
+ this._rAssetId,
+ this._feeBytes
+ )
+ return params
+ }
+}
diff --git a/qortal-ui-crypto/api/transactions/transactions.js b/qortal-ui-crypto/api/transactions/transactions.js
index 9fa87e99..0423d3ae 100644
--- a/qortal-ui-crypto/api/transactions/transactions.js
+++ b/qortal-ui-crypto/api/transactions/transactions.js
@@ -22,6 +22,7 @@ import LeaveGroupTransaction from './groups/LeaveGroupTransaction.js'
import RewardShareTransaction from './reward-share/RewardShareTransaction.js'
import RemoveRewardShareTransaction from './reward-share/RemoveRewardShareTransaction.js'
import TransferPrivsTransaction from './TransferPrivsTransaction.js'
+import DeployAtTransaction from './DeployAtTransaction.js'
export const transactionTypes = {
2: PaymentTransaction,
@@ -30,6 +31,7 @@ export const transactionTypes = {
5: SellNameTransacion,
6: CancelSellNameTransacion,
7: BuyNameTransacion,
+ 16: DeployAtTransaction,
17: MessageTransaction,
18: ChatTransaction,
181: GroupChatTransaction,
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 2f58042b..8266c5db 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -119,7 +119,7 @@ class WebBrowser extends LitElement {
this.path =
urlParams.get('path') != null
? (urlParams.get('path').startsWith('/') ? '' : '/') +
- urlParams.get('path')
+ urlParams.get('path')
: '';
this.followedNames = [];
this.blockedNames = [];
@@ -166,23 +166,20 @@ class WebBrowser extends LitElement {
const render = () => {
const myNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
- window.parent.reduxStore.getState().app.nodeConfig.node
+ window.parent.reduxStore.getState().app.nodeConfig.node
];
const nodeUrl =
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
- this.url = `${nodeUrl}/render/${this.service}/${this.name}${
- this.path != null ? this.path : ''
- }?theme=${this.theme}&identifier=${
- this.identifier != null ? this.identifier : ''
- }`;
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ''
+ }?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ''
+ }`;
};
const authorizeAndRender = () => {
parentEpml
.request('apiCall', {
- url: `/render/authorize/${
- this.name
- }?apiKey=${this.getApiKey()}`,
+ url: `/render/authorize/${this.name
+ }?apiKey=${this.getApiKey()}`,
method: 'POST',
})
.then((res) => {
@@ -231,7 +228,6 @@ class WebBrowser extends LitElement {
}
render() {
- console.log(2, 'browser page here');
return html`
@@ -273,6 +267,142 @@ class WebBrowser extends LitElement {
`;
}
+ async unitJoinFee() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ const url = `${nodeUrl}/transactions/unitfee?txType=JOIN_GROUP`
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new Error('Error when fetching join fee');
+ }
+
+ const data = await response.json()
+ const joinFee = (Number(data) / 1e8).toFixed(8)
+ return joinFee
+ }
+
+ async deployAtFee() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ const url = `${nodeUrl}/transactions/unitfee?txType=DEPLOY_AT`
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new Error('Error when fetching join fee');
+ }
+
+ const data = await response.json()
+ const joinFee = data
+ return joinFee
+ }
+
+ async _joinGroup(groupId, groupName) {
+ const joinFeeInput = await this.unitJoinFee()
+ const getLastRef = async () => {
+ let myRef = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/addresses/lastreference/${this.selectedAddress.address}`
+ })
+ return myRef
+ };
+
+ const validateReceiver = async () => {
+ let lastRef = await getLastRef();
+ let myTransaction = await makeTransactionRequest(lastRef)
+ const res = getTxnRequestResponse(myTransaction)
+ return res
+ }
+
+ const makeTransactionRequest = async (lastRef) => {
+ let groupdialog1 = get("transactions.groupdialog1")
+ let groupdialog2 = get("transactions.groupdialog2")
+ let myTxnrequest = await parentEpml.request('transaction', {
+ type: 31,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ fee: joinFeeInput,
+ registrantAddress: this.selectedAddress.address,
+ rGroupName: groupName,
+ rGroupId: groupId,
+ lastReference: lastRef,
+ groupdialog1: groupdialog1,
+ groupdialog2: groupdialog2
+ }
+ })
+ return myTxnrequest
+ }
+
+ const getTxnRequestResponse = (txnResponse) => {
+ if (txnResponse.success === false && txnResponse.message) {
+ throw new Error(txnResponse.message)
+ } else if (txnResponse.success === true && !txnResponse.data.error) {
+ return txnResponse.data
+ } else if (txnResponse.data && txnResponse.data.message) {
+ throw new Error(txnResponse.data.message)
+ } else {
+ throw new Error('Server error. Could not perform action.')
+ }
+ }
+ const groupRes = await validateReceiver()
+ return groupRes
+
+ }
+
+ async _deployAt(name, description, tags, creationBytes, amount, assetId, fee, atType) {
+ const deployAtFee = await this.deployAtFee()
+ const getLastRef = async () => {
+ let myRef = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/addresses/lastreference/${this.selectedAddress.address}`
+ })
+ return myRef
+ };
+
+ const validateReceiver = async () => {
+ let lastRef = await getLastRef();
+ let myTransaction = await makeTransactionRequest(lastRef)
+ const res = getTxnRequestResponse(myTransaction)
+ return res
+ }
+
+ const makeTransactionRequest = async (lastRef) => {
+ let groupdialog1 = get("transactions.groupdialog1")
+ let groupdialog2 = get("transactions.groupdialog2")
+ let myTxnrequest = await parentEpml.request('transaction', {
+ type: 16,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ fee: fee || deployAtFee,
+ rName: name,
+ rDescription: description,
+ rTags: tags,
+ rAmount: amount,
+ rAssetId: assetId,
+ rCreationBytes: creationBytes,
+ atType: atType,
+ lastReference: lastRef,
+ atDeployDialog1: groupdialog1,
+ atDeployDialog2: groupdialog2
+ }
+ })
+ return myTxnrequest
+ }
+
+ const getTxnRequestResponse = (txnResponse) => {
+ if (txnResponse.success === false && txnResponse.message) {
+ throw new Error(txnResponse.message)
+ } else if (txnResponse.success === true && !txnResponse.data.error) {
+ return txnResponse.data
+ } else if (txnResponse.data && txnResponse.data.message) {
+ throw new Error(txnResponse.data.message)
+ } else {
+ throw new Error('Server error. Could not perform action.')
+ }
+ }
+ const groupRes = await validateReceiver()
+ return groupRes
+
+ }
+
firstUpdated() {
this.changeTheme();
this.changeLanguage();
@@ -320,9 +450,9 @@ class WebBrowser extends LitElement {
let data = event.data;
console.log('UI received event: ' + JSON.stringify(data));
- switch (data.action) {
- case 'GET_USER_ACCOUNT':
- case actions.GET_USER_ACCOUNT:
+ switch (data.action) {
+ case 'GET_USER_ACCOUNT':
+ case actions.GET_USER_ACCOUNT:
const res1 = await showModalAndWait(
actions.GET_USER_ACCOUNT
);
@@ -338,7 +468,7 @@ class WebBrowser extends LitElement {
const errorMsg = get('browserpage.bchange17');
data['error'] = errorMsg;
response = JSON.stringify(data);
- return;
+ break;
}
case 'LINK_TO_QDN_RESOURCE':
case actions.QDN_RESOURCE_DISPLAYED:
@@ -363,16 +493,29 @@ class WebBrowser extends LitElement {
this.displayUrl = url;
return;
- case actions.PUBLISH_QDN_RESOURCE:
+ case actions.PUBLISH_QDN_RESOURCE: {
+ const requiredFields = ['service', 'name', 'data64'];
+ const missingFields = [];
+
+ requiredFields.forEach((field) => {
+ if (!data[field]) {
+ missingFields.push(field);
+ }
+ });
+
+ if (missingFields.length > 0) {
+ const missingFieldsString = missingFields.join(', ');
+ const errorMsg = `Missing fields: ${missingFieldsString}`
+ let data = {};
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ break
+ }
// Use "default" if user hasn't specified an identifer
const service = data.service;
const name = data.name;
let identifier = data.identifier;
const data64 = data.data64;
-
- if (!service || !name || !data64) {
- return;
- }
if (data.identifier == null) {
identifier = 'default';
}
@@ -394,17 +537,16 @@ class WebBrowser extends LitElement {
worker: worker,
isBase64: true,
});
- let data = {};
- data['data'] = resPublish;
- response = JSON.stringify(data);
+
+ response = JSON.stringify(resPublish);
worker.terminate();
} catch (error) {
worker.terminate();
- const data = {};
+ const obj = {};
const errorMsg = error.message || 'Upload failed';
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- console.error(error);
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ console.error(error);
return;
} finally {
this.loader.hide();
@@ -417,6 +559,8 @@ class WebBrowser extends LitElement {
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
+ }
+
case 'SEND_CHAT_MESSAGE':
// Params: data.groupId, data.destinationAddress, data.message
@@ -425,11 +569,60 @@ class WebBrowser extends LitElement {
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
- case actions.JOIN_GROUP:
+ case actions.JOIN_GROUP: {
+ const requiredFields = ['groupId'];
+ const missingFields = [];
+
+ requiredFields.forEach((field) => {
+ if (!data[field]) {
+ missingFields.push(field);
+ }
+ });
+
+ if (missingFields.length > 0) {
+ const missingFieldsString = missingFields.join(', ');
+ const errorMsg = `Missing fields: ${missingFieldsString}`
+ let data = {};
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ break
+ }
const groupId = data.groupId;
- if (!groupId) {
- return;
+
+ let groupInfo = null
+ try {
+ groupInfo = await parentEpml.request("apiCall", {
+ type: "api",
+ url: `/groups/${groupId}`,
+ });
+ } catch (error) {
+ const errorMsg = (error && error.message) || 'Group not found';
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break
+ }
+
+ if (!groupInfo || groupInfo.error) {
+ const errorMsg = (groupInfo && groupInfo.message) || 'Group not found';
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break
+ }
+
+ try {
+ this.loader.show();
+ const resJoinGroup = await this._joinGroup(groupId, groupInfo.groupName)
+ response = JSON.stringify(resJoinGroup);
+ } catch (error) {
+ const obj = {};
+ const errorMsg = error.message || 'Failed to join the group.';
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ } finally {
+ this.loader.hide();
}
// Params: data.groupId
@@ -437,99 +630,132 @@ class WebBrowser extends LitElement {
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
+ }
- case 'DEPLOY_AT':
+ case 'DEPLOY_AT': {
+ const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'];
+ const missingFields = [];
+
+ requiredFields.forEach((field) => {
+ if (!data[field]) {
+ missingFields.push(field);
+ }
+ });
+
+ if (missingFields.length > 0) {
+ const missingFieldsString = missingFields.join(', ');
+ const errorMsg = `Missing fields: ${missingFieldsString}`
+ let data = {};
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ break
+ }
+
+
+ try {
+ this.loader.show();
+ const fee = data.fee || undefined
+ const resJoinGroup = await this._deployAt(data.name, data.description, data.tags, data.creationBytes, data.amount, data.assetId, fee, data.type)
+ response = JSON.stringify(resJoinGroup);
+ } catch (error) {
+ const obj = {};
+ const errorMsg = error.message || 'Failed to join the group.';
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ } finally {
+ this.loader.hide();
+ }
// Params: data.creationBytes, data.name, data.description, data.type, data.tags, data.amount, data.assetId, data.fee
// TODO: prompt user to deploy an AT. If they confirm, sign+process a DEPLOY_AT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
break;
+ }
+
case 'GET_WALLET_BALANCE':
// Params: data.coin (QORT / LTC / DOGE / DGB / C / ARRR)
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- console.log('case passed here');
- console.log(data.coin, "data coin here");
- const res3 = await showModalAndWait(
+
+ const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE
);
if (res3.action === 'accept') {
- let coin = data.coin;
- if (coin === "QORT") {
- let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
- try {
- this.loader.show();
- const QORTBalance = await parentEpml.request('apiCall', {
- url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
- })
- console.log({QORTBalance})
- return QORTBalance;
- } catch (error) {
- console.error(error);
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } finally {
- this.loader.hide();
- }
- } else {
- let _url = ``
- let _body = null
+ let coin = data.coin;
+ if (coin === "QORT") {
+ let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
+ try {
+ this.loader.show();
+ const QORTBalance = await parentEpml.request('apiCall', {
+ url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
+ })
+ return QORTBalance;
+ } catch (error) {
+ console.error(error);
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } finally {
+ this.loader.hide();
+ }
+ } else {
+ let _url = ``
+ let _body = null
- switch (coin) {
- case 'LTC':
- _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
- break
- case 'DOGE':
- _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
- break
- case 'DGB':
- _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
- break
- case 'RVN':
- _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
- break
- case 'ARRR':
- _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
- break
- default:
- break
- }
- try {
- this.loader.show()
- await parentEpml.request('apiCall', {
- url: _url,
- method: 'POST',
- body: _body,
- }).then((res) => {
- if (isNaN(Number(res))) {
- throw new Error(get("browserpage.bchange21"));
- } else {
- console.log((Number(res) / 1e8).toFixed(8), "other wallet balance here");
- return (Number(res) / 1e8).toFixed(8)
- }
- })
- } catch (error) {
- console.error(error);
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } finally {
- this.loader.hide()
- }
- }
- } else if (res3.action === 'reject') {
+ switch (coin) {
+ case 'LTC':
+ _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
+ break
+ case 'DOGE':
+ _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
+ break
+ case 'DGB':
+ _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
+ break
+ case 'RVN':
+ _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
+ break
+ case 'ARRR':
+ _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
+ break
+ default:
+ break
+ }
+ try {
+ this.loader.show()
+ await parentEpml.request('apiCall', {
+ url: _url,
+ method: 'POST',
+ body: _body,
+ }).then((res) => {
+ if (isNaN(Number(res))) {
+ throw new Error(get("browserpage.bchange21"));
+ } else {
+ console.log((Number(res) / 1e8).toFixed(8), "other wallet balance here");
+ return (Number(res) / 1e8).toFixed(8)
+ }
+ })
+ } catch (error) {
+ console.error(error);
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } finally {
+ this.loader.hide()
+ }
+ }
+ } else if (res3.action === 'reject') {
response = '{"error": "User declined request"}';
}
break;
@@ -554,14 +780,16 @@ class WebBrowser extends LitElement {
// Not all responses will be JSON
responseObj = response;
}
-
+ console.log({ responseObj })
// Respond to app
if (responseObj.error != null) {
+ console.log('hello error')
event.ports[0].postMessage({
result: null,
error: responseObj,
});
} else {
+ console.log('hello success')
event.ports[0].postMessage({
result: responseObj,
error: null,
@@ -654,15 +882,13 @@ class WebBrowser extends LitElement {
refresh() {
const myNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
- window.parent.reduxStore.getState().app.nodeConfig.node
+ window.parent.reduxStore.getState().app.nodeConfig.node
];
const nodeUrl =
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
- this.url = `${nodeUrl}/render/${this.service}/${this.name}${
- this.path != null ? this.path : ''
- }?theme=${this.theme}&identifier=${
- this.identifier != null ? this.identifier : ''
- }`;
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ''
+ }?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ''
+ }`;
}
goBackToList() {
@@ -811,9 +1037,8 @@ class WebBrowser extends LitElement {
this.identifier == null ? 'default' : resource.identifier;
let ret = await parentEpml.request('apiCall', {
- url: `/arbitrary/resource/${this.service}/${
- this.name
- }/${identifier}?apiKey=${this.getApiKey()}`,
+ url: `/arbitrary/resource/${this.service}/${this.name
+ }/${identifier}?apiKey=${this.getApiKey()}`,
method: 'DELETE',
});
@@ -864,7 +1089,7 @@ class WebBrowser extends LitElement {
getApiKey() {
const myNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
- window.parent.reduxStore.getState().app.nodeConfig.node
+ window.parent.reduxStore.getState().app.nodeConfig.node
];
let apiKey = myNode.apiKey;
return apiKey;
@@ -883,10 +1108,10 @@ async function showModalAndWait(type, data) {
return new Promise((resolve) => {
// Create the modal and add it to the DOM
const modal = document.createElement('div');
- modal.id = "backdrop"
- modal.classList.add("backdrop");
- modal.innerHTML =
- `
+ modal.id = "backdrop"
+ modal.classList.add("backdrop");
+ modal.innerHTML =
+ `
${type === actions.GET_USER_ACCOUNT ? `
${get("browserpage.bchange18")}
` : ''}
@@ -900,30 +1125,30 @@ async function showModalAndWait(type, data) {
`;
- document.body.appendChild(modal);
+ document.body.appendChild(modal);
// Add click event listeners to the buttons
const okButton = modal.querySelector('#ok-button');
okButton.addEventListener('click', () => {
const userData = {};
- if (modal.parentNode === document.body) {
- document.body.removeChild(modal);
- }
+ if (modal.parentNode === document.body) {
+ document.body.removeChild(modal);
+ }
resolve({ action: 'accept', userData });
});
- const backdropClick = document.getElementById('backdrop');
+ const backdropClick = document.getElementById('backdrop');
backdropClick.addEventListener('click', () => {
- if (modal.parentNode === document.body) {
- document.body.removeChild(modal);
- }
- resolve({ action: 'reject' });
+ if (modal.parentNode === document.body) {
+ document.body.removeChild(modal);
+ }
+ resolve({ action: 'reject' });
});
const cancelButton = modal.querySelector('#cancel-button');
cancelButton.addEventListener('click', () => {
- if (modal.parentNode === document.body) {
- document.body.removeChild(modal);
- }
- resolve({ action: 'reject' });
+ if (modal.parentNode === document.body) {
+ document.body.removeChild(modal);
+ }
+ resolve({ action: 'reject' });
});
});
}
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 69f4861e..56668e23 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -148,7 +148,8 @@ export const publishData = async ({
}
}
try {
- await validate()
+ const validateRes = await validate()
+ return validateRes
} catch (error) {
throw new Error(error.message)
}
From a58eecfebe10b5a6190d91863eec4c6ab4b14958 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Thu, 23 Feb 2023 23:21:25 +0000
Subject: [PATCH 16/83] comment-out deploy_at
---
.../plugins/core/qdn/browser/browser.src.js | 66 +++++++++----------
1 file changed, 31 insertions(+), 35 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 8266c5db..78bb881b 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -632,45 +632,41 @@ class WebBrowser extends LitElement {
break;
}
- case 'DEPLOY_AT': {
- const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'];
- const missingFields = [];
+ // case 'DEPLOY_AT': {
+ // const requiredFields = ['name', 'description', 'tags', 'creationBytes', 'amount', 'assetId', 'type'];
+ // const missingFields = [];
- requiredFields.forEach((field) => {
- if (!data[field]) {
- missingFields.push(field);
- }
- });
+ // requiredFields.forEach((field) => {
+ // if (!data[field]) {
+ // missingFields.push(field);
+ // }
+ // });
- if (missingFields.length > 0) {
- const missingFieldsString = missingFields.join(', ');
- const errorMsg = `Missing fields: ${missingFieldsString}`
- let data = {};
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- break
- }
+ // if (missingFields.length > 0) {
+ // const missingFieldsString = missingFields.join(', ');
+ // const errorMsg = `Missing fields: ${missingFieldsString}`
+ // let data = {};
+ // data['error'] = errorMsg;
+ // response = JSON.stringify(data);
+ // break
+ // }
- try {
- this.loader.show();
- const fee = data.fee || undefined
- const resJoinGroup = await this._deployAt(data.name, data.description, data.tags, data.creationBytes, data.amount, data.assetId, fee, data.type)
- response = JSON.stringify(resJoinGroup);
- } catch (error) {
- const obj = {};
- const errorMsg = error.message || 'Failed to join the group.';
- obj['error'] = errorMsg;
- response = JSON.stringify(obj);
- } finally {
- this.loader.hide();
- }
- // Params: data.creationBytes, data.name, data.description, data.type, data.tags, data.amount, data.assetId, data.fee
- // TODO: prompt user to deploy an AT. If they confirm, sign+process a DEPLOY_AT transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
- }
+ // try {
+ // this.loader.show();
+ // const fee = data.fee || undefined
+ // const resJoinGroup = await this._deployAt(data.name, data.description, data.tags, data.creationBytes, data.amount, data.assetId, fee, data.type)
+ // response = JSON.stringify(resJoinGroup);
+ // } catch (error) {
+ // const obj = {};
+ // const errorMsg = error.message || 'Failed to join the group.';
+ // obj['error'] = errorMsg;
+ // response = JSON.stringify(obj);
+ // } finally {
+ // this.loader.hide();
+ // }
+ // break;
+ // }
case 'GET_WALLET_BALANCE':
From fb9da8d1d4a344088ec66948b0c4e6ce751c8bff Mon Sep 17 00:00:00 2001
From: Phillip
Date: Thu, 23 Feb 2023 23:24:43 +0000
Subject: [PATCH 17/83] format file
---
.../plugins/core/qdn/browser/browser.src.js | 712 +++++++++---------
1 file changed, 356 insertions(+), 356 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 52c17de5..c9c9b401 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -452,9 +452,9 @@ class WebBrowser extends LitElement {
let data = event.data;
console.log('UI received event: ' + JSON.stringify(data));
- switch (data.action) {
- case 'GET_USER_ACCOUNT':
- case actions.GET_USER_ACCOUNT:
+ switch (data.action) {
+ case 'GET_USER_ACCOUNT':
+ case actions.GET_USER_ACCOUNT:
const res1 = await showModalAndWait(
actions.GET_USER_ACCOUNT
);
@@ -573,140 +573,140 @@ class WebBrowser extends LitElement {
window.crypto.getRandomValues(_reference);
let reference = window.parent.Base58.encode(_reference);
const sendMessageRequest = async () => {
- let chatResponse = await parentEpml.request('chat', {
- type: 18,
- nonce: this.selectedAddress.nonce,
- params: {
- timestamp: Date.now(),
- recipient: recipient,
- recipientPublicKey: this._publicKey.key,
- hasChatReference: 0,
- chatReference: chatReference,
- message: messageText,
- lastReference: reference,
- proofOfWorkNonce: 0,
- isEncrypted: 1,
- isText: 1
- }
- });
- const msgResponse = await _computePow(chatResponse)
- return msgResponse;
+ let chatResponse = await parentEpml.request('chat', {
+ type: 18,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ timestamp: Date.now(),
+ recipient: recipient,
+ recipientPublicKey: this._publicKey.key,
+ hasChatReference: 0,
+ chatReference: chatReference,
+ message: messageText,
+ lastReference: reference,
+ proofOfWorkNonce: 0,
+ isEncrypted: 1,
+ isText: 1
+ }
+ });
+ const msgResponse = await _computePow(chatResponse)
+ return msgResponse;
};
-
+
const _computePow = async (chatBytes) => {
- const difficulty = 8;
- const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
- const worker = new WebWorkerChat();
- let nonce = null;
- let chatBytesArray = null;
-
- await new Promise((res) => {
- worker.postMessage({chatBytes, path, difficulty});
- worker.onmessage = e => {
- chatBytesArray = e.data.chatBytesArray;
- nonce = e.data.nonce;
- res();
- }
- });
-
- let _response = await parentEpml.request('sign_chat', {
- nonce: this.selectedAddress.nonce,
- chatBytesArray: chatBytesArray,
- chatNonce: nonce
- });
-
- const chatResponse = getSendChatResponse(_response);
+ const difficulty = 8;
+ const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full'
+ const worker = new WebWorkerChat();
+ let nonce = null;
+ let chatBytesArray = null;
+
+ await new Promise((res) => {
+ worker.postMessage({ chatBytes, path, difficulty });
+ worker.onmessage = e => {
+ chatBytesArray = e.data.chatBytesArray;
+ nonce = e.data.nonce;
+ res();
+ }
+ });
+
+ let _response = await parentEpml.request('sign_chat', {
+ nonce: this.selectedAddress.nonce,
+ chatBytesArray: chatBytesArray,
+ chatNonce: nonce
+ });
+
+ const chatResponse = getSendChatResponse(_response);
return chatResponse;
};
-
+
const getSendChatResponse = (res) => {
- if (res === true) {
- let successString = get("browserpage.bchange23");
- parentEpml.request('showSnackBar', `${successString}`);
- } else if (res.error) {
- parentEpml.request('showSnackBar', res.message);
- }
- this.loader.hide();
- return res;
+ if (res === true) {
+ let successString = get("browserpage.bchange23");
+ parentEpml.request('showSnackBar', `${successString}`);
+ } else if (res.error) {
+ parentEpml.request('showSnackBar', res.message);
+ }
+ this.loader.hide();
+ return res;
};
-
+
const chatResponse = await sendMessageRequest();
return chatResponse;
- }
+ }
const result = await showModalAndWait(
actions.SEND_CHAT_MESSAGE
);
if (result.action === "accept") {
- let hasPublicKey = true;
- const res = await parentEpml.request('apiCall', {
- type: 'api',
- url: `/addresses/publickey/${recipient}`
- });
+ let hasPublicKey = true;
+ const res = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/addresses/publickey/${recipient}`
+ });
- if (res.error === 102) {
- this._publicKey.key = ''
- this._publicKey.hasPubKey = false
- hasPublicKey = false;
- } else if (res !== false) {
- this._publicKey.key = res
- this._publicKey.hasPubKey = true
- } else {
- this._publicKey.key = ''
- this._publicKey.hasPubKey = false
- hasPublicKey = false;
- }
+ if (res.error === 102) {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ } else if (res !== false) {
+ this._publicKey.key = res
+ this._publicKey.hasPubKey = true
+ } else {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ }
- if (!hasPublicKey) {
- let err4string = get("chatpage.cchange39");
- parentEpml.request('showSnackBar', `${err4string}`)
- return
- }
+ if (!hasPublicKey) {
+ let err4string = get("chatpage.cchange39");
+ parentEpml.request('showSnackBar', `${err4string}`)
+ return
+ }
- this.loader.show();
+ this.loader.show();
- const tiptapJson = {
- type: 'doc',
- content: [
- {
- type: 'paragraph',
- content: [
- {
- type: 'text',
- text: message,
- },
-
- ],
- },
- ],
- }
+ const tiptapJson = {
+ type: 'doc',
+ content: [
+ {
+ type: 'paragraph',
+ content: [
+ {
+ type: 'text',
+ text: message,
+ },
- const messageObject = {
- messageText: tiptapJson,
- images: [''],
- repliedTo: '',
- version: 2
- };
+ ],
+ },
+ ],
+ }
+
+ const messageObject = {
+ messageText: tiptapJson,
+ images: [''],
+ repliedTo: '',
+ version: 2
+ };
+
+ const stringifyMessageObject = JSON.stringify(messageObject);
+ // if (this.balance < 4) {
+ // this.myTrimmedMeassage = ''
+ // this.myTrimmedMeassage = stringifyMessageObject
+ // this.shadowRoot.getElementById('confirmDialog').open()
+ // } else {
+ // this.sendMessage(stringifyMessageObject, typeMessage);
+ // }
+ try {
+ const msgResponse = await sendMessage(stringifyMessageObject);
+ response = msgResponse;
+ } catch (error) {
+ console.error(error);
+ return '{"error": "Request could not be fulfilled"}';
+ } finally {
+ this.loader.hide();
+ console.log("Case completed.");
+ }
- const stringifyMessageObject = JSON.stringify(messageObject);
- // if (this.balance < 4) {
- // this.myTrimmedMeassage = ''
- // this.myTrimmedMeassage = stringifyMessageObject
- // this.shadowRoot.getElementById('confirmDialog').open()
- // } else {
- // this.sendMessage(stringifyMessageObject, typeMessage);
- // }
- try {
- const msgResponse = await sendMessage(stringifyMessageObject);
- response = msgResponse;
- } catch (error) {
- console.error(error);
- return '{"error": "Request could not be fulfilled"}';
- } finally {
- this.loader.hide();
- console.log("Case completed.");
- }
-
} else {
response = '{"error": "User declined request"}';
}
@@ -738,7 +738,7 @@ class WebBrowser extends LitElement {
}
const groupId = data.groupId;
-
+
let groupInfo = null
try {
groupInfo = await parentEpml.request("apiCall", {
@@ -799,8 +799,8 @@ class WebBrowser extends LitElement {
// response = JSON.stringify(data);
// break
// }
-
-
+
+
// try {
// this.loader.show();
// const fee = data.fee || undefined
@@ -823,85 +823,85 @@ class WebBrowser extends LitElement {
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- const res3 = await showModalAndWait(
+ const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE
);
if (res3.action === 'accept') {
- let coin = data.coin;
- if (coin === "QORT") {
- let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
- try {
- this.loader.show();
- const QORTBalance = await parentEpml.request('apiCall', {
- url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
- })
- return QORTBalance;
- } catch (error) {
- console.error(error);
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } finally {
- this.loader.hide();
- }
- } else {
- let _url = ``
- let _body = null
+ let coin = data.coin;
+ if (coin === "QORT") {
+ let qortAddress = window.parent.reduxStore.getState().app.selectedAddress.address
+ try {
+ this.loader.show();
+ const QORTBalance = await parentEpml.request('apiCall', {
+ url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
+ })
+ return QORTBalance;
+ } catch (error) {
+ console.error(error);
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } finally {
+ this.loader.hide();
+ }
+ } else {
+ let _url = ``
+ let _body = null
- switch (coin) {
- case 'LTC':
- _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
- break
- case 'DOGE':
- _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
- break
- case 'DGB':
- _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
- break
- case 'RVN':
- _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
- break
- case 'ARRR':
- _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
- break
- default:
- break
- }
- try {
- this.loader.show();
- const res = await parentEpml.request('apiCall', {
- url: _url,
- method: 'POST',
- body: _body,
- })
- if (isNaN(Number(res))) {
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } else {
- response = (Number(res) / 1e8).toFixed(8);
- }
- } catch (error) {
- console.error(error);
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } finally {
- this.loader.hide()
- }
- }
- } else if (res3.action === 'reject') {
+ switch (coin) {
+ case 'LTC':
+ _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
+ break
+ case 'DOGE':
+ _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
+ break
+ case 'DGB':
+ _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
+ break
+ case 'RVN':
+ _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
+ break
+ case 'ARRR':
+ _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
+ _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
+ break
+ default:
+ break
+ }
+ try {
+ this.loader.show();
+ const res = await parentEpml.request('apiCall', {
+ url: _url,
+ method: 'POST',
+ body: _body,
+ })
+ if (isNaN(Number(res))) {
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } else {
+ response = (Number(res) / 1e8).toFixed(8);
+ }
+ } catch (error) {
+ console.error(error);
+ const data = {};
+ const errorMsg = error.message || get("browserpage.bchange21");
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ return;
+ } finally {
+ this.loader.hide()
+ }
+ }
+ } else if (res3.action === 'reject') {
response = '{"error": "User declined request"}';
}
break;
@@ -911,170 +911,170 @@ class WebBrowser extends LitElement {
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- const amount = data.amount;
- let recipient = data.destinationAddress;
- const fee = data.fee
- this.loader.show();
+ const amount = data.amount;
+ let recipient = data.destinationAddress;
+ const fee = data.fee
+ this.loader.show();
- const walletBalance = await parentEpml.request('apiCall', {
- url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
- }).then((res) => {
- if (isNaN(Number(res))) {
- let snack4string = get("chatpage.cchange48")
- parentEpml.request('showSnackBar', `${snack4string}`)
- return;
- } else {
- return Number(res).toFixed(8);
- }
- })
+ const walletBalance = await parentEpml.request('apiCall', {
+ url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
+ }).then((res) => {
+ if (isNaN(Number(res))) {
+ let snack4string = get("chatpage.cchange48")
+ parentEpml.request('showSnackBar', `${snack4string}`)
+ return;
+ } else {
+ return Number(res).toFixed(8);
+ }
+ })
- const myRef = await parentEpml.request("apiCall", {
- type: "api",
- url: `/addresses/lastreference/${this.myAddress.address}`,
- })
+ const myRef = await parentEpml.request("apiCall", {
+ type: "api",
+ url: `/addresses/lastreference/${this.myAddress.address}`,
+ })
- if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalance)) {
- this.loader.hide();
- let snack1string = get("chatpage.cchange51");
- parentEpml.request('showSnackBar', `${snack1string}`);
- return false;
- }
-
- if (parseFloat(amount) <= 0) {
- this.loader.hide();
- let snack2string = get("chatpage.cchange52");
- parentEpml.request('showSnackBar', `${snack2string}`);
- return false;
- }
-
- if (recipient.length === 0) {
- this.loader.hide();
- let snack3string = get("chatpage.cchange53");
- parentEpml.request('showSnackBar', `${snack3string}`);
- return false;
- }
-
- const validateName = async (receiverName) => {
- let myRes;
- let myNameRes = await parentEpml.request('apiCall', {
- type: 'api',
- url: `/names/${receiverName}`,
- })
-
- if (myNameRes.error === 401) {
- myRes = false;
- } else {
- myRes = myNameRes;
- }
- return myRes;
- }
-
- const validateAddress = async (receiverAddress) => {
- let myAddress = await window.parent.validateAddress(receiverAddress);
- return myAddress;
- }
-
- const validateReceiver = async (recipient) => {
- let lastRef = myRef;
- let isAddress;
-
- try {
- isAddress = await validateAddress(recipient);
- } catch (err) {
- isAddress = false;
- }
-
- if (isAddress) {
- let myTransaction = await makeTransactionRequest(recipient, lastRef);
- return getTxnRequestResponse(myTransaction);
- } else {
- let myNameRes = await validateName(recipient);
- if (myNameRes !== false) {
- let myNameAddress = myNameRes.owner
- let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
- return getTxnRequestResponse(myTransaction)
- } else {
- console.error(`${translate("chatpage.cchange54")}`)
- parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
- this.loader.hide();
- }
- }
- }
-
- const getName = async (recipient)=> {
- try {
- const getNames = await parentEpml.request("apiCall", {
- type: "api",
- url: `/names/address/${recipient}`,
- });
-
- if (getNames.length > 0 ) {
- return getNames[0].name;
- } else {
- return '';
- }
- } catch (error) {
- return "";
- }
- }
-
- const makeTransactionRequest = async (receiver, lastRef) => {
- let myReceiver = receiver;
- let mylastRef = lastRef;
- let dialogamount = get("transactions.amount");
- let dialogAddress = get("login.address");
- let dialogName = get("login.name");
- let dialogto = get("transactions.to");
- let recipientName = await getName(myReceiver);
- let myTxnrequest = await parentEpml.request('transaction', {
- type: 2,
- nonce: this.myAddress.nonce,
- params: {
- recipient: myReceiver,
- recipientName: recipientName,
- amount: amount,
- lastReference: mylastRef,
- fee: fee,
- dialogamount: dialogamount,
- dialogto: dialogto,
- dialogAddress,
- dialogName
- },
- })
- return myTxnrequest;
- }
-
- const getTxnRequestResponse = (txnResponse) => {
- if (txnResponse.success === false && txnResponse.message) {
- parentEpml.request('showSnackBar', `${txnResponse.message}`);
- this.loader.hide();
- throw new Error(txnResponse);
- } else if (txnResponse.success === true && !txnResponse.data.error) {
- parentEpml.request('showSnackBar', `${get("chatpage.cchange55")}`)
- this.loader.hide();
- } else {
- parentEpml.request('showSnackBar', `${txnResponse.data.message}`);
- this.loader.hide();
- throw new Error(txnResponse);
- }
- }
- try {
- const result = await validateReceiver(recipient);
- if (result) {
- return result;
- }
- } catch (error) {
- console.error(error);
- return '{"error": "Request could not be fulfilled"}';
- } finally {
- console.log("Case completed.");
- }
- break;
+ if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalance)) {
+ this.loader.hide();
+ let snack1string = get("chatpage.cchange51");
+ parentEpml.request('showSnackBar', `${snack1string}`);
+ return false;
+ }
- default:
- console.log('Unhandled message: ' + JSON.stringify(data));
- return;
- }
+ if (parseFloat(amount) <= 0) {
+ this.loader.hide();
+ let snack2string = get("chatpage.cchange52");
+ parentEpml.request('showSnackBar', `${snack2string}`);
+ return false;
+ }
+
+ if (recipient.length === 0) {
+ this.loader.hide();
+ let snack3string = get("chatpage.cchange53");
+ parentEpml.request('showSnackBar', `${snack3string}`);
+ return false;
+ }
+
+ const validateName = async (receiverName) => {
+ let myRes;
+ let myNameRes = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/names/${receiverName}`,
+ })
+
+ if (myNameRes.error === 401) {
+ myRes = false;
+ } else {
+ myRes = myNameRes;
+ }
+ return myRes;
+ }
+
+ const validateAddress = async (receiverAddress) => {
+ let myAddress = await window.parent.validateAddress(receiverAddress);
+ return myAddress;
+ }
+
+ const validateReceiver = async (recipient) => {
+ let lastRef = myRef;
+ let isAddress;
+
+ try {
+ isAddress = await validateAddress(recipient);
+ } catch (err) {
+ isAddress = false;
+ }
+
+ if (isAddress) {
+ let myTransaction = await makeTransactionRequest(recipient, lastRef);
+ return getTxnRequestResponse(myTransaction);
+ } else {
+ let myNameRes = await validateName(recipient);
+ if (myNameRes !== false) {
+ let myNameAddress = myNameRes.owner
+ let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
+ return getTxnRequestResponse(myTransaction)
+ } else {
+ console.error(`${translate("chatpage.cchange54")}`)
+ parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
+ this.loader.hide();
+ }
+ }
+ }
+
+ const getName = async (recipient) => {
+ try {
+ const getNames = await parentEpml.request("apiCall", {
+ type: "api",
+ url: `/names/address/${recipient}`,
+ });
+
+ if (getNames.length > 0) {
+ return getNames[0].name;
+ } else {
+ return '';
+ }
+ } catch (error) {
+ return "";
+ }
+ }
+
+ const makeTransactionRequest = async (receiver, lastRef) => {
+ let myReceiver = receiver;
+ let mylastRef = lastRef;
+ let dialogamount = get("transactions.amount");
+ let dialogAddress = get("login.address");
+ let dialogName = get("login.name");
+ let dialogto = get("transactions.to");
+ let recipientName = await getName(myReceiver);
+ let myTxnrequest = await parentEpml.request('transaction', {
+ type: 2,
+ nonce: this.myAddress.nonce,
+ params: {
+ recipient: myReceiver,
+ recipientName: recipientName,
+ amount: amount,
+ lastReference: mylastRef,
+ fee: fee,
+ dialogamount: dialogamount,
+ dialogto: dialogto,
+ dialogAddress,
+ dialogName
+ },
+ })
+ return myTxnrequest;
+ }
+
+ const getTxnRequestResponse = (txnResponse) => {
+ if (txnResponse.success === false && txnResponse.message) {
+ parentEpml.request('showSnackBar', `${txnResponse.message}`);
+ this.loader.hide();
+ throw new Error(txnResponse);
+ } else if (txnResponse.success === true && !txnResponse.data.error) {
+ parentEpml.request('showSnackBar', `${get("chatpage.cchange55")}`)
+ this.loader.hide();
+ } else {
+ parentEpml.request('showSnackBar', `${txnResponse.data.message}`);
+ this.loader.hide();
+ throw new Error(txnResponse);
+ }
+ }
+ try {
+ const result = await validateReceiver(recipient);
+ if (result) {
+ return result;
+ }
+ } catch (error) {
+ console.error(error);
+ return '{"error": "Request could not be fulfilled"}';
+ } finally {
+ console.log("Case completed.");
+ }
+ break;
+
+ default:
+ console.log('Unhandled message: ' + JSON.stringify(data));
+ return;
+ }
// Parse response
let responseObj;
From 697157c79fdca2a59a9416f37553824df2ce7bd3 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Fri, 24 Feb 2023 00:53:25 +0000
Subject: [PATCH 18/83] fixes
---
.../plugins/core/qdn/browser/browser.src.js | 53 +++++++++++++------
1 file changed, 38 insertions(+), 15 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index c9c9b401..6f405459 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -19,6 +19,7 @@ import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
import WebWorkerChat from 'web-worker:./computePowWorker.src.js';
import { publishData } from '../../../utils/publish-image.js';
import { Loader } from '../../../utils/loader.js';
+import { QORT_DECIMALS } from 'qortal-ui-crypto/api/constants';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class WebBrowser extends LitElement {
@@ -818,7 +819,24 @@ class WebBrowser extends LitElement {
// }
- case 'GET_WALLET_BALANCE':
+ case 'GET_WALLET_BALANCE': {
+ const requiredFields = ['coin'];
+ const missingFields = [];
+
+ requiredFields.forEach((field) => {
+ if (!data[field]) {
+ missingFields.push(field);
+ }
+ });
+
+ if (missingFields.length > 0) {
+ const missingFieldsString = missingFields.join(', ');
+ const errorMsg = `Missing fields: ${missingFieldsString}`
+ let data = {};
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ break
+ }
// Params: data.coin (QORT / LTC / DOGE / DGB / C / ARRR)
// TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
// then set the response string from the core to the `response` variable (defined above)
@@ -826,6 +844,7 @@ class WebBrowser extends LitElement {
const res3 = await showModalAndWait(
actions.GET_WALLET_BALANCE
);
+
if (res3.action === 'accept') {
let coin = data.coin;
if (coin === "QORT") {
@@ -835,14 +854,16 @@ class WebBrowser extends LitElement {
const QORTBalance = await parentEpml.request('apiCall', {
url: `/addresses/balance/${qortAddress}?apiKey=${this.getApiKey()}`,
})
- return QORTBalance;
+ response = QORTBalance
+
+
} catch (error) {
console.error(error);
const data = {};
const errorMsg = error.message || get("browserpage.bchange21");
data['error'] = errorMsg;
response = JSON.stringify(data);
- return;
+
} finally {
this.loader.hide();
}
@@ -904,36 +925,39 @@ class WebBrowser extends LitElement {
} else if (res3.action === 'reject') {
response = '{"error": "User declined request"}';
}
+
break;
+ }
+
case 'SEND_COIN':
// Params: data.coin, data.destinationAddress, data.amount, data.fee
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- const amount = data.amount;
+ const amount = data.amount
let recipient = data.destinationAddress;
const fee = data.fee
this.loader.show();
const walletBalance = await parentEpml.request('apiCall', {
url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
- }).then((res) => {
- if (isNaN(Number(res))) {
- let snack4string = get("chatpage.cchange48")
- parentEpml.request('showSnackBar', `${snack4string}`)
- return;
- } else {
- return Number(res).toFixed(8);
- }
})
+ if (isNaN(Number(walletBalance))) {
+ let snack4string = get("chatpage.cchange48")
+ parentEpml.request('showSnackBar', `${snack4string}`)
+ return;
+ }
+
const myRef = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/lastreference/${this.myAddress.address}`,
})
- if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalance)) {
+ const walletBalanceDecimals = parseFloat(walletBalance) * QORT_DECIMALS;
+
+ if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalanceDecimals)) {
this.loader.hide();
let snack1string = get("chatpage.cchange51");
parentEpml.request('showSnackBar', `${snack1string}`);
@@ -1084,15 +1108,14 @@ class WebBrowser extends LitElement {
// Not all responses will be JSON
responseObj = response;
}
+
// Respond to app
if (responseObj.error != null) {
- console.log('hello error')
event.ports[0].postMessage({
result: null,
error: responseObj,
});
} else {
- console.log('hello success')
event.ports[0].postMessage({
result: responseObj,
error: null,
From 353943cbf9dea480a1d135eed824bf3797484ad2 Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Thu, 23 Feb 2023 21:26:14 -0500
Subject: [PATCH 19/83] Added response return to SEND_QORT
---
.../plugins/core/qdn/browser/browser.src.js | 17 ++++++++---------
1 file changed, 8 insertions(+), 9 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 6f405459..443d2d00 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -231,6 +231,7 @@ class WebBrowser extends LitElement {
}
render() {
+ console.log(1, "browser page here");
return html`
@@ -949,7 +950,6 @@ class WebBrowser extends LitElement {
return;
}
-
const myRef = await parentEpml.request("apiCall", {
type: "api",
url: `/addresses/lastreference/${this.myAddress.address}`,
@@ -1010,13 +1010,15 @@ class WebBrowser extends LitElement {
if (isAddress) {
let myTransaction = await makeTransactionRequest(recipient, lastRef);
- return getTxnRequestResponse(myTransaction);
+ const res = getTxnRequestResponse(myTransaction)
+ return res;
} else {
let myNameRes = await validateName(recipient);
if (myNameRes !== false) {
let myNameAddress = myNameRes.owner
let myTransaction = await makeTransactionRequest(myNameAddress, lastRef)
- return getTxnRequestResponse(myTransaction)
+ const res = getTxnRequestResponse(myTransaction)
+ return res;
} else {
console.error(`${translate("chatpage.cchange54")}`)
parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
@@ -1070,23 +1072,20 @@ class WebBrowser extends LitElement {
const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) {
- parentEpml.request('showSnackBar', `${txnResponse.message}`);
this.loader.hide();
throw new Error(txnResponse);
} else if (txnResponse.success === true && !txnResponse.data.error) {
- parentEpml.request('showSnackBar', `${get("chatpage.cchange55")}`)
this.loader.hide();
} else {
- parentEpml.request('showSnackBar', `${txnResponse.data.message}`);
this.loader.hide();
throw new Error(txnResponse);
}
+ return txnResponse;
}
+
try {
const result = await validateReceiver(recipient);
- if (result) {
- return result;
- }
+ response = result;
} catch (error) {
console.error(error);
return '{"error": "Request could not be fulfilled"}';
From abe7be473deae6ee9464f46bd8a5520be3dfc5bd Mon Sep 17 00:00:00 2001
From: Phillip
Date: Fri, 24 Feb 2023 13:02:05 +0000
Subject: [PATCH 20/83] fix issues
---
.../api/transactions/DeployAtTransaction.js | 4 +-
.../plugins/core/qdn/browser/browser.src.js | 132 ++++++++++++------
2 files changed, 89 insertions(+), 47 deletions(-)
diff --git a/qortal-ui-crypto/api/transactions/DeployAtTransaction.js b/qortal-ui-crypto/api/transactions/DeployAtTransaction.js
index c3eb20e4..a9b3ad5f 100644
--- a/qortal-ui-crypto/api/transactions/DeployAtTransaction.js
+++ b/qortal-ui-crypto/api/transactions/DeployAtTransaction.js
@@ -1,5 +1,6 @@
'use strict'
import TransactionBase from './TransactionBase.js'
+import { store } from '../../api.js'
export default class DeployAtTransaction extends TransactionBase {
constructor() {
@@ -33,7 +34,7 @@ export default class DeployAtTransaction extends TransactionBase {
this._feeBytes = this.constructor.utils.int64ToBytes(this._fee)
}
set rAmount(rAmount) {
- this._rAmount = rAmount
+ this._rAmount = Math.round(rAmount * store.getState().config.coin.decimals)
this._rAmountBytes = this.constructor.utils.int64ToBytes(this._rAmount)
}
@@ -60,7 +61,6 @@ export default class DeployAtTransaction extends TransactionBase {
}
set rCreationBytes(rCreationBytes) {
const decode = this.constructor.Base58.decode(rCreationBytes)
- console.log({decode})
this._rCreationBytes = this.constructor.utils.stringtoUTF8Array(decode)
this._rCreationBytesLength = this.constructor.utils.int32ToBytes(this._rCreationBytes.length)
}
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 443d2d00..2ae43c96 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -231,7 +231,6 @@ class WebBrowser extends LitElement {
}
render() {
- console.log(1, "browser page here");
return html`
@@ -295,7 +294,20 @@ class WebBrowser extends LitElement {
}
const data = await response.json()
- const joinFee = data
+ const joinFee = (Number(data) / 1e8).toFixed(8)
+ return joinFee
+ }
+ async sendQortFee() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ const url = `${nodeUrl}/transactions/unitfee?txType=PAYMENT`
+ const response = await fetch(url)
+ if (!response.ok) {
+ throw new Error('Error when fetching join fee');
+ }
+
+ const data = await response.json()
+ const joinFee = (Number(data) / 1e8).toFixed(8)
return joinFee
}
@@ -452,10 +464,8 @@ class WebBrowser extends LitElement {
let response = '{"error": "Request could not be fulfilled"}';
let data = event.data;
- console.log('UI received event: ' + JSON.stringify(data));
switch (data.action) {
- case 'GET_USER_ACCOUNT':
case actions.GET_USER_ACCOUNT:
const res1 = await showModalAndWait(
actions.GET_USER_ACCOUNT
@@ -469,12 +479,12 @@ class WebBrowser extends LitElement {
break;
} else {
const data = {};
- const errorMsg = get('browserpage.bchange17');
+ const errorMsg = "User declined to share account details"
data['error'] = errorMsg;
response = JSON.stringify(data);
break;
}
- case 'LINK_TO_QDN_RESOURCE':
+ case actions.LINK_TO_QDN_RESOURCE:
case actions.QDN_RESOURCE_DISPLAYED:
// Links are handled by the core, but the UI also listens for these actions in order to update the address bar.
// Note: don't update this.url here, as we don't want to force reload the iframe each time.
@@ -566,11 +576,11 @@ class WebBrowser extends LitElement {
}
- case 'SEND_CHAT_MESSAGE': {
+ case actions.SEND_CHAT_MESSAGE: {
const message = data.message;
const recipient = data.destinationAddress;
const sendMessage = async (messageText, chatReference) => {
- this.loader.show();
+
let _reference = new Uint8Array(64);
window.crypto.getRandomValues(_reference);
let reference = window.parent.Base58.encode(_reference);
@@ -623,13 +633,13 @@ class WebBrowser extends LitElement {
const getSendChatResponse = (res) => {
if (res === true) {
- let successString = get("browserpage.bchange23");
- parentEpml.request('showSnackBar', `${successString}`);
+ return res
} else if (res.error) {
- parentEpml.request('showSnackBar', res.message);
+ throw new Error(res.message);
+ } else {
+ throw new Error('ERROR: Could not send message');
}
- this.loader.hide();
- return res;
+
};
const chatResponse = await sendMessageRequest();
@@ -665,7 +675,7 @@ class WebBrowser extends LitElement {
return
}
- this.loader.show();
+
const tiptapJson = {
type: 'doc',
@@ -699,14 +709,15 @@ class WebBrowser extends LitElement {
// this.sendMessage(stringifyMessageObject, typeMessage);
// }
try {
+ this.loader.show();
const msgResponse = await sendMessage(stringifyMessageObject);
response = msgResponse;
} catch (error) {
console.error(error);
- return '{"error": "Request could not be fulfilled"}';
+ response = '{"error": "Request could not be fulfilled"}';
} finally {
this.loader.hide();
- console.log("Case completed.");
+
}
} else {
@@ -820,7 +831,7 @@ class WebBrowser extends LitElement {
// }
- case 'GET_WALLET_BALANCE': {
+ case actions.GET_WALLET_BALANCE: {
const requiredFields = ['coin'];
const missingFields = [];
@@ -931,23 +942,43 @@ class WebBrowser extends LitElement {
}
- case 'SEND_COIN':
+ case actions.SEND_COIN: {
+ const requiredFields = ['coin', 'destinationAddress', 'amount'];
+ const missingFields = [];
+
+ requiredFields.forEach((field) => {
+ if (!data[field]) {
+ missingFields.push(field);
+ }
+ });
+
+ if (missingFields.length > 0) {
+ this.loader.hide();
+ const missingFieldsString = missingFields.join(', ');
+ const errorMsg = `Missing fields: ${missingFieldsString}`
+ let data = {};
+ data['error'] = errorMsg;
+ response = JSON.stringify(data);
+ break
+ }
// Params: data.coin, data.destinationAddress, data.amount, data.fee
// TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
// then set the response string from the core to the `response` variable (defined above)
// If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- const amount = data.amount
+ const amount = Number(data.amount)
let recipient = data.destinationAddress;
- const fee = data.fee
this.loader.show();
const walletBalance = await parentEpml.request('apiCall', {
url: `/addresses/balance/${this.myAddress.address}?apiKey=${this.getApiKey()}`,
})
if (isNaN(Number(walletBalance))) {
- let snack4string = get("chatpage.cchange48")
- parentEpml.request('showSnackBar', `${snack4string}`)
- return;
+ this.loader.hide();
+ let errorMsg = "Failed to Fetch QORT Balance. Try again!"
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
}
const myRef = await parentEpml.request("apiCall", {
@@ -955,27 +986,35 @@ class WebBrowser extends LitElement {
url: `/addresses/lastreference/${this.myAddress.address}`,
})
- const walletBalanceDecimals = parseFloat(walletBalance) * QORT_DECIMALS;
-
- if (parseFloat(amount) + parseFloat(data.fee) > parseFloat(walletBalanceDecimals)) {
+ const walletBalanceDecimals = Number(walletBalance) * QORT_DECIMALS;
+ const amountDecimals = Number(amount) * QORT_DECIMALS
+ const fee = await this.sendQortFee()
+ // TODO fee
+ if (amountDecimals + (fee * QORT_DECIMALS) > walletBalanceDecimals) {
this.loader.hide();
- let snack1string = get("chatpage.cchange51");
- parentEpml.request('showSnackBar', `${snack1string}`);
- return false;
+ let errorMsg = "Insufficient Funds!"
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
}
- if (parseFloat(amount) <= 0) {
+ if (amount <= 0) {
this.loader.hide();
- let snack2string = get("chatpage.cchange52");
- parentEpml.request('showSnackBar', `${snack2string}`);
- return false;
+ let errorMsg = "Invalid Amount!"
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
}
if (recipient.length === 0) {
this.loader.hide();
- let snack3string = get("chatpage.cchange53");
- parentEpml.request('showSnackBar', `${snack3string}`);
- return false;
+ let errorMsg = "Receiver cannot be empty!"
+ let obj = {};
+ obj['error'] = errorMsg;
+ response = JSON.stringify(obj);
+ break;
}
const validateName = async (receiverName) => {
@@ -1020,9 +1059,10 @@ class WebBrowser extends LitElement {
const res = getTxnRequestResponse(myTransaction)
return res;
} else {
- console.error(`${translate("chatpage.cchange54")}`)
- parentEpml.request('showSnackBar', `${translate("chatpage.cchange54")}`)
- this.loader.hide();
+
+ let errorMsg = "Invalid Receiver!"
+ throw new Error(errorMsg)
+
}
}
}
@@ -1073,14 +1113,15 @@ class WebBrowser extends LitElement {
const getTxnRequestResponse = (txnResponse) => {
if (txnResponse.success === false && txnResponse.message) {
this.loader.hide();
- throw new Error(txnResponse);
+ throw new Error(txnResponse.message);
} else if (txnResponse.success === true && !txnResponse.data.error) {
this.loader.hide();
+ return txnResponse.data;
} else {
this.loader.hide();
- throw new Error(txnResponse);
+ throw new Error('Error: could not send coin');
}
- return txnResponse;
+
}
try {
@@ -1088,11 +1129,13 @@ class WebBrowser extends LitElement {
response = result;
} catch (error) {
console.error(error);
- return '{"error": "Request could not be fulfilled"}';
+ response = '{"error": "Request could not be fulfilled"}';
} finally {
- console.log("Case completed.");
+ this.loader.hide();
}
break;
+ }
+
default:
console.log('Unhandled message: ' + JSON.stringify(data));
@@ -1107,7 +1150,6 @@ class WebBrowser extends LitElement {
// Not all responses will be JSON
responseObj = response;
}
-
// Respond to app
if (responseObj.error != null) {
event.ports[0].postMessage({
From f08fb36fdcbd472b836ba14953c029641bf37bf5 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Fri, 24 Feb 2023 13:14:02 +0000
Subject: [PATCH 21/83] add translations
---
qortal-ui-core/language/us.json | 4 +++-
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 4 ++--
2 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index e0892920..be5010f8 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -500,7 +500,9 @@
"bchange20": "Do you give this application permission to get your wallet balance?",
"bchange21": "Fetch Wallet Failed. Please try again!",
"bchange22": "Do you give this application permission to send a chat message?",
- "bchange23": "Message Sent!"
+ "bchange23": "Message Sent!",
+ "bchange24": "Reject",
+ "bchange25": "Accept"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 2ae43c96..5a423b8f 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -1487,8 +1487,8 @@ async function showModalAndWait(type, data) {
${type === actions.SEND_CHAT_MESSAGE ? `${get("browserpage.bchange22")}
` : ''}
-
-
+
+
From 8f9498b4c9b7c7a63f9bbff5bf54ec05c84787b9 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Fri, 24 Feb 2023 14:56:52 +0000
Subject: [PATCH 22/83] version 2 api transaction for q-app
---
qortal-ui-core/src/plugins/routes.js | 60 ++++++++++++++++---
qortal-ui-crypto/api/api.js | 2 +-
qortal-ui-crypto/api/createTransaction.js | 6 ++
.../plugins/core/qdn/browser/browser.src.js | 11 +++-
.../plugins/utils/publish-image.js | 4 +-
5 files changed, 71 insertions(+), 12 deletions(-)
diff --git a/qortal-ui-core/src/plugins/routes.js b/qortal-ui-core/src/plugins/routes.js
index f51001f8..ac83416b 100644
--- a/qortal-ui-core/src/plugins/routes.js
+++ b/qortal-ui-core/src/plugins/routes.js
@@ -22,6 +22,7 @@ import framePasteMenu from '../functional-components/frame-paste-menu.js';
const createTransaction = api.createTransaction;
const processTransaction = api.processTransaction;
+const processTransactionVersion2 = api.processTransactionVersion2;
const signChatTransaction = api.signChatTransaction;
const signArbitraryTransaction = api.signArbitraryTransaction;
const tradeBotCreateRequest = api.tradeBotCreateRequest;
@@ -144,8 +145,16 @@ export const routes = {
if (!req.disableModal && !req.data.disableModal) {
await requestTransactionDialog.requestTransaction(tx);
}
-
- const res = await processTransaction(tx.signedBytes);
+
+ let res
+
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(tx.signedBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(tx.signedBytes);
+ }
+
let extraData = {}
if(req.data.type === 38 && tx && tx._rewardShareKeyPair && tx._rewardShareKeyPair.secretKey){
extraData.rewardSharePrivateKey = Base58.encode(tx._rewardShareKeyPair.secretKey)
@@ -191,7 +200,16 @@ export const routes = {
_keyPair,
req.data.params
);
- const res = await processTransaction(tx.signedBytes);
+ let res
+
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(tx.signedBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(tx.signedBytes);
+ }
+
+
response = {
success: true,
data: res,
@@ -242,8 +260,16 @@ export const routes = {
req.data.chatNonce,
store.getState().app.wallet._addresses[req.data.nonce].keyPair
);
+
+ let res
- const res = await processTransaction(signedChatBytes);
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(signedChatBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(signedChatBytes);
+ }
+
response = res;
} catch (e) {
console.error(e);
@@ -262,8 +288,15 @@ export const routes = {
req.data.arbitraryNonce,
store.getState().app.wallet._addresses[req.data.nonce].keyPair
);
+ let res
- const res = await processTransaction(signedArbitraryBytes);
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(signedArbitraryBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(signedArbitraryBytes);
+ }
+
response = res;
} catch (e) {
console.error(e);
@@ -293,8 +326,14 @@ export const routes = {
unsignedTxn,
store.getState().app.selectedAddress.keyPair
);
+ let res
- const res = await processTransaction(signedTxnBytes);
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(signedTxnBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(signedTxnBytes);
+ }
response = res;
} catch (e) {
console.error(e);
@@ -327,8 +366,15 @@ export const routes = {
unsignedTxn,
store.getState().app.selectedAddress.keyPair
);
+
+ let res
- const res = await processTransaction(signedTxnBytes);
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(signedTxnBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(signedTxnBytes);
+ }
response = res;
} catch (e) {
diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js
index 98da919b..e8e156dd 100644
--- a/qortal-ui-crypto/api/api.js
+++ b/qortal-ui-crypto/api/api.js
@@ -1,5 +1,5 @@
export { request } from './fetch-request.js'
export { transactionTypes as transactions } from './transactions/transactions.js'
-export { processTransaction, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js'
+export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js'
export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js'
export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js'
diff --git a/qortal-ui-crypto/api/createTransaction.js b/qortal-ui-crypto/api/createTransaction.js
index 2a56aa56..169561dd 100644
--- a/qortal-ui-crypto/api/createTransaction.js
+++ b/qortal-ui-crypto/api/createTransaction.js
@@ -36,3 +36,9 @@ export const processTransaction = bytes => request('/transactions/process', {
method: 'POST',
body: Base58.encode(bytes)
})
+
+export const processTransactionVersion2 = bytes => request('/transactions/process?apiVersion=2', {
+ method: 'POST',
+ body: Base58.encode(bytes)
+})
+
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 5a423b8f..8f695dbf 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -342,7 +342,8 @@ class WebBrowser extends LitElement {
lastReference: lastRef,
groupdialog1: groupdialog1,
groupdialog2: groupdialog2
- }
+ },
+ apiVersion: 2
})
return myTxnrequest
}
@@ -398,7 +399,8 @@ class WebBrowser extends LitElement {
lastReference: lastRef,
atDeployDialog1: groupdialog1,
atDeployDialog2: groupdialog2
- }
+ },
+ apiVersion: 2
})
return myTxnrequest
}
@@ -550,6 +552,7 @@ class WebBrowser extends LitElement {
selectedAddress: this.selectedAddress,
worker: worker,
isBase64: true,
+ apiVersion: 2
});
response = JSON.stringify(resPublish);
@@ -624,7 +627,8 @@ class WebBrowser extends LitElement {
let _response = await parentEpml.request('sign_chat', {
nonce: this.selectedAddress.nonce,
chatBytesArray: chatBytesArray,
- chatNonce: nonce
+ chatNonce: nonce,
+ apiVersion: 2
});
const chatResponse = getSendChatResponse(_response);
@@ -1106,6 +1110,7 @@ class WebBrowser extends LitElement {
dialogAddress,
dialogName
},
+ apiVersion: 2
})
return myTxnrequest;
}
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 56668e23..11aed013 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -18,7 +18,8 @@ export const publishData = async ({
selectedAddress,
worker,
isBase64,
- metaData
+ metaData,
+ apiVersion
}) => {
const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", {
@@ -71,6 +72,7 @@ export const publishData = async ({
arbitraryBytesBase58: transactionBytesBase58,
arbitraryBytesForSigningBase58: convertedBytesBase58,
arbitraryNonce: nonce,
+ apiVersion: apiVersion ? apiVersion : null
})
let myResponse = { error: "" }
if (response === false) {
From 21951f3ebee3544f3b3b39fd9e648ce17da74b5f Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Fri, 24 Feb 2023 17:46:43 -0500
Subject: [PATCH 23/83] Added auth modal to q-apps
---
.../src/components/login-view/login-view.js | 7 +-
.../src/redux/app/actions/app-core.js | 16 ++++-
.../src/redux/app/app-action-types.js | 2 +
qortal-ui-core/src/redux/app/app-reducer.js | 20 +++++-
.../plugins/core/qdn/browser/browser.src.js | 69 +++++++++++++++++--
5 files changed, 103 insertions(+), 11 deletions(-)
diff --git a/qortal-ui-core/src/components/login-view/login-view.js b/qortal-ui-core/src/components/login-view/login-view.js
index ebdf31f2..257bbf36 100644
--- a/qortal-ui-core/src/components/login-view/login-view.js
+++ b/qortal-ui-core/src/components/login-view/login-view.js
@@ -14,14 +14,15 @@ import './login-section.js'
import '../qort-theme-toggle.js'
import settings from '../../functional-components/settings-page.js'
-import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen } from '../../redux/app/app-actions.js'
+import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth } from '../../redux/app/app-actions.js'
window.reduxStore = store
window.reduxAction = {
addAutoLoadImageChat: addAutoLoadImageChat,
removeAutoLoadImageChat: removeAutoLoadImageChat,
- addChatLastSeen: addChatLastSeen
-
+ addChatLastSeen: addChatLastSeen,
+ allowQAPPAutoAuth: allowQAPPAutoAuth,
+ removeQAPPAutoAuth: removeQAPPAutoAuth
}
const animationDuration = 0.7 // Seconds
diff --git a/qortal-ui-core/src/redux/app/actions/app-core.js b/qortal-ui-core/src/redux/app/actions/app-core.js
index 894f2c2e..43d5d57a 100644
--- a/qortal-ui-core/src/redux/app/actions/app-core.js
+++ b/qortal-ui-core/src/redux/app/actions/app-core.js
@@ -1,5 +1,5 @@
// Core App Actions here...
-import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from '../app-action-types.js'
+import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from '../app-action-types.js'
export const doUpdateBlockInfo = (blockObj) => {
return (dispatch, getState) => {
@@ -120,6 +120,20 @@ export const removeAutoLoadImageChat = (payload) => {
}
}
+export const allowQAPPAutoAuth = (payload) => {
+ return {
+ type: ALLOW_QAPP_AUTO_AUTH,
+ payload
+ }
+}
+
+export const removeQAPPAutoAuth = (payload) => {
+ return {
+ type: REMOVE_QAPP_AUTO_AUTH,
+ payload
+ }
+}
+
export const setChatLastSeen = (payload) => {
return {
type: SET_CHAT_LAST_SEEN,
diff --git a/qortal-ui-core/src/redux/app/app-action-types.js b/qortal-ui-core/src/redux/app/app-action-types.js
index 518d4cd7..4125e6b1 100644
--- a/qortal-ui-core/src/redux/app/app-action-types.js
+++ b/qortal-ui-core/src/redux/app/app-action-types.js
@@ -22,5 +22,7 @@ export const PASTE_MENU_SWITCH = 'PASTE_MENU_SWITCH'
export const FRAME_PASTE_MENU_SWITCH = 'FRAME_PASTE_MENU_SWITCH'
export const ADD_AUTO_LOAD_IMAGES_CHAT = 'ADD_AUTO_LOAD_IMAGES_CHAT'
export const REMOVE_AUTO_LOAD_IMAGES_CHAT = 'REMOVE_AUTO_LOAD_IMAGES_CHAT'
+export const ALLOW_QAPP_AUTO_AUTH = 'ALLOW_QAPP_AUTO_AUTH'
+export const REMOVE_QAPP_AUTO_AUTH = 'REMOVE_QAPP_AUTO_AUTH'
export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN'
export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN'
diff --git a/qortal-ui-core/src/redux/app/app-reducer.js b/qortal-ui-core/src/redux/app/app-reducer.js
index 68a48675..6e3849d1 100644
--- a/qortal-ui-core/src/redux/app/app-reducer.js
+++ b/qortal-ui-core/src/redux/app/app-reducer.js
@@ -1,6 +1,6 @@
// Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage.
import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js'
-import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from './app-action-types.js'
+import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from './app-action-types.js'
import { initWorkersReducer } from './reducers/init-workers.js'
import { loginReducer } from './reducers/login-reducer.js'
import { setNode, addNode } from './reducers/manage-node.js'
@@ -50,6 +50,7 @@ const INITIAL_STATE = {
elementId: ''
},
autoLoadImageChats: loadStateFromLocalStorage('autoLoadImageChats') || [],
+ qAPPAutoAuth: loadStateFromLocalStorage('qAPPAutoAuth') || false,
chatLastSeen: []
}
@@ -175,6 +176,23 @@ export default (state = INITIAL_STATE, action) => {
autoLoadImageChats: updatedState
}
}
+
+ case ALLOW_QAPP_AUTO_AUTH: {
+ saveStateToLocalStorage("qAPPAutoAuth", true)
+ return {
+ ...state,
+ qAPPAutoAuth: action.payload
+ }
+ }
+
+ case REMOVE_QAPP_AUTO_AUTH: {
+ saveStateToLocalStorage("qAPPAutoAuth", false)
+ return {
+ ...state,
+ qAPPAutoAuth: action.payload
+ }
+ }
+
case SET_CHAT_LAST_SEEN: {
return {
...state,
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 443d2d00..dc32aaaa 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -15,6 +15,7 @@ registerTranslateConfig({
import '@material/mwc-button';
import '@material/mwc-icon';
+import '@material/mwc-checkbox'
import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
import WebWorkerChat from 'web-worker:./computePowWorker.src.js';
import { publishData } from '../../../utils/publish-image.js';
@@ -231,7 +232,6 @@ class WebBrowser extends LitElement {
}
render() {
- console.log(1, "browser page here");
return html`
@@ -457,10 +457,21 @@ class WebBrowser extends LitElement {
switch (data.action) {
case 'GET_USER_ACCOUNT':
case actions.GET_USER_ACCOUNT:
- const res1 = await showModalAndWait(
- actions.GET_USER_ACCOUNT
- );
- if (res1.action === 'accept') {
+ let skip = false;
+ if (window.parent.reduxStore.getState().app.qAPPAutoAuth) {
+ skip = true;
+ }
+ let res1;
+ if (!skip) {
+ res1 = await showModalAndWait(
+ actions.GET_USER_ACCOUNT,
+ {
+ service: this.service,
+ name: this.name
+ }
+ );
+ };
+ if ((res1 && res1.action === 'accept') || skip) {
let account = {};
account['address'] = this.selectedAddress.address;
account['publicKey'] =
@@ -1439,7 +1450,21 @@ async function showModalAndWait(type, data) {
`
- ${type === actions.GET_USER_ACCOUNT ? `
${get("browserpage.bchange18")}
` : ''}
+ ${type === actions.GET_USER_ACCOUNT ? `
+
+
${`${data.service} ${data.name} ${get("browserpage.bchange18")}`}
+
${get("browserpage.bchange24")} ${data.service}
+
${get("browserpage.bchange25")}
+
+
+
+
+
+
+ ` : ''}
${type === actions.PUBLISH_QDN_RESOURCE ? `
${get("browserpage.bchange19")}
` : ''}
${type === actions.GET_WALLET_BALANCE ? `
${get("browserpage.bchange20")}
` : ''}
${type === actions.SEND_CHAT_MESSAGE ? `
${get("browserpage.bchange22")}
` : ''}
@@ -1462,6 +1487,11 @@ async function showModalAndWait(type, data) {
}
resolve({ action: 'accept', userData });
});
+ const modalContent = modal.querySelector('.modal-content');
+ modalContent.addEventListener('click', (e) => {
+ e.stopPropagation();
+ return;
+ });
const backdropClick = document.getElementById('backdrop');
backdropClick.addEventListener('click', () => {
if (modal.parentNode === document.body) {
@@ -1476,6 +1506,18 @@ async function showModalAndWait(type, data) {
}
resolve({ action: 'reject' });
});
+ const labelButton = modal.querySelector('#authButtonLabel');
+ labelButton.addEventListener('click', () => {
+ this.shadowRoot.getElementById('authButton').click();
+ })
+ const checkbox = modal.querySelector('#authButton');
+ checkbox.addEventListener('click', (e) => {
+ if (e.target.checked) {
+ window.parent.reduxStore.dispatch( window.parent.reduxAction.removeQAPPAutoAuth(false))
+ return
+ }
+ window.parent.reduxStore.dispatch( window.parent.reduxAction.allowQAPPAutoAuth(true))
+ })
});
}
@@ -1553,6 +1595,13 @@ justify-content: space-between;
padding: 25px;
}
+.modal-subcontainer {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 15px;
+}
+
.modal-paragraph {
font-family: Roboto, sans-serif;
font-size: 18px;
@@ -1562,6 +1611,14 @@ color: black;
margin: 0;
}
+.checkbox-row {
+ display: flex;
+ align-items: center;
+ font-family: Montserrat, sans-serif;
+ font-weight: 600;
+ color: black;
+}
+
.modal-buttons {
display: flex;
justify-content: space-between;
From 10d4489ba42afe2480d60ea5f1deabf144b2a46b Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Fri, 24 Feb 2023 17:47:07 -0500
Subject: [PATCH 24/83] Added translations
---
qortal-ui-core/language/us.json | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index e0892920..f2b65bb9 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -495,12 +495,15 @@
"bchange15": "Can't delete data from followed names. Please unfollow first.",
"bchange16": "Error occurred when trying to delete this resource. Please try again!",
"bchange17": "User declined to share account details",
- "bchange18": "Do you give this application permission to get your user address?",
+ "bchange18": "has requested authentication. Would you like to authenticate?",
"bchange19": "Do you give this application permission to publish to QDN?",
"bchange20": "Do you give this application permission to get your wallet balance?",
"bchange21": "Fetch Wallet Failed. Please try again!",
"bchange22": "Do you give this application permission to send a chat message?",
- "bchange23": "Message Sent!"
+ "bchange23": "Message Sent!",
+ "bchange24": "This shares your QORT address and allows your account to interact with the",
+ "bchange25": "No sensitive data is shared.",
+ "bchange26": "Always authenticate automatically"
},
"datapage": {
"dchange1": "Data Management",
From bd6cf70b2fadfc16c1eeb19e5e3eb88a5c93c4cd Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Sat, 25 Feb 2023 20:56:39 -0500
Subject: [PATCH 25/83] Removed other coins in SEND_COIN & fixed bug
---
.../plugins/core/qdn/browser/browser.src.js | 133 +++++++++---------
1 file changed, 69 insertions(+), 64 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 53ab4001..eae796af 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -895,61 +895,62 @@ class WebBrowser extends LitElement {
} finally {
this.loader.hide();
}
- } else {
- let _url = ``
- let _body = null
+ }
+ // else {
+ // let _url = ``
+ // let _body = null
- switch (coin) {
- case 'LTC':
- _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
- break
- case 'DOGE':
- _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
- break
- case 'DGB':
- _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
- break
- case 'RVN':
- _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
- break
- case 'ARRR':
- _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
- _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
- break
- default:
- break
- }
- try {
- this.loader.show();
- const res = await parentEpml.request('apiCall', {
- url: _url,
- method: 'POST',
- body: _body,
- })
- if (isNaN(Number(res))) {
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } else {
- response = (Number(res) / 1e8).toFixed(8);
- }
- } catch (error) {
- console.error(error);
- const data = {};
- const errorMsg = error.message || get("browserpage.bchange21");
- data['error'] = errorMsg;
- response = JSON.stringify(data);
- return;
- } finally {
- this.loader.hide()
- }
- }
+ // switch (coin) {
+ // case 'LTC':
+ // _url = `/crosschain/ltc/walletbalance?apiKey=${this.getApiKey()}`
+ // _body = window.parent.reduxStore.getState().app.selectedAddress.ltcWallet.derivedMasterPublicKey
+ // break
+ // case 'DOGE':
+ // _url = `/crosschain/doge/walletbalance?apiKey=${this.getApiKey()}`
+ // _body = window.parent.reduxStore.getState().app.selectedAddress.dogeWallet.derivedMasterPublicKey
+ // break
+ // case 'DGB':
+ // _url = `/crosschain/dgb/walletbalance?apiKey=${this.getApiKey()}`
+ // _body = window.parent.reduxStore.getState().app.selectedAddress.dgbWallet.derivedMasterPublicKey
+ // break
+ // case 'RVN':
+ // _url = `/crosschain/rvn/walletbalance?apiKey=${this.getApiKey()}`
+ // _body = window.parent.reduxStore.getState().app.selectedAddress.rvnWallet.derivedMasterPublicKey
+ // break
+ // case 'ARRR':
+ // _url = `/crosschain/arrr/walletbalance?apiKey=${this.getApiKey()}`
+ // _body = window.parent.reduxStore.getState().app.selectedAddress.arrrWallet.seed58
+ // break
+ // default:
+ // break
+ // }
+ // try {
+ // this.loader.show();
+ // const res = await parentEpml.request('apiCall', {
+ // url: _url,
+ // method: 'POST',
+ // body: _body,
+ // })
+ // if (isNaN(Number(res))) {
+ // const data = {};
+ // const errorMsg = error.message || get("browserpage.bchange21");
+ // data['error'] = errorMsg;
+ // response = JSON.stringify(data);
+ // return;
+ // } else {
+ // response = (Number(res) / 1e8).toFixed(8);
+ // }
+ // } catch (error) {
+ // console.error(error);
+ // const data = {};
+ // const errorMsg = error.message || get("browserpage.bchange21");
+ // data['error'] = errorMsg;
+ // response = JSON.stringify(data);
+ // return;
+ // } finally {
+ // this.loader.hide()
+ // }
+ // }
} else if (res3.action === 'reject') {
response = '{"error": "User declined request"}';
}
@@ -1555,17 +1556,21 @@ async function showModalAndWait(type, data) {
resolve({ action: 'reject' });
});
const labelButton = modal.querySelector('#authButtonLabel');
- labelButton.addEventListener('click', () => {
- this.shadowRoot.getElementById('authButton').click();
- })
+ if (labelButton) {
+ labelButton.addEventListener('click', () => {
+ this.shadowRoot.getElementById('authButton').click();
+ })
+ }
const checkbox = modal.querySelector('#authButton');
- checkbox.addEventListener('click', (e) => {
- if (e.target.checked) {
- window.parent.reduxStore.dispatch( window.parent.reduxAction.removeQAPPAutoAuth(false))
- return
- }
- window.parent.reduxStore.dispatch( window.parent.reduxAction.allowQAPPAutoAuth(true))
- })
+ if (checkbox) {
+ checkbox.addEventListener('click', (e) => {
+ if (e.target.checked) {
+ window.parent.reduxStore.dispatch( window.parent.reduxAction.removeQAPPAutoAuth(false))
+ return
+ }
+ window.parent.reduxStore.dispatch( window.parent.reduxAction.allowQAPPAutoAuth(true))
+ })
+ }
});
}
From 45e0326bfd5b9fd05dd58df1c6d06ff427355b74 Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Fri, 13 Jan 2023 17:38:23 +0000
Subject: [PATCH 26/83] Initial UI support and placeholders for Q-Apps
---
.../plugins/core/qdn/browser/browser.src.js | 98 +++++++++++++++++++
1 file changed, 98 insertions(+)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 283e07f3..7c8d4570 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -234,6 +234,104 @@ class WebBrowser extends LitElement {
parentEpml.request('closeCopyTextMenu', null)
}
}
+
+ window.addEventListener("message", (event) => {
+ if (event == null || event.data == null || event.data.length == 0 || event.data.action == null) {
+ return;
+ }
+
+ let response = "{\"error\": \"Request could not be fulfilled\"}";
+ let data = event.data;
+ console.log("UI received event: " + JSON.stringify(data));
+
+ switch (data.action) {
+ case "GET_ACCOUNT_ADDRESS":
+ // For now, we will return this without prompting the user, but we may need to add a prompt later
+ response = this.selectedAddress.address;
+ break;
+
+ case "GET_ACCOUNT_PUBLIC_KEY":
+ // For now, we will return this without prompting the user, but we may need to add a prompt later
+ response = this.selectedAddress.base58PublicKey;
+ break;
+
+ case "PUBLISH_QDN_RESOURCE":
+ // Use "default" if user hasn't specified an identifer
+ if (data.identifier == null) {
+ data.identifier = "default";
+ }
+
+ // Params: data.service, data.name, data.identifier, data.data64,
+ // TODO: prompt user for publish. If they confirm, call `POST /arbitrary/{service}/{name}/{identifier}/base64` and sign+process transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "SEND_CHAT_MESSAGE":
+ // Params: data.groupId, data.destinationAddress, data.message
+ // TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "JOIN_GROUP":
+ // Params: data.groupId
+ // TODO: prompt user to join group. If they confirm, sign+process a JOIN_GROUP transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "DEPLOY_AT":
+ // Params: data.creationBytes, data.name, data.description, data.type, data.tags, data.amount, data.assetId, data.fee
+ // TODO: prompt user to deploy an AT. If they confirm, sign+process a DEPLOY_AT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "GET_WALLET_BALANCE":
+ // Params: data.coin (QORT / LTC / DOGE / DGB / RVN / ARRR)
+ // TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "SEND_COIN":
+ // Params: data.coin, data.destinationAddress, data.amount, data.fee
+ // TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ default:
+ console.log("Unhandled message: " + JSON.stringify(data));
+ return;
+ }
+
+
+ // Parse response
+ let responseObj;
+ try {
+ responseObj = JSON.parse(response);
+ } catch (e) {
+ // Not all responses will be JSON
+ responseObj = response;
+ }
+
+ // Respond to app
+ if (responseObj.error != null) {
+ event.ports[0].postMessage({
+ result: null,
+ error: responseObj
+ });
+ }
+ else {
+ event.ports[0].postMessage({
+ result: responseObj,
+ error: null
+ });
+ }
+
+ });
}
changeTheme() {
From 44732fcb018695e5ccc56bcfbd68fa4db2e201a5 Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Sun, 29 Jan 2023 13:22:12 +0000
Subject: [PATCH 27/83] GET_ACCOUNT_ADDRESS and GET_ACCOUNT_PUBLIC_KEY replaced
with a single action: GET_USER_ACCOUNT, as it doesn't make sense to request
address and public key separately (they are essentially the same thing).
---
.../plugins/core/qdn/browser/browser.src.js | 12 +++++-------
1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 7c8d4570..09f68ac4 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -245,14 +245,12 @@ class WebBrowser extends LitElement {
console.log("UI received event: " + JSON.stringify(data));
switch (data.action) {
- case "GET_ACCOUNT_ADDRESS":
+ case "GET_USER_ACCOUNT":
// For now, we will return this without prompting the user, but we may need to add a prompt later
- response = this.selectedAddress.address;
- break;
-
- case "GET_ACCOUNT_PUBLIC_KEY":
- // For now, we will return this without prompting the user, but we may need to add a prompt later
- response = this.selectedAddress.base58PublicKey;
+ let account = {};
+ account["address"] = this.selectedAddress.address;
+ account["publicKey"] = this.selectedAddress.base58PublicKey;
+ response = JSON.stringify(account);
break;
case "PUBLISH_QDN_RESOURCE":
From 836ef5d6d102e34d7c3e38becf0cff726d3c473c Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Fri, 17 Feb 2023 15:38:54 +0000
Subject: [PATCH 28/83] Upgraded browser functionality to support identifier,
paths, and a dynamic address bar.
Requires Q-Apps functionality in the core.
---
.../plugins/core/qdn/browser/browser.src.js | 34 ++++++++++++++++---
1 file changed, 29 insertions(+), 5 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 09f68ac4..6c5962f9 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -19,6 +19,8 @@ class WebBrowser extends LitElement {
name: { type: String },
service: { type: String },
identifier: { type: String },
+ path: { type: String },
+ displayUrl: {type: String },
followedNames: { type: Array },
blockedNames: { type: Array },
theme: { type: String, reflect: true }
@@ -103,12 +105,18 @@ class WebBrowser extends LitElement {
const urlParams = new URLSearchParams(window.location.search);
this.name = urlParams.get('name');
this.service = urlParams.get('service');
- // FUTURE: add support for identifiers
- this.identifier = null;
+ this.identifier = urlParams.get('identifier') != null ? urlParams.get('identifier') : null;
+ this.path = urlParams.get('path') != null ? ((urlParams.get('path').startsWith("/") ? "" : "/") + urlParams.get('path')) : "";
this.followedNames = []
this.blockedNames = []
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
+ // Build initial display URL
+ let displayUrl = "qortal://" + this.service + "/" + this.name;
+ if (this.identifier != null && data.identifier != "" && this.identifier != "default") displayUrl = displayUrl.concat("/" + this.identifier);
+ if (this.path != null && this.path != "/") displayUrl = displayUrl.concat(this.path);
+ this.displayUrl = displayUrl;
+
const getFollowedNames = async () => {
let followedNames = await parentEpml.request('apiCall', {
@@ -132,7 +140,7 @@ class WebBrowser extends LitElement {
const render = () => {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
- this.url = `${nodeUrl}/render/${this.service}/${this.name}?theme=${this.theme}`;
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
}
const authorizeAndRender = () => {
@@ -186,7 +194,7 @@ class WebBrowser extends LitElement {
this.goForward()} title="${translate("browserpage.bchange1")}" class="address-bar-button">arrow_forward_ios
this.refresh()} title="${translate("browserpage.bchange2")}" class="address-bar-button">refresh
this.goBackToList()} title="${translate("browserpage.bchange3")}" class="address-bar-button">home
-
+
this.delete()} title="${translate("browserpage.bchange4")} ${this.service} ${this.name} ${translate("browserpage.bchange5")}" class="address-bar-button float-right">delete
${this.renderBlockUnblockButton()}
${this.renderFollowUnfollowButton()}
@@ -253,6 +261,20 @@ class WebBrowser extends LitElement {
response = JSON.stringify(account);
break;
+ case "LINK_TO_QDN_RESOURCE":
+ case "QDN_RESOURCE_DISPLAYED":
+ // Links are handled by the core, but the UI also listens for these actions in order to update the address bar.
+ // Note: don't update this.url here, as we don't want to force reload the iframe each time.
+ let url = "qortal://" + data.service + "/" + data.name;
+ this.path = data.path != null ? ((data.path.startsWith("/") ? "" : "/") + data.path) : null;
+ if (data.identifier != null && data.identifier != "" && data.identifier != "default") url = url.concat("/" + data.identifier);
+ if (this.path != null && this.path != "/") url = url.concat(this.path);
+ this.name = data.name;
+ this.service = data.service;
+ this.identifier = data.identifier;
+ this.displayUrl = url;
+ return;
+
case "PUBLISH_QDN_RESOURCE":
// Use "default" if user hasn't specified an identifer
if (data.identifier == null) {
@@ -397,7 +419,9 @@ class WebBrowser extends LitElement {
}
refresh() {
- window.location.reload();
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
}
goBackToList() {
From 194f46114754a4c7232759555fe1873726bd205d Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Thu, 2 Mar 2023 21:51:28 +0000
Subject: [PATCH 29/83] Fix browser loading issue. We no longer need to
authorize a website/app before viewing.
---
.../plugins/core/qdn/browser/browser.src.js | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index eae796af..e0eea567 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -179,22 +179,6 @@ class WebBrowser extends LitElement {
}`;
};
- const authorizeAndRender = () => {
- parentEpml
- .request('apiCall', {
- url: `/render/authorize/${this.name
- }?apiKey=${this.getApiKey()}`,
- method: 'POST',
- })
- .then((res) => {
- if (res.error) {
- // Authorization problem - API key incorrect?
- } else {
- render();
- }
- });
- };
-
let configLoaded = false;
parentEpml.ready().then(() => {
@@ -214,7 +198,7 @@ class WebBrowser extends LitElement {
parentEpml.subscribe('config', (c) => {
this.config = JSON.parse(c);
if (!configLoaded) {
- authorizeAndRender();
+ render();
setTimeout(getFollowedNames, 1);
setTimeout(getBlockedNames, 1);
configLoaded = true;
From fdde6aeffe9855cde55ac971c60983f29570c818 Mon Sep 17 00:00:00 2001
From: Justin Ferrari
Date: Thu, 2 Mar 2023 21:22:08 -0500
Subject: [PATCH 30/83] Fixed issue with send_message
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index eae796af..b40105d0 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -648,14 +648,13 @@ class WebBrowser extends LitElement {
};
const getSendChatResponse = (res) => {
- if (res === true) {
+ if (res.signature) {
return res
} else if (res.error) {
throw new Error(res.message);
} else {
throw new Error('ERROR: Could not send message');
}
-
};
const chatResponse = await sendMessageRequest();
From a4481c14ad09a610205c58cd3c92d6a148728319 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:06:24 +0100
Subject: [PATCH 31/83] Add q-app
---
.../core/q-app/app-browser/app-browser.src.js | 626 ++++++++++
.../plugins/core/q-app/app-browser/index.html | 55 +
.../plugins/core/q-app/index.html | 55 +
.../plugins/core/q-app/publish-app/index.html | 55 +
.../core/q-app/publish-app/publish-app.src.js | 670 +++++++++++
.../plugins/core/q-app/q-apps.src.js | 1041 +++++++++++++++++
6 files changed, 2502 insertions(+)
create mode 100644 qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
create mode 100644 qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
create mode 100644 qortal-ui-plugins/plugins/core/q-app/index.html
create mode 100644 qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
create mode 100644 qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
create mode 100644 qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
diff --git a/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js b/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
new file mode 100644
index 00000000..b64c55bb
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
@@ -0,0 +1,626 @@
+import { LitElement, html, css } from 'lit'
+import { render } from 'lit/html.js'
+import { Epml } from '../../../../epml'
+import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
+
+registerTranslateConfig({
+ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
+})
+
+import '@material/mwc-button'
+import '@material/mwc-icon'
+
+const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
+
+class AppBrowser extends LitElement {
+ static get properties() {
+ return {
+ url: { type: String },
+ name: { type: String },
+ service: { type: String },
+ identifier: { type: String },
+ path: { type: String },
+ displayUrl: {type: String },
+ followedNames: { type: Array },
+ blockedNames: { type: Array },
+ theme: { type: String, reflect: true }
+ }
+ }
+
+ static get observers() {
+ return ['_kmxKeyUp(amount)']
+ }
+
+ static get styles() {
+ return css`
+ * {
+ --mdc-theme-primary: rgb(3, 169, 244);
+ --mdc-theme-secondary: var(--mdc-theme-primary);
+ --paper-input-container-focus-color: var(--mdc-theme-primary);
+ }
+
+ #websitesWrapper paper-button {
+ float: right;
+ }
+
+ #websitesWrapper .buttons {
+ width: auto !important;
+ }
+
+ .address-bar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 100px;
+ background-color: var(--white);
+ height: 36px;
+ }
+
+ .address-bar-button mwc-icon {
+ width: 20px;
+ }
+
+ .iframe-container {
+ position: absolute;
+ top: 36px;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border-top: 1px solid var(--black);
+ }
+
+ .iframe-container iframe {
+ display: block;
+ width: 100%;
+ height: 100%;
+ border: none;
+ background-color: var(--white);
+ }
+
+ input[type=text] {
+ margin: 0;
+ padding: 2px 0 0 20px;
+ border: 0;
+ height: 34px;
+ font-size: 16px;
+ background-color: var(--white);
+ }
+
+ paper-progress {
+ --paper-progress-active-color: var(--mdc-theme-primary);
+ }
+
+ .float-right {
+ float: right;
+ }
+
+ `
+ }
+
+ constructor() {
+ super()
+ this.url = 'about:blank'
+
+ const urlParams = new URLSearchParams(window.location.search);
+ this.name = urlParams.get('name');
+ this.service = urlParams.get('service');
+ this.identifier = urlParams.get('identifier') != null ? urlParams.get('identifier') : null;
+ this.path = urlParams.get('path') != null ? ((urlParams.get('path').startsWith("/") ? "" : "/") + urlParams.get('path')) : "";
+ this.followedNames = []
+ this.blockedNames = []
+ this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
+
+ // Build initial display URL
+ let displayUrl = "qortal://" + this.service + "/" + this.name;
+ if (this.identifier != null && data.identifier != "" && this.identifier != "default") displayUrl = displayUrl.concat("/" + this.identifier);
+ if (this.path != null && this.path != "/") displayUrl = displayUrl.concat(this.path);
+ this.displayUrl = displayUrl;
+
+ const getFollowedNames = async () => {
+
+ let followedNames = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`
+ })
+
+ this.followedNames = followedNames
+ setTimeout(getFollowedNames, this.config.user.nodeSettings.pingInterval)
+ }
+
+ const getBlockedNames = async () => {
+
+ let blockedNames = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`
+ })
+
+ this.blockedNames = blockedNames
+ setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval)
+ }
+
+ const render = () => {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
+ }
+
+ const authorizeAndRender = () => {
+ parentEpml.request('apiCall', {
+ url: `/render/authorize/${this.name}?apiKey=${this.getApiKey()}`,
+ method: "POST"
+ }).then(res => {
+ if (res.error) {
+ // Authorization problem - API key incorrect?
+ }
+ else {
+ render()
+ }
+ })
+ }
+
+ let configLoaded = false
+
+ parentEpml.ready().then(() => {
+ parentEpml.subscribe('selected_address', async selectedAddress => {
+ this.selectedAddress = {}
+ selectedAddress = JSON.parse(selectedAddress)
+ if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
+ this.selectedAddress = selectedAddress
+ })
+ parentEpml.subscribe('config', c => {
+ this.config = JSON.parse(c)
+ if (!configLoaded) {
+ authorizeAndRender()
+ setTimeout(getFollowedNames, 1)
+ setTimeout(getBlockedNames, 1)
+ configLoaded = true
+ }
+ })
+ parentEpml.subscribe('copy_menu_switch', async value => {
+
+ if (value === 'false' && window.getSelection().toString().length !== 0) {
+
+ this.clearSelection()
+ }
+ })
+ })
+ }
+
+ render() {
+ return html`
+
+
+
+ this.goBack()} title="${translate("general.back")}" class="address-bar-button">arrow_back_ios
+ this.goForward()} title="${translate("browserpage.bchange1")}" class="address-bar-button">arrow_forward_ios
+ this.refresh()} title="${translate("browserpage.bchange2")}" class="address-bar-button">refresh
+ this.goBackToList()} title="${translate("browserpage.bchange3")}" class="address-bar-button">home
+
+ this.delete()} title="${translate("browserpage.bchange4")} ${this.service} ${this.name} ${translate("browserpage.bchange5")}" class="address-bar-button float-right">delete
+ ${this.renderBlockUnblockButton()}
+ ${this.renderFollowUnfollowButton()}
+
+
+
+
+
+
+ `
+ }
+
+ firstUpdated() {
+
+ this.changeTheme()
+ this.changeLanguage()
+
+ window.addEventListener('contextmenu', (event) => {
+ event.preventDefault()
+ this._textMenu(event)
+ })
+
+ window.addEventListener('click', () => {
+ parentEpml.request('closeCopyTextMenu', null)
+ })
+
+ window.addEventListener('storage', () => {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+ const checkTheme = localStorage.getItem('qortalTheme')
+
+ use(checkLanguage)
+
+ if (checkTheme === 'dark') {
+ this.theme = 'dark'
+ } else {
+ this.theme = 'light'
+ }
+ document.querySelector('html').setAttribute('theme', this.theme)
+ })
+
+ window.onkeyup = (e) => {
+ if (e.keyCode === 27) {
+ parentEpml.request('closeCopyTextMenu', null)
+ }
+ }
+
+ window.addEventListener("message", (event) => {
+ if (event == null || event.data == null || event.data.length == 0 || event.data.action == null) {
+ return;
+ }
+
+ let response = "{\"error\": \"Request could not be fulfilled\"}";
+ let data = event.data;
+ console.log("UI received event: " + JSON.stringify(data));
+
+ switch (data.action) {
+ case "GET_USER_ACCOUNT":
+ // For now, we will return this without prompting the user, but we may need to add a prompt later
+ let account = {};
+ account["address"] = this.selectedAddress.address;
+ account["publicKey"] = this.selectedAddress.base58PublicKey;
+ response = JSON.stringify(account);
+ break;
+
+ case "LINK_TO_QDN_RESOURCE":
+ case "QDN_RESOURCE_DISPLAYED":
+ // Links are handled by the core, but the UI also listens for these actions in order to update the address bar.
+ // Note: don't update this.url here, as we don't want to force reload the iframe each time.
+ let url = "qortal://" + data.service + "/" + data.name;
+ this.path = data.path != null ? ((data.path.startsWith("/") ? "" : "/") + data.path) : null;
+ if (data.identifier != null && data.identifier != "" && data.identifier != "default") url = url.concat("/" + data.identifier);
+ if (this.path != null && this.path != "/") url = url.concat(this.path);
+ this.name = data.name;
+ this.service = data.service;
+ this.identifier = data.identifier;
+ this.displayUrl = url;
+ return;
+
+ case "PUBLISH_QDN_RESOURCE":
+ // Use "default" if user hasn't specified an identifer
+ if (data.identifier == null) {
+ data.identifier = "default";
+ }
+
+ // Params: data.service, data.name, data.identifier, data.data64,
+ // TODO: prompt user for publish. If they confirm, call `POST /arbitrary/{service}/{name}/{identifier}/base64` and sign+process transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "SEND_CHAT_MESSAGE":
+ // Params: data.groupId, data.destinationAddress, data.message
+ // TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "JOIN_GROUP":
+ // Params: data.groupId
+ // TODO: prompt user to join group. If they confirm, sign+process a JOIN_GROUP transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "DEPLOY_AT":
+ // Params: data.creationBytes, data.name, data.description, data.type, data.tags, data.amount, data.assetId, data.fee
+ // TODO: prompt user to deploy an AT. If they confirm, sign+process a DEPLOY_AT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "GET_WALLET_BALANCE":
+ // Params: data.coin (QORT / LTC / DOGE / DGB / RVN / ARRR)
+ // TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ case "SEND_COIN":
+ // Params: data.coin, data.destinationAddress, data.amount, data.fee
+ // TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
+ // then set the response string from the core to the `response` variable (defined above)
+ // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
+ break;
+
+ default:
+ console.log("Unhandled message: " + JSON.stringify(data));
+ return;
+ }
+
+
+ // Parse response
+ let responseObj;
+ try {
+ responseObj = JSON.parse(response);
+ } catch (e) {
+ // Not all responses will be JSON
+ responseObj = response;
+ }
+
+ // Respond to app
+ if (responseObj.error != null) {
+ event.ports[0].postMessage({
+ result: null,
+ error: responseObj
+ });
+ }
+ else {
+ event.ports[0].postMessage({
+ result: responseObj,
+ error: null
+ });
+ }
+
+ });
+ }
+
+ changeTheme() {
+ const checkTheme = localStorage.getItem('qortalTheme')
+ if (checkTheme === 'dark') {
+ this.theme = 'dark';
+ } else {
+ this.theme = 'light';
+ }
+ document.querySelector('html').setAttribute('theme', this.theme);
+ }
+
+ changeLanguage() {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+
+ if (checkLanguage === null || checkLanguage.length === 0) {
+ localStorage.setItem('qortalLanguage', 'us')
+ use('us')
+ } else {
+ use(checkLanguage)
+ }
+ }
+
+ renderFollowUnfollowButton() {
+ // Only show the follow/unfollow button if we have permission to modify the list on this node
+ if (this.followedNames == null || !Array.isArray(this.followedNames)) {
+ return html``
+ }
+
+ if (this.followedNames.indexOf(this.name) === -1) {
+ // render follow button
+ return html` this.follow()} title="${translate("browserpage.bchange7")} ${this.name}" class="address-bar-button float-right">add_to_queue`
+ }
+ else {
+ // render unfollow button
+ return html` this.unfollow()} title="${translate("browserpage.bchange8")} ${this.name}" class="address-bar-button float-right">remove_from_queue`
+ }
+ }
+
+ renderBlockUnblockButton() {
+ // Only show the block/unblock button if we have permission to modify the list on this node
+ if (this.blockedNames == null || !Array.isArray(this.blockedNames)) {
+ return html``
+ }
+
+ if (this.blockedNames.indexOf(this.name) === -1) {
+ // render block button
+ return html` this.block()} title="${translate("browserpage.bchange9")} ${this.name}" class="address-bar-button float-right">block`
+ }
+ else {
+ // render unblock button
+ return html` this.unblock()} title="${translate("browserpage.bchange10")} ${this.name}" class="address-bar-button float-right">radio_button_unchecked`
+ }
+ }
+
+
+ // Navigation
+
+ goBack() {
+ window.history.back();
+ }
+
+ goForward() {
+ window.history.forward();
+ }
+
+ refresh() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
+ }
+
+ goBackToList() {
+ window.location = "../index.html";
+ }
+
+ follow() {
+ this.followName(this.name);
+ }
+
+ unfollow() {
+ this.unfollowName(this.name);
+ }
+
+ block() {
+ this.blockName(this.name);
+ }
+
+ unblock() {
+ this.unblockName(this.name);
+ }
+
+ delete() {
+ this.deleteCurrentResource();
+ }
+
+
+ async followName(name) {
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ // Successfully followed - add to local list
+ // Remove it first by filtering the list - doing it this way ensures the UI updates
+ // immediately, as apposed to only adding if it doesn't already exist
+ this.followedNames = this.followedNames.filter(item => item != name);
+ this.followedNames.push(name)
+ }
+ else {
+ let err1string = get("browserpage.bchange11")
+ parentEpml.request('showSnackBar', `${err1string}`)
+ }
+
+ return ret
+ }
+
+ async unfollowName(name) {
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ // Successfully unfollowed - remove from local list
+ this.followedNames = this.followedNames.filter(item => item != name);
+ }
+ else {
+ let err2string = get("browserpage.bchange12")
+ parentEpml.request('showSnackBar', `${err2string}`)
+ }
+
+ return ret
+ }
+
+ async blockName(name) {
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ // Successfully blocked - add to local list
+ // Remove it first by filtering the list - doing it this way ensures the UI updates
+ // immediately, as apposed to only adding if it doesn't already exist
+ this.blockedNames = this.blockedNames.filter(item => item != name);
+ this.blockedNames.push(name)
+ }
+ else {
+ let err3string = get("browserpage.bchange13")
+ parentEpml.request('showSnackBar', `${err3string}`)
+ }
+
+ return ret
+ }
+
+ async unblockName(name) {
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ // Successfully unblocked - remove from local list
+ this.blockedNames = this.blockedNames.filter(item => item != name);
+ }
+ else {
+ let err4string = get("browserpage.bchange14")
+ parentEpml.request('showSnackBar', `${err4string}`)
+ }
+
+ return ret
+ }
+
+ async deleteCurrentResource() {
+ if (this.followedNames.indexOf(this.name) != -1) {
+ // Following name - so deleting won't work
+ let err5string = get("browserpage.bchange15")
+ parentEpml.request('showSnackBar', `${err5string}`)
+ return;
+ }
+
+ let identifier = this.identifier == null ? "default" : resource.identifier;
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resource/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`,
+ method: 'DELETE'
+ })
+
+ if (ret === true) {
+ this.goBackToList();
+ }
+ else {
+ let err6string = get("browserpage.bchange16")
+ parentEpml.request('showSnackBar', `${err6string}`)
+ }
+
+ return ret
+ }
+
+ _textMenu(event) {
+ const getSelectedText = () => {
+ var text = ''
+ if (typeof window.getSelection != 'undefined') {
+ text = window.getSelection().toString()
+ } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
+ text = this.shadowRoot.selection.createRange().text
+ }
+ return text
+ }
+
+ const checkSelectedTextAndShowMenu = () => {
+ let selectedText = getSelectedText()
+ if (selectedText && typeof selectedText === 'string') {
+ let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
+ let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
+ parentEpml.request('openCopyTextMenu', textMenuObject)
+ }
+ }
+ checkSelectedTextAndShowMenu()
+ }
+
+ getApiKey() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
+ let apiKey = myNode.apiKey;
+ return apiKey;
+ }
+
+ clearSelection() {
+ window.getSelection().removeAllRanges()
+ window.parent.getSelection().removeAllRanges()
+ }
+}
+
+window.customElements.define('app-browser', AppBrowser)
diff --git a/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html b/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
new file mode 100644
index 00000000..03cf4220
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qortal-ui-plugins/plugins/core/q-app/index.html b/qortal-ui-plugins/plugins/core/q-app/index.html
new file mode 100644
index 00000000..8898264a
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/index.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html b/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
new file mode 100644
index 00000000..57f183df
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js b/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
new file mode 100644
index 00000000..25ca22cd
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
@@ -0,0 +1,670 @@
+import { LitElement, html, css } from 'lit'
+import { render } from 'lit/html.js'
+import { Epml } from '../../../../epml'
+import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
+
+registerTranslateConfig({
+ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
+})
+
+import '@material/mwc-button'
+import '@material/mwc-textfield'
+import '@material/mwc-select'
+import '@material/mwc-list/mwc-list-item.js'
+import '@polymer/paper-progress/paper-progress.js'
+
+const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
+
+class PublishApp extends LitElement {
+ static get properties() {
+ return {
+ name: { type: String },
+ service: { type: String },
+ identifier: { type: String },
+ category: { type: String },
+ uploadType: { type: String },
+ showName: { type: Boolean },
+ showService: { type: Boolean },
+ showIdentifier: { type: Boolean },
+ showMetadata: { type: Boolean },
+ tags: { type: Array },
+ serviceLowercase: { type: String },
+ metadata: { type: Array },
+ categories: { type: Array },
+ names: { type: Array },
+ myRegisteredName: { type: String },
+ selectedName: { type: String },
+ path: { type: String },
+ portForwardingEnabled: { type: Boolean },
+ amount: { type: Number },
+ generalMessage: { type: String },
+ successMessage: { type: String },
+ errorMessage: { type: String },
+ loading: { type: Boolean },
+ btnDisable: { type: Boolean },
+ theme: { type: String, reflect: true }
+ }
+ }
+
+ static get observers() {
+ return ['_kmxKeyUp(amount)']
+ }
+
+ static get styles() {
+ return css`
+ * {
+ --mdc-theme-primary: rgb(3, 169, 244);
+ --mdc-theme-secondary: var(--mdc-theme-primary);
+ --paper-input-container-focus-color: var(--mdc-theme-primary);
+ --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);
+ --_lumo-grid-border-color: var(--border);
+ --_lumo-grid-secondary-border-color: var(--border2);
+ }
+
+
+ input[type=text] {
+ padding: 6px 6px 6px 6px;
+ color: var(--black);
+ }
+
+ input[type=file]::file-selector-button {
+ border: 1px solid transparent;
+ padding: 6px 6px 6px 6px;
+ border-radius: 5px;
+ color: #fff;
+ background-color: var(--mdc-theme-primary);
+ transition: 1s;
+ }
+
+ input[type=file]::file-selector-button:hover {
+ color: #000;
+ background-color: #81ecec;
+ border: 1px solid transparent;
+ }
+
+ #publishWrapper paper-button {
+ float: right;
+ }
+
+ #publishWrapper .buttons {
+ width: auto !important;
+ }
+
+ mwc-textfield {
+ margin: 0;
+ }
+
+ paper-progress {
+ --paper-progress-active-color: var(--mdc-theme-primary);
+ }
+
+ .upload-text {
+ display: block;
+ font-size: 14px;
+ color: var(--black);
+ }
+
+ .address-bar {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 100px;
+ background-color: var(--white);
+ height: 36px;
+ }
+
+ .address-bar-button mwc-icon {
+ width: 30px;
+ }
+ `
+ }
+
+ constructor() {
+ super()
+
+ this.showName = false;
+ this.showService = false
+ this.showIdentifier = false
+ this.showMetadata = false
+
+ const urlParams = new URLSearchParams(window.location.search)
+ this.name = urlParams.get('name')
+ this.service = urlParams.get('service')
+ this.identifier = urlParams.get('identifier')
+ this.category = urlParams.get('category')
+ this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file"
+
+ if (urlParams.get('showName') === "true") {
+ this.showName = true
+ }
+
+ if (urlParams.get('showService') === "true") {
+ this.showService = true
+ }
+
+ if (urlParams.get('showIdentifier') === "true") {
+ this.showIdentifier = true
+ }
+
+ if (urlParams.get('showMetadata') === "true") {
+ this.showMetadata = true
+ }
+
+ if (this.identifier != null) {
+ if (this.identifier === "null" || this.identifier.trim().length == 0) {
+ this.identifier = null
+ }
+ }
+
+ // Default to true so the message doesn't appear and disappear quickly
+ this.portForwardingEnabled = true
+ this.names = []
+ this.myRegisteredName = ''
+ this.selectedName = 'invalid'
+ this.path = ''
+ this.successMessage = ''
+ this.generalMessage = ''
+ this.errorMessage = ''
+ this.loading = false
+ this.btnDisable = false
+ this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
+
+ const fetchNames = () => {
+ parentEpml.request('apiCall', {url: `/names/address/${this.selectedAddress.address}?limit=0&reverse=true`}).then(res => {
+ setTimeout(() => {
+ this.names = res
+ if (res[0] != null) {
+ this.myRegisteredName = res[0].name;
+ }
+ }, 1)
+ })
+ setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval)
+ }
+
+ const fetchCategories = () => {
+ parentEpml.request('apiCall', {url: `/arbitrary/categories`}).then(res => {
+ setTimeout(() => {
+ this.categories = res
+ }, 1)
+ })
+ setTimeout(fetchCategories, this.config.user.nodeSettings.pingInterval)
+ }
+
+ const fetchPeersSummary = () => {
+ parentEpml.request('apiCall', {url: `/peers/summary`}).then(res => {
+ setTimeout(() => {
+ this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0);
+ }, 1)
+ })
+ setTimeout(fetchPeersSummary, this.config.user.nodeSettings.pingInterval)
+ }
+
+ let configLoaded = false
+
+ parentEpml.ready().then(() => {
+ parentEpml.subscribe('selected_address', async selectedAddress => {
+ this.selectedAddress = {}
+ selectedAddress = JSON.parse(selectedAddress)
+ if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
+ this.selectedAddress = selectedAddress
+ })
+
+ parentEpml.subscribe('config', c => {
+ if (!configLoaded) {
+ setTimeout(fetchNames, 1)
+ setTimeout(fetchCategories, 1)
+ setTimeout(fetchPeersSummary, 1)
+ configLoaded = true
+ }
+ this.config = JSON.parse(c)
+ })
+
+ parentEpml.subscribe('copy_menu_switch', async value => {
+ if (value === 'false' && window.getSelection().toString().length !== 0) {
+ this.clearSelection()
+ }
+ })
+ })
+ }
+
+ render() {
+ return html`
+
+
+
+ this.goBack()} class="address-bar-button">arrow_back_ios ${translate("general.back")}
+
+
+
+
${translate("publishpage.pchange1")} / ${translate("publishpage.pchange2")} Q-App
+
${translate("publishpage.pchange3")}
+
+
+
+
+ this.selectName(e)} style="min-width: 130px; max-width:100%; width:100%;">
+
+ ${this.myRegisteredName}
+
+
+
+
+
+
+
+
+
+
+
+ ${this.categories.map((c, index) => html`
+ ${c.name}
+ `)}
+
+
+
+
+
+
+
+
+
+
+ ${this.renderUploadField()}
+
+
+
+
+
+
+
${this.generalMessage}
+
${this.errorMessage}
+
${this.successMessage}
+ ${this.loading ? html`
` : ''}
+
+
+
+ `
+ }
+
+ firstUpdated() {
+
+ this.changeTheme()
+ this.changeLanguage()
+
+ window.addEventListener('contextmenu', (event) => {
+ event.preventDefault()
+ this._textMenu(event)
+ })
+
+ window.addEventListener('click', () => {
+ parentEpml.request('closeCopyTextMenu', null)
+ })
+
+ window.addEventListener('storage', () => {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+ const checkTheme = localStorage.getItem('qortalTheme')
+
+ use(checkLanguage)
+
+ if (checkTheme === 'dark') {
+ this.theme = 'dark'
+ } else {
+ this.theme = 'light'
+ }
+ document.querySelector('html').setAttribute('theme', this.theme)
+ })
+
+ window.onkeyup = (e) => {
+ if (e.keyCode === 27) {
+ parentEpml.request('closeCopyTextMenu', null)
+ }
+ }
+ }
+
+ changeTheme() {
+ const checkTheme = localStorage.getItem('qortalTheme')
+ if (checkTheme === 'dark') {
+ this.theme = 'dark';
+ } else {
+ this.theme = 'light';
+ }
+ document.querySelector('html').setAttribute('theme', this.theme);
+ }
+
+ changeLanguage() {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+
+ if (checkLanguage === null || checkLanguage.length === 0) {
+ localStorage.setItem('qortalLanguage', 'us')
+ use('us')
+ } else {
+ use(checkLanguage)
+ }
+ }
+
+ // Navigation
+ goBack() {
+ window.history.back();
+ }
+
+
+ renderUploadField() {
+ if (this.uploadType === "file") {
+ return html`
+
+
+
+ `
+ }
+ else if (this.uploadType === "zip") {
+ return html`
+
+ ${translate("publishpage.pchange12")}:
+
+
+ `
+ }
+ else {
+ return html`
+
+
+
+ `
+ }
+ }
+
+
+ doPublish(e) {
+ let registeredName = this.shadowRoot.getElementById('registeredName').value
+ let service = this.shadowRoot.getElementById('service').value
+ let identifier = this.shadowRoot.getElementById('identifier').value
+
+ // If name is hidden, use the value passed in via the name parameter
+ if (!this.showName) {
+ registeredName = this.name
+ }
+
+ let file;
+ let path;
+
+ if (this.uploadType === "file" || this.uploadType === "zip") {
+ file = this.shadowRoot.getElementById('file').files[0]
+ }
+ else if (this.uploadType === "path") {
+ path = this.shadowRoot.getElementById('path').value
+ }
+
+ this.generalMessage = ''
+ this.successMessage = ''
+ this.errorMessage = ''
+
+ if (registeredName === '') {
+ this.showName = true
+ let err1string = get("publishpage.pchange14")
+ parentEpml.request('showSnackBar', `${err1string}`)
+ }
+ else if (this.uploadType === "file" && file == null) {
+ let err2string = get("publishpage.pchange15")
+ parentEpml.request('showSnackBar', `${err2string}`)
+ }
+ else if (this.uploadType === "zip" && file == null) {
+ let err3string = get("publishpage.pchange16")
+ parentEpml.request('showSnackBar', `${err3string}`)
+ }
+ else if (this.uploadType === "path" && path === '') {
+ let err4string = get("publishpage.pchange17")
+ parentEpml.request('showSnackBar', `${err4string}`)
+ }
+ else if (service === '') {
+ let err5string = get("publishpage.pchange18")
+ parentEpml.request('showSnackBar', `${err5string}`)
+ }
+ else {
+ this.publishData(registeredName, path, file, service, identifier)
+ }
+ }
+
+ async publishData(registeredName, path, file, service, identifier) {
+ this.loading = true
+ this.btnDisable = true
+
+ const validateName = async (receiverName) => {
+ let nameRes = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/names/${receiverName}`,
+ })
+
+ return nameRes
+ }
+
+ const showError = async (errorMessage) => {
+ this.loading = false
+ this.btnDisable = false
+ this.generalMessage = ''
+ this.successMessage = ''
+ console.error(errorMessage)
+ }
+
+ const validate = async () => {
+ let validNameRes = await validateName(registeredName)
+ if (validNameRes.error) {
+ this.errorMessage = "Error: " + validNameRes.message
+ showError(this.errorMessage)
+ throw new Error(this.errorMessage);
+ }
+
+ let err6string = get("publishpage.pchange19")
+ this.generalMessage = `${err6string}`
+
+ let transactionBytes = await uploadData(registeredName, path, file)
+ if (transactionBytes.error) {
+ let err7string = get("publishpage.pchange20")
+ this.errorMessage = `${err7string}` + transactionBytes.message
+ showError(this.errorMessage)
+ throw new Error(this.errorMessage);
+ }
+ else if (transactionBytes.includes("Error 500 Internal Server Error")) {
+ let err8string = get("publishpage.pchange21")
+ this.errorMessage = `${err8string}`
+ showError(this.errorMessage)
+ throw new Error(this.errorMessage);
+ }
+
+ let err9string = get("publishpage.pchange22")
+ this.generalMessage = `${err9string}`
+
+ let signAndProcessRes = await signAndProcess(transactionBytes)
+ if (signAndProcessRes.error) {
+ let err10string = get("publishpage.pchange20")
+ this.errorMessage = `${err10string}` + signAndProcessRes.message
+ showError(this.errorMessage)
+ throw new Error(this.errorMessage);
+ }
+
+ let err11string = get("publishpage.pchange23")
+
+ this.btnDisable = false
+ this.loading = false
+ this.errorMessage = ''
+ this.generalMessage = ''
+ this.successMessage = `${err11string}`
+ }
+
+ const uploadData = async (registeredName, path, file) => {
+ let postBody = path
+ let urlSuffix = ""
+ if (file != null) {
+
+ // If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API
+ if (this.uploadType === "zip") {
+ urlSuffix = "/zip"
+ }
+ // If we're sending file data, use the /base64 version of the POST /arbitrary/* API
+ else if (this.uploadType === "file") {
+ urlSuffix = "/base64"
+ }
+
+ // Base64 encode the file to work around compatibility issues between javascript and java byte arrays
+ let fileBuffer = new Uint8Array(await file.arrayBuffer())
+ postBody = Buffer.from(fileBuffer).toString('base64');
+ }
+
+ // Optional metadata
+ let title = encodeURIComponent(this.shadowRoot.getElementById('title').value);
+ let description = encodeURIComponent(this.shadowRoot.getElementById('description').value);
+ let category = encodeURIComponent(this.shadowRoot.getElementById('category').value);
+ let tag1 = encodeURIComponent(this.shadowRoot.getElementById('tag1').value);
+ let tag2 = encodeURIComponent(this.shadowRoot.getElementById('tag2').value);
+ let tag3 = encodeURIComponent(this.shadowRoot.getElementById('tag3').value);
+ let tag4 = encodeURIComponent(this.shadowRoot.getElementById('tag4').value);
+ let tag5 = encodeURIComponent(this.shadowRoot.getElementById('tag5').value);
+
+ let metadataQueryString = `title=${title}&description=${description}&category=${category}&tags=${tag1}&tags=${tag2}&tags=${tag3}&tags=${tag4}&tags=${tag5}`
+
+ let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
+ if (identifier != null && identifier.trim().length > 0) {
+ uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
+ }
+
+ let uploadDataRes = await parentEpml.request('apiCall', {
+ type: 'api',
+ method: 'POST',
+ url: `${uploadDataUrl}`,
+ body: `${postBody}`,
+ })
+ return uploadDataRes
+ }
+
+ const convertBytesForSigning = async (transactionBytesBase58) => {
+ let convertedBytes = await parentEpml.request('apiCall', {
+ type: 'api',
+ method: 'POST',
+ url: `/transactions/convert`,
+ body: `${transactionBytesBase58}`,
+ })
+ return convertedBytes
+ }
+
+ const signAndProcess = async (transactionBytesBase58) => {
+ let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58)
+ if (convertedBytesBase58.error) {
+ let err12string = get("publishpage.pchange20")
+ this.errorMessage = `${err12string}` + convertedBytesBase58.message
+ showError(this.errorMessage)
+ throw new Error(this.errorMessage);
+ }
+
+ const convertedBytes = window.parent.Base58.decode(convertedBytesBase58);
+ const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; });
+ const convertedBytesArray = new Uint8Array(_convertedBytesArray)
+ const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result
+
+ const hashPtr = window.parent.sbrk(32, window.parent.heap);
+ const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
+ hashAry.set(convertedBytesHash);
+
+ const difficulty = 14;
+ const workBufferLength = 8 * 1024 * 1024;
+ const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
+
+ this.errorMessage = '';
+ this.successMessage = '';
+ let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
+
+ let response = await parentEpml.request('sign_arbitrary', {
+ nonce: this.selectedAddress.nonce,
+ arbitraryBytesBase58: transactionBytesBase58,
+ arbitraryBytesForSigningBase58: convertedBytesBase58,
+ arbitraryNonce: nonce
+ })
+
+ let myResponse = { error: '' }
+ if (response === false) {
+ let err13string = get("publishpage.pchange24")
+ myResponse.error = `${err13string}`
+ }
+ else {
+ myResponse = response
+ }
+ return myResponse
+ }
+ validate()
+ }
+
+ _textMenu(event) {
+ const getSelectedText = () => {
+ var text = ''
+ if (typeof window.getSelection != 'undefined') {
+ text = window.getSelection().toString()
+ } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
+ text = this.shadowRoot.selection.createRange().text
+ }
+ return text
+ }
+
+ const checkSelectedTextAndShowMenu = () => {
+ let selectedText = getSelectedText()
+ if (selectedText && typeof selectedText === 'string') {
+ let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
+ let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
+ parentEpml.request('openCopyTextMenu', textMenuObject)
+ }
+ }
+ checkSelectedTextAndShowMenu()
+ }
+
+
+ fetchResourceMetadata() {
+ let identifier = this.identifier != null ? this.identifier : "default";
+
+ parentEpml.request('apiCall', {
+ url: `/arbitrary/metadata/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`
+ }).then(res => {
+
+ setTimeout(() => {
+ this.metadata = res
+ if (this.metadata != null && this.metadata.category != null) {
+ this.shadowRoot.getElementById('category').value = this.metadata.category;
+ }
+ else {
+ this.shadowRoot.getElementById('category').value = "";
+ }
+ }, 1)
+ })
+ }
+
+ selectName(e) {
+ let name = this.shadowRoot.getElementById('registeredName')
+ this.selectedName = (name.value)
+ // Update the current name if one has been selected
+ if (name.value.length > 0) {
+ this.name = (name.value)
+ }
+ this.fetchResourceMetadata();
+ }
+
+ getApiKey() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
+ let apiKey = myNode.apiKey;
+ return apiKey;
+ }
+
+ clearSelection() {
+ window.getSelection().removeAllRanges()
+ window.parent.getSelection().removeAllRanges()
+ }
+}
+
+window.customElements.define('publish-app', PublishApp)
diff --git a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
new file mode 100644
index 00000000..6f29fd66
--- /dev/null
+++ b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
@@ -0,0 +1,1041 @@
+import { LitElement, html, css } from 'lit'
+import { render } from 'lit/html.js'
+import { Epml } from '../../../epml.js'
+import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
+import { columnBodyRenderer, gridRowDetailsRenderer } from '@vaadin/grid/lit.js'
+
+registerTranslateConfig({
+ loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
+})
+
+import '@material/mwc-icon'
+import '@material/mwc-button'
+import '@material/mwc-tab-bar'
+import '@material/mwc-textfield'
+
+import '@vaadin/button'
+import '@vaadin/grid'
+import '@vaadin/icon'
+import '@vaadin/icons'
+import '@vaadin/text-field'
+
+const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
+
+class QApps extends LitElement {
+ static get properties() {
+ return {
+ service: { type: String },
+ identifier: { type: String },
+ loading: { type: Boolean },
+ resources: { type: Array },
+ pageRes: { type: Array },
+ followedNames: { type: Array },
+ blockedNames: { type: Array },
+ relayMode: { type: Boolean },
+ selectedAddress: { type: Object },
+ searchName: { type: String },
+ searchResources: { type: Array },
+ followedResources: { type: Array },
+ blockedResources: { type: Array },
+ theme: { type: String, reflect: true }
+ }
+ }
+
+ static get styles() {
+ return css`
+ * {
+ --mdc-theme-primary: rgb(3, 169, 244);
+ --paper-input-container-focus-color: var(--mdc-theme-primary);
+ --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);
+ --_lumo-grid-border-color: var(--border);
+ --_lumo-grid-secondary-border-color: var(--border2);
+ }
+
+ #tabs-1 {
+ --mdc-tab-height: 50px;
+ }
+
+ #tabs-1-content {
+ height: 100%;
+ padding-bottom: 10px;
+ }
+
+ mwc-tab-bar {
+ --mdc-text-transform: none;
+ --mdc-tab-color-default: var(--black);
+ --mdc-tab-text-label-color-default: var(--black);
+ }
+
+ #pages {
+ display: flex;
+ flex-wrap: wrap;
+ padding: 10px 5px 5px 5px;
+ margin: 0px 20px 20px 20px;
+ }
+
+ #pages > button {
+ user-select: none;
+ padding: 5px;
+ margin: 0 5px;
+ border-radius: 10%;
+ border: 0;
+ background: transparent;
+ font: inherit;
+ outline: none;
+ cursor: pointer;
+ color: var(--black);
+ }
+
+ #pages > button:not([disabled]):hover,
+ #pages > button:focus {
+ color: #ccc;
+ background-color: #eee;
+ }
+
+ #pages > button[selected] {
+ font-weight: bold;
+ color: var(--white);
+ background-color: #ccc;
+ }
+
+ #pages > button[disabled] {
+ opacity: 0.5;
+ cursor: default;
+ }
+
+ #apps-list-page {
+ background: var(--white);
+ padding: 12px 24px;
+ }
+
+ #search {
+ display: flex;
+ width: 50%;
+ align-items: center;
+ }
+
+ .divCard {
+ border: 1px solid var(--border);
+ padding: 1em;
+ box-shadow: 0 .3px 1px 0 rgba(0,0,0,0.14), 0 1px 1px -1px rgba(0,0,0,0.12), 0 1px 2px 0 rgba(0,0,0,0.20);
+ margin-bottom: 2em;
+ }
+
+ h2 {
+ margin:0;
+ }
+
+ h2, h3, h4, h5 {
+ color: var(--black);
+ font-weight: 400;
+ }
+
+ a.visitSite {
+ color: var(--black);
+ text-decoration: none;
+ }
+
+ [hidden] {
+ display: hidden !important;
+ visibility: none !important;
+ }
+
+ .details {
+ display: flex;
+ font-size: 18px;
+ }
+
+ span {
+ font-size: 14px;
+ word-break: break-all;
+ }
+
+ select {
+ padding: 13px 20px;
+ width: 100%;
+ font-size: 14px;
+ color: #555;
+ font-weight: 400;
+ }
+
+ .title {
+ font-weight:600;
+ font-size:12px;
+ line-height: 32px;
+ opacity: 0.66;
+ }
+
+ .resourceTitle {
+ font-size:15px;
+ line-height: 32px;
+ }
+
+ .resourceDescription {
+ font-size:11px;
+ padding-bottom: 5px;
+ }
+
+ .resourceCategoryTags {
+ font-size:11px;
+ padding-bottom: 10px;
+ }
+
+ .resourceRegisteredName {
+ font-size:15px;
+ line-height: 32px;
+ }
+
+ .resourceStatus, .resourceStatus span {
+ font-size:11px;
+ }
+
+ .itemList {
+ padding:0;
+ }
+
+ .relay-mode-notice {
+ margin:auto;
+ text-align:center;
+ word-break:normal;
+ font-size:14px;
+ line-height:20px;
+ color: var(--relaynodetxt);
+ }
+
+ img {
+ border-radius: 25%;
+ max-width: 65px;
+ height: 100%;
+ max-height: 65px;
+ }
+
+ .green {
+ --mdc-theme-primary: #198754;
+ }
+ `
+ }
+
+ constructor() {
+ super()
+ this.service = "APP"
+ this.identifier = null
+ this.selectedAddress = {}
+ this.resources = []
+ this.pageRes = []
+ this.followedNames = []
+ this.blockedNames = []
+ this.relayMode = null
+ this.isLoading = false
+ this.searchName = ''
+ this.searchResources = []
+ this.followedResources = []
+ this.blockedResources = []
+ this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
+ }
+
+ render() {
+ return html`
+
+
+ this.displayTabContent('browse')}">
+ this.displayTabContent('followed')}">
+ this.displayTabContent('blocked')}">
+
+
+
+
+
${translate("appspage.schange1")}
+ ${this.renderPublishButton()}
+
+
+
${translate("appspage.schange4")}
+
+
+
+
+ this.doSearch(e)}">
+
+ ${translate("appspage.schange35")}
+
+
+
+ {
+ render(html`${this.renderAvatar(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderInfo(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderPublishedBy(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderDownload(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderOpenApp(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderFollowUnfollowButton(data.item)}`, root);
+ }}>
+
+ {
+ render(html`${this.renderBlockUnblockButton(data.item)}`, root);
+ }}>
+
+
+
+
+
${translate("appspage.schange9")}
+
+ {
+ render(html`${this.renderAvatar(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderInfo(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderPublishedBy(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderDownload(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderOpenApp(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderFollowUnfollowButton(data.item)}`, root);
+ }}>
+
+ {
+ render(html`${this.renderBlockUnblockButton(data.item)}`, root);
+ }}>
+
+
+
+ ${this.pageRes == null ? html`
+ Loading...
+ ` : ''}
+ ${this.isEmptyArray(this.pageRes) ? html`
+
${translate("appspage.schange10")}
+ ` : ''}
+
+ ${this.renderRelayModeText()}
+
+
+
+
${translate("appspage.schange11")}
+ ${this.renderPublishButton()}
+
+
+
${translate("appspage.schange12")}
+
+ {
+ render(html`${this.renderAvatar(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderInfo(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderPublishedBy(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderDownload(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderOpenApp(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderFollowUnfollowButton(data.item)}`, root);
+ }}>
+
+ {
+ render(html`${this.renderBlockUnblockButton(data.item)}`, root);
+ }}>
+
+
+ ${this.followedResources == null ? html`
+ Loading...
+ ` : ''}
+ ${this.isEmptyArray(this.followedResources) ? html`
+ ${translate("appspage.schange13")}
+ ` : ''}
+
+ ${this.renderRelayModeText()}
+
+
+
+
${translate("appspage.schange14")}
+ ${this.renderPublishButton()}
+
+
+
${translate("appspage.schange15")}
+
+ {
+ render(html`${this.renderAvatar(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderInfo(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderPublishedBy(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderDownload(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderOpenApp(data.item)}`, root)
+ }}>
+
+ {
+ render(html`${this.renderFollowUnfollowButton(data.item)}`, root);
+ }}>
+
+ {
+ render(html`${this.renderBlockUnblockButton(data.item)}`, root);
+ }}>
+
+
+ ${this.blockedResources == null ? html`
+ Loading...
+ ` : ''}
+ ${this.isEmptyArray(this.blockedResources) ? html`
+ ${translate("appspage.schange16")}
+ ` : ''}
+
+ ${this.renderRelayModeText()}
+
+
+
+ `
+ }
+
+ firstUpdated() {
+
+ this.changeTheme()
+ this.changeLanguage()
+ this.showapps()
+
+ setTimeout(() => {
+ this.displayTabContent('browse')
+ }, 0)
+
+ const getFollowedNames = async () => {
+ let followedNames = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`
+ })
+
+ this.followedNames = followedNames
+ setTimeout(getFollowedNames, 60000)
+ }
+
+ const getBlockedNames = async () => {
+ let blockedNames = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`
+ })
+ this.blockedNames = blockedNames
+ setTimeout(getBlockedNames, 60000)
+ }
+
+ const getRelayMode = async () => {
+ let relayMode = await parentEpml.request('apiCall', {
+ url: `/arbitrary/relaymode?apiKey=${this.getApiKey()}`
+ })
+
+ this.relayMode = relayMode;
+ setTimeout(getRelayMode, 600000)
+ }
+
+ window.addEventListener("contextmenu", (event) => {
+ event.preventDefault();
+ this._textMenu(event)
+ });
+
+ window.addEventListener("click", () => {
+ parentEpml.request('closeCopyTextMenu', null)
+ });
+
+ window.onkeyup = (e) => {
+ if (e.keyCode === 27) {
+ parentEpml.request('closeCopyTextMenu', null)
+ }
+ }
+
+ window.addEventListener('storage', () => {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+ const checkTheme = localStorage.getItem('qortalTheme')
+
+ use(checkLanguage)
+
+ if (checkTheme === 'dark') {
+ this.theme = 'dark'
+ } else {
+ this.theme = 'light'
+ }
+ document.querySelector('html').setAttribute('theme', this.theme)
+ })
+
+ let configLoaded = false
+
+ parentEpml.ready().then(() => {
+ parentEpml.subscribe('selected_address', async selectedAddress => {
+ this.selectedAddress = {}
+ selectedAddress = JSON.parse(selectedAddress)
+ if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
+ this.selectedAddress = selectedAddress
+ })
+ parentEpml.subscribe('config', c => {
+ if (!configLoaded) {
+ setTimeout(getFollowedNames, 1)
+ setTimeout(getBlockedNames, 1)
+ setTimeout(getRelayMode, 1)
+ setTimeout(this.getFollowedNamesResource, 1)
+ setTimeout(this.getBlockedNamesResource, 1)
+ setInterval(this.getArbitraryResources, 600000)
+ configLoaded = true
+ }
+ this.config = JSON.parse(c)
+ })
+ parentEpml.subscribe('copy_menu_switch', async value => {
+ if (value === 'false' && window.getSelection().toString().length !== 0) {
+ this.clearSelection()
+ }
+ })
+ })
+ parentEpml.imReady()
+ }
+
+ changeTheme() {
+ const checkTheme = localStorage.getItem('qortalTheme')
+ if (checkTheme === 'dark') {
+ this.theme = 'dark';
+ } else {
+ this.theme = 'light';
+ }
+ document.querySelector('html').setAttribute('theme', this.theme)
+ }
+
+ changeLanguage() {
+ const checkLanguage = localStorage.getItem('qortalLanguage')
+
+ if (checkLanguage === null || checkLanguage.length === 0) {
+ localStorage.setItem('qortalLanguage', 'us')
+ use('us')
+ } else {
+ use(checkLanguage)
+ }
+ }
+
+ renderCatText() {
+ return html`${translate("appspage.schange26")}`
+ }
+
+ displayTabContent(tab) {
+ const tabBrowseContent = this.shadowRoot.getElementById('tab-browse-content')
+ const tabFollowedContent = this.shadowRoot.getElementById('tab-followed-content')
+ const tabBlockedContent = this.shadowRoot.getElementById('tab-blocked-content')
+ tabBrowseContent.style.display = (tab === 'browse') ? 'block' : 'none'
+ tabFollowedContent.style.display = (tab === 'followed') ? 'block' : 'none'
+ tabBlockedContent.style.display = (tab === 'blocked') ? 'block' : 'none'
+ }
+
+ searchListener(e) {
+ if (e.key === 'Enter') {
+ this.doSearch(e)
+ }
+ }
+
+ async getResourcesGrid() {
+ this.resourcesGrid = this.shadowRoot.querySelector(`#resourcesGrid`)
+ this.pagesControl = this.shadowRoot.querySelector('#pages')
+ this.pages = undefined
+ }
+
+ getArbitraryResources = async () => {
+ const resources = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=false&includemetadata=false`
+ })
+ this.resources = resources
+ }
+
+ getFollowedNamesResource = async () => {
+ const followedRes = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&namefilter=followedNames`
+ })
+ this.followedResources = followedRes
+ }
+
+ getFollowedNamesRefresh = async () => {
+ let followedNames = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`
+ })
+ this.followedNames = followedNames
+ }
+
+ getBlockedNamesResource = async () => {
+ const blockedRes = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resources?service=${this.service}&default=true&limit=0&reverse=false&includestatus=true&includemetadata=true&namefilter=blockedNames`
+ })
+ this.blockedResources = blockedRes
+ }
+
+ getBlockedNamesRefresh = async () => {
+ let blockedNames = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`
+ })
+ this.blockedNames = blockedNames
+ }
+
+ async getData(offset) {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ let jsonOffsetUrl = `${nodeUrl}/arbitrary/resources?service=APP&default=true&limit=20&offset=${offset}&reverse=false&includestatus=true&includemetadata=true`
+
+ const jsonOffsetRes = await fetch(jsonOffsetUrl)
+ const jsonOffsetData = await jsonOffsetRes.json()
+
+ this.pageRes = jsonOffsetData
+ }
+
+ async updateItemsFromPage(page) {
+ if (page === undefined) {
+ return
+ }
+
+ if (!this.pages) {
+ this.pages = Array.apply(null, { length: Math.ceil(this.resources.length / 20) }).map((item, index) => {
+ return index + 1
+ })
+
+ let offset = 0
+
+ const prevBtn = document.createElement('button')
+ prevBtn.textContent = '<'
+ prevBtn.addEventListener('click', () => {
+ if (parseInt(this.pagesControl.querySelector('[selected]').textContent) > 1) {
+ offset = (parseInt(this.pagesControl.querySelector('[selected]').textContent) - 2) * 20
+ } else {
+ offset = 0
+ }
+ this.getData(offset);
+ const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent)
+ this.updateItemsFromPage(selectedPage - 1)
+ })
+ this.pagesControl.appendChild(prevBtn)
+
+ this.pages.forEach((pageNumber) => {
+ const pageBtn = document.createElement('button')
+ pageBtn.textContent = pageNumber
+ let offset = 0;
+ pageBtn.addEventListener('click', (e) => {
+ if (parseInt(e.target.textContent) > 1) {
+ offset = (parseInt(e.target.textContent) - 1) * 20
+ } else {
+ offset = 0
+ }
+ this.getData(offset);
+ this.updateItemsFromPage(parseInt(e.target.textContent))
+ })
+ if (pageNumber === page) {
+ pageBtn.setAttribute('selected', true)
+ }
+ this.pagesControl.appendChild(pageBtn)
+ })
+
+ const nextBtn = window.document.createElement('button')
+ nextBtn.textContent = '>'
+ nextBtn.addEventListener('click', () => {
+ if (parseInt(this.pagesControl.querySelector('[selected]').textContent) >= 1) {
+ offset = ((parseInt(this.pagesControl.querySelector('[selected]').textContent) + 1) * 20) - 20
+ } else {
+ offset = 0
+ }
+ this.getData(offset);
+ const selectedPage = parseInt(this.pagesControl.querySelector('[selected]').textContent)
+ this.updateItemsFromPage(selectedPage + 1)
+ })
+ this.pagesControl.appendChild(nextBtn)
+ }
+
+ const buttons = Array.from(this.pagesControl.children)
+ buttons.forEach((btn, index) => {
+ if (parseInt(btn.textContent) === page) {
+ btn.setAttribute('selected', true)
+ } else {
+ btn.removeAttribute('selected')
+ }
+ if (index === 0) {
+ if (page === 1) {
+ btn.setAttribute('disabled', '')
+ } else {
+ btn.removeAttribute('disabled')
+ }
+ }
+ if (index === buttons.length - 1) {
+ if (page === this.pages.length) {
+ btn.setAttribute('disabled', '')
+ } else {
+ btn.removeAttribute('disabled')
+ }
+ }
+ })
+ }
+
+ async showapps() {
+ await this.getData(0)
+ await this.getArbitraryResources()
+ await this.getResourcesGrid()
+ await this.updateItemsFromPage(1, true)
+ }
+
+ doSearch(e) {
+ this.searchResult()
+ }
+
+ async searchResult() {
+ let searchName = this.shadowRoot.getElementById('searchName').value
+ if (searchName.length === 0) {
+ let err1string = get("appspage.schange34")
+ parentEpml.request('showSnackBar', `${err1string}`)
+ } else {
+ let searchResources = await parentEpml.request('apiCall', {
+ url: `/arbitrary/resources/search?service=${this.service}&query=${searchName}&default=true&limit=5&reverse=false&includestatus=true&includemetadata=true`
+ })
+ if (this.isEmptyArray(searchResources)) {
+ let err2string = get("appspage.schange17")
+ parentEpml.request('showSnackBar', `${err2string}`)
+ } else {
+ this.searchResources = searchResources
+ }
+ }
+ }
+
+ renderAvatar(appObj) {
+ let name = appObj.name
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ const url = `${nodeUrl}/arbitrary/THUMBNAIL/${name}/qortal_avatar?async=true&apiKey=${this.getApiKey()}`
+ return html`
`
+ }
+
+ renderRelayModeText() {
+ if (this.relayMode === true) {
+ return html`${translate("appspage.schange18")} "relayModeEnabled": false ${translate("appspage.schange19")} settings.json
`
+ }
+ else if (this.relayMode === false) {
+ return html`${translate("appspage.schange20")} "relayModeEnabled": true ${translate("appspage.schange19")} settings.json
`
+ }
+ return html``
+ }
+
+ renderPublishButton() {
+ if (this.followedNames == null || !Array.isArray(this.followedNames)) {
+ return html``
+ }
+ return html` this.publishApp()}>add${translate("appspage.schange21")}`
+ }
+
+ renderDownload(downObj) {
+ if (downObj.status.description === "Published but not yet downloaded") {
+ return html` this.downloadApp(downObj)}>`
+ } else if (downObj.status.description === "Ready") {
+ return html``
+ } else {
+ return html``
+ }
+ }
+
+ async downloadApp(downObj) {
+ this.showChunks(downObj)
+ await parentEpml.request('apiCall', {
+ url: `/arbitrary/resource/status/APP/${downObj.name}?build=true&apiKey=${this.getApiKey()}`
+ })
+ this.showApps()
+ }
+
+ showChunks(downObj) {
+ }
+
+ renderOpenApp(openObj) {
+ if (openObj.status.description === "Published but not yet downloaded") {
+ return html``
+ } else if (openObj.status.description === "Ready") {
+ return html``
+ } else {
+ return html``
+ }
+ }
+
+ publishApp() {
+ window.location.href = `publish-app/index.html?service=${this.service}&identifier=${this.identifier}&uploadType=zip&category=app&showName=true&showService=false&showIdentifier=false&showMetadata=true`
+ }
+
+ async followName(appObj) {
+ let name = appObj.name
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ this.followedNames = this.followedNames.filter(item => item != name)
+ this.followedNames.push(name)
+ this.getFollowedNamesRefresh()
+ this.getFollowedNamesResource()
+ this.getArbitraryResources()
+ this.updateComplete.then(() => this.requestUpdate())
+ } else {
+ let err3string = get("appspage.schange22")
+ parentEpml.request('showSnackBar', `${err3string}`)
+ }
+ return ret
+ }
+
+ async unfollowName(appObj) {
+ let name = appObj.name
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ this.followedNames = this.followedNames.filter(item => item != name)
+ this.getFollowedNamesRefresh()
+ this.getFollowedNamesResource()
+ this.getArbitraryResources()
+ this.updateComplete.then(() => this.requestUpdate())
+ } else {
+ let err4string = get("appspage.schange23")
+ parentEpml.request('showSnackBar', `${err4string}`)
+ }
+ return ret
+ }
+
+ async blockName(appObj) {
+ let name = appObj.name
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ this.blockedNames = this.blockedNames.filter(item => item != name)
+ this.blockedNames.push(name)
+ this.getBlockedNamesRefresh()
+ this.getBlockedNamesResource()
+ this.getArbitraryResources()
+ this.updateComplete.then(() => this.requestUpdate())
+ } else {
+ let err5string = get("appspage.schange24")
+ parentEpml.request('showSnackBar', `${err5string}`)
+ }
+ return ret
+ }
+
+ async unblockName(appObj) {
+ let name = appObj.name
+ let items = [
+ name
+ ]
+ let namesJsonString = JSON.stringify({ "items": items })
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
+ method: 'DELETE',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: `${namesJsonString}`
+ })
+
+ if (ret === true) {
+ this.blockedNames = this.blockedNames.filter(item => item != name)
+ this.getBlockedNamesRefresh()
+ this.getBlockedNamesResource()
+ this.getArbitraryResources()
+ this.updateComplete.then(() => this.requestUpdate())
+ } else {
+ let err6string = get("appspage.schange25")
+ parentEpml.request('showSnackBar', `${err6string}`)
+ }
+ return ret
+ }
+
+ renderInfo(appObj) {
+ let name = appObj.name
+ let title = name
+ let description = ""
+ let categoryName = this.renderCatText()
+ let tags = "";
+ let sizeReadable = ""
+
+ if (appObj.metadata != null) {
+ title = appObj.metadata.title;
+ description = appObj.metadata.description;
+ categoryName = appObj.metadata.categoryName;
+ if (appObj.metadata.tags != null && appObj.metadata.tags.length > 0) {
+ tags = "Tags: " + appObj.metadata.tags.join(", ")
+ }
+ }
+
+ if (appObj.size != null) {
+ sizeReadable = this.bytesToSize(appObj.size);
+ }
+
+ return html`
+
+
+ ${description}
+
+
+ ${categoryName}
+ ${tags.length > 0 ? " | " : ""}
+ ${tags}
+ ${sizeReadable.length > 0 ? " | " : ""}
+ ${translate("appspage.schange27")}: ${sizeReadable}
+
+ `
+ }
+
+ renderPublishedBy(appObj) {
+ return html`${appObj.name}
+ ${translate("appspage.schange28")}: ${appObj.status.title}
`
+ }
+
+ renderSize(appObj) {
+ if (appObj.size === null) {
+ return html``
+ }
+ let sizeReadable = this.bytesToSize(appObj.size)
+ return html`${sizeReadable}`
+ }
+
+ renderFollowUnfollowButton(appObj) {
+ let name = appObj.name
+
+ if (this.followedNames == null || !Array.isArray(this.followedNames)) {
+ return html``
+ }
+
+ if (this.followedNames.indexOf(name) === -1) {
+ return html` this.followName(appObj)}>add_to_queue ${translate("appspage.schange29")}`
+ } else {
+ return html` this.unfollowName(appObj)}>remove_from_queue ${translate("appspage.schange30")}`
+ }
+ }
+
+ renderBlockUnblockButton(appObj) {
+ let name = appObj.name
+
+ if (this.blockedNames == null || !Array.isArray(this.blockedNames)) {
+ return html``
+ }
+
+ if (this.blockedNames.indexOf(name) === -1) {
+ return html` this.blockName(appObj)}>block ${translate("appspage.schange31")}`
+ } else {
+ return html` this.unblockName(appObj)}>radio_button_unchecked ${translate("appspage.schange32")}`
+ }
+ }
+
+ bytesToSize(bytes) {
+ var sizes = ['bytes', 'KB', 'MB', 'GB', 'TB']
+ if (bytes == 0) return '0 bytes'
+ var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)))
+ return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]
+ }
+
+ _textMenu(event) {
+ const getSelectedText = () => {
+ var text = "";
+ if (typeof window.getSelection != "undefined") {
+ text = window.getSelection().toString();
+ } else if (typeof this.shadowRoot.selection != "undefined" && this.shadowRoot.selection.type == "Text") {
+ text = this.shadowRoot.selection.createRange().text;
+ }
+ return text
+ }
+
+ const checkSelectedTextAndShowMenu = () => {
+ let selectedText = getSelectedText();
+ if (selectedText && typeof selectedText === 'string') {
+ let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
+ let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
+ parentEpml.request('openCopyTextMenu', textMenuObject)
+ }
+ }
+ checkSelectedTextAndShowMenu()
+ }
+
+ getApiKey() {
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ let apiKey = myNode.apiKey
+ return apiKey
+ }
+
+ clearSelection() {
+ window.getSelection().removeAllRanges()
+ window.parent.getSelection().removeAllRanges()
+ }
+
+ isEmptyArray(arr) {
+ if (!arr) { return true }
+ return arr.length === 0
+ }
+}
+
+window.customElements.define('q-apps', QApps)
From bc9549e612eef5e014d4f3342dbb55dc42e6a6f2 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:08:18 +0100
Subject: [PATCH 32/83] Update translations
---
qortal-ui-core/language/de.json | 41 ++++++++++++++++++++++
qortal-ui-core/language/es.json | 37 ++++++++++++++++++++
qortal-ui-core/language/fr.json | 37 ++++++++++++++++++++
qortal-ui-core/language/hindi.json | 37 ++++++++++++++++++++
qortal-ui-core/language/hr.json | 37 ++++++++++++++++++++
qortal-ui-core/language/hu.json | 37 ++++++++++++++++++++
qortal-ui-core/language/it.json | 37 ++++++++++++++++++++
qortal-ui-core/language/ko.json | 37 ++++++++++++++++++++
qortal-ui-core/language/no.json | 37 ++++++++++++++++++++
qortal-ui-core/language/pl.json | 37 ++++++++++++++++++++
qortal-ui-core/language/pt.json | 37 ++++++++++++++++++++
qortal-ui-core/language/ro.json | 37 ++++++++++++++++++++
qortal-ui-core/language/rs.json | 37 ++++++++++++++++++++
qortal-ui-core/language/ru.json | 37 ++++++++++++++++++++
qortal-ui-core/language/us.json | 55 +++++++++++++++++++++++-------
qortal-ui-core/language/zhc.json | 37 ++++++++++++++++++++
qortal-ui-core/language/zht.json | 37 ++++++++++++++++++++
17 files changed, 638 insertions(+), 13 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index 61b0cf2c..c062b590 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -482,6 +482,47 @@
"schange34": "Name darf nicht leer sein!",
"schange35": "Suchen"
},
+ "appspage": {
+ "schange1": "Q-Apps durchsuchen",
+ "schange2": "Gefolgte Q-Apps",
+ "schange3": "Blockierte Q-Apps",
+ "schange4": "Q-Apps suchen",
+ "schange5": "Avatar",
+ "schange6": "Details",
+ "schange7": "Herausgegeben von",
+ "schange8": "Aktionen",
+ "schange9": "Q-Apps",
+ "schange10": "Keine Q-Apps verfügbar",
+ "schange11": "Ihre gefolgten Q-Apps",
+ "schange12": "Gefolgte Q-Apps",
+ "schange13": "Du folgst keinen Q-Apps",
+ "schange14": "Ihre blockierten Q-Apps",
+ "schange15": "Blockierte Q-Apps",
+ "schange16": "Sie haben keine Q-Apps blockiert",
+ "schange17": "Name nicht gefunden!",
+ "schange18": "Relaismodus ist aktiviert. Das bedeutet, dass Ihr Knoten dabei hilft, verschlüsselte Daten durch das Netzwerk zu transportieren, wenn ein Peer dies anfordert. Sie können sich durch Einstellung abmelden",
+ "schange19": "in",
+ "schange20": "Relaismodus ist deaktiviert. Sie können ihn durch Einstellung aktivieren",
+ "schange21": "Q-App veröffentlichen",
+ "schange22": "Beim Versuch, diesem registrierten Namen zu folgen, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange23": "Beim Versuch, diesem registrierten Namen nicht mehr zu folgen, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange24": "Beim Blockieren dieses registrierten Namens ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange25": "Beim Versuch, diesen registrierten Namen zu entsperren, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange26": "Nicht kategorisiert",
+ "schange27": "Größe",
+ "schange28": "Status",
+ "schange29": "Folgen",
+ "schange30": "Entfolgen",
+ "schange31": "Sperren",
+ "schange32": "Entsperren",
+ "schange33": "Name zu suchen",
+ "schange34": "Name darf nicht leer sein!",
+ "schange35": "Suchen",
+ "schange36": "Herunterladen",
+ "schange37": "Heruntergeladen",
+ "schange38": "Update",
+ "schange39": "Öffnen"
+ },
"publishpage": {
"pchange1": "Veröffentlichen",
"pchange2": "Aktualisieren",
diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json
index c5ba54c0..753e89fe 100644
--- a/qortal-ui-core/language/es.json
+++ b/qortal-ui-core/language/es.json
@@ -482,6 +482,43 @@
"schange34": "El nombre no puede estar vacío!",
"schange35": "Buscar"
},
+ "appspage": {
+ "schange1": "Explorar Q-Apps",
+ "schange2": "Q-Apps seguidas",
+ "schange3": "Q-Apps bloqueadas",
+ "schange4": "Buscar Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detalles",
+ "schange7": "Publicado por",
+ "schange8": "Acciones",
+ "schange9": "Q-Apps",
+ "schange10": "No hay q-apps disponibles",
+ "schange11": "Tus Q-Apps seguidas",
+ "schange12": "Q-Apps seguidas",
+ "schange13": "No estás siguiendo ninguna q-apps",
+ "schange14": "Tus Q-Apps bloqueadas",
+ "schange15": "Q-Apps bloqueadas",
+ "schange16": "No has bloqueado ninguna q-apps",
+ "schange17": "¡No se encontró el nombre!",
+ "schange18": "El modo de retransmisión está habilitado. Esto significa que su nodo ayudará a transportar datos cifrados por la red cuando un par lo solicite. Puede optar por no hacerlo configurando",
+ "schange19": "en",
+ "schange20": "El modo de relé está deshabilitado. Puedes habilitarlo configurando",
+ "schange21": "Publicar Q-App",
+ "schange22": "Ha ocurrido un error al intentar seguir este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange23": "Ha ocurrido un error al intentar dejar de seguir este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange24": "Ha ocurrido un error al intentar bloquear este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange25": "Ha ocurrido un error al intentar desbloquear este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange26": "Sin categoría",
+ "schange27": "Tamaño",
+ "schange28": "Estado",
+ "schange29": "Seguir",
+ "schange30": "Dejar de Seguir",
+ "schange31": "Bloquear",
+ "schange32": "Desbloquear",
+ "schange33": "Nombre a buscar",
+ "schange34": "El nombre no puede estar vacío!",
+ "schange35": "Buscar"
+ },
"publishpage": {
"pchange1": "Publicar",
"pchange2": "Actualizar",
diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json
index 9a521674..a8c86d66 100644
--- a/qortal-ui-core/language/fr.json
+++ b/qortal-ui-core/language/fr.json
@@ -482,6 +482,43 @@
"schange34": "Le nom ne peut être vide!",
"schange35": "Recherche"
},
+ "appspage": {
+ "schange1": "Parcourir les Q-Apps",
+ "schange2": "Q-Apps suivies",
+ "schange3": "Applications Q bloquées",
+ "schange4": "Rechercher des Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Détails",
+ "schange7": "Publié par",
+ "schange8": "Actions",
+ "schange9": "Q-Apps",
+ "schange10": "Aucune q-apps disponible",
+ "schange11": "Vos Q-Apps suivies",
+ "schange12": "Q-Apps suivies",
+ "schange13": "Vous ne suivez aucune q-apps",
+ "schange14": "Vos Q-Apps bloquées",
+ "schange15": "Applications Q bloquées",
+ "schange16": "Vous n'avez bloqué aucune q-apps",
+ "schange17": "Nom introuvable !",
+ "schange18": "Le mode relais est activé. Cela signifie que votre nœud aidera à transporter des données cryptées sur le réseau lorsqu'un pair le demande. Vous pouvez vous désinscrire en définissant",
+ "schange19": "dans",
+ "schange20": "Le mode relais est désactivé. Vous pouvez l'activer en définissant",
+ "schange21": "Publier Q-App",
+ "schange22": "Une erreur s’est produite lors de la tentative de suivi de ce nom enregistré. Veuillez réessayer!",
+ "schange23": "Une erreur s’est produite lors de la tentative de désabonnement de ce nom enregistré. Veuillez réessayer!",
+ "schange24": "Une erreur s’est produite lors de la tentative de blocage de ce nom enregistré. Veuillez réessayer!",
+ "schange25": "Une erreur s’est produite lors de la tentative de déverrouillage de ce nom enregistré. Veuillez réessayer!",
+ "schange26": "Non classé",
+ "schange27": "Taille",
+ "schange28": "Etat",
+ "schange29": "Suivre",
+ "schange30": "Ne plus suivre",
+ "schange31": "Bloquer",
+ "schange32": "Débloquer",
+ "schange33": "Nom à chercher",
+ "schange34": "Le nom ne peut être vide!",
+ "schange35": "Recherche"
+ },
"publishpage": {
"pchange1": "Publier",
"pchange2": "Mettre à jour",
diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json
index 428844da..83707fbc 100644
--- a/qortal-ui-core/language/hindi.json
+++ b/qortal-ui-core/language/hindi.json
@@ -483,6 +483,43 @@
"schange34": "नाम खाली नहीं हो सकता!",
"schange35": "खोज"
},
+ "appspage": {
+ "schange1": "क्यू-एप्स ब्राउज़ करें",
+ "schange2": "क्यू-ऐप्स का अनुसरण किया",
+ "schange3": "अवरुद्ध Q-Apps",
+ "schange4": "क्यू-ऐप्स खोजें",
+ "schange5": "अवतार",
+ "schange6": "विवरण",
+ "schange7": "द्वारा प्रकाशित",
+ "schange8": "कार्रवाई",
+ "schange9": "क्यू-ऐप्स",
+ "schange10": "कोई q-एप्लिकेशन उपलब्ध नहीं",
+ "schange11": "आपके द्वारा फ़ॉलो किए गए Q-Apps",
+ "schange12": "क्यू-ऐप्स का अनुसरण किया",
+ "schange13": "आप किसी भी क्यू-एप्स को फॉलो नहीं कर रहे हैं",
+ "schange14": "आपका अवरोधित क्यू-ऐप्स",
+ "schange15": "अवरुद्ध Q-Apps",
+ "schange16": "आपने किसी भी क्यू-एप्स को अवरूद्ध नहीं किया है",
+ "schange17": "नाम नहीं मिला!",
+ "schange18": "रिले मोड सक्षम है। इसका मतलब है कि आपका नोड नेटवर्क के चारों ओर एन्क्रिप्टेड डेटा को ट्रांसपोर्ट करने में मदद करेगा जब कोई सहकर्मी इसका अनुरोध करता है। आप सेटिंग करके ऑप्ट आउट कर सकते हैं",
+ "schange19": "में",
+ "schange20": "रिले मोड अक्षम है। आप सेटिंग करके इसे सक्रिय कर सकते हैं",
+ "schange21": "क्यू-ऐप प्रकाशित करें",
+ "schange22": "इस पंजीकृत नाम का अनुसरण करने की कोशिश करते समय त्रुटि हुई। कृपया फिर से प्रयास करें!",
+ "schange23": "इस पंजीकृत नाम को अनफ़ॉलो करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange24": "इस पंजीकृत नाम को ब्लॉक करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange25": "इस पंजीकृत नाम को अनवरोधित करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange26": "अवर्गीकृत",
+ "schange27": "आकार",
+ "schange28": "स्थिति",
+ "schange29": "अनुसरण",
+ "schange30": "अनफ़ॉलो करें",
+ "schange31": "ब्लॉक",
+ "schange32": "अनब्लॉक",
+ "schange33": "खोजने के लिए नाम",
+ "schange34": "नाम खाली नहीं हो सकता!",
+ "schange35": "खोज"
+ },
"publishpage": {
"pchange1": "प्रकाशित",
"pchange2": "अपडेट करना",
diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json
index a8f29388..169e6aaf 100644
--- a/qortal-ui-core/language/hr.json
+++ b/qortal-ui-core/language/hr.json
@@ -482,6 +482,43 @@
"schange34": "Ime nemože biti prazno!",
"schange35": "Traži"
},
+ "appspage": {
+ "schange1": "Pregledaj Q-Apps",
+ "schange2": "Pratite Q-Apps",
+ "schange3": "Blokirane Q-Apps",
+ "schange4": "Traži Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detalji",
+ "schange7": "Objavio",
+ "schange8": "Akcije",
+ "schange9": "Q-Apps",
+ "schange10": "Nema dostupnih q-apps",
+ "schange11": "Q-Apps koje pratite",
+ "schange12": "Pratite Q-Apps",
+ "schange13": "Ne pratite nijednu q-apps",
+ "schange14": "Vaše blokirane Q-Apps",
+ "schange15": "Blokirane Q-Apps",
+ "schange16": "Niste blokirali nijednu q-apps",
+ "schange17": "Ime nije pronađeno!",
+ "schange18": "Relejni način rada je omogućen. To znači da će vaš čvor pomoći u prijenosu šifriranih podataka po mreži kada to ravnopravni uređaj zatraži. Možete se isključiti postavljanjem",
+ "schange19": "u",
+ "schange20": "Relejni način rada je onemogućen. Možete ga omogućiti postavljanjem",
+ "schange21": "Objavi Q-App",
+ "schange22": "Došlo je do pogreške prilikom pokušaja da pratite ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange23": "Došlo je do pogreške prilikom pokušaja da nepratite ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange24": "Došlo je do pogreške prilikom pokušaja da blokirate ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange25": "Došlo je do pogreške prilikom pokušaja da odblokirate ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange26": "Nekategorizirano",
+ "schange27": "Veličina",
+ "schange28": "Status",
+ "schange29": "Prati",
+ "schange30": "Neprati",
+ "schange31": "Blokiraj",
+ "schange32": "Odblokiraj",
+ "schange33": "Ime za tražiti",
+ "schange34": "Ime nemože biti prazno!",
+ "schange35": "Traži"
+ },
"publishpage": {
"pchange1": "Objavi",
"pchange2": "Ažuriraj",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index 01c959ba..d7f00d01 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -482,6 +482,43 @@
"schange34": "A név nem lehet üres!",
"schange35": "Keresés"
},
+ "appspage": {
+ "schange1": "Tallózás a Q-Apps között",
+ "schange2": "Követett Q-Apps",
+ "schange3": "Letiltott Q-Apps",
+ "schange4": "Keresés a Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Részletek",
+ "schange7": "Kiadó",
+ "schange8": "Műveletek",
+ "schange9": "Q-Apps",
+ "schange10": "Nincs elérhető q-apps",
+ "schange11": "Az Ön által követett Q-Apps",
+ "schange12": "Követett Q-alkalmazások",
+ "schange13": "Nem követsz egyetlen q-apps sem",
+ "schange14": "Az Ön letiltott Q-Apps",
+ "schange15": "Letiltott Q-Apps",
+ "schange16": "Nem tiltott le egyetlen q-apps sem",
+ "schange17": "A név nem található!",
+ "schange18": "A továbbítási mód engedélyezve van. Ez azt jelenti, hogy a csomópont segít a titkosított adatok továbbításában a hálózaton, amikor egy társ kéri. A beállítással letilthatja",
+ "schange19": "in",
+ "schange20": "Relé mód le van tiltva. Beállítással engedélyezheti",
+ "schange21": "Q-App közzététele",
+ "schange22": "Hiba történt a regisztrált név követésekor. Próbálkozzon újra!",
+ "schange23": "Hiba történt, amikor megpróbálta megszüntetni a regisztrált név követését Próbálkozzon újra!",
+ "schange24": "Hiba történt a regisztrált név blokkolása közben.. Próbálkozzon újra!",
+ "schange25": "Hiba történt a regisztrált név blokkolásának feloldásakor. Próbálkozzon újra!",
+ "schange26": "Nem Kategorizált",
+ "schange27": "Méret",
+ "schange28": "Állapot",
+ "schange29": "Követ",
+ "schange30": "Követés megszüntetése",
+ "schange31": "Blokk",
+ "schange32": "Felszabadít",
+ "schange33": "Keresendő Név",
+ "schange34": "A név nem lehet üres!",
+ "schange35": "Keresés"
+ },
"publishpage": {
"pchange1": "Közzétesz",
"pchange2": "Frissítés",
diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json
index 8bae51b4..39932bbf 100644
--- a/qortal-ui-core/language/it.json
+++ b/qortal-ui-core/language/it.json
@@ -482,6 +482,43 @@
"schange34": "Il nome non può essere vuoto!",
"schange35": "Cerca"
},
+ "appspage": {
+ "schange1": "Sfoglia Q-Apps",
+ "schange2": "Q-Apps seguite",
+ "schange3": "Q-Apps bloccate",
+ "schange4": "Cerca Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Dettagli",
+ "schange7": "Pubblicato da",
+ "schange8": "Azioni",
+ "schange9": "Q-Apps",
+ "schange10": "Nessuna q-apps disponibile",
+ "schange11": "Le tue Q-Apps seguite",
+ "schange12": "Q-Apps seguite",
+ "schange13": "Non stai seguendo nessuna q-apps",
+ "schange14": "Le tue Q-Apps bloccate",
+ "schange15": "Q-App bloccate",
+ "schange16": "Non hai bloccato nessuna q-apps",
+ "schange17": "Nome non trovato!",
+ "schange18": "La modalità di inoltro è abilitata. Ciò significa che il tuo nodo aiuterà a trasportare i dati crittografati sulla rete quando un peer lo richiede. Puoi disattivarli impostando",
+ "schange19": "dentro",
+ "schange20": "La modalità inoltro è disabilitata. Puoi abilitarla impostando",
+ "schange21": "Pubblica Q-App",
+ "schange22": "Si è verificato un errore durante il tentativo di seguire questo nome registrato. Per favore, riprova!",
+ "schange23": "Si è verificato un errore durante il tentativo di smettere di seguire questo nome registrato. Per favore, riprova!",
+ "schange24": "Si è verificato un errore durante il tentativo di bloccare questo nome registrato. Per favore, riprova!",
+ "schange25": "Si è verificato un errore durante il tentativo di sbloccare questo nome registrato. Per favore, riprova!",
+ "schange26": "Senza categoria",
+ "schange27": "Taglia",
+ "schange28": "Stato",
+ "schange29": "Segui",
+ "schange30": "Non seguire più",
+ "schange31": "Blocca",
+ "schange32": "Sblocca",
+ "schange33": "Nome da cercare",
+ "schange34": "Il nome non può essere vuoto!",
+ "schange35": "Cerca"
+ },
"publishpage": {
"pchange1": "Pubblica",
"pchange2": "Aggiorna",
diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json
index 107f722c..76a18c5c 100644
--- a/qortal-ui-core/language/ko.json
+++ b/qortal-ui-core/language/ko.json
@@ -482,6 +482,43 @@
"schange34": "이름은 비워 둘 수 없습니다!",
"schange35": "검색"
},
+ "appspage": {
+ "schange1": "Q-Apps 찾아보기",
+ "schange2": "팔로우한 Q-Apps",
+ "schange3": "차단된 Q-Apps",
+ "schange4": "Q-Apps 검색",
+ "schange5": "아바타",
+ "schange6": "자세히",
+ "schange7": "출판사",
+ "schange8": "작업",
+ "schange9": "Q-Apps",
+ "schange10": "사용할 수 있는 q-apps 없음",
+ "schange11": "내가 팔로우한 Q-Apps",
+ "schange12": "팔로우한 Q-Apps",
+ "schange13": "팔로우 중인 q-apps 없습니다",
+ "schange14": "차단된 Q-Apps",
+ "schange15": "차단된 Q-Apps",
+ "schange16": "Q-Apps 차단하지 않았습니다",
+ "schange17": "이름을 찾을 수 없습니다!",
+ "schange18": "릴레이 모드가 활성화되었습니다. 이는 피어가 요청할 때 노드가 네트워크에서 암호화된 데이터를 전송하는 데 도움이 된다는 것을 의미합니다. 설정을 통해 옵트아웃할 수 있습니다.",
+ "schange19": "에서",
+ "schange20": "릴레이 모드가 비활성화되었습니다. 설정을 통해 활성화할 수 있습니다.",
+ "schange21": "Q-App 게시",
+ "schange22": "이 등록된 이름을 따르는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange23": "이 등록된 이름의 팔로우를 해제하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange24": "이 등록된 이름을 차단하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange25": "이 등록된 이름의 차단을 해제하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange26": "분류되지 않음",
+ "schange27": "크기",
+ "schange28": "상태",
+ "schange29": "팔로우",
+ "schange30": "언팔로우",
+ "schange31": "차단",
+ "schange32": "차단 해제",
+ "schange33": "검색할 이름",
+ "schange34": "이름은 비워 둘 수 없습니다!",
+ "schange35": "검색"
+ },
"publishpage": {
"pchange1": "발표",
"pchange2": "업데이트",
diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json
index 268a91fa..0a875921 100644
--- a/qortal-ui-core/language/no.json
+++ b/qortal-ui-core/language/no.json
@@ -482,6 +482,43 @@
"schange34": "Navn kan ikke være tomt!",
"schange35": "Søk"
},
+ "appspage": {
+ "schange1": "Bla gjennom Q-Apps",
+ "schange2": "Følgte Q-Apps",
+ "schange3": "Blokkerte Q-Apps",
+ "schange4": "Søk i Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detaljer",
+ "schange7": "Publisert av",
+ "schange8": "Handlinger",
+ "schange9": "Q-Apps",
+ "schange10": "Ingen q-apps tilgjengelig",
+ "schange11": "Dine fulgte Q-Apps",
+ "schange12": "Følgte Q-Apps",
+ "schange13": "Du følger ingen q-apps",
+ "schange14": "Dine blokkerte Q-Apps",
+ "schange15": "Blokkerte Q-apper",
+ "schange16": "Du har ikke blokkert noen q-apps",
+ "schange17": "Navnet ble ikke funnet!",
+ "schange18": "Relémodus er aktivert. Dette betyr at noden din vil hjelpe til med å transportere krypterte data rundt i nettverket når en peer ber om det. Du kan velge bort ved å stille inn",
+ "schange19": "i",
+ "schange20": "Relémodus er deaktivert. Du kan aktivere den ved å stille inn",
+ "schange21": "Publiser Q-App",
+ "schange22": "Det oppstod en feil ved forsøk på å følge dette registrerte navnet. Prøv på nytt!",
+ "schange23": "Det oppstod en feil ved forsøk på å avfølge dette registrerte navnet. Prøv på nytt!",
+ "schange24": "Det oppstod en feil ved forsøk på å blokkere dette registrerte navnet. Prøv på nytt!",
+ "schange25": "Det oppstod en feil ved forsøk på å oppheve blokkeringen av dette registrerte navnet. Prøv på nytt!",
+ "schange26": "Ukategorisert",
+ "schange27": "Størrelse",
+ "schange28": "Status",
+ "schange29": "Følg",
+ "schange30": "Avfølg",
+ "schange31": "Blokker",
+ "schange32": "Opphev blokkering",
+ "schange33": "Navn å søke på",
+ "schange34": "Navn kan ikke være tomt!",
+ "schange35": "Søk"
+ },
"publishpage": {
"pchange1": "Publiser",
"pchange2": "Oppdater",
diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json
index 3f0fbafa..9c6603cc 100644
--- a/qortal-ui-core/language/pl.json
+++ b/qortal-ui-core/language/pl.json
@@ -482,6 +482,43 @@
"schange34": "Nazwa nie może być pusta!",
"schange35": "Szukaj"
},
+ "appspage": {
+ "schange1": "Przeglądaj Q-Apps",
+ "schange2": "Obserwowane Q-Apps",
+ "schange3": "Zablokowane Q-Apps",
+ "schange4": "Wyszukaj Q-Apps",
+ "schange5": "Awatar",
+ "schange6": "Szczegóły",
+ "schange7": "Opublikowane przez",
+ "schange8": "Akcje",
+ "schange9": "Q-Apps",
+ "schange10": "Brak dostępnych q-apps",
+ "schange11": "Twoje obserwowane Q-Apps",
+ "schange12": "Obserwowane Q-Apps",
+ "schange13": "Nie obserwujesz żadnych q-apps",
+ "schange14": "Twoje zablokowane Q-Apps",
+ "schange15": "Zablokowane Q-Apps",
+ "schange16": "Nie zablokowałeś żadnych q-apps",
+ "schange17": "Nie znaleziono nazwy!",
+ "schange18": "Tryb przekazywania jest włączony. Oznacza to, że twój węzeł pomoże w transporcie zaszyfrowanych danych w sieci, gdy zażąda tego peer. Możesz zrezygnować, ustawiając",
+ "schange19": "w",
+ "schange20": "Tryb przekaźnika jest wyłączony. Możesz go włączyć, ustawiając",
+ "schange21": "Opublikuj Q-App",
+ "schange22": "Wystąpił błąd podczas próby śledzenia tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange23": "Wystąpił błąd podczas próby zaprzestania obserwowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange24": "Wystąpił błąd podczas próby zablokowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange25": "Wystąpił błąd podczas próby odblokowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange26": "Bez kategorii",
+ "schange27": "Rozmiar",
+ "schange28": "Status",
+ "schange29": "Obserwuj",
+ "schange30": "Przestań obserwować",
+ "schange31": "Zablokuj",
+ "schange32": "Odblokuj",
+ "schange33": "Nazwa do wyszukania",
+ "schange34": "Nazwa nie może być pusta!",
+ "schange35": "Szukaj"
+ },
"publishpage": {
"pchange1": "Opublikuj",
"pchange2": "Aktualizuj",
diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json
index 2cb47799..65d54199 100644
--- a/qortal-ui-core/language/pt.json
+++ b/qortal-ui-core/language/pt.json
@@ -482,6 +482,43 @@
"schange34": "Nome não pode estar vazio!",
"schange35": "Pesquisar"
},
+ "appspage": {
+ "schange1": "Navegar Q-Apps",
+ "schange2": "Q-Apps seguidos",
+ "schange3": "Q-Apps bloqueados",
+ "schange4": "Pesquisar Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detalhes",
+ "schange7": "Publicado por",
+ "schange8": "Ações",
+ "schange9": "Q-Apps",
+ "schange10": "Nenhum q-apps disponível",
+ "schange11": "Seus Q-Apps seguidos",
+ "schange12": "Q-Apps seguidos",
+ "schange13": "Você não está seguindo nenhum q-apps",
+ "schange14": "Seus Q-Apps bloqueados",
+ "schange15": "Q-Apps bloqueados",
+ "schange16": "Você não bloqueou nenhum q-apps",
+ "schange17": "Nome não encontrado!",
+ "schange18": "O modo de retransmissão está ativado. Isso significa que seu nó ajudará a transportar dados criptografados pela rede quando um par solicitar. Você pode optar por não configurar",
+ "schange19": "em",
+ "schange20": "O modo relé está desativado. Você pode ativá-lo configurando",
+ "schange21": "Publicar Q-App",
+ "schange22": "Ocorreu erro ao tentar seguir esse nome registrado. Por favor, tente de novo!",
+ "schange23": "Ocorreu erro ao tentar desseguir esse nome registrado. Por favor, tente de novo!",
+ "schange24": "Ocorreu erro ao tentar bloquear esse nome registrado. Por favor, tente de novo!",
+ "schange25": "O erro ocorreu ao tentar desbloquear esse nome registrado. Por favor, tente de novo!",
+ "schange26": "Não categorizado",
+ "schange27": "Tamanho",
+ "schange28": "Status",
+ "schange29": "Seguir",
+ "schange30": "Desseguir",
+ "schange31": "Bloquear",
+ "schange32": "Desbloquear",
+ "schange33": "Nome para pesquisar",
+ "schange34": "Nome não pode estar vazio!",
+ "schange35": "Pesquisar"
+ },
"publishpage": {
"pchange1": "Publicar",
"pchange2": "Atualizar",
diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json
index b8e8cb4e..f045c3ab 100644
--- a/qortal-ui-core/language/ro.json
+++ b/qortal-ui-core/language/ro.json
@@ -482,6 +482,43 @@
"schange34": "Numele nu poate fi gol!",
"schange35": "Cauta"
},
+ "appspage": {
+ "schange1": "Răsfoiți Q-Apps",
+ "schange2": "Q-Apps urmărite",
+ "schange3": "Q-Apps blocate",
+ "schange4": "Căutați Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detalii",
+ "schange7": "Publicat de",
+ "schange8": "Acțiuni",
+ "schange9": "Q-Apps",
+ "schange10": "Nu există q-apps disponibile",
+ "schange11": "Q-Apps urmărite",
+ "schange12": "Q-Apps urmărite",
+ "schange13": "Nu urmăriți nicio q-apps",
+ "schange14": "Q-Apps dvs. blocate",
+ "schange15": "Q-Apps blocate",
+ "schange16": "Nu ați blocat nicio q-apps",
+ "schange17": "Numele nu a fost găsit!",
+ "schange18": "Modul de retransmisie este activat. Aceasta înseamnă că nodul dvs. va ajuta la transportul datelor criptate în rețea atunci când un peer o solicită. Puteți renunța prin setare",
+ "schange19": "în",
+ "schange20": "Modul releu este dezactivat. Îl puteți activa setând",
+ "schange21": "Publică Q-App",
+ "schange22": "A aparut o eroare atunci cand ati incercat sa urmariti acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange23": "A aparut o eroare atunci cand ati incercat sa dezactivati urmarirea acestui nume inregistrat. Va rugam sa incercati din nou!",
+ "schange24": "A aparut o eroare in timpul incercarii de a bloca acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange25": "A aparut o eroare atunci cand ati incercat sa deblocati acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange26": "Neclasificat",
+ "schange27": "Dimensiune",
+ "schange28": "Stare",
+ "schange29": "Urmareste",
+ "schange30": "Opreste urmarirea",
+ "schange31": "Blocheaza",
+ "schange32": "Deblocheaza",
+ "schange33": "Numele cautat",
+ "schange34": "Numele nu poate fi gol!",
+ "schange35": "Cauta"
+ },
"publishpage": {
"pchange1": "Publica",
"pchange2": "Actualizeaza",
diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json
index 7586a1a3..272ea7cd 100644
--- a/qortal-ui-core/language/rs.json
+++ b/qortal-ui-core/language/rs.json
@@ -482,6 +482,43 @@
"schange34": "Ime ne može biti prazno!",
"schange35": "Pretraga"
},
+ "appspage": {
+ "schange1": "Pregledaj Q-Apps",
+ "schange2": "Praćene Q-Apps",
+ "schange3": "Blokirane Q-Apps",
+ "schange4": "Pretraži Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Detalji",
+ "schange7": "Objavio",
+ "schange8": "Radnje",
+ "schange9": "Q-Apps",
+ "schange10": "Nema dostupnih q-apps",
+ "schange11": "Vaše praćene Q-Apps",
+ "schange12": "Praćene Q-Apps",
+ "schange13": "Ne pratite nijednu q-apps",
+ "schange14": "Vaše blokirane Q-Apps",
+ "schange15": "Blokirane Q-Apps",
+ "schange16": "Niste blokirali nijednu q-apps",
+ "schange17": "Ime nije pronađeno!",
+ "schange18": "Relejni režim je omogućen. To znači da će vaš čvor pomoći da se šifrovane podatke transportuju po mreži kada kolega to zatraži. Možete isključiti podešavanjem",
+ "schange19": "u",
+ "schange20": "Relejni režim je onemogućen. Možete ga omogućiti podešavanjem",
+ "schange21": "Objavi Q-App",
+ "schange22": "Desila se greška pri pokušaju praćenja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange23": "Desila se greška pri pokušaju otpraćivanja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange24": "Desila se greška pri pokušaju blokiranja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange25": "Desila se greška pri pokušaju odblokiranja ovog rebgistrovanog imena. Molim pokušajte ponovo!",
+ "schange26": "Nekategorizovano",
+ "schange27": "Veličina",
+ "schange28": "Status",
+ "schange29": "Pratite",
+ "schange30": "Otpratite",
+ "schange31": "Blokirajte",
+ "schange32": "Odblokirajte",
+ "schange33": "Ime za pretragu",
+ "schange34": "Ime ne može biti prazno!",
+ "schange35": "Pretraga"
+ },
"publishpage": {
"pchange1": "Objavite",
"pchange2": "Ažurirajte",
diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json
index 24471b43..bfc71cdd 100644
--- a/qortal-ui-core/language/ru.json
+++ b/qortal-ui-core/language/ru.json
@@ -482,6 +482,43 @@
"schange34": "Имя не может быть пустым!",
"schange35": "Поиск"
},
+ "appspage": {
+ "schange1": "Просмотреть Q-Apps",
+ "schange2": "Подписан на Q-Apps",
+ "schange3": "Заблокированные Q-Apps",
+ "schange4": "Поиск Q-Apps",
+ "schange5": "Аватар",
+ "schange6": "Подробнее",
+ "schange7": "Опубликовано",
+ "schange8": "Действия",
+ "schange9": "Q-Apps",
+ "schange10": "Нет доступных q-apps",
+ "schange11": "Q-Apps, на которые вы подписаны",
+ "schange12": "Подписан на Q-Apps",
+ "schange13": "Вы не подписаны ни на одно q-apps",
+ "schange14": "Ваши заблокированные Q-Apps",
+ "schange15": "Заблокированные Q-Apps",
+ "schange16": "Вы не заблокировали ни одно q-apps",
+ "schange17": "Имя не найдено!",
+ "schange18": "Режим ретрансляции включен. Это означает, что ваш узел будет помогать передавать зашифрованные данные по сети, когда их запрашивает одноранговый узел. Вы можете отказаться, настроив",
+ "schange19": "в",
+ "schange20": "Режим реле отключен. Вы можете включить его в настройках",
+ "schange21": "Опубликовать Q-App",
+ "schange22": "Произошла ошибка при попытке подписаться на это зарегистрированное имя. Повторите попытку!",
+ "schange23": "Произошла ошибка при попытке отписаться от этого зарегистрированного имени. Повторите попытку!",
+ "schange24": "Произошла ошибка при попытке заблокировать это зарегистрированное имя. Повторите попытку!",
+ "schange25": "Произошла ошибка при попытке разблокировать это зарегистрированное имя. Пожалуйста, попробуйте еще раз!",
+ "schange26": "Без категории",
+ "schange27": "Размер",
+ "schange28": "Статус",
+ "schange29": "Подписаться",
+ "schange30": "Отписаться",
+ "schange31": "Заблокировать",
+ "schange32": "Разблокировать",
+ "schange33": "Имя для поиска",
+ "schange34": "Имя не может быть пустым!",
+ "schange35": "Поиск"
+ },
"publishpage": {
"pchange1": "Опубликовать",
"pchange2": "Обновить",
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 11e92128..10e6f914 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -482,6 +482,47 @@
"schange34": "Name can not be empty!",
"schange35": "Search"
},
+ "appspage": {
+ "schange1": "Browse Q-Apps",
+ "schange2": "Followed Q-Apps",
+ "schange3": "Blocked Q-Apps",
+ "schange4": "Search Q-Apps",
+ "schange5": "Avatar",
+ "schange6": "Details",
+ "schange7": "Published by",
+ "schange8": "Actions",
+ "schange9": "Q-Apps",
+ "schange10": "No q-apps available",
+ "schange11": "Your Followed Q-Apps",
+ "schange12": "Followed Q-Apps",
+ "schange13": "You aren't following any q-apps",
+ "schange14": "Your Blocked Q-Apps",
+ "schange15": "Blocked Q-Apps",
+ "schange16": "You have not blocked any q-apps",
+ "schange17": "Name Not Found!",
+ "schange18": "Relay mode is enabled. This means that your node will help to transport encrypted data around the network when a peer requests it. You can opt out by setting",
+ "schange19": "in",
+ "schange20": "Relay mode is disabled. You can enable it by setting",
+ "schange21": "Publish Q-App",
+ "schange22": "Error occurred when trying to follow this registered name. Please try again!",
+ "schange23": "Error occurred when trying to unfollow this registered name. Please try again!",
+ "schange24": "Error occurred when trying to block this registered name. Please try again!",
+ "schange25": "Error occurred when trying to unblock this registered name. Please try again!",
+ "schange26": "Uncategorized",
+ "schange27": "Size",
+ "schange28": "Status",
+ "schange29": "Follow",
+ "schange30": "Unfollow",
+ "schange31": "Block",
+ "schange32": "Unblock",
+ "schange33": "Name to search",
+ "schange34": "Name can not be empty!",
+ "schange35": "Search",
+ "schange36": "Download",
+ "schange37": "Downloaded",
+ "schange38": "Update",
+ "schange39": "Open"
+ },
"publishpage": {
"pchange1": "Publish",
"pchange2": "Update",
@@ -525,19 +566,7 @@
"bchange13": "Error occurred when trying to block this registered name. Please try again!",
"bchange14": "Error occurred when trying to unblock this registered name. Please try again!",
"bchange15": "Can't delete data from followed names. Please unfollow first.",
- "bchange16": "Error occurred when trying to delete this resource. Please try again!",
- "bchange17": "User declined to share account details",
- "bchange18": "has requested authentication. Would you like to authenticate?",
- "bchange19": "Do you give this application permission to publish to QDN?",
- "bchange20": "Do you give this application permission to get your wallet balance?",
- "bchange21": "Fetch Wallet Failed. Please try again!",
- "bchange22": "Do you give this application permission to send a chat message?",
- "bchange23": "Message Sent!",
- "bchange24": "This shares your QORT address and allows your account to interact with the",
- "bchange25": "No sensitive data is shared.",
- "bchange26": "Always authenticate automatically",
- "bchange27": "Reject",
- "bchange28": "Accept"
+ "bchange16": "Error occurred when trying to delete this resource. Please try again!"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json
index 2900e0d2..a603e629 100644
--- a/qortal-ui-core/language/zhc.json
+++ b/qortal-ui-core/language/zhc.json
@@ -482,6 +482,43 @@
"schange34": "名称不能为空!",
"schange35": "搜寻"
},
+ "appspage": {
+ "schange1": "浏览 Q-Apps",
+ "schange2": "关注 Q-Apps",
+ "schange3": "被阻止的 Q-Apps",
+ "schange4": "搜索 Q-Apps",
+ "schange5": "头像",
+ "schange6": "详情",
+ "schange7": "发布者",
+ "schange8": "动作",
+ "schange9": "Q-Apps",
+ "schange10": "没有可用的 q-apps",
+ "schange11": "您关注的 Q-Apps",
+ "schange12": "关注 Q-Apps",
+ "schange13": "您没有关注任何 q-apps",
+ "schange14": "你被屏蔽的 Q-Apps",
+ "schange15": "被阻止的 Q-Apps",
+ "schange16": "你没有屏蔽任何 q-apps",
+ "schange17": "找不到名字!",
+ "schange18": "中继模式已启用。这意味着您的节点将在对等点请求时帮助在网络中传输加密数据。您可以通过设置选择退出",
+ "schange19": "在",
+ "schange20": "中继模式已禁用。您可以通过设置启用它",
+ "schange21": "发布Q-App",
+ "schange22": "尝试关注此注册名称时发生错误。 请再试一次!",
+ "schange23": "尝试取消关注此注册名称时发生错误。 请再试一次!",
+ "schange24": "尝试封锁此注册名称时发生错误。 请再试一次!",
+ "schange25": "尝试解封此注册名称时发生错误。 请再试一次!",
+ "schange26": "未分类",
+ "schange27": "大小",
+ "schange28": "状态",
+ "schange29": "关注",
+ "schange30": "取消关注",
+ "schange31": "封锁",
+ "schange32": "解除封锁",
+ "schange33": "输入需要搜寻的名称",
+ "schange34": "名称不能为空!",
+ "schange35": "搜寻"
+ },
"publishpage": {
"pchange1": "发布",
"pchange2": "更新",
diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json
index 775245d1..8a4145ec 100644
--- a/qortal-ui-core/language/zht.json
+++ b/qortal-ui-core/language/zht.json
@@ -482,6 +482,43 @@
"schange34": "名稱不能為空!",
"schange35": "搜尋"
},
+ "appspage": {
+ "schange1": "瀏覽 Q-Apps",
+ "schange2": "關注 Q-Apps",
+ "schange3": "被阻止的 Q-Apps",
+ "schange4": "搜索 Q-Apps",
+ "schange5": "頭像",
+ "schange6": "詳情",
+ "schange7": "發布者",
+ "schange8": "動作",
+ "schange9": "Q-Apps",
+ "schange10": "沒有可用的 q-apps",
+ "schange11": "您關注的 Q-Apps",
+ "schange12": "關注 Q-Apps",
+ "schange13": "您沒有關注任何 q-apps",
+ "schange14": "你被屏蔽的 Q-Apps",
+ "schange15": "被阻止的 Q-Apps",
+ "schange16": "你沒有屏蔽任何 q-apps",
+ "schange17": "找不到名字!",
+ "schange18": "中繼模式已啟用。這意味著您的節點將在對等點請求時幫助在網絡中傳輸加密數據。您可以通過設置選擇退出",
+ "schange19": "在",
+ "schange20": "中繼模式已禁用。您可以通過設置啟用它",
+ "schange21": "發布Q-App",
+ "schange22": "嘗試關注此註冊名稱時發生錯誤。 請再試一次!",
+ "schange23": "嘗試取消關注此註冊名稱時發生錯誤。 請再試一次!",
+ "schange24": "嘗試封鎖此註冊名稱時發生錯誤。 請再試一次!",
+ "schange25": "嘗試解封此註冊名稱時發生錯誤。 請再試一次!",
+ "schange26": "未分類",
+ "schange27": "大小",
+ "schange28": "狀態",
+ "schange29": "關注",
+ "schange30": "取消關注",
+ "schange31": "封鎖",
+ "schange32": "解除封鎖",
+ "schange33": "輸入需要搜尋的名稱",
+ "schange34": "名稱不能為空!",
+ "schange35": "搜尋"
+ },
"publishpage": {
"pchange1": "發佈",
"pchange2": "更新",
From edfed5d4cb687242a82d4e2f371e99a19ad463ed Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:10:21 +0100
Subject: [PATCH 33/83] Add q-app to menu
---
qortal-ui-core/src/components/app-view.js | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-core/src/components/app-view.js b/qortal-ui-core/src/components/app-view.js
index db343f78..6c570082 100644
--- a/qortal-ui-core/src/components/app-view.js
+++ b/qortal-ui-core/src/components/app-view.js
@@ -1528,8 +1528,16 @@ class AppView extends connect(store)(LitElement) {
-
-
+
+
+
+
+
+
+
+
+
+
From a2126fc4ce009a4f8a80685e644676ef4918b7f6 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:11:39 +0100
Subject: [PATCH 34/83] Add build q-app src
---
qortal-ui-plugins/build-config.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/qortal-ui-plugins/build-config.js b/qortal-ui-plugins/build-config.js
index e1bfac58..a44994b2 100644
--- a/qortal-ui-plugins/build-config.js
+++ b/qortal-ui-plugins/build-config.js
@@ -144,6 +144,18 @@ const generateForPlugins = () => {
in: 'plugins/core/puzzles/puzzles.src.js',
out: 'plugins/core/puzzles/puzzles.js',
},
+ {
+ in: 'plugins/core/q-app/q-apps.src.js',
+ out: 'plugins/core/q-app/q-apps.js',
+ },
+ {
+ in: 'plugins/core/q-app/app-browser/app-browser.src.js',
+ out: 'plugins/core/q-app/app-browser/app-browser.js',
+ },
+ {
+ in: 'plugins/core/q-app/publish-app/publish-app.src.js',
+ out: 'plugins/core/q-app/publish-app/publish-app.js',
+ },
].map((file) => {
return generateRollupConfig(
path.join(__dirname, file.in),
From bf907e9f8c27b9a2a483d0db4d3ac93c4263ec11 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:13:16 +0100
Subject: [PATCH 35/83] Missing menu
---
qortal-ui-plugins/plugins/core/main.src.js | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/qortal-ui-plugins/plugins/core/main.src.js b/qortal-ui-plugins/plugins/core/main.src.js
index 68de819a..62dd79e7 100644
--- a/qortal-ui-plugins/plugins/core/main.src.js
+++ b/qortal-ui-plugins/plugins/core/main.src.js
@@ -97,6 +97,15 @@ parentEpml.ready().then(() => {
menus: [],
parent: false,
},
+ {
+ url: 'qapps',
+ domain: 'core',
+ page: 'q-app/index.html',
+ title: 'Q-Apps',
+ icon: 'vaadin:desktop',
+ menus: [],
+ parent: false,
+ },
{
url: 'data-management',
domain: 'core',
From 583115cfd15aa08aab7db6418675b941bc3084e8 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:21:07 +0100
Subject: [PATCH 36/83] Update links
---
qortal-ui-plugins/plugins/core/q-app/q-apps.src.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
index 6f29fd66..fd487701 100644
--- a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
+++ b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
@@ -785,14 +785,14 @@ class QApps extends LitElement {
if (openObj.status.description === "Published but not yet downloaded") {
return html``
} else if (openObj.status.description === "Ready") {
- return html``
+ return html``
} else {
return html``
}
}
publishApp() {
- window.location.href = `publish-app/index.html?service=${this.service}&identifier=${this.identifier}&uploadType=zip&category=app&showName=true&showService=false&showIdentifier=false&showMetadata=true`
+ window.location.href = `../qdn/publish/index.html?service=${this.service}&identifier=${this.identifier}&uploadType=zip&category=app&showName=true&showService=false&showIdentifier=false&showMetadata=true`
}
async followName(appObj) {
From 7d4386d31e1fc728b0da609bd90ec310c16756d9 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:40:27 +0100
Subject: [PATCH 37/83] No more needed
---
.../core/q-app/app-browser/app-browser.src.js | 626 ------------------
.../plugins/core/q-app/app-browser/index.html | 55 --
2 files changed, 681 deletions(-)
delete mode 100644 qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
delete mode 100644 qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
diff --git a/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js b/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
deleted file mode 100644
index b64c55bb..00000000
--- a/qortal-ui-plugins/plugins/core/q-app/app-browser/app-browser.src.js
+++ /dev/null
@@ -1,626 +0,0 @@
-import { LitElement, html, css } from 'lit'
-import { render } from 'lit/html.js'
-import { Epml } from '../../../../epml'
-import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
-
-registerTranslateConfig({
- loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
-})
-
-import '@material/mwc-button'
-import '@material/mwc-icon'
-
-const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
-
-class AppBrowser extends LitElement {
- static get properties() {
- return {
- url: { type: String },
- name: { type: String },
- service: { type: String },
- identifier: { type: String },
- path: { type: String },
- displayUrl: {type: String },
- followedNames: { type: Array },
- blockedNames: { type: Array },
- theme: { type: String, reflect: true }
- }
- }
-
- static get observers() {
- return ['_kmxKeyUp(amount)']
- }
-
- static get styles() {
- return css`
- * {
- --mdc-theme-primary: rgb(3, 169, 244);
- --mdc-theme-secondary: var(--mdc-theme-primary);
- --paper-input-container-focus-color: var(--mdc-theme-primary);
- }
-
- #websitesWrapper paper-button {
- float: right;
- }
-
- #websitesWrapper .buttons {
- width: auto !important;
- }
-
- .address-bar {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 100px;
- background-color: var(--white);
- height: 36px;
- }
-
- .address-bar-button mwc-icon {
- width: 20px;
- }
-
- .iframe-container {
- position: absolute;
- top: 36px;
- left: 0;
- right: 0;
- bottom: 0;
- border-top: 1px solid var(--black);
- }
-
- .iframe-container iframe {
- display: block;
- width: 100%;
- height: 100%;
- border: none;
- background-color: var(--white);
- }
-
- input[type=text] {
- margin: 0;
- padding: 2px 0 0 20px;
- border: 0;
- height: 34px;
- font-size: 16px;
- background-color: var(--white);
- }
-
- paper-progress {
- --paper-progress-active-color: var(--mdc-theme-primary);
- }
-
- .float-right {
- float: right;
- }
-
- `
- }
-
- constructor() {
- super()
- this.url = 'about:blank'
-
- const urlParams = new URLSearchParams(window.location.search);
- this.name = urlParams.get('name');
- this.service = urlParams.get('service');
- this.identifier = urlParams.get('identifier') != null ? urlParams.get('identifier') : null;
- this.path = urlParams.get('path') != null ? ((urlParams.get('path').startsWith("/") ? "" : "/") + urlParams.get('path')) : "";
- this.followedNames = []
- this.blockedNames = []
- this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
-
- // Build initial display URL
- let displayUrl = "qortal://" + this.service + "/" + this.name;
- if (this.identifier != null && data.identifier != "" && this.identifier != "default") displayUrl = displayUrl.concat("/" + this.identifier);
- if (this.path != null && this.path != "/") displayUrl = displayUrl.concat(this.path);
- this.displayUrl = displayUrl;
-
- const getFollowedNames = async () => {
-
- let followedNames = await parentEpml.request('apiCall', {
- url: `/lists/followedNames?apiKey=${this.getApiKey()}`
- })
-
- this.followedNames = followedNames
- setTimeout(getFollowedNames, this.config.user.nodeSettings.pingInterval)
- }
-
- const getBlockedNames = async () => {
-
- let blockedNames = await parentEpml.request('apiCall', {
- url: `/lists/blockedNames?apiKey=${this.getApiKey()}`
- })
-
- this.blockedNames = blockedNames
- setTimeout(getBlockedNames, this.config.user.nodeSettings.pingInterval)
- }
-
- const render = () => {
- const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
- const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
- this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
- }
-
- const authorizeAndRender = () => {
- parentEpml.request('apiCall', {
- url: `/render/authorize/${this.name}?apiKey=${this.getApiKey()}`,
- method: "POST"
- }).then(res => {
- if (res.error) {
- // Authorization problem - API key incorrect?
- }
- else {
- render()
- }
- })
- }
-
- let configLoaded = false
-
- parentEpml.ready().then(() => {
- parentEpml.subscribe('selected_address', async selectedAddress => {
- this.selectedAddress = {}
- selectedAddress = JSON.parse(selectedAddress)
- if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
- this.selectedAddress = selectedAddress
- })
- parentEpml.subscribe('config', c => {
- this.config = JSON.parse(c)
- if (!configLoaded) {
- authorizeAndRender()
- setTimeout(getFollowedNames, 1)
- setTimeout(getBlockedNames, 1)
- configLoaded = true
- }
- })
- parentEpml.subscribe('copy_menu_switch', async value => {
-
- if (value === 'false' && window.getSelection().toString().length !== 0) {
-
- this.clearSelection()
- }
- })
- })
- }
-
- render() {
- return html`
-
-
-
- this.goBack()} title="${translate("general.back")}" class="address-bar-button">arrow_back_ios
- this.goForward()} title="${translate("browserpage.bchange1")}" class="address-bar-button">arrow_forward_ios
- this.refresh()} title="${translate("browserpage.bchange2")}" class="address-bar-button">refresh
- this.goBackToList()} title="${translate("browserpage.bchange3")}" class="address-bar-button">home
-
- this.delete()} title="${translate("browserpage.bchange4")} ${this.service} ${this.name} ${translate("browserpage.bchange5")}" class="address-bar-button float-right">delete
- ${this.renderBlockUnblockButton()}
- ${this.renderFollowUnfollowButton()}
-
-
-
-
-
-
- `
- }
-
- firstUpdated() {
-
- this.changeTheme()
- this.changeLanguage()
-
- window.addEventListener('contextmenu', (event) => {
- event.preventDefault()
- this._textMenu(event)
- })
-
- window.addEventListener('click', () => {
- parentEpml.request('closeCopyTextMenu', null)
- })
-
- window.addEventListener('storage', () => {
- const checkLanguage = localStorage.getItem('qortalLanguage')
- const checkTheme = localStorage.getItem('qortalTheme')
-
- use(checkLanguage)
-
- if (checkTheme === 'dark') {
- this.theme = 'dark'
- } else {
- this.theme = 'light'
- }
- document.querySelector('html').setAttribute('theme', this.theme)
- })
-
- window.onkeyup = (e) => {
- if (e.keyCode === 27) {
- parentEpml.request('closeCopyTextMenu', null)
- }
- }
-
- window.addEventListener("message", (event) => {
- if (event == null || event.data == null || event.data.length == 0 || event.data.action == null) {
- return;
- }
-
- let response = "{\"error\": \"Request could not be fulfilled\"}";
- let data = event.data;
- console.log("UI received event: " + JSON.stringify(data));
-
- switch (data.action) {
- case "GET_USER_ACCOUNT":
- // For now, we will return this without prompting the user, but we may need to add a prompt later
- let account = {};
- account["address"] = this.selectedAddress.address;
- account["publicKey"] = this.selectedAddress.base58PublicKey;
- response = JSON.stringify(account);
- break;
-
- case "LINK_TO_QDN_RESOURCE":
- case "QDN_RESOURCE_DISPLAYED":
- // Links are handled by the core, but the UI also listens for these actions in order to update the address bar.
- // Note: don't update this.url here, as we don't want to force reload the iframe each time.
- let url = "qortal://" + data.service + "/" + data.name;
- this.path = data.path != null ? ((data.path.startsWith("/") ? "" : "/") + data.path) : null;
- if (data.identifier != null && data.identifier != "" && data.identifier != "default") url = url.concat("/" + data.identifier);
- if (this.path != null && this.path != "/") url = url.concat(this.path);
- this.name = data.name;
- this.service = data.service;
- this.identifier = data.identifier;
- this.displayUrl = url;
- return;
-
- case "PUBLISH_QDN_RESOURCE":
- // Use "default" if user hasn't specified an identifer
- if (data.identifier == null) {
- data.identifier = "default";
- }
-
- // Params: data.service, data.name, data.identifier, data.data64,
- // TODO: prompt user for publish. If they confirm, call `POST /arbitrary/{service}/{name}/{identifier}/base64` and sign+process transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- case "SEND_CHAT_MESSAGE":
- // Params: data.groupId, data.destinationAddress, data.message
- // TODO: prompt user to send chat message. If they confirm, sign+process a CHAT transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- case "JOIN_GROUP":
- // Params: data.groupId
- // TODO: prompt user to join group. If they confirm, sign+process a JOIN_GROUP transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- case "DEPLOY_AT":
- // Params: data.creationBytes, data.name, data.description, data.type, data.tags, data.amount, data.assetId, data.fee
- // TODO: prompt user to deploy an AT. If they confirm, sign+process a DEPLOY_AT transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- case "GET_WALLET_BALANCE":
- // Params: data.coin (QORT / LTC / DOGE / DGB / RVN / ARRR)
- // TODO: prompt user to share wallet balance. If they confirm, call `GET /crosschain/:coin/walletbalance`, or for QORT, call `GET /addresses/balance/:address`
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- case "SEND_COIN":
- // Params: data.coin, data.destinationAddress, data.amount, data.fee
- // TODO: prompt user to send. If they confirm, call `POST /crosschain/:coin/send`, or for QORT, broadcast a PAYMENT transaction
- // then set the response string from the core to the `response` variable (defined above)
- // If they decline, send back JSON that includes an `error` key, such as `{"error": "User declined request"}`
- break;
-
- default:
- console.log("Unhandled message: " + JSON.stringify(data));
- return;
- }
-
-
- // Parse response
- let responseObj;
- try {
- responseObj = JSON.parse(response);
- } catch (e) {
- // Not all responses will be JSON
- responseObj = response;
- }
-
- // Respond to app
- if (responseObj.error != null) {
- event.ports[0].postMessage({
- result: null,
- error: responseObj
- });
- }
- else {
- event.ports[0].postMessage({
- result: responseObj,
- error: null
- });
- }
-
- });
- }
-
- changeTheme() {
- const checkTheme = localStorage.getItem('qortalTheme')
- if (checkTheme === 'dark') {
- this.theme = 'dark';
- } else {
- this.theme = 'light';
- }
- document.querySelector('html').setAttribute('theme', this.theme);
- }
-
- changeLanguage() {
- const checkLanguage = localStorage.getItem('qortalLanguage')
-
- if (checkLanguage === null || checkLanguage.length === 0) {
- localStorage.setItem('qortalLanguage', 'us')
- use('us')
- } else {
- use(checkLanguage)
- }
- }
-
- renderFollowUnfollowButton() {
- // Only show the follow/unfollow button if we have permission to modify the list on this node
- if (this.followedNames == null || !Array.isArray(this.followedNames)) {
- return html``
- }
-
- if (this.followedNames.indexOf(this.name) === -1) {
- // render follow button
- return html` this.follow()} title="${translate("browserpage.bchange7")} ${this.name}" class="address-bar-button float-right">add_to_queue`
- }
- else {
- // render unfollow button
- return html` this.unfollow()} title="${translate("browserpage.bchange8")} ${this.name}" class="address-bar-button float-right">remove_from_queue`
- }
- }
-
- renderBlockUnblockButton() {
- // Only show the block/unblock button if we have permission to modify the list on this node
- if (this.blockedNames == null || !Array.isArray(this.blockedNames)) {
- return html``
- }
-
- if (this.blockedNames.indexOf(this.name) === -1) {
- // render block button
- return html` this.block()} title="${translate("browserpage.bchange9")} ${this.name}" class="address-bar-button float-right">block`
- }
- else {
- // render unblock button
- return html` this.unblock()} title="${translate("browserpage.bchange10")} ${this.name}" class="address-bar-button float-right">radio_button_unchecked`
- }
- }
-
-
- // Navigation
-
- goBack() {
- window.history.back();
- }
-
- goForward() {
- window.history.forward();
- }
-
- refresh() {
- const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
- const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
- this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ""}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ""}`;
- }
-
- goBackToList() {
- window.location = "../index.html";
- }
-
- follow() {
- this.followName(this.name);
- }
-
- unfollow() {
- this.unfollowName(this.name);
- }
-
- block() {
- this.blockName(this.name);
- }
-
- unblock() {
- this.unblockName(this.name);
- }
-
- delete() {
- this.deleteCurrentResource();
- }
-
-
- async followName(name) {
- let items = [
- name
- ]
- let namesJsonString = JSON.stringify({ "items": items })
-
- let ret = await parentEpml.request('apiCall', {
- url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: `${namesJsonString}`
- })
-
- if (ret === true) {
- // Successfully followed - add to local list
- // Remove it first by filtering the list - doing it this way ensures the UI updates
- // immediately, as apposed to only adding if it doesn't already exist
- this.followedNames = this.followedNames.filter(item => item != name);
- this.followedNames.push(name)
- }
- else {
- let err1string = get("browserpage.bchange11")
- parentEpml.request('showSnackBar', `${err1string}`)
- }
-
- return ret
- }
-
- async unfollowName(name) {
- let items = [
- name
- ]
- let namesJsonString = JSON.stringify({ "items": items })
-
- let ret = await parentEpml.request('apiCall', {
- url: `/lists/followedNames?apiKey=${this.getApiKey()}`,
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: `${namesJsonString}`
- })
-
- if (ret === true) {
- // Successfully unfollowed - remove from local list
- this.followedNames = this.followedNames.filter(item => item != name);
- }
- else {
- let err2string = get("browserpage.bchange12")
- parentEpml.request('showSnackBar', `${err2string}`)
- }
-
- return ret
- }
-
- async blockName(name) {
- let items = [
- name
- ]
- let namesJsonString = JSON.stringify({ "items": items })
-
- let ret = await parentEpml.request('apiCall', {
- url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: `${namesJsonString}`
- })
-
- if (ret === true) {
- // Successfully blocked - add to local list
- // Remove it first by filtering the list - doing it this way ensures the UI updates
- // immediately, as apposed to only adding if it doesn't already exist
- this.blockedNames = this.blockedNames.filter(item => item != name);
- this.blockedNames.push(name)
- }
- else {
- let err3string = get("browserpage.bchange13")
- parentEpml.request('showSnackBar', `${err3string}`)
- }
-
- return ret
- }
-
- async unblockName(name) {
- let items = [
- name
- ]
- let namesJsonString = JSON.stringify({ "items": items })
-
- let ret = await parentEpml.request('apiCall', {
- url: `/lists/blockedNames?apiKey=${this.getApiKey()}`,
- method: 'DELETE',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: `${namesJsonString}`
- })
-
- if (ret === true) {
- // Successfully unblocked - remove from local list
- this.blockedNames = this.blockedNames.filter(item => item != name);
- }
- else {
- let err4string = get("browserpage.bchange14")
- parentEpml.request('showSnackBar', `${err4string}`)
- }
-
- return ret
- }
-
- async deleteCurrentResource() {
- if (this.followedNames.indexOf(this.name) != -1) {
- // Following name - so deleting won't work
- let err5string = get("browserpage.bchange15")
- parentEpml.request('showSnackBar', `${err5string}`)
- return;
- }
-
- let identifier = this.identifier == null ? "default" : resource.identifier;
-
- let ret = await parentEpml.request('apiCall', {
- url: `/arbitrary/resource/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`,
- method: 'DELETE'
- })
-
- if (ret === true) {
- this.goBackToList();
- }
- else {
- let err6string = get("browserpage.bchange16")
- parentEpml.request('showSnackBar', `${err6string}`)
- }
-
- return ret
- }
-
- _textMenu(event) {
- const getSelectedText = () => {
- var text = ''
- if (typeof window.getSelection != 'undefined') {
- text = window.getSelection().toString()
- } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
- text = this.shadowRoot.selection.createRange().text
- }
- return text
- }
-
- const checkSelectedTextAndShowMenu = () => {
- let selectedText = getSelectedText()
- if (selectedText && typeof selectedText === 'string') {
- let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
- let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
- parentEpml.request('openCopyTextMenu', textMenuObject)
- }
- }
- checkSelectedTextAndShowMenu()
- }
-
- getApiKey() {
- const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
- let apiKey = myNode.apiKey;
- return apiKey;
- }
-
- clearSelection() {
- window.getSelection().removeAllRanges()
- window.parent.getSelection().removeAllRanges()
- }
-}
-
-window.customElements.define('app-browser', AppBrowser)
diff --git a/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html b/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
deleted file mode 100644
index 03cf4220..00000000
--- a/qortal-ui-plugins/plugins/core/q-app/app-browser/index.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
From 0601879fa96ef7a2f73ef73db43dcd40f16b499c Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:40:40 +0100
Subject: [PATCH 38/83] No more needed
---
.../plugins/core/q-app/publish-app/index.html | 55 --
.../core/q-app/publish-app/publish-app.src.js | 670 ------------------
2 files changed, 725 deletions(-)
delete mode 100644 qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
delete mode 100644 qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
diff --git a/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html b/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
deleted file mode 100644
index 57f183df..00000000
--- a/qortal-ui-plugins/plugins/core/q-app/publish-app/index.html
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js b/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
deleted file mode 100644
index 25ca22cd..00000000
--- a/qortal-ui-plugins/plugins/core/q-app/publish-app/publish-app.src.js
+++ /dev/null
@@ -1,670 +0,0 @@
-import { LitElement, html, css } from 'lit'
-import { render } from 'lit/html.js'
-import { Epml } from '../../../../epml'
-import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
-
-registerTranslateConfig({
- loader: lang => fetch(`/language/${lang}.json`).then(res => res.json())
-})
-
-import '@material/mwc-button'
-import '@material/mwc-textfield'
-import '@material/mwc-select'
-import '@material/mwc-list/mwc-list-item.js'
-import '@polymer/paper-progress/paper-progress.js'
-
-const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
-
-class PublishApp extends LitElement {
- static get properties() {
- return {
- name: { type: String },
- service: { type: String },
- identifier: { type: String },
- category: { type: String },
- uploadType: { type: String },
- showName: { type: Boolean },
- showService: { type: Boolean },
- showIdentifier: { type: Boolean },
- showMetadata: { type: Boolean },
- tags: { type: Array },
- serviceLowercase: { type: String },
- metadata: { type: Array },
- categories: { type: Array },
- names: { type: Array },
- myRegisteredName: { type: String },
- selectedName: { type: String },
- path: { type: String },
- portForwardingEnabled: { type: Boolean },
- amount: { type: Number },
- generalMessage: { type: String },
- successMessage: { type: String },
- errorMessage: { type: String },
- loading: { type: Boolean },
- btnDisable: { type: Boolean },
- theme: { type: String, reflect: true }
- }
- }
-
- static get observers() {
- return ['_kmxKeyUp(amount)']
- }
-
- static get styles() {
- return css`
- * {
- --mdc-theme-primary: rgb(3, 169, 244);
- --mdc-theme-secondary: var(--mdc-theme-primary);
- --paper-input-container-focus-color: var(--mdc-theme-primary);
- --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);
- --_lumo-grid-border-color: var(--border);
- --_lumo-grid-secondary-border-color: var(--border2);
- }
-
-
- input[type=text] {
- padding: 6px 6px 6px 6px;
- color: var(--black);
- }
-
- input[type=file]::file-selector-button {
- border: 1px solid transparent;
- padding: 6px 6px 6px 6px;
- border-radius: 5px;
- color: #fff;
- background-color: var(--mdc-theme-primary);
- transition: 1s;
- }
-
- input[type=file]::file-selector-button:hover {
- color: #000;
- background-color: #81ecec;
- border: 1px solid transparent;
- }
-
- #publishWrapper paper-button {
- float: right;
- }
-
- #publishWrapper .buttons {
- width: auto !important;
- }
-
- mwc-textfield {
- margin: 0;
- }
-
- paper-progress {
- --paper-progress-active-color: var(--mdc-theme-primary);
- }
-
- .upload-text {
- display: block;
- font-size: 14px;
- color: var(--black);
- }
-
- .address-bar {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- height: 100px;
- background-color: var(--white);
- height: 36px;
- }
-
- .address-bar-button mwc-icon {
- width: 30px;
- }
- `
- }
-
- constructor() {
- super()
-
- this.showName = false;
- this.showService = false
- this.showIdentifier = false
- this.showMetadata = false
-
- const urlParams = new URLSearchParams(window.location.search)
- this.name = urlParams.get('name')
- this.service = urlParams.get('service')
- this.identifier = urlParams.get('identifier')
- this.category = urlParams.get('category')
- this.uploadType = urlParams.get('uploadType') !== "null" ? urlParams.get('uploadType') : "file"
-
- if (urlParams.get('showName') === "true") {
- this.showName = true
- }
-
- if (urlParams.get('showService') === "true") {
- this.showService = true
- }
-
- if (urlParams.get('showIdentifier') === "true") {
- this.showIdentifier = true
- }
-
- if (urlParams.get('showMetadata') === "true") {
- this.showMetadata = true
- }
-
- if (this.identifier != null) {
- if (this.identifier === "null" || this.identifier.trim().length == 0) {
- this.identifier = null
- }
- }
-
- // Default to true so the message doesn't appear and disappear quickly
- this.portForwardingEnabled = true
- this.names = []
- this.myRegisteredName = ''
- this.selectedName = 'invalid'
- this.path = ''
- this.successMessage = ''
- this.generalMessage = ''
- this.errorMessage = ''
- this.loading = false
- this.btnDisable = false
- this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
-
- const fetchNames = () => {
- parentEpml.request('apiCall', {url: `/names/address/${this.selectedAddress.address}?limit=0&reverse=true`}).then(res => {
- setTimeout(() => {
- this.names = res
- if (res[0] != null) {
- this.myRegisteredName = res[0].name;
- }
- }, 1)
- })
- setTimeout(fetchNames, this.config.user.nodeSettings.pingInterval)
- }
-
- const fetchCategories = () => {
- parentEpml.request('apiCall', {url: `/arbitrary/categories`}).then(res => {
- setTimeout(() => {
- this.categories = res
- }, 1)
- })
- setTimeout(fetchCategories, this.config.user.nodeSettings.pingInterval)
- }
-
- const fetchPeersSummary = () => {
- parentEpml.request('apiCall', {url: `/peers/summary`}).then(res => {
- setTimeout(() => {
- this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0);
- }, 1)
- })
- setTimeout(fetchPeersSummary, this.config.user.nodeSettings.pingInterval)
- }
-
- let configLoaded = false
-
- parentEpml.ready().then(() => {
- parentEpml.subscribe('selected_address', async selectedAddress => {
- this.selectedAddress = {}
- selectedAddress = JSON.parse(selectedAddress)
- if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
- this.selectedAddress = selectedAddress
- })
-
- parentEpml.subscribe('config', c => {
- if (!configLoaded) {
- setTimeout(fetchNames, 1)
- setTimeout(fetchCategories, 1)
- setTimeout(fetchPeersSummary, 1)
- configLoaded = true
- }
- this.config = JSON.parse(c)
- })
-
- parentEpml.subscribe('copy_menu_switch', async value => {
- if (value === 'false' && window.getSelection().toString().length !== 0) {
- this.clearSelection()
- }
- })
- })
- }
-
- render() {
- return html`
-
-
-
- this.goBack()} class="address-bar-button">arrow_back_ios ${translate("general.back")}
-
-
-
-
${translate("publishpage.pchange1")} / ${translate("publishpage.pchange2")} Q-App
-
${translate("publishpage.pchange3")}
-
-
-
-
- this.selectName(e)} style="min-width: 130px; max-width:100%; width:100%;">
-
- ${this.myRegisteredName}
-
-
-
-
-
-
-
-
-
-
-
- ${this.categories.map((c, index) => html`
- ${c.name}
- `)}
-
-
-
-
-
-
-
-
-
-
- ${this.renderUploadField()}
-
-
-
-
-
-
-
${this.generalMessage}
-
${this.errorMessage}
-
${this.successMessage}
- ${this.loading ? html`
` : ''}
-
-
-
- `
- }
-
- firstUpdated() {
-
- this.changeTheme()
- this.changeLanguage()
-
- window.addEventListener('contextmenu', (event) => {
- event.preventDefault()
- this._textMenu(event)
- })
-
- window.addEventListener('click', () => {
- parentEpml.request('closeCopyTextMenu', null)
- })
-
- window.addEventListener('storage', () => {
- const checkLanguage = localStorage.getItem('qortalLanguage')
- const checkTheme = localStorage.getItem('qortalTheme')
-
- use(checkLanguage)
-
- if (checkTheme === 'dark') {
- this.theme = 'dark'
- } else {
- this.theme = 'light'
- }
- document.querySelector('html').setAttribute('theme', this.theme)
- })
-
- window.onkeyup = (e) => {
- if (e.keyCode === 27) {
- parentEpml.request('closeCopyTextMenu', null)
- }
- }
- }
-
- changeTheme() {
- const checkTheme = localStorage.getItem('qortalTheme')
- if (checkTheme === 'dark') {
- this.theme = 'dark';
- } else {
- this.theme = 'light';
- }
- document.querySelector('html').setAttribute('theme', this.theme);
- }
-
- changeLanguage() {
- const checkLanguage = localStorage.getItem('qortalLanguage')
-
- if (checkLanguage === null || checkLanguage.length === 0) {
- localStorage.setItem('qortalLanguage', 'us')
- use('us')
- } else {
- use(checkLanguage)
- }
- }
-
- // Navigation
- goBack() {
- window.history.back();
- }
-
-
- renderUploadField() {
- if (this.uploadType === "file") {
- return html`
-
-
-
- `
- }
- else if (this.uploadType === "zip") {
- return html`
-
- ${translate("publishpage.pchange12")}:
-
-
- `
- }
- else {
- return html`
-
-
-
- `
- }
- }
-
-
- doPublish(e) {
- let registeredName = this.shadowRoot.getElementById('registeredName').value
- let service = this.shadowRoot.getElementById('service').value
- let identifier = this.shadowRoot.getElementById('identifier').value
-
- // If name is hidden, use the value passed in via the name parameter
- if (!this.showName) {
- registeredName = this.name
- }
-
- let file;
- let path;
-
- if (this.uploadType === "file" || this.uploadType === "zip") {
- file = this.shadowRoot.getElementById('file').files[0]
- }
- else if (this.uploadType === "path") {
- path = this.shadowRoot.getElementById('path').value
- }
-
- this.generalMessage = ''
- this.successMessage = ''
- this.errorMessage = ''
-
- if (registeredName === '') {
- this.showName = true
- let err1string = get("publishpage.pchange14")
- parentEpml.request('showSnackBar', `${err1string}`)
- }
- else if (this.uploadType === "file" && file == null) {
- let err2string = get("publishpage.pchange15")
- parentEpml.request('showSnackBar', `${err2string}`)
- }
- else if (this.uploadType === "zip" && file == null) {
- let err3string = get("publishpage.pchange16")
- parentEpml.request('showSnackBar', `${err3string}`)
- }
- else if (this.uploadType === "path" && path === '') {
- let err4string = get("publishpage.pchange17")
- parentEpml.request('showSnackBar', `${err4string}`)
- }
- else if (service === '') {
- let err5string = get("publishpage.pchange18")
- parentEpml.request('showSnackBar', `${err5string}`)
- }
- else {
- this.publishData(registeredName, path, file, service, identifier)
- }
- }
-
- async publishData(registeredName, path, file, service, identifier) {
- this.loading = true
- this.btnDisable = true
-
- const validateName = async (receiverName) => {
- let nameRes = await parentEpml.request('apiCall', {
- type: 'api',
- url: `/names/${receiverName}`,
- })
-
- return nameRes
- }
-
- const showError = async (errorMessage) => {
- this.loading = false
- this.btnDisable = false
- this.generalMessage = ''
- this.successMessage = ''
- console.error(errorMessage)
- }
-
- const validate = async () => {
- let validNameRes = await validateName(registeredName)
- if (validNameRes.error) {
- this.errorMessage = "Error: " + validNameRes.message
- showError(this.errorMessage)
- throw new Error(this.errorMessage);
- }
-
- let err6string = get("publishpage.pchange19")
- this.generalMessage = `${err6string}`
-
- let transactionBytes = await uploadData(registeredName, path, file)
- if (transactionBytes.error) {
- let err7string = get("publishpage.pchange20")
- this.errorMessage = `${err7string}` + transactionBytes.message
- showError(this.errorMessage)
- throw new Error(this.errorMessage);
- }
- else if (transactionBytes.includes("Error 500 Internal Server Error")) {
- let err8string = get("publishpage.pchange21")
- this.errorMessage = `${err8string}`
- showError(this.errorMessage)
- throw new Error(this.errorMessage);
- }
-
- let err9string = get("publishpage.pchange22")
- this.generalMessage = `${err9string}`
-
- let signAndProcessRes = await signAndProcess(transactionBytes)
- if (signAndProcessRes.error) {
- let err10string = get("publishpage.pchange20")
- this.errorMessage = `${err10string}` + signAndProcessRes.message
- showError(this.errorMessage)
- throw new Error(this.errorMessage);
- }
-
- let err11string = get("publishpage.pchange23")
-
- this.btnDisable = false
- this.loading = false
- this.errorMessage = ''
- this.generalMessage = ''
- this.successMessage = `${err11string}`
- }
-
- const uploadData = async (registeredName, path, file) => {
- let postBody = path
- let urlSuffix = ""
- if (file != null) {
-
- // If we're sending zipped data, make sure to use the /zip version of the POST /arbitrary/* API
- if (this.uploadType === "zip") {
- urlSuffix = "/zip"
- }
- // If we're sending file data, use the /base64 version of the POST /arbitrary/* API
- else if (this.uploadType === "file") {
- urlSuffix = "/base64"
- }
-
- // Base64 encode the file to work around compatibility issues between javascript and java byte arrays
- let fileBuffer = new Uint8Array(await file.arrayBuffer())
- postBody = Buffer.from(fileBuffer).toString('base64');
- }
-
- // Optional metadata
- let title = encodeURIComponent(this.shadowRoot.getElementById('title').value);
- let description = encodeURIComponent(this.shadowRoot.getElementById('description').value);
- let category = encodeURIComponent(this.shadowRoot.getElementById('category').value);
- let tag1 = encodeURIComponent(this.shadowRoot.getElementById('tag1').value);
- let tag2 = encodeURIComponent(this.shadowRoot.getElementById('tag2').value);
- let tag3 = encodeURIComponent(this.shadowRoot.getElementById('tag3').value);
- let tag4 = encodeURIComponent(this.shadowRoot.getElementById('tag4').value);
- let tag5 = encodeURIComponent(this.shadowRoot.getElementById('tag5').value);
-
- let metadataQueryString = `title=${title}&description=${description}&category=${category}&tags=${tag1}&tags=${tag2}&tags=${tag3}&tags=${tag4}&tags=${tag5}`
-
- let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
- if (identifier != null && identifier.trim().length > 0) {
- uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
- }
-
- let uploadDataRes = await parentEpml.request('apiCall', {
- type: 'api',
- method: 'POST',
- url: `${uploadDataUrl}`,
- body: `${postBody}`,
- })
- return uploadDataRes
- }
-
- const convertBytesForSigning = async (transactionBytesBase58) => {
- let convertedBytes = await parentEpml.request('apiCall', {
- type: 'api',
- method: 'POST',
- url: `/transactions/convert`,
- body: `${transactionBytesBase58}`,
- })
- return convertedBytes
- }
-
- const signAndProcess = async (transactionBytesBase58) => {
- let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58)
- if (convertedBytesBase58.error) {
- let err12string = get("publishpage.pchange20")
- this.errorMessage = `${err12string}` + convertedBytesBase58.message
- showError(this.errorMessage)
- throw new Error(this.errorMessage);
- }
-
- const convertedBytes = window.parent.Base58.decode(convertedBytesBase58);
- const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; });
- const convertedBytesArray = new Uint8Array(_convertedBytesArray)
- const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result
-
- const hashPtr = window.parent.sbrk(32, window.parent.heap);
- const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
- hashAry.set(convertedBytesHash);
-
- const difficulty = 14;
- const workBufferLength = 8 * 1024 * 1024;
- const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
-
- this.errorMessage = '';
- this.successMessage = '';
- let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
-
- let response = await parentEpml.request('sign_arbitrary', {
- nonce: this.selectedAddress.nonce,
- arbitraryBytesBase58: transactionBytesBase58,
- arbitraryBytesForSigningBase58: convertedBytesBase58,
- arbitraryNonce: nonce
- })
-
- let myResponse = { error: '' }
- if (response === false) {
- let err13string = get("publishpage.pchange24")
- myResponse.error = `${err13string}`
- }
- else {
- myResponse = response
- }
- return myResponse
- }
- validate()
- }
-
- _textMenu(event) {
- const getSelectedText = () => {
- var text = ''
- if (typeof window.getSelection != 'undefined') {
- text = window.getSelection().toString()
- } else if (typeof this.shadowRoot.selection != 'undefined' && this.shadowRoot.selection.type == 'Text') {
- text = this.shadowRoot.selection.createRange().text
- }
- return text
- }
-
- const checkSelectedTextAndShowMenu = () => {
- let selectedText = getSelectedText()
- if (selectedText && typeof selectedText === 'string') {
- let _eve = { pageX: event.pageX, pageY: event.pageY, clientX: event.clientX, clientY: event.clientY }
- let textMenuObject = { selectedText: selectedText, eventObject: _eve, isFrame: true }
- parentEpml.request('openCopyTextMenu', textMenuObject)
- }
- }
- checkSelectedTextAndShowMenu()
- }
-
-
- fetchResourceMetadata() {
- let identifier = this.identifier != null ? this.identifier : "default";
-
- parentEpml.request('apiCall', {
- url: `/arbitrary/metadata/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`
- }).then(res => {
-
- setTimeout(() => {
- this.metadata = res
- if (this.metadata != null && this.metadata.category != null) {
- this.shadowRoot.getElementById('category').value = this.metadata.category;
- }
- else {
- this.shadowRoot.getElementById('category').value = "";
- }
- }, 1)
- })
- }
-
- selectName(e) {
- let name = this.shadowRoot.getElementById('registeredName')
- this.selectedName = (name.value)
- // Update the current name if one has been selected
- if (name.value.length > 0) {
- this.name = (name.value)
- }
- this.fetchResourceMetadata();
- }
-
- getApiKey() {
- const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
- let apiKey = myNode.apiKey;
- return apiKey;
- }
-
- clearSelection() {
- window.getSelection().removeAllRanges()
- window.parent.getSelection().removeAllRanges()
- }
-}
-
-window.customElements.define('publish-app', PublishApp)
From 48997f58b7218373426a0b9a00814b86e539a905 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 12:41:51 +0100
Subject: [PATCH 39/83] Removed sources
---
qortal-ui-plugins/build-config.js | 8 --------
1 file changed, 8 deletions(-)
diff --git a/qortal-ui-plugins/build-config.js b/qortal-ui-plugins/build-config.js
index a44994b2..1c90aae0 100644
--- a/qortal-ui-plugins/build-config.js
+++ b/qortal-ui-plugins/build-config.js
@@ -148,14 +148,6 @@ const generateForPlugins = () => {
in: 'plugins/core/q-app/q-apps.src.js',
out: 'plugins/core/q-app/q-apps.js',
},
- {
- in: 'plugins/core/q-app/app-browser/app-browser.src.js',
- out: 'plugins/core/q-app/app-browser/app-browser.js',
- },
- {
- in: 'plugins/core/q-app/publish-app/publish-app.src.js',
- out: 'plugins/core/q-app/publish-app/publish-app.js',
- },
].map((file) => {
return generateRollupConfig(
path.join(__dirname, file.in),
From 4b662e3a84039ee74483fbc3b14b5b46ad4747a6 Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Fri, 3 Mar 2023 12:54:01 +0000
Subject: [PATCH 40/83] Put back missing translations
---
qortal-ui-core/language/us.json | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 10e6f914..b41c77be 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -566,7 +566,19 @@
"bchange13": "Error occurred when trying to block this registered name. Please try again!",
"bchange14": "Error occurred when trying to unblock this registered name. Please try again!",
"bchange15": "Can't delete data from followed names. Please unfollow first.",
- "bchange16": "Error occurred when trying to delete this resource. Please try again!"
+ "bchange16": "Error occurred when trying to delete this resource. Please try again!",
+ "bchange17": "User declined to share account details",
+ "bchange18": "has requested authentication. Would you like to authenticate?",
+ "bchange19": "Do you give this application permission to publish to QDN?",
+ "bchange20": "Do you give this application permission to get your wallet balance?",
+ "bchange21": "Fetch Wallet Failed. Please try again!",
+ "bchange22": "Do you give this application permission to send a chat message?",
+ "bchange23": "Message Sent!",
+ "bchange24": "This shares your QORT address and allows your account to interact with the",
+ "bchange25": "No sensitive data is shared.",
+ "bchange26": "Always authenticate automatically",
+ "bchange27": "Reject",
+ "bchange28": "Accept"
},
"datapage": {
"dchange1": "Data Management",
From 198d6fba0754f14726ae4ff2c70f99e732008fac Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Fri, 3 Mar 2023 13:16:05 +0000
Subject: [PATCH 41/83] Small tweaks to authentication popup.
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index e0eea567..1f00b376 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -1485,8 +1485,8 @@ async function showModalAndWait(type, data) {
${type === actions.GET_USER_ACCOUNT ? `
-
${`${data.service} ${data.name} ${get("browserpage.bchange18")}`}
-
${get("browserpage.bchange24")} ${data.service}
+
${`${data.service.toLowerCase()} ${get("browserpage.bchange18")}`}
+
${get("browserpage.bchange24")} ${data.service.toLowerCase()}.
${get("browserpage.bchange25")}
${this.renderUploadField()}
From 17b400e73c598cd943bc1ae33a895c93c9d7d34b Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Fri, 3 Mar 2023 18:01:37 +0000
Subject: [PATCH 49/83] Ensure the refresh button works every time it is
pushed.
Including the current time ensures that the URL is always different, so will always reload.
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index c86dbdbe..c741076c 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -1272,7 +1272,7 @@ class WebBrowser extends LitElement {
myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
this.url = `${nodeUrl}/render/${this.service}/${this.name}${this.path != null ? this.path : ''
}?theme=${this.theme}&identifier=${this.identifier != null ? this.identifier : ''
- }`;
+ }&time=${new Date().getMilliseconds()}`;
}
goBackToList() {
From 47801033a5b339f5d7d489b4ed6e0b00a9ed03a4 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 3 Mar 2023 20:47:09 +0100
Subject: [PATCH 50/83] Change button statuis after download
---
.../plugins/core/q-app/q-apps.src.js | 68 +++++++++++++++++--
1 file changed, 64 insertions(+), 4 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
index 3a8ea27a..dfa47d66 100644
--- a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
+++ b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
@@ -37,6 +37,8 @@ class QApps extends LitElement {
searchResources: { type: Array },
followedResources: { type: Array },
blockedResources: { type: Array },
+ textStatus: { type: String },
+ textProgress: { type: String },
theme: { type: String, reflect: true }
}
}
@@ -237,6 +239,8 @@ class QApps extends LitElement {
this.searchResources = []
this.followedResources = []
this.blockedResources = []
+ this.textStatus = ''
+ this.textProgress = ''
this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light'
}
@@ -328,7 +332,8 @@ class QApps extends LitElement {
${translate("appspage.schange10")}
` : ''}
- ${this.renderRelayModeText()}
+ ${this.renderRelayModeText()}
+
${this.textStatus} ${this.textProgress}
@@ -747,7 +752,7 @@ class QApps extends LitElement {
renderDownload(downObj) {
if (downObj.status.description === "Published but not yet downloaded" || downObj.status.status === "MISSING_DATA") {
return html`
this.downloadApp(downObj)}>`
- } else if (downObj.status.description === "Ready") {
+ } else if (downObj.status.description === "Ready" || downObj.status.status === "DOWNLOADED") {
return html`
`
} else {
return html``
@@ -759,11 +764,66 @@ class QApps extends LitElement {
await parentEpml.request('apiCall', {
url: `/arbitrary/resource/status/APP/${downObj.name}?build=true&apiKey=${this.getApiKey()}`
})
- this.getData(0)
- this.updateComplete.then(() => this.requestUpdate())
}
showChunks(downObj) {
+ const checkStatus = async () => {
+ const service = this.service
+ const name = downObj.name
+
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
+ const url = `${nodeUrl}/arbitrary/resource/status/${service}/${name}?build=true&apiKey=${this.getApiKey()}`
+
+ this.textStatus = 'Loading...'
+ this.textProgress = ''
+
+ const response = await fetch(url, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ })
+
+ const status = await response.json()
+
+ console.log("status:", status.id)
+
+ if (status.id === "UNSUPPORTED") {
+ this.textStatus = status.description
+ } else if (status.id === "BLOCKED") {
+ this.textStatus = name + " is blocked so content cannot be served"
+ this.retryInterval = 5000
+ setTimeout(checkStatus, this.retryInterval)
+ } else if (status.id === "READY") {
+ this.textStatus = ''
+ this.textProgress = ''
+ this.getData(0)
+ this.updateComplete.then(() => this.requestUpdate())
+ } else if (status.id === "BUILDING") {
+ this.textStatus = status.description
+ this.retryInterval = 1000
+ setTimeout(checkStatus, this.retryInterval)
+ } else if (status.id === "BUILD_FAILED") {
+ this.textStatus = status.description
+ } else if (status.id === "NOT_STARTED") {
+ this.textStatus = status.description
+ this.retryInterval = 1000
+ setTimeout(checkStatus, this.retryInterval)
+ } else if (status.id === "DOWNLOADING") {
+ this.textStatus = status.description
+ this.textProgress = "Files downloaded: " + status.localChunkCount + " / " + status.totalChunkCount
+ this.retryInterval = 1000
+ setTimeout(checkStatus, this.retryInterval)
+ } else if (status.id === "MISSING_DATA") {
+ this.textStatus = status.description
+ this.retryInterval = 5000
+ setTimeout(checkStatus, this.retryInterval)
+ } else if (status.id === "DOWNLOADED") {
+ this.textStatus = status.description
+ }
+ }
+ checkStatus()
}
publishApp() {
From 5465582b9775b92cf7f9b8d5d2dbeab9e3f513c1 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Fri, 3 Mar 2023 23:47:59 +0000
Subject: [PATCH 51/83] add send msg to group
---
.../plugins/core/qdn/browser/browser.src.js | 109 ++++++++++++------
1 file changed, 74 insertions(+), 35 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index c741076c..d73073a3 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -594,28 +594,58 @@ class WebBrowser extends LitElement {
case actions.SEND_CHAT_MESSAGE: {
const message = data.message;
const recipient = data.destinationAddress;
+ const groupId = data.groupId;
+ const isRecipient = groupId ? false : true
const sendMessage = async (messageText, chatReference) => {
let _reference = new Uint8Array(64);
window.crypto.getRandomValues(_reference);
let reference = window.parent.Base58.encode(_reference);
const sendMessageRequest = async () => {
- let chatResponse = await parentEpml.request('chat', {
- type: 18,
- nonce: this.selectedAddress.nonce,
- params: {
- timestamp: Date.now(),
- recipient: recipient,
- recipientPublicKey: this._publicKey.key,
- hasChatReference: 0,
- chatReference: chatReference,
- message: messageText,
- lastReference: reference,
- proofOfWorkNonce: 0,
- isEncrypted: 1,
- isText: 1
- }
- });
+ let chatResponse
+
+ if(isRecipient){
+ chatResponse = await parentEpml.request('chat', {
+ type: 18,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ timestamp: Date.now(),
+ recipient: recipient,
+ recipientPublicKey: this._publicKey.key,
+ hasChatReference: 0,
+ chatReference: chatReference,
+ message: messageText,
+ lastReference: reference,
+ proofOfWorkNonce: 0,
+ isEncrypted: 1,
+ isText: 1
+ }
+ });
+
+
+ }
+
+ if(!isRecipient){
+ chatResponse = await parentEpml.request('chat', {
+ type: 181,
+ nonce: this.selectedAddress.nonce,
+ params: {
+ timestamp: Date.now(),
+ groupID: Number(groupId),
+ hasReceipient: 0,
+ hasChatReference: 0,
+ chatReference: chatReference,
+ message: messageText,
+ lastReference: reference,
+ proofOfWorkNonce: 0,
+ isEncrypted: 0,
+ isText: 1
+ }
+ });
+
+
+ }
+
const msgResponse = await _computePow(chatResponse)
return msgResponse;
};
@@ -666,28 +696,31 @@ class WebBrowser extends LitElement {
);
if (result.action === "accept") {
let hasPublicKey = true;
- const res = await parentEpml.request('apiCall', {
- type: 'api',
- url: `/addresses/publickey/${recipient}`
- });
- if (res.error === 102) {
- this._publicKey.key = ''
- this._publicKey.hasPubKey = false
- hasPublicKey = false;
- } else if (res !== false) {
- this._publicKey.key = res
- this._publicKey.hasPubKey = true
- } else {
- this._publicKey.key = ''
- this._publicKey.hasPubKey = false
- hasPublicKey = false;
+ if(isRecipient){
+ const res = await parentEpml.request('apiCall', {
+ type: 'api',
+ url: `/addresses/publickey/${recipient}`
+ });
+
+ if (res.error === 102) {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ } else if (res !== false) {
+ this._publicKey.key = res
+ this._publicKey.hasPubKey = true
+ } else {
+ this._publicKey.key = ''
+ this._publicKey.hasPubKey = false
+ hasPublicKey = false;
+ }
}
+
- if (!hasPublicKey) {
- let err4string = get("chatpage.cchange39");
- parentEpml.request('showSnackBar', `${err4string}`)
- return
+ if (!hasPublicKey && isRecipient) {
+ response = '{"error": "Cannot send an encrypted message to this user since they do not have their publickey on chain."}';
+ break
}
@@ -729,6 +762,12 @@ class WebBrowser extends LitElement {
response = msgResponse;
} catch (error) {
console.error(error);
+ if(error.message){
+ let data = {};
+ data['error'] = error.message;
+ response = JSON.stringify(data);
+ break
+ }
response = '{"error": "Request could not be fulfilled"}';
} finally {
this.loader.hide();
From 2b6c7409bea99009b4c3a53a9b9ee1668c108b1c Mon Sep 17 00:00:00 2001
From: Phillip
Date: Sat, 4 Mar 2023 00:01:29 +0000
Subject: [PATCH 52/83] update chat version to 3
---
qortal-ui-plugins/plugins/core/components/ChatPage.js | 6 +++---
.../plugins/core/components/ChatWelcomePage.js | 2 +-
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js
index 6a66e6bc..59e10143 100644
--- a/qortal-ui-plugins/plugins/core/components/ChatPage.js
+++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js
@@ -3425,7 +3425,7 @@ class ChatPage extends LitElement {
}],
isImageDeleted: false,
repliedTo: '',
- version: 2
+ version: 3
};
const stringifyMessageObject = JSON.stringify(messageObject);
this.sendMessage(stringifyMessageObject, typeMessage);
@@ -3446,7 +3446,7 @@ class ChatPage extends LitElement {
filePath: outSideMsg.filePath
}],
repliedTo: '',
- version: 2
+ version: 3
};
const stringifyMessageObject = JSON.stringify(messageObject);
this.sendMessage(stringifyMessageObject, typeMessage);
@@ -3508,7 +3508,7 @@ class ChatPage extends LitElement {
}],
isAttachmentDeleted: false,
repliedTo: '',
- version: 2
+ version: 3
};
const stringifyMessageObject = JSON.stringify(messageObject);
this.sendMessage(stringifyMessageObject, typeMessage);
diff --git a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js
index eb95cb18..58bc2ce5 100644
--- a/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js
+++ b/qortal-ui-plugins/plugins/core/components/ChatWelcomePage.js
@@ -412,7 +412,7 @@ class ChatWelcomePage extends LitElement {
messageText,
images: [''],
repliedTo: '',
- version: 1
+ version: 3
};
const stringifyMessageObject = JSON.stringify(messageObject);
let chatResponse = await parentEpml.request('chat', {
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index d73073a3..94028ff4 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -745,7 +745,7 @@ class WebBrowser extends LitElement {
messageText: tiptapJson,
images: [''],
repliedTo: '',
- version: 2
+ version: 3
};
const stringifyMessageObject = JSON.stringify(messageObject);
From d1a489bdbc2f392ceafa1a5b816fa1a7c94d3185 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Sat, 4 Mar 2023 09:40:31 +0100
Subject: [PATCH 53/83] Update translations
---
qortal-ui-core/language/de.json | 4 +++-
qortal-ui-core/language/es.json | 4 +++-
qortal-ui-core/language/fr.json | 4 +++-
qortal-ui-core/language/hindi.json | 4 +++-
qortal-ui-core/language/hr.json | 4 +++-
qortal-ui-core/language/hu.json | 4 +++-
qortal-ui-core/language/it.json | 4 +++-
qortal-ui-core/language/ko.json | 4 +++-
qortal-ui-core/language/no.json | 4 +++-
qortal-ui-core/language/pl.json | 4 +++-
qortal-ui-core/language/pt.json | 4 +++-
qortal-ui-core/language/ro.json | 4 +++-
qortal-ui-core/language/rs.json | 4 +++-
qortal-ui-core/language/ru.json | 4 +++-
qortal-ui-core/language/us.json | 4 +++-
qortal-ui-core/language/zhc.json | 4 +++-
qortal-ui-core/language/zht.json | 4 +++-
17 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index 06e35b30..1aae4f7f 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -522,7 +522,9 @@
"schange37": "Heruntergeladen",
"schange38": "Update",
"schange39": "Öffnen",
- "schange40": "Vorschau"
+ "schange40": "Vorschau",
+ "schange41": "Wird heruntergeladen, bitte warten...",
+ "schange42": "Heruntergeladene Dateien"
},
"publishpage": {
"pchange1": "Veröffentlichen",
diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json
index 55188672..66c6e38b 100644
--- a/qortal-ui-core/language/es.json
+++ b/qortal-ui-core/language/es.json
@@ -522,7 +522,9 @@
"schange37": "Descargado",
"schange38": "Actualizar",
"schange39": "Abrir",
- "schange40": "Vista previa"
+ "schange40": "Vista previa",
+ "schange41": "Descargando por favor espere...",
+ "schange42": "Archivos descargados"
},
"publishpage": {
"pchange1": "Publicar",
diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json
index 52eaaeb6..003ce177 100644
--- a/qortal-ui-core/language/fr.json
+++ b/qortal-ui-core/language/fr.json
@@ -522,7 +522,9 @@
"schange37": "Téléchargé",
"schange38": "Mettre à jour",
"schange39": "Ouvrir",
- "schange40": "Aperçu"
+ "schange40": "Aperçu",
+ "schange41": "Téléchargement, veuillez patienter...",
+ "schange42": "Fichiers téléchargés"
},
"publishpage": {
"pchange1": "Publier",
diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json
index 2d36dc26..66e10732 100644
--- a/qortal-ui-core/language/hindi.json
+++ b/qortal-ui-core/language/hindi.json
@@ -523,7 +523,9 @@
"schange37": "डाउनलोड किया गया",
"schange38": "अपडेट",
"schange39": "खोलें",
- "schange40": "पूर्वावलोकन"
+ "schange40": "पूर्वावलोकन",
+ "schange41": "डाउनलोड हो रहा है कृपया प्रतीक्षा करें...",
+ "schange42": "फ़ाइलें डाउनलोड की गईं"
},
"publishpage": {
"pchange1": "प्रकाशित",
diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json
index b6c0b200..cdeb47cb 100644
--- a/qortal-ui-core/language/hr.json
+++ b/qortal-ui-core/language/hr.json
@@ -522,7 +522,9 @@
"schange37": "Preuzeto",
"schange38": "Ažuriraj",
"schange39": "Otvori",
- "schange40": "Pregled"
+ "schange40": "Pregled",
+ "schange41": "Preuzimanje, molimo pričekajte...",
+ "schange42": "Preuzete datoteke"
},
"publishpage": {
"pchange1": "Objavi",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index 7268df8f..b41e1e8f 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -522,7 +522,9 @@
"schange37": "Letöltve",
"schange38": "Frissítés",
"schange39": "Nyitva",
- "schange40": "Előnézet"
+ "schange40": "Előnézet",
+ "schange41": "Letöltés, kérem várjon...",
+ "schange42": "Fájlok letöltve"
},
"publishpage": {
"pchange1": "Közzétesz",
diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json
index ce947891..d6940ecb 100644
--- a/qortal-ui-core/language/it.json
+++ b/qortal-ui-core/language/it.json
@@ -522,7 +522,9 @@
"schange37": "Scaricato",
"schange38": "Aggiorna",
"schange39": "Apri",
- "schange40": "Anteprima"
+ "schange40": "Anteprima",
+ "schange41": "Download in corso, attendere...",
+ "schange42": "File scaricati"
},
"publishpage": {
"pchange1": "Pubblica",
diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json
index c2265546..116aaa30 100644
--- a/qortal-ui-core/language/ko.json
+++ b/qortal-ui-core/language/ko.json
@@ -522,7 +522,9 @@
"schange37": "다운로드됨",
"schange38": "업데이트",
"schange39": "열기",
- "schange40": "미리보기"
+ "schange40": "미리보기",
+ "schange41": "다운로드 중입니다...",
+ "schange42": "다운로드된 파일"
},
"publishpage": {
"pchange1": "발표",
diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json
index 87deb3b1..e1b190c3 100644
--- a/qortal-ui-core/language/no.json
+++ b/qortal-ui-core/language/no.json
@@ -522,7 +522,9 @@
"schange37": "Nedlastet",
"schange38": "Oppdater",
"schange39": "Åpne",
- "schange40": "Forhåndsvisning"
+ "schange40": "Forhåndsvisning",
+ "schange41": "Laster ned, vennligst vent...",
+ "schange42": "Filer lastet ned"
},
"publishpage": {
"pchange1": "Publiser",
diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json
index a5733e08..7c52775f 100644
--- a/qortal-ui-core/language/pl.json
+++ b/qortal-ui-core/language/pl.json
@@ -522,7 +522,9 @@
"schange37": "Pobrano",
"schange38": "Aktualizacja",
"schange39": "Otwórz",
- "schange40": "Podgląd"
+ "schange40": "Podgląd",
+ "schange41": "Pobieranie, proszę czekać...",
+ "schange42": "Pliki pobrane"
},
"publishpage": {
"pchange1": "Opublikuj",
diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json
index d7556a32..e2f53832 100644
--- a/qortal-ui-core/language/pt.json
+++ b/qortal-ui-core/language/pt.json
@@ -522,7 +522,9 @@
"schange37": "Baixado",
"schange38": "Atualizar",
"schange39": "Abrir",
- "schange40": "Pré-visualização"
+ "schange40": "Pré-visualização",
+ "schange41": "Baixando, por favor, aguarde...",
+ "schange42": "Arquivos baixados"
},
"publishpage": {
"pchange1": "Publicar",
diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json
index 86332830..97074371 100644
--- a/qortal-ui-core/language/ro.json
+++ b/qortal-ui-core/language/ro.json
@@ -522,7 +522,9 @@
"schange37": "Descărcat",
"schange38": "Actualizare",
"schange39": "Deschide",
- "schange40": "Previzualizare"
+ "schange40": "Previzualizare",
+ "schange41": "Se descarcă, așteptați...",
+ "schange42": "Fișiere descărcate"
},
"publishpage": {
"pchange1": "Publica",
diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json
index c636334e..870b26ef 100644
--- a/qortal-ui-core/language/rs.json
+++ b/qortal-ui-core/language/rs.json
@@ -522,7 +522,9 @@
"schange37": "Preuzeto",
"schange38": "Ažuriraj",
"schange39": "Otvori",
- "schange40": "Pregled"
+ "schange40": "Pregled",
+ "schange41": "Preuzimanje molim sačekajte...",
+ "schange42": "Preuzete datoteke"
},
"publishpage": {
"pchange1": "Objavite",
diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json
index 48da1180..b4dd1efa 100644
--- a/qortal-ui-core/language/ru.json
+++ b/qortal-ui-core/language/ru.json
@@ -522,7 +522,9 @@
"schange37": "Скачано",
"schange38": "Обновить",
"schange39": "Открыть",
- "schange40": "Предварительный просмотр"
+ "schange40": "Предварительный просмотр",
+ "schange41": "Идет загрузка, подождите...",
+ "schange42": "Файлы загружены"
},
"publishpage": {
"pchange1": "Опубликовать",
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index d2e0a314..034d786d 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -522,7 +522,9 @@
"schange37": "Downloaded",
"schange38": "Update",
"schange39": "Open",
- "schange40": "Preview"
+ "schange40": "Preview",
+ "schange41": "Downloading please wait...",
+ "schange42": "Files downloaded"
},
"publishpage": {
"pchange1": "Publish",
diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json
index dab36a89..391681f7 100644
--- a/qortal-ui-core/language/zhc.json
+++ b/qortal-ui-core/language/zhc.json
@@ -522,7 +522,9 @@
"schange37": "已下载",
"schange38": "更新",
"schange39": "打开",
- "schange40": "预览"
+ "schange40": "预览",
+ "schange41": "下载中请稍候...",
+ "schange42": "文件已下载"
},
"publishpage": {
"pchange1": "发布",
diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json
index 6b2fef2b..2f919c07 100644
--- a/qortal-ui-core/language/zht.json
+++ b/qortal-ui-core/language/zht.json
@@ -522,7 +522,9 @@
"schange37": "已下載",
"schange38": "更新",
"schange39": "打開",
- "schange40": "預覽"
+ "schange40": "預覽",
+ "schange41": "下載中請稍候...",
+ "schange42": "文件已下載"
},
"publishpage": {
"pchange1": "發佈",
From ba6ef87de802c67acd9f8b696582c022e6f6f961 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Sat, 4 Mar 2023 09:41:41 +0100
Subject: [PATCH 54/83] Update download functions
---
.../plugins/core/q-app/q-apps.src.js | 251 ++++++++++++++----
1 file changed, 204 insertions(+), 47 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
index dfa47d66..b50c038c 100644
--- a/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
+++ b/qortal-ui-plugins/plugins/core/q-app/q-apps.src.js
@@ -12,7 +12,7 @@ import '@material/mwc-icon'
import '@material/mwc-button'
import '@material/mwc-tab-bar'
import '@material/mwc-textfield'
-
+import '@polymer/paper-dialog/paper-dialog.js'
import '@vaadin/button'
import '@vaadin/grid'
import '@vaadin/icon'
@@ -32,6 +32,7 @@ class QApps extends LitElement {
followedNames: { type: Array },
blockedNames: { type: Array },
relayMode: { type: Boolean },
+ btnDisabled: { type: Boolean },
selectedAddress: { type: Object },
searchName: { type: String },
searchResources: { type: Array },
@@ -47,6 +48,8 @@ class QApps extends LitElement {
return css`
* {
--mdc-theme-primary: rgb(3, 169, 244);
+ --mdc-button-disabled-fill-color: rgba(3, 169, 244, 0.5);
+
--paper-input-container-focus-color: var(--mdc-theme-primary);
--lumo-primary-text-color: rgb(0, 167, 245);
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
@@ -73,44 +76,44 @@ class QApps extends LitElement {
--mdc-text-transform: none;
--mdc-tab-color-default: var(--black);
--mdc-tab-text-label-color-default: var(--black);
- }
+ }
#pages {
display: flex;
flex-wrap: wrap;
padding: 10px 5px 5px 5px;
margin: 0px 20px 20px 20px;
- }
+ }
- #pages > button {
- user-select: none;
- padding: 5px;
- margin: 0 5px;
- border-radius: 10%;
- border: 0;
- background: transparent;
- font: inherit;
- outline: none;
- cursor: pointer;
- color: var(--black);
- }
+ #pages > button {
+ user-select: none;
+ padding: 5px;
+ margin: 0 5px;
+ border-radius: 10%;
+ border: 0;
+ background: transparent;
+ font: inherit;
+ outline: none;
+ cursor: pointer;
+ color: var(--black);
+ }
- #pages > button:not([disabled]):hover,
- #pages > button:focus {
- color: #ccc;
- background-color: #eee;
- }
+ #pages > button:not([disabled]):hover,
+ #pages > button:focus {
+ color: #ccc;
+ background-color: #eee;
+ }
- #pages > button[selected] {
- font-weight: bold;
- color: var(--white);
- background-color: #ccc;
- }
+ #pages > button[selected] {
+ font-weight: bold;
+ color: var(--white);
+ background-color: #ccc;
+ }
- #pages > button[disabled] {
- opacity: 0.5;
- cursor: default;
- }
+ #pages > button[disabled] {
+ opacity: 0.5;
+ cursor: default;
+ }
#apps-list-page {
background: var(--white);
@@ -118,9 +121,9 @@ class QApps extends LitElement {
}
#search {
- display: flex;
- width: 50%;
- align-items: center;
+ display: flex;
+ width: 50%;
+ align-items: center;
}
.divCard {
@@ -130,6 +133,21 @@ class QApps extends LitElement {
margin-bottom: 2em;
}
+ paper-dialog.progress {
+ width: auto;
+ max-width: 50vw;
+ height: auto;
+ max-height: 30vh;
+ background-color: var(--white);
+ color: var(--black);
+ border: 1px solid var(--black);
+ border-radius: 15px;
+ text-align:center;
+ padding: 15px;
+ line-height: 1.6;
+ overflow-y: auto;
+ }
+
h2 {
margin:0;
}
@@ -221,6 +239,111 @@ class QApps extends LitElement {
.green {
--mdc-theme-primary: #198754;
}
+
+ .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);
+ }
+ }
+
`
}
@@ -235,6 +358,7 @@ class QApps extends LitElement {
this.blockedNames = []
this.relayMode = null
this.isLoading = false
+ this.btnDisabled = false
this.searchName = ''
this.searchResources = []
this.followedResources = []
@@ -333,7 +457,6 @@ class QApps extends LitElement {
` : ''}
${this.renderRelayModeText()}
-
${this.textStatus} ${this.textProgress}
@@ -421,6 +544,12 @@ class QApps extends LitElement {
+
+
+
+ ${translate("appspage.schange41")}
+ ${this.textProgress}
+
`
}
@@ -751,7 +880,7 @@ class QApps extends LitElement {
renderDownload(downObj) {
if (downObj.status.description === "Published but not yet downloaded" || downObj.status.status === "MISSING_DATA") {
- return html`
this.downloadApp(downObj)}>`
+ return html`
this.downloadApp(downObj)}>`
} else if (downObj.status.description === "Ready" || downObj.status.status === "DOWNLOADED") {
return html`
`
} else {
@@ -776,7 +905,12 @@ class QApps extends LitElement {
const url = `${nodeUrl}/arbitrary/resource/status/${service}/${name}?build=true&apiKey=${this.getApiKey()}`
this.textStatus = 'Loading...'
- this.textProgress = ''
+
+ this.btnDisabled = true
+
+ this.shadowRoot.getElementById('downloadProgressDialog').open()
+
+ let timerDownload
const response = await fetch(url, {
method: 'GET',
@@ -790,37 +924,60 @@ class QApps extends LitElement {
console.log("status:", status.id)
if (status.id === "UNSUPPORTED") {
+ this.btnDisabled = false
+ this.textProgress = ''
+ clearTimeout(timerDownload)
this.textStatus = status.description
} else if (status.id === "BLOCKED") {
+ this.btnDisabled = false
+ this.textProgress = ''
this.textStatus = name + " is blocked so content cannot be served"
- this.retryInterval = 5000
- setTimeout(checkStatus, this.retryInterval)
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 5000)
} else if (status.id === "READY") {
+ this.btnDisabled = false
+ clearTimeout(timerDownload)
this.textStatus = ''
this.textProgress = ''
+ this.shadowRoot.getElementById('downloadProgressDialog').close()
this.getData(0)
this.updateComplete.then(() => this.requestUpdate())
} else if (status.id === "BUILDING") {
+ this.btnDisabled = true
+ this.textProgress = ''
this.textStatus = status.description
- this.retryInterval = 1000
- setTimeout(checkStatus, this.retryInterval)
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 1000)
} else if (status.id === "BUILD_FAILED") {
+ this.btnDisabled = false
+ this.textProgress = ''
+ clearTimeout(timerDownload)
this.textStatus = status.description
} else if (status.id === "NOT_STARTED") {
+ this.btnDisabled = false
+ this.textProgress = ''
this.textStatus = status.description
- this.retryInterval = 1000
- setTimeout(checkStatus, this.retryInterval)
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 1000)
} else if (status.id === "DOWNLOADING") {
+ this.btnDisabled = true
this.textStatus = status.description
- this.textProgress = "Files downloaded: " + status.localChunkCount + " / " + status.totalChunkCount
- this.retryInterval = 1000
- setTimeout(checkStatus, this.retryInterval)
+ let progressString = get("appspage.schange42")
+ this.textProgress = progressString + ": " + status.localChunkCount + " / " + status.totalChunkCount
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 1000)
} else if (status.id === "MISSING_DATA") {
+ this.btnDisabled = true
+ this.textProgress = ''
this.textStatus = status.description
- this.retryInterval = 5000
- setTimeout(checkStatus, this.retryInterval)
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 5000)
} else if (status.id === "DOWNLOADED") {
- this.textStatus = status.description
+ this.btnDisabled = true
+ this.textProgress = ''
+ this.textStatus = status.description
+ clearTimeout(timerDownload)
+ timerDownload = setTimeout(checkStatus, 1000)
}
}
checkStatus()
From ade66a21362c3aa22176df5b20c33719751e9eca Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Sat, 4 Mar 2023 17:06:13 +0000
Subject: [PATCH 55/83] Fixed deletion bugs in browser.
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 94028ff4..420d995e 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -1461,8 +1461,7 @@ class WebBrowser extends LitElement {
return;
}
- let identifier =
- this.identifier == null ? 'default' : resource.identifier;
+ let identifier = (this.identifier == null || this.identifier.length == 0) ? 'default' : this.identifier;
let ret = await parentEpml.request('apiCall', {
url: `/arbitrary/resource/${this.service}/${this.name
From edc7dae13dd234edca1762480cbdd41a3e180ae3 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Thu, 16 Mar 2023 13:53:12 +0000
Subject: [PATCH 56/83] publish option with fee
---
qortal-ui-core/language/us.json | 3 +-
qortal-ui-core/src/plugins/routes.js | 27 +++++++++++
qortal-ui-crypto/api/api.js | 2 +-
qortal-ui-crypto/api/createTransaction.js | 7 +++
.../arbitrary/signArbitraryWithFee.js | 33 +++++++++++++
.../plugins/core/qdn/browser/browser.src.js | 18 +++++++-
.../plugins/utils/publish-image.js | 46 +++++++++++++++++--
7 files changed, 129 insertions(+), 7 deletions(-)
create mode 100644 qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 034d786d..8db1812a 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -581,7 +581,8 @@
"bchange25": "No sensitive data is shared.",
"bchange26": "Always authenticate automatically",
"bchange27": "Reject",
- "bchange28": "Accept"
+ "bchange28": "Accept",
+ "bchange29": "Instant publish (requires 0.001 QORT fee)"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-core/src/plugins/routes.js b/qortal-ui-core/src/plugins/routes.js
index ac83416b..4e81f894 100644
--- a/qortal-ui-core/src/plugins/routes.js
+++ b/qortal-ui-core/src/plugins/routes.js
@@ -25,6 +25,7 @@ const processTransaction = api.processTransaction;
const processTransactionVersion2 = api.processTransactionVersion2;
const signChatTransaction = api.signChatTransaction;
const signArbitraryTransaction = api.signArbitraryTransaction;
+const signArbitraryWithFeeTransaction = api.signArbitraryWithFeeTransaction;
const tradeBotCreateRequest = api.tradeBotCreateRequest;
const tradeBotRespondRequest = api.tradeBotRespondRequest;
const signTradeBotTxn = api.signTradeBotTxn;
@@ -306,6 +307,32 @@ export const routes = {
return response;
},
+ sign_arbitrary_with_fee: async (req) => {
+ let response;
+ try {
+ const signedArbitraryBytes = await signArbitraryWithFeeTransaction(
+ req.data.arbitraryBytesBase58,
+ req.data.arbitraryBytesForSigningBase58,
+ store.getState().app.wallet._addresses[req.data.nonce].keyPair
+ );
+ let res
+
+ if(req.data.apiVersion && req.data.apiVersion === 2){
+ res = await processTransactionVersion2(signedArbitraryBytes)
+ }
+ if(!req.data.apiVersion){
+ res = await processTransaction(signedArbitraryBytes);
+ }
+
+ response = res;
+ } catch (e) {
+ console.error(e);
+ console.error(e.message);
+ response = false;
+ }
+ return response;
+ },
+
showNotification: async (req) => {
doNewMessage(req.data);
},
diff --git a/qortal-ui-crypto/api/api.js b/qortal-ui-crypto/api/api.js
index e8e156dd..36a635cc 100644
--- a/qortal-ui-crypto/api/api.js
+++ b/qortal-ui-crypto/api/api.js
@@ -1,5 +1,5 @@
export { request } from './fetch-request.js'
export { transactionTypes as transactions } from './transactions/transactions.js'
-export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction } from './createTransaction.js'
+export { processTransaction, processTransactionVersion2, createTransaction, computeChatNonce, signChatTransaction, signArbitraryTransaction, signArbitraryWithFeeTransaction } from './createTransaction.js'
export { tradeBotCreateRequest, tradeBotRespondRequest, signTradeBotTxn, deleteTradeOffer, sendBtc, sendLtc, sendDoge, sendDgb, sendRvn, sendArrr } from './tradeRequest.js'
export { cancelAllOffers } from './transactions/trade-portal/tradeoffer/cancelAllOffers.js'
diff --git a/qortal-ui-crypto/api/createTransaction.js b/qortal-ui-crypto/api/createTransaction.js
index 169561dd..b4bf7802 100644
--- a/qortal-ui-crypto/api/createTransaction.js
+++ b/qortal-ui-crypto/api/createTransaction.js
@@ -3,6 +3,7 @@ import Base58 from './deps/Base58.js'
import { request } from './fetch-request'
import signChat from './transactions/chat/signChat.js'
import signArbitrary from './transactions/arbitrary/signArbitrary.js'
+import signArbitraryWithFee from './transactions/arbitrary/signArbitraryWithFee.js'
export const createTransaction = (type, keyPair, params) => {
@@ -31,6 +32,12 @@ export const signArbitraryTransaction = (arbitraryBytesBase58, arbitraryBytesFor
return signArbitrary(arbitraryBytesBase58, arbitraryBytesForSigningBase58, nonce, keyPair)
}
+export const signArbitraryWithFeeTransaction = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => {
+ return signArbitraryWithFee(arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair)
+}
+
+
+
// Process Transactions
export const processTransaction = bytes => request('/transactions/process', {
method: 'POST',
diff --git a/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js b/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js
new file mode 100644
index 00000000..1a71cc2e
--- /dev/null
+++ b/qortal-ui-crypto/api/transactions/arbitrary/signArbitraryWithFee.js
@@ -0,0 +1,33 @@
+import nacl from '../../deps/nacl-fast.js'
+import utils from '../../deps/utils.js'
+import Base58 from '../../deps/Base58.js'
+
+const signArbitraryWithFee = (arbitraryBytesBase58, arbitraryBytesForSigningBase58, keyPair) => {
+
+ if (!arbitraryBytesBase58) {
+ throw new Error('ArbitraryBytesBase58 not defined')
+ }
+
+
+ if (!keyPair) {
+ throw new Error('keyPair not defined')
+ }
+
+ const arbitraryBytes = Base58.decode(arbitraryBytesBase58)
+ const _arbitraryBytesBuffer = Object.keys(arbitraryBytes).map(function (key) { return arbitraryBytes[key]; })
+ const arbitraryBytesBuffer = new Uint8Array(_arbitraryBytesBuffer)
+
+ const arbitraryBytesForSigning = Base58.decode(arbitraryBytesForSigningBase58)
+ const _arbitraryBytesForSigningBuffer = Object.keys(arbitraryBytesForSigning).map(function (key) { return arbitraryBytesForSigning[key]; })
+ const arbitraryBytesForSigningBuffer = new Uint8Array(_arbitraryBytesForSigningBuffer)
+
+
+
+ const signature = nacl.sign.detached(arbitraryBytesForSigningBuffer, keyPair.privateKey)
+
+ const signedBytes = utils.appendBuffer(arbitraryBytesBuffer, signature)
+
+ return signedBytes
+}
+
+export default signArbitraryWithFee
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 420d995e..27c706ca 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -564,7 +564,8 @@ class WebBrowser extends LitElement {
selectedAddress: this.selectedAddress,
worker: worker,
isBase64: true,
- apiVersion: 2
+ apiVersion: 2,
+ withFee: res2.userData.isWithFee === true ? true: false
});
response = JSON.stringify(resPublish);
@@ -1556,7 +1557,16 @@ async function showModalAndWait(type, data) {
` : ''}
- ${type === actions.PUBLISH_QDN_RESOURCE ? `
${get("browserpage.bchange19")}
` : ''}
+ ${type === actions.PUBLISH_QDN_RESOURCE ? `
+
${get("browserpage.bchange19")}
+
+
+
+
+
+
` : ''}
${type === actions.GET_WALLET_BALANCE ? `
${get("browserpage.bchange20")}
` : ''}
${type === actions.SEND_CHAT_MESSAGE ? `
${get("browserpage.bchange22")}
` : ''}
@@ -1573,6 +1583,10 @@ async function showModalAndWait(type, data) {
const okButton = modal.querySelector('#ok-button');
okButton.addEventListener('click', () => {
const userData = {};
+ if (type === actions.PUBLISH_QDN_RESOURCE) {
+ const isWithFeeCheckbox = modal.querySelector('#isWithFee');
+ userData.isWithFee = isWithFeeCheckbox.checked;
+ }
if (modal.parentNode === document.body) {
document.body.removeChild(modal);
}
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 11aed013..22484335 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -19,7 +19,8 @@ export const publishData = async ({
worker,
isBase64,
metaData,
- apiVersion
+ apiVersion,
+ withFee
}) => {
const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", {
@@ -81,6 +82,33 @@ export const publishData = async ({
myResponse = response
}
+ return myResponse
+ }
+
+ const signAndProcessWithFee = async (transactionBytesBase58) => {
+ let convertedBytesBase58 = await convertBytesForSigning(
+ transactionBytesBase58
+ )
+ if (convertedBytesBase58.error) {
+ throw new Error('Error when signing');
+ }
+
+
+
+
+ let response = await parentEpml.request("sign_arbitrary_with_fee", {
+ nonce: selectedAddress.nonce,
+ arbitraryBytesBase58: transactionBytesBase58,
+ arbitraryBytesForSigningBase58: convertedBytesBase58,
+ apiVersion: apiVersion ? apiVersion : null
+ })
+ let myResponse = { error: "" }
+ if (response === false) {
+ throw new Error('Error when signing');
+ } else {
+ myResponse = response
+ }
+
return myResponse
}
@@ -91,14 +119,22 @@ export const publishData = async ({
}
let transactionBytes = await uploadData(registeredName, path, file)
if (transactionBytes.error) {
- throw new Error('Error when uploading');
+ throw new Error(transactionBytes.message || 'Error when uploading');
} else if (
transactionBytes.includes("Error 500 Internal Server Error")
) {
throw new Error('Error when uploading');
}
- let signAndProcessRes = await signAndProcess(transactionBytes)
+ let signAndProcessRes
+ if(withFee){
+ signAndProcessRes = await signAndProcessWithFee(transactionBytes)
+
+ }
+ if(!withFee){
+ signAndProcessRes = await signAndProcess(transactionBytes)
+
+ }
if (signAndProcessRes.error) {
throw new Error('Error when signing');
}
@@ -139,6 +175,10 @@ export const publishData = async ({
}
}
+
+ if(withFee){
+ uploadDataUrl = uploadDataUrl + '&fee=100000'
+ }
let uploadDataRes = await parentEpml.request("apiCall", {
type: "api",
From 58e7dee8a16a305d4b2f18fdd07082a0f9a1c4e5 Mon Sep 17 00:00:00 2001
From: CalDescent <>
Date: Sat, 18 Mar 2023 18:16:07 +0000
Subject: [PATCH 57/83] Added optional "filename" parameter to
`PUBLISH_QDN_RESOURCE` action.
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 2 ++
qortal-ui-plugins/plugins/utils/publish-image.js | 5 +++++
2 files changed, 7 insertions(+)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 27c706ca..b5628f77 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -544,6 +544,7 @@ class WebBrowser extends LitElement {
const name = data.name;
let identifier = data.identifier;
const data64 = data.data64;
+ const filename = data.filename;
if (data.identifier == null) {
identifier = 'default';
}
@@ -564,6 +565,7 @@ class WebBrowser extends LitElement {
selectedAddress: this.selectedAddress,
worker: worker,
isBase64: true,
+ filename: filename,
apiVersion: 2,
withFee: res2.userData.isWithFee === true ? true: false
});
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 22484335..471bfc73 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -18,6 +18,7 @@ export const publishData = async ({
selectedAddress,
worker,
isBase64,
+ filename,
metaData,
apiVersion,
withFee
@@ -179,6 +180,10 @@ export const publishData = async ({
if(withFee){
uploadDataUrl = uploadDataUrl + '&fee=100000'
}
+
+ if(filename != null && filename != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&filename=' + encodeURIComponent(filename)
+ }
let uploadDataRes = await parentEpml.request("apiCall", {
type: "api",
From f37e2b76c9f851d008eea18f910b4809fb0c7483 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Sun, 19 Mar 2023 12:13:36 +0200
Subject: [PATCH 58/83] fix publish metadata
---
.../core/components/ChatGifs/ChatGifs.js | 2 +-
.../plugins/core/qdn/browser/browser.src.js | 16 ++++++++
.../plugins/utils/publish-image.js | 39 ++++++++++++++++---
3 files changed, 50 insertions(+), 7 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js
index 63361262..b018f9c0 100644
--- a/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js
+++ b/qortal-ui-plugins/plugins/core/components/ChatGifs/ChatGifs.js
@@ -520,7 +520,7 @@ setOpenGifModal: { attribute: false }
service: 'GIF_REPOSITORY',
identifier: this.newCollectionName,
parentEpml,
- metaData: `title=${this.newCollectionName}`,
+ title: this.newCollectionName,
uploadType: 'zip',
selectedAddress: this.selectedAddress,
worker: this.webWorkerImage,
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index b5628f77..7447906d 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -545,6 +545,14 @@ class WebBrowser extends LitElement {
let identifier = data.identifier;
const data64 = data.data64;
const filename = data.filename;
+ const title = data.title;
+ const description = data.description;
+ const category = data.category;
+ const tag1 = data.tag1;
+ const tag2 = data.tag2;
+ const tag3 = data.tag3;
+ const tag4 = data.tag4;
+ const tag5 = data.tag5;
if (data.identifier == null) {
identifier = 'default';
}
@@ -566,6 +574,14 @@ class WebBrowser extends LitElement {
worker: worker,
isBase64: true,
filename: filename,
+ title,
+ description,
+ category,
+ tag1,
+ tag2,
+ tag3,
+ tag4,
+ tag5,
apiVersion: 2,
withFee: res2.userData.isWithFee === true ? true: false
});
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 471bfc73..356932c6 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -19,9 +19,16 @@ export const publishData = async ({
worker,
isBase64,
filename,
- metaData,
apiVersion,
- withFee
+ withFee,
+ title,
+ description,
+ category,
+ tag1,
+ tag2,
+ tag3,
+ tag4,
+ tag5
}) => {
const validateName = async (receiverName) => {
let nameRes = await parentEpml.request("apiCall", {
@@ -171,10 +178,6 @@ export const publishData = async ({
if (identifier != null && identifier.trim().length > 0) {
uploadDataUrl = `/arbitrary/${service}/${registeredName}/${identifier}${urlSuffix}?apiKey=${getApiKey()}`
- if(metaData){
- uploadDataUrl = `/arbitrary/${service}/${registeredName}/${identifier}${urlSuffix}?${metaData}&apiKey=${getApiKey()}`
-
- }
}
if(withFee){
@@ -184,6 +187,30 @@ export const publishData = async ({
if(filename != null && filename != "undefined"){
uploadDataUrl = uploadDataUrl + '&filename=' + encodeURIComponent(filename)
}
+ if(title != null && title != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&title=' + encodeURIComponent(title)
+ }
+ if(description != null && description != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&description=' + encodeURIComponent(description)
+ }
+ if(category != null && category != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&category=' + encodeURIComponent(category)
+ }
+ if(tag1 != null && tag1 != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&tag1=' + encodeURIComponent(tag1)
+ }
+ if(tag2 != null && tag2 != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&tag2=' + encodeURIComponent(tag2)
+ }
+ if(tag3 != null && tag3 != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&tag3=' + encodeURIComponent(tag3)
+ }
+ if(tag4 != null && tag4 != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&tag4=' + encodeURIComponent(tag4)
+ }
+ if(tag5 != null && tag5 != "undefined"){
+ uploadDataUrl = uploadDataUrl + '&tag5=' + encodeURIComponent(tag5)
+ }
let uploadDataRes = await parentEpml.request("apiCall", {
type: "api",
From 9bf50d82a7d8b13c4921af371c95175c778247b1 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Tue, 21 Mar 2023 11:15:29 +0100
Subject: [PATCH 59/83] Update translations
---
qortal-ui-core/language/de.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/es.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/fr.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/hindi.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/hr.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/hu.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/it.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/ko.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/no.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/pl.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/pt.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/ro.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/rs.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/ru.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/us.json | 45 ++++++++++++++++++++++++++++
qortal-ui-core/language/zhc.json | 48 +++++++++++++++++++++++++++++-
qortal-ui-core/language/zht.json | 48 +++++++++++++++++++++++++++++-
17 files changed, 797 insertions(+), 16 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index 1aae4f7f..7db218eb 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -526,6 +526,51 @@
"schange41": "Wird heruntergeladen, bitte warten...",
"schange42": "Heruntergeladene Dateien"
},
+ "tubespage": {
+ "schange1": "Q-Tubes durchsuchen",
+ "schange2": "Verfolgte Q-Tubes",
+ "schange3": "Blockierte Q-Röhren",
+ "schange4": "Suche Q-Tubes",
+ "schange5": "Abdeckung",
+ "schange6": "Details",
+ "schange7": "Herausgegeben von",
+ "schange8": "Aktionen",
+ "schange9": "Q-Röhren",
+ "schange10": "Keine Q-Röhrchen verfügbar",
+ "schange11": "Ihre gefolgten Q-Tubes",
+ "schange12": "Verfolgte Q-Tubes",
+ "schange13": "Du folgst keinen Q-Tubes",
+ "schange14": "Ihre blockierten Q-Tubes",
+ "schange15": "Blockierte Q-Röhren",
+ "schange16": "Sie haben keine Q-Tubes blockiert",
+ "schange17": "Name nicht gefunden!",
+ "schange18": "Relaismodus ist aktiviert. Das bedeutet, dass Ihr Knoten dabei hilft, verschlüsselte Daten durch das Netzwerk zu transportieren, wenn ein Peer dies anfordert. Sie können sich durch Einstellung abmelden",
+ "schange19": "in",
+ "schange20": "Relaismodus ist deaktiviert. Sie können ihn durch Einstellung aktivieren",
+ "schange21": "Video veröffentlichen",
+ "schange22": "Beim Versuch, diesem registrierten Namen zu folgen, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange23": "Beim Versuch, diesem registrierten Namen nicht mehr zu folgen, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange24": "Beim Blockieren dieses registrierten Namens ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange25": "Beim Versuch, diesen registrierten Namen zu entsperren, ist ein Fehler aufgetreten. Bitte versuche es erneut!",
+ "schange26": "Nicht kategorisiert",
+ "schange27": "Größe",
+ "schange28": "Status",
+ "schange29": "Folgen",
+ "schange30": "Entfolgen",
+ "schange31": "Sperren",
+ "schange32": "Entsperren",
+ "schange33": "Name zu suchen",
+ "schange34": "Name darf nicht leer sein!",
+ "schange35": "Suchen",
+ "schange36": "Herunterladen",
+ "schange37": "Heruntergeladen",
+ "schange38": "Update",
+ "schange39": "Öffnen",
+ "schange40": "Vorschau",
+ "schange41": "Wird heruntergeladen, bitte warten...",
+ "schange42": "Heruntergeladene Dateien",
+ "schange43": "Öffne, bitte warten..."
+ },
"publishpage": {
"pchange1": "Veröffentlichen",
"pchange2": "Aktualisieren",
@@ -581,7 +626,8 @@
"bchange25": "Es werden keine sensiblen Daten geteilt.",
"bchange26": "Immer automatisch authentifizieren",
"bchange27": "Ablehnen",
- "bchange28": "Akzeptieren"
+ "bchange28": "Akzeptieren",
+ "bchange29": "Sofortige Veröffentlichung (erfordert 0,001 QORT-Gebühr)"
},
"datapage": {
"dchange1": "Datenmanagement",
diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json
index 66c6e38b..52be60fe 100644
--- a/qortal-ui-core/language/es.json
+++ b/qortal-ui-core/language/es.json
@@ -526,6 +526,51 @@
"schange41": "Descargando por favor espere...",
"schange42": "Archivos descargados"
},
+ "tubespage": {
+ "schange1": "Explorar Q-Tubes",
+ "schange2": "Q-Tubes seguidos",
+ "schange3": "Q-Tubes bloqueados",
+ "schange4": "Buscar Q-Tubes",
+ "schange5": "Portada",
+ "schange6": "Detalles",
+ "schange7": "Publicado por",
+ "schange8": "Acciones",
+ "schange9": "Q-Tubes",
+ "schange10": "No hay q-tubos disponibles",
+ "schange11": "Tus Q-Tubes seguidos",
+ "schange12": "Q-Tubes seguidos",
+ "schange13": "No estás siguiendo ningún q-tubes",
+ "schange14": "Tus Q-Tubes bloqueados",
+ "schange15": "Q-Tubes bloqueados",
+ "schange16": "No has bloqueado ningún q-tubes",
+ "schange17": "¡No se encontró el nombre!",
+ "schange18": "El modo de retransmisión está habilitado. Esto significa que su nodo ayudará a transportar datos cifrados por la red cuando un par lo solicite. Puede optar por no hacerlo configurando",
+ "schange19": "en",
+ "schange20": "El modo de relé está deshabilitado. Puedes habilitarlo configurando",
+ "schange21": "Publicar vídeo",
+ "schange22": "Ha ocurrido un error al intentar seguir este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange23": "Ha ocurrido un error al intentar dejar de seguir este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange24": "Ha ocurrido un error al intentar bloquear este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange25": "Ha ocurrido un error al intentar desbloquear este nombre registrado. Por favor, inténtelo de nuevo!",
+ "schange26": "Sin categoría",
+ "schange27": "Tamaño",
+ "schange28": "Estado",
+ "schange29": "Seguir",
+ "schange30": "Dejar de Seguir",
+ "schange31": "Bloquear",
+ "schange32": "Desbloquear",
+ "schange33": "Nombre a buscar",
+ "schange34": "El nombre no puede estar vacío!",
+ "schange35": "Buscar",
+ "schange36": "Descargar",
+ "schange37": "Descargado",
+ "schange38": "Actualizar",
+ "schange39": "Abrir",
+ "schange40": "Vista previa",
+ "schange41": "Descargando por favor espere...",
+ "schange42": "Archivos descargados",
+ "schange43": "Abrir, por favor espere..."
+ },
"publishpage": {
"pchange1": "Publicar",
"pchange2": "Actualizar",
@@ -581,7 +626,8 @@
"bchange25": "No se comparten datos sensibles.",
"bchange26": "Autenticar siempre automáticamente",
"bchange27": "Rechazar",
- "bchange28": "Aceptar"
+ "bchange28": "Aceptar",
+ "bchange29": "Publicación instantánea (requiere una tarifa de 0.001 QORT)"
},
"datapage": {
"dchange1": "Gestión de datos",
diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json
index 003ce177..cea21ca9 100644
--- a/qortal-ui-core/language/fr.json
+++ b/qortal-ui-core/language/fr.json
@@ -526,6 +526,51 @@
"schange41": "Téléchargement, veuillez patienter...",
"schange42": "Fichiers téléchargés"
},
+ "tubespage": {
+ "schange1": "Parcourir Q-Tubes",
+ "schange2": "A suivi Q-Tubes",
+ "schange3": "Q-Tubes bloqués",
+ "schange4": "Rechercher Q-Tubes",
+ "schange5": "Couverture",
+ "schange6": "Détails",
+ "schange7": "Publié par",
+ "schange8": "Actions",
+ "schange9": "Q-Tubes",
+ "schange10": "Aucun q-tube disponible",
+ "schange11": "Vos Q-Tubes suivis",
+ "schange12": "A suivi Q-Tubes",
+ "schange13": "Vous ne suivez aucun q-tubes",
+ "schange14": "Vos Q-Tubes bloqués",
+ "schange15": "Q-Tubes bloqués",
+ "schange16": "Vous n'avez bloqué aucun q-tubes",
+ "schange17": "Nom introuvable !",
+ "schange18": "Le mode relais est activé. Cela signifie que votre nœud aidera à transporter des données cryptées sur le réseau lorsqu'un pair le demande. Vous pouvez vous désinscrire en définissant",
+ "schange19": "dans",
+ "schange20": "Le mode relais est désactivé. Vous pouvez l'activer en définissant",
+ "schange21": "Publier la vidéo",
+ "schange22": "Une erreur s’est produite lors de la tentative de suivi de ce nom enregistré. Veuillez réessayer!",
+ "schange23": "Une erreur s’est produite lors de la tentative de désabonnement de ce nom enregistré. Veuillez réessayer!",
+ "schange24": "Une erreur s’est produite lors de la tentative de blocage de ce nom enregistré. Veuillez réessayer!",
+ "schange25": "Une erreur s’est produite lors de la tentative de déverrouillage de ce nom enregistré. Veuillez réessayer!",
+ "schange26": "Non classé",
+ "schange27": "Taille",
+ "schange28": "Etat",
+ "schange29": "Suivre",
+ "schange30": "Ne plus suivre",
+ "schange31": "Bloquer",
+ "schange32": "Débloquer",
+ "schange33": "Nom à chercher",
+ "schange34": "Le nom ne peut être vide!",
+ "schange35": "Recherche",
+ "schange36": "Télécharger",
+ "schange37": "Téléchargé",
+ "schange38": "Mettre à jour",
+ "schange39": "Ouvrir",
+ "schange40": "Aperçu",
+ "schange41": "Téléchargement, veuillez patienter...",
+ "schange42": "Fichiers téléchargés",
+ "schange43": "Ouvrir veuillez patienter..."
+ },
"publishpage": {
"pchange1": "Publier",
"pchange2": "Mettre à jour",
@@ -581,7 +626,8 @@
"bchange25": "Aucune donnée sensible n'est partagée.",
"bchange26": "Toujours s'authentifier automatiquement",
"bchange27": "Rejeter",
- "bchange28": "Accepter"
+ "bchange28": "Accepter",
+ "bchange29": "Publication instantanée (nécessite des frais de 0,001 QORT)"
},
"datapage": {
"dchange1": "Gestion de données",
diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json
index 66e10732..459c7b5b 100644
--- a/qortal-ui-core/language/hindi.json
+++ b/qortal-ui-core/language/hindi.json
@@ -527,6 +527,51 @@
"schange41": "डाउनलोड हो रहा है कृपया प्रतीक्षा करें...",
"schange42": "फ़ाइलें डाउनलोड की गईं"
},
+ "tubespage": {
+ "schange1": "क्यू-ट्यूब ब्राउज़ करें",
+ "schange2": "क्यू-ट्यूब का अनुसरण किया",
+ "schange3": "अवरुद्ध क्यू-ट्यूब",
+ "schange4": "क्यू-ट्यूब खोजें",
+ "schange5": "कवर",
+ "schange6": "विवरण",
+ "schange7": "द्वारा प्रकाशित",
+ "schange8": "कार्रवाई",
+ "schange9": "क्यू-ट्यूब",
+ "schange10": "कोई क्यू-ट्यूब उपलब्ध नहीं",
+ "schange11": "आपके द्वारा अनुसरण किए गए क्यू-ट्यूब",
+ "schange12": "क्यू-ट्यूब का अनुसरण किया",
+ "schange13": "आप किसी क्यू-ट्यूब को फॉलो नहीं कर रहे हैं",
+ "schange14": "आपकी अवरूद्ध क्यू-ट्यूब",
+ "schange15": "अवरुद्ध क्यू-ट्यूब",
+ "schange16": "आपने किसी क्यू-ट्यूब को अवरूद्ध नहीं किया है",
+ "schange17": "नाम नहीं मिला!",
+ "schange18": "रिले मोड सक्षम है। इसका मतलब है कि आपका नोड नेटवर्क के चारों ओर एन्क्रिप्टेड डेटा को ट्रांसपोर्ट करने में मदद करेगा जब कोई सहकर्मी अनुरोध करता है। आप सेटिंग करके ऑप्ट आउट कर सकते हैं",
+ "schange19": "में",
+ "schange20": "रिले मोड अक्षम है। आप सेटिंग करके इसे सक्रिय कर सकते हैं",
+ "schange21": "वीडियो प्रकाशित करें",
+ "schange22": "इस पंजीकृत नाम का अनुसरण करने की कोशिश करते समय त्रुटि हुई। कृपया फिर से प्रयास करें!",
+ "schange23": "इस पंजीकृत नाम को अनफ़ॉलो करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange24": "इस पंजीकृत नाम को ब्लॉक करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange25": "इस पंजीकृत नाम को अनवरोधित करने का प्रयास करते समय त्रुटि उत्पन्न हुई। कृपया पुन: प्रयास करें!",
+ "schange26": "अवर्गीकृत",
+ "schange27": "आकार",
+ "schange28": "स्थिति",
+ "schange29": "अनुसरण",
+ "schange30": "अनफ़ॉलो करें",
+ "schange31": "ब्लॉक",
+ "schange32": "अनब्लॉक",
+ "schange33": "खोजने के लिए नाम",
+ "schange34": "नाम खाली नहीं हो सकता!",
+ "schange35": "खोज",
+ "schange36": "डाउनलोड करें",
+ "schange37": "डाउनलोड किया गया",
+ "schange38": "अपडेट",
+ "schange39": "खोलें",
+ "schange40": "पूर्वावलोकन",
+ "schange41": "डाउनलोड हो रहा है कृपया प्रतीक्षा करें...",
+ "schange42": "फ़ाइलें डाउनलोड की गईं",
+ "schange43": "खोलें, कृपया प्रतीक्षा करें..."
+ },
"publishpage": {
"pchange1": "प्रकाशित",
"pchange2": "अपडेट करना",
@@ -582,7 +627,8 @@
"bchange25": "कोई संवेदनशील डेटा साझा नहीं किया गया है।",
"bchange26": "हमेशा स्वचालित रूप से प्रमाणित करें",
"bchange27": "अस्वीकार करें",
- "bchange28": "स्वीकार करें"
+ "bchange28": "स्वीकार करें",
+ "bchange29": "तत्काल प्रकाशन (0.001 QORT शुल्क की आवश्यकता है)"
},
"datapage": {
"dchange1": "डाटा प्रबंधन",
diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json
index cdeb47cb..8746ca9a 100644
--- a/qortal-ui-core/language/hr.json
+++ b/qortal-ui-core/language/hr.json
@@ -526,6 +526,51 @@
"schange41": "Preuzimanje, molimo pričekajte...",
"schange42": "Preuzete datoteke"
},
+ "tubespage": {
+ "schange1": "Pregledaj Q-Tubes",
+ "schange2": "Pratio Q-Tubes",
+ "schange3": "Blokirane Q-cijevi",
+ "schange4": "Traži Q-Tubes",
+ "schange5": "Naslovna stranica",
+ "schange6": "Detalji",
+ "schange7": "Objavio",
+ "schange8": "Akcije",
+ "schange9": "Q-Tubes",
+ "schange10": "Nema dostupnih q-tubes",
+ "schange11": "Q-Tubes koje pratite",
+ "schange12": "Pratio Q-Tubes",
+ "schange13": "Ne pratite nijednu q-tubes",
+ "schange14": "Vaše blokirane Q-Tubes",
+ "schange15": "Blokirane Q-Tubes",
+ "schange16": "Niste blokirali nijednu q-tubes",
+ "schange17": "Ime nije pronađeno!",
+ "schange18": "Relejni način rada je omogućen. To znači da će vaš čvor pomoći u prijenosu šifriranih podataka po mreži kada to ravnopravni uređaj zatraži. Možete se isključiti postavljanjem",
+ "schange19": "u",
+ "schange20": "Relejni način rada je onemogućen. Možete ga omogućiti postavljanjem",
+ "schange21": "Objavi video",
+ "schange22": "Došlo je do pogreške prilikom pokušaja da pratite ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange23": "Došlo je do pogreške prilikom pokušaja da nepratite ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange24": "Došlo je do pogreške prilikom pokušaja da blokirate ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange25": "Došlo je do pogreške prilikom pokušaja da odblokirate ovo registrirano ime. Molimo pokušajte ponovno!",
+ "schange26": "Nekategorizirano",
+ "schange27": "Veličina",
+ "schange28": "Status",
+ "schange29": "Prati",
+ "schange30": "Neprati",
+ "schange31": "Blokiraj",
+ "schange32": "Odblokiraj",
+ "schange33": "Ime za tražiti",
+ "schange34": "Ime nemože biti prazno!",
+ "schange35": "Traži",
+ "schange36": "Preuzmi",
+ "schange37": "Preuzeto",
+ "schange38": "Ažuriraj",
+ "schange39": "Otvori",
+ "schange40": "Pregled",
+ "schange41": "Preuzimanje, molimo pričekajte...",
+ "schange42": "Preuzete datoteke",
+ "schange43": "Otvorite molimo pričekajte..."
+ },
"publishpage": {
"pchange1": "Objavi",
"pchange2": "Ažuriraj",
@@ -581,7 +626,8 @@
"bchange25": "Ne dijele se osjetljivi podaci.",
"bchange26": "Uvijek autentificiraj automatski",
"bchange27": "Odbaci",
- "bchange28": "Prihvati"
+ "bchange28": "Prihvati",
+ "bchange29": "Trenutno objavljivanje (zahtijeva naknadu od 0,001 QORT)"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index b41e1e8f..01e9c7d6 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -526,6 +526,51 @@
"schange41": "Letöltés, kérem várjon...",
"schange42": "Fájlok letöltve"
},
+ "tubespage": {
+ "schange1": "Tallózás a Q-Tubes-ban",
+ "schange2": "Követve Q-Tubes",
+ "schange3": "Blocked Q-Tubes",
+ "schange4": "Keresés a Q-Tubes-ban",
+ "schange5": "Borító",
+ "schange6": "Részletek",
+ "schange7": "Kiadó",
+ "schange8": "Műveletek",
+ "schange9": "Q-Tubes",
+ "schange10": "Nincs elérhető q-tubes",
+ "schange11": "Az Ön által követett Q-Tubes",
+ "schange12": "Követve Q-Tubes",
+ "schange13": "Nem követsz egyetlen q-tubes sem",
+ "schange14": "Az Ön blokkolt Q-Tubes",
+ "schange15": "Blocked Q-Tubes",
+ "schange16": "Nem blokkoltál egyetlen q-tubes sem",
+ "schange17": "A név nem található!",
+ "schange18": "A továbbítási mód engedélyezve van. Ez azt jelenti, hogy a csomópont segít a titkosított adatok továbbításában a hálózaton, amikor egy társ kéri. A beállítással letilthatja",
+ "schange19": "in",
+ "schange20": "Relé mód le van tiltva. Beállítással engedélyezheti",
+ "schange21": "Videó közzététele",
+ "schange22": "Hiba történt a regisztrált név követésekor. Próbálkozzon újra!",
+ "schange23": "Hiba történt, amikor megpróbálta megszüntetni a regisztrált név követését Próbálkozzon újra!",
+ "schange24": "Hiba történt a regisztrált név blokkolása közben.. Próbálkozzon újra!",
+ "schange25": "Hiba történt a regisztrált név blokkolásának feloldásakor. Próbálkozzon újra!",
+ "schange26": "Nem Kategorizált",
+ "schange27": "Méret",
+ "schange28": "Állapot",
+ "schange29": "Követ",
+ "schange30": "Követés megszüntetése",
+ "schange31": "Blokk",
+ "schange32": "Felszabadít",
+ "schange33": "Keresendő Név",
+ "schange34": "A név nem lehet üres!",
+ "schange35": "Keresés",
+ "schange36": "Letöltés",
+ "schange37": "Letöltve",
+ "schange38": "Frissítés",
+ "schange39": "Nyitva",
+ "schange40": "Előnézet",
+ "schange41": "Letöltés, kérem várjon...",
+ "schange42": "Fájlok letöltve",
+ "schange43": "Nyissa meg, kérem várjon..."
+ },
"publishpage": {
"pchange1": "Közzétesz",
"pchange2": "Frissítés",
@@ -581,7 +626,8 @@
"bchange25": "Nincs kényes adat megosztása.",
"bchange26": "Mindig automatikus hitelesítés",
"bchange27": "Elutasítás",
- "bchange28": "Elfogadás"
+ "bchange28": "Elfogadás",
+ "bchange29": "Azonnali közzététel (0,001 QORT díj szükséges)"
},
"datapage": {
"dchange1": "Adatkezelés",
diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json
index d6940ecb..9dbdafbf 100644
--- a/qortal-ui-core/language/it.json
+++ b/qortal-ui-core/language/it.json
@@ -526,6 +526,51 @@
"schange41": "Download in corso, attendere...",
"schange42": "File scaricati"
},
+ "tubespage": {
+ "schange1": "Sfoglia Q-Tubes",
+ "schange2": "Seguito Q-Tubes",
+ "schange3": "Q-Tubes bloccati",
+ "schange4": "Cerca Q-Tubes",
+ "schange5": "Copertina",
+ "schange6": "Dettagli",
+ "schange7": "Pubblicato da",
+ "schange8": "Azioni",
+ "schange9": "Q-Tubes",
+ "schange10": "Nessun q-tubes disponibile",
+ "schange11": "I tuoi Q-Tubes seguiti",
+ "schange12": "Seguito Q-Tubes",
+ "schange13": "Non stai seguendo nessun q-tubes",
+ "schange14": "I tuoi Q-Tubes bloccati",
+ "schange15": "Q-Tubes bloccati",
+ "schange16": "Non hai bloccato nessun q-tubes",
+ "schange17": "Nome non trovato!",
+ "schange18": "La modalità di inoltro è abilitata. Ciò significa che il tuo nodo aiuterà a trasportare i dati crittografati sulla rete quando un peer lo richiede. Puoi disattivarli impostando",
+ "schange19": "dentro",
+ "schange20": "La modalità inoltro è disabilitata. Puoi abilitarla impostando",
+ "schange21": "Pubblica video",
+ "schange22": "Si è verificato un errore durante il tentativo di seguire questo nome registrato. Per favore, riprova!",
+ "schange23": "Si è verificato un errore durante il tentativo di smettere di seguire questo nome registrato. Per favore, riprova!",
+ "schange24": "Si è verificato un errore durante il tentativo di bloccare questo nome registrato. Per favore, riprova!",
+ "schange25": "Si è verificato un errore durante il tentativo di sbloccare questo nome registrato. Per favore, riprova!",
+ "schange26": "Senza categoria",
+ "schange27": "Taglia",
+ "schange28": "Stato",
+ "schange29": "Segui",
+ "schange30": "Non seguire più",
+ "schange31": "Blocca",
+ "schange32": "Sblocca",
+ "schange33": "Nome da cercare",
+ "schange34": "Il nome non può essere vuoto!",
+ "schange35": "Cerca",
+ "schange36": "Scarica",
+ "schange37": "Scaricato",
+ "schange38": "Aggiorna",
+ "schange39": "Apri",
+ "schange40": "Anteprima",
+ "schange41": "Download in corso, attendere...",
+ "schange42": "File scaricati",
+ "schange43": "Apri, per favore aspetta..."
+ },
"publishpage": {
"pchange1": "Pubblica",
"pchange2": "Aggiorna",
@@ -581,7 +626,8 @@
"bchange25": "Nessun dato sensibile viene condiviso.",
"bchange26": "Autenticati sempre automaticamente",
"bchange27": "Rifiuta",
- "bchange28": "Accetta"
+ "bchange28": "Accetta",
+ "bchange29": "Pubblicazione istantanea (richiede una quota di 0,001 QORT)"
},
"datapage": {
"dchange1": "Gestione dati",
diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json
index 116aaa30..02d8cedf 100644
--- a/qortal-ui-core/language/ko.json
+++ b/qortal-ui-core/language/ko.json
@@ -526,6 +526,51 @@
"schange41": "다운로드 중입니다...",
"schange42": "다운로드된 파일"
},
+ "tubespage": {
+ "schange1": "Q-Tubes 둘러보기",
+ "schange2": "팔로잉한 Q-Tubes",
+ "schange3": "차단된 Q-Tubes",
+ "schange4": "Q-Tubes 검색",
+ "schange5": "덮개",
+ "schange6": "자세히",
+ "schange7": "출판사",
+ "schange8": "작업",
+ "schange9": "Q-Tubes",
+ "schange10": "사용 가능한 q-tubes 없음",
+ "schange11": "내가 팔로우한 Q-Tubes",
+ "schange12": "팔로잉한 Q-Tubes",
+ "schange13": "팔로우 중인 q-tubes가 없습니다",
+ "schange14": "차단된 Q-Tubes",
+ "schange15": "차단된 Q-Tubes",
+ "schange16": "어떤 q-tubes 차단하지 않았습니다",
+ "schange17": "이름을 찾을 수 없습니다!",
+ "schange18": "릴레이 모드가 활성화되었습니다. 이는 피어가 요청할 때 노드가 네트워크에서 암호화된 데이터를 전송하는 데 도움이 된다는 것을 의미합니다. 설정을 통해 옵트아웃할 수 있습니다.",
+ "schange19": "에서",
+ "schange20": "릴레이 모드가 비활성화되었습니다. 설정을 통해 활성화할 수 있습니다.",
+ "schange21": "비디오 게시",
+ "schange22": "이 등록된 이름을 따르는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange23": "이 등록된 이름의 팔로우를 해제하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange24": "이 등록된 이름을 차단하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange25": "이 등록된 이름의 차단을 해제하는 동안 오류가 발생했습니다. 다시 시도하십시오!",
+ "schange26": "분류되지 않음",
+ "schange27": "크기",
+ "schange28": "상태",
+ "schange29": "팔로우",
+ "schange30": "언팔로우",
+ "schange31": "차단",
+ "schange32": "차단 해제",
+ "schange33": "검색할 이름",
+ "schange34": "이름은 비워 둘 수 없습니다!",
+ "schange35": "검색",
+ "schange36": "다운로드",
+ "schange37": "다운로드됨",
+ "schange38": "업데이트",
+ "schange39": "열기",
+ "schange40": "미리보기",
+ "schange41": "다운로드 중입니다...",
+ "schange42": "다운로드된 파일",
+ "schange43": "열어주세요..."
+ },
"publishpage": {
"pchange1": "발표",
"pchange2": "업데이트",
@@ -581,7 +626,8 @@
"bchange25": "민감한 데이터는 공유되지 않습니다.",
"bchange26": "항상 자동으로 인증",
"bchange27": "거부",
- "bchange28": "수락"
+ "bchange28": "수락",
+ "bchange29": "즉시 게시(0.001QORT 수수료 필요)"
},
"datapage": {
"dchange1": "데이터 관리",
diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json
index e1b190c3..e09f8292 100644
--- a/qortal-ui-core/language/no.json
+++ b/qortal-ui-core/language/no.json
@@ -526,6 +526,51 @@
"schange41": "Laster ned, vennligst vent...",
"schange42": "Filer lastet ned"
},
+ "tubespage": {
+ "schange1": "Bla gjennom Q-Tubes",
+ "schange2": "Fulgte Q-Tubes",
+ "schange3": "Blokkerte Q-Tubes",
+ "schange4": "Søk etter Q-Tubes",
+ "schange5": "Deksel",
+ "schange6": "Detaljer",
+ "schange7": "Publisert av",
+ "schange8": "Handlinger",
+ "schange9": "Q-Tubes",
+ "schange10": "Ingen q-tubes tilgjengelig",
+ "schange11": "Dine fulgte Q-Tubes",
+ "schange12": "Følgte Q-Tubes",
+ "schange13": "Du følger ingen q-tubes",
+ "schange14": "Dine blokkerte Q-Tubes",
+ "schange15": "Blokkerte Q-Tubes",
+ "schange16": "Du har ikke blokkert noen q-tubes",
+ "schange17": "Navnet ble ikke funnet!",
+ "schange18": "Relémodus er aktivert. Dette betyr at noden din vil hjelpe til med å transportere krypterte data rundt i nettverket når en peer ber om det. Du kan velge bort ved å stille inn",
+ "schange19": "i",
+ "schange20": "Relémodus er deaktivert. Du kan aktivere den ved å stille inn",
+ "schange21": "Publiser video",
+ "schange22": "Det oppstod en feil ved forsøk på å følge dette registrerte navnet. Prøv på nytt!",
+ "schange23": "Det oppstod en feil ved forsøk på å avfølge dette registrerte navnet. Prøv på nytt!",
+ "schange24": "Det oppstod en feil ved forsøk på å blokkere dette registrerte navnet. Prøv på nytt!",
+ "schange25": "Det oppstod en feil ved forsøk på å oppheve blokkeringen av dette registrerte navnet. Prøv på nytt!",
+ "schange26": "Ukategorisert",
+ "schange27": "Størrelse",
+ "schange28": "Status",
+ "schange29": "Følg",
+ "schange30": "Avfølg",
+ "schange31": "Blokker",
+ "schange32": "Opphev blokkering",
+ "schange33": "Navn å søke på",
+ "schange34": "Navn kan ikke være tomt!",
+ "schange35": "Søk",
+ "schange36": "Last ned",
+ "schange37": "Nedlastet",
+ "schange38": "Oppdater",
+ "schange39": "Åpne",
+ "schange40": "Forhåndsvisning",
+ "schange41": "Laster ned, vennligst vent...",
+ "schange42": "Filer lastet ned",
+ "schange43": "Åpne, vennligst vent..."
+ },
"publishpage": {
"pchange1": "Publiser",
"pchange2": "Oppdater",
@@ -581,7 +626,8 @@
"bchange25": "Ingen sensitive data er delt.",
"bchange26": "Autentiser alltid automatisk",
"bchange27": "Avvis",
- "bchange28": "Godta"
+ "bchange28": "Godta",
+ "bchange29": "Øyeblikkelig publisering (krever 0,001 QORT-avgift)"
},
"datapage": {
"dchange1": "Data-administrasjon",
diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json
index 7c52775f..edf68d4b 100644
--- a/qortal-ui-core/language/pl.json
+++ b/qortal-ui-core/language/pl.json
@@ -526,6 +526,51 @@
"schange41": "Pobieranie, proszę czekać...",
"schange42": "Pliki pobrane"
},
+ "tubespage": {
+ "schange1": "Przeglądaj Q-Tubes",
+ "schange2": "Obserwowano Q-Tubes",
+ "schange3": "Zablokowane Q-Tubes",
+ "schange4": "Wyszukaj Q-Tubes",
+ "schange5": "Okładka",
+ "schange6": "Szczegóły",
+ "schange7": "Opublikowane przez",
+ "schange8": "Akcje",
+ "schange9": "Q-Tubes",
+ "schange10": "Brak dostępnych q-tubes",
+ "schange11": "Twoje obserwowane Q-Tubes",
+ "schange12": "Obserwowano Q-Tubes",
+ "schange13": "Nie obserwujesz żadnych q-tubes",
+ "schange14": "Twoje zablokowane Q-Tubes",
+ "schange15": "Zablokowane Q-Tubes",
+ "schange16": "Nie zablokowałeś żadnych q-tubes",
+ "schange17": "Nie znaleziono nazwy!",
+ "schange18": "Tryb przekazywania jest włączony. Oznacza to, że twój węzeł pomoże w transporcie zaszyfrowanych danych w sieci, gdy zażąda tego peer. Możesz zrezygnować, ustawiając",
+ "schange19": "w",
+ "schange20": "Tryb przekaźnika jest wyłączony. Możesz go włączyć, ustawiając",
+ "schange21": "Opublikuj wideo",
+ "schange22": "Wystąpił błąd podczas próby śledzenia tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange23": "Wystąpił błąd podczas próby zaprzestania obserwowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange24": "Wystąpił błąd podczas próby zablokowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange25": "Wystąpił błąd podczas próby odblokowania tej zarejestrowanej nazwy. Spróbuj ponownie!",
+ "schange26": "Bez kategorii",
+ "schange27": "Rozmiar",
+ "schange28": "Status",
+ "schange29": "Obserwuj",
+ "schange30": "Przestań obserwować",
+ "schange31": "Zablokuj",
+ "schange32": "Odblokuj",
+ "schange33": "Nazwa do wyszukania",
+ "schange34": "Nazwa nie może być pusta!",
+ "schange35": "Szukaj",
+ "schange36": "Pobierz",
+ "schange37": "Pobrano",
+ "schange38": "Aktualizacja",
+ "schange39": "Otwórz",
+ "schange40": "Podgląd",
+ "schange41": "Pobieranie, proszę czekać...",
+ "schange42": "Pliki pobrane",
+ "schange43": "Otwórz, proszę czekać..."
+ },
"publishpage": {
"pchange1": "Opublikuj",
"pchange2": "Aktualizuj",
@@ -581,7 +626,8 @@
"bchange25": "Żadne wrażliwe dane nie są udostępniane.",
"bchange26": "Zawsze uwierzytelniaj automatycznie",
"bchange27": "Odrzuć",
- "bchange28": "Akceptuj"
+ "bchange28": "Akceptuj",
+ "bchange29": "Natychmiastowa publikacja (wymagana opłata QORT 0,001)"
},
"datapage": {
"dchange1": "Zarządzanie danymi",
diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json
index e2f53832..979c7f9c 100644
--- a/qortal-ui-core/language/pt.json
+++ b/qortal-ui-core/language/pt.json
@@ -526,6 +526,51 @@
"schange41": "Baixando, por favor, aguarde...",
"schange42": "Arquivos baixados"
},
+ "tubespage": {
+ "schange1": "Navegar Q-Tubes",
+ "schange2": "Q-Tubes seguidos",
+ "schange3": "Q-Tubes bloqueados",
+ "schange4": "Pesquisar Q-Tubes",
+ "schange5": "Capa",
+ "schange6": "Detalhes",
+ "schange7": "Publicado por",
+ "schange8": "Ações",
+ "schange9": "Q-Tubes",
+ "schange10": "Nenhum q-tubes disponível",
+ "schange11": "Seus Q-Tubes seguidos",
+ "schange12": "Q-Tubes seguidos",
+ "schange13": "Você não está seguindo nenhum q-tubes",
+ "schange14": "Seus Q-Tubes bloqueados",
+ "schange15": "Q-Tubes bloqueados",
+ "schange16": "Você não bloqueou nenhum q-tubes",
+ "schange17": "Nome não encontrado!",
+ "schange18": "O modo de retransmissão está ativado. Isso significa que seu nó ajudará a transportar dados criptografados pela rede quando um ponto solicitar. Você pode optar por não configurar",
+ "schange19": "em",
+ "schange20": "O modo relé está desativado. Você pode ativá-lo configurando",
+ "schange21": "Publicar vídeo",
+ "schange22": "Ocorreu erro ao tentar seguir esse nome registrado. Por favor, tente de novo!",
+ "schange23": "Ocorreu erro ao tentar desseguir esse nome registrado. Por favor, tente de novo!",
+ "schange24": "Ocorreu erro ao tentar bloquear esse nome registrado. Por favor, tente de novo!",
+ "schange25": "O erro ocorreu ao tentar desbloquear esse nome registrado. Por favor, tente de novo!",
+ "schange26": "Não categorizado",
+ "schange27": "Tamanho",
+ "schange28": "Status",
+ "schange29": "Seguir",
+ "schange30": "Desseguir",
+ "schange31": "Bloquear",
+ "schange32": "Desbloquear",
+ "schange33": "Nome para pesquisar",
+ "schange34": "Nome não pode estar vazio!",
+ "schange35": "Pesquisar",
+ "schange36": "Baixar",
+ "schange37": "Baixado",
+ "schange38": "Atualizar",
+ "schange39": "Abrir",
+ "schange40": "Pré-visualização",
+ "schange41": "Baixando, por favor, aguarde...",
+ "schange42": "Arquivos baixados",
+ "schange43": "Abrir, por favor, aguarde..."
+ },
"publishpage": {
"pchange1": "Publicar",
"pchange2": "Atualizar",
@@ -581,7 +626,8 @@
"bchange25": "Nenhum dado confidencial é compartilhado.",
"bchange26": "Sempre autenticar automaticamente",
"bchange27": "Rejeitar",
- "bchange28": "Aceitar"
+ "bchange28": "Aceitar",
+ "bchange29": "Publicação instantânea (requer taxa QORT de 0,001)"
},
"datapage": {
"dchange1": "Gerenciamento de Dados",
diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json
index 97074371..4204be46 100644
--- a/qortal-ui-core/language/ro.json
+++ b/qortal-ui-core/language/ro.json
@@ -526,6 +526,51 @@
"schange41": "Se descarcă, așteptați...",
"schange42": "Fișiere descărcate"
},
+ "tubespage": {
+ "schange1": "Răsfoiți Q-Tubes",
+ "schange2": "Urmărite Q-Tubes",
+ "schange3": "Tube Q-Tubes",
+ "schange4": "Căutați Q-Tubes",
+ "schange5": "Copertă",
+ "schange6": "Detalii",
+ "schange7": "Publicat de",
+ "schange8": "Acțiuni",
+ "schange9": "Q-Tubes",
+ "schange10": "Nu există q-tubes disponibile",
+ "schange11": "Q-Tubes urmărite",
+ "schange12": "Urmărite Q-Tubes",
+ "schange13": "Nu urmăriți niciun q-tubes",
+ "schange14": "Q-Tubes blocate",
+ "schange15": "Q-Tubes blocate",
+ "schange16": "Nu ați blocat niciun q-tubes",
+ "schange17": "Numele nu a fost găsit!",
+ "schange18": "Modul de retransmisie este activat. Aceasta înseamnă că nodul dvs. va ajuta la transportul datelor criptate în rețea atunci când un peer o solicită. Puteți renunța prin setare",
+ "schange19": "în",
+ "schange20": "Modul releu este dezactivat. Îl puteți activa setând",
+ "schange21": "Publicați videoclipul",
+ "schange22": "A aparut o eroare atunci cand ati incercat sa urmariti acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange23": "A aparut o eroare atunci cand ati incercat sa dezactivati urmarirea acestui nume inregistrat. Va rugam sa incercati din nou!",
+ "schange24": "A aparut o eroare in timpul incercarii de a bloca acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange25": "A aparut o eroare atunci cand ati incercat sa deblocati acest nume inregistrat. Va rugam sa incercati din nou!",
+ "schange26": "Neclasificat",
+ "schange27": "Dimensiune",
+ "schange28": "Stare",
+ "schange29": "Urmareste",
+ "schange30": "Opreste urmarirea",
+ "schange31": "Blocheaza",
+ "schange32": "Deblocheaza",
+ "schange33": "Numele cautat",
+ "schange34": "Numele nu poate fi gol!",
+ "schange35": "Cauta",
+ "schange36": "Descărcați",
+ "schange37": "Descărcat",
+ "schange38": "Actualizare",
+ "schange39": "Deschide",
+ "schange40": "Previzualizare",
+ "schange41": "Se descarcă, așteptați...",
+ "schange42": "Fișiere descărcate",
+ "schange43": "Deschideți, așteptați..."
+ },
"publishpage": {
"pchange1": "Publica",
"pchange2": "Actualizeaza",
@@ -581,7 +626,8 @@
"bchange25": "Nu sunt partajate date sensibile.",
"bchange26": "Autentificați-vă întotdeauna automat",
"bchange27": "Respinge",
- "bchange28": "Accept"
+ "bchange28": "Accept",
+ "bchange29": "Publicare instantanee (necesită o taxă QORT de 0,001)"
},
"datapage": {
"dchange1": "Gestionare date",
diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json
index 870b26ef..8d0763f0 100644
--- a/qortal-ui-core/language/rs.json
+++ b/qortal-ui-core/language/rs.json
@@ -526,6 +526,51 @@
"schange41": "Preuzimanje molim sačekajte...",
"schange42": "Preuzete datoteke"
},
+ "tubespage": {
+ "schange1": "Pregledaj Q-Tubes",
+ "schange2": "Praćene Q-Tubes",
+ "schange3": "Blokirane Q-Tubes",
+ "schange4": "Pretraži Q-Tubes",
+ "schange5": "Poklopac",
+ "schange6": "Detalji",
+ "schange7": "Objavio",
+ "schange8": "Radnje",
+ "schange9": "Q-Tubes",
+ "schange10": "Nije dostupne q-tubes",
+ "schange11": "Vaše praćene Q-Tubes",
+ "schange12": "Praćene Q-Tubes",
+ "schange13": "Ne pratite nijednu q-tubes",
+ "schange14": "Vaše blokirane Q-Tubes",
+ "schange15": "Blokirane Q-Tubes",
+ "schange16": "Niste blokirali nijednu q-tubes",
+ "schange17": "Ime nije pronađeno!",
+ "schange18": "Relejni režim je omogućen. To znači da će vaš čvor pomoći da se šifrovane podatke transportuju po mreži kada kolega to zatraži. Možete isključiti podešavanjem",
+ "schange19": "u",
+ "schange20": "Relejni režim je onemogućen. Možete ga omogućiti podešavanjem",
+ "schange21": "Objavi video",
+ "schange22": "Desila se greška pri pokušaju praćenja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange23": "Desila se greška pri pokušaju otpraćivanja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange24": "Desila se greška pri pokušaju blokiranja ovog registrovanog imena. Molim pokušajte ponovo!",
+ "schange25": "Desila se greška pri pokušaju odblokiranja ovog rebgistrovanog imena. Molim pokušajte ponovo!",
+ "schange26": "Nekategorizovano",
+ "schange27": "Veličina",
+ "schange28": "Status",
+ "schange29": "Pratite",
+ "schange30": "Otpratite",
+ "schange31": "Blokirajte",
+ "schange32": "Odblokirajte",
+ "schange33": "Ime za pretragu",
+ "schange34": "Ime ne može biti prazno!",
+ "schange35": "Pretraga",
+ "schange36": "Preuzmi",
+ "schange37": "Preuzeto",
+ "schange38": "Ažuriraj",
+ "schange39": "Otvori",
+ "schange40": "Pregled",
+ "schange41": "Preuzimanje molim sačekajte...",
+ "schange42": "Preuzete datoteke",
+ "schange43": "Отвори молим сачекајте..."
+ },
"publishpage": {
"pchange1": "Objavite",
"pchange2": "Ažurirajte",
@@ -581,7 +626,8 @@
"bchange25": "Ne dele se nikakvi osetljivi podaci.",
"bchange26": "Uvek automatski autentifikovati",
"bchange27": "Odbaci",
- "bchange28": "Prihvatam"
+ "bchange28": "Prihvatam",
+ "bchange29": "Trenutno objavljivanje (zahteva 0,001 QORT naknade)"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json
index b4dd1efa..ae04ae3d 100644
--- a/qortal-ui-core/language/ru.json
+++ b/qortal-ui-core/language/ru.json
@@ -526,6 +526,51 @@
"schange41": "Идет загрузка, подождите...",
"schange42": "Файлы загружены"
},
+ "tubespage": {
+ "schange1": "Просмотреть Q-Tubes",
+ "schange2": "Следил за Q-Tubes",
+ "schange3": "Заблокированные Q-Tubes",
+ "schange4": "Поиск на Q-Tubes",
+ "schange5": "Обложка",
+ "schange6": "Подробнее",
+ "schange7": "Опубликовано",
+ "schange8": "Действия",
+ "schange9": "Q-Tubes",
+ "schange10": "Нет доступных q-tubes",
+ "schange11": "Ваши подписчики Q-Tubes",
+ "schange12": "Следил за Q-Tubes",
+ "schange13": "Вы не подписаны ни на один q-tubes",
+ "schange14": "Ваши заблокированные Q-Tubes",
+ "schange15": "Заблокированные Q-Tubes",
+ "schange16": "Вы не заблокировали ни одну q-tubes",
+ "schange17": "Имя не найдено!",
+ "schange18": "Режим ретрансляции включен. Это означает, что ваш узел будет помогать передавать зашифрованные данные по сети, когда их запрашивает одноранговый узел. Вы можете отказаться, настроив",
+ "schange19": "в",
+ "schange20": "Режим реле отключен. Вы можете включить его в настройках",
+ "schange21": "Опубликовать видео",
+ "schange22": "Произошла ошибка при попытке подписаться на это зарегистрированное имя. Повторите попытку!",
+ "schange23": "Произошла ошибка при попытке отписаться от этого зарегистрированного имени. Повторите попытку!",
+ "schange24": "Произошла ошибка при попытке заблокировать это зарегистрированное имя. Повторите попытку!",
+ "schange25": "Произошла ошибка при попытке разблокировать это зарегистрированное имя. Пожалуйста, попробуйте еще раз!",
+ "schange26": "Без категории",
+ "schange27": "Размер",
+ "schange28": "Статус",
+ "schange29": "Подписаться",
+ "schange30": "Отписаться",
+ "schange31": "Заблокировать",
+ "schange32": "Разблокировать",
+ "schange33": "Имя для поиска",
+ "schange34": "Имя не может быть пустым!",
+ "schange35": "Поиск",
+ "schange36": "Скачать",
+ "schange37": "Скачано",
+ "schange38": "Обновить",
+ "schange39": "Открыть",
+ "schange40": "Предварительный просмотр",
+ "schange41": "Идет загрузка, подождите...",
+ "schange42": "Файлы загружены",
+ "schange43": "Откройте, пожалуйста, подождите..."
+ },
"publishpage": {
"pchange1": "Опубликовать",
"pchange2": "Обновить",
@@ -581,7 +626,8 @@
"bchange25": "Конфиденциальные данные не передаются.",
"bchange26": "Всегда аутентифицироваться автоматически",
"bchange27": "Отклонить",
- "bchange28": "Принять"
+ "bchange28": "Принять",
+ "bchange29": "Мгновенная публикация (требуется плата в размере 0,001 QORT)"
},
"datapage": {
"dchange1": "Управление данными",
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 8db1812a..ca60692d 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -526,6 +526,51 @@
"schange41": "Downloading please wait...",
"schange42": "Files downloaded"
},
+ "tubespage": {
+ "schange1": "Browse Q-Tubes",
+ "schange2": "Followed Q-Tubes",
+ "schange3": "Blocked Q-Tubes",
+ "schange4": "Search Q-Tubes",
+ "schange5": "Cover",
+ "schange6": "Details",
+ "schange7": "Published by",
+ "schange8": "Actions",
+ "schange9": "Q-Tubes",
+ "schange10": "No q-tubes available",
+ "schange11": "Your Followed Q-Tubes",
+ "schange12": "Followed Q-Tubes",
+ "schange13": "You aren't following any q-tubes",
+ "schange14": "Your Blocked Q-Tubes",
+ "schange15": "Blocked Q-Tubes",
+ "schange16": "You have not blocked any q-tubes",
+ "schange17": "Name Not Found!",
+ "schange18": "Relay mode is enabled. This means that your node will help to transport encrypted data around the network when a peer requests it. You can opt out by setting",
+ "schange19": "in",
+ "schange20": "Relay mode is disabled. You can enable it by setting",
+ "schange21": "Publish Video",
+ "schange22": "Error occurred when trying to follow this registered name. Please try again!",
+ "schange23": "Error occurred when trying to unfollow this registered name. Please try again!",
+ "schange24": "Error occurred when trying to block this registered name. Please try again!",
+ "schange25": "Error occurred when trying to unblock this registered name. Please try again!",
+ "schange26": "Uncategorized",
+ "schange27": "Size",
+ "schange28": "Status",
+ "schange29": "Follow",
+ "schange30": "Unfollow",
+ "schange31": "Block",
+ "schange32": "Unblock",
+ "schange33": "Name to search",
+ "schange34": "Name can not be empty!",
+ "schange35": "Search",
+ "schange36": "Download",
+ "schange37": "Downloaded",
+ "schange38": "Update",
+ "schange39": "Open",
+ "schange40": "Preview",
+ "schange41": "Downloading please wait...",
+ "schange42": "Files downloaded",
+ "schange43": "Open please wait..."
+ },
"publishpage": {
"pchange1": "Publish",
"pchange2": "Update",
diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json
index 391681f7..38c9eedd 100644
--- a/qortal-ui-core/language/zhc.json
+++ b/qortal-ui-core/language/zhc.json
@@ -526,6 +526,51 @@
"schange41": "下载中请稍候...",
"schange42": "文件已下载"
},
+ "tubespage": {
+ "schange1": "浏览 Q-Tubes",
+ "schange2": "关注 Q-Tubes",
+ "schange3": "阻塞的 Q-Tubes",
+ "schange4": "搜索 Q-Tubes",
+ "schange5": "封面",
+ "schange6": "详情",
+ "schange7": "发布者",
+ "schange8": "动作",
+ "schange9": "Q-Tubes",
+ "schange10": "没有可用的 q-tubes",
+ "schange11": "您关注的 Q-Tubes",
+ "schange12": "关注 Q-Tubes",
+ "schange13": "你没有关注任何 q-tubes",
+ "schange14": "你阻塞的 Q-Tubes",
+ "schange15": "阻塞的 Q-Tubes",
+ "schange16": "你没有阻塞任何 q-tubes",
+ "schange17": "找不到名字!",
+ "schange18": "中继模式已启用。这意味着您的节点将在对等点请求时帮助在网络中传输加密数据。您可以通过设置选择退出",
+ "schange19": "在",
+ "schange20": "中继模式已禁用。您可以通过设置启用它",
+ "schange21": "发布视频",
+ "schange22": "尝试关注此注册名称时发生错误。 请再试一次!",
+ "schange23": "尝试取消关注此注册名称时发生错误。 请再试一次!",
+ "schange24": "尝试封锁此注册名称时发生错误。 请再试一次!",
+ "schange25": "尝试解封此注册名称时发生错误。 请再试一次!",
+ "schange26": "未分类",
+ "schange27": "大小",
+ "schange28": "状态",
+ "schange29": "关注",
+ "schange30": "取消关注",
+ "schange31": "封锁",
+ "schange32": "解除封锁",
+ "schange33": "输入需要搜寻的名称",
+ "schange34": "名称不能为空!",
+ "schange35": "搜寻",
+ "schange36": "下载",
+ "schange37": "已下载",
+ "schange38": "更新",
+ "schange39": "打开",
+ "schange40": "预览",
+ "schange41": "下载中请稍候...",
+ "schange42": "文件已下载",
+ "schange43": "打开请稍候..."
+ },
"publishpage": {
"pchange1": "发布",
"pchange2": "更新",
@@ -581,7 +626,8 @@
"bchange25": "没有共享敏感数据。",
"bchange26": "始终自动验证",
"bchange27": "拒绝",
- "bchange28": "接受"
+ "bchange28": "接受",
+ "bchange29": "即时发布(需要 0.001 QORT 费用)"
},
"datapage": {
"dchange1": "资料管理",
diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json
index 2f919c07..d8a44903 100644
--- a/qortal-ui-core/language/zht.json
+++ b/qortal-ui-core/language/zht.json
@@ -526,6 +526,51 @@
"schange41": "下載中請稍候...",
"schange42": "文件已下載"
},
+ "tubespage": {
+ "schange1": "瀏覽 Q-Tubes",
+ "schange2": "關注 Q-Tubes",
+ "schange3": "阻塞的 Q-Tubes",
+ "schange4": "搜索 Q-Tubes",
+ "schange5": "封面",
+ "schange6": "詳情",
+ "schange7": "發布者",
+ "schange8": "動作",
+ "schange9": "Q-Tubes",
+ "schange10": "沒有可用的 q-tubes",
+ "schange11": "您關注的 Q-Tubes",
+ "schange12": "關注 Q-Tubes",
+ "schange13": "你沒有關注任何 q-tubes",
+ "schange14": "你阻塞的 Q-Tubes",
+ "schange15": "阻塞的 Q-Tubes",
+ "schange16": "你沒有阻塞任何 q-tubes",
+ "schange17": "找不到名字!",
+ "schange18": "中繼模式已啟用。這意味著您的節點將在對等點請求時幫助在網絡中傳輸加密數據。您可以通過設置選擇退出",
+ "schange19": "在",
+ "schange20": "中繼模式已禁用。您可以通過設置啟用它",
+ "schange21": "發布視頻",
+ "schange22": "嘗試關注此註冊名稱時發生錯誤。 請再試一次!",
+ "schange23": "嘗試取消關注此註冊名稱時發生錯誤。 請再試一次!",
+ "schange24": "嘗試封鎖此註冊名稱時發生錯誤。 請再試一次!",
+ "schange25": "嘗試解封此註冊名稱時發生錯誤。 請再試一次!",
+ "schange26": "未分類",
+ "schange27": "大小",
+ "schange28": "狀態",
+ "schange29": "關注",
+ "schange30": "取消關注",
+ "schange31": "封鎖",
+ "schange32": "解除封鎖",
+ "schange33": "輸入需要搜尋的名稱",
+ "schange34": "名稱不能為空!",
+ "schange35": "搜尋",
+ "schange36": "下載",
+ "schange37": "已下載",
+ "schange38": "更新",
+ "schange39": "打開",
+ "schange40": "預覽",
+ "schange41": "下載中請稍候...",
+ "schange42": "文件已下載",
+ "schange43": "打開請稍等..."
+ },
"publishpage": {
"pchange1": "發佈",
"pchange2": "更新",
@@ -581,7 +626,8 @@
"bchange25": "沒有共享敏感數據。",
"bchange26": "始終自動驗證",
"bchange27": "拒絕",
- "bchange28": "接受"
+ "bchange28": "接受",
+ "bchange29": "即時發布(需要 0.001 QORT 費用)"
},
"datapage": {
"dchange1": "資料管理",
From 94218497c56a66df612cc6080b8c9cf53be00374 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Tue, 21 Mar 2023 11:58:02 +0100
Subject: [PATCH 60/83] Fix translations
---
qortal-ui-core/language/de.json | 8 ++++----
qortal-ui-core/language/hu.json | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index 7db218eb..253020f4 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -529,14 +529,14 @@
"tubespage": {
"schange1": "Q-Tubes durchsuchen",
"schange2": "Verfolgte Q-Tubes",
- "schange3": "Blockierte Q-Röhren",
+ "schange3": "Blockierte Q-Tubes",
"schange4": "Suche Q-Tubes",
- "schange5": "Abdeckung",
+ "schange5": "Cover",
"schange6": "Details",
"schange7": "Herausgegeben von",
"schange8": "Aktionen",
- "schange9": "Q-Röhren",
- "schange10": "Keine Q-Röhrchen verfügbar",
+ "schange9": "Q-Tubes",
+ "schange10": "Keine Q-Tubes verfügbar",
"schange11": "Ihre gefolgten Q-Tubes",
"schange12": "Verfolgte Q-Tubes",
"schange13": "Du folgst keinen Q-Tubes",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index 01e9c7d6..f39e5a6f 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -527,10 +527,10 @@
"schange42": "Fájlok letöltve"
},
"tubespage": {
- "schange1": "Tallózás a Q-Tubes-ban",
+ "schange1": "Tallózás a Q-Tubes",
"schange2": "Követve Q-Tubes",
"schange3": "Blocked Q-Tubes",
- "schange4": "Keresés a Q-Tubes-ban",
+ "schange4": "Keresés a Q-Tubes",
"schange5": "Borító",
"schange6": "Részletek",
"schange7": "Kiadó",
From 19076dbdc6c55f86079f00ee7e302fba61916cb7 Mon Sep 17 00:00:00 2001
From: Phillip
Date: Thu, 23 Mar 2023 23:58:50 +0200
Subject: [PATCH 61/83] qdn publish add name,service, identifier modal
---
qortal-ui-core/language/us.json | 5 ++++-
.../plugins/core/qdn/browser/browser.src.js | 10 +++++++++-
2 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index ca60692d..26614884 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -627,7 +627,10 @@
"bchange26": "Always authenticate automatically",
"bchange27": "Reject",
"bchange28": "Accept",
- "bchange29": "Instant publish (requires 0.001 QORT fee)"
+ "bchange29": "Instant publish (requires 0.001 QORT fee)",
+ "bchange30": "Service",
+ "bchange31": "Name",
+ "bchange32": "Identifier"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 7447906d..97288342 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -557,7 +557,12 @@ class WebBrowser extends LitElement {
identifier = 'default';
}
const res2 = await showModalAndWait(
- actions.PUBLISH_QDN_RESOURCE
+ actions.PUBLISH_QDN_RESOURCE,
+ {
+ name,
+ identifier,
+ service
+ }
);
if (res2.action === 'accept') {
const worker = new WebWorker();
@@ -1577,6 +1582,9 @@ async function showModalAndWait(type, data) {
` : ''}
${type === actions.PUBLISH_QDN_RESOURCE ? `
${get("browserpage.bchange19")}
+
${get("browserpage.bchange30")}: ${data.service}
+
${get("browserpage.bchange31")}: ${data.name}
+
${get("browserpage.bchange32")}: ${data.identifier}
` : ''}
- ${type === actions.PUBLISH_QDN_RESOURCE ? `
+ ${type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES ? `
+
+
+
${get("browserpage.bchange19")}
+
+ ${data.resources.map((resource) => `
+
+ ${get("browserpage.bchange30")}: ${resource.service} |
+ ${get("browserpage.bchange31")}: ${resource.name} |
+ ${get("browserpage.bchange32")}: ${resource.identifier} |
+ ${resource.filename ? `${get("browserpage.bchange34")}: ${resource.filename} | ` : ''}
+
+ `).join('')}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ` : ''}
+ ${type === actions.PUBLISH_QDN_RESOURCE ? `
${get("browserpage.bchange19")}
${get("browserpage.bchange30")}: ${data.service}
${get("browserpage.bchange31")}: ${data.name}
@@ -1593,6 +1761,7 @@ async function showModalAndWait(type, data) {
` : ''}
+
${type === actions.GET_WALLET_BALANCE ? `
${get("browserpage.bchange20")}
` : ''}
${type === actions.SEND_CHAT_MESSAGE ? `
${get("browserpage.bchange22")}
` : ''}
@@ -1609,7 +1778,7 @@ async function showModalAndWait(type, data) {
const okButton = modal.querySelector('#ok-button');
okButton.addEventListener('click', () => {
const userData = {};
- if (type === actions.PUBLISH_QDN_RESOURCE) {
+ if (type === actions.PUBLISH_QDN_RESOURCE || type === actions.PUBLISH_MULTIPLE_QDN_RESOURCES) {
const isWithFeeCheckbox = modal.querySelector('#isWithFee');
userData.isWithFee = isWithFeeCheckbox.checked;
}
From 6364f7f4e342398cd47ab55e5191d355fb90ddd7 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Sun, 26 Mar 2023 21:43:11 +0200
Subject: [PATCH 64/83] Fix publish with tags
---
qortal-ui-plugins/plugins/utils/publish-image.js | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/qortal-ui-plugins/plugins/utils/publish-image.js b/qortal-ui-plugins/plugins/utils/publish-image.js
index 356932c6..b3511283 100644
--- a/qortal-ui-plugins/plugins/utils/publish-image.js
+++ b/qortal-ui-plugins/plugins/utils/publish-image.js
@@ -197,19 +197,19 @@ export const publishData = async ({
uploadDataUrl = uploadDataUrl + '&category=' + encodeURIComponent(category)
}
if(tag1 != null && tag1 != "undefined"){
- uploadDataUrl = uploadDataUrl + '&tag1=' + encodeURIComponent(tag1)
+ uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag1)
}
if(tag2 != null && tag2 != "undefined"){
- uploadDataUrl = uploadDataUrl + '&tag2=' + encodeURIComponent(tag2)
+ uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag2)
}
if(tag3 != null && tag3 != "undefined"){
- uploadDataUrl = uploadDataUrl + '&tag3=' + encodeURIComponent(tag3)
+ uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag3)
}
if(tag4 != null && tag4 != "undefined"){
- uploadDataUrl = uploadDataUrl + '&tag4=' + encodeURIComponent(tag4)
+ uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag4)
}
if(tag5 != null && tag5 != "undefined"){
- uploadDataUrl = uploadDataUrl + '&tag5=' + encodeURIComponent(tag5)
+ uploadDataUrl = uploadDataUrl + '&tags=' + encodeURIComponent(tag5)
}
let uploadDataRes = await parentEpml.request("apiCall", {
From aaabfdc9f7692f85564198a339c72746246fca0d Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Sun, 26 Mar 2023 21:49:37 +0200
Subject: [PATCH 65/83] Modal match ui theme
---
.../plugins/core/qdn/browser/browser.src.js | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index b85ca695..90f7a7a8 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -1710,7 +1710,7 @@ async function showModalAndWait(type, data) {
${get("browserpage.bchange24")} ${data.service.toLowerCase()}.
${get("browserpage.bchange25")}
-
`
}
@@ -99,6 +122,14 @@ class SecurityView extends connect(store)(LitElement) {
stateChanged(state) {
}
+ checkForAuth(e) {
+ if (e.target.checked) {
+ store.dispatch(removeQAPPAutoAuth(false))
+ } else {
+ store.dispatch(allowQAPPAutoAuth(true))
+ }
+ }
+
checkForDownload() {
const checkPass = this.shadowRoot.getElementById('downloadBackupPassword').value
if (checkPass === '') {
From 04c7fbc015ec8f90b7db18c778943d8a1ec14182 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Thu, 13 Apr 2023 16:34:13 +0200
Subject: [PATCH 74/83] Update us.json
---
qortal-ui-core/language/us.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index ec9efb54..c4cb76aa 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -634,7 +634,8 @@
"bchange32": "Identifier",
"bchange33": "Instant publish",
"bchange34": "Filename",
- "bchange35": "Do you give this application permission to send coins?"
+ "bchange35": "Do you give this application permission to send coins?",
+ "bchange36": "Do you want to publish instant to QDN without computing proof-of-work?"
},
"datapage": {
"dchange1": "Data Management",
From bc279c87c1f87a0acb97d646be228ca99e1edd50 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Thu, 13 Apr 2023 16:36:15 +0200
Subject: [PATCH 75/83] add upload instant with fee
---
.../plugins/core/qdn/publish/publish.src.js | 202 +++++++++++-------
1 file changed, 129 insertions(+), 73 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
index 4be8bf2b..705a3782 100644
--- a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
@@ -10,6 +10,7 @@ registerTranslateConfig({
import '@material/mwc-button'
import '@material/mwc-textfield'
import '@material/mwc-select'
+import '@material/mwc-dialog'
import '@material/mwc-list/mwc-list-item.js'
import '@polymer/paper-progress/paper-progress.js'
@@ -55,6 +56,10 @@ class PublishData extends LitElement {
* {
--mdc-theme-primary: rgb(3, 169, 244);
--mdc-theme-secondary: var(--mdc-theme-primary);
+ --mdc-dialog-content-ink-color: var(--black);
+ --mdc-theme-surface: var(--white);
+ --mdc-dialog-min-width: 400px;
+ --mdc-dialog-max-width: 1024px;
--paper-input-container-focus-color: var(--mdc-theme-primary);
--lumo-primary-text-color: rgb(0, 167, 245);
--lumo-primary-color-50pct: rgba(0, 167, 245, 0.5);
@@ -68,7 +73,6 @@ class PublishData extends LitElement {
--_lumo-grid-secondary-border-color: var(--border2);
}
-
input[type=text] {
padding: 6px 6px 6px 6px;
color: var(--black);
@@ -94,7 +98,10 @@ class PublishData extends LitElement {
}
#publishWrapper .buttons {
- width: auto !important;
+ display: flex;
+ justify-content: space-between;
+ max-width:100%;
+ width:100%;
}
mwc-textfield {
@@ -124,16 +131,24 @@ class PublishData extends LitElement {
.address-bar-button mwc-icon {
width: 30px;
}
+
+ .red {
+ --mdc-theme-primary: #F44336;
+ }
+
+ .green {
+ --mdc-theme-primary: #198754;
+ }
`
}
constructor() {
super()
- this.showName = false;
+ this.showName = false
this.showService = false
this.showIdentifier = false
- this.showMetadata = false
+ this.showMetadata = false
const urlParams = new URLSearchParams(window.location.search)
this.name = urlParams.get('name')
@@ -182,7 +197,7 @@ class PublishData extends LitElement {
setTimeout(() => {
this.names = res
if (res[0] != null) {
- this.myRegisteredName = res[0].name;
+ this.myRegisteredName = res[0].name
}
}, 1)
})
@@ -201,7 +216,7 @@ class PublishData extends LitElement {
const fetchPeersSummary = () => {
parentEpml.request('apiCall', {url: `/peers/summary`}).then(res => {
setTimeout(() => {
- this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0);
+ this.portForwardingEnabled = (res.inboundConnections != null && res.inboundConnections > 0)
}, 1)
})
setTimeout(fetchPeersSummary, this.config.user.nodeSettings.pingInterval)
@@ -252,7 +267,7 @@ class PublishData extends LitElement {
this.selectName(e)} style="min-width: 130px; max-width:100%; width:100%;">
- ${this.myRegisteredName}
+ ${this.myRegisteredName}
@@ -269,13 +284,13 @@ class PublishData extends LitElement {
`)}
-
+
-
+
${this.renderUploadField()}
@@ -289,14 +304,22 @@ class PublishData extends LitElement {
${this.successMessage}
${this.loading ? html`
` : ''}
- `
+
+
+ ${translate("browserpage.bchange36")}
${translate("browserpage.bchange29")}
+ this.feeDialogNo(e, false, false)}" class="red">
+ ${translate("general.no")}
+
+ this.feeDialogYes(e, false, true)}" class="green">
+ ${translate("general.yes")}
+
+
+ `
}
firstUpdated() {
@@ -337,11 +360,11 @@ class PublishData extends LitElement {
changeTheme() {
const checkTheme = localStorage.getItem('qortalTheme')
if (checkTheme === 'dark') {
- this.theme = 'dark';
+ this.theme = 'dark'
} else {
- this.theme = 'light';
+ this.theme = 'light'
}
- document.querySelector('html').setAttribute('theme', this.theme);
+ document.querySelector('html').setAttribute('theme', this.theme)
}
changeLanguage() {
@@ -357,7 +380,7 @@ class PublishData extends LitElement {
// Navigation
goBack() {
- window.history.back();
+ window.history.back()
}
@@ -386,8 +409,17 @@ class PublishData extends LitElement {
}
}
+ feeDialogYes(e, preview, fee) {
+ this.doPublish(e, preview, fee)
+ this.shadowRoot.querySelector('#publishWithFeeDialog').close()
+ }
- doPublish(e, preview) {
+ feeDialogNo(e, preview, fee) {
+ this.doPublish(e, preview, fee)
+ this.shadowRoot.querySelector('#publishWithFeeDialog').close()
+ }
+
+ doPublish(e, preview, fee) {
let registeredName = this.shadowRoot.getElementById('registeredName').value
let service = this.shadowRoot.getElementById('service').value
let identifier = this.shadowRoot.getElementById('identifier').value
@@ -397,8 +429,8 @@ class PublishData extends LitElement {
registeredName = this.name
}
- let file;
- let path;
+ let file
+ let path
if (this.uploadType === "file" || this.uploadType === "zip") {
file = this.shadowRoot.getElementById('file').files[0]
@@ -433,11 +465,11 @@ class PublishData extends LitElement {
parentEpml.request('showSnackBar', `${err5string}`)
}
else {
- this.publishData(registeredName, path, file, service, identifier, preview)
+ this.publishData(registeredName, path, file, service, identifier, preview, fee)
}
}
- async publishData(registeredName, path, file, service, identifier, preview) {
+ async publishData(registeredName, path, file, service, identifier, preview, fee) {
this.loading = true
this.btnDisable = true
@@ -463,48 +495,50 @@ class PublishData extends LitElement {
if (validNameRes.error) {
this.errorMessage = "Error: " + validNameRes.message
showError(this.errorMessage)
- throw new Error(this.errorMessage);
+ throw new Error(this.errorMessage)
}
let err6string = get("publishpage.pchange19")
this.generalMessage = `${err6string}`
- let transactionBytes;
- let previewUrlPath;
+ let transactionBytes
+ let previewUrlPath
+
+ let uploadDataRes = await uploadData(registeredName, path, file, preview, fee)
- let uploadDataRes = await uploadData(registeredName, path, file, preview)
if (uploadDataRes.error) {
let err7string = get("publishpage.pchange20")
this.errorMessage = `${err7string}` + uploadDataRes.message
showError(this.errorMessage)
- throw new Error(this.errorMessage);
+ throw new Error(this.errorMessage)
}
else if (uploadDataRes.includes("Error 500 Internal Server Error")) {
let err8string = get("publishpage.pchange21")
this.errorMessage = `${err8string}`
showError(this.errorMessage)
- throw new Error(this.errorMessage);
+ throw new Error(this.errorMessage)
}
if (preview) {
// uploadData() returns preview URL path when in preview mode
- previewUrlPath = uploadDataRes;
- window.location = `../browser/index.html?service=${this.service}&name=Preview&preview=${previewUrlPath}`;
- return;
+ previewUrlPath = uploadDataRes
+ window.location = `../browser/index.html?service=${this.service}&name=Preview&preview=${previewUrlPath}`
+ return
}
else {
// uploadData() returns transaction bytes when not in preview mode
- transactionBytes = uploadDataRes;
+ transactionBytes = uploadDataRes
}
let err9string = get("publishpage.pchange22")
this.generalMessage = `${err9string}`
- let signAndProcessRes = await signAndProcess(transactionBytes)
+ let signAndProcessRes = await signAndProcess(transactionBytes, fee)
+
if (signAndProcessRes.error) {
let err10string = get("publishpage.pchange20")
this.errorMessage = `${err10string}` + signAndProcessRes.message
showError(this.errorMessage)
- throw new Error(this.errorMessage);
+ throw new Error(this.errorMessage)
}
let err11string = get("publishpage.pchange23")
@@ -516,7 +550,7 @@ class PublishData extends LitElement {
this.successMessage = `${err11string}`
}
- const uploadData = async (registeredName, path, file, preview) => {
+ const uploadData = async (registeredName, path, file, preview, fee) => {
let postBody = path
let urlSuffix = ""
if (file != null) {
@@ -532,24 +566,37 @@ class PublishData extends LitElement {
// Base64 encode the file to work around compatibility issues between javascript and java byte arrays
let fileBuffer = new Uint8Array(await file.arrayBuffer())
- postBody = Buffer.from(fileBuffer).toString('base64');
+ postBody = Buffer.from(fileBuffer).toString('base64')
}
// Optional metadata
- let title = encodeURIComponent(this.shadowRoot.getElementById('title').value);
- let description = encodeURIComponent(this.shadowRoot.getElementById('description').value);
- let category = encodeURIComponent(this.shadowRoot.getElementById('category').value);
- let tag1 = encodeURIComponent(this.shadowRoot.getElementById('tag1').value);
- let tag2 = encodeURIComponent(this.shadowRoot.getElementById('tag2').value);
- let tag3 = encodeURIComponent(this.shadowRoot.getElementById('tag3').value);
- let tag4 = encodeURIComponent(this.shadowRoot.getElementById('tag4').value);
- let tag5 = encodeURIComponent(this.shadowRoot.getElementById('tag5').value);
+ let title = encodeURIComponent(this.shadowRoot.getElementById('title').value)
+ let description = encodeURIComponent(this.shadowRoot.getElementById('description').value)
+ let category = encodeURIComponent(this.shadowRoot.getElementById('category').value)
+ let tag1 = encodeURIComponent(this.shadowRoot.getElementById('tag1').value)
+ let tag2 = encodeURIComponent(this.shadowRoot.getElementById('tag2').value)
+ let tag3 = encodeURIComponent(this.shadowRoot.getElementById('tag3').value)
+ let tag4 = encodeURIComponent(this.shadowRoot.getElementById('tag4').value)
+ let tag5 = encodeURIComponent(this.shadowRoot.getElementById('tag5').value)
let metadataQueryString = `title=${title}&description=${description}&category=${category}&tags=${tag1}&tags=${tag2}&tags=${tag3}&tags=${tag4}&tags=${tag5}`
+ let uploadDataUrl = ``
- let uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
- if (identifier != null && identifier.trim().length > 0) {
- uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
+ if (preview) {
+ uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
+ if (identifier != null && identifier.trim().length > 0) {
+ uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}&preview=${new Boolean(preview).toString()}`
+ }
+ } else if (fee) {
+ uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&fee=100000&apiKey=${this.getApiKey()}`
+ if (identifier != null && identifier.trim().length > 0) {
+ uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&fee=100000&apiKey=${this.getApiKey()}`
+ }
+ } else {
+ uploadDataUrl = `/arbitrary/${this.service}/${registeredName}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
+ if (identifier != null && identifier.trim().length > 0) {
+ uploadDataUrl = `/arbitrary/${service}/${registeredName}/${this.identifier}${urlSuffix}?${metadataQueryString}&apiKey=${this.getApiKey()}`
+ }
}
let uploadDataRes = await parentEpml.request('apiCall', {
@@ -571,38 +618,47 @@ class PublishData extends LitElement {
return convertedBytes
}
- const signAndProcess = async (transactionBytesBase58) => {
+ const signAndProcess = async (transactionBytesBase58, fee) => {
let convertedBytesBase58 = await convertBytesForSigning(transactionBytesBase58)
if (convertedBytesBase58.error) {
let err12string = get("publishpage.pchange20")
this.errorMessage = `${err12string}` + convertedBytesBase58.message
showError(this.errorMessage)
- throw new Error(this.errorMessage);
+ throw new Error(this.errorMessage)
}
- const convertedBytes = window.parent.Base58.decode(convertedBytesBase58);
- const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key]; });
+ const convertedBytes = window.parent.Base58.decode(convertedBytesBase58)
+ const _convertedBytesArray = Object.keys(convertedBytes).map(function (key) { return convertedBytes[key] })
const convertedBytesArray = new Uint8Array(_convertedBytesArray)
const convertedBytesHash = new window.parent.Sha256().process(convertedBytesArray).finish().result
- const hashPtr = window.parent.sbrk(32, window.parent.heap);
- const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32);
- hashAry.set(convertedBytesHash);
+ const hashPtr = window.parent.sbrk(32, window.parent.heap)
+ const hashAry = new Uint8Array(window.parent.memory.buffer, hashPtr, 32)
+ hashAry.set(convertedBytesHash)
- const difficulty = 14;
- const workBufferLength = 8 * 1024 * 1024;
- const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap);
+ const difficulty = 14
+ const workBufferLength = 8 * 1024 * 1024
+ const workBufferPtr = window.parent.sbrk(workBufferLength, window.parent.heap)
- this.errorMessage = '';
- this.successMessage = '';
+ this.errorMessage = ''
+ this.successMessage = ''
let nonce = window.parent.computePow(hashPtr, workBufferPtr, workBufferLength, difficulty)
+ let response = false
- let response = await parentEpml.request('sign_arbitrary', {
- nonce: this.selectedAddress.nonce,
- arbitraryBytesBase58: transactionBytesBase58,
- arbitraryBytesForSigningBase58: convertedBytesBase58,
- arbitraryNonce: nonce
- })
+ if (fee) {
+ response = await parentEpml.request('sign_arbitrary_with_fee', {
+ nonce: this.selectedAddress.nonce,
+ arbitraryBytesBase58: transactionBytesBase58,
+ arbitraryBytesForSigningBase58: convertedBytesBase58
+ })
+ } else {
+ response = await parentEpml.request('sign_arbitrary', {
+ nonce: this.selectedAddress.nonce,
+ arbitraryBytesBase58: transactionBytesBase58,
+ arbitraryBytesForSigningBase58: convertedBytesBase58,
+ arbitraryNonce: nonce
+ })
+ }
let myResponse = { error: '' }
if (response === false) {
@@ -641,7 +697,7 @@ class PublishData extends LitElement {
fetchResourceMetadata() {
- let identifier = this.identifier != null ? this.identifier : "default";
+ let identifier = this.identifier != null ? this.identifier : "default"
parentEpml.request('apiCall', {
url: `/arbitrary/metadata/${this.service}/${this.name}/${identifier}?apiKey=${this.getApiKey()}`
@@ -650,10 +706,10 @@ class PublishData extends LitElement {
setTimeout(() => {
this.metadata = res
if (this.metadata != null && this.metadata.category != null) {
- this.shadowRoot.getElementById('category').value = this.metadata.category;
+ this.shadowRoot.getElementById('category').value = this.metadata.category
}
else {
- this.shadowRoot.getElementById('category').value = "";
+ this.shadowRoot.getElementById('category').value = ""
}
}, 1)
})
@@ -666,13 +722,13 @@ class PublishData extends LitElement {
if (name.value.length > 0) {
this.name = (name.value)
}
- this.fetchResourceMetadata();
+ this.fetchResourceMetadata()
}
getApiKey() {
- const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
- let apiKey = myNode.apiKey;
- return apiKey;
+ const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
+ let apiKey = myNode.apiKey
+ return apiKey
}
clearSelection() {
From 61b4a49fdb1a76f37c963b3ed824f4381e6a68c2 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 10:41:03 +0200
Subject: [PATCH 76/83] Update us.json
---
qortal-ui-core/language/us.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index c4cb76aa..33ce763e 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -597,7 +597,8 @@
"pchange22": "Computing proof of work... this can take some time...",
"pchange23": "Transaction successful!",
"pchange24": "Unable to sign and process transaction",
- "pchange25": "Choose File"
+ "pchange25": "Choose File",
+ "pchange26": "Uploading data... this can take some time..."
},
"browserpage": {
"bchange1": "Forward",
From 16d98aced8fb824360e83fc0ea1f335adb0d324f Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 10:42:35 +0200
Subject: [PATCH 77/83] Update publish.src.js
---
.../plugins/core/qdn/publish/publish.src.js | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
index 705a3782..602704d1 100644
--- a/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/publish/publish.src.js
@@ -529,8 +529,13 @@ class PublishData extends LitElement {
transactionBytes = uploadDataRes
}
- let err9string = get("publishpage.pchange22")
- this.generalMessage = `${err9string}`
+ if (fee) {
+ let err9string = get("publishpage.pchange26")
+ this.generalMessage = `${err9string}`
+ } else {
+ let err9string = get("publishpage.pchange22")
+ this.generalMessage = `${err9string}`
+ }
let signAndProcessRes = await signAndProcess(transactionBytes, fee)
From dd801ff68f98ad58bdd317ef1af6f0409f18c40c Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 12:35:35 +0200
Subject: [PATCH 78/83] Update Translations
---
qortal-ui-core/language/de.json | 12 ++++++++++--
qortal-ui-core/language/es.json | 12 ++++++++++--
qortal-ui-core/language/fr.json | 12 ++++++++++--
qortal-ui-core/language/hindi.json | 12 ++++++++++--
qortal-ui-core/language/hr.json | 12 ++++++++++--
qortal-ui-core/language/hu.json | 12 ++++++++++--
qortal-ui-core/language/it.json | 12 ++++++++++--
qortal-ui-core/language/ko.json | 12 ++++++++++--
qortal-ui-core/language/no.json | 12 ++++++++++--
qortal-ui-core/language/pl.json | 12 ++++++++++--
qortal-ui-core/language/pt.json | 12 ++++++++++--
qortal-ui-core/language/ro.json | 12 ++++++++++--
qortal-ui-core/language/rs.json | 12 ++++++++++--
qortal-ui-core/language/ru.json | 12 ++++++++++--
qortal-ui-core/language/zhc.json | 12 ++++++++++--
qortal-ui-core/language/zht.json | 12 ++++++++++--
16 files changed, 160 insertions(+), 32 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index 253020f4..b8b04d8a 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -596,7 +596,8 @@
"pchange22": "Berechnung des Arbeitsnachweises ... dies kann einige Zeit dauern ...",
"pchange23": "Transaktion Erfolgreich!",
"pchange24": "Transaktion kann nicht signiert und verarbeitet werden",
- "pchange25": "Datei wählen"
+ "pchange25": "Datei wählen",
+ "pchange26": "Daten werden hochgeladen... dies kann einige Zeit dauern..."
},
"browserpage": {
"bchange1": "Vorwärts",
@@ -627,7 +628,14 @@
"bchange26": "Immer automatisch authentifizieren",
"bchange27": "Ablehnen",
"bchange28": "Akzeptieren",
- "bchange29": "Sofortige Veröffentlichung (erfordert 0,001 QORT-Gebühr)"
+ "bchange29": "Sofortige Veröffentlichung (erfordert 0,001 QORT-Gebühr)",
+ "bchange30": "Dienst",
+ "bchange31": "Name",
+ "bchange32": "Kennung",
+ "bchange33": "Sofortige Veröffentlichung",
+ "bchange34": "Dateiname",
+ "bchange35": "Erteilen Sie dieser Anwendung die Erlaubnis, Coins zu senden?",
+ "bchange36": "Möchten Sie sofort auf QDN veröffentlichen, ohne einen Proof-of-Work zu berechnen?"
},
"datapage": {
"dchange1": "Datenmanagement",
diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json
index 52be60fe..c4b25b94 100644
--- a/qortal-ui-core/language/es.json
+++ b/qortal-ui-core/language/es.json
@@ -596,7 +596,8 @@
"pchange22": "Computando prueba de trabajo... esto puede tomar un tiempo...",
"pchange23": "Transacción realizada con éxito!",
"pchange24": "No se pudo firmar y procesar la transacción",
- "pchange25": "Elegir archivo"
+ "pchange25": "Elegir archivo",
+ "pchange26": "Cargando datos... esto puede llevar algo de tiempo..."
},
"browserpage": {
"bchange1": "Avanzar",
@@ -627,7 +628,14 @@
"bchange26": "Autenticar siempre automáticamente",
"bchange27": "Rechazar",
"bchange28": "Aceptar",
- "bchange29": "Publicación instantánea (requiere una tarifa de 0.001 QORT)"
+ "bchange29": "Publicación instantánea (requiere una tarifa de 0.001 QORT)",
+ "bchange30": "Servicio",
+ "bchange31": "Nombre",
+ "bchange32": "Identificador",
+ "bchange33": "Publicación instantánea",
+ "bchange34": "Nombre de archivo",
+ "bchange35": "¿Le das permiso a esta aplicación para enviar monedas?",
+ "bchange36": "¿Desea publicar instantáneamente en QDN sin calcular la prueba de trabajo?"
},
"datapage": {
"dchange1": "Gestión de datos",
diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json
index cea21ca9..568be163 100644
--- a/qortal-ui-core/language/fr.json
+++ b/qortal-ui-core/language/fr.json
@@ -596,7 +596,8 @@
"pchange22": "Calcul de la preuve de travail... cela peut prendre un certain temps...",
"pchange23": "Transaction réussie!",
"pchange24": "Impossible de signer et de traiter la transaction",
- "pchange25": "Choisissez un fichier"
+ "pchange25": "Choisissez un fichier",
+ "pchange26": "Télécharger des données... cela peut prendre un certain temps..."
},
"browserpage": {
"bchange1": "En avant",
@@ -627,7 +628,14 @@
"bchange26": "Toujours s'authentifier automatiquement",
"bchange27": "Rejeter",
"bchange28": "Accepter",
- "bchange29": "Publication instantanée (nécessite des frais de 0,001 QORT)"
+ "bchange29": "Publication instantanée (nécessite des frais de 0,001 QORT)",
+ "bchange30": "Service",
+ "bchange31": "Nom",
+ "bchange32": "Identifiant",
+ "bchange33": "Publication instantanée",
+ "bchange34": "Nom de fichier",
+ "bchange35": "Autorisez-vous cette application à envoyer des pièces ?",
+ "bchange36": "Voulez-vous publier instantanément sur QDN sans calculer de preuve de travail ?"
},
"datapage": {
"dchange1": "Gestion de données",
diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json
index 459c7b5b..38444556 100644
--- a/qortal-ui-core/language/hindi.json
+++ b/qortal-ui-core/language/hindi.json
@@ -597,7 +597,8 @@
"pchange22": "काम का सबूत कंप्यूटिंग... इसमें कुछ समय लग सकता है...",
"pchange23": "लेनदेन सफल!",
"pchange24": "लेन-देन पर हस्ताक्षर करने और संसाधित करने में असमर्थ",
- "pchange25": "फ़ाइल चुनें"
+ "pchange25": "फ़ाइल चुनें",
+ "pchange26": "डेटा अपलोड हो रहा है... इसमें कुछ समय लग सकता है..."
},
"browserpage": {
"bchange1": "आगे भेजना",
@@ -628,7 +629,14 @@
"bchange26": "हमेशा स्वचालित रूप से प्रमाणित करें",
"bchange27": "अस्वीकार करें",
"bchange28": "स्वीकार करें",
- "bchange29": "तत्काल प्रकाशन (0.001 QORT शुल्क की आवश्यकता है)"
+ "bchange29": "तत्काल प्रकाशन (0.001 QORT शुल्क की आवश्यकता है)",
+ "bchange30": "सेवा",
+ "bchange31": "नाम",
+ "bchange32": "पहचानकर्ता",
+ "bchange33": "तत्काल प्रकाशन",
+ "bchange34": "फ़ाइल का नाम",
+ "bchange35": "क्या आप इस एप्लिकेशन को सिक्के भेजने की अनुमति देते हैं?",
+ "bchange36": "क्या आप कार्य-प्रमाण की गणना किए बिना QDN पर तुरंत प्रकाशित करना चाहते हैं?"
},
"datapage": {
"dchange1": "डाटा प्रबंधन",
diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json
index 8746ca9a..94de36a4 100644
--- a/qortal-ui-core/language/hr.json
+++ b/qortal-ui-core/language/hr.json
@@ -596,7 +596,8 @@
"pchange22": "Računalni dokaz o poslu ... ovo može potrajati neko vrijeme ...",
"pchange23": "Transakcija uspješna!",
"pchange24": "Nije moguće potpisati i obraditi transakciju",
- "pchange25": "Odaberite datoteku"
+ "pchange25": "Odaberite datoteku",
+ "pchange26": "Učitavanje podataka... ovo može potrajati..."
},
"browserpage": {
"bchange1": "Naprijed",
@@ -627,7 +628,14 @@
"bchange26": "Uvijek autentificiraj automatski",
"bchange27": "Odbaci",
"bchange28": "Prihvati",
- "bchange29": "Trenutno objavljivanje (zahtijeva naknadu od 0,001 QORT)"
+ "bchange29": "Trenutno objavljivanje (zahtijeva naknadu od 0,001 QORT)",
+ "bchange30": "Usluga",
+ "bchange31": "Ime",
+ "bchange32": "Identifikator",
+ "bchange33": "Trenutno objavljivanje",
+ "bchange34": "Naziv datoteke",
+ "bchange35": "Dajete li ovoj aplikaciji dopuštenje za slanje novčića?",
+ "bchange36": "Želite li objaviti instant na QDN bez izračunavanja dokaza o radu?"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index f39e5a6f..f1d202f7 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -596,7 +596,8 @@
"pchange22": "A munka igazolásának számítása... Ez eltarthat egy ideig...",
"pchange23": "A tranzakció sikeres!",
"pchange24": "Nem lehet aláírni és feldolgozni a tranzakciót",
- "pchange25": "Fájl Kiválasztása"
+ "pchange25": "Fájl Kiválasztása",
+ "pchange26": "Adatok feltöltése... ez eltarthat egy ideig..."
},
"browserpage": {
"bchange1": "Előre",
@@ -627,7 +628,14 @@
"bchange26": "Mindig automatikus hitelesítés",
"bchange27": "Elutasítás",
"bchange28": "Elfogadás",
- "bchange29": "Azonnali közzététel (0,001 QORT díj szükséges)"
+ "bchange29": "Azonnali közzététel (0,001 QORT díj szükséges)",
+ "bchange30": "Szolgáltatás",
+ "bchange31": "Név",
+ "bchange32": "Azonosító",
+ "bchange33": "Azonnali közzététel",
+ "bchange34": "Fájlnév",
+ "bchange35": "Engedélyt ad ennek az alkalmazásnak érmék küldésére?",
+ "bchange36": "Szeretne azonnal közzétenni a QDN-ben a munkaigazolás kiszámítása nélkül?"
},
"datapage": {
"dchange1": "Adatkezelés",
diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json
index 9dbdafbf..9990dab9 100644
--- a/qortal-ui-core/language/it.json
+++ b/qortal-ui-core/language/it.json
@@ -596,7 +596,8 @@
"pchange22": "Prova di calcolo del lavoro... questo può richiedere del tempo...",
"pchange23": "Transazione riuscita!",
"pchange24": "Impossibile firmare ed elaborare la transazione",
- "pchange25": "Scegli file"
+ "pchange25": "Scegli file",
+ "pchange26": "Caricamento dei dati... questo può richiedere del tempo..."
},
"browserpage": {
"bchange1": "Avanti",
@@ -627,7 +628,14 @@
"bchange26": "Autenticati sempre automaticamente",
"bchange27": "Rifiuta",
"bchange28": "Accetta",
- "bchange29": "Pubblicazione istantanea (richiede una quota di 0,001 QORT)"
+ "bchange29": "Pubblicazione istantanea (richiede una quota di 0,001 QORT)",
+ "bchange30": "Servizio",
+ "bchange31": "Nome",
+ "bchange32": "Identificativo",
+ "bchange33": "Pubblicazione istantanea",
+ "bchange34": "Nome file",
+ "bchange35": "Concedi a questa applicazione il permesso di inviare monete?",
+ "bchange36": "Vuoi pubblicare istantaneamente su QDN senza calcolare la prova del lavoro?"
},
"datapage": {
"dchange1": "Gestione dati",
diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json
index 02d8cedf..e071b9f0 100644
--- a/qortal-ui-core/language/ko.json
+++ b/qortal-ui-core/language/ko.json
@@ -596,7 +596,8 @@
"pchange22": "작업 증명 계산 중... 시간이 좀 걸릴 수 있어...",
"pchange23": "트랜잭션이 성공했습니다!",
"pchange24": "트랜잭션 서명 및 처리 불가",
- "pchange25": "파일 선택"
+ "pchange25": "파일 선택",
+ "pchange26": "데이터 업로드 중... 시간이 좀 걸릴 수 있습니다..."
},
"browserpage": {
"bchange1": "앞으로",
@@ -627,7 +628,14 @@
"bchange26": "항상 자동으로 인증",
"bchange27": "거부",
"bchange28": "수락",
- "bchange29": "즉시 게시(0.001QORT 수수료 필요)"
+ "bchange29": "즉시 게시(0.001QORT 수수료 필요)",
+ "bchange30": "서비스",
+ "bchange31": "이름",
+ "bchange32": "식별자",
+ "bchange33": "즉시 게시",
+ "bchange34": "파일 이름",
+ "bchange35": "이 애플리케이션에 코인을 보낼 수 있는 권한을 부여하시겠습니까?",
+ "bchange36": "작업 증명을 계산하지 않고 QDN에 즉시 게시하시겠습니까?"
},
"datapage": {
"dchange1": "데이터 관리",
diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json
index e09f8292..d8952d51 100644
--- a/qortal-ui-core/language/no.json
+++ b/qortal-ui-core/language/no.json
@@ -596,7 +596,8 @@
"pchange22": "Databehandler proof of work... dette kan ta litt tid...",
"pchange23": "Transaksjon vellykket!",
"pchange24": "Kan ikke signere og behandle transaksjonen",
- "pchange25": "Velg fil"
+ "pchange25": "Velg fil",
+ "pchange26": "Laster opp data... dette kan ta litt tid..."
},
"browserpage": {
"bchange1": "Frem",
@@ -627,7 +628,14 @@
"bchange26": "Autentiser alltid automatisk",
"bchange27": "Avvis",
"bchange28": "Godta",
- "bchange29": "Øyeblikkelig publisering (krever 0,001 QORT-avgift)"
+ "bchange29": "Øyeblikkelig publisering (krever 0,001 QORT-avgift)",
+ "bchange30": "Tjeneste",
+ "bchange31": "Navn",
+ "bchange32": "Identifikator",
+ "bchange33": "Øyeblikkelig publisering",
+ "bchange34": "Filnavn",
+ "bchange35": "Gir du denne applikasjonen tillatelse til å sende mynter?",
+ "bchange36": "Vil du publisere øyeblikkelig til QDN uten å regne ut bevis på arbeid?"
},
"datapage": {
"dchange1": "Data-administrasjon",
diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json
index edf68d4b..1a3d0bcb 100644
--- a/qortal-ui-core/language/pl.json
+++ b/qortal-ui-core/language/pl.json
@@ -596,7 +596,8 @@
"pchange22": "Obliczanie dowodu pracy... może to zająć trochę czasu...",
"pchange23": "Transakcja powiodła się!",
"pchange24": "Nie można podpisać i przetworzyć transakcji",
- "pchange25": "Wybierz plik"
+ "pchange25": "Wybierz plik",
+ "pchange26": "Ładowanie danych... może to trochę potrwać..."
},
"browserpage": {
"bchange1": "Naprzód",
@@ -627,7 +628,14 @@
"bchange26": "Zawsze uwierzytelniaj automatycznie",
"bchange27": "Odrzuć",
"bchange28": "Akceptuj",
- "bchange29": "Natychmiastowa publikacja (wymagana opłata QORT 0,001)"
+ "bchange29": "Natychmiastowa publikacja (wymagana opłata QORT 0,001)",
+ "bchange30": "Usługa",
+ "bchange31": "Nazwa",
+ "bchange32": "Identyfikator",
+ "bchange33": "Natychmiastowa publikacja",
+ "bchange34": "Nazwa pliku",
+ "bchange35": "Czy zezwalasz tej aplikacji na wysyłanie monet?",
+ "bchange36": "Czy chcesz natychmiast opublikować w QDN bez obliczania dowodu pracy?"
},
"datapage": {
"dchange1": "Zarządzanie danymi",
diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json
index 979c7f9c..81f3d193 100644
--- a/qortal-ui-core/language/pt.json
+++ b/qortal-ui-core/language/pt.json
@@ -596,7 +596,8 @@
"pchange22": "Computando prova de trabalho... isso pode levar algum tempo...",
"pchange23": "Transação bem sucedida!",
"pchange24": "Não foi possível assinar e processar a transação",
- "pchange25": "Escolha um Arqivo"
+ "pchange25": "Escolha um Arqivo",
+ "pchange26": "Carregando dados... isso pode levar algum tempo..."
},
"browserpage": {
"bchange1": "Encaminhar",
@@ -627,7 +628,14 @@
"bchange26": "Sempre autenticar automaticamente",
"bchange27": "Rejeitar",
"bchange28": "Aceitar",
- "bchange29": "Publicação instantânea (requer taxa QORT de 0,001)"
+ "bchange29": "Publicação instantânea (requer taxa QORT de 0,001)",
+ "bchange30": "Serviço",
+ "bchange31": "Nome",
+ "bchange32": "Identificador",
+ "bchange33": "Publicação instantânea",
+ "bchange34": "Nome do arquivo",
+ "bchange35": "Você dá permissão a este aplicativo para enviar moedas?",
+ "bchange36": "Deseja publicar instantaneamente em QDN sem calcular a prova de trabalho?"
},
"datapage": {
"dchange1": "Gerenciamento de Dados",
diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json
index 4204be46..f62b2f8f 100644
--- a/qortal-ui-core/language/ro.json
+++ b/qortal-ui-core/language/ro.json
@@ -596,7 +596,8 @@
"pchange22": "Se calculeaza evidenta contributiei in retea... acest lucru poate dura ceva timp...",
"pchange23": "Tranzactie reusita!",
"pchange24": "Nu s-a putut semna si procesa tranzactia",
- "pchange25": "Alege fisier"
+ "pchange25": "Alege fisier",
+ "pchange26": "Încărcarea datelor... poate dura ceva timp..."
},
"browserpage": {
"bchange1": "Inainte",
@@ -627,7 +628,14 @@
"bchange26": "Autentificați-vă întotdeauna automat",
"bchange27": "Respinge",
"bchange28": "Accept",
- "bchange29": "Publicare instantanee (necesită o taxă QORT de 0,001)"
+ "bchange29": "Publicare instantanee (necesită o taxă QORT de 0,001)",
+ "bchange30": "Serviciul",
+ "bchange31": "Nume",
+ "bchange32": "Identificator",
+ "bchange33": "Publicare instantanee",
+ "bchange34": "Nume fișier",
+ "bchange35": "Acordați acestei aplicații permisiunea de a trimite monede?",
+ "bchange36": "Doriți să publicați instant în QDN fără a calcula dovada de lucru?"
},
"datapage": {
"dchange1": "Gestionare date",
diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json
index 8d0763f0..d51aa26a 100644
--- a/qortal-ui-core/language/rs.json
+++ b/qortal-ui-core/language/rs.json
@@ -596,7 +596,8 @@
"pchange22": "Proračunavanje dokaza o radu... ovo može potrajati...",
"pchange23": "Transakcija uspešna!",
"pchange24": "Nemogućnost potpisa i izvršenja transakcije",
- "pchange25": "Izaberite Datoteku"
+ "pchange25": "Izaberite Datoteku",
+ "pchange26": "Otpremanje podataka... ovo može potrajati..."
},
"browserpage": {
"bchange1": "Prosledite",
@@ -627,7 +628,14 @@
"bchange26": "Uvek automatski autentifikovati",
"bchange27": "Odbaci",
"bchange28": "Prihvatam",
- "bchange29": "Trenutno objavljivanje (zahteva 0,001 QORT naknade)"
+ "bchange29": "Trenutno objavljivanje (zahteva 0,001 QORT naknade)",
+ "bchange30": "Usluga",
+ "bchange31": "Ime",
+ "bchange32": "Identifikator",
+ "bchange33": "Objavljivanje odmah",
+ "bchange34": "Ime datoteke",
+ "bchange35": "Da li ovoj aplikaciji dajete dozvolu za slanje novčića?",
+ "bchange36": "Da li želite da objavite instant na QDN bez izračunavanja dokaza o radu?"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json
index ae04ae3d..9046fcfd 100644
--- a/qortal-ui-core/language/ru.json
+++ b/qortal-ui-core/language/ru.json
@@ -596,7 +596,8 @@
"pchange22": "Вычисление доказательства работы... это может занять некоторое время...",
"pchange23": "Транзакция прошла успешно!",
"pchange24": "Невозможно подписать и обработать транзакцию",
- "pchange25": "Выбрать файл"
+ "pchange25": "Выбрать файл",
+ "pchange26": "Выгрузка данных... это может занять некоторое время..."
},
"browserpage": {
"bchange1": "Вперед",
@@ -627,7 +628,14 @@
"bchange26": "Всегда аутентифицироваться автоматически",
"bchange27": "Отклонить",
"bchange28": "Принять",
- "bchange29": "Мгновенная публикация (требуется плата в размере 0,001 QORT)"
+ "bchange29": "Мгновенная публикация (требуется плата в размере 0,001 QORT)",
+ "bchange30": "Сервис",
+ "bchange31": "Имя",
+ "bchange32": "Идентификатор",
+ "bchange33": "Мгновенная публикация",
+ "bchange34": "Имя файла",
+ "bchange35": "Вы разрешаете этому приложению отправлять монеты?",
+ "bchange36": "Вы хотите опубликовать мгновенную публикацию в QDN без вычисления доказательства работы?"
},
"datapage": {
"dchange1": "Управление данными",
diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json
index 38c9eedd..24990890 100644
--- a/qortal-ui-core/language/zhc.json
+++ b/qortal-ui-core/language/zhc.json
@@ -596,7 +596,8 @@
"pchange22": "计算工作量证明中... 请稍等...",
"pchange23": "发布成功!",
"pchange24": "发布失败!",
- "pchange25": "选择文件"
+ "pchange25": "选择文件",
+ "pchange26": "正在上传数据...这可能需要一些时间..."
},
"browserpage": {
"bchange1": "下一页",
@@ -627,7 +628,14 @@
"bchange26": "始终自动验证",
"bchange27": "拒绝",
"bchange28": "接受",
- "bchange29": "即时发布(需要 0.001 QORT 费用)"
+ "bchange29": "即时发布(需要 0.001 QORT 费用)",
+ "bchange30": "服务",
+ "bchange31": "姓名",
+ "bchange32": "标识符",
+ "bchange33": "即时发布",
+ "bchange34": "文件名",
+ "bchange35": "你允许这个应用程序发送硬币吗?",
+ "bchange36": "你想在不计算工作证明的情况下即时发布到 QDN 吗?"
},
"datapage": {
"dchange1": "资料管理",
diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json
index d8a44903..fb665b06 100644
--- a/qortal-ui-core/language/zht.json
+++ b/qortal-ui-core/language/zht.json
@@ -596,7 +596,8 @@
"pchange22": "計算工作量證明中... 請稍等...",
"pchange23": "發佈成功!",
"pchange24": "發佈失敗!",
- "pchange25": "選擇文件"
+ "pchange25": "選擇文件",
+ "pchange26": "正在上傳數據...這可能需要一些時間..."
},
"browserpage": {
"bchange1": "下一頁",
@@ -627,7 +628,14 @@
"bchange26": "始終自動驗證",
"bchange27": "拒絕",
"bchange28": "接受",
- "bchange29": "即時發布(需要 0.001 QORT 費用)"
+ "bchange29": "即時發布(需要 0.001 QORT 費用)",
+ "bchange30": "服務",
+ "bchange31": "姓名",
+ "bchange32": "標識符",
+ "bchange33": "即時發布",
+ "bchange34": "文件名",
+ "bchange35": "你允許這個應用程序發送硬幣嗎?",
+ "bchange36": "你想在不計算工作證明的情況下即時發佈到 QDN 嗎?"
},
"datapage": {
"dchange1": "資料管理",
From 670df9457db83d57ac7127ad84b89aba5778a84c Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 16:51:39 +0200
Subject: [PATCH 79/83] Added fullscreen function
---
.../plugins/core/qdn/browser/browser.src.js | 109 ++++++++++++------
1 file changed, 75 insertions(+), 34 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 6c1e02d7..8e69858b 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -244,42 +244,81 @@ class WebBrowser extends LitElement {
render() {
return html`
-
-
-
- this.goBack()} title="${translate(
- 'general.back'
- )}" class="address-bar-button">arrow_back_ios
- this.goForward()} title="${translate(
- 'browserpage.bchange1'
- )}" class="address-bar-button">arrow_forward_ios
- this.refresh()} title="${translate(
- 'browserpage.bchange2'
- )}" class="address-bar-button">refresh
- this.goBackToList()} title="${translate(
- 'browserpage.bchange3'
- )}" class="address-bar-button">home
-
- this.delete()} title="${translate(
- 'browserpage.bchange4'
- )} ${this.service} ${this.name} ${translate(
- 'browserpage.bchange5'
- )}" class="address-bar-button float-right">delete
- ${this.renderBlockUnblockButton()}
- ${this.renderFollowUnfollowButton()}
-
-
-
+
+
+
+ this.goBack()} title="${translate('general.back')}" class="address-bar-button">arrow_back_ios
+ this.goForward()} title="${translate('browserpage.bchange1')}" class="address-bar-button">arrow_forward_ios
+ this.refresh()} title="${translate('browserpage.bchange2')}" class="address-bar-button">refresh
+ this.goBackToList()} title="${translate('browserpage.bchange3')}" class="address-bar-button">home
+
+ ${this.renderFullScreen()}
+ this.delete()} title="${translate('browserpage.bchange4')} ${this.service} ${this.name} ${translate('browserpage.bchange5')}" class="address-bar-button float-right">delete
+ ${this.renderBlockUnblockButton()}
+ ${this.renderFollowUnfollowButton()}
+
+
+
+
-
- `;
+ `;
+ }
+
+ renderFullScreen() {
+ if (window.innerHeight == screen.height) {
+ return html`
+
this.exitFullScreen()}
+ title="${translate('browserpage.bchange9')} ${this.name}"
+ class="address-bar-button float-right"
+ >
+ fullscreen_exit
+
+ `
+ } else {
+ return html`
+
this.goFullScreen()}
+ title="${translate('browserpage.bchange9')} ${this.name}"
+ class="address-bar-button float-right"
+ >
+ fullscreen
+
+ `
+ }
+ }
+
+ goFullScreen() {
+ var elem = this.shadowRoot.getElementById('websitesWrapper')
+
+ if (elem.requestFullscreen) {
+ elem.requestFullscreen()
+ } else if (elem.mozRequestFullScreen) {
+ elem.mozRequestFullScreen()
+ } else if (elem.webkitRequestFullscreen) {
+ elem.webkitRequestFullscreen()
+ } else if (elem.msRequestFullscreen) {
+ elem.msRequestFullscreen()
+ }
+
+ this.renderFullScreen()
+ }
+
+ exitFullScreen() {
+ if(document.exitFullscreen) {
+ document.exitFullscreen()
+ } else if (document.mozCancelFullScreen) {
+ document.mozCancelFullScreen()
+ } else if (document.webkitExitFullscreen) {
+ document.webkitExitFullscreen()
+ } else if (document.msExitFullscreen) {
+ document.msExitFullscreen()
+ }
+
+ this.renderFullScreen()
}
async unitJoinFee() {
@@ -2168,9 +2207,11 @@ class WebBrowser extends LitElement {
goBackToList() {
if (this.service == "APP") {
+ this.exitFullScreen()
window.location = '../../q-app/index.html';
}
else { // Default to websites list
+ this.exitFullScreen()
window.location = '../index.html';
}
}
From 77749c97ecd817667c979d05fbf26622812ebb34 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 21:56:28 +0200
Subject: [PATCH 80/83] Add translations
---
qortal-ui-core/language/de.json | 4 +++-
qortal-ui-core/language/es.json | 4 +++-
qortal-ui-core/language/fr.json | 4 +++-
qortal-ui-core/language/hindi.json | 4 +++-
qortal-ui-core/language/hr.json | 4 +++-
qortal-ui-core/language/hu.json | 4 +++-
qortal-ui-core/language/it.json | 4 +++-
qortal-ui-core/language/ko.json | 4 +++-
qortal-ui-core/language/no.json | 4 +++-
qortal-ui-core/language/pl.json | 4 +++-
qortal-ui-core/language/pt.json | 4 +++-
qortal-ui-core/language/ro.json | 4 +++-
qortal-ui-core/language/rs.json | 4 +++-
qortal-ui-core/language/ru.json | 4 +++-
qortal-ui-core/language/us.json | 4 +++-
qortal-ui-core/language/zhc.json | 4 +++-
qortal-ui-core/language/zht.json | 4 +++-
17 files changed, 51 insertions(+), 17 deletions(-)
diff --git a/qortal-ui-core/language/de.json b/qortal-ui-core/language/de.json
index b8b04d8a..313d9aff 100644
--- a/qortal-ui-core/language/de.json
+++ b/qortal-ui-core/language/de.json
@@ -635,7 +635,9 @@
"bchange33": "Sofortige Veröffentlichung",
"bchange34": "Dateiname",
"bchange35": "Erteilen Sie dieser Anwendung die Erlaubnis, Coins zu senden?",
- "bchange36": "Möchten Sie sofort auf QDN veröffentlichen, ohne einen Proof-of-Work zu berechnen?"
+ "bchange36": "Möchten Sie sofort auf QDN veröffentlichen, ohne einen Proof-of-Work zu berechnen?",
+ "bchange37": "Vollbild aufrufen",
+ "bchange38": "Vollbild beenden"
},
"datapage": {
"dchange1": "Datenmanagement",
diff --git a/qortal-ui-core/language/es.json b/qortal-ui-core/language/es.json
index c4b25b94..395d317c 100644
--- a/qortal-ui-core/language/es.json
+++ b/qortal-ui-core/language/es.json
@@ -635,7 +635,9 @@
"bchange33": "Publicación instantánea",
"bchange34": "Nombre de archivo",
"bchange35": "¿Le das permiso a esta aplicación para enviar monedas?",
- "bchange36": "¿Desea publicar instantáneamente en QDN sin calcular la prueba de trabajo?"
+ "bchange36": "¿Desea publicar instantáneamente en QDN sin calcular la prueba de trabajo?",
+ "bchange37": "Ingresar a pantalla completa",
+ "bchange38": "Salir de pantalla completa"
},
"datapage": {
"dchange1": "Gestión de datos",
diff --git a/qortal-ui-core/language/fr.json b/qortal-ui-core/language/fr.json
index 568be163..d55e71a7 100644
--- a/qortal-ui-core/language/fr.json
+++ b/qortal-ui-core/language/fr.json
@@ -635,7 +635,9 @@
"bchange33": "Publication instantanée",
"bchange34": "Nom de fichier",
"bchange35": "Autorisez-vous cette application à envoyer des pièces ?",
- "bchange36": "Voulez-vous publier instantanément sur QDN sans calculer de preuve de travail ?"
+ "bchange36": "Voulez-vous publier instantanément sur QDN sans calculer de preuve de travail ?",
+ "bchange37": "Entrez en plein écran",
+ "bchange38": "Quitter le plein écran"
},
"datapage": {
"dchange1": "Gestion de données",
diff --git a/qortal-ui-core/language/hindi.json b/qortal-ui-core/language/hindi.json
index 38444556..2fc27e4f 100644
--- a/qortal-ui-core/language/hindi.json
+++ b/qortal-ui-core/language/hindi.json
@@ -636,7 +636,9 @@
"bchange33": "तत्काल प्रकाशन",
"bchange34": "फ़ाइल का नाम",
"bchange35": "क्या आप इस एप्लिकेशन को सिक्के भेजने की अनुमति देते हैं?",
- "bchange36": "क्या आप कार्य-प्रमाण की गणना किए बिना QDN पर तुरंत प्रकाशित करना चाहते हैं?"
+ "bchange36": "क्या आप कार्य-प्रमाण की गणना किए बिना QDN पर तुरंत प्रकाशित करना चाहते हैं?",
+ "bchange37": "पूर्णस्क्रीन में प्रवेश करें",
+ "bchange38": "पूर्णस्क्रीन से बाहर निकलें"
},
"datapage": {
"dchange1": "डाटा प्रबंधन",
diff --git a/qortal-ui-core/language/hr.json b/qortal-ui-core/language/hr.json
index 94de36a4..0ef9c7fb 100644
--- a/qortal-ui-core/language/hr.json
+++ b/qortal-ui-core/language/hr.json
@@ -635,7 +635,9 @@
"bchange33": "Trenutno objavljivanje",
"bchange34": "Naziv datoteke",
"bchange35": "Dajete li ovoj aplikaciji dopuštenje za slanje novčića?",
- "bchange36": "Želite li objaviti instant na QDN bez izračunavanja dokaza o radu?"
+ "bchange36": "Želite li objaviti instant na QDN bez izračunavanja dokaza o radu?",
+ "bchange37": "Uđi u cijeli zaslon",
+ "bchange38": "Izađi preko cijelog zaslona"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/hu.json b/qortal-ui-core/language/hu.json
index f1d202f7..d6a5d44b 100644
--- a/qortal-ui-core/language/hu.json
+++ b/qortal-ui-core/language/hu.json
@@ -635,7 +635,9 @@
"bchange33": "Azonnali közzététel",
"bchange34": "Fájlnév",
"bchange35": "Engedélyt ad ennek az alkalmazásnak érmék küldésére?",
- "bchange36": "Szeretne azonnal közzétenni a QDN-ben a munkaigazolás kiszámítása nélkül?"
+ "bchange36": "Szeretne azonnal közzétenni a QDN-ben a munkaigazolás kiszámítása nélkül?",
+ "bchange37": "Belépés a teljes képernyőre",
+ "bchange38": "Kilépés a teljes képernyőről"
},
"datapage": {
"dchange1": "Adatkezelés",
diff --git a/qortal-ui-core/language/it.json b/qortal-ui-core/language/it.json
index 9990dab9..35de8e6c 100644
--- a/qortal-ui-core/language/it.json
+++ b/qortal-ui-core/language/it.json
@@ -635,7 +635,9 @@
"bchange33": "Pubblicazione istantanea",
"bchange34": "Nome file",
"bchange35": "Concedi a questa applicazione il permesso di inviare monete?",
- "bchange36": "Vuoi pubblicare istantaneamente su QDN senza calcolare la prova del lavoro?"
+ "bchange36": "Vuoi pubblicare istantaneamente su QDN senza calcolare la prova del lavoro?",
+ "bchange37": "Entra a schermo intero",
+ "bchange38": "Esci da schermo intero"
},
"datapage": {
"dchange1": "Gestione dati",
diff --git a/qortal-ui-core/language/ko.json b/qortal-ui-core/language/ko.json
index e071b9f0..89cd68c4 100644
--- a/qortal-ui-core/language/ko.json
+++ b/qortal-ui-core/language/ko.json
@@ -635,7 +635,9 @@
"bchange33": "즉시 게시",
"bchange34": "파일 이름",
"bchange35": "이 애플리케이션에 코인을 보낼 수 있는 권한을 부여하시겠습니까?",
- "bchange36": "작업 증명을 계산하지 않고 QDN에 즉시 게시하시겠습니까?"
+ "bchange36": "작업 증명을 계산하지 않고 QDN에 즉시 게시하시겠습니까?",
+ "bchange37": "전체화면으로 전환",
+ "bchange38": "전체화면 종료"
},
"datapage": {
"dchange1": "데이터 관리",
diff --git a/qortal-ui-core/language/no.json b/qortal-ui-core/language/no.json
index d8952d51..a75127c4 100644
--- a/qortal-ui-core/language/no.json
+++ b/qortal-ui-core/language/no.json
@@ -635,7 +635,9 @@
"bchange33": "Øyeblikkelig publisering",
"bchange34": "Filnavn",
"bchange35": "Gir du denne applikasjonen tillatelse til å sende mynter?",
- "bchange36": "Vil du publisere øyeblikkelig til QDN uten å regne ut bevis på arbeid?"
+ "bchange36": "Vil du publisere øyeblikkelig til QDN uten å regne ut bevis på arbeid?",
+ "bchange37": "Gå inn i fullskjerm",
+ "bchange38": "Avslutt fullskjerm"
},
"datapage": {
"dchange1": "Data-administrasjon",
diff --git a/qortal-ui-core/language/pl.json b/qortal-ui-core/language/pl.json
index 1a3d0bcb..b550a5f0 100644
--- a/qortal-ui-core/language/pl.json
+++ b/qortal-ui-core/language/pl.json
@@ -635,7 +635,9 @@
"bchange33": "Natychmiastowa publikacja",
"bchange34": "Nazwa pliku",
"bchange35": "Czy zezwalasz tej aplikacji na wysyłanie monet?",
- "bchange36": "Czy chcesz natychmiast opublikować w QDN bez obliczania dowodu pracy?"
+ "bchange36": "Czy chcesz natychmiast opublikować w QDN bez obliczania dowodu pracy?",
+ "bchange37": "Wejdź na pełny ekran",
+ "bchange38": "Wyjdź z pełnego ekranu"
},
"datapage": {
"dchange1": "Zarządzanie danymi",
diff --git a/qortal-ui-core/language/pt.json b/qortal-ui-core/language/pt.json
index 81f3d193..c24360f8 100644
--- a/qortal-ui-core/language/pt.json
+++ b/qortal-ui-core/language/pt.json
@@ -635,7 +635,9 @@
"bchange33": "Publicação instantânea",
"bchange34": "Nome do arquivo",
"bchange35": "Você dá permissão a este aplicativo para enviar moedas?",
- "bchange36": "Deseja publicar instantaneamente em QDN sem calcular a prova de trabalho?"
+ "bchange36": "Deseja publicar instantaneamente em QDN sem calcular a prova de trabalho?",
+ "bchange37": "Entrar em tela cheia",
+ "bchange38": "Sair da tela cheia"
},
"datapage": {
"dchange1": "Gerenciamento de Dados",
diff --git a/qortal-ui-core/language/ro.json b/qortal-ui-core/language/ro.json
index f62b2f8f..47d767d6 100644
--- a/qortal-ui-core/language/ro.json
+++ b/qortal-ui-core/language/ro.json
@@ -635,7 +635,9 @@
"bchange33": "Publicare instantanee",
"bchange34": "Nume fișier",
"bchange35": "Acordați acestei aplicații permisiunea de a trimite monede?",
- "bchange36": "Doriți să publicați instant în QDN fără a calcula dovada de lucru?"
+ "bchange36": "Doriți să publicați instant în QDN fără a calcula dovada de lucru?",
+ "bchange37": "Intrați pe ecran complet",
+ "bchange38": "Ieșiți din ecranul complet"
},
"datapage": {
"dchange1": "Gestionare date",
diff --git a/qortal-ui-core/language/rs.json b/qortal-ui-core/language/rs.json
index d51aa26a..5fd4f9c5 100644
--- a/qortal-ui-core/language/rs.json
+++ b/qortal-ui-core/language/rs.json
@@ -635,7 +635,9 @@
"bchange33": "Objavljivanje odmah",
"bchange34": "Ime datoteke",
"bchange35": "Da li ovoj aplikaciji dajete dozvolu za slanje novčića?",
- "bchange36": "Da li želite da objavite instant na QDN bez izračunavanja dokaza o radu?"
+ "bchange36": "Da li želite da objavite instant na QDN bez izračunavanja dokaza o radu?",
+ "bchange37": "Uđi u ceo ekran",
+ "bchange38": "Izađi iz celog ekrana"
},
"datapage": {
"dchange1": "Upravljanje podacima",
diff --git a/qortal-ui-core/language/ru.json b/qortal-ui-core/language/ru.json
index 9046fcfd..669be0c1 100644
--- a/qortal-ui-core/language/ru.json
+++ b/qortal-ui-core/language/ru.json
@@ -635,7 +635,9 @@
"bchange33": "Мгновенная публикация",
"bchange34": "Имя файла",
"bchange35": "Вы разрешаете этому приложению отправлять монеты?",
- "bchange36": "Вы хотите опубликовать мгновенную публикацию в QDN без вычисления доказательства работы?"
+ "bchange36": "Вы хотите опубликовать мгновенную публикацию в QDN без вычисления доказательства работы?",
+ "bchange37": "Войти в полноэкранный режим",
+ "bchange38": "Выйти из полноэкранного режима"
},
"datapage": {
"dchange1": "Управление данными",
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 33ce763e..dafef222 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -636,7 +636,9 @@
"bchange33": "Instant publish",
"bchange34": "Filename",
"bchange35": "Do you give this application permission to send coins?",
- "bchange36": "Do you want to publish instant to QDN without computing proof-of-work?"
+ "bchange36": "Do you want to publish instant to QDN without computing proof-of-work?",
+ "bchange37": "Enter Fullscreen",
+ "bchange38": "Exit Fullscreen"
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-core/language/zhc.json b/qortal-ui-core/language/zhc.json
index 24990890..03b27352 100644
--- a/qortal-ui-core/language/zhc.json
+++ b/qortal-ui-core/language/zhc.json
@@ -635,7 +635,9 @@
"bchange33": "即时发布",
"bchange34": "文件名",
"bchange35": "你允许这个应用程序发送硬币吗?",
- "bchange36": "你想在不计算工作证明的情况下即时发布到 QDN 吗?"
+ "bchange36": "你想在不计算工作证明的情况下即时发布到 QDN 吗?",
+ "bchange37": "进入全屏",
+ "bchange38": "退出全屏"
},
"datapage": {
"dchange1": "资料管理",
diff --git a/qortal-ui-core/language/zht.json b/qortal-ui-core/language/zht.json
index fb665b06..4f9fd465 100644
--- a/qortal-ui-core/language/zht.json
+++ b/qortal-ui-core/language/zht.json
@@ -635,7 +635,9 @@
"bchange33": "即時發布",
"bchange34": "文件名",
"bchange35": "你允許這個應用程序發送硬幣嗎?",
- "bchange36": "你想在不計算工作證明的情況下即時發佈到 QDN 嗎?"
+ "bchange36": "你想在不計算工作證明的情況下即時發佈到 QDN 嗎?",
+ "bchange37": "進入全屏",
+ "bchange38": "退出全屏"
},
"datapage": {
"dchange1": "資料管理",
From 79fa6d73c268d99374cd8cc6e454133f0c3427a3 Mon Sep 17 00:00:00 2001
From: AlphaX-Projects <77661270+AlphaX-Projects@users.noreply.github.com>
Date: Fri, 14 Apr 2023 21:59:16 +0200
Subject: [PATCH 81/83] Add fullscreen translation
---
qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 8e69858b..11f95266 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -272,7 +272,7 @@ class WebBrowser extends LitElement {
return html`
this.exitFullScreen()}
- title="${translate('browserpage.bchange9')} ${this.name}"
+ title="${translate('browserpage.bchange38')}"
class="address-bar-button float-right"
>
fullscreen_exit
@@ -282,7 +282,7 @@ class WebBrowser extends LitElement {
return html`
this.goFullScreen()}
- title="${translate('browserpage.bchange9')} ${this.name}"
+ title="${translate('browserpage.bchange37')}"
class="address-bar-button float-right"
>
fullscreen
From 145c06a8357f87b839646456d5ba2a00c338939b Mon Sep 17 00:00:00 2001
From: Phillip
Date: Sat, 15 Apr 2023 20:25:58 +0300
Subject: [PATCH 82/83] add lists modals
---
qortal-ui-core/language/us.json | 9 +-
.../src/components/login-view/login-view.js | 6 +-
.../components/settings-view/security-view.js | 15 +-
.../src/redux/app/actions/app-core.js | 15 +-
.../src/redux/app/app-action-types.js | 2 +
qortal-ui-core/src/redux/app/app-reducer.js | 18 +-
.../core/components/qdn-action-types.js | 11 +-
.../plugins/core/qdn/browser/browser.src.js | 240 +++++++++++++++++-
8 files changed, 305 insertions(+), 11 deletions(-)
diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json
index 33ce763e..1e66e515 100644
--- a/qortal-ui-core/language/us.json
+++ b/qortal-ui-core/language/us.json
@@ -636,7 +636,14 @@
"bchange33": "Instant publish",
"bchange34": "Filename",
"bchange35": "Do you give this application permission to send coins?",
- "bchange36": "Do you want to publish instant to QDN without computing proof-of-work?"
+ "bchange36": "Do you want to publish instant to QDN without computing proof-of-work?",
+ "bchange37": "Do you give this application permission to add to this list?",
+ "bchange38": "Do you give this application permission to delete from this list?",
+ "bchange39": "Always allow lists to be retrieved automatically",
+ "bchange40": "List",
+ "bchange41": "Do you give this application permission to access this list?",
+ "bchange42": "Items"
+
},
"datapage": {
"dchange1": "Data Management",
diff --git a/qortal-ui-core/src/components/login-view/login-view.js b/qortal-ui-core/src/components/login-view/login-view.js
index 257bbf36..928de419 100644
--- a/qortal-ui-core/src/components/login-view/login-view.js
+++ b/qortal-ui-core/src/components/login-view/login-view.js
@@ -14,7 +14,7 @@ import './login-section.js'
import '../qort-theme-toggle.js'
import settings from '../../functional-components/settings-page.js'
-import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth } from '../../redux/app/app-actions.js'
+import { addAutoLoadImageChat, removeAutoLoadImageChat, addChatLastSeen, allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists } from '../../redux/app/app-actions.js'
window.reduxStore = store
window.reduxAction = {
@@ -22,7 +22,9 @@ window.reduxAction = {
removeAutoLoadImageChat: removeAutoLoadImageChat,
addChatLastSeen: addChatLastSeen,
allowQAPPAutoAuth: allowQAPPAutoAuth,
- removeQAPPAutoAuth: removeQAPPAutoAuth
+ removeQAPPAutoAuth: removeQAPPAutoAuth,
+ allowQAPPAutoLists: allowQAPPAutoLists,
+ removeQAPPAutoLists: removeQAPPAutoLists
}
const animationDuration = 0.7 // Seconds
diff --git a/qortal-ui-core/src/components/settings-view/security-view.js b/qortal-ui-core/src/components/settings-view/security-view.js
index f9facaea..aaee8212 100644
--- a/qortal-ui-core/src/components/settings-view/security-view.js
+++ b/qortal-ui-core/src/components/settings-view/security-view.js
@@ -1,7 +1,7 @@
import { LitElement, html, css } from 'lit'
import { connect } from 'pwa-helpers'
import { store } from '../../store.js'
-import { allowQAPPAutoAuth, removeQAPPAutoAuth } from '../../redux/app/app-actions.js'
+import { allowQAPPAutoAuth, removeQAPPAutoAuth, removeQAPPAutoLists, allowQAPPAutoLists } from '../../redux/app/app-actions.js'
import { use, get, translate, translateUnsafeHTML, registerTranslateConfig } from 'lit-translate'
import '@material/mwc-checkbox'
@@ -115,6 +115,12 @@ class SecurityView extends connect(store)(LitElement) {
this.checkForAuth(e)} ?checked=${store.getState().app.qAPPAutoAuth}>
+
+
+ ${get('browserpage.bchange39')}
+
+ this.checkForLists(e)} ?checked=${store.getState().app.qAPPAutoLists}>
+
`
}
@@ -129,6 +135,13 @@ class SecurityView extends connect(store)(LitElement) {
store.dispatch(allowQAPPAutoAuth(true))
}
}
+ checkForLists(e) {
+ if (e.target.checked) {
+ store.dispatch(removeQAPPAutoLists(false))
+ } else {
+ store.dispatch(allowQAPPAutoLists(true))
+ }
+ }
checkForDownload() {
const checkPass = this.shadowRoot.getElementById('downloadBackupPassword').value
diff --git a/qortal-ui-core/src/redux/app/actions/app-core.js b/qortal-ui-core/src/redux/app/actions/app-core.js
index 43d5d57a..35767dae 100644
--- a/qortal-ui-core/src/redux/app/actions/app-core.js
+++ b/qortal-ui-core/src/redux/app/actions/app-core.js
@@ -1,5 +1,5 @@
// Core App Actions here...
-import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from '../app-action-types.js'
+import { UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, CHAT_HEADS, ACCOUNT_INFO, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS } from '../app-action-types.js'
export const doUpdateBlockInfo = (blockObj) => {
return (dispatch, getState) => {
@@ -133,6 +133,19 @@ export const removeQAPPAutoAuth = (payload) => {
payload
}
}
+export const allowQAPPAutoLists = (payload) => {
+ return {
+ type: ALLOW_QAPP_AUTO_LISTS,
+ payload
+ }
+}
+
+export const removeQAPPAutoLists = (payload) => {
+ return {
+ type: REMOVE_QAPP_AUTO_LISTS,
+ payload
+ }
+}
export const setChatLastSeen = (payload) => {
return {
diff --git a/qortal-ui-core/src/redux/app/app-action-types.js b/qortal-ui-core/src/redux/app/app-action-types.js
index 4125e6b1..5ace372c 100644
--- a/qortal-ui-core/src/redux/app/app-action-types.js
+++ b/qortal-ui-core/src/redux/app/app-action-types.js
@@ -24,5 +24,7 @@ export const ADD_AUTO_LOAD_IMAGES_CHAT = 'ADD_AUTO_LOAD_IMAGES_CHAT'
export const REMOVE_AUTO_LOAD_IMAGES_CHAT = 'REMOVE_AUTO_LOAD_IMAGES_CHAT'
export const ALLOW_QAPP_AUTO_AUTH = 'ALLOW_QAPP_AUTO_AUTH'
export const REMOVE_QAPP_AUTO_AUTH = 'REMOVE_QAPP_AUTO_AUTH'
+export const ALLOW_QAPP_AUTO_LISTS = 'ALLOW_QAPP_AUTO_LISTS'
+export const REMOVE_QAPP_AUTO_LISTS = 'REMOVE_QAPP_AUTO_LISTS'
export const SET_CHAT_LAST_SEEN = 'SET_CHAT_LAST_SEEN'
export const ADD_CHAT_LAST_SEEN = 'ADD_CHAT_LAST_SEEN'
diff --git a/qortal-ui-core/src/redux/app/app-reducer.js b/qortal-ui-core/src/redux/app/app-reducer.js
index 6e3849d1..0855ecbf 100644
--- a/qortal-ui-core/src/redux/app/app-reducer.js
+++ b/qortal-ui-core/src/redux/app/app-reducer.js
@@ -1,6 +1,6 @@
// Loading state, login state, isNavDrawOpen state etc. None of this needs to be saved to localstorage.
import { loadStateFromLocalStorage, saveStateToLocalStorage } from '../../localStorageHelpers.js'
-import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN } from './app-action-types.js'
+import { LOG_IN, LOG_OUT, NETWORK_CONNECTION_STATUS, INIT_WORKERS, ADD_PLUGIN_URL, ADD_PLUGIN, ADD_NEW_PLUGIN_URL, NAVIGATE, SELECT_ADDRESS, ACCOUNT_INFO, CHAT_HEADS, UPDATE_BLOCK_INFO, UPDATE_NODE_STATUS, UPDATE_NODE_INFO, LOAD_NODE_CONFIG, SET_NODE, ADD_NODE, PAGE_URL, COPY_MENU_SWITCH, PASTE_MENU_SWITCH, FRAME_PASTE_MENU_SWITCH, ADD_AUTO_LOAD_IMAGES_CHAT, REMOVE_AUTO_LOAD_IMAGES_CHAT, ALLOW_QAPP_AUTO_AUTH, REMOVE_QAPP_AUTO_AUTH, SET_CHAT_LAST_SEEN, ADD_CHAT_LAST_SEEN, ALLOW_QAPP_AUTO_LISTS, REMOVE_QAPP_AUTO_LISTS } from './app-action-types.js'
import { initWorkersReducer } from './reducers/init-workers.js'
import { loginReducer } from './reducers/login-reducer.js'
import { setNode, addNode } from './reducers/manage-node.js'
@@ -51,6 +51,7 @@ const INITIAL_STATE = {
},
autoLoadImageChats: loadStateFromLocalStorage('autoLoadImageChats') || [],
qAPPAutoAuth: loadStateFromLocalStorage('qAPPAutoAuth') || false,
+ qAPPAutoLists: loadStateFromLocalStorage('qAPPAutoLists') || false,
chatLastSeen: []
}
@@ -192,6 +193,21 @@ export default (state = INITIAL_STATE, action) => {
qAPPAutoAuth: action.payload
}
}
+ case ALLOW_QAPP_AUTO_LISTS: {
+ saveStateToLocalStorage("qAPPAutoLists", true)
+ return {
+ ...state,
+ qAPPAutoLists: action.payload
+ }
+ }
+
+ case REMOVE_QAPP_AUTO_LISTS: {
+ saveStateToLocalStorage("qAPPAutoLists", false)
+ return {
+ ...state,
+ qAPPAutoLists: action.payload
+ }
+ }
case SET_CHAT_LAST_SEEN: {
return {
diff --git a/qortal-ui-plugins/plugins/core/components/qdn-action-types.js b/qortal-ui-plugins/plugins/core/components/qdn-action-types.js
index b51caa6f..1eb816a6 100644
--- a/qortal-ui-plugins/plugins/core/components/qdn-action-types.js
+++ b/qortal-ui-plugins/plugins/core/components/qdn-action-types.js
@@ -26,4 +26,13 @@ export const GET_WALLET_BALANCE = 'GET_WALLET_BALANCE';
export const SEND_COIN = 'SEND_COIN';
// PUBLISH_MULTIPLE_QDN_RESOURCES
-export const PUBLISH_MULTIPLE_QDN_RESOURCES = 'PUBLISH_MULTIPLE_QDN_RESOURCES'
\ No newline at end of file
+export const PUBLISH_MULTIPLE_QDN_RESOURCES = 'PUBLISH_MULTIPLE_QDN_RESOURCES'
+
+// GET_LIST_ITEMS
+export const GET_LIST_ITEMS = 'GET_LIST_ITEMS'
+
+// ADD_LIST_ITEMS
+export const ADD_LIST_ITEMS = 'ADD_LIST_ITEMS'
+
+// DELETE_LIST_ITEM
+export const DELETE_LIST_ITEM = 'DELETE_LIST_ITEM'
\ No newline at end of file
diff --git a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
index 8e69858b..13d0ec42 100644
--- a/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
+++ b/qortal-ui-plugins/plugins/core/qdn/browser/browser.src.js
@@ -258,7 +258,7 @@ class WebBrowser extends LitElement {
${this.renderFollowUnfollowButton()}