4
1
mirror of https://github.com/Qortal/qortal-ui.git synced 2025-02-11 17:55:51 +00:00

right side panel for imgs

This commit is contained in:
PhilReact 2023-09-22 01:40:14 -05:00
parent 81129398b6
commit a80f6800d8
6 changed files with 1039 additions and 56 deletions

View File

@ -835,7 +835,8 @@
"cchange91": "Sending...",
"cchange92": "Unread messages below",
"cchange93": "Image copied to clipboard",
"cchange94": "loaded"
"cchange94": "loaded",
"cchange95": "Only my resources"
},
"welcomepage": {
"wcchange1": "Welcome to Q-Chat",

View File

@ -198,11 +198,7 @@ getMyNode(){
setTimeout(() => {
isCalling = false
this.fetchResource({
name,
service,
identifier
})
this.fetchResource()
}, 25000)
return
}

View File

@ -10,6 +10,7 @@ import { inputKeyCodes } from '../../utils/keyCodes.js'
import { replaceMessagesEdited } from '../../utils/replace-messages-edited.js'
import { publishData } from '../../utils/publish-image.js'
import { EmojiPicker } from 'emoji-picker-js'
import {ifDefined} from 'lit/directives/if-defined.js';
import * as zip from '@zip.js/zip.js'
@ -38,6 +39,7 @@ import './ChatSideNavHeads.js'
import './ChatLeaveGroup.js'
import './ChatGroupSettings.js'
import './ChatRightPanel.js'
import './ChatRightPanelResources.js'
import './ChatSearchResults.js'
import '@material/mwc-button'
import '@material/mwc-dialog'
@ -105,6 +107,7 @@ class ChatPage extends LitElement {
groupAdmin: { type: Array },
groupMembers: { type: Array },
shifted: { type: Boolean },
shiftedResources: {type: Boolean},
groupInfo: { type: Object },
setActiveChatHeadUrl: { attribute: false },
userFound: { type: Array },
@ -1058,13 +1061,14 @@ class ChatPage extends LitElement {
.group-nav-container {
display: flex;
height: 40px;
padding: 25px 5px 25px 20px;
padding: 5px;
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);
z-index: 1;
}
.top-bar-icon {
@ -1344,6 +1348,7 @@ class ChatPage extends LitElement {
this.groupAdmin = []
this.groupMembers = []
this.shifted = false
this.shiftedResources = false
this.groupInfo = {}
this.pageNumber = 1
this.userFoundModalOpen = false
@ -1389,6 +1394,10 @@ class ChatPage extends LitElement {
this.shifted = value === (false || true) ? value : !this.shifted
this.requestUpdate()
}
_toggleResources(value) {
this.shiftedResources = value === (false || true) ? value : !this.shiftedResources
this.requestUpdate()
}
setOpenTipUser(props) {
this.openTipUser = props
@ -1489,23 +1498,32 @@ class ChatPage extends LitElement {
render() {
console.log('this.chatId', this.chatId, this._chatId)
return html`
<div class="main-container">
<div
class="chat-container"
style=${(!this.isReceipient && +this._chatId !== 0) ? "grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); flex: 3;" : "grid-template-rows: minmax(6%, 92vh) minmax(40px, auto); flex: 2;"}>
${(!this.isReceipient && +this._chatId !== 0) ?
html`
style="grid-template-rows: minmax(40px, auto) minmax(6%, 92vh) minmax(40px, auto); flex: 3;">
<div class="group-nav-container">
<div @click=${this._toggle} style="height: 100%; display: flex; align-items: center;flex-grow: 1; cursor: pointer; cursor: pointer; user-select: none">
${this.isReceipient ? '' : +this._chatId === 0 ? html`
<p class="group-name">Qortal General Chat</p>
` : html`
<p class="group-name">${this.groupInfo && this.groupInfo.groupName}</p>
`}
</div>
<div style="display: flex; height: 100%; align-items: center">
<vaadin-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px" icon="vaadin:info" slot="icon"></vaadin-icon>
<mwc-icon class="top-bar-icon" @click=${this._toggleResources} style="margin: 0px 10px">photo_library</mwc-icon>
${(!this.isReceipient && +this._chatId !== 0) ?
html`
<mwc-icon class="top-bar-icon" @click=${this._toggle} style="margin: 0px 10px">groups</mwc-icon>
`
: ''}
</div>
</div>
` : null}
<div>
${this.isLoadingMessages ?
html`
@ -1949,6 +1967,24 @@ class ChatPage extends LitElement {
>
</chat-right-panel>
</div>
<div class="chat-right-panel ${this.shiftedResources ? "movedin" : "movedout"}" ${animate()}>
<chat-right-panel-resources
.getMoreMembers=${(val) => this.getMoreMembers(val)}
.toggle=${(val) => this._toggleResources(val)}
.selectedAddress=${this.selectedAddress}
.groupMembers=${this.groupMembers}
.groupAdmin=${this.groupAdmin}
.leaveGroupObj=${this.groupInfo}
.setOpenPrivateMessage=${(val) => this.setOpenPrivateMessage(val)}
.setOpenTipUser=${(val) => this.setOpenTipUser(val)}
.setOpenUserInfo=${(val) => this.setOpenUserInfo(val)}
.setUserName=${(val) => this.setUserName(val)}
_chatId=${ifDefined(this._chatId)}
chatId=${this.chatId}
?isreceipient=${this.isReceipient}
>
</chat-right-panel-resources>
</div>
</div>
`
}
@ -2901,7 +2937,7 @@ class ChatPage extends LitElement {
}));
let list = [...decodeMsgs]
this.messagesRendered = {
messages: list,
@ -3890,7 +3926,8 @@ class ChatPage extends LitElement {
const image = this.imageFile
const id = this.uid.rnd()
const identifier = `qchat_${id}`
const groupPart = this.isReceipient ? `direct_${this._chatId.slice(-15)}` : `group_${this._chatId}`
const identifier = `qchat_${groupPart}_${id}`
let compressedFile = ''
await new Promise(resolve => {
new Compressor(image, {

View File

@ -0,0 +1,651 @@
import { LitElement, html, css } from 'lit';
import { render } from 'lit/html.js';
import { Epml } from '../../../epml';
import { getUserNameFromAddress } from '../../utils/getUserNameFromAddress';
import snackbar from './snackbar.js';
import '@material/mwc-button';
import '@material/mwc-dialog';
import '@polymer/paper-spinner/paper-spinner-lite.js';
import '@polymer/paper-progress/paper-progress.js';
import '@material/mwc-icon';
import '@vaadin/button';
import './WrapperModal';
import './TipUser';
import './UserInfo/UserInfo';
import './ChatImage';
import './ReusableImage';
import {
use,
get,
translate,
translateUnsafeHTML,
registerTranslateConfig,
} from 'lit-translate';
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
class ChatRightPanelResources extends LitElement {
static get properties() {
return {
leaveGroupObj: { type: Object },
error: { type: Boolean },
chatHeads: { type: Array },
groupAdmin: { attribute: false },
groupMembers: { attribute: false },
selectedHead: { type: Object },
toggle: { attribute: false },
getMoreMembers: { attribute: false },
setOpenPrivateMessage: { attribute: false },
userName: { type: String },
walletBalance: { type: Number },
sendMoneyLoading: { type: Boolean },
btnDisable: { type: Boolean },
errorMessage: { type: String },
successMessage: { type: String },
setOpenTipUser: { attribute: false },
setOpenUserInfo: { attribute: false },
setUserName: { attribute: false },
chatId: { type: String },
_chatId: { type: String },
isReceipient: { type: Boolean },
images: { type: Array },
viewImage: { type: Boolean },
autoView: {type: Boolean},
onlyMyImages: {type: Boolean}
};
}
constructor() {
super();
this.leaveGroupObj = {};
this.leaveFee = 0.001;
this.error = false;
this.chatHeads = [];
this.groupAdmin = [];
this.groupMembers = [];
this.observerHandler = this.observerHandler.bind(this);
this.getMoreImages = this.getMoreImages.bind(this);
this.viewElement = '';
this.downObserverElement = '';
this.sendMoneyLoading = false;
this.btnDisable = false;
this.errorMessage = '';
this.successMessage = '';
this.images = [];
this.viewImage = false;
this.myName =
window.parent.reduxStore.getState().app.accountInfo.names[0].name;
this.autoView =false
this.onlyMyImages = true
}
static get styles() {
return css`
.top-bar-icon {
cursor: pointer;
height: 18px;
width: 18px;
transition: 0.2s all;
}
.top-bar-icon:hover {
color: var(--black);
}
.modal-button {
font-family: Roboto, sans-serif;
font-size: 16px;
color: var(--mdc-theme-primary);
background-color: transparent;
padding: 8px 10px;
border-radius: 5px;
border: none;
transition: all 0.3s ease-in-out;
}
.close-row {
width: 100%;
display: flex;
justify-content: flex-end;
height: 50px;
flex: 0;
align-items: center;
}
.container-body {
width: 100%;
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: auto;
margin-top: 5px;
padding: 0px 6px;
box-sizing: border-box;
}
.container-body::-webkit-scrollbar-track {
background-color: whitesmoke;
border-radius: 7px;
}
.container-body::-webkit-scrollbar {
width: 6px;
border-radius: 7px;
background-color: whitesmoke;
}
.container-body::-webkit-scrollbar-thumb {
background-color: rgb(180, 176, 176);
border-radius: 7px;
transition: all 0.3s ease-in-out;
}
.container-body::-webkit-scrollbar-thumb:hover {
background-color: rgb(148, 146, 146);
cursor: pointer;
}
p {
color: var(--black);
margin: 0px;
padding: 0px;
word-break: break-all;
}
.container {
display: flex;
width: 100%;
flex-direction: column;
height: 100%;
}
.chat-right-panel-label {
font-family: Montserrat, sans-serif;
color: var(--group-header);
padding: 5px;
font-size: 13px;
user-select: none;
}
.group-info {
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 10px;
}
.group-name {
font-family: Raleway, sans-serif;
font-size: 20px;
color: var(--chat-bubble-msg-color);
text-align: center;
user-select: none;
}
.group-description {
font-family: Roboto, sans-serif;
color: var(--chat-bubble-msg-color);
letter-spacing: 0.3px;
font-weight: 300;
font-size: 14px;
margin-top: 15px;
word-break: break-word;
user-select: none;
}
.group-subheader {
font-family: Montserrat, sans-serif;
font-size: 14px;
color: var(--chat-bubble-msg-color);
}
.group-data {
font-family: Roboto, sans-serif;
letter-spacing: 0.3px;
font-weight: 300;
font-size: 14px;
color: var(--chat-bubble-msg-color);
}
.message-myBg {
background-color: var(--chat-bubble-myBg) !important;
margin-bottom: 15px;
border-radius: 5px;
padding: 5px;
}
.message-data-name {
user-select: none;
color: #03a9f4;
margin-bottom: 5px;
}
.message-user-info {
display: flex;
justify-content: space-between;
width: 100%;
gap: 10px;
}
.hideImg {
visibility: hidden;
}
.checkbox-row {
position: relative;
display: flex;
align-items: center;
align-content: center;
font-family: Montserrat, sans-serif;
font-weight: 600;
color: var(--black);
}
`;
}
async getMoreImages(reset) {
try {
console.log({reset})
if(reset){
this.images = []
}
const groupPart = this.isReceipient
? `direct_${this._chatId.slice(-15)}`
: `group_${this._chatId}`;
let offset = reset ? 0 : this.images.length;
let endpoint = `/arbitrary/resources/search?service=QCHAT_IMAGE&identifier=qchat_${groupPart}&reverse=true&limit=20&reverse=true&offset=${offset}`
if(this.onlyMyImages){
endpoint = endpoint + `&name=${this.myName}`
}
const qchatImages = await parentEpml.request('apiCall', {
type: 'api',
url: endpoint,
});
let list = []
if(reset){
list = qchatImages
} else {
list = [...this.images, ...qchatImages]
}
this.images = list
} catch (error) {
console.log(error);
}
}
firstUpdated() {
this.viewElement = this.shadowRoot.getElementById('viewElement');
this.downObserverElement =
this.shadowRoot.getElementById('downObserver');
this.elementObserver();
}
async updated(changedProperties) {
console.log({ changedProperties });
if (changedProperties && changedProperties.has('_chatId')) {
this.images = [];
this.getMoreImages(true);
}
if (changedProperties && changedProperties.has('onlyMyImages')) {
this.getMoreImages(true)
}
}
elementObserver() {
const options = {
root: this.viewElement,
rootMargin: '0px',
threshold: 1,
};
// identify an element to observe
const elementToObserve = this.downObserverElement;
// passing it a callback function
const observer = new IntersectionObserver(
this.observerHandler,
options
);
// call `observe()` on that MutationObserver instance,
// passing it the element to observe, and the options object
observer.observe(elementToObserve);
}
observerHandler(entries) {
if (!entries[0].isIntersecting) {
return;
} else {
console.log('hello', this.images)
if (this.images.length < 20) {
return;
}
this.getMoreImages();
}
}
selectAuto(e) {
if (e.target.checked) {
this.autoView = false
} else {
this.autoView = true
}
}
selectMyImages(e) {
if (e.target.checked) {
this.onlyMyImages = false
} else {
this.onlyMyImages = true
}
}
render() {
console.log('hello resources3', this.images);
return html`
<div class="container">
<div class="close-row" style="margin-top: 15px">
<mwc-icon @click=${()=> {
this.getMoreImages(true)
}} style="color: var(--black); cursor:pointer;">refresh</mwc-icon>
<vaadin-icon class="top-bar-icon" @click=${() =>
this.toggle(
false
)} style="margin: 0px 10px" icon="vaadin:close" slot="icon"></vaadin-icon>
</div>
<div class="checkbox-row">
<label for="authButton" id="authButtonLabel" style="color: var(--black);">
${get('chatpage.cchange69')}
</label>
<mwc-checkbox style="margin-right: -15px;" id="authButton" @click=${(e) => this.selectAuto(e)} ?checked=${this.autoView}></mwc-checkbox>
</div>
<div class="checkbox-row">
<label for="authButton" id="authButtonLabel" style="color: var(--black);">
${get('chatpage.cchange95')}
</label>
<mwc-checkbox style="margin-right: -15px;" id="authButton" @click=${(e) => this.selectMyImages(e)} ?checked=${this.onlyMyImages}></mwc-checkbox>
</div>
<div id="viewElement" class="container-body">
${this.images.map((image) => {
return html`<image-parent .image=${image} ?autoView=${this.autoView}></image-parent>`;
})}
<div id='downObserver'></div>
</div>
</div>
</div>
`;
}
}
customElements.define('chat-right-panel-resources', ChatRightPanelResources);
class ImageParent extends LitElement {
static get properties() {
return {
leaveGroupObj: { type: Object },
error: { type: Boolean },
chatHeads: { type: Array },
groupAdmin: { attribute: false },
groupMembers: { attribute: false },
selectedHead: { type: Object },
toggle: { attribute: false },
getMoreMembers: { attribute: false },
setOpenPrivateMessage: { attribute: false },
userName: { type: String },
walletBalance: { type: Number },
sendMoneyLoading: { type: Boolean },
btnDisable: { type: Boolean },
errorMessage: { type: String },
successMessage: { type: String },
setOpenTipUser: { attribute: false },
setOpenUserInfo: { attribute: false },
setUserName: { attribute: false },
chatId: { type: String },
_chatId: { type: String },
isReceipient: { type: Boolean },
images: { type: Array },
viewImage: { type: Boolean },
image: { type: Object },
autoView: {type: Boolean}
};
}
constructor() {
super();
this.leaveGroupObj = {};
this.leaveFee = 0.001;
this.error = false;
this.chatHeads = [];
this.groupAdmin = [];
this.groupMembers = [];
this.viewElement = '';
this.sendMoneyLoading = false;
this.btnDisable = false;
this.errorMessage = '';
this.successMessage = '';
this.images = [];
this.viewImage = false;
this.myName =
window.parent.reduxStore.getState().app.accountInfo.names[0].name;
}
static get styles() {
return css`
.top-bar-icon {
cursor: pointer;
height: 18px;
width: 18px;
transition: 0.2s all;
}
.top-bar-icon:hover {
color: var(--black);
}
.modal-button {
font-family: Roboto, sans-serif;
font-size: 16px;
color: var(--mdc-theme-primary);
background-color: transparent;
padding: 8px 10px;
border-radius: 5px;
border: none;
transition: all 0.3s ease-in-out;
}
.close-row {
width: 100%;
display: flex;
justify-content: flex-end;
height: 50px;
flex: 0;
gap: 20px;
align-items: center;
}
.container-body {
width: 100%;
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: auto;
margin-top: 5px;
padding: 0px 6px;
box-sizing: border-box;
}
.container-body::-webkit-scrollbar-track {
background-color: whitesmoke;
border-radius: 7px;
}
.container-body::-webkit-scrollbar {
width: 6px;
border-radius: 7px;
background-color: whitesmoke;
}
.container-body::-webkit-scrollbar-thumb {
background-color: rgb(180, 176, 176);
border-radius: 7px;
transition: all 0.3s ease-in-out;
}
.container-body::-webkit-scrollbar-thumb:hover {
background-color: rgb(148, 146, 146);
cursor: pointer;
}
p {
color: var(--black);
margin: 0px;
padding: 0px;
word-break: break-all;
}
.container {
display: flex;
width: 100%;
flex-direction: column;
height: 100%;
}
.chat-right-panel-label {
font-family: Montserrat, sans-serif;
color: var(--group-header);
padding: 5px;
font-size: 13px;
user-select: none;
}
.group-info {
display: flex;
flex-direction: column;
justify-content: flex-start;
gap: 10px;
}
.group-name {
font-family: Raleway, sans-serif;
font-size: 20px;
color: var(--chat-bubble-msg-color);
text-align: center;
user-select: none;
}
.group-description {
font-family: Roboto, sans-serif;
color: var(--chat-bubble-msg-color);
letter-spacing: 0.3px;
font-weight: 300;
font-size: 14px;
margin-top: 15px;
word-break: break-word;
user-select: none;
}
.group-subheader {
font-family: Montserrat, sans-serif;
font-size: 14px;
color: var(--chat-bubble-msg-color);
}
.group-data {
font-family: Roboto, sans-serif;
letter-spacing: 0.3px;
font-weight: 300;
font-size: 14px;
color: var(--chat-bubble-msg-color);
}
.message-myBg {
background-color: var(--chat-bubble-myBg) !important;
margin-bottom: 15px;
border-radius: 5px;
padding: 5px;
}
.message-data-name {
user-select: none;
color: #03a9f4;
margin-bottom: 5px;
}
.message-user-info {
display: flex;
justify-content: space-between;
width: 100%;
gap: 10px;
}
.hideImg {
visibility: hidden;
}
.image-container {
display: flex;
}
`;
}
firstUpdated() {}
async updated(changedProperties) {
if (changedProperties && changedProperties.has('chatId')) {
// const autoSeeChatList =
// window.parent.reduxStore.getState().app.autoLoadImageChats;
// if (autoSeeChatList.includes(this.chatId)) {
// this.viewImage = true;
// }
}
}
render() {
return html`
${!this.autoView && !this.viewImage && this.myName !== this.image.name
? html`
<div class="message-myBg">
<div class="message-user-info">
<span class="message-data-name">
${this.image.name}
</span>
</div>
<div
@click=${() => {
this.viewImage = true;
}}
class=${[`image-container`].join(' ')}
style="height: 200px"
>
<div
style="display:flex;width:100%;height:100%;justify-content:center;align-items:center;cursor:pointer;color:var(--black);"
>
${translate('chatpage.cchange40')}
</div>
</div>
</div>
`
: html``}
${this.autoView || this.viewImage || this.myName === this.image.name
? html`
<div class="message-myBg">
<div class="message-user-info">
<span class="message-data-name">
${this.image.name}
</span>
</div>
<reusable-image
.resource=${{
name: this.image.name,
service: this.image.service,
identifier: this.image.identifier,
}}
></reusable-image>
<
</div>
`
: ''}
`;
}
}
customElements.define('image-parent', ImageParent);

View File

@ -185,44 +185,7 @@ function processText(input) {
return wrapper;
}
const formatMessages = (messages) => {
const formattedMessages = messages.reduce((messageArray, message) => {
const currentMessage = message;
const lastGroupedMessage = messageArray[messageArray.length - 1];
currentMessage.firstMessageInChat = messageArray.length === 0;
let timestamp, sender, repliedToData;
if (lastGroupedMessage) {
timestamp = lastGroupedMessage.timestamp;
sender = lastGroupedMessage.sender;
repliedToData = lastGroupedMessage.repliedToData;
} else {
timestamp = currentMessage.timestamp;
sender = currentMessage.sender;
repliedToData = currentMessage.repliedToData;
}
const isSameGroup =
Math.abs(timestamp - currentMessage.timestamp) < 600000 &&
sender === currentMessage.sender &&
!repliedToData;
if (isSameGroup && lastGroupedMessage) {
lastGroupedMessage.messages.push(currentMessage);
} else {
messageArray.push({
messages: [currentMessage],
...currentMessage,
});
}
return messageArray;
}, []);
return formattedMessages;
};
class ChatScroller extends LitElement {
static get properties() {
@ -510,8 +473,7 @@ class ChatScroller extends LitElement {
!previousMessage ||
!this.shouldGroupWithLastMessage(message, previousMessage)
) {
// If no previous message, or if the current message shouldn't be grouped with the previous,
// push the current group to the front of the formatted messages (since these are older messages)
if (currentMessageGroup) {
this.messagesToRender.unshift(currentMessageGroup);
}
@ -2207,7 +2169,7 @@ class MessageTemplate extends LitElement {
toblockaddress=${this.messageObj.sender}
>
</chat-modals>
<mwc-dialog MessageTemplate
<mwc-dialog
id="showDialogPublicKey"
?open=${this.openDialogImage}
@closed=${() => {
@ -2225,7 +2187,6 @@ class MessageTemplate extends LitElement {
dialogAction="cancel"
class="red"
@click=${() => {
MessageTemplate;
this.openDialogImage = false;
}}
>

View File

@ -0,0 +1,337 @@
import { LitElement, html, css } from 'lit';
import { render } from 'lit/html.js';
import {
use,
get,
translate,
translateUnsafeHTML,
registerTranslateConfig,
} from 'lit-translate';
import axios from 'axios';
import { RequestQueueWithPromise } from '../../utils/queue';
import '@material/mwc-menu';
import '@material/mwc-list/mwc-list-item.js';
import { Epml } from '../../../epml';
import '@material/mwc-dialog'
const requestQueue = new RequestQueueWithPromise(5);
const requestQueue2 = new RequestQueueWithPromise(5);
const parentEpml = new Epml({ type: 'WINDOW', source: window.parent });
export class ResuableImage extends LitElement {
static get properties() {
return {
resource: { type: Object },
isReady: { type: Boolean },
status: { type: Object },
missingData: {type: Boolean},
openDialogImage: { type: Boolean },
};
}
static get styles() {
return css`
* {
--mdc-theme-text-primary-on-background: var(--black);
--mdc-dialog-max-width: 85vw;
--mdc-dialog-max-height: 95vh;
}
img {
width: 100%;
height: auto;
object-fit: contain;
border-radius: 5px;
position: relative;
}
.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: 30px;
position: relative;
text-indent: -9999em;
transform: translateZ(0px);
animation: 1.1s linear 0s infinite normal none running
loadingAnimation;
}
.imageContainer {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}
@-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);
}
}
`;
}
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.missingData = false
this.openDialogImage = false
this.observer = new IntersectionObserver((entries) => {
for (const entry of entries) {
if (entry.isIntersecting && this.status.status !== 'READY') {
this._fetchImage();
// Stop observing after the image has started loading
this.observer.unobserve(this);
}
}
});
}
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;
}
getApiKey() {
const myNode =
window.parent.reduxStore.getState().app.nodeConfig.knownNodes[
window.parent.reduxStore.getState().app.nodeConfig.node
];
let apiKey = myNode.apiKey;
return apiKey;
}
async fetchResource() {
try {
if (this.isFetching) return;
this.isFetching = true;
await requestQueue2.enqueue(() => {
return axios.get(
`${this.nodeUrl}/arbitrary/resource/properties/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?apiKey=${this.myNode.apiKey}`
);
});
this.isFetching = false;
} catch (error) {
this.isFetching = false;
}
}
async fetchVideoUrl() {
this.fetchResource();
this.url = `${this.nodeUrl}/arbitrary/${this.resource.service}/${this.resource.name}/${this.resource.identifier}?async=true&apiKey=${this.myNode.apiKey}`;
}
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}?apiKey=${this.myNode.apiKey}`
);
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}?apiKey=${this.myNode.apiKey}`
);
});
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;
}
if(res?.status === 'MISSING_DATA'){
this.status = res
this.missingData = true
clearInterval(intervalId)
}
}, 5000); // 1 second interval
}
async _fetchImage() {
try {
this.fetchVideoUrl({
name: this.resource.name,
service: this.resource.service,
identifier: this.resource.identifier,
});
this.fetchStatus();
} catch (error) {}
}
firstUpdated() {
this.observer.observe(this);
}
showContextMenu(e) {
e.preventDefault();
e.stopPropagation();
const contextMenu = this.shadowRoot.getElementById('contextMenu');
const containerRect = e.currentTarget.getBoundingClientRect();
// Adjusting the positions
const adjustedX = e.clientX - containerRect.left;
const adjustedY = e.clientY - containerRect.top;
contextMenu.style.top = `${adjustedY}px`;
contextMenu.style.left = `${adjustedX}px`;
contextMenu.open = true;
}
render() {
return html`
<div>
${this.status.status !== 'READY'
? html`
<div
style="display:flex;flex-direction:column;width:100%;height:100%;justify-content:center;align-items:center;"
>
<div class=${`smallLoading`}></div>
<p style="color: var(--black)">
${`${Math.round(
this.status.percentLoaded || 0
).toFixed(0)}% `}${translate(
'chatpage.cchange94'
)}
</p>
</div>
`
: ''}
${this.status.status === 'READY'
? html`
<div style="position:relative; cursor:pointer" @click=${()=> {
this.openDialogImage = true;
}}>
<img crossorigin="anonymous" src=${this.url} />
</div>
`
: ''}
</div>
<mwc-dialog
id="showDialogPublicKey"
?open=${this.openDialogImage}
@closed=${() => {
this.openDialogImage = false;
}}>
<div class="dialog-header"></div>
<div class="dialog-container imageContainer">
${this.openDialogImage ? html`
<img src=${this.url} style="height: auto; max-height: 80vh; width: auto; max-width: 80vw; object-fit: contain; border-radius: 5px;"/>
` : ''}
</div>
<mwc-button
slot="primaryAction"
dialogAction="cancel"
class="red"
@click=${() => {
this.openDialogImage = false;
}}
>
${translate('general.close')}
</mwc-button>
</mwc-dialog>
`;
}
}
customElements.define('reusable-image', ResuableImage);