diff --git a/plugins/plugins/core/components/ChatImageGif.js b/plugins/plugins/core/components/ChatImageGif.js new file mode 100644 index 00000000..9ff7ae95 --- /dev/null +++ b/plugins/plugins/core/components/ChatImageGif.js @@ -0,0 +1,230 @@ +import { html, LitElement } from 'lit' +import { Epml } from '../../../epml' +import { RequestQueueWithPromise } from '../../utils/classes' +import { chatImageStyles } from './plugins-css' +import axios from 'axios' + +// Multi language support +import { get, translate } from '../../../../core/translate' + +const parentEpml = new Epml({ type: 'WINDOW', source: window.parent }) + +const requestQueue = new RequestQueueWithPromise(5) + +export class ChatImageGif extends LitElement { + static get properties() { + return { + resource: { type: Object }, + isReady: { type: Boolean }, + status: { type: Object }, + setOpenDialogGif: { attribute: false } + } + } + + static get styles() { + return [chatImageStyles] + } + + constructor() { + super(); + this.resource = { + identifier: '', + name: '', + service: '' + } + this.status = { + status: '' + } + this.url = '' + this.isReady = false + this.nodeUrl = this.getNodeUrl() + this.myNode = this.getMyNode() + this.hasCalledWhenDownloaded = false + this.isFetching = false + this.observer = new IntersectionObserver(entries => { + for (const entry of entries) { + if (entry.isIntersecting && this.status.status !== 'READY') { + this.fetchGif() + this.observer.unobserve(this) + } + } + }) + } + + render() { + + return html` +
+ ${this.status.status !== 'READY' ? + html` +
+
+

${`${Math.round(this.status.percentLoaded || 0).toFixed(0)}% `}${translate('chatpage.cchange94')}

+
+ ` + : '' + } + ${this.status.status === 'READY' ? + html` + ${this.createGif(this.url)} + ` + : '' + } +
+ ` + } + + firstUpdated() { + this.observer.observe(this) + } + + createGif(gif) { + const gifHTMLRes = new Image() + gifHTMLRes.src = gif + gifHTMLRes.style = 'max-width:45vh; max-height:40vh; border-radius: 5px; cursor: pointer;' + gifHTMLRes.onclick = () => {this.setOpenDialogGif(true);} + gifHTMLRes.onload = () => {this.isGifLoaded = true;} + gifHTMLRes.onerror = () => { + if (this.gifFetches < 4) { + setTimeout(() => { + this.gifFetches = this.gifFetches + 1 + gifHTMLRes.src = gif + }, 10000) + } else { + gifHTMLRes.src = '/img/chain.png' + gifHTMLRes.style = 'max-width:45vh; max-height:20vh; border-radius: 5px; filter: opacity(0.5);' + gifHTMLRes.onclick = () => {} + this.isGifLoaded = true + } + } + return gifHTMLRes + } + + getNodeUrl() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port + return nodeUrl + } + + getMyNode() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + return myNode + } + + async fetchResource() { + try { + if (this.isFetching) return + this.isFetching = true + await axios.get(`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}`) + this.isFetching = false + } catch (error) { + this.isFetching = false + } + } + + async fetchGifUrl() { + this.fetchResource() + this.url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?async=true` + } + + async fetchStatus() { + let isCalling = false + let percentLoaded = 0 + let timer = 24 + + const response = await axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}`) + + if (response && response.data && response.data.status === 'READY') { + this.status = response.data + return + } + + const intervalId = setInterval(async () => { + if (isCalling) return + + isCalling = true + + const data = await requestQueue.enqueue(() => { + return axios.get(`${this.nodeUrl}/arbitrary/resource/status/${this.resource.service}/${this.resource.name}/${this.resource.identifier}`) + }) + + const res = data.data + + isCalling = false + + if (res.localChunkCount) { + if (res.percentLoaded) { + if (res.percentLoaded === percentLoaded && res.percentLoaded !== 100) { + timer = timer - 5 + } else { + timer = 24 + } + + if (timer < 0) { + timer = 24 + + isCalling = true + + this.status = { + ...res, + status: 'REFETCHING' + } + + setTimeout(() => { + isCalling = false + this.fetchResource() + }, 25000) + + return + } + + percentLoaded = res.percentLoaded + } + + this.status = res + + if (this.status.status === 'DOWNLOADED') { + this.fetchResource() + } + } + + // check if progress is 100% and clear interval if true + if (res.status === 'READY') { + clearInterval(intervalId) + this.status = res + this.isReady = true + } + }, 5000) // 5 second interval + } + + async fetchGif() { + try { + this.fetchGifUrl({name: this.resource.name, service: this.resource.service, identifier: this.resource.identifier}) + this.fetchStatus() + } catch (error) { /* empty */ } + } + + shouldUpdate(changedProperties) { + if (changedProperties.has('setOpenDialogGif') && changedProperties.size === 1) { + return false + } + return true + } + + // Standard functions + getApiKey() { + const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] + return myNode.apiKey + } + + isEmptyArray(arr) { + if (!arr) { return true } + return arr.length === 0 + } + + round(number) { + return (Math.round(parseFloat(number) * 1e8) / 1e8).toFixed(8) + } +} + +window.customElements.define('chat-image-gif', ChatImageGif) diff --git a/plugins/plugins/core/components/ChatScroller.js b/plugins/plugins/core/components/ChatScroller.js index 9d450241..68169191 100644 --- a/plugins/plugins/core/components/ChatScroller.js +++ b/plugins/plugins/core/components/ChatScroller.js @@ -18,6 +18,7 @@ import './NameMenu' import './UserInfo' import './WrapperModal' import './ChatImage' +import './ChatImageGif' import '@material/mwc-button' import '@material/mwc-dialog' import '@material/mwc-icon' @@ -1118,15 +1119,6 @@ class MessageTemplate extends LitElement { levelFounder = html`` - if (this.messageObj.senderName) { - 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.messageObj.senderName}/qortal_avatar?async=true` - avatarImg = html`` - } else { - avatarImg = html`` - } - const createGif = (gif) => { const gifHTMLRes = new Image() gifHTMLRes.src = gif @@ -1149,6 +1141,15 @@ class MessageTemplate extends LitElement { return gifHTMLRes } + if (this.messageObj.senderName) { + 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.messageObj.senderName}/qortal_avatar?async=true` + avatarImg = html`` + } else { + avatarImg = html`` + } + if (image) { const myNode = window.parent.reduxStore.getState().app.nodeConfig.knownNodes[window.parent.reduxStore.getState().app.nodeConfig.node] const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port @@ -1157,7 +1158,7 @@ class MessageTemplate extends LitElement { imageHTML = html` this.setOpenDialogImage(val)} + .setOpenDialogImage=${(val) => this.setOpenDialogImage(val)} > ` @@ -1169,7 +1170,13 @@ class MessageTemplate extends LitElement { const nodeUrl = myNode.protocol + '://' + myNode.domain + ':' + myNode.port gifUrl = `${nodeUrl}/arbitrary/${gif.service}/${gif.name}/${gif.identifier}?async=true` if (this.viewImage || this.myAddress === this.messageObj.sender) { - gifHTML = createGif(gifUrl) + gifHTML = html` + this.setOpenDialogGif(val)} + > + + ` gifHTMLDialog = createGif(gifUrl) gifHTMLDialog.style = 'height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px;' } @@ -1612,7 +1619,7 @@ class MessageTemplate extends LitElement { {this.openDialogImage = false;}}>
- ${this.openDialogImage ? html`` : ''} + ${this.openDialogImage ? html`` : ''}
{this.openDialogImage = false;}}> ${translate('general.close')} @@ -1875,6 +1882,10 @@ class MessageTemplate extends LitElement { this.openDialogImage = val } + setOpenDialogGif(val) { + this.openDialogGif = val + } + shouldUpdate(changedProperties) { if (changedProperties.has('messageObj')) { return true