diff --git a/blog-test.json b/blog-test.json
index 35323b11..04dd800a 100644
--- a/blog-test.json
+++ b/blog-test.json
@@ -7,24 +7,16 @@
"version": 1,
"updated": 1696646223261,
"title": "Q-Blog Post creations",
- "description": "blablabla",
+ "description": "Get your friends Q-Blog posts on your feed",
"search": {
"query": "-post-",
"identifier": "q-blog-",
"service": "BLOG_POST",
"exactmatchnames": true
},
- "click": "qortal://APP/Q-Blog/$${resource.name}$$/$${customParams.blogId}$$/$${customParams.shortIdentifier}$$",
+ "click": "qortal://APP/Q-Blog/$${resource.name}$$/blog/$${resource.identifier}$$",
"display": {
"title": "$${rawdata.title}$$"
- },
- "customParams": {
- "blogId": "**methods.getBlogId(resource)**",
- "shortIdentifier": "**methods.getShortId(resource)**"
- },
- "methods": {
- "getShortId": "return resource.identifier.split('-post-')[1];",
- "getBlogId": "const arr = resource.identifier.split('-post-'); const id = arr[0]; return id.startsWith('q-blog-') ? id.substring(7) : id;"
}
}
]
diff --git a/core/language/us.json b/core/language/us.json
index 8676082d..f9a003ec 100644
--- a/core/language/us.json
+++ b/core/language/us.json
@@ -1212,5 +1212,12 @@
"saving2": "Nothing to save",
"saving3": "Save unsaved changes",
"saving4": "Undo changes"
+ },
+ "profile": {
+ "profile1": "You do not have a name",
+ "profile2": "Go to name registration",
+ "profile3": "Update profile",
+ "profile4": "Tagline",
+ "profile5": "Bio"
}
}
\ No newline at end of file
diff --git a/core/src/components/WebWorkerFile.js b/core/src/components/WebWorkerFile.js
new file mode 100644
index 00000000..3b8c2b87
--- /dev/null
+++ b/core/src/components/WebWorkerFile.js
@@ -0,0 +1,5 @@
+import WebWorker from 'web-worker:./computePowWorkerFile.js';
+
+// You can add any initialization or configuration for the Web Worker here
+
+export default WebWorker;
\ No newline at end of file
diff --git a/core/src/components/app-view.js b/core/src/components/app-view.js
index 1bf6a5fa..bedaeda7 100644
--- a/core/src/components/app-view.js
+++ b/core/src/components/app-view.js
@@ -46,6 +46,7 @@ import './notification-view/notification-bell-general.js'
import './friends-view/friends-side-panel-parent.js'
import './friends-view/save-settings-qdn.js'
import './friends-view/core-sync-status.js'
+import './friends-view/profile.js'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class AppView extends connect(store)(LitElement) {
@@ -584,6 +585,7 @@ class AppView extends connect(store)(LitElement) {
+
diff --git a/core/src/components/computePowWorkerFile.js b/core/src/components/computePowWorkerFile.js
new file mode 100644
index 00000000..d9f5f662
--- /dev/null
+++ b/core/src/components/computePowWorkerFile.js
@@ -0,0 +1,92 @@
+import { Sha256 } from 'asmcrypto.js'
+
+
+
+function sbrk(size, heap){
+ let brk = 512 * 1024 // stack top
+ let old = brk
+ brk += size
+
+ if (brk > heap.length)
+ throw new Error('heap exhausted')
+
+ return old
+}
+
+
+
+
+self.addEventListener('message', async e => {
+ const response = await computePow(e.data.convertedBytes, e.data.path)
+ postMessage(response)
+
+})
+
+
+const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 })
+const heap = new Uint8Array(memory.buffer)
+
+
+
+const computePow = async (convertedBytes, path) => {
+
+
+ let response = null
+
+ await new Promise((resolve, reject)=> {
+
+ const _convertedBytesArray = Object.keys(convertedBytes).map(
+ function (key) {
+ return convertedBytes[key]
+ }
+)
+const convertedBytesArray = new Uint8Array(_convertedBytesArray)
+const convertedBytesHash = new Sha256()
+ .process(convertedBytesArray)
+ .finish().result
+const hashPtr = sbrk(32, heap)
+const hashAry = new Uint8Array(
+ memory.buffer,
+ hashPtr,
+ 32
+)
+
+hashAry.set(convertedBytesHash)
+const difficulty = 14
+const workBufferLength = 8 * 1024 * 1024
+const workBufferPtr = sbrk(
+ workBufferLength,
+ heap
+)
+
+ const importObject = {
+ env: {
+ memory: memory
+ },
+ };
+
+ function loadWebAssembly(filename, imports) {
+ return fetch(filename)
+ .then(response => response.arrayBuffer())
+ .then(buffer => WebAssembly.compile(buffer))
+ .then(module => {
+ return new WebAssembly.Instance(module, importObject);
+ });
+}
+
+
+loadWebAssembly(path)
+ .then(wasmModule => {
+ response = {
+ nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty),
+
+ }
+ resolve()
+
+ });
+
+
+ })
+
+ return response
+}
\ No newline at end of file
diff --git a/core/src/components/friends-view/avatar.js b/core/src/components/friends-view/avatar.js
new file mode 100644
index 00000000..12f7090b
--- /dev/null
+++ b/core/src/components/friends-view/avatar.js
@@ -0,0 +1,310 @@
+import { LitElement, html, css } from 'lit';
+import { get, translate } from 'lit-translate';
+import axios from 'axios';
+import '@material/mwc-menu';
+import '@material/mwc-list/mwc-list-item.js';
+import { RequestQueueWithPromise } from '../../../../plugins/plugins/utils/queue';
+import '../../../../plugins/plugins/core/components/TimeAgo';
+import { connect } from 'pwa-helpers';
+import { store } from '../../store';
+import { setNewTab } from '../../redux/app/app-actions';
+import ShortUniqueId from 'short-unique-id';
+
+const requestQueue = new RequestQueueWithPromise(3);
+const requestQueueRawData = new RequestQueueWithPromise(3);
+const requestQueueStatus = new RequestQueueWithPromise(3);
+
+export class AvatarComponent extends connect(store)(LitElement) {
+ static get properties() {
+ return {
+ resource: { type: Object },
+ isReady: { type: Boolean },
+ status: { type: Object },
+ name: { type: String },
+ };
+ }
+
+ static get styles() {
+ return css`
+ * {
+ --mdc-theme-text-primary-on-background: var(--black);
+ box-sizing: border-box;
+ }
+ :host {
+ width: 100%;
+ box-sizing: border-box;
+ }
+ img {
+ width: 100%;
+ max-height: 30vh;
+ border-radius: 5px;
+ cursor: pointer;
+ position: relative;
+ }
+ .smallLoading,
+ .smallLoading:after {
+ border-radius: 50%;
+ width: 2px;
+ height: 2px;
+ }
+
+ .defaultSize {
+ width: 100%;
+ height: 160px;
+ }
+ .parent-feed-item {
+ position: relative;
+ display: flex;
+ background-color: var(--chat-bubble-bg);
+ flex-grow: 0;
+ flex-direction: column;
+ align-items: flex-start;
+ justify-content: center;
+ border-radius: 5px;
+ padding: 12px 15px 4px 15px;
+ min-width: 150px;
+ width: 100%;
+ box-sizing: border-box;
+ cursor: pointer;
+ font-size: 16px;
+ }
+ .avatar {
+ width: 36px;
+ height: 36px;
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ }
+ .avatarApp {
+ width: 30px;
+ height: 30px;
+ border-radius: 50%;
+ overflow: hidden;
+ display: flex;
+ align-items: center;
+ }
+ .feed-item-name {
+ user-select: none;
+ color: #03a9f4;
+ margin-bottom: 5px;
+ }
+
+ .app-name {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ }
+
+ mwc-menu {
+ position: absolute;
+ }
+ `;
+ }
+
+ constructor() {
+ super();
+ this.resource = {
+ identifier: '',
+ name: '',
+ service: '',
+ };
+ this.status = {
+ status: '',
+ };
+ this.isReady = false;
+ this.nodeUrl = this.getNodeUrl();
+ this.myNode = this.getMyNode();
+ this.isFetching = false;
+ this.uid = new ShortUniqueId();
+ }
+ getNodeUrl() {
+ const myNode =
+ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ const nodeUrl =
+ myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
+ return nodeUrl;
+ }
+ getMyNode() {
+ const myNode =
+ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ return myNode;
+ }
+
+ getApiKey() {
+ const myNode =
+ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+ let apiKey = myNode.apiKey;
+ return apiKey;
+ }
+
+ async fetchResource() {
+ try {
+ if (this.isFetching) return;
+ this.isFetching = true;
+ await axios.get(
+ `${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
+ );
+ this.isFetching = false;
+ } catch (error) {
+ this.isFetching = false;
+ }
+ }
+
+ async fetchVideoUrl() {
+ this.fetchResource();
+ }
+
+ async getRawData() {
+ const url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`;
+ return await requestQueueRawData.enqueue(() => {
+ return axios.get(url);
+ });
+ // const response2 = await fetch(url, {
+ // method: 'GET',
+ // headers: {
+ // 'Content-Type': 'application/json'
+ // }
+ // })
+
+ // const responseData2 = await response2.json()
+ // return responseData2
+ }
+
+ updateDisplayWithPlaceholders(display, resource, rawdata) {
+ const pattern = /\$\$\{([a-zA-Z0-9_\.]+)\}\$\$/g;
+
+ for (const key in display) {
+ const value = display[key];
+
+ display[key] = value.replace(pattern, (match, p1) => {
+ if (p1.startsWith('rawdata.')) {
+ const dataKey = p1.split('.')[1];
+ if (rawdata[dataKey] === undefined) {
+ console.error('rawdata key not found:', dataKey);
+ }
+ return rawdata[dataKey] || match;
+ } else if (p1.startsWith('resource.')) {
+ const resourceKey = p1.split('.')[1];
+ if (resource[resourceKey] === undefined) {
+ console.error('resource key not found:', resourceKey);
+ }
+ return resource[resourceKey] || match;
+ }
+ return match;
+ });
+ }
+ }
+
+ async fetchStatus() {
+ let isCalling = false;
+ let percentLoaded = 0;
+ let timer = 24;
+ const response = await requestQueueStatus.enqueue(() => {
+ return axios.get(
+ `${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
+ );
+ });
+ if (response && response.data && response.data.status === 'READY') {
+ this.status = response.data;
+
+ return;
+ }
+ const intervalId = setInterval(async () => {
+ if (isCalling) return;
+ isCalling = true;
+
+ const data = await requestQueue.enqueue(() => {
+ return axios.get(
+ `${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
+ );
+ });
+ const res = data.data;
+
+ isCalling = false;
+ if (res.localChunkCount) {
+ if (res.percentLoaded) {
+ if (
+ res.percentLoaded === percentLoaded &&
+ res.percentLoaded !== 100
+ ) {
+ timer = timer - 5;
+ } else {
+ timer = 24;
+ }
+ if (timer < 0) {
+ clearInterval(intervalId);
+ }
+ percentLoaded = res.percentLoaded;
+ }
+
+ this.status = res;
+ if (this.status.status === 'DOWNLOADED') {
+ this.fetchResource();
+ }
+ }
+
+ // check if progress is 100% and clear interval if true
+ if (res.status === 'READY') {
+ clearInterval(intervalId);
+ this.status = res;
+ this.isReady = true;
+ }
+ }, 5000); // 1 second interval
+ }
+
+ async _fetchImage() {
+ try {
+ this.fetchVideoUrl();
+ this.fetchStatus();
+ } catch (error) {
+ /* empty */
+ }
+ }
+
+ firstUpdated() {
+ this._fetchImage();
+ }
+
+ render() {
+ console.log('hello', this.name, this.resource, this.status);
+ return html`
+
+ ${this.status.status !== 'READY'
+ ? html`
+
account_circle
+ `
+ : ''}
+ ${this.status.status === 'READY'
+ ? html`
+
+
![](${this
+ .nodeUrl}/arbitrary/THUMBNAIL/${this
+ .name}/qortal_avatar?async=true&apiKey=${this
+ .myNode.apiKey})
+
+ `
+ : ''}
+
+ `;
+ }
+}
+
+customElements.define('avatar-component', AvatarComponent);
diff --git a/core/src/components/friends-view/profile-modal-update.js b/core/src/components/friends-view/profile-modal-update.js
new file mode 100644
index 00000000..e7ad8777
--- /dev/null
+++ b/core/src/components/friends-view/profile-modal-update.js
@@ -0,0 +1,301 @@
+import { LitElement, html, css } from 'lit';
+import { render } from 'lit/html.js';
+import {
+ use,
+ get,
+ translate,
+ translateUnsafeHTML,
+ registerTranslateConfig,
+} from 'lit-translate';
+import '@material/mwc-button';
+import '@material/mwc-dialog';
+import '@material/mwc-checkbox';
+import { connect } from 'pwa-helpers';
+import { store } from '../../store';
+import '@polymer/paper-spinner/paper-spinner-lite.js';
+
+class ProfileModalUpdate extends connect(store)(LitElement) {
+ static get properties() {
+ return {
+ isOpen: { type: Boolean },
+ setIsOpen: { attribute: false },
+ isLoading: { type: Boolean },
+ onSubmit: { attribute: false },
+ editContent: { type: Object },
+ onClose: { attribute: false },
+ tagline: {type: String},
+ bio: {type: String}
+ };
+ }
+
+ constructor() {
+ super();
+ this.isOpen = false;
+ this.isLoading = false;
+ this.nodeUrl = this.getNodeUrl();
+ this.myNode = this.getMyNode();
+ this.tagline = "";
+ this.bio = "",
+ this.walletList = [
+ "btcWallet", "ltcWallet", "dogeWallet","dgbWallet", "rvnWallet", "arrrWallet"
+ ]
+ }
+
+ static get styles() {
+ return css`
+ * {
+ --mdc-theme-primary: rgb(3, 169, 244);
+ --mdc-theme-secondary: var(--mdc-theme-primary);
+ --mdc-theme-surface: var(--white);
+ --mdc-dialog-content-ink-color: var(--black);
+ --mdc-dialog-min-width: 400px;
+ --mdc-dialog-max-width: 1024px;
+ box-sizing: border-box;
+ }
+ .input {
+ width: 90%;
+ outline: 0;
+ border-width: 0 0 2px;
+ border-color: var(--mdc-theme-primary);
+ background-color: transparent;
+ padding: 10px;
+ font-family: Roboto, sans-serif;
+ font-size: 15px;
+ color: var(--chat-bubble-msg-color);
+ box-sizing: border-box;
+ }
+
+ .input::selection {
+ background-color: var(--mdc-theme-primary);
+ color: white;
+ }
+
+ .input::placeholder {
+ opacity: 0.6;
+ color: var(--black);
+ }
+
+ .modal-button {
+ font-family: Roboto, sans-serif;
+ font-size: 16px;
+ color: var(--mdc-theme-primary);
+ background-color: transparent;
+ padding: 8px 10px;
+ border-radius: 5px;
+ border: none;
+ transition: all 0.3s ease-in-out;
+ }
+
+ .modal-button-red {
+ font-family: Roboto, sans-serif;
+ font-size: 16px;
+ color: #f44336;
+ background-color: transparent;
+ padding: 8px 10px;
+ border-radius: 5px;
+ border: none;
+ transition: all 0.3s ease-in-out;
+ }
+
+ .modal-button-red:hover {
+ cursor: pointer;
+ background-color: #f4433663;
+ }
+
+ .modal-button:hover {
+ cursor: pointer;
+ background-color: #03a8f475;
+ }
+ .checkbox-row {
+ position: relative;
+ display: flex;
+ align-items: center;
+ align-content: center;
+ font-family: Montserrat, sans-serif;
+ font-weight: 600;
+ color: var(--black);
+ }
+ .modal-overlay {
+ display: block;
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100vw;
+ height: 100vh;
+ background-color: rgba(
+ 0,
+ 0,
+ 0,
+ 0.5
+ ); /* Semi-transparent backdrop */
+ z-index: 1000;
+ }
+
+ .modal-content {
+ position: fixed;
+ top: 50vh;
+ left: 50vw;
+ transform: translate(-50%, -50%);
+ background-color: var(--mdc-theme-surface);
+ width: 80vw;
+ max-width: 600px;
+ padding: 20px;
+ box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 6px;
+ z-index: 1001;
+ border-radius: 5px;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .modal-overlay.hidden {
+ display: none;
+ }
+ .avatar {
+ width: 36px;
+ height: 36px;
+ display: flex;
+ align-items: center;
+ }
+
+ .app-name {
+ display: flex;
+ gap: 20px;
+ align-items: center;
+ width: 100%;
+ cursor: pointer;
+ padding: 5px;
+ border-radius: 5px;
+ margin-bottom: 10px;
+ }
+ .inner-content {
+ display: flex;
+ flex-direction: column;
+ max-height: 75vh;
+ flex-grow: 1;
+ overflow: auto;
+ }
+
+ .inner-content::-webkit-scrollbar-track {
+ background-color: whitesmoke;
+ border-radius: 7px;
+ }
+
+ .inner-content::-webkit-scrollbar {
+ width: 12px;
+ border-radius: 7px;
+ background-color: whitesmoke;
+ }
+
+ .inner-content::-webkit-scrollbar-thumb {
+ background-color: rgb(180, 176, 176);
+ border-radius: 7px;
+ transition: all 0.3s ease-in-out;
+ }
+ `;
+ }
+
+ firstUpdated() {}
+
+ getNodeUrl() {
+ const myNode =
+ store.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ const nodeUrl =
+ myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
+ return nodeUrl;
+ }
+ getMyNode() {
+ const myNode =
+ store.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ return myNode;
+ }
+
+ clearFields() {}
+
+ render() {
+ return html`
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+ }
+}
+
+customElements.define('profile-modal-update', ProfileModalUpdate);
diff --git a/core/src/components/friends-view/profile.js b/core/src/components/friends-view/profile.js
new file mode 100644
index 00000000..f8ef2ab6
--- /dev/null
+++ b/core/src/components/friends-view/profile.js
@@ -0,0 +1,672 @@
+import { LitElement, html, css } from 'lit';
+import '@material/mwc-icon';
+import './friends-side-panel.js';
+import { connect } from 'pwa-helpers';
+import { store } from '../../store.js';
+import WebWorker2 from '../WebWorkerFile.js';
+import '@polymer/paper-spinner/paper-spinner-lite.js';
+import '@vaadin/tooltip';
+import { get, translate } from 'lit-translate';
+import ShortUniqueId from 'short-unique-id';
+
+import {
+ decryptGroupData,
+ encryptDataGroup,
+ objectToBase64,
+ uint8ArrayToBase64,
+ uint8ArrayToObject,
+} from '../../../../plugins/plugins/core/components/qdn-action-encryption.js';
+import { publishData } from '../../../../plugins/plugins/utils/publish-image.js';
+import { parentEpml } from '../show-plugin.js';
+import '../notification-view/popover.js';
+import './avatar.js';
+import { setNewTab } from '../../redux/app/app-actions.js';
+import './profile-modal-update.js'
+
+class ProfileQdn extends connect(store)(LitElement) {
+ static get properties() {
+ return {
+ isOpen: { type: Boolean },
+ syncPercentage: { type: Number },
+ settingsRawData: { type: Object },
+ valuesToBeSavedOnQdn: { type: Object },
+ resourceExists: { type: Boolean },
+ isSaving: { type: Boolean },
+ fee: { type: Object },
+ name: { type: String },
+ isOpenProfileModalUpdate: {type: Boolean},
+ editContent: {type: Object}
+ };
+ }
+
+ constructor() {
+ super();
+ this.isOpen = false;
+ this.getProfile = this.getProfile.bind(this);
+ this._updateTempSettingsData = this._updateTempSettingsData.bind(this);
+ this.setValues = this.setValues.bind(this);
+ this.saveToQdn = this.saveToQdn.bind(this);
+ this.syncPercentage = 0;
+ this.hasRetrievedResource = false;
+ this.hasAttemptedToFetchResource = false;
+ this.resourceExists = undefined;
+ this.settingsRawData = null;
+ this.nodeUrl = this.getNodeUrl();
+ this.myNode = this.getMyNode();
+ this.valuesToBeSavedOnQdn = {};
+ this.isSaving = false;
+ this.fee = null;
+ this.name = undefined;
+ this.uid = new ShortUniqueId();
+ this.isOpenProfileModalUpdate = false
+ this.editContent = null
+ }
+ static styles = css`
+ .header {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding: 16px;
+ border-bottom: 1px solid #e0e0e0;
+ }
+
+ .content {
+ padding: 16px;
+ }
+ .close {
+ visibility: hidden;
+ position: fixed;
+ z-index: -100;
+ right: -1000px;
+ }
+
+ .parent-side-panel {
+ transform: translateX(100%); /* start from outside the right edge */
+ transition: transform 0.3s ease-in-out;
+ }
+ .parent-side-panel.open {
+ transform: translateX(0); /* slide in to its original position */
+ }
+ .notActive {
+ opacity: 0.5;
+ cursor: default;
+ color: var(--black);
+ }
+ .active {
+ opacity: 1;
+ cursor: pointer;
+ color: green;
+ }
+ .accept-button {
+ font-family: Roboto, sans-serif;
+ letter-spacing: 0.3px;
+ font-weight: 300;
+ padding: 8px 5px;
+ border-radius: 3px;
+ text-align: center;
+ color: var(--mdc-theme-primary);
+ transition: all 0.3s ease-in-out;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 18px;
+ }
+
+ .accept-button:hover {
+ cursor: pointer;
+ background-color: #03a8f485;
+ }
+
+ .undo-button {
+ font-family: Roboto, sans-serif;
+ letter-spacing: 0.3px;
+ font-weight: 300;
+ padding: 8px 5px;
+ border-radius: 3px;
+ text-align: center;
+ color: #f44336;
+ transition: all 0.3s ease-in-out;
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ font-size: 18px;
+ }
+
+ .undo-button:hover {
+ cursor: pointer;
+ background-color: #f4433663;
+ }
+ `;
+
+ getNodeUrl() {
+ const myNode =
+ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ const nodeUrl =
+ myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
+ return nodeUrl;
+ }
+ getMyNode() {
+ const myNode =
+ window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
+ window.parent.reduxStore.getState().app.nodeConfig.node
+ ];
+
+ return myNode;
+ }
+
+ async getAvatar(dataItem) {
+ const url = `${this.nodeUrl}/arbitrary/${dataItem.service}/${dataItem.name}/${dataItem.identifier}?encoding=base64`;
+ const res = await fetch(url);
+ const data = await res.text();
+ if (data.error) throw new Error('Cannot retrieve your data from qdn');
+ const decryptedData = decryptGroupData(data);
+ const decryptedDataToBase64 = uint8ArrayToObject(decryptedData);
+ return decryptedDataToBase64;
+ }
+
+ async getRawData(dataItem) {
+ const url = `${this.nodeUrl}/arbitrary/${dataItem.service}/${dataItem.name}/${dataItem.identifier}?encoding=base64`;
+ const res = await fetch(url);
+ const data = await res.text();
+ if (data.error) throw new Error('Cannot retrieve your data from qdn');
+ const decryptedData = decryptGroupData(data);
+ const decryptedDataToBase64 = uint8ArrayToObject(decryptedData);
+ return decryptedDataToBase64;
+ }
+
+ async getMyFollowedNames() {
+ let myFollowedNames = [];
+ try {
+ myFollowedNames = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.myNode.apiKey}`,
+ });
+ } catch (error) {}
+
+ return myFollowedNames;
+ }
+
+ async followNames(names) {
+ let items = names;
+ let namesJsonString = JSON.stringify({ items: items });
+
+ let ret = await parentEpml.request('apiCall', {
+ url: `/lists/followedNames?apiKey=${this.myNode.apiKey}`,
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: `${namesJsonString}`,
+ });
+
+ return ret;
+ }
+
+ async setValues(response, resource) {
+ this.settingsRawData = response;
+ const rawDataTimestamp = resource.updated;
+
+ const tempSettingsData = JSON.parse(
+ localStorage.getItem('temp-settings-data') || '{}'
+ );
+
+ const userLists = response.userLists || [];
+ const friendsFeed = response.friendsFeed;
+ const myMenuPlugs = response.myMenuPlugs;
+
+ this.valuesToBeSavedOnQdn = {};
+ if (
+ userLists.length > 0 &&
+ (!tempSettingsData.userLists ||
+ (tempSettingsData.userLists &&
+ tempSettingsData.userLists.timestamp < rawDataTimestamp))
+ ) {
+ const friendList = userLists[0];
+ const copyPayload = [...friendList];
+ const onlyNames = copyPayload.map((item) => item.name);
+ const followedList = await this.getMyFollowedNames();
+
+ const namesNotInFollowedList = onlyNames.filter(
+ (name) => !followedList.includes(name)
+ );
+ if (namesNotInFollowedList.length > 0) {
+ await this.followNames(namesNotInFollowedList);
+ }
+
+ localStorage.setItem(
+ 'friends-my-friend-list',
+ JSON.stringify(friendList)
+ );
+ this.dispatchEvent(
+ new CustomEvent('friends-my-friend-list-event', {
+ bubbles: true,
+ composed: true,
+ detail: copyPayload,
+ })
+ );
+ } else if (
+ tempSettingsData.userLists &&
+ tempSettingsData.userLists.timestamp > rawDataTimestamp
+ ) {
+ this.valuesToBeSavedOnQdn = {
+ ...this.valuesToBeSavedOnQdn,
+ userLists: {
+ data: tempSettingsData.userLists.data,
+ },
+ };
+ }
+
+ if (
+ friendsFeed &&
+ (!tempSettingsData.friendsFeed ||
+ (tempSettingsData.friendsFeed &&
+ tempSettingsData.friendsFeed.timestamp < rawDataTimestamp))
+ ) {
+ const copyPayload = [...friendsFeed];
+
+ localStorage.setItem(
+ 'friends-my-selected-feeds',
+ JSON.stringify(friendsFeed)
+ );
+ this.dispatchEvent(
+ new CustomEvent('friends-my-selected-feeds-event', {
+ bubbles: true,
+ composed: true,
+ detail: copyPayload,
+ })
+ );
+ } else if (
+ tempSettingsData.friendsFeed &&
+ tempSettingsData.friendsFeed.timestamp > rawDataTimestamp
+ ) {
+ this.valuesToBeSavedOnQdn = {
+ ...this.valuesToBeSavedOnQdn,
+ friendsFeed: {
+ data: tempSettingsData.friendsFeed.data,
+ },
+ };
+ }
+
+ if (
+ myMenuPlugs &&
+ (!tempSettingsData.myMenuPlugs ||
+ (tempSettingsData.myMenuPlugs &&
+ tempSettingsData.myMenuPlugs.timestamp < rawDataTimestamp))
+ ) {
+ if (Array.isArray(myMenuPlugs)) {
+ const copyPayload = [...myMenuPlugs];
+
+ localStorage.setItem(
+ 'myMenuPlugs',
+ JSON.stringify(myMenuPlugs)
+ );
+
+ this.dispatchEvent(
+ new CustomEvent('myMenuPlugs-event', {
+ bubbles: true,
+ composed: true,
+ detail: copyPayload,
+ })
+ );
+ }
+ } else if (
+ tempSettingsData.myMenuPlugs &&
+ tempSettingsData.myMenuPlugs.timestamp > rawDataTimestamp
+ ) {
+ this.valuesToBeSavedOnQdn = {
+ ...this.valuesToBeSavedOnQdn,
+ myMenuPlugs: {
+ data: tempSettingsData.myMenuPlugs.data,
+ },
+ };
+ }
+ }
+
+ async getProfile() {
+ try {
+ const arbFee = await this.getArbitraryFee();
+ this.fee = arbFee;
+ this.hasAttemptedToFetchResource = true;
+ let resource;
+ const nameObject = store.getState().app.accountInfo.names[0];
+ if (!nameObject) {
+ this.name = null;
+ throw new Error('no name');
+ }
+ const name = nameObject.name;
+ this.name = name;
+ this.error = '';
+ const url = `${this.nodeUrl}/arbitrary/resources/search?service=DOCUMENT&identifier=qortal_profile&name=${name}&prefix=true&exactmatchnames=true&excludeblocked=true&limit=20`;
+ const res = await fetch(url);
+ let data = '';
+ try {
+ data = await res.json();
+ if (Array.isArray(data)) {
+ data = data.filter(
+ (item) => item.identifier === 'qortal_profile'
+ );
+
+ if (data.length > 0) {
+ this.resourceExists = true;
+ const dataItem = data[0];
+ try {
+ const response = await this.getRawData(dataItem);
+ if (response.version) {
+ // this.setValues(response, dataItem);
+ } else {
+ this.error = 'Cannot get saved user settings';
+ }
+ } catch (error) {
+ console.log({ error });
+ this.error = 'Cannot get saved user settings';
+ }
+ } else {
+ this.resourceExists = false;
+ }
+ } else {
+ this.error = 'Unable to perform query';
+ }
+ } catch (error) {
+ data = {
+ error: 'No resource found',
+ };
+ }
+
+ if (resource) {
+ this.hasRetrievedResource = true;
+ }
+ } catch (error) {
+ console.log({ error });
+ }
+ }
+
+ stateChanged(state) {
+ if (
+ state.app.accountInfo &&
+ state.app.accountInfo.names.length &&
+ state.app.nodeStatus &&
+ state.app.nodeStatus.syncPercent !== this.syncPercentage
+ ) {
+ this.syncPercentage = state.app.nodeStatus.syncPercent;
+
+ if (
+ !this.hasAttemptedToFetchResource &&
+ state.app.nodeStatus.syncPercent === 100
+ ) {
+ this.getProfile();
+ }
+ }
+ }
+
+ async getArbitraryFee() {
+ const timestamp = Date.now();
+ const url = `${this.nodeUrl}/transactions/unitfee?txType=ARBITRARY×tamp=${timestamp}`;
+ const response = await fetch(url);
+ if (!response.ok) {
+ throw new Error('Error when fetching arbitrary fee');
+ }
+ const data = await response.json();
+ const arbitraryFee = (Number(data) / 1e8).toFixed(8);
+ return {
+ timestamp,
+ fee: Number(data),
+ feeToShow: arbitraryFee,
+ };
+ }
+
+ async saveToQdn() {
+ try {
+ this.isSaving = true;
+ if (this.resourceExists === true && this.error)
+ throw new Error('Unable to save');
+
+ const nameObject = store.getState().app.accountInfo.names[0];
+ if (!nameObject) throw new Error('no name');
+ const name = nameObject.name;
+ const identifer = 'qortal_general_settings';
+ const filename = 'qortal_general_settings.json';
+ const selectedAddress = store.getState().app.selectedAddress;
+ const getArbitraryFee = await this.getArbitraryFee();
+ const feeAmount = getArbitraryFee.fee;
+ const friendsList = JSON.parse(
+ localStorage.getItem('friends-my-friend-list') || '[]'
+ );
+ const friendsFeed = JSON.parse(
+ localStorage.getItem('friends-my-selected-feeds') || '[]'
+ );
+ const myMenuPlugs = JSON.parse(
+ localStorage.getItem('myMenuPlugs') || '[]'
+ );
+
+ let newObject;
+
+ if (this.resourceExists === false) {
+ newObject = {
+ version: 1,
+ userLists: [friendsList],
+ friendsFeed,
+ myMenuPlugs,
+ };
+ } else if (this.settingsRawData) {
+ const tempSettingsData = JSON.parse(
+ localStorage.getItem('temp-settings-data') || '{}'
+ );
+ newObject = {
+ ...this.settingsRawData,
+ };
+ for (const key in tempSettingsData) {
+ if (tempSettingsData[key].hasOwnProperty('data')) {
+ if (
+ key === 'userLists' &&
+ !Array.isArray(tempSettingsData[key].data)
+ )
+ continue;
+ if (
+ key === 'friendsFeed' &&
+ !Array.isArray(tempSettingsData[key].data)
+ )
+ continue;
+ if (
+ key === 'myMenuPlugs' &&
+ !Array.isArray(tempSettingsData[key].data)
+ )
+ continue;
+ newObject[key] = tempSettingsData[key].data;
+ }
+ }
+ }
+
+ const newObjectToBase64 = await objectToBase64(newObject);
+ const encryptedData = encryptDataGroup({
+ data64: newObjectToBase64,
+ publicKeys: [],
+ });
+
+ const worker = new WebWorker2();
+ try {
+ const resPublish = await publishData({
+ registeredName: encodeURIComponent(name),
+ file: encryptedData,
+ service: 'DOCUMENT_PRIVATE',
+ identifier: encodeURIComponent(identifer),
+ parentEpml: parentEpml,
+ uploadType: 'file',
+ selectedAddress: selectedAddress,
+ worker: worker,
+ isBase64: true,
+ filename: filename,
+ apiVersion: 2,
+ withFee: true,
+ feeAmount: feeAmount,
+ });
+
+ this.resourceExists = true;
+ this.setValues(newObject, {
+ updated: Date.now(),
+ });
+ localStorage.setItem('temp-settings-data', JSON.stringify({}));
+ this.valuesToBeSavedOnQdn = {};
+ worker.terminate();
+ } catch (error) {
+ worker.terminate();
+ }
+ } catch (error) {
+ console.log({ error });
+ } finally {
+ this.isSaving = false;
+ }
+ }
+
+ _updateTempSettingsData() {
+ this.valuesToBeSavedOnQdn = JSON.parse(
+ localStorage.getItem('temp-settings-data') || '{}'
+ );
+ }
+
+ connectedCallback() {
+ super.connectedCallback();
+ window.addEventListener(
+ 'temp-settings-data-event',
+ this._updateTempSettingsData
+ );
+ }
+
+ disconnectedCallback() {
+ window.removeEventListener(
+ 'temp-settings-data-event',
+ this._updateTempSettingsData
+ );
+ super.disconnectedCallback();
+ }
+
+ publishProfile(){
+
+ }
+
+ onClose(){
+ this.isOpenProfileModalUpdate = false
+ }
+ render() {
+ console.log('sup profile2', this.name);
+ return html`
+ ${this.isSaving ||
+ (!this.error && this.resourceExists === undefined)
+ ? html`
+
+ `
+ : !this.name
+ ? html`
+
0 || this.resourceExists === false
+ ? 'active'
+ : 'notActive'}
+ @click=${() => {
+ const target = this.shadowRoot.getElementById(
+ 'popover-notification'
+ );
+ const popover =
+ this.shadowRoot.querySelector(
+ 'popover-component'
+ );
+ if (popover) {
+ popover.openPopover(target);
+ }
+ }}
+ style="user-select:none;cursor:pointer"
+ >account_circle
+
0 ||
+ this.resourceExists === false
+ ? get('save.saving3')
+ : get('save.saving2')}
+ >
+
+
+
+
+ ${`${get('profile.profile1')}`}
+
+
+
+
{
+ store.dispatch(
+ setNewTab({
+ url: `group-management`,
+ id: this.uid.rnd(),
+ myPlugObj: {
+ url: 'name-registration',
+ domain: 'core',
+ page: 'name-registration/index.html',
+ title: 'Name Registration',
+ icon: 'vaadin:user-check',
+ mwcicon: 'manage_accounts',
+ pluginNumber:
+ 'plugin-qCmtXAQmtu',
+ menus: [],
+ parent: false,
+ },
+ openExisting: true,
+ })
+ );
+ const popover =
+ this.shadowRoot.querySelector(
+ 'popover-component'
+ );
+ if (popover) {
+ popover.closePopover();
+ }
+ }}"
+ >
+ ${translate('profile.profile2')}
+
+
+
+ `
+ : html`
+
{
+ this.isOpenProfileModalUpdate = !this.isOpenProfileModalUpdate
+ }}>
+
+
+ `}
+
+
{
+ this.isOpenProfileModalUpdate = val
+ }}
+ .onSubmit=${(val, isEdit)=> this.publishProfile(val, isEdit)}
+ .editContent=${this.editContent}
+ .onClose=${()=> this.onClose()}
+ >
+ `;
+ }
+}
+
+customElements.define('profile-qdn', ProfileQdn);
diff --git a/core/src/components/friends-view/save-settings-qdn.js b/core/src/components/friends-view/save-settings-qdn.js
index b2e558a5..710813f7 100644
--- a/core/src/components/friends-view/save-settings-qdn.js
+++ b/core/src/components/friends-view/save-settings-qdn.js
@@ -3,12 +3,13 @@ import '@material/mwc-icon';
import './friends-side-panel.js';
import { connect } from 'pwa-helpers';
import { store } from '../../store.js';
-import WebWorker from 'web-worker:./computePowWorkerFile.src.js';
+import WebWorker from '../WebWorkerFile.js';
import '@polymer/paper-spinner/paper-spinner-lite.js';
import '@vaadin/tooltip';
import { get, translate } from 'lit-translate';
import {
decryptGroupData,
+
encryptDataGroup,
objectToBase64,
uint8ArrayToBase64,
diff --git a/core/src/components/show-plugin.js b/core/src/components/show-plugin.js
index 266df4a2..8c12ee90 100644
--- a/core/src/components/show-plugin.js
+++ b/core/src/components/show-plugin.js
@@ -337,6 +337,7 @@ class ShowPlugin extends connect(store)(LitElement) {
}
render() {
+ console.log('this.tabs', this.tabs)
const plugSrc = (myPlug) => {
return myPlug === undefined ? 'about:blank' : `${window.location.origin}/plugin/${myPlug.domain}/${myPlug.page}${this.linkParam}`
}