diff --git a/img/file-icon.png b/img/file-icon.png
new file mode 100644
index 00000000..0e12769d
Binary files /dev/null and b/img/file-icon.png differ
diff --git a/plugins/plugins/core/components/ChatPage.js b/plugins/plugins/core/components/ChatPage.js
index 030126b3..b6047770 100644
--- a/plugins/plugins/core/components/ChatPage.js
+++ b/plugins/plugins/core/components/ChatPage.js
@@ -8,6 +8,7 @@ import { escape } from 'html-escaper'
import { inputKeyCodes, replaceMessagesEdited, generateIdFromAddresses } from '../../utils/functions'
import { publishData, modalHelper, RequestQueue } from '../../utils/classes'
import { EmojiPicker } from 'emoji-picker-js'
+import { Slice, Fragment, Node } from 'prosemirror-model'
import { chatpageStyles } from './plugins-css'
import localForage from 'localforage'
import StarterKit from '@tiptap/starter-kit'
@@ -84,11 +85,17 @@ class ChatPage extends LitElement {
editedMessageObj: { type: Object },
iframeHeight: { type: Number },
imageFile: { type: Object },
+ gifFile: { type: Object },
attachment: { type: Object },
+ appFile: { type: Object },
isUploadingImage: { type: Boolean },
- isDeletingImage: { type: Boolean },
+ isUploadingGif: { type: Boolean },
isUploadingAttachment: { type: Boolean },
+ isUploadingAppFile: { type: Boolean },
+ isDeletingImage: { type: Boolean },
+ isDeletingGif: { type: Boolean },
isDeletingAttachment: { type: Boolean },
+ isDeletingAppFile: { type: Boolean },
userLanguage: { type: String },
lastMessageRefVisible: { type: Boolean },
isLoadingOldMessages: { type: Boolean },
@@ -172,7 +179,9 @@ class ChatPage extends LitElement {
this.editedMessageObj = null
this.iframeHeight = 42
this.imageFile = null
+ this.gifFile = null
this.attachment = null
+ this.appFile = null
this.uid = new ShortUniqueId()
this.userLanguage = ""
this.lastMessageRefVisible = false
@@ -391,6 +400,19 @@ class ChatPage extends LitElement {
`
: ''
}
+ ${(this.isUploadingGif || this.isDeletingGif) ?
+ html`
+
+
+
+
+
${this.isDeletingImage ? translate("chatpage.cchange104") : translate("chatpage.cchange103")}
+
+
+
+ `
+ : ''
+ }
${(this.isUploadingAttachment || this.isDeletingAttachment) ?
html`
@@ -404,9 +426,23 @@ class ChatPage extends LitElement {
`
: ''
}
+ ${(this.isUploadingAppFile || this.isDeletingAppFile) ?
+ html`
+
+
+
+
+
${this.isDeletingAppFile ? translate("chatpage.cchange99") : translate("chatpage.cchange98")}
+
+
+
+ `
+ : ''
+ }
{this.removeImage();}} style=${(this.imageFile && !this.isUploadingImage) ? "visibility:visible; z-index:50" : "visibility: hidden;z-index:-100"}>
+
${translate("chatpage.cchange110")}
${this.imageFile &&
html`
+
{this.removeGif();}} style=${(this.gifFile && !this.isUploadingGif) ? "visibility:visible; z-index:50" : "visibility: hidden;z-index:-100"}>
+
+
+
${translate("chatpage.cchange111")}
+ ${this.gifFile &&
+ html`
+
![dialog-gif](${this.gifFile.identifier)
+ `
+ }
+
+ this.updatePlaceholder(editor, value)}
+ >
+
+
+
+
+
+
+
+
+
{this.removeAttachment();}} style=${this.attachment && !this.isUploadingAttachment ? "visibility: visible; z-index: 50" : "visibility: hidden; z-index: -100"}>
+
${translate("chatpage.cchange112")}
${this.attachment &&
html`
@@ -499,6 +588,50 @@ class ChatPage extends LitElement {
+
{this.removeAppFile();}} style=${this.appFile && !this.isUploadingAppFile ? "visibility: visible; z-index: 50" : "visibility: hidden; z-index: -100"}>
+
+
+
${translate("chatpage.cchange113")}
+ ${this.appFile &&
+ html`
+
+ `
+ }
+
${this.appFile && this.appFile.name}
+
+ this.updatePlaceholder(editor, value)}
+ >
+
+
+
+
+
+
+
+
+
${translate("chatpage.cchange41")}
@@ -834,36 +967,70 @@ class ChatPage extends LitElement {
async connectedCallback() {
super.connectedCallback()
await this.initUpdate()
+
if (!this.webWorker) {
this.webWorker = new WebWorker()
}
+
if (!this.webWorkerFile) {
this.webWorkerFile = new WebWorkerFile()
}
+
if (!this.webWorkerSortMessages) {
this.webWorkerSortMessages = new WebWorkerSortMessages()
-
}
+
if (!this.webWorkerDecodeMessages) {
this.webWorkerDecodeMessages = new WebWorkerDecodeMessages()
}
+
await this.getUpdateCompleteTextEditor()
const elementChatId = this.shadowRoot.getElementById('_chatEditorDOM').shadowRoot.getElementById('_chatEditorDOM')
const elementChatImageId = this.shadowRoot.getElementById('chatTextCaption').shadowRoot.getElementById('newChat')
+ const elementChatGifId = this.shadowRoot.getElementById('chatGifId').shadowRoot.getElementById('newGifChat')
const elementChatAttachmentId = this.shadowRoot.getElementById('chatAttachmentId').shadowRoot.getElementById('newAttachmentChat')
+ const elementChatFileId = this.shadowRoot.getElementById('chatFileId').shadowRoot.getElementById('newFileChat')
+
+ const placeholderString = get('chatpage.cchange114')
+
+ const clipboardTextParser = (text, context, plain) => {
+ const splitLines = text.replace().split(/(?:\r\n?|\n)/)
+ const nodesLines = []
+
+ splitLines.forEach(line => {
+ let nodeJson = {type: "paragraph"}
+
+ if (line.length === 0) {
+ nodeJson.content = [{type: "hardBreak"}]
+ } else if (line.length > 0) {
+ nodeJson.content = [{type: "text", text: line}]
+ }
+
+ let modifiedLine = Node.fromJSON(context.doc.type.schema, nodeJson)
+
+ nodesLines.push(modifiedLine)
+ })
+
+ const fragment = Fragment.fromArray(nodesLines)
+
+ return Slice.maxOpen(fragment)
+ }
+
this.editor = new Editor({
+ editorProps: {
+ clipboardTextParser: clipboardTextParser
+ },
onUpdate: () => {
this.shadowRoot.getElementById('_chatEditorDOM').getMessageSize(this.editor.getJSON())
},
-
element: elementChatId,
extensions: [
StarterKit,
Underline,
Highlight,
Placeholder.configure({
- placeholder: 'Write something …',
+ placeholder: `${placeholderString}`
}),
Extension.create({
name: 'shortcuts',
@@ -901,7 +1068,7 @@ class ChatPage extends LitElement {
Underline,
Highlight,
Placeholder.configure({
- placeholder: 'Write something …',
+ placeholder: `${placeholderString}`
}),
Extension.create({
addKeyboardShortcuts: () => {
@@ -919,6 +1086,34 @@ class ChatPage extends LitElement {
]
})
+ this.editorGif = new Editor({
+ onUpdate: () => {
+ this.shadowRoot.getElementById('chatGifId').getMessageSize(this.editorGif.getJSON())
+ },
+ element: elementChatGifId,
+ extensions: [
+ StarterKit,
+ Underline,
+ Highlight,
+ Placeholder.configure({
+ placeholder: `${placeholderString}`
+ }),
+ Extension.create({
+ addKeyboardShortcuts: () => {
+ return {
+ 'Enter': () => {
+ const chatTextEditor = this.shadowRoot.getElementById('chatGifId')
+ chatTextEditor.sendMessageFunc({
+ type: 'gif'
+ })
+ return true
+ }
+ }
+ }
+ })
+ ]
+ })
+
this.editorAttachment = new Editor({
onUpdate: () => {
this.shadowRoot.getElementById('chatAttachmentId').getMessageSize(this.editorAttachment.getJSON())
@@ -929,7 +1124,7 @@ class ChatPage extends LitElement {
Underline,
Highlight,
Placeholder.configure({
- placeholder: 'Write something …',
+ placeholder: `${placeholderString}`
}),
Extension.create({
addKeyboardShortcuts: () => {
@@ -947,6 +1142,34 @@ class ChatPage extends LitElement {
]
})
+ this.editorFile = new Editor({
+ onUpdate: () => {
+ this.shadowRoot.getElementById('chatFileId').getMessageSize(this.editorFile.getJSON())
+ },
+ element: elementChatFileId,
+ extensions: [
+ StarterKit,
+ Underline,
+ Highlight,
+ Placeholder.configure({
+ placeholder: `${placeholderString}`
+ }),
+ Extension.create({
+ addKeyboardShortcuts: () => {
+ return {
+ 'Enter': () => {
+ const chatTextEditor = this.shadowRoot.getElementById('chatFileId')
+ chatTextEditor.sendMessageFunc({
+ type: 'file'
+ })
+ return true
+ }
+ }
+ }
+ })
+ ]
+ })
+
document.addEventListener('keydown', this.initialChat)
document.addEventListener('paste', this.pasteImage)
@@ -983,25 +1206,44 @@ class ChatPage extends LitElement {
disconnectedCallback() {
super.disconnectedCallback()
+
if (this.webSocket) {
this.webSocket.close(1000, 'switch chat')
this.webSocket = ''
}
+
if (this.webWorker) {
this.webWorker.terminate()
}
+
if (this.webWorkerFile) {
this.webWorkerFile.terminate()
}
+
if (this.webWorkerSortMessages) {
this.webWorkerSortMessages.terminate()
}
+
if (this.editor) {
this.editor.destroy()
}
+
if (this.editorImage) {
this.editorImage.destroy()
}
+
+ if (this.editorGif) {
+ this.editorGif.destroy()
+ }
+
+ if (this.editorAttachment) {
+ this.editorAttachment.destroy()
+ }
+
+ if (this.editorFile) {
+ this.editorFile.destroy()
+ }
+
if (this.observer) {
this.observer.disconnect()
}
@@ -1023,7 +1265,6 @@ class ChatPage extends LitElement {
}
async pasteImage(e) {
- const event = e
const handleTransferIntoURL = (dataTransfer) => {
try {
const [firstItem] = dataTransfer.items
@@ -1031,15 +1272,19 @@ class ChatPage extends LitElement {
return blob
} catch (error) { /* empty */ }
}
- if (event.clipboardData) {
- const blobFound = handleTransferIntoURL(event.clipboardData)
+
+ if (e.clipboardData) {
+ const blobFound = handleTransferIntoURL(e.clipboardData)
+
if (blobFound) {
this.insertFile(blobFound)
e.preventDefault()
return
} else {
const item_list = await navigator.clipboard.read()
+
let image_type
+
const item = item_list.find(item =>
item.types.some(type => {
if (type.startsWith('image/')) {
@@ -1048,10 +1293,11 @@ class ChatPage extends LitElement {
}
})
)
+
if (item) {
try {
const blob = item && await item.getType(image_type)
- let file = new File([blob], "name", {
+ let file = new File([blob], 'name', {
type: image_type
})
this.insertFile(file)
@@ -1196,17 +1442,47 @@ class ChatPage extends LitElement {
}
insertFile(file) {
+ const acceptedFileExtension = [
+ 'zip', 'jar', 'gzip', 'exe', 'deb',
+ 'rar', 'dmg', 'pkg', '7z', 'gz', 'psd',
+ 'mp4', 'rpm', 'snap', 'AppImage'
+ ]
+
+ const acceptedAttachmentExtension = [
+ 'pdf', 'txt', 'odt', 'ods', 'doc', 'html',
+ 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'sh', 'log'
+ ]
+
+ const fileExtension = file.name.split('.').pop()
+
if (file.identifier) {
this.imageFile = file
this.currentEditor = 'newChat'
+ this.editorImage.commands.setContent('')
+ return
+ } else if (file.type === 'image/gif') {
+ this.gifFile = file
+ this.currentEditor = 'newGifChat'
+ this.editorGif.commands.setContent('')
return
} else if (file.type.includes('image')) {
this.imageFile = file
this.currentEditor = 'newChat'
+ this.editorImage.commands.setContent('')
return
- } else {
+ } else if (acceptedFileExtension.includes(fileExtension)) {
+ this.appFile = file
+ this.currentEditor = 'newFileChat'
+ this.editorFile.commands.setContent('')
+ return
+ } else if (acceptedAttachmentExtension.includes(fileExtension)){
this.attachment = file
this.currentEditor = "newAttachmentChat"
+ this.editorAttachment.commands.setContent('')
+ return
+ } else {
+ this.resetChatEditor()
+ parentEpml.request('showSnackBar', get("chatpage.cchange109"))
return
}
}
@@ -1217,12 +1493,24 @@ class ChatPage extends LitElement {
this.currentEditor = '_chatEditorDOM'
}
+ removeGif() {
+ this.gifFile = null
+ this.resetChatEditor()
+ this.currentEditor = '_chatEditorDOM'
+ }
+
removeAttachment() {
this.attachment = null
this.resetChatEditor()
this.currentEditor = '_chatEditorDOM'
}
+ removeAppFile() {
+ this.appFile = null
+ this.resetChatEditor()
+ this.currentEditor = '_chatEditorDOM'
+ }
+
changeMsgInput(id) {
this.chatMessageInput = this.shadowRoot.getElementById(id)
this.initChatEditor()
@@ -1233,7 +1521,9 @@ class ChatPage extends LitElement {
this.webSocket.close(1000, 'switch chat')
this.webSocket = ''
}
+
this.pageNumber = 1
+
const getAddressPublicKey = () => {
parentEpml.request('apiCall', {
type: 'api',
@@ -1260,18 +1550,16 @@ class ChatPage extends LitElement {
this.chatId.includes('direct') === true ? this.isReceipient = true : this.isReceipient = false
this._chatId = this.chatId.split('/')[1]
- const mstring = get("chatpage.cchange8")
+ const mstring = get('chatpage.cchange114')
const placeholder = isRecipient === true ? `Message ${this._chatId}` : `${mstring}`
this.chatEditorPlaceholder = placeholder
isRecipient ? getAddressPublicKey() : this.fetchChatMessages(this._chatId)
-
- // Init ChatEditor
- // this.initChatEditor()
}, 100)
const isRecipient = this.chatId.includes('direct') === true ? true : false
const groupId = this.chatId.split('/')[1]
+
if (!isRecipient && groupId.toString() !== '0') {
try {
const getMembers = await parentEpml.request("apiCall", {
@@ -1314,7 +1602,9 @@ class ChatPage extends LitElement {
} catch (error) { /* empty */ }
return memberItem
})
+
const membersWithName = await Promise.all(getMembersWithName)
+
this.groupAdmin = membersAdminsWithName
this.groupMembers = membersWithName
this.groupInfo = getGroupInfo
@@ -1337,7 +1627,7 @@ class ChatPage extends LitElement {
const userLang = changedProperties.get('userLanguage')
if (userLang) {
await new Promise(r => setTimeout(r, 100))
- this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get("chatpage.cchange8")}`
+ this.chatEditorPlaceholder = this.isReceipient === true ? `Message ${this._chatId}` : `${get('chatpage.cchange114')}`
}
}
@@ -1345,10 +1635,12 @@ class ChatPage extends LitElement {
if (this.isLoading === true && this.currentEditor === '_chatEditorDOM' && this.editor && this.editor.setEditable) {
this.editor.setEditable(false)
}
+
if (this.isLoading === false && this.currentEditor === '_chatEditorDOM' && this.editor && this.editor.setEditable) {
this.editor.setEditable(true)
}
}
+
if (changedProperties && changedProperties.has('chatId') && this.webSocket) {
const previousChatId = changedProperties.get('chatId')
@@ -1427,12 +1719,16 @@ class ChatPage extends LitElement {
return ""
}
}
- let userName = ""
+
+ let userName = ''
+
if (this.isReceipient) {
userName = await getName(this._chatId)
}
- const mstring = get("chatpage.cchange8")
+
+ const mstring = get('chatpage.cchange114')
const placeholder = this.isReceipient === true ? `Message ${userName ? userName : this._chatId}` : `${mstring}`
+
return placeholder
}
@@ -1865,13 +2161,14 @@ class ChatPage extends LitElement {
const signature = item.originalSignature || item.signature
newObj[signature] = item
})
+
this.updateMessageHash = {
...this.updateMessageHash,
...newObj
}
+
this.requestUpdate()
await this.getUpdateComplete()
-
}
async clearUpdateMessageHashmap() {
@@ -1895,31 +2192,35 @@ class ChatPage extends LitElement {
}
}
}
+
return null
}
async processMessages(messages, isInitial, isUnread, count) {
const isReceipient = this.chatId.includes('direct')
let decodedMessages = []
+
if (!this.webWorkerDecodeMessages) {
this.webWorkerDecodeMessages = new WebWorkerDecodeMessages()
}
+
if (!this.webWorkerSortMessages) {
this.webWorkerSortMessages = new WebWorkerSortMessages()
}
+
await new Promise((res, rej) => {
this.webWorkerDecodeMessages.postMessage({ messages: messages, isReceipient: this.isReceipient, _publicKey: this._publicKey, privateKey: window.parent.reduxStore.getState().app.selectedAddress.keyPair.privateKey })
this.webWorkerDecodeMessages.onmessage = e => {
decodedMessages = e.data
res()
-
}
+
this.webWorkerDecodeMessages.onerror = () => {
rej()
-
}
})
+
if (isInitial) {
this.chatEditorPlaceholder = await this.renderPlaceholder()
@@ -1953,7 +2254,6 @@ class ChatPage extends LitElement {
const lastReadMessageTimestamp = this.lastReadMessageTimestamp
if (isUnread) {
-
this.messagesRendered = {
messages: this._messages,
type: 'initialLastSeen',
@@ -2045,6 +2345,7 @@ class ChatPage extends LitElement {
}
let viewElement = this.shadowRoot.querySelector('chat-scroller')
+
if (viewElement) {
viewElement = viewElement.shadowRoot.getElementById('viewElement')
} else {
@@ -2052,34 +2353,34 @@ class ChatPage extends LitElement {
}
if (newMessage.sender === this.selectedAddress.address) {
-
-
this.messagesRendered = {
messages: [newMessage],
type: 'newComingInAuto',
}
+
await this.getUpdateComplete()
// viewElement.scrollTop = viewElement.scrollHeight
} else if (this.isUserDown) {
-
this.messagesRendered = {
messages: [newMessage],
type: 'newComingInAuto',
}
+
// Append the message and scroll to the bottom if user is down the page
// this.messagesRendered = [...this.messagesRendered, newMessage]
await this.getUpdateComplete()
+
if (viewElement) {
viewElement.scrollTop = viewElement.scrollHeight
}
} else {
-
this.messagesRendered = {
messages: [newMessage],
type: 'newComingInAuto',
}
+
await this.getUpdateComplete()
this.showNewMessageBar()
@@ -2094,6 +2395,7 @@ class ChatPage extends LitElement {
decodeMessage(encodedMessageObj, isReceipient, _publicKey) {
let isReceipientVar
let _publicKeyVar
+
try {
isReceipientVar = this.isReceipient === undefined ? isReceipient : this.isReceipient
_publicKeyVar = this._publicKey === undefined ? _publicKey : this._publicKey
@@ -2115,12 +2417,12 @@ class ChatPage extends LitElement {
} else {
decodedMessageObj = { ...encodedMessageObj, decodedMessage: "Cannot Decrypt Message!" }
}
-
} else {
// group chat
let decodedMessage = window.parent.Base64.decode(encodedMessageObj.data)
decodedMessageObj = { ...encodedMessageObj, decodedMessage }
}
+
return decodedMessageObj
}
@@ -2144,6 +2446,7 @@ class ChatPage extends LitElement {
}
this.webSocket = new WebSocket(directSocketLink)
+
// Open Connection
this.webSocket.onopen = () => {
setTimeout(pingDirectSocket, 50)
@@ -2375,9 +2678,19 @@ class ChatPage extends LitElement {
if (this.currentEditor === '_chatEditorDOM') {
this.editor.commands.setContent('')
}
+
if (this.currentEditor === 'newChat') {
this.editorImage.commands.setContent('')
}
+
+ if (this.currentEditor === 'newGifChat') {
+ this.editorGif.commands.setContent('')
+ }
+
+ if (this.currentEditor === 'newFileChat') {
+ this.editorAttachment.commands.setContent('')
+ }
+
if (this.currentEditor === 'newAttachmentChat') {
this.editorAttachment.commands.setContent('')
}
@@ -2386,8 +2699,9 @@ class ChatPage extends LitElement {
async _sendMessage(outSideMsg, msg, messageQueue) {
const _chatId = this._chatId
const isReceipient = this.isReceipient
+ const str = "iVBORw0KGgoAAAANSUhEUgAAAsAAAAGMAQMAAADuk4YmAAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAADlJREFUeF7twDEBAAAAwiD7p7bGDlgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAGJrAABgPqdWQAAAABJRU5ErkJggg=="
+
let _publicKey = this._publicKey
- const attachment = this.attachment
try {
if (this.isReceipient) {
@@ -2420,14 +2734,16 @@ class ChatPage extends LitElement {
}
}
+
// 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
// need whole original message object, transform the data and put it in local storage
// create new var called repliedToData and use that to modify the UI
// find specific object property in local
+
let typeMessage = 'regular'
- // this.isLoading = true
+
const trimmedMessage = msg
const getName = async (recipient) => {
@@ -2444,16 +2760,18 @@ class ChatPage extends LitElement {
}
} catch (error) {
- return ""
+ return ''
}
}
if (outSideMsg && outSideMsg.type === 'delete') {
this.isDeletingImage = true
- const userName = outSideMsg.name
- const identifier = outSideMsg.identifier
- let compressedFile = ''
- var str = "iVBORw0KGgoAAAANSUhEUgAAAsAAAAGMAQMAAADuk4YmAAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAADlJREFUeF7twDEBAAAAwiD7p7bGDlgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAGJrAABgPqdWQAAAABJRU5ErkJggg=="
+
+ let userName
+ let identifier
+
+ userName = outSideMsg.name
+ identifier = outSideMsg.identifier
if (this.webWorkerFile) {
this.webWorkerFile.terminate()
@@ -2481,7 +2799,11 @@ class ChatPage extends LitElement {
const blob = new Blob(byteArrays, { type: contentType })
return blob
}
+
const blob = b64toBlob(str, 'image/png')
+
+ let compressedFile = ''
+
await new Promise(resolve => {
new Compressor(blob, {
quality: 0.6,
@@ -2498,13 +2820,15 @@ class ChatPage extends LitElement {
},
})
})
+
const arbitraryFeeData = await modalHelper.getArbitraryFee()
- const res = await modalHelper.showModalAndWaitPublish(
- {
- feeAmount: arbitraryFeeData.feeToShow
- }
- )
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
if (res.action !== 'accept') throw new Error('User declined publish')
+
try {
await publishData({
registeredName: userName,
@@ -2519,37 +2843,46 @@ class ChatPage extends LitElement {
withFee: true,
feeAmount: arbitraryFeeData.fee
})
+
this.isDeletingImage = false
} catch (error) {
this.isLoading = false
return
}
+
typeMessage = 'edit'
+
let chatReference = outSideMsg.editedMessageObj.signature
if (outSideMsg.editedMessageObj.chatReference) {
chatReference = outSideMsg.editedMessageObj.chatReference
}
- let message = ""
+ let message = ''
+
try {
const parsedMessageObj = JSON.parse(outSideMsg.editedMessageObj.decodedMessage)
message = parsedMessageObj
} catch (error) {
message = outSideMsg.editedMessageObj.decodedMessage
}
+
const messageObject = {
...message,
isImageDeleted: true
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
- } else if (outSideMsg && outSideMsg.type === 'deleteAttachment') {
- this.isDeletingAttachment = true
- let compressedFile = ''
- const str = "iVBORw0KGgoAAAANSUhEUgAAAsAAAAGMAQMAAADuk4YmAAAAA1BMVEX///+nxBvIAAAAAXRSTlMAQObYZgAAADlJREFUeF7twDEBAAAAwiD7p7bGDlgYAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAGJrAABgPqdWQAAAABJRU5ErkJggg=="
- const userName = outSideMsg.name
- const identifier = outSideMsg.identifier
+ } else if (outSideMsg && outSideMsg.type === 'deleteGif') {
+ this.isDeletingGif = true
+
+ let userName
+ let identifier
+
+ userName = outSideMsg.name
+ identifier = outSideMsg.identifier
if (this.webWorkerFile) {
this.webWorkerFile.terminate()
@@ -2579,6 +2912,9 @@ class ChatPage extends LitElement {
}
const blob = b64toBlob(str, 'image/png')
+
+ let compressedFile = ''
+
await new Promise(resolve => {
new Compressor(blob, {
quality: 0.6,
@@ -2595,18 +2931,20 @@ class ChatPage extends LitElement {
},
})
})
+
const arbitraryFeeData = await modalHelper.getArbitraryFee()
- const res = await modalHelper.showModalAndWaitPublish(
- {
- feeAmount: arbitraryFeeData.feeToShow
- }
- )
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
if (res.action !== 'accept') throw new Error('User declined publish')
+
try {
await publishData({
registeredName: userName,
file: compressedFile,
- service: 'QCHAT_ATTACHMENT',
+ service: 'IMAGE',
identifier: identifier,
parentEpml,
metaData: undefined,
@@ -2616,19 +2954,23 @@ class ChatPage extends LitElement {
withFee: true,
feeAmount: arbitraryFeeData.fee
})
- this.isDeletingAttachment = false
+
+ this.isDeletingGif = false
} catch (error) {
this.isLoading = false
return
}
+
typeMessage = 'edit'
+
let chatReference = outSideMsg.editedMessageObj.signature
if (outSideMsg.editedMessageObj.chatReference) {
chatReference = outSideMsg.editedMessageObj.chatReference
}
- let message = ""
+ let message = ''
+
try {
const parsedMessageObj = JSON.parse(outSideMsg.editedMessageObj.decodedMessage)
message = parsedMessageObj
@@ -2636,17 +2978,247 @@ class ChatPage extends LitElement {
} catch (error) {
message = outSideMsg.editedMessageObj.decodedMessage
}
+
+ const messageObject = {
+ ...message,
+ isGifDeleted: true
+ }
+
+ const stringifyMessageObject = JSON.stringify(messageObject)
+
+ return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
+ } else if (outSideMsg && outSideMsg.type === 'deleteAttachment') {
+ this.isDeletingAttachment = true
+
+ let userName
+ let identifier
+
+ userName = outSideMsg.name
+ identifier = outSideMsg.identifier
+
+ if (this.webWorkerFile) {
+ this.webWorkerFile.terminate()
+ this.webWorkerFile = null
+ }
+
+ this.webWorkerFile = new WebWorkerFile()
+
+ 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 = b64toBlob(str, 'image/png')
+
+ let compressedFile = ''
+
+ await new Promise(resolve => {
+ new Compressor(blob, {
+ quality: 0.6,
+ maxWidth: 500,
+ success(result) {
+ const file = new File([result], "name", {
+ type: 'image/png'
+ })
+
+ compressedFile = file
+ resolve()
+ },
+ error() {
+ },
+ })
+ })
+
+ const arbitraryFeeData = await modalHelper.getArbitraryFee()
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
+ if (res.action !== 'accept') throw new Error('User declined publish')
+
+ try {
+ await publishData({
+ registeredName: userName,
+ file: compressedFile,
+ service: 'ATTACHMENT',
+ identifier: identifier,
+ parentEpml,
+ metaData: undefined,
+ uploadType: 'file',
+ selectedAddress: this.selectedAddress,
+ worker: this.webWorkerFile,
+ withFee: true,
+ feeAmount: arbitraryFeeData.fee
+ })
+
+ this.isDeletingAttachment = false
+ } catch (error) {
+ this.isLoading = false
+ return
+ }
+
+ typeMessage = 'edit'
+
+ let chatReference = outSideMsg.editedMessageObj.signature
+
+ if (outSideMsg.editedMessageObj.chatReference) {
+ chatReference = outSideMsg.editedMessageObj.chatReference
+ }
+
+ let message = ''
+
+ try {
+ const parsedMessageObj = JSON.parse(outSideMsg.editedMessageObj.decodedMessage)
+ message = parsedMessageObj
+
+ } catch (error) {
+ message = outSideMsg.editedMessageObj.decodedMessage
+ }
+
const messageObject = {
...message,
isAttachmentDeleted: true
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
+ return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
+ } else if (outSideMsg && outSideMsg.type === 'deleteFile') {
+ this.isDeletingAppFile = true
+
+ let userName
+ let identifier
+
+ userName = outSideMsg.name
+ identifier = outSideMsg.identifier
+
+ if (this.webWorkerFile) {
+ this.webWorkerFile.terminate()
+ this.webWorkerFile = null
+ }
+
+ this.webWorkerFile = new WebWorkerFile()
+
+ 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 = b64toBlob(str, 'image/png')
+
+ let compressedFile = ''
+
+ await new Promise(resolve => {
+ new Compressor(blob, {
+ quality: 0.6,
+ maxWidth: 500,
+ success(result) {
+ const file = new File([result], "name", {
+ type: 'image/png'
+ })
+
+ compressedFile = file
+ resolve()
+ },
+ error() {
+ },
+ })
+ })
+
+ const arbitraryFeeData = await modalHelper.getArbitraryFee()
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
+ if (res.action !== 'accept') throw new Error('User declined publish')
+
+ try {
+ await publishData({
+ registeredName: userName,
+ file: compressedFile,
+ service: 'FILE',
+ identifier: identifier,
+ parentEpml,
+ metaData: undefined,
+ uploadType: 'file',
+ selectedAddress: this.selectedAddress,
+ worker: this.webWorkerFile,
+ withFee: true,
+ feeAmount: arbitraryFeeData.fee
+ })
+
+ this.isDeletingAppFile = false
+ } catch (error) {
+ this.isDeletingAppFile = false
+ this.isLoading = false
+ return
+ }
+
+ typeMessage = 'edit'
+
+ let chatReference = outSideMsg.editedMessageObj.signature
+
+ if (outSideMsg.editedMessageObj.chatReference) {
+ chatReference = outSideMsg.editedMessageObj.chatReference
+ }
+
+ let message = ''
+
+ try {
+ const parsedMessageObj = JSON.parse(outSideMsg.editedMessageObj.decodedMessage)
+ message = parsedMessageObj
+
+ } catch (error) {
+ message = outSideMsg.editedMessageObj.decodedMessage
+ }
+
+ const messageObject = {
+ ...message,
+ isFileDeleted: true
+ }
+
+ const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (outSideMsg && outSideMsg.type === 'image') {
if (!this.imageFile.identifier) {
this.isUploadingImage = true
}
+
const userName = await getName(this.selectedAddress.address)
+
if (!userName) {
parentEpml.request('showSnackBar', get("chatpage.cchange27"))
this.isLoading = false
@@ -2655,21 +3227,21 @@ class ChatPage extends LitElement {
return
}
-
let service = "QCHAT_IMAGE"
let name = userName
let identifier
+
if (this.imageFile.identifier) {
identifier = this.imageFile.identifier
name = this.imageFile.name
service = this.imageFile.service
} else {
const arbitraryFeeData = await modalHelper.getArbitraryFee()
- const res = await modalHelper.showModalAndWaitPublish(
- {
- feeAmount: arbitraryFeeData.feeToShow
- }
- )
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
if (res.action !== 'accept') throw new Error('User declined publish')
if (this.webWorkerFile) {
@@ -2678,16 +3250,21 @@ class ChatPage extends LitElement {
}
this.webWorkerFile = new WebWorkerFile()
+
const image = this.imageFile
const id = this.uid.rnd()
let groupPart
+
if (this.isReceipient) {
groupPart = `direct_${generateIdFromAddresses(this._chatId, this.selectedAddress.address)}`
} else {
groupPart = `group_${this._chatId}`
}
+
identifier = `qchat_${groupPart}_${id}`
+
let compressedFile = ''
+
await new Promise(resolve => {
new Compressor(image, {
quality: .6,
@@ -2704,7 +3281,9 @@ class ChatPage extends LitElement {
},
})
})
+
const fileSize = compressedFile.size
+
if (fileSize > 500000) {
parentEpml.request('showSnackBar', get("chatpage.cchange26"))
this.isLoading = false
@@ -2713,7 +3292,6 @@ class ChatPage extends LitElement {
}
try {
-
await publishData({
registeredName: userName,
file: compressedFile,
@@ -2727,6 +3305,7 @@ class ChatPage extends LitElement {
withFee: true,
feeAmount: arbitraryFeeData.fee
})
+
this.isUploadingImage = false
this.removeImage()
} catch (error) {
@@ -2742,42 +3321,124 @@ class ChatPage extends LitElement {
images: [{
service: service,
name: name,
- identifier: identifier,
+ identifier: identifier
}],
isImageDeleted: false,
repliedTo: '',
version: 3
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
this.removeImage()
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (outSideMsg && outSideMsg.type === 'gif') {
+ if (!this.gifFile.identifier) {
+ this.isUploadingGif = true
+ }
+
const userName = await getName(this.selectedAddress.address)
+
if (!userName) {
parentEpml.request('showSnackBar', get("chatpage.cchange27"))
this.isLoading = false
+ this.isUploadingGif = false
+ this.gifFile = null
+ return
+ }
+
+ let identifier
+ let groupPart
+
+ if (this.webWorkerFile) {
+ this.webWorkerFile.terminate()
+ this.webWorkerFile = null
+ }
+
+ this.webWorkerFile = new WebWorkerFile()
+
+ const gifFile = this.gifFile
+ const id = this.uid.rnd()
+
+ if (this.isReceipient) {
+ groupPart = `direct_${generateIdFromAddresses(this._chatId, this.selectedAddress.address)}`
+ } else {
+ groupPart = `group_${this._chatId}`
+ }
+
+ identifier = `qchat_${groupPart}_gif_${id}`
+
+ const fileSize = gifFile.size
+
+ if (fileSize > 3000000) {
+ parentEpml.request('showSnackBar', get("chatpage.cchange103"))
+ this.isLoading = false
+ this.isUploadingGif = false
+ return
+ }
+
+ const arbitraryFeeData = await modalHelper.getArbitraryFee()
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
+ if (res.action !== 'accept') throw new Error('User declined publish')
+
+ try {
+ await publishData({
+ registeredName: userName,
+ file: gifFile,
+ service: 'IMAGE',
+ identifier: identifier,
+ parentEpml,
+ metaData: undefined,
+ uploadType: 'file',
+ selectedAddress: this.selectedAddress,
+ worker: this.webWorkerFile,
+ withFee: true,
+ feeAmount: arbitraryFeeData.fee
+ })
+
+ this.isUploadingGif = false
+ this.removeGif()
+ } catch (error) {
+ this.isLoading = false
+ this.isUploadingGif = false
return
}
const messageObject = {
- messageText: '',
+ messageText: trimmedMessage,
gifs: [{
- service: outSideMsg.service,
- name: outSideMsg.name,
- identifier: outSideMsg.identifier,
- filePath: outSideMsg.filePath
+ service: 'IMAGE',
+ name: userName,
+ identifier: identifier
}],
+ isGifDeleted: false,
repliedTo: '',
version: 3
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (outSideMsg && outSideMsg.type === 'attachment') {
- this.isUploadingAttachment = true
+ if (!this.attachment.identifier) {
+ this.isUploadingAttachment = true
+ }
+
+ let identifier
+ let groupPart
+
const userName = await getName(this.selectedAddress.address)
+
if (!userName) {
parentEpml.request('showSnackBar', get("chatpage.cchange27"))
+ this.isUploadingAttachment = false
this.isLoading = false
+ this.attachment = null
return
}
@@ -2788,28 +3449,39 @@ class ChatPage extends LitElement {
this.webWorkerFile = new WebWorkerFile()
- // const attachment = attachment
- const id = this.uid()
- const identifier = `qchat_${id}`
+ const attachment = this.attachment
+ const id = this.uid.rnd()
+
+ if (this.isReceipient) {
+ groupPart = `direct_${generateIdFromAddresses(this._chatId, this.selectedAddress.address)}`
+ } else {
+ groupPart = `group_${this._chatId}`
+ }
+
+ identifier = `qchat_${groupPart}_attachment_${id}`
+
const fileSize = attachment.size
- if (fileSize > 1000000) {
+
+ if (fileSize > 10000000) {
parentEpml.request('showSnackBar', get("chatpage.cchange77"))
this.isLoading = false
this.isUploadingAttachment = false
return
}
+
const arbitraryFeeData = await modalHelper.getArbitraryFee()
- const res = await modalHelper.showModalAndWaitPublish(
- {
- feeAmount: arbitraryFeeData.feeToShow
- }
- )
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
if (res.action !== 'accept') throw new Error('User declined publish')
+
try {
await publishData({
registeredName: userName,
file: attachment,
- service: 'QCHAT_ATTACHMENT',
+ service: 'ATTACHMENT',
identifier: identifier,
parentEpml,
metaData: undefined,
@@ -2819,6 +3491,7 @@ class ChatPage extends LitElement {
withFee: true,
feeAmount: arbitraryFeeData.fee
})
+
this.isUploadingAttachment = false
this.removeAttachment()
} catch (error) {
@@ -2826,10 +3499,11 @@ class ChatPage extends LitElement {
this.isUploadingAttachment = false
return
}
+
const messageObject = {
messageText: trimmedMessage,
attachments: [{
- service: 'QCHAT_ATTACHMENT',
+ service: 'ATTACHMENT',
name: userName,
identifier: identifier,
attachmentName: attachment.name,
@@ -2839,18 +3513,115 @@ class ChatPage extends LitElement {
repliedTo: '',
version: 3
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
+ return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
+ } else if (outSideMsg && outSideMsg.type === 'file') {
+ if (!this.appFile.identifier) {
+ this.isUploadingAppFile = true
+ }
+
+ let identifier
+ let groupPart
+
+ const userName = await getName(this.selectedAddress.address)
+
+ if (!userName) {
+ parentEpml.request('showSnackBar', get("chatpage.cchange27"))
+ this.isUploadingAppFile = false
+ this.isLoading = false
+ this.appFile = null
+ return
+ }
+
+ if (this.webWorkerFile) {
+ this.webWorkerFile.terminate()
+ this.webWorkerFile = null
+ }
+
+ this.webWorkerFile = new WebWorkerFile()
+
+ const appFile = this.appFile
+ const id = this.uid.rnd()
+
+ if (this.isReceipient) {
+ groupPart = `direct_${generateIdFromAddresses(this._chatId, this.selectedAddress.address)}`
+ } else {
+ groupPart = `group_${this._chatId}`
+ }
+
+ identifier = `qchat_${groupPart}_file_${id}`
+
+ const fileSize = appFile.size
+
+ if (fileSize > 125000000) {
+ parentEpml.request('showSnackBar', get("chatpage.cchange100"))
+ this.isLoading = false
+ this.isUploadingAppFile = false
+ return
+ }
+
+ const arbitraryFeeData = await modalHelper.getArbitraryFee()
+
+ const res = await modalHelper.showModalAndWaitPublish({
+ feeAmount: arbitraryFeeData.feeToShow
+ })
+
+ if (res.action !== 'accept') throw new Error('User declined publish')
+
+ try {
+ await publishData({
+ registeredName: userName,
+ file: appFile,
+ service: 'FILE',
+ identifier: identifier,
+ parentEpml,
+ metaData: undefined,
+ uploadType: 'file',
+ selectedAddress: this.selectedAddress,
+ worker: this.webWorkerFile,
+ withFee: true,
+ feeAmount: arbitraryFeeData.fee
+ })
+
+ this.isUploadingAppFile = false
+ this.removeAppFile()
+ } catch (error) {
+ this.isLoading = false
+ this.isUploadingAppFile = false
+ return
+ }
+
+ const messageObject = {
+ messageText: trimmedMessage,
+ files: [{
+ service: 'FILE',
+ name: userName,
+ identifier: identifier,
+ appFileName: appFile.name,
+ appFileSize: appFile.size
+ }],
+ isFileDeleted: false,
+ repliedTo: '',
+ version: 3
+ }
+
+ const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (outSideMsg && outSideMsg.type === 'reaction') {
const userName = await getName(this.selectedAddress.address)
+
typeMessage = 'edit'
+
let chatReference = outSideMsg.editedMessageObj.signature
if (outSideMsg.editedMessageObj.chatReference) {
chatReference = outSideMsg.editedMessageObj.chatReference
}
- let message = ""
+ let message = ''
try {
const parsedMessageObj = JSON.parse(outSideMsg.editedMessageObj.decodedMessage)
@@ -2860,10 +3631,13 @@ class ChatPage extends LitElement {
}
let reactions = message.reactions || []
+
const findEmojiIndex = reactions.findIndex((reaction) => reaction.type === outSideMsg.reaction)
+
if (findEmojiIndex !== -1) {
let users = reactions[findEmojiIndex].users || []
const findUserIndex = users.findIndex((user) => user.address === this.selectedAddress.address)
+
if (findUserIndex !== -1) {
users.splice(findUserIndex, 1)
} else {
@@ -2872,11 +3646,13 @@ class ChatPage extends LitElement {
name: userName
})
}
+
reactions[findEmojiIndex] = {
...reactions[findEmojiIndex],
qty: users.length,
users
}
+
if (users.length === 0) {
reactions.splice(findEmojiIndex, 1)
}
@@ -2890,27 +3666,35 @@ class ChatPage extends LitElement {
}]
}]
}
+
const messageObject = {
...message,
reactions
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (/^\s*$/.test(trimmedMessage)) {
this.isLoading = false
} else if (this.repliedToMessageObj) {
let chatReference = this.repliedToMessageObj.signature
+
if (this.repliedToMessageObj.chatReference) {
chatReference = this.repliedToMessageObj.chatReference
}
+
typeMessage = 'reply'
+
const messageObject = {
messageText: trimmedMessage,
images: [''],
repliedTo: chatReference,
version: 3
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference: undefined, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else if (this.editedMessageObj) {
typeMessage = 'edit'
@@ -2920,7 +3704,8 @@ class ChatPage extends LitElement {
chatReference = this.editedMessageObj.chatReference
}
- let message = ""
+ let message = ''
+
try {
const parsedMessageObj = JSON.parse(this.editedMessageObj.decodedMessage)
message = parsedMessageObj
@@ -2928,12 +3713,15 @@ class ChatPage extends LitElement {
} catch (error) {
message = this.editedMessageObj.decodedMessage
}
+
const messageObject = {
...message,
messageText: trimmedMessage,
isEdited: true
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
+
return this.sendMessage({ messageText: stringifyMessageObject, typeMessage, chatReference, isForward: false, isReceipient, _chatId, _publicKey, messageQueue })
} else {
const messageObject = {
@@ -2942,6 +3730,7 @@ class ChatPage extends LitElement {
repliedTo: '',
version: 3
}
+
const stringifyMessageObject = JSON.stringify(messageObject)
if (this.balance < 4) {
@@ -2955,6 +3744,9 @@ class ChatPage extends LitElement {
} catch (error) {
this.isLoading = false
this.isUploadingImage = false
+ this.isUploadingGif = false
+ this.isUploadingAttachment = false
+ this.isUploadingAppFile = false
return
}
@@ -2968,6 +3760,7 @@ class ChatPage extends LitElement {
this.closeRepliedToContainer()
return
}
+
if (isForward) {
this.isLoading = true
}
@@ -2975,6 +3768,7 @@ class ChatPage extends LitElement {
let _reference = new Uint8Array(64)
window.crypto.getRandomValues(_reference)
let reference = window.parent.Base58.encode(_reference)
+
const sendMessageRequest = async () => {
if (isReceipient === true) {
let chatResponse = await parentEpml.request('chat', {
diff --git a/plugins/plugins/core/components/ChatScroller.js b/plugins/plugins/core/components/ChatScroller.js
index 14963901..8086fe8a 100644
--- a/plugins/plugins/core/components/ChatScroller.js
+++ b/plugins/plugins/core/components/ChatScroller.js
@@ -21,6 +21,9 @@ import './ChatImage'
import '@material/mwc-button'
import '@material/mwc-dialog'
import '@material/mwc-icon'
+import '@polymer/paper-dialog/paper-dialog.js'
+import '@polymer/paper-icon-button/paper-icon-button.js'
+import '@polymer/iron-icons/iron-icons.js'
import '@vaadin/icon'
import '@vaadin/icons'
import '@vaadin/tooltip'
@@ -96,6 +99,7 @@ function processText(input) {
parts.forEach((part) => {
if (part.startsWith('qortal://')) {
const link = document.createElement('span')
+
// Store the URL in a data attribute
link.setAttribute('data-url', part)
link.textContent = part
@@ -107,7 +111,9 @@ function processText(input) {
e.preventDefault()
try {
const res = await extractComponents(part)
+
if (!res) return
+
if (res.type && res.groupid && res.action === 'join') {
window.parent.reduxStore.dispatch(
window.parent.reduxAction.setNewTab({
@@ -130,7 +136,7 @@ function processText(input) {
window.parent.reduxStore.dispatch(
window.parent.reduxAction.setSideEffectAction({
type: 'openJoinGroupModal',
- data: +res.groupid
+ data: res.groupid
})
)
return
@@ -987,7 +993,9 @@ class MessageTemplate extends LitElement {
openDialogImage: { type: Boolean },
openDialogGif: { type: Boolean },
openDeleteImage: { type: Boolean },
+ openDeleteGif: { type: Boolean },
openDeleteAttachment: { type: Boolean },
+ openDeleteFile: { type: Boolean },
isImageLoaded: { type: Boolean },
isGifLoaded: { type: Boolean },
isFirstMessage: { type: Boolean },
@@ -1032,6 +1040,10 @@ class MessageTemplate extends LitElement {
this.isLastMessageInGroup = false
this.viewImage = false
this.isInProgress = false
+ this.openDeleteImage = false
+ this.openDeleteGif = false
+ this.openDeleteAttachment = false
+ this.openDeleteFile = false
}
render() {
@@ -1044,36 +1056,50 @@ class MessageTemplate extends LitElement {
let repliedToData = null
let image = null
let gif = null
+ let attachment = null
+ let file = null
let isImageDeleted = false
+ let isGifDeleted = false
let isAttachmentDeleted = false
+ let isFileDeleted = false
let version = 0
let isForwarded = false
let isEdited = false
- let attachment = null
try {
const parsedMessageObj = JSON.parse(this.messageObj.decodedMessage)
+
if (+parsedMessageObj.version > 1 && parsedMessageObj.messageText) {
messageVersion2 = generateHTML(parsedMessageObj.messageText, [StarterKit, Underline, Highlight])
messageVersion2WithLink = processText(messageVersion2)
}
+
message = parsedMessageObj.messageText
repliedToData = this.messageObj.repliedToData
isImageDeleted = parsedMessageObj.isImageDeleted
+ isGifDeleted = parsedMessageObj.isGifDeleted
isAttachmentDeleted = parsedMessageObj.isAttachmentDeleted
+ isFileDeleted = parsedMessageObj.isFileDeleted
// reactions = parsedMessageObj.reactions || []
version = parsedMessageObj.version
isForwarded = parsedMessageObj.type === 'forward'
isEdited = parsedMessageObj.isEdited && true
- if (parsedMessageObj.attachments && Array.isArray(parsedMessageObj.attachments) && parsedMessageObj.attachments.length > 0) {
- attachment = parsedMessageObj.attachments[0]
- }
+
if (parsedMessageObj.images && Array.isArray(parsedMessageObj.images) && parsedMessageObj.images.length > 0) {
image = parsedMessageObj.images[0]
}
+
if (parsedMessageObj.gifs && Array.isArray(parsedMessageObj.gifs) && parsedMessageObj.gifs.length > 0) {
gif = parsedMessageObj.gifs[0]
}
+
+ if (parsedMessageObj.attachments && Array.isArray(parsedMessageObj.attachments) && parsedMessageObj.attachments.length > 0) {
+ attachment = parsedMessageObj.attachments[0]
+ }
+
+ if (parsedMessageObj.files && Array.isArray(parsedMessageObj.files) && parsedMessageObj.files.length > 0) {
+ file = parsedMessageObj.files[0]
+ }
} catch (error) {
message = this.messageObj.decodedMessage
}
@@ -1141,7 +1167,7 @@ class MessageTemplate extends LitElement {
if (gif) {
const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node]
const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port
- gifUrl = `${nodeUrl}/arbitrary/${gif.service}/${gif.name}/${gif.identifier}?filepath=${gif.filePath}`
+ gifUrl = `${nodeUrl}/arbitrary/${gif.service}/${gif.name}/${gif.identifier}?async=true`
if (this.viewImage || this.myAddress === this.messageObj.sender) {
gifHTML = createGif(gifUrl)
gifHTMLDialog = createGif(gifUrl)
@@ -1280,7 +1306,7 @@ class MessageTemplate extends LitElement {
class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : '',].join(' ')}
style=${this.isFirstMessage && 'margin-top: 10px;'}
>
-
+
${translate('chatpage.cchange40')}
@@ -1293,7 +1319,12 @@ class MessageTemplate extends LitElement {
${imageHTML}
${this.myAddress === this.messageObj.sender ?
html`
- {this.openDeleteImage = true;}} class="image-delete-icon" icon="vaadin:close" slot="icon">
+ this.openDeleteImageDialog()}
+ icon="vaadin:close"
+ slot="icon"
+ class="image-delete-icon"
+ >
`
: ''
}
@@ -1301,35 +1332,62 @@ class MessageTemplate extends LitElement {
`
: image && isImageDeleted ?
html`
- ${translate('chatpage.cchange80')}
+
+
+
+ ${translate('chatpage.cchange80')}
+
+
+
`
: html``
}
- ${gif && !this.viewImage && this.myAddress !== this.messageObj.sender ?
+ ${gif && !isGifDeleted && !this.viewImage && this.myAddress !== this.messageObj.sender ?
html`
{this.viewImage = true;}}
- class=${[`image-container`, !this.isImageLoaded ? 'defaultSize' : '', ].join(' ')}
+ class=${[`image-container`, !this.isGifoaded ? 'defaultSize' : '', ].join(' ')}
style=${this.isFirstMessage && 'margin-top: 10px;'}
>
-
+
${translate('gifs.gchange25')}
`
: html``
}
- ${gif && (this.viewImage || this.myAddress === this.messageObj.sender) ?
+ ${gif && !isGifDeleted && (this.viewImage || this.myAddress === this.messageObj.sender) ?
html`
${gifHTML}
+ ${this.myAddress === this.messageObj.sender ?
+ html`
+ this.openDeleteGifDialog()}
+ icon="vaadin:close"
+ slot="icon"
+ class="image-delete-icon"
+ >
+ `
+ : ''
+ }
`
+ : gif && isGifDeleted ?
+ html`
+
+
+
+ ${translate('chatpage.cchange107')}
+
+
+
+ `
: html``
}
${attachment && !isAttachmentDeleted ?
html`
-
await this.downloadAttachment(attachment)} class="attachment-container">
+
@@ -1341,11 +1399,16 @@ class MessageTemplate extends LitElement {
${roundToNearestDecimal(attachment.attachmentSize)} mb
-
+
await this.downloadAttachment(attachment)}
+ icon="vaadin:download-alt"
+ slot="icon"
+ class="download-icon"
+ >
${this.myAddress === this.messageObj.sender ?
html`
{e.stopPropagation(); this.openDeleteAttachment = true;}}
+ @click=${() => this.openDeleteAttachmentDialog()}
class="image-delete-icon"
icon="vaadin:close"
slot="icon"
@@ -1368,6 +1431,51 @@ class MessageTemplate extends LitElement {
`
: html``
}
+ ${file && !isFileDeleted ?
+ html`
+
+
+
![file-icon](/img/file-icon.png)
+
+
+
+ ${file && file.appFileName}
+
+
+ ${roundToNearestDecimal(file.appFileSize)} mb
+
+
+
await this.downloadFile(file)}
+ icon="vaadin:download-alt"
+ slot="icon"
+ class="download-icon"
+ >
+ ${this.myAddress === this.messageObj.sender ?
+ html`
+
this.openDeleteFileDialog()}
+ class="image-delete-icon"
+ icon="vaadin:close"
+ slot="icon"
+ >
+ `
+ : html``
+ }
+
+ `
+ : file && isFileDeleted ?
+ html`
+
+
+
+ ${translate('chatpage.cchange102')}
+
+
+
+ `
+ : html``
+ }
${+version > 1 ? messageVersion2WithLink ?
html`
@@ -1511,7 +1619,6 @@ class MessageTemplate extends LitElement {
{this.openDialogGif = false;}}>
- MessageTemplate
${gifHTMLDialog}
@@ -1519,34 +1626,88 @@ class MessageTemplate extends LitElement {
{this.openDialogGif = false;}}>
${translate('general.close')}
- MessageTemplate
-
{this.openDeleteImage = false;}}>
+
${translate('chatpage.cchange78')}
-
@@ -295,7 +299,7 @@ class ChatTextEditor extends LitElement {
}
sendMessageFunc(props) {
- if (this.editor.isEmpty && (this.iframeId !== 'newChat' && this.iframeId !== 'newAttachmentChat')) return
+ if (this.editor.isEmpty && (this.iframeId !== 'newChat' && this.iframeId !== 'newGifChat' && this.iframeId !== 'newAttachmentChat' && this.iframeId !== 'newFileChat')) return
this.getMessageSize(this.editor.getJSON())
@@ -351,18 +355,42 @@ class ChatTextEditor extends LitElement {
repliedTo: '',
version: 3
}
+ } else if (this.gifFile && this.iframeId === 'newGifChat') {
+ messageObject = {
+ messageText: trimmedMessage,
+ images: [{
+ service: "IMAGE",
+ name: '123456789123456789123456789',
+ identifier: '123456'
+ }],
+ repliedTo: '',
+ version: 3
+ }
} else if (this.attachment && this.iframeId === 'newAttachmentChat') {
messageObject = {
messageText: trimmedMessage,
attachments: [{
- service: "QCHAT_ATTACHMENT",
+ service: "ATTACHMENT",
name: '123456789123456789123456789',
identifier: '123456',
attachmentName: "123456789123456789123456789",
attachmentSize: "123456"
}],
repliedTo: '',
- version: 2
+ version: 3
+ }
+ } else if (this.appFile && this.iframeId === 'newFileChat') {
+ messageObject = {
+ messageText: trimmedMessage,
+ files: [{
+ service: "FILE",
+ name: '123456789123456789123456789',
+ identifier: '123456',
+ appFileName: "123456789123456789123456789",
+ appFileSize: "123456"
+ }],
+ repliedTo: '',
+ version: 3
}
} else {
messageObject = {
diff --git a/plugins/plugins/core/components/plugins-css.js b/plugins/plugins/core/components/plugins-css.js
index 6ee176c2..b5c570db 100644
--- a/plugins/plugins/core/components/plugins-css.js
+++ b/plugins/plugins/core/components/plugins-css.js
@@ -426,7 +426,6 @@ export const chatpageStyles = css`
width: 800px;
}
-
.close-icon {
color: #676b71;
width: 18px;
@@ -1152,6 +1151,22 @@ export const chatpageStyles = css`
width: 70%;
}
+ .file-icon-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 128px;
+ width: 128px;
+ border-radius: 50%;
+ border: none;
+ background-color: transparent;
+ }
+
+ .file-icon {
+ height: 128px;
+ width: 128px;
+ }
+
.attachment-name {
font-family: Work Sans, sans-serif;
font-size: 20px;
@@ -1440,6 +1455,7 @@ export const chatStyles = css`
--mdc-theme-secondary: var(--mdc-theme-primary);
--mdc-dialog-max-width: 85vw;
--mdc-dialog-max-height: 95vh;
+
}
* :focus-visible {
@@ -1567,7 +1583,6 @@ export const chatStyles = css`
min-width: 150px;
}
-
.message-myBg {
background-color: var(--chat-bubble-myBg) !important;
}
@@ -2107,10 +2122,8 @@ export const chatStyles = css`
justify-content: space-evenly;
padding: 5px 0 10px 0;
gap: 20px;
- cursor: pointer;
}
-
.attachment-icon-container {
display: flex;
align-items: center;
@@ -2126,6 +2139,30 @@ export const chatStyles = css`
width: 70%;
}
+ .file-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-evenly;
+ padding: 5px 0 10px 0;
+ gap: 20px;
+ }
+
+ .file-icon-container {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: 50px;
+ width: 50px;
+ border-radius: 50%;
+ border: none;
+ background-color: transparent;
+ }
+
+ .file-icon {
+ height: 50px;
+ width: 50px;
+ }
+
.attachment-info {
display: flex;
flex-direction: column;
@@ -2158,6 +2195,7 @@ export const chatStyles = css`
color: var(--chat-bubble-msg-color);
width: 19px;
background-color: transparent;
+ cursor: pointer;
}
.download-icon:hover::before {
@@ -2247,6 +2285,155 @@ export const chatStyles = css`
transform: rotate(360deg);
}
}
+
+ paper-dialog.progress {
+ width: auto;
+ max-width: 50vw;
+ height: auto;
+ max-height: 30vh;
+ background-color: var(--white);
+ color: var(--black);
+ border: 1px solid var(--black);
+ border-radius: 15px;
+ text-align: center;
+ padding: 15px;
+ line-height: 1.6;
+ overflow: hidden;
+ }
+
+ paper-dialog.close-progress {
+ min-width: 550px;
+ max-width: 550px;
+ height: auto;
+ background-color: var(--white);
+ color: var(--black);
+ border: 1px solid var(--black);
+ border-radius: 15px;
+ text-align: center;
+ padding: 15px;
+ font-size: 17px;
+ font-weight: 500;
+ line-height: 20px;
+ overflow: hidden;
+ }
+
+ .lds-roller {
+ display: inline-block;
+ position: relative;
+ width: 80px;
+ height: 80px;
+ }
+
+ .lds-roller div {
+ animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
+ transform-origin: 40px 40px;
+ }
+
+ .lds-roller div:after {
+ content: " ";
+ display: block;
+ position: absolute;
+ width: 7px;
+ height: 7px;
+ border-radius: 50%;
+ background: var(--black);
+ margin: -4px 0 0 -4px;
+ }
+
+ .lds-roller div:nth-child(1) {
+ animation-delay: -0.036s;
+ }
+
+ .lds-roller div:nth-child(1):after {
+ top: 63px;
+ left: 63px;
+ }
+
+ .lds-roller div:nth-child(2) {
+ animation-delay: -0.072s;
+ }
+
+ .lds-roller div:nth-child(2):after {
+ top: 68px;
+ left: 56px;
+ }
+
+ .lds-roller div:nth-child(3) {
+ animation-delay: -0.108s;
+ }
+
+ .lds-roller div:nth-child(3):after {
+ top: 71px;
+ left: 48px;
+ }
+
+ .lds-roller div:nth-child(4) {
+ animation-delay: -0.144s;
+ }
+
+ .lds-roller div:nth-child(4):after {
+ top: 72px;
+ left: 40px;
+ }
+
+ .lds-roller div:nth-child(5) {
+ animation-delay: -0.18s;
+ }
+
+ .lds-roller div:nth-child(5):after {
+ top: 71px;
+ left: 32px;
+ }
+
+ .lds-roller div:nth-child(6) {
+ animation-delay: -0.216s;
+ }
+
+ .lds-roller div:nth-child(6):after {
+ top: 68px;
+ left: 24px;
+ }
+
+ .lds-roller div:nth-child(7) {
+ animation-delay: -0.252s;
+ }
+
+ .lds-roller div:nth-child(7):after {
+ top: 63px;
+ left: 17px;
+ }
+
+ .lds-roller div:nth-child(8) {
+ animation-delay: -0.288s;
+ }
+
+ .lds-roller div:nth-child(8):after {
+ top: 56px;
+ left: 12px;
+ }
+
+ @keyframes lds-roller {
+ 0% {
+ transform: rotate(0deg);
+ }
+
+ 100% {
+ transform: rotate(360deg);
+ }
+ }
+
+ .close-download {
+ color: var(--black);
+ font-size: 14px;
+ font-weight: bold;
+ position: absolute;
+ top: -15px;
+ right: -15px;
+ }
+
+ .close-download:hover {
+ color: #df3636;
+ }
`
export const toolTipStyles = css`
@@ -3631,6 +3818,12 @@ export const chatTextEditorStyles = css`
cursor: pointer;
}
+ .ProseMirror {
+ word-wrap: break-word;
+ white-space: pre-wrap;
+ white-space: break-spaces;
+ }
+
.ProseMirror:focus {
outline: none;
}