diff --git a/qortal-ui-core/font/KoHo.ttf b/qortal-ui-core/font/KoHo.ttf new file mode 100644 index 00000000..72841e9d Binary files /dev/null and b/qortal-ui-core/font/KoHo.ttf differ diff --git a/qortal-ui-core/font/Livvic.ttf b/qortal-ui-core/font/Livvic.ttf new file mode 100644 index 00000000..f477b285 Binary files /dev/null and b/qortal-ui-core/font/Livvic.ttf differ diff --git a/qortal-ui-core/font/Montserrat.ttf b/qortal-ui-core/font/Montserrat.ttf new file mode 100644 index 00000000..656db666 Binary files /dev/null and b/qortal-ui-core/font/Montserrat.ttf differ diff --git a/qortal-ui-core/font/Raleway.ttf b/qortal-ui-core/font/Raleway.ttf new file mode 100644 index 00000000..424fb0e8 Binary files /dev/null and b/qortal-ui-core/font/Raleway.ttf differ diff --git a/qortal-ui-core/font/material-icons.css b/qortal-ui-core/font/material-icons.css index 2270c09d..0363d4ee 100644 --- a/qortal-ui-core/font/material-icons.css +++ b/qortal-ui-core/font/material-icons.css @@ -2,19 +2,49 @@ font-family: 'Material Icons'; font-style: normal; font-weight: 400; - src: url(MaterialIcons-Regular.eot); /* For IE6-8 */ + src: url(MaterialIcons-Regular.eot); + /* For IE6-8 */ src: local('Material Icons'), - local('MaterialIcons-Regular'), - url(MaterialIcons-Regular.woff2) format('woff2'), - url(MaterialIcons-Regular.woff) format('woff'), - url(MaterialIcons-Regular.ttf) format('truetype'); + local('MaterialIcons-Regular'), + url(MaterialIcons-Regular.woff2) format('woff2'), + url(MaterialIcons-Regular.woff) format('woff'), + url(MaterialIcons-Regular.ttf) format('truetype'); +} + +@font-face { + font-family: 'Montserrat'; + src: local('Montserrat'), + local('Montserrat'), + url(Montserrat.ttf) format('truetype'); +} + +@font-face { + font-family: 'Raleway'; + src: local('Raleway'), + local('Raleway'), + url(Raleway.ttf) format('truetype'); +} + +@font-face { + font-family: 'KoHo'; + src: local('KoHo'), + local('KoHo'), + url(KoHo.ttf) format('truetype'); +} + +@font-face { + font-family: 'Livvic'; + src: local('Livvic'), + local('Livvic'), + url(Livvic.ttf) format('truetype'); } .material-icons { font-family: 'Material Icons'; font-weight: normal; font-style: normal; - font-size: 24px; /* Preferred icon size */ + font-size: 24px; + /* Preferred icon size */ display: inline-block; line-height: 1; text-transform: none; @@ -33,4 +63,4 @@ /* Support for IE. */ font-feature-settings: 'liga'; -} +} \ No newline at end of file diff --git a/qortal-ui-core/font/switch-theme.css b/qortal-ui-core/font/switch-theme.css index b9eeee64..110700a3 100644 --- a/qortal-ui-core/font/switch-theme.css +++ b/qortal-ui-core/font/switch-theme.css @@ -48,6 +48,8 @@ html { --chatHeadText: #080808; --chatHeadTextActive: #080808; --lightChatHeadHover: #1e1f201a; + --group-header: #929292; + --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; } html[theme="dark"] { @@ -100,4 +102,6 @@ html[theme="dark"] { --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; --lightChatHeadHover: #e0e1e31a; + --group-header: #c8c8c8; + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px } \ No newline at end of file diff --git a/qortal-ui-core/language/us.json b/qortal-ui-core/language/us.json index c2bc9565..efeca99f 100644 --- a/qortal-ui-core/language/us.json +++ b/qortal-ui-core/language/us.json @@ -465,8 +465,8 @@ "cchange3": "Blocked Users", "cchange4": "New Message", "cchange5": "(Click to scroll down)", - "cchange6": "Type the name or address of who you want to chat with to send a private message!", - "cchange7": "Name / Address", + "cchange6": "Type the name or address of who you want to chat with to send a private message! You can validate the person's name by clicking on the book icon.", + "cchange7": "Username / Address", "cchange8": "Message...", "cchange9": "Send", "cchange10": "Blocked Users List", @@ -478,7 +478,7 @@ "cchange16": "Successfully unblocked this user.", "cchange17": "Error occurred when trying to unblock this user. Please try again!", "cchange18": "unblock", - "cchange19": "Invalid Name / Address, Check the name / address and retry...", + "cchange19": "Invalid Username / Address, Check the name / address and retry...", "cchange20": "Message Sent Successfully!", "cchange21": "Sending failed, Please retry...", "cchange22": "Loading Messages...", @@ -492,7 +492,13 @@ "cchange30": "Uploading image. This may take up to one minute.", "cchange31": "Deleting image. This may take up to one minute.", "cchange33": "Cancel", - "cchange34": "This chat message is using an older message version and cannot use this feature." + "cchange34": "This chat message is using an older message version and cannot use this feature.", + "cchange35": "Error when trying to fetch the user's name. Please try again!", + "cchange36": "Search Results", + "cchange37": "No Results Found", + "cchange38": "User Verified", + "cchange39": "Cannot send an encrypted message to this user since they do not have their publickey on chain.", + "cchange40": "IMAGE (click to view)" }, "welcomepage": { "wcchange1": "Welcome to Q-Chat", @@ -521,7 +527,7 @@ "bcchange13": "Reaction", "bcchange14": "Forward", "bcchange15": "Message Forwarded", - "bcchange16": "Choose recipient", + "bcchange16": "Choose Recipient or Search for One Below", "bcchange17": "FORWARDED" }, "grouppage": { diff --git a/qortal-ui-core/package.json b/qortal-ui-core/package.json index b293210f..1e00ccfb 100644 --- a/qortal-ui-core/package.json +++ b/qortal-ui-core/package.json @@ -77,7 +77,8 @@ "rollup-plugin-postcss": "4.0.2", "rollup-plugin-progress": "1.1.2", "rollup-plugin-scss": "3.0.0", - "rollup-plugin-terser": "7.0.2" + "rollup-plugin-terser": "7.0.2", + "rollup-plugin-web-worker-loader": "^1.6.1" }, "engines": { "node": ">=16.15.0" diff --git a/qortal-ui-core/src/components/app-info.js b/qortal-ui-core/src/components/app-info.js index 06bedc8a..e7372515 100644 --- a/qortal-ui-core/src/components/app-info.js +++ b/qortal-ui-core/src/components/app-info.js @@ -3,6 +3,8 @@ import { connect } from 'pwa-helpers' import { store } from '../store.js' import { doPageUrl } from '../redux/app/app-actions.js' import { translate, translateUnsafeHTML } from 'lit-translate' +import WebWorker from 'web-worker:./computePowWorker.js'; +import { routes } from '../plugins/routes.js'; import '@material/mwc-icon' import '@material/mwc-button' @@ -94,6 +96,8 @@ class AppInfo extends connect(store)(LitElement) { this.nodeStatus = {} this.pageUrl = '' this.theme = localStorage.getItem('qortalTheme') ? localStorage.getItem('qortalTheme') : 'light' + this.publicKeyisOnChainConfirmation = false + this.interval } render() { @@ -107,10 +111,110 @@ class AppInfo extends connect(store)(LitElement) { ` } + async confirmPublicKeyOnChain(address) { + const _computePow2 = async (chatBytes) => { + const difficulty = 15; + const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full' + const worker = new WebWorker(); + let nonce = null + let chatBytesArray = null + await new Promise((res, rej) => { + worker.postMessage({chatBytes, path, difficulty}); + + worker.onmessage = e => { + worker.terminate() + chatBytesArray = e.data.chatBytesArray + nonce = e.data.nonce + res() + + } + }) + + let _response = await routes.sign_chat({ + data: { + nonce: store.getState().app.selectedAddress.nonce, + chatBytesArray: chatBytesArray, + chatNonce: nonce + }, + + }); + return _response + }; + + + let stop = false + const checkPublicKey = async () => { + if (!stop) { + stop = true; + try { + const myNode = store.getState().app.nodeConfig.knownNodes[store.getState().app.nodeConfig.node]; + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; + const url = `${nodeUrl}/addresses/publickey/${address}`; + const res = await fetch(url) + let data = '' + try { + data = await res.text(); + } catch (error) { + data = { + error: 'error' + } + } + if(data === 'false' && this.nodeInfo.isSynchronizing !== true){ + let _reference = new Uint8Array(64); + window.crypto.getRandomValues(_reference); + let reference = window.parent.Base58.encode(_reference); + const chatRes = await routes.chat({ + data: { + type: 19, + nonce: store.getState().app.selectedAddress.nonce, + params: { + lastReference: reference, + proofOfWorkNonce: 0, + fee: 0, + timestamp: Date.now(), + + }, + disableModal: true + }, + disableModal: true, + }); + + try { + const powRes = await _computePow2(chatRes) + if(powRes === true){ + clearInterval(this.interval) + + this.publicKeyisOnChainConfirmation = true + } + } catch (error) { + console.error(error) + } + } + + if (!data.error && data !== 'false' && data) { + clearInterval(this.interval) + + this.publicKeyisOnChainConfirmation = true + } + + } catch (error) { + } + stop = false + } + }; + this.interval = setInterval(checkPublicKey, 5000); + } + firstUpdated() { this.getNodeInfo() this.getCoreInfo() - + try { + this.confirmPublicKeyOnChain(store.getState().app.selectedAddress.address) + } catch (error) { + console.error(error) + } + + setInterval(() => { this.getNodeInfo() this.getCoreInfo() diff --git a/qortal-ui-core/src/components/computePowWorker.js b/qortal-ui-core/src/components/computePowWorker.js new file mode 100644 index 00000000..2ed60a20 --- /dev/null +++ b/qortal-ui-core/src/components/computePowWorker.js @@ -0,0 +1,82 @@ +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.chatBytes, e.data.path, e.data.difficulty) + postMessage(response) + +}) + + +const memory = new WebAssembly.Memory({ initial: 256, maximum: 256 }) +const heap = new Uint8Array(memory.buffer) + + + +const computePow = async (chatBytes, path, difficulty) => { + + let response = null + + await new Promise((resolve, reject)=> { + + const _chatBytesArray = Object.keys(chatBytes).map(function (key) { return chatBytes[key]; }); + const chatBytesArray = new Uint8Array(_chatBytesArray); + const chatBytesHash = new Sha256().process(chatBytesArray).finish().result; + const hashPtr = sbrk(32, heap); + const hashAry = new Uint8Array(memory.buffer, hashPtr, 32); + hashAry.set(chatBytesHash); + + + const workBufferLength = 8 * 1024 * 1024; + const workBufferPtr = sbrk(workBufferLength, heap); + + + + const importObject = { + env: { + memory: memory + }, + }; + + function loadWebAssembly(filename, imports) { + // Fetch the file and compile it + return fetch(filename) + .then(response => response.arrayBuffer()) + .then(buffer => WebAssembly.compile(buffer)) + .then(module => { + + // Create the instance. + return new WebAssembly.Instance(module, importObject); + }); +} + + +loadWebAssembly(path) + .then(wasmModule => { + response = { + nonce : wasmModule.exports.compute2(hashPtr, workBufferPtr, workBufferLength, difficulty), + chatBytesArray + } + + resolve() + + }); + + + }) + + return response +} \ No newline at end of file diff --git a/qortal-ui-core/src/styles/switch-theme.css b/qortal-ui-core/src/styles/switch-theme.css index a3108823..72dfa151 100644 --- a/qortal-ui-core/src/styles/switch-theme.css +++ b/qortal-ui-core/src/styles/switch-theme.css @@ -46,6 +46,8 @@ html { --chatHeadBgActive: #ebebeb; --chatHeadText: #080808; --chatHeadTextActive: #080808; + --group-header: #929292; + --group-drop-shadow: rgb(17 17 26 / 10%) 0px 1px 0px; } html[theme="dark"] { @@ -96,4 +98,6 @@ html[theme="dark"] { --chatHeadBgActive: #0f1a2e; --chatHeadText: #ffffff; --chatHeadTextActive: #ffffff; + --group-header: #c8c8c8; + --group-drop-shadow: rgb(191 191 191 / 32%) 0px 1px 0px } \ No newline at end of file diff --git a/qortal-ui-core/tooling/generateBuildConfig.js b/qortal-ui-core/tooling/generateBuildConfig.js index e8beb2b8..6d163ae9 100644 --- a/qortal-ui-core/tooling/generateBuildConfig.js +++ b/qortal-ui-core/tooling/generateBuildConfig.js @@ -7,6 +7,8 @@ const commonjs = require('@rollup/plugin-commonjs') const alias = require('@rollup/plugin-alias') const { terser } = require('rollup-plugin-terser') const scss = require('rollup-plugin-scss') +const webWorkerLoader = require('rollup-plugin-web-worker-loader'); + const generateES5BuildConfig = require('./generateES5BuildConfig') @@ -61,6 +63,7 @@ const generateBuildConfig = ({ elementComponents, functionalComponents, otherOut commonjs(), globals(), progress(), + webWorkerLoader(), scss({ output: options.sassOutputDir }), diff --git a/qortal-ui-core/tooling/generateES5BuildConfig.js b/qortal-ui-core/tooling/generateES5BuildConfig.js index 2b5d15b1..a746a6c1 100644 --- a/qortal-ui-core/tooling/generateES5BuildConfig.js +++ b/qortal-ui-core/tooling/generateES5BuildConfig.js @@ -6,6 +6,7 @@ const progress = require('rollup-plugin-progress'); const { terser } = require("rollup-plugin-terser"); const path = require('path'); const alias = require('@rollup/plugin-alias'); +const webWorkerLoader = require('rollup-plugin-web-worker-loader'); const generateRollupConfig = (file, { outputDir, aliases }) => { @@ -36,6 +37,7 @@ const generateRollupConfig = (file, { outputDir, aliases }) => { }), commonjs(), progress(), + webWorkerLoader(), babel.babel({ babelHelpers: 'bundled', exclude: 'node_modules/**' diff --git a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js index d4982bcb..20dd0ebc 100644 --- a/qortal-ui-crypto/api/transactions/PublicizeTransaction.js +++ b/qortal-ui-crypto/api/transactions/PublicizeTransaction.js @@ -1,5 +1,6 @@ "use strict"; import ChatBase from "./chat/ChatBase.js" +import { QORT_DECIMALS } from "../constants.js" export default class PublicizeTransaction extends ChatBase { constructor() { @@ -11,13 +12,17 @@ export default class PublicizeTransaction extends ChatBase { set proofOfWorkNonce(proofOfWorkNonce) { this._proofOfWorkNonce = this.constructor.utils.int32ToBytes(proofOfWorkNonce) } - + set fee(fee) { + this._fee = fee * QORT_DECIMALS + this._feeBytes = this.constructor.utils.int64ToBytes(this._fee) + } get params() { const params = super.params; params.push( this._proofOfWorkNonce, this._feeBytes ) + console.log({params}) return params; } } diff --git a/qortal-ui-plugins/package.json b/qortal-ui-plugins/package.json index 59282688..cde55b60 100644 --- a/qortal-ui-plugins/package.json +++ b/qortal-ui-plugins/package.json @@ -51,12 +51,12 @@ "@rollup/plugin-commonjs": "23.0.0", "@rollup/plugin-node-resolve": "15.0.0", "@rollup/plugin-replace": "5.0.0", + "@vaadin/avatar": "23.2.5", "@vaadin/button": "23.2.5", "@vaadin/grid": "23.2.5", + "@vaadin/horizontal-layout": "23.2.5", "@vaadin/icons": "23.2.5", "@vaadin/tabs": "23.2.5", - "@vaadin/avatar": "23.2.5", - "@vaadin/horizontal-layout": "23.2.5", "epml": "0.3.3", "file-saver": "2.0.5", "html-escaper": "3.0.3", diff --git a/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js b/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js index da5f951d..ac50df20 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js +++ b/qortal-ui-plugins/plugins/core/components/ChatGroupSettings.js @@ -43,9 +43,11 @@ class ChatGroupSettings extends LitElement { width: 18px; transition: .2s all; } + .top-bar-icon:hover { color: var(--black) } + .modal-button { font-family: Roboto, sans-serif; font-size: 16px; diff --git a/qortal-ui-plugins/plugins/core/components/ChatModals.js b/qortal-ui-plugins/plugins/core/components/ChatModals.js index c9daf3b4..a41f6748 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatModals.js +++ b/qortal-ui-plugins/plugins/core/components/ChatModals.js @@ -366,7 +366,6 @@ class ChatModals extends LitElement {

{ - console.log("here500"); this._sendMessage(); } }>${translate('welcomepage.wcchange6')} diff --git a/qortal-ui-plugins/plugins/core/components/ChatPage.js b/qortal-ui-plugins/plugins/core/components/ChatPage.js index 25fae5b4..e93498b3 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatPage.js +++ b/qortal-ui-plugins/plugins/core/components/ChatPage.js @@ -17,23 +17,23 @@ import './ChatScroller.js'; import './LevelFounder.js'; import './NameMenu.js'; import './TimeAgo.js'; -import './ChatTextEditor'; -import './WrapperModal'; +import './ChatTextEditor.js'; +import './WrapperModal.js'; import './ChatSelect.js' import './ChatSideNavHeads.js' import './ChatLeaveGroup.js' import './ChatGroupSettings.js' import './ChatRightPanel.js' +import './ChatSeachResults.js'; import '@polymer/paper-spinner/paper-spinner-lite.js'; import '@material/mwc-button'; import '@material/mwc-dialog'; import '@material/mwc-icon'; import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js'; import { publishData } from '../../utils/publish-image.js'; +import { EmojiPicker } from 'emoji-picker-js'; import WebWorker from 'web-worker:./computePowWorker.js'; import WebWorkerImage from 'web-worker:./computePowWorkerImage.js'; -import { EmojiPicker } from 'emoji-picker-js'; - // const messagesCache = localForage.createInstance({ // name: "messages-cache", @@ -61,8 +61,9 @@ class ChatPage extends LitElement { _initialMessages: { type: Array }, isUserDown: { type: Boolean }, isPasteMenuOpen: { type: Boolean }, - showNewMesssageBar: { attribute: false }, - hideNewMesssageBar: { attribute: false }, + showNewMessageBar: { attribute: false }, + hideNewMessageBar: { attribute: false }, + setOpenPrivateMessage: { attribute: false }, chatEditorPlaceholder: { type: String }, messagesRendered: { type: Array }, repliedToMessageObj: { type: Object }, @@ -74,507 +75,711 @@ class ChatPage extends LitElement { chatEditorNewChat: { type: Object }, userLanguage: { type: String }, lastMessageRefVisible: { type: Boolean }, - isLoadingOldMessages: {type: Boolean}, + isLoadingOldMessages: { type: Boolean }, isEditMessageOpen: { type: Boolean }, - webSocket: {attribute: false}, - chatHeads: {type: Array}, - forwardActiveChatHeadUrl: {type: String}, - openForwardOpen: {type: Boolean}, + webSocket: { attribute: false }, + chatHeads: { type: Array }, + forwardActiveChatHeadUrl: { type: Object }, + openForwardOpen: {type: Boolean }, groupAdmin: {type: Array}, groupMembers: {type: Array}, shifted: {type: Boolean}, groupInfo: {type: Object}, - setActiveChatHeadUrl: {attribute: false} + setActiveChatHeadUrl: {attribute: false}, + userFound: { type: Array }, + userFoundModalOpen: { type: Boolean }, + webWorker: { type: Object }, + webWorkerImage: { type: Object } } } static get styles() { - return css` - html { - scroll-behavior: smooth; - } - - .chat-head-container { - display: flex; - justify-content: flex-start; - flex-direction: column; - height: 50vh; - overflow-y: auto; - width: 100%; - } - - - - .chat-text-area { - display: flex; - position: relative; - justify-content: center; - min-height: 60px; - max-height: 100%; - } - - .chat-text-area .typing-area { - display: flex; - flex-direction: column; - width: 98%; - box-sizing: border-box; - margin-bottom: 8px; - border: 1px solid var(--chat-bubble-bg); - border-radius: 10px; - background: var(--chat-bubble-bg); - } - - .chat-text-area .typing-area textarea { - display: none; - } - - .chat-text-area .typing-area .chat-editor { - display: flex; - max-height: -webkit-fill-available; - width: 100%; - border-color: transparent; - margin: 0; - padding: 0; - border: none; - } - - .repliedTo-container { - display: flex; - flex-direction: row; - justify-content: space-between; - align-items: center; - padding: 10px 10px 8px 10px; - } - - .repliedTo-subcontainer { - display: flex; - flex-direction: row; - align-items: center; - gap: 15px; - width: 100%; - } - - .repliedTo-message { - display: flex; - flex-direction: column; - gap: 5px; - width: 100%; - } - - .senderName { - margin: 0; - color: var(--mdc-theme-primary); - font-weight: bold; - user-select: none; - } - - .original-message { - color: var(--chat-bubble-msg-color); - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - margin: 0; - width: 800px; - } - - .reply-icon { - width: 20px; - color: var(--mdc-theme-primary); - } - - .close-icon { - color: #676b71; - width: 18px; - transition: all 0.1s ease-in-out; - } - - .close-icon:hover { - cursor: pointer; - color: #494c50; - } - - .chat-text-area .typing-area .chatbar { - position: relative; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: auto; - padding: 5px 5px 5px 7px; - overflow-y: hidden; - } - - .chatbar-container { - width: 100%; - display: flex; - height: auto; - overflow: hidden; - } - - .chat-text-area .typing-area .emoji-button { - width: 45px; - height: 40px; - padding-top: 4px; - border: none; - outline: none; - background: transparent; - cursor: pointer; - max-height: 40px; - color: var(--black); - } - - .emoji-button-caption { - width: 45px; - height: 40px; - padding-top: 4px; - border: none; - outline: none; - background: transparent; - cursor: pointer; - max-height: 40px; - color: var(--black); - } - - .caption-container { - width: 100%; - display: flex; - height: auto; - overflow: hidden; - justify-content: center; - background-color: var(--white); - padding: 5px; - border-radius: 1px; - } - - .chatbar-caption { - font-family: Roboto, sans-serif; - width: 70%; - margin-right: 10px; - outline: none; - align-items: center; - font-size: 18px; - resize: none; - border-top: 0; - border-right: 0; - border-left: 0; - border-bottom: 1px solid #cac8c8; - padding: 3px; - } - - .message-size-container { - display: flex; - justify-content: flex-end; - width: 100%; - } - - .message-size { - font-family: Roboto, sans-serif; - font-size: 12px; - color: black; - } - - .lds-grid { - width: 120px; - height: 120px; - position: absolute; - left: 50%; - top: 40%; - } - - .lds-grid div { - position: absolute; - width: 34px; - height: 34px; - border-radius: 50%; - background: #03a9f4; - animation: lds-grid 1.2s linear infinite; - } - - .lds-grid div:nth-child(1) { - top: 4px; - left: 4px; - animation-delay: 0s; - } - - .lds-grid div:nth-child(2) { - top: 4px; - left: 48px; - animation-delay: -0.4s; - } - - .lds-grid div:nth-child(3) { - top: 4px; - left: 90px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(4) { - top: 50px; - left: 4px; - animation-delay: -0.4s; - } - - .lds-grid div:nth-child(5) { - top: 50px; - left: 48px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(6) { - top: 50px; - left: 90px; - animation-delay: -1.2s; - } - - .lds-grid div:nth-child(7) { - top: 95px; - left: 4px; - animation-delay: -0.8s; - } - - .lds-grid div:nth-child(8) { - top: 95px; - left: 48px; - animation-delay: -1.2s; - } - - .lds-grid div:nth-child(9) { - top: 95px; - left: 90px; - animation-delay: -1.6s; - } - - @keyframes lds-grid { - 0%, 100% { - opacity: 1; - } - 50% { - opacity: 0.5; - } - } - - .float-left { - float: left; - } - - img { - border-radius: 25%; - } - - .dialogCustom { - position: fixed; - z-index: 10000; - display: flex; - justify-content: center; - flex-direction: column; - align-items: center; - top: 10px; - right: 20px; - user-select: none; - } - - .dialogCustom p { - color: var(--black) - } - - .dialogCustomInner { - min-width: 300px; - height: 40px; - background-color: var(--white); - box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; - padding: 10px; - border-radius: 4px; - } - - .dialogCustomInner ul { - padding-left: 0px - } - .dialogCustomInner li { - margin-bottom: 10px; - } - - .marginLoader { - margin-right: 8px; - } - - .smallLoading, - .smallLoading:after { - border-radius: 50%; - width: 2px; - height: 2px; - } - - .smallLoading { - border-width: 0.8em; - border-style: solid; - border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2) - rgba(3, 169, 244, 0.2) rgb(3, 169, 244); - font-size: 10px; - position: relative; - text-indent: -9999em; - transform: translateZ(0px); - animation: 1.1s linear 0s infinite normal none running loadingAnimation; - } - - @-webkit-keyframes loadingAnimation { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - @keyframes loadingAnimation { - 0% { - -webkit-transform: rotate(0deg); - transform: rotate(0deg); - } - 100% { - -webkit-transform: rotate(360deg); - transform: rotate(360deg); - } - } - - /* Add Image Modal Dialog Styling */ - - .dialog-container { - position: relative; - display: flex; - align-items: center; - flex-direction: column; - padding: 0 10px; - gap: 10px; - height: 100%; - } - - .dialog-container-title { - color: var(--black); - font-size: 18px; - } - - .dialog-container-loader { - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - gap: 10px; - height: 100%; - } - - .dialog-image { - width: 100%; - max-height: 300px; - border-radius: 0; - object-fit: contain; - } - - .last-message-ref { - position: absolute; - font-size: 18px; - top: -40px; - right: 30px; - width: 50; - height: 50; - z-index: 5; - color: black; - background-color: white; - border-radius: 50%; - transition: all 0.1s ease-in-out; - } - - .last-message-ref:hover { - cursor: pointer; - transform: scale(1.1); - } - - .arrow-down-icon { - transform: scale(1.15); - } - - .modal-button-row { - display: flex; - align-items: center; - justify-content: space-between; - width: 100%; - } - - .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; - } - .chat-container { - display: grid; - grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); - max-height: 100%; - flex: 3; - } - .chat-right-panel { - flex: 0; - border-left: 3px solid rgb(221, 221, 221); - height: 100%; - overflow-y: auto; - background: transparent; - } - .movedin { - flex: 1 !important; - background: transparent; - } - - .chat-right-panel-label { - color: white; - padding: 5px; - font-size: 16px; - user-select: none; - } - .main-container { - display: flex; - height: 100%; - } - .top-bar-icon { - cursor: pointer; - height: 18px; - width: 18px; - transition: .2s all; - } - .top-bar-icon:hover { - color: var(--black) - } - ` + return css` + html { + scroll-behavior: smooth; } + + .chat-head-container { + display: flex; + justify-content: flex-start; + flex-direction: column; + height: 50vh; + overflow-y: auto; + width: 100%; + } + + .repliedTo-container { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px 10px 8px 10px; + } + + .senderName { + margin: 0; + color: var(--mdc-theme-primary); + font-weight: bold; + user-select: none; + } + + .original-message { + color: var(--chat-bubble-msg-color); + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + margin: 0; + width: 800px; + } + + + .close-icon { + color: #676b71; + width: 18px; + transition: all 0.1s ease-in-out; + } + + .close-icon:hover { + cursor: pointer; + color: #494c50; + } + + .chat-text-area .typing-area .chatbar { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: auto; + padding: 5px 5px 5px 7px; + overflow-y: hidden; + } + + .chat-text-area .typing-area .emoji-button { + width: 45px; + height: 40px; + padding-top: 4px; + border: none; + outline: none; + background: transparent; + cursor: pointer; + max-height: 40px; + color: var(--black); + } + + .emoji-button-caption { + width: 45px; + height: 40px; + padding-top: 4px; + border: none; + outline: none; + background: transparent; + cursor: pointer; + max-height: 40px; + color: var(--black); + } + + .caption-container { + width: 100%; + display: flex; + height: auto; + overflow: hidden; + justify-content: center; + background-color: var(--white); + padding: 5px; + border-radius: 1px; + } + + .chatbar-caption { + font-family: Roboto, sans-serif; + width: 70%; + margin-right: 10px; + outline: none; + align-items: center; + font-size: 18px; + resize: none; + border-top: 0; + border-right: 0; + border-left: 0; + border-bottom: 1px solid #cac8c8; + padding: 3px; + } + + .message-size-container { + display: flex; + justify-content: flex-end; + width: 100%; + } + + .message-size { + font-family: Roboto, sans-serif; + font-size: 12px; + color: black; + } + + .lds-grid { + width: 120px; + height: 120px; + position: absolute; + left: 50%; + top: 40%; + } + + img { + border-radius: 25%; + } + + .dialogCustom { + position: fixed; + z-index: 10000; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + top: 10px; + right: 20px; + user-select: none; + } + + .dialogCustomInner { + min-width: 300px; + height: 40px; + background-color: var(--white); + box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; + padding: 10px; + border-radius: 4px; + } + + .dialogCustomInner ul { + padding-left: 0px + } + + .dialogCustomInner li { + margin-bottom: 10px; + } + + .marginLoader { + margin-right: 8px; + } + + .last-message-ref { + position: absolute; + font-size: 18px; + top: -40px; + right: 30px; + width: 50; + height: 50; + z-index: 5; + color: black; + background-color: white; + border-radius: 50%; + transition: all 0.1s ease-in-out; + } + + .last-message-ref:hover { + cursor: pointer; + transform: scale(1.1); + } + + .arrow-down-icon { + transform: scale(1.15); + } + + .chat-container { + display: grid; + grid-template-rows: minmax(6%, 92vh) minmax(40px, auto); + max-height: 100%; + } + + .chat-text-area { + display: flex; + position: relative; + justify-content: center; + min-height: 60px; + max-height: 100%; + } + + .chat-text-area .typing-area { + display: flex; + flex-direction: column; + width: 98%; + box-sizing: border-box; + margin-bottom: 8px; + border: 1px solid var(--chat-bubble-bg); + border-radius: 10px; + background: var(--chat-bubble-bg); + } + + .chat-text-area .typing-area textarea { + display: none; + } + + .chat-text-area .typing-area .chat-editor { + display: flex; + max-height: -webkit-fill-available; + width: 100%; + border-color: transparent; + margin: 0; + padding: 0; + border: none; + } + + .repliedTo-container { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 10px 10px 8px 10px; + } + + .repliedTo-subcontainer { + display: flex; + flex-direction: row; + align-items: center; + gap: 15px; + width: 100%; + } + + .repliedTo-message { + display: flex; + flex-direction: column; + gap: 5px; + width: 100%; + } + + .reply-icon { + width: 20px; + color: var(--mdc-theme-primary); + } + + .close-icon { + color: #676b71; + width: 18px; + transition: all 0.1s ease-in-out; + } + + .close-icon:hover { + cursor: pointer; + color: #494c50; + } + + .chatbar-container { + width: 100%; + display: flex; + height: auto; + overflow: hidden; + } + + .lds-grid { + width: 120px; + height: 120px; + position: absolute; + left: 50%; + top: 40%; + } + + .lds-grid div { + position: absolute; + width: 34px; + height: 34px; + border-radius: 50%; + background: #03a9f4; + animation: lds-grid 1.2s linear infinite; + } + + .lds-grid div:nth-child(1) { + top: 4px; + left: 4px; + animation-delay: 0s; + } + + .lds-grid div:nth-child(2) { + top: 4px; + left: 48px; + animation-delay: -0.4s; + } + + .lds-grid div:nth-child(3) { + top: 4px; + left: 90px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(4) { + top: 50px; + left: 4px; + animation-delay: -0.4s; + } + + .lds-grid div:nth-child(5) { + top: 50px; + left: 48px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(6) { + top: 50px; + left: 90px; + animation-delay: -1.2s; + } + + .lds-grid div:nth-child(7) { + top: 95px; + left: 4px; + animation-delay: -0.8s; + } + + .lds-grid div:nth-child(8) { + top: 95px; + left: 48px; + animation-delay: -1.2s; + } + + .lds-grid div:nth-child(9) { + top: 95px; + left: 90px; + animation-delay: -1.6s; + } + + @keyframes lds-grid { + 0%, 100% { + opacity: 1; + } + 50% { + opacity: 0.5; + } +} + + .float-left { + float: left; + } + + .dialogCustom { + position: fixed; + z-index: 10000; + display: flex; + justify-content: center; + flex-direction: column; + align-items: center; + top: 10px; + right: 20px; + user-select: none; + } + + .dialogCustom p { + color: var(--black) + } + + .dialogCustomInner { + min-width: 300px; + height: 40px; + background-color: var(--white); + box-shadow: rgb(119 119 119 / 32%) 0px 4px 12px; + padding: 10px; + border-radius: 4px; + } + + .dialogCustomInner ul { + padding-left: 0px + } + + .dialogCustomInner li { + margin-bottom: 10px; + } + + .marginLoader { + margin-right: 8px; + } + + .smallLoading, + .smallLoading:after { + border-radius: 50%; + width: 2px; + height: 2px; + } + + .smallLoading { + border-width: 0.8em; + border-style: solid; + border-color: rgba(3, 169, 244, 0.2) rgba(3, 169, 244, 0.2) + rgba(3, 169, 244, 0.2) rgb(3, 169, 244); + font-size: 10px; + position: relative; + text-indent: -9999em; + transform: translateZ(0px); + animation: 1.1s linear 0s infinite normal none running loadingAnimation; + } + + @-webkit-keyframes loadingAnimation { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + + @keyframes loadingAnimation { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } + } + + /* Add Image Modal Dialog Styling */ + + .dialog-container { + position: relative; + display: flex; + align-items: center; + flex-direction: column; + padding: 0 10px; + gap: 10px; + height: 100%; + } + + .dialog-container-title { + font-family: Montserrat; + color: var(--black); + font-size: 20px; + margin: 15px 0 0 0; + } + + .divider { + height: 1px; + background-color: var(--chat-bubble-msg-color); + user-select: none; + width: 70%; + margin-bottom: 20px; + } + + .dialog-container-loader { + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + gap: 10px; + height: 100%; + } + + .dialog-image { + width: 100%; + max-height: 300px; + border-radius: 0; + object-fit: contain; + } + + .chat-container { + display: grid; + grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); + max-height: 100%; + flex: 3; + } + + .chat-right-panel { + flex: 0; + border-left: 3px solid rgb(221, 221, 221); + height: 100%; + overflow-y: auto; + background: transparent; + } + + .movedin { + flex: 1 !important; + background: transparent; + } + + .main-container { + display: flex; + height: 100%; + } + + .group-nav-container { + display: flex; + height: 40px; + padding: 25px 5px 25px 20px; + margin: 0px; + background-color: var(--chat-bubble-bg); + box-sizing: border-box; + align-items: center; + justify-content: space-between; + box-shadow: var(--group-drop-shadow); + } + + .top-bar-icon { + border-radius: 50%; + color: var(--chat-bubble-msg-color); + transition: 0.3s all ease-in-out; + padding: 5px; + background-color: transparent; + } + + .top-bar-icon:hover { + background-color: #e6e6e69b; + cursor: pointer; + color: var(--black) + } + + .group-name { + font-family: Raleway, sans-serif; + font-size: 16px; + color: var(--black); + margin:0px; + padding:0px; + } + + .modal-button-row { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + + .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; + } + + .name-input { + width: 100%; + margin-bottom: 15px; + 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); + } + + .name-input::selection { + background-color: var(--mdc-theme-primary); + color: white; + } + + .name-input::placeholder { + opacity: 0.9; + color: var(--black); + } + + .search-results-div { + position: absolute; + top: 25px; + right: 25px; + } + + .search-field { + width: 100%; + position: relative; + margin-bottom: 5px; + } + + .search-icon { + position: absolute; + right: 3px; + top: 0; + color: var(--chat-bubble-msg-color); + transition: all 0.3s ease-in-out; + background: none; + border-radius: 50%; + padding: 6px 3px; + font-size: 21px; + } + + .search-icon:hover { + cursor: pointer; + background: #d7d7d75c; + } + + .user-verified { + position: absolute; + top: 0; + right: 5px; + display: flex; + align-items: center; + gap: 10px; + color: #04aa2e; + font-size: 13px; + } + + .user-selected { + display: flex; + justify-content: space-between; + align-items: center; + margin: 0; + box-shadow: rgb(0 0 0 / 16%) 0px 3px 6px, rgb(0 0 0 / 23%) 0px 3px 6px; + padding: 18px 20px; + color: var(--chat-bubble-msg-color); + border-radius: 5px; + background-color: #ececec96; + } + + .user-selected-name { + font-family: Roboto, sans-serif; + margin: 0; + font-size: 16px; + } + + .forwarding-container { + display: flex; + gap: 15px; + } + + .user-selected-forwarding { + font-family: Livvic, sans-serif; + margin: 0; + font-size: 16px; + } + + .close-forwarding { + color: #676b71; + width: 14px; + transition: all 0.1s ease-in-out; + } + + .close-forwarding:hover { + cursor: pointer; + color: #4e5054; + } +` +} constructor() { super() - this.changeMsgInput = this.changeMsgInput.bind(this) this.getOldMessage = this.getOldMessage.bind(this) this._sendMessage = this._sendMessage.bind(this) this.insertImage = this.insertImage.bind(this) @@ -620,6 +825,15 @@ class ChatPage extends LitElement { this.shifted = false this.groupInfo = {} this.pageNumber = 1 + this.userFoundModalOpen = false + this.userFound = [] + this.forwardActiveChatHeadUrl = { + url: "", + name: "", + selected: false + } + this.webWorker = null; + this.webWorkerImage = null; } _toggle(value) { @@ -629,21 +843,20 @@ class ChatPage extends LitElement { } render() { - console.log('this._chatId', this._chatId) return html`
${(!this.isReceipient && +this._chatId !== 0) ? html` -
+
-

${this.groupInfo && this.groupInfo.groupName}

+

${this.groupInfo && this.groupInfo.groupName}

- this.setActiveChatHeadUrl(val)}> + - this.setActiveChatHeadUrl(val)}> +
` : html`
`} @@ -723,9 +936,7 @@ class ChatPage extends LitElement { .chatEditor=${this.chatEditor} .imageFile=${this.imageFile} .insertImage=${this.insertImage} - .chatMessageInput=${this.chatMessageInput} .editedMessageObj=${this.editedMessageObj} - .mirrorChatInput=${this.mirrorChatInput} ?isLoading=${this.isLoading} ?isLoadingMessages=${this.isLoadingMessages} ?isEditMessageOpen=${this.isEditMessageOpen}> @@ -749,10 +960,10 @@ class ChatPage extends LitElement {
`: ''} { - this.chatEditorNewChat.resetValue() - this.removeImage() - } } + .onClickFunc=${() => { + this.chatEditorNewChat.resetValue(); + this.removeImage(); + }} style=${(this.imageFile && !this.isUploadingImage) ? "display: block" : "display: none"}>
@@ -778,14 +989,15 @@ class ChatPage extends LitElement {
{ - this.openForwardOpen = false - this.forwardActiveChatHeadUrl = "" + .onClickFunc=${() => { + this.openForwardOpen = false; + this.forwardActiveChatHeadUrl = {}; + this.chatEditor.enable(); + this.requestUpdate(); } } style=${this.openForwardOpen ? "display: block" : "display: none"}>
@@ -810,18 +1024,88 @@ class ChatPage extends LitElement {

${translate("blockpage.bcchange16")}

+
- ${this.chatHeads.map((item)=> { - return html` { - this.forwardActiveChatHeadUrl = val - }} chatInfo=${JSON.stringify(item)}>` - })} -
+
+ { + this.forwardActiveChatHeadUrl = {}; + this.requestUpdate(); + } + } + /> + ${this.forwardActiveChatHeadUrl.selected ? ( + html` +
+

${translate("chatpage.cchange38")}

+ +
+ ` + ) : ( + html` + + + ` + )} +
+ ${this.forwardActiveChatHeadUrl.selected ? ( + html` +
+

+ ${this.forwardActiveChatHeadUrl.name} +

+
+

+ Forwarding... +

+ { + this.userFound = []; + this.forwardActiveChatHeadUrl = {}; + this.requestUpdate(); + this.shadowRoot.getElementById("sendTo").value = ""; + }}> + +
+
+ ` + ) : ( + html` + ${this.chatHeads.map((item) => { + return html` + { + this.forwardActiveChatHeadUrl = { + ...this.forwardActiveChatHeadUrl, + url: val + }; + this.userFound = []; + }} + chatInfo=${JSON.stringify(item)}> + ` + })} + ` + )} +
-
+
+ { + this.forwardActiveChatHeadUrl = { + ...this.forwardActiveChatHeadUrl, + url: `direct/${result.owner}`, + name: result.name, + selected: true + }; + this.userFound = []; + this.userFoundModalOpen = false; + }} + .closeFunc=${() => { + this.userFoundModalOpen = false; + this.userFound = []; + }} + .searchResults=${this.userFound} + ?isOpen=${this.userFoundModalOpen} + ?loading=${this.isLoading}> + +
+
@@ -877,41 +1182,58 @@ class ChatPage extends LitElement { } } + connectedCallback() { + super.connectedCallback(); + this.webWorker = new WebWorker(); + this.webWorkerImage = new WebWorkerImage(); + } + + disconnectedCallback() { + super.disconnectedCallback(); + this.webWorker.terminate(); + this.webWorkerImage.terminate(); + } + + async userSearch() { + const nameValue = this.shadowRoot.getElementById('sendTo').value; + if (!nameValue) { + this.userFound = []; + this.userFoundModalOpen = true; + return; + } + try { + const result = await parentEpml.request('apiCall', { + type: 'api', + url: `/names/${nameValue}` + }) + if (result.error === 401) { + this.userFound = []; + } else { + this.userFound = [ + ...this.userFound, + result, + ]; + } + this.userFoundModalOpen = true; + } catch (error) { + console.error(error); + let err4string = get("chatpage.cchange35"); + parentEpml.request('showSnackBar', `${err4string}`) + } + } + setForwardProperties(forwardedMessage){ this.openForwardOpen = true this.forwardedMessage = forwardedMessage } - - async sendForwardMessage(){ - let parsedMessageObj = {} - let publicKey = { - hasPubKey: false, - key: '' - } + + async sendForwardMessage() { + let parsedMessageObj = {}; try { parsedMessageObj = JSON.parse(this.forwardedMessage); - - } catch (error) { - parsedMessageObj = {} - } - - try { - const res = await parentEpml.request('apiCall', { - type: 'api', - url: `/addresses/publickey/${this.forwardChatId}` - }) - if (res.error === 102) { - publicKey.key = '' - publicKey.hasPubKey = false - } else if (res !== false) { - publicKey.key = res - publicKey.hasPubKey = true - } else { - publicKey.key = '' - publicKey.hasPubKey = false - } - } catch (error) { - + } + catch (error) { + parsedMessageObj = {}; } try { @@ -920,17 +1242,10 @@ class ChatPage extends LitElement { type: 'forward' } delete message.reactions - const stringifyMessageObject = JSON.stringify(message) - this.sendMessage(stringifyMessageObject, undefined, '', true, { - isReceipient: true, - chatId: 'Qdxha59Cm1Ty4QkKMBWPnKrNigcDCDk6eq', - publicKey: { - hasPubKey: false, - key: '' - } - }) + const stringifyMessageObject = JSON.stringify(message); + this.sendMessage(stringifyMessageObject, undefined, '', true) } catch (error) { - console.log({error}) + console.log({error}); } } @@ -950,9 +1265,6 @@ class ChatPage extends LitElement { if (file.type.includes('image')) { this.imageFile = file; this.chatEditor.disable(); - // this.changeMsgInput('newChat') - // this.initChatEditor(); - // this.chatEditor.disable(); return; } parentEpml.request('showSnackBar', get("chatpage.cchange28")); @@ -1121,9 +1433,16 @@ class ChatPage extends LitElement { } } + if (changedProperties && changedProperties.has('chatId') && changedProperties.get('chatId')) { await this.initUpdate() } + + if (changedProperties && changedProperties.has('openForwardOpen')) { + if (this.openForwardOpen === true) { + this.chatEditor.disable(); + } + } } @@ -1189,6 +1508,7 @@ async getName (recipient) { ?isLoadingMessages=${this.isLoadingOldMessages} .setIsLoadingMessages=${(val) => this.setIsLoadingMessages(val)} .setForwardProperties=${(forwardedMessage)=> this.setForwardProperties(forwardedMessage)} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} > ` @@ -1400,7 +1720,7 @@ async getName (recipient) { this.messagesRendered = [...this.messagesRendered, newMessage] await this.getUpdateComplete(); - this.showNewMesssageBar(); + this.showNewMessageBar(); } } @@ -1639,7 +1959,39 @@ async getName (recipient) { } async _sendMessage(outSideMsg) { + if(this.isReceipient){ + let hasPublicKey = true + if(!this._publicKey.hasPubKey){ + hasPublicKey = false + try { + const res = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/publickey/${this.selectedAddress.address}` + }) + if (res.error === 102) { + this._publicKey.key = '' + this._publicKey.hasPubKey = false + } else if (res !== false) { + this._publicKey.key = res + this._publicKey.hasPubKey = true + hasPublicKey = true + } else { + this._publicKey.key = '' + this._publicKey.hasPubKey = false + } + } catch (error) { + console.error(error); + } + if(!hasPublicKey || !this._publicKey.hasPubKey){ + let err4string = get("chatpage.cchange39"); + parentEpml.request('showSnackBar', `${err4string}`) + return + } + + } + } + console.log(outSideMsg); // have params to determine if it's a reply or not // have variable to determine if it's a response, holds signature in constructor // need original message signature @@ -1647,7 +1999,7 @@ async getName (recipient) { // create new var called repliedToData and use that to modify the UI // find specific object property in local let typeMessage = 'regular'; - + let workerImage; this.isLoading = true; this.chatEditor.disable(); this.chatEditorNewChat.disable() @@ -1680,26 +2032,32 @@ async getName (recipient) { const identifier = outSideMsg.identifier let compressedFile = '' var str = "iVBORw0KGgoAAAANSUhEUgAAAsAAAAGMAQMAAADuk4YmAAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAADlJREFUeF7twDEBAAAAwiD7p7bGDlgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAGJrAABgPqdWQAAAABJRU5ErkJggg=="; + + if (this.webWorkerImage) { + workerImage = this.webWorkerImage; + } else { + this.webWorkerImage = new WebWorkerImage(); + } - const b64toBlob = (b64Data, contentType='', sliceSize=512) => { - const byteCharacters = atob(b64Data); - const byteArrays = []; - - for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { - const slice = byteCharacters.slice(offset, offset + sliceSize); - - const byteNumbers = new Array(slice.length); - for (let i = 0; i < slice.length; i++) { - byteNumbers[i] = slice.charCodeAt(i); - } - - const byteArray = new Uint8Array(byteNumbers); - byteArrays.push(byteArray); + const b64toBlob = (b64Data, contentType='', sliceSize=512) => { + const byteCharacters = atob(b64Data); + const byteArrays = []; + + for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) { + const slice = byteCharacters.slice(offset, offset + sliceSize); + + const byteNumbers = new Array(slice.length); + for (let i = 0; i < slice.length; i++) { + byteNumbers[i] = slice.charCodeAt(i); + } + + const byteArray = new Uint8Array(byteNumbers); + byteArrays.push(byteArray); + } + + const blob = new Blob(byteArrays, {type: contentType}); + return blob; } - - const blob = new Blob(byteArrays, {type: contentType}); - return blob; - } const blob = b64toBlob(str, 'image/png'); await new Promise(resolve => { new Compressor(blob, { @@ -1728,7 +2086,7 @@ async getName (recipient) { metaData: undefined, uploadType: 'file', selectedAddress: this.selectedAddress, - worker: new WebWorkerImage() + worker: workerImage }) this.isDeletingImage = false } catch (error) { @@ -1772,6 +2130,13 @@ async getName (recipient) { this.chatEditorNewChat.enable() return; } + + if (this.webWorkerImage) { + workerImage = this.webWorkerImage; + } else { + this.webWorkerImage = new WebWorkerImage(); + } + const image = this.imageFile const id = this.uid(); const identifier = `qchat_${id}`; @@ -1811,7 +2176,7 @@ async getName (recipient) { metaData: undefined, uploadType: 'file', selectedAddress: this.selectedAddress, - worker: new WebWorkerImage() + worker: workerImage }); this.isUploadingImage = false; this.imageFile = null; @@ -1883,35 +2248,31 @@ async getName (recipient) { users: [this.selectedAddress.address] }] } - const messageObject = { ...message, reactions - } const stringifyMessageObject = JSON.stringify(messageObject) this.sendMessage(stringifyMessageObject, typeMessage, chatReference); - } else if (/^\s*$/.test(trimmedMessage)) { this.isLoading = false; this.chatEditor.enable(); - this.chatEditorNewChat.enable() + this.chatEditorNewChat.enable(); } else if (this.repliedToMessageObj) { - let chatReference = this.repliedToMessageObj.reference - + let chatReference = this.repliedToMessageObj.reference; if(this.repliedToMessageObj.chatReference){ - chatReference = this.repliedToMessageObj.chatReference + chatReference = this.repliedToMessageObj.chatReference; } - typeMessage = 'reply' + typeMessage = 'reply'; const messageObject = { messageText: trimmedMessage, images: [''], repliedTo: chatReference, version: 1 } - const stringifyMessageObject = JSON.stringify(messageObject) - this.sendMessage(stringifyMessageObject, typeMessage ); + const stringifyMessageObject = JSON.stringify(messageObject); + this.sendMessage(stringifyMessageObject, typeMessage); } else if (this.editedMessageObj) { typeMessage = 'edit' let chatReference = this.editedMessageObj.reference @@ -1947,7 +2308,7 @@ async getName (recipient) { } } - async sendMessage(messageText, typeMessage, chatReference, isForward, forwardParams) { + async sendMessage(messageText, typeMessage, chatReference, isForward) { this.isLoading = true; let _reference = new Uint8Array(64); @@ -1967,7 +2328,7 @@ async getName (recipient) { message: messageText, lastReference: reference, proofOfWorkNonce: 0, - isEncrypted: this._publicKey.hasPubKey === false ? 0 : 1, + isEncrypted: 1, isText: 1 } }); @@ -1996,26 +2357,80 @@ async getName (recipient) { }; const sendForwardRequest = async () => { - const { publicKey } = forwardParams + let publicKey = { + hasPubKey: false, + key: '' + }; - const isRecipient = this.forwardActiveChatHeadUrl.includes('direct') === true ? true : false; + if (this.forwardActiveChatHeadUrl.url) { + const activeChatHeadAddress = this.forwardActiveChatHeadUrl.url.split('/')[1] + try { + const res = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/publickey/${activeChatHeadAddress}` + }) + + if (res.error === 102) { + publicKey.key = '' + publicKey.hasPubKey = false + } else if (res !== false) { + publicKey.key = res + publicKey.hasPubKey = true + } else { + publicKey.key = '' + publicKey.hasPubKey = false + } + } catch (error) { + console.error(error); + } + } + + if (!this.forwardActiveChatHeadUrl && this.shadowRoot.getElementById("sendTo").value !== "") { + try { + const res = await parentEpml.request('apiCall', { + type: 'api', + url: `/addresses/publickey/${this.shadowRoot.getElementById("sendTo").value}` + }) + if (res.error === 102) { + publicKey.key = '' + publicKey.hasPubKey = false + } else if (res !== false) { + publicKey.key = res + publicKey.hasPubKey = true + } else { + publicKey.key = '' + publicKey.hasPubKey = false + } + } catch (error) { + console.error(error); + } + } + + const isRecipient = this.forwardActiveChatHeadUrl.url.includes('direct') === true ? true : false; - const chatId = this.forwardActiveChatHeadUrl.split('/')[1]; - this.openForwardOpen = false + const recipientAddress = this.forwardActiveChatHeadUrl.url.split('/')[1]; + this.openForwardOpen = false; + this.chatEditor.enable(); if (isRecipient === true) { + if(!publicKey.hasPubKey){ + let err4string = get("chatpage.cchange39"); + parentEpml.request('showSnackBar', `${err4string}`) + getSendChatResponse(false) + return + } let chatResponse = await parentEpml.request('chat', { type: 18, nonce: this.selectedAddress.nonce, params: { timestamp: Date.now(), - recipient: chatId, + recipient: recipientAddress, recipientPublicKey: publicKey.key, hasChatReference: 0, chatReference: "", message: messageText, lastReference: reference, proofOfWorkNonce: 0, - isEncrypted: publicKey.hasPubKey === false ? 0 : 1, + isEncrypted: 1, isText: 1 } }); @@ -2027,7 +2442,7 @@ async getName (recipient) { nonce: this.selectedAddress.nonce, params: { timestamp: Date.now(), - groupID: Number(chatId), + groupID: Number(recipientAddress), hasReceipient: 0, hasChatReference: 0, chatReference: chatReference, @@ -2045,28 +2460,35 @@ async getName (recipient) { const _computePow = async (chatBytes, isForward) => { const difficulty = this.balance === 0 ? 12 : 8; + const path = window.parent.location.origin + '/memory-pow/memory-pow.wasm.full' - const worker = new WebWorker(); - let nonce = null - let chatBytesArray = null + + let worker; + + if (this.webWorker) { + worker = this.webWorker; + } else { + this.webWorker = new WebWorker(); + } + + let nonce = null; + + let chatBytesArray = null; + await new Promise((res, rej) => { worker.postMessage({chatBytes, path, difficulty}); - worker.onmessage = e => { - worker.terminate() - chatBytesArray = e.data.chatBytesArray - nonce = e.data.nonce - res() - + chatBytesArray = e.data.chatBytesArray; + nonce = e.data.nonce; + res(); } - }) + }); let _response = await parentEpml.request('sign_chat', { nonce: this.selectedAddress.nonce, chatBytesArray: chatBytesArray, chatNonce: nonce }); - getSendChatResponse(_response, isForward); }; @@ -2095,9 +2517,9 @@ async getName (recipient) { this.forwardActiveChatHeadUrl = "" }; - if(isForward){ + if (isForward) { sendForwardRequest(); - return + return; } sendMessageRequest(); } @@ -2115,7 +2537,7 @@ async getName (recipient) { if (entries[0].isIntersecting) { this.setIsUserDown(true) - this.hideNewMesssageBar() + this.hideNewMessageBar() } else { this.setIsUserDown(false) diff --git a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js index 402fe2cf..2366400e 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js +++ b/qortal-ui-plugins/plugins/core/components/ChatRightPanel.js @@ -23,8 +23,8 @@ class ChatRightPanel extends LitElement { groupAdmin: { attribute: false }, groupMembers: { attribute: false }, selectedHead: { type: Object }, - toggle: {attribute: false}, - getMoreMembers:{attribute: false} + toggle: { attribute: false }, + getMoreMembers:{ attribute: false } } } @@ -44,80 +44,135 @@ class ChatRightPanel extends LitElement { this.downObserverElement = '' } - static get styles() { - return css` - .top-bar-icon { - cursor: pointer; - height: 18px; - width: 18px; - transition: 0.2s all; - } - .top-bar-icon:hover { - color: var(--black); - } - .modal-button { - font-family: Roboto, sans-serif; - font-size: 16px; - color: var(--mdc-theme-primary); - background-color: transparent; - padding: 8px 10px; - border-radius: 5px; - border: none; - transition: all 0.3s ease-in-out; - } - .close-row { - width: 100%; - display: flex; - justify-content: flex-end; - height: 50px; - flex:0 +static get styles() { +return css` + .top-bar-icon { + cursor: pointer; + height: 18px; + width: 18px; + transition: 0.2s all; + } - } - .container-body { - width: 100%; - display: flex; - flex-direction: column; - flex-grow: 1; - overflow:auto; - margin-top: 15px; - padding: 0px 5px; - box-sizing: border-box; - } - .container-body::-webkit-scrollbar-track { - background-color: whitesmoke; - border-radius: 7px; - } - - .container-body::-webkit-scrollbar { - width: 6px; - border-radius: 7px; - background-color: whitesmoke; - } - - .container-body::-webkit-scrollbar-thumb { - background-color: rgb(180, 176, 176); - border-radius: 7px; - transition: all 0.3s ease-in-out; - } - - .container-body::-webkit-scrollbar-thumb:hover { - background-color: rgb(148, 146, 146); - cursor: pointer; - } - p { - color: var(--black); - margin: 0px; - padding: 0px; - word-break: break-all; - } - .container { - display: flex; - width: 100%; - flex-direction: column; - height: 100%; - } - ` - } + .top-bar-icon:hover { + color: var(--black); + } + + .modal-button { + font-family: Roboto, sans-serif; + font-size: 16px; + color: var(--mdc-theme-primary); + background-color: transparent; + padding: 8px 10px; + border-radius: 5px; + border: none; + transition: all 0.3s ease-in-out; + } + + .close-row { + width: 100%; + display: flex; + justify-content: flex-end; + height: 50px; + flex:0 + + } + + .container-body { + width: 100%; + display: flex; + flex-direction: column; + flex-grow: 1; + overflow:auto; + margin-top: 5px; + padding: 0px 6px; + box-sizing: border-box; + } + + .container-body::-webkit-scrollbar-track { + background-color: whitesmoke; + border-radius: 7px; + } + + .container-body::-webkit-scrollbar { + width: 6px; + border-radius: 7px; + background-color: whitesmoke; + } + + .container-body::-webkit-scrollbar-thumb { + background-color: rgb(180, 176, 176); + border-radius: 7px; + transition: all 0.3s ease-in-out; + } + + .container-body::-webkit-scrollbar-thumb:hover { + background-color: rgb(148, 146, 146); + cursor: pointer; + } + + p { + color: var(--black); + margin: 0px; + padding: 0px; + word-break: break-all; + } + + .container { + display: flex; + width: 100%; + flex-direction: column; + height: 100%; + } + + .chat-right-panel-label { + font-family: Montserrat, sans-serif; + color: var(--group-header); + padding: 5px; + font-size: 13px; + user-select: none; + } + + .group-info { + display: flex; + flex-direction: column; + justify-content: flex-start; + gap: 10px; + } + + .group-name { + font-family: Raleway, sans-serif; + font-size: 20px; + color: var(--chat-bubble-msg-color); + text-align: center; + user-select: none; + } + + .group-description { + font-family: Roboto, sans-serif; + color: var(--chat-bubble-msg-color); + letter-spacing: 0.3px; + font-weight: 300; + font-size: 14px; + margin-top: 15px; + word-break: break-word; + user-select: none; + } + + .group-subheader { + font-family: Montserrat, sans-serif; + font-size: 14px; + color: var(--chat-bubble-msg-color); + } + + .group-data { + font-family: Roboto, sans-serif; + letter-spacing: 0.3px; + font-weight: 300; + font-size: 14px; + color: var(--chat-bubble-msg-color); + } +` +} firstUpdated() { this.viewElement = this.shadowRoot.getElementById('viewElement'); @@ -167,20 +222,20 @@ class ChatRightPanel extends LitElement { } async unitFee(txType) { - 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=${txType}` - let fee = null + 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=${txType}`; + let fee = null; try { - const res = await fetch(url) - const data = await res.json() - fee = (Number(data) / 1e8).toFixed(3) + const res = await fetch(url); + const data = await res.json(); + fee = (Number(data) / 1e8).toFixed(3); } catch (error) { - fee = null + fee = null; } - return fee + return fee; } async getLastRef() { @@ -188,7 +243,7 @@ class ChatRightPanel extends LitElement { type: "api", url: `/addresses/lastreference/${this.selectedAddress.address}`, }) - return myRef + return myRef; } getTxnRequestResponse(txnResponse, reference) { @@ -381,7 +436,8 @@ class ChatRightPanel extends LitElement { } } render() { - console.log('this.groupMembers', this.groupMembers) + console.log('this.groupMembers', this.groupMembers); + console.log(5, "Chat Right Panel Here"); const owner = this.groupAdmin.filter((admin)=> admin.address === this.leaveGroupObj.owner) return html`
@@ -389,42 +445,44 @@ class ChatRightPanel extends LitElement { this.toggle(false)} style="margin: 0px 10px" icon="vaadin:close" slot="icon">
-

${this.leaveGroupObj && this.leaveGroupObj.groupName}

-

${this.leaveGroupObj && this.leaveGroupObj.description}

-

Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}

- -

Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}

-
-

Group Owner

- ${owner.map((item) => { - return html` {}} - chatInfo=${JSON.stringify(item)} - >` - })} -

Admins

- ${this.groupAdmin.map((item) => { - return html` {}} - chatInfo=${JSON.stringify(item)} - >` - })} -

Members

- ${this.groupMembers.map((item) => { - return html` { - console.log({ val }) - this.selectedHead = val - this.isOpenLeaveModal = true - }} - chatInfo=${JSON.stringify(item)} - >` - })} -
+

${this.leaveGroupObj && this.leaveGroupObj.groupName}

+
+

${this.leaveGroupObj && this.leaveGroupObj.description}

+

Members: ${this.leaveGroupObj && this.leaveGroupObj.memberCount}

+ +

Date created : ${new Date(this.leaveGroupObj.created).toLocaleDateString("en-US")}

+
+

GROUP OWNER

+ ${owner.map((item) => { + return html` {}} + chatInfo=${JSON.stringify(item)} + >` + })} +

ADMINS

+ ${this.groupAdmin.map((item) => { + return html` {}} + chatInfo=${JSON.stringify(item)} + >` + })} +

MEMBERS

+ ${this.groupMembers.map((item) => { + return html` { + console.log({ val }) + this.selectedHead = val + this.isOpenLeaveModal = true + }} + chatInfo=${JSON.stringify(item)} + >` + })} +
+
{ diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js index 4b644c79..1d054bab 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller-css.js @@ -446,4 +446,52 @@ export const chatStyles = css` width: 100%; justify-content: center } + + .delete-image-msg { + font-family: Livvic, sans-serif; + font-size: 20px; + color: var(--chat-bubble-msg-color); + letter-spacing: 0.3px; + font-weight: 300; + text-align: center; + } + + .modal-button-row { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + } + + .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; + } ` diff --git a/qortal-ui-plugins/plugins/core/components/ChatScroller.js b/qortal-ui-plugins/plugins/core/components/ChatScroller.js index ad87b308..23d5d191 100644 --- a/qortal-ui-plugins/plugins/core/components/ChatScroller.js +++ b/qortal-ui-plugins/plugins/core/components/ChatScroller.js @@ -36,7 +36,8 @@ class ChatScroller extends LitElement { isLoadingMessages: { type: Boolean}, setIsLoadingMessages: {attribute: false}, chatId: { type: String }, - setForwardProperties: {attribute: false}, + setForwardProperties: { attribute: false }, + setOpenPrivateMessage: { attribute: false }, } } @@ -48,17 +49,27 @@ class ChatScroller extends LitElement { this._upObserverhandler = this._upObserverhandler.bind(this) this._downObserverHandler = this._downObserverHandler.bind(this) this.myAddress = window.parent.reduxStore.getState().app.selectedAddress.address - this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]") + this.hideMessages = JSON.parse(localStorage.getItem("MessageBlockedAddresses") || "[]") } render() { - console.log({messages: this.messages}) - let formattedMessages = this.messages.reduce((messageArray, message) => { + let formattedMessages = this.messages.reduce((messageArray, message, index) => { const lastGroupedMessage = messageArray[messageArray.length - 1]; let timestamp; let sender; let repliedToData; + + let firstMessageInChat; + + if (index === 0) { + firstMessageInChat = true; + } else { + firstMessageInChat = false; + } + + message = {...message, firstMessageInChat} + if (lastGroupedMessage) { timestamp = lastGroupedMessage.timestamp; sender = lastGroupedMessage.sender; @@ -105,6 +116,7 @@ class ChatScroller extends LitElement { ?isLastMessageInGroup=${indexMessage === formattedMessage.messages.length - 1} .setToggledMessage=${this.setToggledMessage} .setForwardProperties=${this.setForwardProperties} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} > ` ) @@ -132,21 +144,18 @@ class ChatScroller extends LitElement { return true; } - setToggledMessage(message){ - toggledMessage = message + setToggledMessage (message) { + toggledMessage = message; } - async firstUpdated() { this.emojiPicker.on('emoji', selection => { this.sendMessage({ type: 'reaction', - editedMessageObj: toggledMessage, + editedMessageObj: toggledMessage, reaction: selection.emoji, - - - }) + }) }); this.viewElement = this.shadowRoot.getElementById('viewElement'); this.upObserverElement = this.shadowRoot.getElementById('upObserver'); @@ -217,21 +226,24 @@ class MessageTemplate extends LitElement { emojiPicker: { attribute: false }, escapeHTML: { attribute: false }, hideMessages: { type: Array }, - openDialogPrivateMessage: {type: Boolean}, - openDialogBlockUser: {type: Boolean}, + openDialogPrivateMessage: { type: Boolean }, + openDialogBlockUser: { type: Boolean }, showBlockAddressIcon: { type: Boolean }, - setRepliedToMessageObj: {attribute: false}, - setEditedMessageObj: {attribute: false}, - focusChatEditor: {attribute: false}, - sendMessage: {attribute: false}, - sendMessageForward: {attribute: false}, - openDialogImage: {attribute: false}, + setRepliedToMessageObj: { attribute: false }, + setEditedMessageObj: { attribute: false }, + focusChatEditor: { attribute: false }, + sendMessage: { attribute: false }, + sendMessageForward: { attribute: false }, + openDialogImage: { attribute: false }, + openDeleteImage: { type: Boolean }, isImageLoaded: { type: Boolean }, isFirstMessage: { type: Boolean }, isSingleMessageInGroup: { type: Boolean }, isLastMessageInGroup: { type: Boolean }, setToggledMessage: {attribute: false}, setForwardProperties: {attribute: false}, + viewImage: {type: Boolean}, + setOpenPrivateMessage : { attribute: false } } } @@ -248,6 +260,7 @@ class MessageTemplate extends LitElement { this.isFirstMessage = false this.isSingleMessageInGroup = false this.isLastMessageInGroup = false + this.viewImage = false } static styles = [chatStyles] @@ -352,9 +365,13 @@ class MessageTemplate extends LitElement { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]; const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port; imageUrl = `${nodeUrl}/arbitrary/${image.service}/${image.name}/${image.identifier}?async=true&apiKey=${myNode.apiKey}`; - imageHTML = createImage(imageUrl); - imageHTMLDialog = createImage(imageUrl); - imageHTMLDialog.style= "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px"; + + if(this.viewImage || this.myAddress === this.messageObj.sender){ + imageHTML = createImage(imageUrl); + imageHTMLDialog = createImage(imageUrl) + imageHTMLDialog.style= "height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px"; + } + } nameMenu = html` @@ -453,17 +470,28 @@ class MessageTemplate extends LitElement {

`} - ${image && !isImageDeleted ? html` + ${image && !isImageDeleted && !this.viewImage && this.myAddress !== this.messageObj.sender ? html` +
{ + this.viewImage = true + }} + class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : ''].join(' ')} + style=${this.isFirstMessage && "margin-top: 10px;"}> +
+ ${translate("chatpage.cchange40")} +
+ +
+ ` : html``} + ${image && !isImageDeleted && (this.viewImage || this.myAddress === this.messageObj.sender) ? html`
${imageHTML} this.sendMessage({ - type: 'delete', - name: image.name, - identifier: image.identifier, - editedMessageObj: this.messageObj, - })} + @click=${() => { + this.openDeleteImage = true; + this.chatE + }} class="image-delete-icon" icon="vaadin:close" slot="icon">
` : image && isImageDeleted ? html` @@ -508,6 +536,8 @@ class MessageTemplate extends LitElement { .emojiPicker=${this.emojiPicker} .setToggledMessage=${this.setToggledMessage} .setForwardProperties=${this.setForwardProperties} + ?firstMessageInChat=${this.messageObj.firstMessageInChat} + .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)} > @@ -561,6 +591,31 @@ class MessageTemplate extends LitElement { ${translate("general.close")}
+ { + this.openDeleteImage = false; + }}> +
+

Are you sure you want to delete this image?

+
+ +
` } } @@ -582,11 +637,13 @@ class ChatMenu extends LitElement { focusChatEditor: {attribute: false}, myAddress: { type: Object }, emojiPicker: { attribute: false }, - sendMessage: {attribute: false}, - version: {type: String}, - setToggledMessage: {attribute: false}, - sendMessageForward: {attribute: false}, - setForwardProperties: {attribute: false} + sendMessage: { attribute: false }, + version: { type: String }, + setToggledMessage: { attribute: false }, + sendMessageForward: { attribute: false }, + setForwardProperties: { attribute: false }, + firstMessageInChat: { type: Boolean }, + setOpenPrivateMessage: { attribute: false } } } @@ -666,7 +723,7 @@ class ChatMenu extends LitElement { return html`
-