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/material-icons.css b/qortal-ui-core/font/material-icons.css
index 02a4ec31..0363d4ee 100644
--- a/qortal-ui-core/font/material-icons.css
+++ b/qortal-ui-core/font/material-icons.css
@@ -25,6 +25,20 @@
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;
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/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/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 6412129d..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,529 +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;
- }
-
- .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;
- }
- `
+ 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)
@@ -642,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) {
@@ -651,7 +843,6 @@ class ChatPage extends LitElement {
}
render() {
- console.log('this._chatId', this._chatId)
return html`
@@ -745,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}>
@@ -771,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"}>
@@ -800,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"}>
@@ -832,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)}>
+ `
+ })}
+ `
+ )}
+
@@ -858,7 +1120,28 @@ class ChatPage extends LitElement {
-
+
+ {
+ 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}>
+
+
+
@@ -899,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 {
@@ -942,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});
}
}
@@ -972,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"));
@@ -1143,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();
+ }
+ }
}
@@ -1211,6 +1508,7 @@ async getName (recipient) {
?isLoadingMessages=${this.isLoadingOldMessages}
.setIsLoadingMessages=${(val) => this.setIsLoadingMessages(val)}
.setForwardProperties=${(forwardedMessage)=> this.setForwardProperties(forwardedMessage)}
+ .setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
>
`
@@ -1422,7 +1720,7 @@ async getName (recipient) {
this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete();
- this.showNewMesssageBar();
+ this.showNewMessageBar();
}
}
@@ -1661,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
@@ -1669,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()
@@ -1702,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, {
@@ -1750,7 +2086,7 @@ async getName (recipient) {
metaData: undefined,
uploadType: 'file',
selectedAddress: this.selectedAddress,
- worker: new WebWorkerImage()
+ worker: workerImage
})
this.isDeletingImage = false
} catch (error) {
@@ -1794,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}`;
@@ -1833,7 +2176,7 @@ async getName (recipient) {
metaData: undefined,
uploadType: 'file',
selectedAddress: this.selectedAddress,
- worker: new WebWorkerImage()
+ worker: workerImage
});
this.isUploadingImage = false;
this.imageFile = null;
@@ -1905,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
@@ -1969,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);
@@ -1989,7 +2328,7 @@ async getName (recipient) {
message: messageText,
lastReference: reference,
proofOfWorkNonce: 0,
- isEncrypted: this._publicKey.hasPubKey === false ? 0 : 1,
+ isEncrypted: 1,
isText: 1
}
});
@@ -2018,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
}
});
@@ -2049,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,
@@ -2067,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);
};
@@ -2117,9 +2517,9 @@ async getName (recipient) {
this.forwardActiveChatHeadUrl = ""
};
- if(isForward){
+ if (isForward) {
sendForwardRequest();
- return
+ return;
}
sendMessageRequest();
}
@@ -2137,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/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?
+
+ this.openDeleteImage = false}>
+
+
+
+
`
}
}
@@ -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`
-