forward msg feature version 1

This commit is contained in:
Phillip Lang Martinez 2022-12-12 19:01:48 -05:00
parent 3a9cb55451
commit 10a464c748
6 changed files with 449 additions and 14 deletions

View File

@ -518,7 +518,11 @@
"bcchange10": "More",
"bcchange11": "Reply",
"bcchange12": "Edit",
"bcchange13": "Reaction"
"bcchange13": "Reaction",
"bcchange14": "Forward",
"bcchange15": "Message Forwarded",
"bcchange16": "Choose recipient",
"bcchange17": "FORWARDED"
},
"grouppage": {
"gchange1": "Qortal Groups",

View File

@ -16,6 +16,7 @@ import './NameMenu.js';
import './TimeAgo.js';
import './ChatTextEditor';
import './WrapperModal';
import './ChatSelect.js'
import '@polymer/paper-spinner/paper-spinner-lite.js';
import '@material/mwc-button';
import '@material/mwc-dialog';
@ -68,7 +69,10 @@ class ChatPage extends LitElement {
lastMessageRefVisible: { type: Boolean },
isLoadingOldMessages: {type: Boolean},
isEditMessageOpen: { type: Boolean },
webSocket: {attribute: false}
webSocket: {attribute: false},
chatHeads: {type: Array},
forwardActiveChatHeadUrl: {type: String},
openForwardOpen: {type: Boolean}
}
}
@ -78,6 +82,15 @@ class ChatPage extends LitElement {
scroll-behavior: smooth;
}
.chat-head-container {
display: flex;
justify-content: flex-start;
flex-direction: column;
height: 50vh;
overflow-y: auto;
width: 100%;
}
.chat-container {
display: grid;
grid-template-rows: minmax(6%, 92vh) minmax(40px, auto);
@ -429,6 +442,11 @@ class ChatPage extends LitElement {
height: 100%;
}
.dialog-container-title {
color: var(--black);
font-size: 18px;
}
.dialog-container-loader {
position: relative;
display: flex;
@ -551,6 +569,7 @@ class ChatPage extends LitElement {
position: 'top-start',
boxShadow: 'rgba(4, 4, 5, 0.15) 0px 0px 0px 1px, rgba(0, 0, 0, 0.24) 0px 8px 16px 0px'
});
this.openForwardOpen = false
}
render() {
@ -705,11 +724,104 @@ class ChatPage extends LitElement {
</div>
</div>
</wrapper-modal>
<wrapper-modal
.removeImage=${() => {
this.openForwardOpen = false
this.forwardActiveChatHeadUrl = ""
} }
style=${this.openForwardOpen ? "display: block" : "display: none"}>
<div>
<div class="dialog-container">
<div>
<p class="dialog-container-title">${translate("blockpage.bcchange16")}</p>
</div>
<div class="chat-head-container">
${this.chatHeads.map((item)=> {
return html`<chat-select activeChatHeadUrl=${this.forwardActiveChatHeadUrl} .setActiveChatHeadUrl=${(val)=> {
this.forwardActiveChatHeadUrl = val
}} chatInfo=${JSON.stringify(item)}></chat-select>`
})}
</div>
<div class="modal-button-row">
<button class="modal-button-red" @click=${() => {
this.openForwardOpen = false
this.forwardActiveChatHeadUrl = ""
}}>
${translate("chatpage.cchange33")}
</button>
<button
?disabled=${!this.forwardActiveChatHeadUrl}
class="modal-button"
@click=${()=> {
this.sendForwardMessage()
}}
>
${translate("blockpage.bcchange14")}
</button>
</div>
</div>
</div>
</wrapper-modal>
</div>
`
}
setForwardProperties(forwardedMessage){
this.openForwardOpen = true
this.forwardedMessage = forwardedMessage
}
async sendForwardMessage(){
let parsedMessageObj = {}
let publicKey = {
hasPubKey: false,
key: ''
}
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) {
}
try {
const message = {
...parsedMessageObj,
type: 'forward'
}
const stringifyMessageObject = JSON.stringify(message)
this.sendMessage(stringifyMessageObject, undefined, '', true, {
isReceipient: true,
chatId: 'Qdxha59Cm1Ty4QkKMBWPnKrNigcDCDk6eq',
publicKey: {
hasPubKey: false,
key: ''
}
})
} catch (error) {
console.log({error})
}
}
showLastMessageRefScroller(props) {
this.lastMessageRefVisible = props;
@ -884,10 +996,12 @@ class ChatPage extends LitElement {
.setEditedMessageObj=${(val) => this.setEditedMessageObj(val)}
.focusChatEditor=${() => this.focusChatEditor()}
.sendMessage=${(val) => this._sendMessage(val)}
.sendMessageForward=${(messageText, typeMessage, chatReference, isForward, forwardParams)=> this.sendMessage(messageText, typeMessage, chatReference, isForward, forwardParams)}
.showLastMessageRefScroller=${(val) => this.showLastMessageRefScroller(val)}
.emojiPicker=${this.emojiPicker}
?isLoadingMessages=${this.isLoadingOldMessages}
.setIsLoadingMessages=${(val) => this.setIsLoadingMessages(val)}
.setForwardProperties=${(forwardedMessage)=> this.setForwardProperties(forwardedMessage)}
>
</chat-scroller>
`
@ -1147,7 +1261,6 @@ class ChatPage extends LitElement {
async fetchChatMessages(chatId) {
const initDirect = async (cid) => {
let initial = 0
let directSocketTimeout
@ -1646,8 +1759,7 @@ class ChatPage extends LitElement {
}
}
async sendMessage(messageText, typeMessage, chatReference) {
async sendMessage(messageText, typeMessage, chatReference, isForward, forwardParams) {
this.isLoading = true;
let _reference = new Uint8Array(64);
@ -1695,7 +1807,55 @@ class ChatPage extends LitElement {
}
};
const _computePow = async (chatBytes) => {
const sendForwardRequest = async () => {
const { publicKey } = forwardParams
const isRecipient = this.forwardActiveChatHeadUrl.includes('direct') === true ? true : false;
const chatId = this.forwardActiveChatHeadUrl.split('/')[1];
this.openForwardOpen = false
if (isRecipient === true) {
let chatResponse = await parentEpml.request('chat', {
type: 18,
nonce: this.selectedAddress.nonce,
params: {
timestamp: Date.now(),
recipient: chatId,
recipientPublicKey: publicKey.key,
hasChatReference: 0,
chatReference: "",
message: messageText,
lastReference: reference,
proofOfWorkNonce: 0,
isEncrypted: publicKey.hasPubKey === false ? 0 : 1,
isText: 1
}
});
_computePow(chatResponse, true)
} else {
let groupResponse = await parentEpml.request('chat', {
type: 181,
nonce: this.selectedAddress.nonce,
params: {
timestamp: Date.now(),
groupID: Number(chatId),
hasReceipient: 0,
hasChatReference: 0,
chatReference: chatReference,
message: messageText,
lastReference: reference,
proofOfWorkNonce: 0,
isEncrypted: 0, // Set default to not encrypted for groups
isText: 1
}
});
_computePow(groupResponse, true)
}
};
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();
@ -1720,13 +1880,17 @@ class ChatPage extends LitElement {
});
getSendChatResponse(_response);
getSendChatResponse(_response, isForward);
};
const getSendChatResponse = (response) => {
const getSendChatResponse = (response, isForward) => {
if (response === true) {
this.chatEditor.resetValue();
this.chatEditorNewChat.resetValue()
if(isForward){
let successString = get("blockpage.bcchange15");
parentEpml.request('showSnackBar', `${successString}`);
}
} else if (response.error) {
parentEpml.request('showSnackBar', response.message);
} else {
@ -1739,9 +1903,14 @@ class ChatPage extends LitElement {
this.chatEditorNewChat.enable()
this.closeEditMessageContainer()
this.closeRepliedToContainer()
this.openForwardOpen = false
this.forwardActiveChatHeadUrl = ""
};
// Exec..
if(isForward){
sendForwardRequest();
return
}
sendMessageRequest();
}

View File

@ -63,6 +63,12 @@ export const chatStyles = css`
margin-bottom: 5px;
}
.message-data-forward {
user-select: none;
color: var(--mainmenutext);
margin-bottom: 5px;
font-size: 12px;
}
.message-data-my-name {
color: #cf21e8;
text-shadow: 0 0 3px #cf21e8;

View File

@ -30,11 +30,13 @@ class ChatScroller extends LitElement {
setEditedMessageObj: {attribute: false},
focusChatEditor: {attribute: false},
sendMessage: {attribute: false},
sendMessageForward: {attribute: false},
showLastMessageRefScroller: { type: Function },
emojiPicker: { attribute: false },
isLoadingMessages: { type: Boolean},
setIsLoadingMessages: {attribute: false},
chatId: { type: String }
chatId: { type: String },
setForwardProperties: {attribute: false},
}
}
@ -51,6 +53,7 @@ class ChatScroller extends LitElement {
render() {
console.log({messages: this.messages})
let formattedMessages = this.messages.reduce((messageArray, message) => {
const lastGroupedMessage = messageArray[messageArray.length - 1];
let timestamp;
@ -96,10 +99,12 @@ class ChatScroller extends LitElement {
.setEditedMessageObj=${this.setEditedMessageObj}
.focusChatEditor=${this.focusChatEditor}
.sendMessage=${this.sendMessage}
.sendMessageForward=${this.sendMessageForward}
?isFirstMessage=${indexMessage === 0}
?isSingleMessageInGroup=${formattedMessage.messages.length > 1}
?isLastMessageInGroup=${indexMessage === formattedMessage.messages.length - 1}
.setToggledMessage=${this.setToggledMessage}
.setForwardProperties=${this.setForwardProperties}
>
</message-template>`
)
@ -219,12 +224,14 @@ class MessageTemplate extends LitElement {
setEditedMessageObj: {attribute: false},
focusChatEditor: {attribute: false},
sendMessage: {attribute: false},
sendMessageForward: {attribute: false},
openDialogImage: {attribute: false},
isImageLoaded: { type: Boolean },
isFirstMessage: { type: Boolean },
isSingleMessageInGroup: { type: Boolean },
isLastMessageInGroup: { type: Boolean },
setToggledMessage: {attribute: false}
setToggledMessage: {attribute: false},
setForwardProperties: {attribute: false},
}
}
@ -279,6 +286,7 @@ class MessageTemplate extends LitElement {
let image = null;
let isImageDeleted = false;
let version = 0;
let isForwarded = false
try {
const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage);
message = parsedMessageObj.messageText;
@ -286,6 +294,7 @@ class MessageTemplate extends LitElement {
isImageDeleted = parsedMessageObj.isImageDeleted;
reactions = parsedMessageObj.reactions || [];
version = parsedMessageObj.version
isForwarded = parsedMessageObj.type === 'forward'
if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) {
image = parsedMessageObj.images[0];
}
@ -299,6 +308,7 @@ class MessageTemplate extends LitElement {
let nameMenu = '';
let levelFounder = '';
let hideit = hidemsg.includes(this.messageObj.sender);
let forwarded = ''
levelFounder = html`<level-founder checkleveladdress="${this.messageObj.sender}"></level-founder>`;
if (this.messageObj.senderName) {
@ -352,6 +362,11 @@ class MessageTemplate extends LitElement {
${this.messageObj.senderName ? this.messageObj.senderName : cropAddress(this.messageObj.sender)}
</span>
`;
forwarded = html`
<span class="${this.messageObj.sender === this.myAddress && 'message-data-forward'}">
${translate("blockpage.bcchange17")}
</span>
`;
if (repliedToData) {
try {
@ -414,6 +429,14 @@ class MessageTemplate extends LitElement {
`
: null
}
${isForwarded ?
html`
<span class="message-data-name">
${forwarded}
</span>
`
: null
}
${this.isFirstMessage ? (
html`
<span class="message-data-level">${levelFounder}</span>
@ -480,9 +503,11 @@ class MessageTemplate extends LitElement {
.myAddress=${this.myAddress}
@blur=${() => this.showBlockIconFunc(false)}
.sendMessage=${this.sendMessage}
.sendMessageForward=${this.sendMessageForward}
version=${version}
.emojiPicker=${this.emojiPicker}
.setToggledMessage=${this.setToggledMessage}
.setForwardProperties=${this.setForwardProperties}
>
</chat-menu>
</div>
@ -559,7 +584,9 @@ class ChatMenu extends LitElement {
emojiPicker: { attribute: false },
sendMessage: {attribute: false},
version: {type: String},
setToggledMessage: {attribute: false}
setToggledMessage: {attribute: false},
sendMessageForward: {attribute: false},
setForwardProperties: {attribute: false}
}
}
@ -589,6 +616,51 @@ class ChatMenu extends LitElement {
parentEpml.request('showSnackBar', `${errorMsg}`)
}
async messageForwardFunc(){
let parsedMessageObj = {}
let publicKey = {
hasPubKey: false,
key: ''
}
try {
parsedMessageObj = JSON.parse(this.originalMessage.decodedMessage);
} catch (error) {
parsedMessageObj = {}
}
try {
const res = await parentEpml.request('apiCall', {
type: 'api',
url: `/addresses/publickey/${this._chatId}`
})
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) {
}
try {
const message = {
...parsedMessageObj,
type: 'forward'
}
const stringifyMessageObject = JSON.stringify(message)
this.setForwardProperties(stringifyMessageObject)
} catch (error) {
console.log({error})
}
}
render() {
return html`
<div class="container">
@ -610,6 +682,14 @@ class ChatMenu extends LitElement {
}}
>
<vaadin-icon icon="vaadin:smiley-o" slot="icon"></vaadin-icon>
</div>
<div
class="menu-icon tooltip"
data-text="${translate("blockpage.bcchange14")}"
@click="${() => {
this.messageForwardFunc()
}}">
<vaadin-icon icon="vaadin:arrow-forward" slot="icon"></vaadin-icon>
</div>
<div class="menu-icon tooltip" data-text="${translate("blockpage.bcchange9")}" @click="${() => this.showPrivateMessageModal()}">
<vaadin-icon icon="vaadin:paperplane" slot="icon"></vaadin-icon>

View File

@ -0,0 +1,176 @@
import { LitElement, html, css } from 'lit'
import { Epml } from '../../../epml.js'
import '@material/mwc-icon'
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent })
class ChatSelect extends LitElement {
static get properties() {
return {
selectedAddress: { type: Object },
config: { type: Object },
chatInfo: { type: Object },
iconName: { type: String },
activeChatHeadUrl: { type: String },
isImageLoaded: { type: Boolean },
setActiveChatHeadUrl: {attribute: false}
}
}
static get styles() {
return css`
ul {
list-style-type: none;
}
li {
padding: 10px 2px 20px 5px;
cursor: pointer;
width: 100%;
display: flex;
box-sizing: border-box;
}
li:hover {
background-color: var(--menuhover);
}
.active {
background: var(--menuactive);
border-left: 4px solid #3498db;
}
.img-icon {
font-size:40px;
color: var(--chat-group);
}
.about {
margin-top: 8px;
}
.about {
padding-left: 8px;
}
.status {
color: #92959e;
}
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
`
}
constructor() {
super()
this.selectedAddress = {}
this.config = {
user: {
node: {
}
}
}
this.chatInfo = {}
this.iconName = ''
this.activeChatHeadUrl = ''
this.isImageLoaded = false
this.imageFetches = 0
}
createImage(imageUrl) {
const imageHTMLRes = new Image();
imageHTMLRes.src = imageUrl;
imageHTMLRes.style= "width:40px; height:40px; float: left; border-radius:50%";
imageHTMLRes.onclick= () => {
this.openDialogImage = true;
}
imageHTMLRes.onload = () => {
this.isImageLoaded = true;
}
imageHTMLRes.onerror = () => {
if (this.imageFetches < 4) {
setTimeout(() => {
this.imageFetches = this.imageFetches + 1;
imageHTMLRes.src = imageUrl;
}, 500);
} else {
this.isImageLoaded = false
}
};
return imageHTMLRes;
}
render() {
let avatarImg = '';
let backupAvatarImg = ''
if(this.chatInfo.name){
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node];
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port;
const avatarUrl = `${nodeUrl}/arbitrary/THUMBNAIL/${this.chatInfo.name}/qortal_avatar?async=true&apiKey=${myNode.apiKey}`;
avatarImg= this.createImage(avatarUrl)
}
return html`
<li @click=${() => this.getUrl(this.chatInfo.url)} class="clearfix ${this.activeChatHeadUrl === this.chatInfo.url ? 'active' : ''}">
${this.isImageLoaded ? html`${avatarImg}` : html`` }
${!this.isImageLoaded && !this.chatInfo.name && !this.chatInfo.groupName ? html`<mwc-icon class="img-icon">account_circle</mwc-icon>` : html`` }
${!this.isImageLoaded && this.chatInfo.name ? html`<div style="width:40px; height:40px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.name.charAt(0)}</div>`: ''}
${!this.isImageLoaded && this.chatInfo.groupName ? html`<div style="width:40px; height:40px; float: left; border-radius:50%; background: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadBgActive)' : 'var(--chatHeadBg)' }; color: ${this.activeChatHeadUrl === this.chatInfo.url ? 'var(--chatHeadTextActive)' : 'var(--chatHeadText)' }; font-weight:bold; display: flex; justify-content: center; align-items: center; text-transform: capitalize">${this.chatInfo.groupName.charAt(0)}</div>`: ''}
<div class="about">
<div class="name"><span style="float:left; padding-left: 8px; color: var(--chat-group);">${this.chatInfo.groupName ? this.chatInfo.groupName : this.chatInfo.name !== undefined ? this.chatInfo.name : this.chatInfo.address.substr(0, 15)} </span> </div>
</div>
</li>
`
}
firstUpdated() {
let configLoaded = false
parentEpml.ready().then(() => {
parentEpml.subscribe('selected_address', async selectedAddress => {
this.selectedAddress = {}
selectedAddress = JSON.parse(selectedAddress)
if (!selectedAddress || Object.entries(selectedAddress).length === 0) return
this.selectedAddress = selectedAddress
})
parentEpml.subscribe('config', c => {
if (!configLoaded) {
configLoaded = true
}
this.config = JSON.parse(c)
})
})
parentEpml.imReady()
}
shouldUpdate(changedProperties) {
if(changedProperties.has('activeChatHeadUrl')){
return true
}
if(changedProperties.has('chatInfo')){
return true
}
return false
}
getUrl(chatUrl) {
this.setActiveChatHeadUrl(chatUrl)
}
onPageNavigation(pageUrl) {
parentEpml.request('setPageUrl', pageUrl)
}
}
window.customElements.define('chat-select', ChatSelect)

View File

@ -702,7 +702,7 @@ class Chat extends LitElement {
// Else render Welcome to Q-CHat
// TODO: DONE: Do the above in the ChatPage
return html`<chat-page .hideNewMesssageBar=${this.hideNewMesssageBar} .showNewMesssageBar=${this.showNewMesssageBar} myAddress=${window.parent.reduxStore.getState().app.selectedAddress.address} chatId=${this.activeChatHeadUrl}></chat-page>`
return html`<chat-page .chatHeads=${this.chatHeads} .hideNewMesssageBar=${this.hideNewMesssageBar} .showNewMesssageBar=${this.showNewMesssageBar} myAddress=${window.parent.reduxStore.getState().app.selectedAddress.address} chatId=${this.activeChatHeadUrl}></chat-page>`
}
setChatHeads(chatObj) {