Allow sending different media types
Added drag&drop in new media popup Fix rendering thumbnail for outgoing document Allow pasting media in current popup
This commit is contained in:
parent
24c1a4af23
commit
bbb754196e
@ -2557,13 +2557,15 @@ export default class ChatBubbles {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return new Promise<PeerId>((resolve, reject) => {
|
return new Promise<PeerId>((resolve, reject) => {
|
||||||
new PopupForward({
|
const popup = new PopupForward({
|
||||||
[this.peerId]: []
|
[this.peerId]: []
|
||||||
}, (peerId) => {
|
}, (peerId) => {
|
||||||
resolve(peerId);
|
resolve(peerId);
|
||||||
}, () => {
|
|
||||||
reject();
|
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
|
popup.addEventListener('close', () => {
|
||||||
|
reject();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import generatePathData from "../../helpers/generatePathData";
|
import generatePathData from "../../helpers/generatePathData";
|
||||||
import { i18n, LangPackKey } from "../../lib/langPack";
|
import { FormatterArguments, i18n, LangPackKey } from "../../lib/langPack";
|
||||||
|
|
||||||
export default class ChatDragAndDrop {
|
export default class ChatDragAndDrop {
|
||||||
container: HTMLDivElement;
|
container: HTMLDivElement;
|
||||||
@ -14,9 +14,10 @@ export default class ChatDragAndDrop {
|
|||||||
path: SVGPathElement;
|
path: SVGPathElement;
|
||||||
|
|
||||||
constructor(appendTo: HTMLElement, private options: {
|
constructor(appendTo: HTMLElement, private options: {
|
||||||
icon: string,
|
icon?: string,
|
||||||
header: LangPackKey,
|
header: LangPackKey,
|
||||||
subtitle: LangPackKey,
|
headerArgs?: FormatterArguments,
|
||||||
|
subtitle?: LangPackKey,
|
||||||
onDrop: (e: DragEvent) => void
|
onDrop: (e: DragEvent) => void
|
||||||
}) {
|
}) {
|
||||||
this.container = document.createElement('div');
|
this.container = document.createElement('div');
|
||||||
@ -31,21 +32,27 @@ export default class ChatDragAndDrop {
|
|||||||
this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
this.path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
|
||||||
this.path.classList.add('drop-outline-path');
|
this.path.classList.add('drop-outline-path');
|
||||||
|
|
||||||
const dropIcon = document.createElement('div');
|
let dropIcon: HTMLElement;
|
||||||
dropIcon.classList.add('drop-icon', 'tgico-' + options.icon);
|
if(options.icon) {
|
||||||
|
dropIcon = document.createElement('div');
|
||||||
|
dropIcon.classList.add('drop-icon', 'tgico-' + options.icon);
|
||||||
|
}
|
||||||
|
|
||||||
const dropHeader = document.createElement('div');
|
const dropHeader = document.createElement('div');
|
||||||
dropHeader.classList.add('drop-header');
|
dropHeader.classList.add('drop-header');
|
||||||
dropHeader.append(i18n(options.header));
|
dropHeader.append(i18n(options.header, options.headerArgs));
|
||||||
|
|
||||||
const dropSubtitle = document.createElement('div');
|
let dropSubtitle: HTMLElement;
|
||||||
dropSubtitle.classList.add('drop-subtitle');
|
if(options.subtitle) {
|
||||||
dropSubtitle.append(i18n(options.subtitle));
|
dropSubtitle = document.createElement('div');
|
||||||
|
dropSubtitle.classList.add('drop-subtitle');
|
||||||
|
dropSubtitle.append(i18n(options.subtitle));
|
||||||
|
}
|
||||||
|
|
||||||
this.svg.append(this.path);
|
this.svg.append(this.path);
|
||||||
this.outlineWrapper.append(this.svg);
|
this.outlineWrapper.append(this.svg);
|
||||||
|
|
||||||
this.container.append(this.outlineWrapper, dropIcon, dropHeader, dropSubtitle);
|
this.container.append(...[this.outlineWrapper, dropIcon, dropHeader, dropSubtitle].filter(Boolean));
|
||||||
appendTo.append(this.container);
|
appendTo.append(this.container);
|
||||||
|
|
||||||
this.container.addEventListener('dragover', this.onDragOver);
|
this.container.addEventListener('dragover', this.onDragOver);
|
||||||
|
@ -1677,9 +1677,11 @@ export default class ChatInput {
|
|||||||
this.clearHelper();
|
this.clearHelper();
|
||||||
this.updateSendBtn();
|
this.updateSendBtn();
|
||||||
let selected = false;
|
let selected = false;
|
||||||
new PopupForward(copy(this.forwarding), () => {
|
const popup = new PopupForward(copy(this.forwarding), () => {
|
||||||
selected = true;
|
selected = true;
|
||||||
}, () => {
|
});
|
||||||
|
|
||||||
|
popup.addEventListener('close', () => {
|
||||||
this.helperWaitingForward = false;
|
this.helperWaitingForward = false;
|
||||||
|
|
||||||
if(!selected) {
|
if(!selected) {
|
||||||
|
@ -104,7 +104,7 @@ class InputField {
|
|||||||
this.required = options.required;
|
this.required = options.required;
|
||||||
this.validate = options.validate;
|
this.validate = options.validate;
|
||||||
|
|
||||||
if(options.maxLength) {
|
if(options.maxLength !== undefined && options.showLengthOn === undefined) {
|
||||||
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
|
options.showLengthOn = Math.min(40, Math.round(options.maxLength / 3));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,12 +81,12 @@ export default class PopupAvatar extends PopupElement {
|
|||||||
|
|
||||||
this.container.append(this.cropContainer, this.btnConfirm, this.input);
|
this.container.append(this.cropContainer, this.btnConfirm, this.input);
|
||||||
|
|
||||||
this.onCloseAfterTimeout = () => {
|
this.addEventListener('closeAfterTimeout', () => {
|
||||||
this.cropper.removeHandlers();
|
this.cropper.removeHandlers();
|
||||||
if(this.image) {
|
if(this.image) {
|
||||||
this.image.remove();
|
this.image.remove();
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolve() {
|
private resolve() {
|
||||||
|
@ -11,7 +11,6 @@ export default class PopupForward extends PopupPickUser {
|
|||||||
constructor(
|
constructor(
|
||||||
peerIdMids: {[fromPeerId: PeerId]: number[]},
|
peerIdMids: {[fromPeerId: PeerId]: number[]},
|
||||||
onSelect?: (peerId: PeerId) => Promise<void> | void,
|
onSelect?: (peerId: PeerId) => Promise<void> | void,
|
||||||
onClose?: () => void,
|
|
||||||
overrideOnSelect = false
|
overrideOnSelect = false
|
||||||
) {
|
) {
|
||||||
super({
|
super({
|
||||||
@ -27,7 +26,6 @@ export default class PopupForward extends PopupPickUser {
|
|||||||
appImManager.setInnerPeer(peerId);
|
appImManager.setInnerPeer(peerId);
|
||||||
appImManager.chat.input.initMessagesForward(peerIdMids);
|
appImManager.chat.input.initMessagesForward(peerIdMids);
|
||||||
},
|
},
|
||||||
onClose,
|
|
||||||
placeholder: 'ShareModal.Search.ForwardPlaceholder',
|
placeholder: 'ShareModal.Search.ForwardPlaceholder',
|
||||||
chatRightsAction: 'send_messages',
|
chatRightsAction: 'send_messages',
|
||||||
selfPresence: 'ChatYourSelf'
|
selfPresence: 'ChatYourSelf'
|
||||||
|
@ -16,6 +16,7 @@ import { attachClickEvent, simulateClickEvent } from "../../helpers/dom/clickEve
|
|||||||
import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
|
import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
|
||||||
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
import { cancelEvent } from "../../helpers/dom/cancelEvent";
|
||||||
import getKeyFromEvent from "../../helpers/dom/getKeyFromEvent";
|
import getKeyFromEvent from "../../helpers/dom/getKeyFromEvent";
|
||||||
|
import EventListenerBase from "../../helpers/eventListenerBase";
|
||||||
|
|
||||||
export type PopupButton = {
|
export type PopupButton = {
|
||||||
text?: string,
|
text?: string,
|
||||||
@ -35,7 +36,10 @@ export type PopupOptions = Partial<{
|
|||||||
confirmShortcutIsSendShortcut: boolean
|
confirmShortcutIsSendShortcut: boolean
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
export default class PopupElement {
|
export default class PopupElement extends EventListenerBase<{
|
||||||
|
close: () => void,
|
||||||
|
closeAfterTimeout: () => void
|
||||||
|
}> {
|
||||||
protected element = document.createElement('div');
|
protected element = document.createElement('div');
|
||||||
protected container = document.createElement('div');
|
protected container = document.createElement('div');
|
||||||
protected header = document.createElement('div');
|
protected header = document.createElement('div');
|
||||||
@ -45,8 +49,6 @@ export default class PopupElement {
|
|||||||
protected body: HTMLElement;
|
protected body: HTMLElement;
|
||||||
protected buttonsEl: HTMLElement;
|
protected buttonsEl: HTMLElement;
|
||||||
|
|
||||||
protected onClose: () => void;
|
|
||||||
protected onCloseAfterTimeout: () => void;
|
|
||||||
protected onEscape: () => boolean = () => true;
|
protected onEscape: () => boolean = () => true;
|
||||||
|
|
||||||
protected navigationItem: NavigationItem;
|
protected navigationItem: NavigationItem;
|
||||||
@ -57,6 +59,8 @@ export default class PopupElement {
|
|||||||
protected btnConfirmOnEnter: HTMLButtonElement;
|
protected btnConfirmOnEnter: HTMLButtonElement;
|
||||||
|
|
||||||
constructor(className: string, protected buttons?: Array<PopupButton>, options: PopupOptions = {}) {
|
constructor(className: string, protected buttons?: Array<PopupButton>, options: PopupOptions = {}) {
|
||||||
|
super(false);
|
||||||
|
|
||||||
this.element.classList.add('popup');
|
this.element.classList.add('popup');
|
||||||
this.element.className = 'popup' + (className ? ' ' + className : '');
|
this.element.className = 'popup' + (className ? ' ' + className : '');
|
||||||
this.container.classList.add('popup-container', 'z-depth-1');
|
this.container.classList.add('popup-container', 'z-depth-1');
|
||||||
@ -181,7 +185,7 @@ export default class PopupElement {
|
|||||||
};
|
};
|
||||||
|
|
||||||
private destroy = () => {
|
private destroy = () => {
|
||||||
this.onClose && this.onClose();
|
this.dispatchEvent('close');
|
||||||
this.element.classList.add('hiding');
|
this.element.classList.add('hiding');
|
||||||
this.element.classList.remove('active');
|
this.element.classList.remove('active');
|
||||||
this.listenerSetter.removeAll();
|
this.listenerSetter.removeAll();
|
||||||
@ -193,7 +197,8 @@ export default class PopupElement {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.element.remove();
|
this.element.remove();
|
||||||
this.onCloseAfterTimeout && this.onCloseAfterTimeout();
|
this.dispatchEvent('closeAfterTimeout');
|
||||||
|
this.cleanup();
|
||||||
animationIntersector.checkAnimations(false);
|
animationIntersector.checkAnimations(false);
|
||||||
}, 150);
|
}, 150);
|
||||||
};
|
};
|
||||||
|
@ -14,7 +14,7 @@ import CheckboxField from "../checkboxField";
|
|||||||
import SendContextMenu from "../chat/sendContextMenu";
|
import SendContextMenu from "../chat/sendContextMenu";
|
||||||
import { createPosterFromMedia, createPosterFromVideo, onMediaLoad } from "../../helpers/files";
|
import { createPosterFromMedia, createPosterFromVideo, onMediaLoad } from "../../helpers/files";
|
||||||
import { MyDocument } from "../../lib/appManagers/appDocsManager";
|
import { MyDocument } from "../../lib/appManagers/appDocsManager";
|
||||||
import I18n, { i18n, LangPackKey } from "../../lib/langPack";
|
import I18n, { FormatterArguments, i18n, LangPackKey } from "../../lib/langPack";
|
||||||
import appDownloadManager from "../../lib/appManagers/appDownloadManager";
|
import appDownloadManager from "../../lib/appManagers/appDownloadManager";
|
||||||
import calcImageInBox from "../../helpers/calcImageInBox";
|
import calcImageInBox from "../../helpers/calcImageInBox";
|
||||||
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
||||||
@ -24,6 +24,7 @@ import { MediaSize } from "../../helpers/mediaSizes";
|
|||||||
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
import { attachClickEvent } from "../../helpers/dom/clickEvent";
|
||||||
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
import MEDIA_MIME_TYPES_SUPPORTED from '../../environment/mediaMimeTypesSupport';
|
||||||
import getGifDuration from "../../helpers/getGifDuration";
|
import getGifDuration from "../../helpers/getGifDuration";
|
||||||
|
import replaceContent from "../../helpers/dom/replaceContent";
|
||||||
|
|
||||||
type SendFileParams = Partial<{
|
type SendFileParams = Partial<{
|
||||||
file: File,
|
file: File,
|
||||||
@ -36,32 +37,39 @@ type SendFileParams = Partial<{
|
|||||||
width: number,
|
width: number,
|
||||||
height: number,
|
height: number,
|
||||||
duration: number,
|
duration: number,
|
||||||
noSound: boolean
|
noSound: boolean,
|
||||||
|
itemDiv: HTMLElement
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
// TODO: .gif upload as video
|
let currentPopup: PopupNewMedia;
|
||||||
|
|
||||||
|
export function getCurrentNewMediaPopup() {
|
||||||
|
return currentPopup;
|
||||||
|
}
|
||||||
|
|
||||||
export default class PopupNewMedia extends PopupElement {
|
export default class PopupNewMedia extends PopupElement {
|
||||||
private input: HTMLElement;
|
private input: HTMLElement;
|
||||||
private mediaContainer: HTMLElement;
|
private mediaContainer: HTMLElement;
|
||||||
private groupCheckboxField: CheckboxField;
|
private groupCheckboxField: CheckboxField;
|
||||||
private wasInputValue = '';
|
private mediaCheckboxField: CheckboxField;
|
||||||
|
private wasInputValue: string;
|
||||||
|
|
||||||
private willAttach: Partial<{
|
private willAttach: Partial<{
|
||||||
type: 'media' | 'document',
|
type: 'media' | 'document',
|
||||||
isMedia: true,
|
isMedia: true,
|
||||||
group: boolean,
|
group: boolean,
|
||||||
sendFileDetails: SendFileParams[]
|
sendFileDetails: SendFileParams[]
|
||||||
}> = {
|
}>;
|
||||||
sendFileDetails: [],
|
|
||||||
group: false
|
|
||||||
};
|
|
||||||
private inputField: InputField;
|
private inputField: InputField;
|
||||||
|
|
||||||
constructor(private chat: Chat, files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {
|
constructor(private chat: Chat, private files: File[], willAttachType: PopupNewMedia['willAttach']['type']) {
|
||||||
super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send', confirmShortcutIsSendShortcut: true});
|
super('popup-send-photo popup-new-media', null, {closable: true, withConfirm: 'Modal.Send', confirmShortcutIsSendShortcut: true, body: true});
|
||||||
|
|
||||||
this.willAttach.type = willAttachType;
|
this.willAttach = {
|
||||||
|
type: willAttachType,
|
||||||
|
sendFileDetails: [],
|
||||||
|
group: false
|
||||||
|
};
|
||||||
|
|
||||||
attachClickEvent(this.btnConfirm, () => this.send(), {listenerSetter: this.listenerSetter});
|
attachClickEvent(this.btnConfirm, () => this.send(), {listenerSetter: this.listenerSetter});
|
||||||
|
|
||||||
@ -95,41 +103,98 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
placeholder: 'PreviewSender.CaptionPlaceholder',
|
placeholder: 'PreviewSender.CaptionPlaceholder',
|
||||||
label: 'Caption',
|
label: 'Caption',
|
||||||
name: 'photo-caption',
|
name: 'photo-caption',
|
||||||
maxLength: rootScope.config.caption_length_max,
|
maxLength: rootScope.config.caption_length_max
|
||||||
showLengthOn: 80
|
|
||||||
});
|
});
|
||||||
this.input = this.inputField.input;
|
this.input = this.inputField.input;
|
||||||
|
|
||||||
this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.input.innerHTML;
|
this.inputField.value = this.wasInputValue = this.chat.input.messageInputField.input.innerHTML;
|
||||||
this.chat.input.messageInputField.value = '';
|
this.chat.input.messageInputField.value = '';
|
||||||
|
|
||||||
this.container.append(scrollable.container);
|
this.body.append(scrollable.container);
|
||||||
|
this.container.append(this.inputField.container);
|
||||||
|
|
||||||
if(files.length > 1) {
|
this.attachFiles();
|
||||||
|
|
||||||
|
this.addEventListener('close', () => {
|
||||||
|
this.files = [];
|
||||||
|
currentPopup = undefined;
|
||||||
|
});
|
||||||
|
|
||||||
|
currentPopup = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public appendDrops(element: HTMLElement) {
|
||||||
|
this.body.append(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
get type() {
|
||||||
|
return this.willAttach.type;
|
||||||
|
}
|
||||||
|
|
||||||
|
set type(type: PopupNewMedia['willAttach']['type']) {
|
||||||
|
this.willAttach.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendGroupCheckboxField() {
|
||||||
|
const good = this.files.length > 1;
|
||||||
|
if(good && !this.groupCheckboxField) {
|
||||||
this.groupCheckboxField = new CheckboxField({
|
this.groupCheckboxField = new CheckboxField({
|
||||||
text: 'PreviewSender.GroupItems',
|
text: 'PreviewSender.GroupItems',
|
||||||
name: 'group-items'
|
name: 'group-items'
|
||||||
});
|
});
|
||||||
this.container.append(this.groupCheckboxField.label, this.inputField.container);
|
this.container.append(...[this.groupCheckboxField.label, this.mediaCheckboxField?.label, this.inputField.container].filter(Boolean));
|
||||||
|
|
||||||
this.groupCheckboxField.input.checked = true;
|
|
||||||
this.willAttach.group = true;
|
this.willAttach.group = true;
|
||||||
|
this.groupCheckboxField.setValueSilently(this.willAttach.group);
|
||||||
|
|
||||||
this.listenerSetter.add(this.groupCheckboxField.input)('change', () => {
|
this.listenerSetter.add(this.groupCheckboxField.input)('change', () => {
|
||||||
const checked = this.groupCheckboxField.input.checked;
|
const checked = this.groupCheckboxField.checked;
|
||||||
|
|
||||||
this.willAttach.group = checked;
|
this.willAttach.group = checked;
|
||||||
this.willAttach.sendFileDetails.length = 0;
|
|
||||||
|
|
||||||
//this.mediaContainer.innerHTML = '';
|
this.attachFiles();
|
||||||
//this.container.classList.remove('is-media', 'is-document', 'is-album');
|
|
||||||
this.attachFiles(files);
|
|
||||||
});
|
});
|
||||||
|
} else if(this.groupCheckboxField) {
|
||||||
|
this.groupCheckboxField.label.classList.toggle('hide', !good);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
this.container.append(this.inputField.container);
|
|
||||||
|
|
||||||
this.attachFiles(files);
|
private appendMediaCheckboxField() {
|
||||||
|
const good = !!this.files.find(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type));
|
||||||
|
if(good && !this.mediaCheckboxField) {
|
||||||
|
this.mediaCheckboxField = new CheckboxField({
|
||||||
|
text: 'PreviewSender.CompressFile',
|
||||||
|
name: 'compress-items'
|
||||||
|
});
|
||||||
|
this.container.append(...[this.groupCheckboxField?.label, this.mediaCheckboxField.label, this.inputField.container].filter(Boolean));
|
||||||
|
|
||||||
|
this.mediaCheckboxField.setValueSilently(this.willAttach.type === 'media');
|
||||||
|
|
||||||
|
this.listenerSetter.add(this.mediaCheckboxField.input)('change', () => {
|
||||||
|
const checked = this.mediaCheckboxField.checked;
|
||||||
|
|
||||||
|
this.willAttach.type = checked ? 'media' : 'document';
|
||||||
|
|
||||||
|
this.attachFiles();
|
||||||
|
});
|
||||||
|
} else if(this.mediaCheckboxField) {
|
||||||
|
this.mediaCheckboxField.label.classList.toggle('hide', !good);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public addFiles(files: File[]) {
|
||||||
|
const toPush = files.filter(file => {
|
||||||
|
const found = this.files.find(_file => {
|
||||||
|
return _file.lastModified === file.lastModified && _file.name === file.name && _file.size === file.size;
|
||||||
|
});
|
||||||
|
|
||||||
|
return !found;
|
||||||
|
});
|
||||||
|
|
||||||
|
if(toPush.length) {
|
||||||
|
this.files.push(...toPush);
|
||||||
|
this.attachFiles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onKeyDown = (e: KeyboardEvent) => {
|
private onKeyDown = (e: KeyboardEvent) => {
|
||||||
@ -144,7 +209,7 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public send(force = false) {
|
private send(force = false) {
|
||||||
if(this.chat.type === 'scheduled' && !force) {
|
if(this.chat.type === 'scheduled' && !force) {
|
||||||
this.chat.input.scheduleSending(() => {
|
this.chat.input.scheduleSending(() => {
|
||||||
this.send(true);
|
this.send(true);
|
||||||
@ -162,324 +227,335 @@ export default class PopupNewMedia extends PopupElement {
|
|||||||
this.hide();
|
this.hide();
|
||||||
const willAttach = this.willAttach;
|
const willAttach = this.willAttach;
|
||||||
willAttach.isMedia = willAttach.type === 'media' ? true : undefined;
|
willAttach.isMedia = willAttach.type === 'media' ? true : undefined;
|
||||||
|
const {sendFileDetails, isMedia} = willAttach;
|
||||||
|
|
||||||
//console.log('will send files with options:', willAttach);
|
//console.log('will send files with options:', willAttach);
|
||||||
|
|
||||||
const peerId = this.chat.peerId;
|
const {peerId, input} = this.chat;
|
||||||
const input = this.chat.input;
|
const {sendSilent, scheduleDate} = input;
|
||||||
const silent = input.sendSilent;
|
|
||||||
const scheduleDate = input.scheduleDate;
|
|
||||||
|
|
||||||
if(willAttach.sendFileDetails.length > 1 && willAttach.group) {
|
sendFileDetails.forEach(d => {
|
||||||
for(let i = 0; i < willAttach.sendFileDetails.length;) {
|
d.itemDiv = undefined;
|
||||||
let firstType = willAttach.sendFileDetails[i].file.type.split('/')[0];
|
});
|
||||||
for(var k = 0; k < 10 && i < willAttach.sendFileDetails.length; ++i, ++k) {
|
|
||||||
const type = willAttach.sendFileDetails[i].file.type.split('/')[0];
|
|
||||||
if(firstType !== type) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const w = {...willAttach};
|
const {length} = sendFileDetails;
|
||||||
w.sendFileDetails = willAttach.sendFileDetails.slice(i - k, i);
|
const replyToMsgId = input.replyToMsgId;
|
||||||
|
this.iterate((sendFileDetails) => {
|
||||||
this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({
|
if(caption && sendFileDetails.length !== length) {
|
||||||
caption,
|
this.chat.appMessagesManager.sendText(peerId, caption, {
|
||||||
replyToMsgId: input.replyToMsgId,
|
replyToMsgId,
|
||||||
threadId: this.chat.threadId,
|
threadId: this.chat.threadId,
|
||||||
isMedia: willAttach.isMedia,
|
silent: sendSilent,
|
||||||
silent,
|
|
||||||
scheduleDate,
|
scheduleDate,
|
||||||
clearDraft: true as true
|
clearDraft: true
|
||||||
}, w));
|
});
|
||||||
|
|
||||||
caption = undefined;
|
caption = undefined;
|
||||||
input.replyToMsgId = this.chat.threadId;
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if(caption) {
|
|
||||||
if(willAttach.sendFileDetails.length > 1) {
|
|
||||||
this.chat.appMessagesManager.sendText(peerId, caption, {
|
|
||||||
replyToMsgId: input.replyToMsgId,
|
|
||||||
threadId: this.chat.threadId,
|
|
||||||
silent,
|
|
||||||
scheduleDate,
|
|
||||||
clearDraft: true
|
|
||||||
});
|
|
||||||
caption = '';
|
|
||||||
//input.replyToMsgId = undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const promises = willAttach.sendFileDetails.map(params => {
|
|
||||||
const promise = this.chat.appMessagesManager.sendFile(peerId, params.file, Object.assign({
|
|
||||||
//isMedia: willAttach.isMedia,
|
|
||||||
isMedia: willAttach.isMedia,
|
|
||||||
caption,
|
|
||||||
replyToMsgId: input.replyToMsgId,
|
|
||||||
threadId: this.chat.threadId,
|
|
||||||
silent,
|
|
||||||
scheduleDate,
|
|
||||||
clearDraft: true as true
|
|
||||||
}, params));
|
|
||||||
|
|
||||||
caption = '';
|
const w = {
|
||||||
return promise;
|
...willAttach,
|
||||||
});
|
sendFileDetails
|
||||||
|
};
|
||||||
|
|
||||||
input.replyToMsgId = this.chat.threadId;
|
this.chat.appMessagesManager.sendAlbum(peerId, w.sendFileDetails.map(d => d.file), Object.assign({
|
||||||
}
|
caption,
|
||||||
|
replyToMsgId,
|
||||||
|
threadId: this.chat.threadId,
|
||||||
|
isMedia: isMedia,
|
||||||
|
silent: sendSilent,
|
||||||
|
scheduleDate,
|
||||||
|
clearDraft: true as true
|
||||||
|
}, w));
|
||||||
|
|
||||||
//Promise.all(promises);
|
caption = undefined;
|
||||||
|
});
|
||||||
//appMessagesManager.sendFile(appImManager.peerId, willAttach.file, willAttach);
|
|
||||||
|
|
||||||
|
input.replyToMsgId = this.chat.threadId;
|
||||||
input.onMessageSent();
|
input.onMessageSent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public attachFile = (file: File) => {
|
private attachMedia(file: File, params: SendFileParams, itemDiv: HTMLElement) {
|
||||||
const willAttach = this.willAttach;
|
itemDiv.classList.add('popup-item-media');
|
||||||
return new Promise<HTMLDivElement>((resolve) => {
|
|
||||||
const params: SendFileParams = {};
|
|
||||||
params.file = file;
|
|
||||||
//console.log('selected file:', file, typeof(file), willAttach);
|
|
||||||
const itemDiv = document.createElement('div');
|
|
||||||
switch(willAttach.type) {
|
|
||||||
case 'media': {
|
|
||||||
const isVideo = file.type.indexOf('video/') === 0;
|
|
||||||
|
|
||||||
itemDiv.classList.add('popup-item-media');
|
const isVideo = file.type.startsWith('video/');
|
||||||
|
|
||||||
if(isVideo) {
|
let promise: Promise<void>;
|
||||||
const video = document.createElement('video');
|
if(isVideo) {
|
||||||
const source = document.createElement('source');
|
const video = document.createElement('video');
|
||||||
source.src = params.objectURL = URL.createObjectURL(file);
|
const source = document.createElement('source');
|
||||||
video.autoplay = true;
|
source.src = params.objectURL = URL.createObjectURL(file);
|
||||||
video.controls = false;
|
video.autoplay = true;
|
||||||
video.muted = true;
|
video.controls = false;
|
||||||
video.setAttribute('playsinline', 'true');
|
video.muted = true;
|
||||||
|
video.setAttribute('playsinline', 'true');
|
||||||
|
|
||||||
video.addEventListener('timeupdate', () => {
|
video.addEventListener('timeupdate', () => {
|
||||||
video.pause();
|
video.pause();
|
||||||
}, {once: true});
|
}, {once: true});
|
||||||
|
|
||||||
onMediaLoad(video).then(() => {
|
promise = onMediaLoad(video).then(() => {
|
||||||
params.width = video.videoWidth;
|
params.width = video.videoWidth;
|
||||||
params.height = video.videoHeight;
|
params.height = video.videoHeight;
|
||||||
params.duration = Math.floor(video.duration);
|
params.duration = Math.floor(video.duration);
|
||||||
|
|
||||||
|
const audioDecodedByteCount = (video as any).webkitAudioDecodedByteCount;
|
||||||
|
if(audioDecodedByteCount !== undefined) {
|
||||||
|
params.noSound = !audioDecodedByteCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemDiv.append(video);
|
||||||
|
return createPosterFromVideo(video).then(thumb => {
|
||||||
|
params.thumb = {
|
||||||
|
url: URL.createObjectURL(thumb.blob),
|
||||||
|
...thumb
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
video.append(source);
|
||||||
|
} else {
|
||||||
|
const img = new Image();
|
||||||
|
promise = new Promise<void>((resolve) => {
|
||||||
|
img.onload = () => {
|
||||||
|
params.width = img.naturalWidth;
|
||||||
|
params.height = img.naturalHeight;
|
||||||
|
|
||||||
|
itemDiv.append(img);
|
||||||
|
|
||||||
|
if(file.type === 'image/gif') {
|
||||||
|
params.noSound = true;
|
||||||
|
|
||||||
|
Promise.all([
|
||||||
|
getGifDuration(img).then(duration => {
|
||||||
|
params.duration = Math.ceil(duration);
|
||||||
|
}),
|
||||||
|
|
||||||
const audioDecodedByteCount = (video as any).webkitAudioDecodedByteCount;
|
createPosterFromMedia(img).then(thumb => {
|
||||||
if(audioDecodedByteCount !== undefined) {
|
|
||||||
params.noSound = !audioDecodedByteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
itemDiv.append(video);
|
|
||||||
createPosterFromVideo(video).then(thumb => {
|
|
||||||
params.thumb = {
|
params.thumb = {
|
||||||
url: URL.createObjectURL(thumb.blob),
|
url: URL.createObjectURL(thumb.blob),
|
||||||
...thumb
|
...thumb
|
||||||
};
|
};
|
||||||
resolve(itemDiv);
|
})
|
||||||
});
|
]).then(() => {
|
||||||
|
resolve();
|
||||||
});
|
});
|
||||||
|
|
||||||
video.append(source);
|
|
||||||
} else {
|
} else {
|
||||||
const img = new Image();
|
resolve();
|
||||||
img.src = params.objectURL = URL.createObjectURL(file);
|
|
||||||
img.onload = () => {
|
|
||||||
params.width = img.naturalWidth;
|
|
||||||
params.height = img.naturalHeight;
|
|
||||||
|
|
||||||
itemDiv.append(img);
|
|
||||||
|
|
||||||
if(file.type === 'image/gif') {
|
|
||||||
params.noSound = true;
|
|
||||||
|
|
||||||
Promise.all([
|
|
||||||
getGifDuration(img).then(duration => {
|
|
||||||
params.duration = Math.ceil(duration);
|
|
||||||
}),
|
|
||||||
|
|
||||||
createPosterFromMedia(img).then(thumb => {
|
|
||||||
params.thumb = {
|
|
||||||
url: URL.createObjectURL(thumb.blob),
|
|
||||||
...thumb
|
|
||||||
};
|
|
||||||
})
|
|
||||||
]).then(() => {
|
|
||||||
resolve(itemDiv);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
resolve(itemDiv);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'document': {
|
|
||||||
const isPhoto = file.type.indexOf('image/') !== -1;
|
|
||||||
const isAudio = file.type.indexOf('audio/') !== -1;
|
|
||||||
if(isPhoto || isAudio) {
|
|
||||||
params.objectURL = URL.createObjectURL(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
const doc = {
|
|
||||||
_: 'document',
|
|
||||||
file: file,
|
|
||||||
file_name: file.name || '',
|
|
||||||
fileName: file.name ? RichTextProcessor.wrapEmojiText(file.name) : '',
|
|
||||||
size: file.size,
|
|
||||||
type: isPhoto ? 'photo' : 'doc'
|
|
||||||
} as MyDocument;
|
|
||||||
|
|
||||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
|
||||||
cacheContext.url = params.objectURL;
|
|
||||||
cacheContext.downloaded = file.size;
|
|
||||||
|
|
||||||
const docDiv = wrapDocument({
|
|
||||||
message: {
|
|
||||||
_: 'message',
|
|
||||||
pFlags: {
|
|
||||||
is_outgoing: true
|
|
||||||
},
|
|
||||||
mid: 0,
|
|
||||||
peerId: 0,
|
|
||||||
media: {
|
|
||||||
_: 'messageMediaDocument',
|
|
||||||
document: doc
|
|
||||||
}
|
|
||||||
} as any
|
|
||||||
});
|
|
||||||
|
|
||||||
const finish = () => {
|
|
||||||
itemDiv.append(docDiv);
|
|
||||||
resolve(itemDiv);
|
|
||||||
};
|
|
||||||
|
|
||||||
if(isPhoto) {
|
|
||||||
const img = new Image();
|
|
||||||
img.src = params.objectURL;
|
|
||||||
img.onload = () => {
|
|
||||||
params.width = img.naturalWidth;
|
|
||||||
params.height = img.naturalHeight;
|
|
||||||
|
|
||||||
finish();
|
|
||||||
};
|
|
||||||
|
|
||||||
img.onerror = finish;
|
|
||||||
} else {
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
willAttach.sendFileDetails.push(params);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
public attachFiles(files: File[]) {
|
|
||||||
const container = this.container;
|
|
||||||
const willAttach = this.willAttach;
|
|
||||||
|
|
||||||
/* if(files.length > 10 && willAttach.type === 'media') {
|
|
||||||
willAttach.type = 'document';
|
|
||||||
} */
|
|
||||||
|
|
||||||
if(willAttach.type === 'media') {
|
|
||||||
files = files.filter(file => MEDIA_MIME_TYPES_SUPPORTED.has(file.type));
|
|
||||||
} else {
|
|
||||||
files = files.slice();
|
|
||||||
}
|
|
||||||
|
|
||||||
Promise.all(files.map(this.attachFile)).then(results => {
|
|
||||||
this.container.classList.remove('is-media', 'is-document', 'is-album');
|
|
||||||
this.mediaContainer.innerHTML = '';
|
|
||||||
|
|
||||||
if(files.length) {
|
|
||||||
let key: LangPackKey;
|
|
||||||
const args: any[] = [];
|
|
||||||
if(willAttach.type === 'document') {
|
|
||||||
key = 'PreviewSender.SendFile';
|
|
||||||
args.push(files.length);
|
|
||||||
container.classList.add('is-document');
|
|
||||||
} else {
|
|
||||||
container.classList.add('is-media');
|
|
||||||
|
|
||||||
let foundPhotos = 0;
|
|
||||||
let foundVideos = 0;
|
|
||||||
files.forEach(file => {
|
|
||||||
if(file.type.indexOf('image/') === 0) ++foundPhotos;
|
|
||||||
else if(file.type.indexOf('video/') === 0) ++foundVideos;
|
|
||||||
});
|
|
||||||
|
|
||||||
const sum = foundPhotos + foundVideos;
|
|
||||||
if(sum > 1 && willAttach.group) {
|
|
||||||
key = 'PreviewSender.SendAlbum';
|
|
||||||
const albumsLength = Math.ceil(sum / 10);
|
|
||||||
args.push(albumsLength);
|
|
||||||
} else if(foundPhotos) {
|
|
||||||
key = 'PreviewSender.SendPhoto';
|
|
||||||
args.push(foundPhotos);
|
|
||||||
} else if(foundVideos) {
|
|
||||||
key = 'PreviewSender.SendVideo';
|
|
||||||
args.push(foundVideos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.title.textContent = '';
|
|
||||||
this.title.append(i18n(key, args));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(willAttach.type === 'media') {
|
|
||||||
if(willAttach.sendFileDetails.length > 1 && willAttach.group) {
|
|
||||||
container.classList.add('is-album');
|
|
||||||
|
|
||||||
for(let i = 0; i < results.length; i += 10) {
|
|
||||||
const albumContainer = document.createElement('div');
|
|
||||||
albumContainer.classList.add('popup-album');
|
|
||||||
|
|
||||||
albumContainer.append(...results.slice(i, i + 10));
|
|
||||||
prepareAlbum({
|
|
||||||
container: albumContainer,
|
|
||||||
items: willAttach.sendFileDetails.slice(i, i + 10).map(o => ({w: o.width, h: o.height})),
|
|
||||||
maxWidth: 380,
|
|
||||||
minWidth: 100,
|
|
||||||
spacing: 4
|
|
||||||
});
|
|
||||||
|
|
||||||
this.mediaContainer.append(albumContainer);
|
|
||||||
}
|
|
||||||
|
|
||||||
//console.log('chatInput album layout:', layout);
|
|
||||||
} else {
|
|
||||||
for(let i = 0; i < results.length; ++i) {
|
|
||||||
const params = willAttach.sendFileDetails[i];
|
|
||||||
const div = results[i];
|
|
||||||
const size = calcImageInBox(params.width, params.height, 380, 320);
|
|
||||||
div.style.width = size.width + 'px';
|
|
||||||
div.style.height = size.height + 'px';
|
|
||||||
this.mediaContainer.append(div);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.mediaContainer.append(...results);
|
|
||||||
}
|
|
||||||
|
|
||||||
// show now
|
|
||||||
if(!this.element.classList.contains('active')) {
|
|
||||||
this.listenerSetter.add(document.body)('keydown', this.onKeyDown);
|
|
||||||
this.onClose = () => {
|
|
||||||
if(this.wasInputValue) {
|
|
||||||
this.chat.input.messageInputField.value = this.wasInputValue;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
this.show();
|
});
|
||||||
|
|
||||||
|
img.src = params.objectURL = URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachDocument(file: File, params: SendFileParams, itemDiv: HTMLElement): ReturnType<PopupNewMedia['attachMedia']> {
|
||||||
|
itemDiv.classList.add('popup-item-document');
|
||||||
|
|
||||||
|
const isPhoto = file.type.startsWith('image/');
|
||||||
|
const isAudio = file.type.startsWith('audio/');
|
||||||
|
if(isPhoto || isAudio) {
|
||||||
|
params.objectURL = URL.createObjectURL(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
const doc = {
|
||||||
|
_: 'document',
|
||||||
|
file: file,
|
||||||
|
file_name: file.name || '',
|
||||||
|
fileName: file.name ? RichTextProcessor.wrapEmojiText(file.name) : '',
|
||||||
|
size: file.size,
|
||||||
|
type: isPhoto ? 'photo' : 'doc'
|
||||||
|
} as MyDocument;
|
||||||
|
|
||||||
|
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||||
|
cacheContext.url = params.objectURL;
|
||||||
|
cacheContext.downloaded = file.size;
|
||||||
|
|
||||||
|
const docDiv = wrapDocument({
|
||||||
|
message: {
|
||||||
|
_: 'message',
|
||||||
|
pFlags: {
|
||||||
|
is_outgoing: true
|
||||||
|
},
|
||||||
|
mid: 0,
|
||||||
|
peerId: 0,
|
||||||
|
media: {
|
||||||
|
_: 'messageMediaDocument',
|
||||||
|
document: doc
|
||||||
|
}
|
||||||
|
} as any
|
||||||
|
});
|
||||||
|
|
||||||
|
const promise = new Promise<void>((resolve) => {
|
||||||
|
const finish = () => {
|
||||||
|
itemDiv.append(docDiv);
|
||||||
|
resolve();
|
||||||
|
};
|
||||||
|
|
||||||
|
if(isPhoto) {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = params.objectURL;
|
||||||
|
img.onload = () => {
|
||||||
|
params.width = img.naturalWidth;
|
||||||
|
params.height = img.naturalHeight;
|
||||||
|
|
||||||
|
finish();
|
||||||
|
};
|
||||||
|
|
||||||
|
img.onerror = finish;
|
||||||
|
} else {
|
||||||
|
finish();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachFile = (file: File) => {
|
||||||
|
const willAttach = this.willAttach;
|
||||||
|
const shouldCompress = this.shouldCompress(file.type);
|
||||||
|
|
||||||
|
const params: SendFileParams = {};
|
||||||
|
params.file = file;
|
||||||
|
|
||||||
|
const itemDiv = document.createElement('div');
|
||||||
|
itemDiv.classList.add('popup-item');
|
||||||
|
|
||||||
|
params.itemDiv = itemDiv;
|
||||||
|
|
||||||
|
const promise = shouldCompress ? this.attachMedia(file, params, itemDiv) : this.attachDocument(file, params, itemDiv);
|
||||||
|
willAttach.sendFileDetails.push(params);
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
private shouldCompress(mimeType: string) {
|
||||||
|
return this.willAttach.type === 'media' && MEDIA_MIME_TYPES_SUPPORTED.has(mimeType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private onRender() {
|
||||||
|
// show now
|
||||||
|
if(!this.element.classList.contains('active')) {
|
||||||
|
this.listenerSetter.add(document.body)('keydown', this.onKeyDown);
|
||||||
|
this.addEventListener('close', () => {
|
||||||
|
if(this.wasInputValue) {
|
||||||
|
this.chat.input.messageInputField.value = this.wasInputValue;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setTitle() {
|
||||||
|
const {willAttach, title, files} = this;
|
||||||
|
let key: LangPackKey;
|
||||||
|
const args: FormatterArguments = [];
|
||||||
|
if(willAttach.type === 'document') {
|
||||||
|
key = 'PreviewSender.SendFile';
|
||||||
|
args.push(files.length);
|
||||||
|
} else {
|
||||||
|
let foundPhotos = 0, foundVideos = 0, foundFiles = 0;
|
||||||
|
files.forEach(file => {
|
||||||
|
if(file.type.startsWith('image/')) ++foundPhotos;
|
||||||
|
else if(file.type.startsWith('video/')) ++foundVideos;
|
||||||
|
else ++foundFiles;
|
||||||
|
});
|
||||||
|
|
||||||
|
if([foundPhotos, foundVideos, foundFiles].filter(n => n > 0).length > 1) {
|
||||||
|
key = 'PreviewSender.SendFile';
|
||||||
|
args.push(files.length);
|
||||||
|
} else
|
||||||
|
|
||||||
|
/* const sum = foundPhotos + foundVideos;
|
||||||
|
if(sum > 1 && willAttach.group) {
|
||||||
|
key = 'PreviewSender.SendAlbum';
|
||||||
|
const albumsLength = Math.ceil(sum / 10);
|
||||||
|
args.push(albumsLength);
|
||||||
|
} else */if(foundPhotos) {
|
||||||
|
key = 'PreviewSender.SendPhoto';
|
||||||
|
args.push(foundPhotos);
|
||||||
|
} else if(foundVideos) {
|
||||||
|
key = 'PreviewSender.SendVideo';
|
||||||
|
args.push(foundVideos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceContent(title, i18n(key, args));
|
||||||
|
}
|
||||||
|
|
||||||
|
private appendMediaToContainer(div: HTMLElement, params: SendFileParams) {
|
||||||
|
if(this.shouldCompress(params.file.type)) {
|
||||||
|
const size = calcImageInBox(params.width, params.height, 380, 320);
|
||||||
|
div.style.width = size.width + 'px';
|
||||||
|
div.style.height = size.height + 'px';
|
||||||
|
}
|
||||||
|
|
||||||
|
this.mediaContainer.append(div);
|
||||||
|
}
|
||||||
|
|
||||||
|
private iterate(cb: (sendFileDetails: SendFileParams[]) => void) {
|
||||||
|
const {sendFileDetails} = this.willAttach;
|
||||||
|
if(!this.willAttach.group) {
|
||||||
|
sendFileDetails.forEach(p => cb([p]));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const length = sendFileDetails.length;
|
||||||
|
for(let i = 0; i < length;) {
|
||||||
|
const firstType = sendFileDetails[i].file.type;
|
||||||
|
let k = 0;
|
||||||
|
for(; k < 10 && i < length; ++i, ++k) {
|
||||||
|
const type = sendFileDetails[i].file.type;
|
||||||
|
if(this.shouldCompress(firstType) !== this.shouldCompress(type)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb(sendFileDetails.slice(i - k, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private attachFiles() {
|
||||||
|
const {files, willAttach, mediaContainer} = this;
|
||||||
|
willAttach.sendFileDetails.length = 0;
|
||||||
|
|
||||||
|
this.appendGroupCheckboxField();
|
||||||
|
this.appendMediaCheckboxField();
|
||||||
|
|
||||||
|
Promise.all(files.map(this.attachFile)).then(() => {
|
||||||
|
mediaContainer.innerHTML = '';
|
||||||
|
|
||||||
|
if(!files.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setTitle();
|
||||||
|
|
||||||
|
this.iterate((sendFileDetails) => {
|
||||||
|
if(this.shouldCompress(sendFileDetails[0].file.type) && sendFileDetails.length > 1) {
|
||||||
|
const albumContainer = document.createElement('div');
|
||||||
|
albumContainer.classList.add('popup-item-album', 'popup-item');
|
||||||
|
albumContainer.append(...sendFileDetails.map(s => s.itemDiv));
|
||||||
|
|
||||||
|
prepareAlbum({
|
||||||
|
container: albumContainer,
|
||||||
|
items: sendFileDetails.map(o => ({w: o.width, h: o.height})),
|
||||||
|
maxWidth: 380,
|
||||||
|
minWidth: 100,
|
||||||
|
spacing: 4
|
||||||
|
});
|
||||||
|
|
||||||
|
mediaContainer.append(albumContainer);
|
||||||
|
} else {
|
||||||
|
sendFileDetails.forEach((params) => {
|
||||||
|
this.appendMediaToContainer(params.itemDiv, params);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).then(() => {
|
||||||
|
this.onRender();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,6 @@ export default class PopupPickUser extends PopupElement {
|
|||||||
constructor(options: {
|
constructor(options: {
|
||||||
peerTypes: AppSelectPeers['peerType'],
|
peerTypes: AppSelectPeers['peerType'],
|
||||||
onSelect?: (peerId: PeerId) => Promise<void> | void,
|
onSelect?: (peerId: PeerId) => Promise<void> | void,
|
||||||
onClose?: () => void,
|
|
||||||
placeholder: LangPackKey,
|
placeholder: LangPackKey,
|
||||||
chatRightsAction?: AppSelectPeers['chatRightsAction'],
|
chatRightsAction?: AppSelectPeers['chatRightsAction'],
|
||||||
peerId?: number,
|
peerId?: number,
|
||||||
@ -23,8 +22,6 @@ export default class PopupPickUser extends PopupElement {
|
|||||||
}) {
|
}) {
|
||||||
super('popup-forward', null, {closable: true, overlayClosable: true, body: true});
|
super('popup-forward', null, {closable: true, overlayClosable: true, body: true});
|
||||||
|
|
||||||
if(options.onClose) this.onClose = options.onClose;
|
|
||||||
|
|
||||||
this.selector = new AppSelectPeers({
|
this.selector = new AppSelectPeers({
|
||||||
appendTo: this.body,
|
appendTo: this.body,
|
||||||
onChange: async() => {
|
onChange: async() => {
|
||||||
|
@ -38,9 +38,9 @@ export default class PopupStickers extends PopupElement {
|
|||||||
|
|
||||||
this.header.append(this.h6);
|
this.header.append(this.h6);
|
||||||
|
|
||||||
this.onClose = () => {
|
this.addEventListener('close', () => {
|
||||||
animationIntersector.setOnlyOnePlayableGroup('');
|
animationIntersector.setOnlyOnePlayableGroup('');
|
||||||
};
|
});
|
||||||
|
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.classList.add('sticker-set');
|
div.classList.add('sticker-set');
|
||||||
|
@ -586,7 +586,7 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
docDiv.classList.add('document-with-thumb');
|
docDiv.classList.add('document-with-thumb');
|
||||||
|
|
||||||
let imgs: HTMLImageElement[] = [];
|
let imgs: HTMLImageElement[] = [];
|
||||||
if(uploading) {
|
if(message.pFlags.is_outgoing) {
|
||||||
icoDiv.innerHTML = `<img src="${cacheContext.url}">`;
|
icoDiv.innerHTML = `<img src="${cacheContext.url}">`;
|
||||||
imgs.push(icoDiv.firstElementChild as HTMLImageElement);
|
imgs.push(icoDiv.firstElementChild as HTMLImageElement);
|
||||||
} else {
|
} else {
|
||||||
@ -647,9 +647,9 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
|
|
||||||
docDiv.prepend(icoDiv);
|
docDiv.prepend(icoDiv);
|
||||||
|
|
||||||
/* if(!uploading && message.pFlags.is_outgoing) {
|
if(!uploading && message.pFlags.is_outgoing) {
|
||||||
return docDiv;
|
return docDiv;
|
||||||
} */
|
}
|
||||||
|
|
||||||
let downloadDiv: HTMLElement, preloader: ProgressivePreloader = null;
|
let downloadDiv: HTMLElement, preloader: ProgressivePreloader = null;
|
||||||
const onLoad = () => {
|
const onLoad = () => {
|
||||||
@ -700,7 +700,7 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
|
|||||||
downloadDiv = docDiv.querySelector('.document-download');
|
downloadDiv = docDiv.querySelector('.document-download');
|
||||||
preloader = new ProgressivePreloader();
|
preloader = new ProgressivePreloader();
|
||||||
preloader.attach(downloadDiv, false, appDocsManager.downloading.get(doc.id));
|
preloader.attach(downloadDiv, false, appDocsManager.downloading.get(doc.id));
|
||||||
} else if(!(cacheContext.downloaded && !uploading)) {
|
} else if(!cacheContext.downloaded || uploading) {
|
||||||
downloadDiv = docDiv.querySelector('.document-download');
|
downloadDiv = docDiv.querySelector('.document-download');
|
||||||
preloader = message.media.preloader as ProgressivePreloader;
|
preloader = message.media.preloader as ProgressivePreloader;
|
||||||
|
|
||||||
|
@ -791,7 +791,12 @@ const lang = {
|
|||||||
"other_value": "Show More (%d)"
|
"other_value": "Show More (%d)"
|
||||||
},
|
},
|
||||||
//"PeerInfo.Confirm.DeleteGroupConfirmation": "Wait! Deleting this group will remove all members and all messages will be lost. Delete the group anyway?",
|
//"PeerInfo.Confirm.DeleteGroupConfirmation": "Wait! Deleting this group will remove all members and all messages will be lost. Delete the group anyway?",
|
||||||
|
"Preview.Dragging.AddItems": {
|
||||||
|
"one_value": "Add Item",
|
||||||
|
"other_value": "Add Items"
|
||||||
|
},
|
||||||
"PreviewSender.CaptionPlaceholder": "Add a caption...",
|
"PreviewSender.CaptionPlaceholder": "Add a caption...",
|
||||||
|
"PreviewSender.CompressFile": "Send compressed",
|
||||||
"PreviewSender.SendFile": {
|
"PreviewSender.SendFile": {
|
||||||
"one_value": "Send File",
|
"one_value": "Send File",
|
||||||
"other_value": "Send %d Files"
|
"other_value": "Send %d Files"
|
||||||
|
@ -24,7 +24,7 @@ import appPhotosManager from './appPhotosManager';
|
|||||||
import appProfileManager from './appProfileManager';
|
import appProfileManager from './appProfileManager';
|
||||||
import appStickersManager from './appStickersManager';
|
import appStickersManager from './appStickersManager';
|
||||||
import appWebPagesManager from './appWebPagesManager';
|
import appWebPagesManager from './appWebPagesManager';
|
||||||
import PopupNewMedia from '../../components/popups/newMedia';
|
import PopupNewMedia, { getCurrentNewMediaPopup } from '../../components/popups/newMedia';
|
||||||
import MarkupTooltip from '../../components/chat/markupTooltip';
|
import MarkupTooltip from '../../components/chat/markupTooltip';
|
||||||
import { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport';
|
import { IS_TOUCH_SUPPORTED } from '../../environment/touchSupport';
|
||||||
import appPollsManager from './appPollsManager';
|
import appPollsManager from './appPollsManager';
|
||||||
@ -901,6 +901,7 @@ export class AppImManager {
|
|||||||
|
|
||||||
private attachDragAndDropListeners() {
|
private attachDragAndDropListeners() {
|
||||||
const drops: ChatDragAndDrop[] = [];
|
const drops: ChatDragAndDrop[] = [];
|
||||||
|
const mediaDrops: ChatDragAndDrop[] = [];
|
||||||
let mounted = false;
|
let mounted = false;
|
||||||
const toggle = async(e: DragEvent, mount: boolean) => {
|
const toggle = async(e: DragEvent, mount: boolean) => {
|
||||||
if(mount === mounted) return;
|
if(mount === mounted) return;
|
||||||
@ -909,63 +910,84 @@ export class AppImManager {
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;
|
const isFiles = _types.contains ? _types.contains('Files') : _types.indexOf('Files') >= 0;
|
||||||
|
|
||||||
if(!isFiles || !this.canDrag()) { // * skip dragging text case
|
const newMediaPopup = getCurrentNewMediaPopup();
|
||||||
|
if(!isFiles || (!this.canDrag() && !newMediaPopup)) { // * skip dragging text case
|
||||||
counter = 0;
|
counter = 0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mount && !drops.length) {
|
const _dropsContainer = newMediaPopup ? mediaDropsContainer : dropsContainer;
|
||||||
|
const _drops = newMediaPopup ? mediaDrops : drops;
|
||||||
|
|
||||||
|
if(mount && !_drops.length) {
|
||||||
const types: string[] = await getFilesFromEvent(e, true);
|
const types: string[] = await getFilesFromEvent(e, true);
|
||||||
const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari
|
const force = isFiles && !types.length; // * can't get file items not from 'drop' on Safari
|
||||||
|
|
||||||
const foundMedia = types.filter(t => MEDIA_MIME_TYPES_SUPPORTED.has(t)).length;
|
const foundMedia = types.filter(t => MEDIA_MIME_TYPES_SUPPORTED.has(t)).length;
|
||||||
const foundDocuments = types.length - foundMedia;
|
// const foundDocuments = types.length - foundMedia;
|
||||||
|
|
||||||
this.log('drag files', types);
|
this.log('drag files', types);
|
||||||
|
|
||||||
if(types.length || force) {
|
if(newMediaPopup) {
|
||||||
drops.push(new ChatDragAndDrop(dropsContainer, {
|
newMediaPopup.appendDrops(_dropsContainer);
|
||||||
icon: 'dragfiles',
|
|
||||||
header: 'Chat.DropTitle',
|
if(types.length || force) {
|
||||||
subtitle: 'Chat.DropAsFilesDesc',
|
_drops.push(new ChatDragAndDrop(_dropsContainer, {
|
||||||
onDrop: (e: DragEvent) => {
|
header: 'Preview.Dragging.AddItems',
|
||||||
toggle(e, false);
|
headerArgs: [types.length],
|
||||||
appImManager.log('drop', e);
|
onDrop: (e: DragEvent) => {
|
||||||
appImManager.onDocumentPaste(e, 'document');
|
toggle(e, false);
|
||||||
}
|
appImManager.log('drop', e);
|
||||||
}));
|
appImManager.onDocumentPaste(e, 'document');
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(types.length || force) {
|
||||||
|
_drops.push(new ChatDragAndDrop(_dropsContainer, {
|
||||||
|
icon: 'dragfiles',
|
||||||
|
header: 'Chat.DropTitle',
|
||||||
|
subtitle: 'Chat.DropAsFilesDesc',
|
||||||
|
onDrop: (e: DragEvent) => {
|
||||||
|
toggle(e, false);
|
||||||
|
appImManager.log('drop', e);
|
||||||
|
appImManager.onDocumentPaste(e, 'document');
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if((foundMedia && !foundDocuments) || force) {
|
||||||
|
if(foundMedia || force) {
|
||||||
|
_drops.push(new ChatDragAndDrop(_dropsContainer, {
|
||||||
|
icon: 'dragmedia',
|
||||||
|
header: 'Chat.DropTitle',
|
||||||
|
subtitle: 'Chat.DropQuickDesc',
|
||||||
|
onDrop: (e: DragEvent) => {
|
||||||
|
toggle(e, false);
|
||||||
|
appImManager.log('drop', e);
|
||||||
|
appImManager.onDocumentPaste(e, 'media');
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
this.chat.container.append(_dropsContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
if((foundMedia && !foundDocuments) || force) {
|
|
||||||
drops.push(new ChatDragAndDrop(dropsContainer, {
|
|
||||||
icon: 'dragmedia',
|
|
||||||
header: 'Chat.DropTitle',
|
|
||||||
subtitle: 'Chat.DropQuickDesc',
|
|
||||||
onDrop: (e: DragEvent) => {
|
|
||||||
toggle(e, false);
|
|
||||||
appImManager.log('drop', e);
|
|
||||||
appImManager.onDocumentPaste(e, 'media');
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
this.chat.container.append(dropsContainer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//if(!mount) return;
|
//if(!mount) return;
|
||||||
|
|
||||||
SetTransition(dropsContainer, 'is-visible', mount, 200, () => {
|
SetTransition(_dropsContainer, 'is-visible', mount, 200, () => {
|
||||||
if(!mount) {
|
if(!mount) {
|
||||||
drops.forEach(drop => {
|
_drops.forEach(drop => {
|
||||||
drop.destroy();
|
drop.destroy();
|
||||||
});
|
});
|
||||||
|
|
||||||
drops.length = 0;
|
_drops.length = 0;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if(mount) {
|
if(mount) {
|
||||||
drops.forEach(drop => {
|
_drops.forEach(drop => {
|
||||||
drop.setPath();
|
drop.setPath();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -1003,6 +1025,8 @@ export class AppImManager {
|
|||||||
|
|
||||||
const dropsContainer = document.createElement('div');
|
const dropsContainer = document.createElement('div');
|
||||||
dropsContainer.classList.add('drops-container');
|
dropsContainer.classList.add('drops-container');
|
||||||
|
|
||||||
|
const mediaDropsContainer = dropsContainer.cloneNode(true) as HTMLElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
private canDrag() {
|
private canDrag() {
|
||||||
@ -1011,7 +1035,8 @@ export class AppImManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {
|
private onDocumentPaste = (e: ClipboardEvent | DragEvent, attachType?: 'media' | 'document') => {
|
||||||
if(!this.canDrag()) return;
|
const newMediaPopup = getCurrentNewMediaPopup();
|
||||||
|
if(!this.canDrag() && !newMediaPopup) return;
|
||||||
|
|
||||||
//console.log('document paste');
|
//console.log('document paste');
|
||||||
//console.log('item', event.clipboardData.getData());
|
//console.log('item', event.clipboardData.getData());
|
||||||
@ -1027,12 +1052,13 @@ export class AppImManager {
|
|||||||
|
|
||||||
getFilesFromEvent(e).then((files: File[]) => {
|
getFilesFromEvent(e).then((files: File[]) => {
|
||||||
if(files.length) {
|
if(files.length) {
|
||||||
if(/* attachType === 'media' && */files.find(file => !MEDIA_MIME_TYPES_SUPPORTED.has(file.type))) {
|
if(newMediaPopup) {
|
||||||
attachType = 'document';
|
newMediaPopup.addFiles(files);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const chatInput = this.chat.input;
|
const chatInput = this.chat.input;
|
||||||
chatInput.willAttachType = attachType || (MEDIA_MIME_TYPES_SUPPORTED.has(files[0].type) ? 'media' : "document");
|
chatInput.willAttachType = attachType || (MEDIA_MIME_TYPES_SUPPORTED.has(files[0].type) ? 'media' : 'document');
|
||||||
new PopupNewMedia(this.chat, files, chatInput.willAttachType);
|
new PopupNewMedia(this.chat, files, chatInput.willAttachType);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -166,7 +166,7 @@ export class AppMessagesManager {
|
|||||||
}
|
}
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
private sendSmthLazyLoadQueue = new LazyLoadQueueBase(1);
|
private sendSmthLazyLoadQueue = new LazyLoadQueueBase(10);
|
||||||
|
|
||||||
private needSingleMessages: Map<PeerId, Map<number, CancellablePromise<Message>>> = new Map();
|
private needSingleMessages: Map<PeerId, Map<number, CancellablePromise<Message>>> = new Map();
|
||||||
private fetchSingleMessagesPromise: Promise<void> = null;
|
private fetchSingleMessagesPromise: Promise<void> = null;
|
||||||
@ -1115,7 +1115,7 @@ export class AppMessagesManager {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const inputPeer = appPeersManager.getInputPeerById(peerId);
|
const inputPeer = appPeersManager.getInputPeerById(peerId);
|
||||||
const invoke = (multiMedia: any[]) => {
|
const invoke = (multiMedia: InputSingleMedia[]) => {
|
||||||
this.setTyping(peerId, {_: 'sendMessageCancelAction'});
|
this.setTyping(peerId, {_: 'sendMessageCancelAction'});
|
||||||
|
|
||||||
this.sendSmthLazyLoadQueue.push({
|
this.sendSmthLazyLoadQueue.push({
|
||||||
@ -1136,15 +1136,15 @@ export class AppMessagesManager {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const promises: Promise<InputSingleMedia>[] = messages.map((message, idx) => {
|
const promises: Promise<InputSingleMedia>[] = messages.map((message) => {
|
||||||
return (message.send() as Promise<InputMedia>).then((inputMedia: InputMedia) => {
|
return (message.send() as Promise<InputMedia>).then((inputMedia) => {
|
||||||
return apiManager.invokeApi('messages.uploadMedia', {
|
return apiManager.invokeApi('messages.uploadMedia', {
|
||||||
peer: inputPeer,
|
peer: inputPeer,
|
||||||
media: inputMedia
|
media: inputMedia
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.then(messageMedia => {
|
.then(messageMedia => {
|
||||||
let inputMedia: any;
|
let inputMedia: InputMedia;
|
||||||
if(messageMedia._ === 'messageMediaPhoto') {
|
if(messageMedia._ === 'messageMediaPhoto') {
|
||||||
const photo = appPhotosManager.savePhoto(messageMedia.photo);
|
const photo = appPhotosManager.savePhoto(messageMedia.photo);
|
||||||
inputMedia = appPhotosManager.getMediaInput(photo);
|
inputMedia = appPhotosManager.getMediaInput(photo);
|
||||||
|
@ -663,6 +663,30 @@ $chat-helper-size: 36px;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drops-container {
|
||||||
|
--padding: 20px;
|
||||||
|
--pinned-floating-height: 0px;
|
||||||
|
top: calc(56px + var(--pinned-floating-height) + var(--padding));
|
||||||
|
|
||||||
|
@include respond-to(medium-screens) {
|
||||||
|
//transition: transform var(--layer-transition);
|
||||||
|
|
||||||
|
body.is-right-column-shown & {
|
||||||
|
//left: calc(var(--right-column-width) / -2);
|
||||||
|
right: calc(var(--right-column-width));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@include respond-to(handhelds) {
|
||||||
|
--padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.drop {
|
||||||
|
max-width: 696px;
|
||||||
|
--wrapper-padding: 15px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-input-wrapper {
|
.chat-input-wrapper {
|
||||||
|
@ -1039,17 +1039,13 @@ $bubble-beside-button-width: 38px;
|
|||||||
&-content {
|
&-content {
|
||||||
//max-width: 300px;
|
//max-width: 300px;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
max-width: calc(100% - 1.875rem);
|
max-width: calc(100% - 1.25rem);
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.is-media .reply-content {
|
|
||||||
max-width: calc(100% - 1.5rem);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// &:not(.just-media):not(.is-message-empty) .reply {
|
// &:not(.just-media):not(.is-message-empty) .reply {
|
||||||
@ -1068,7 +1064,7 @@ $bubble-beside-button-width: 38px;
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
background-color: var(--message-highlightning-color);
|
background-color: var(--message-highlightning-color);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
max-width: 300px;
|
max-width: 15rem;
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
@include respond-to(handhelds) {
|
||||||
max-width: calc(100vw - #{$chat-padding-handhelds * 2} - 10px - 100%);
|
max-width: calc(100vw - #{$chat-padding-handhelds * 2} - 10px - 100%);
|
||||||
@ -1096,6 +1092,8 @@ $bubble-beside-button-width: 38px;
|
|||||||
|
|
||||||
&-content {
|
&-content {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
position: relative;
|
||||||
|
max-width: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-title,
|
&-title,
|
||||||
@ -1620,7 +1618,6 @@ $bubble-beside-button-width: 38px;
|
|||||||
color: white;
|
color: white;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
height: 1.125rem;
|
height: 1.125rem;
|
||||||
|
|
||||||
@ -1648,7 +1645,6 @@ $bubble-beside-button-width: 38px;
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 2.125rem;
|
font-size: 2.125rem;
|
||||||
cursor: pointer;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@ -5,11 +5,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.drops-container {
|
.drops-container {
|
||||||
--padding: 20px;
|
--padding: 0px;
|
||||||
--pinned-floating-height: 0px;
|
|
||||||
position: absolute !important;
|
position: absolute !important;
|
||||||
z-index: 3;
|
z-index: 3;
|
||||||
top: calc(56px + var(--pinned-floating-height) + var(--padding));
|
top: var(--padding);
|
||||||
right: var(--padding);
|
right: var(--padding);
|
||||||
bottom: var(--padding);
|
bottom: var(--padding);
|
||||||
left: var(--padding);
|
left: var(--padding);
|
||||||
@ -20,19 +19,6 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
width: auto !important;
|
width: auto !important;
|
||||||
|
|
||||||
@include respond-to(medium-screens) {
|
|
||||||
//transition: transform var(--layer-transition);
|
|
||||||
|
|
||||||
body.is-right-column-shown & {
|
|
||||||
//left: calc(var(--right-column-width) / -2);
|
|
||||||
right: calc(var(--right-column-width));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@include respond-to(handhelds) {
|
|
||||||
--padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.is-visible) {
|
&:not(.is-visible) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
@ -47,12 +33,13 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.drop {
|
.drop {
|
||||||
|
--wrapper-padding: -4px;
|
||||||
background-color: var(--surface-color);
|
background-color: var(--surface-color);
|
||||||
position: relative;
|
position: relative;
|
||||||
//height: 100%;
|
//height: 100%;
|
||||||
border-radius: $border-radius-big;
|
border-radius: $border-radius-big;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 696px;
|
max-width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -65,10 +52,10 @@
|
|||||||
&-outline {
|
&-outline {
|
||||||
&-wrapper {
|
&-wrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 15px;
|
top: var(--wrapper-padding);
|
||||||
right: 15px;
|
right: var(--wrapper-padding);
|
||||||
bottom: 15px;
|
bottom: var(--wrapper-padding);
|
||||||
left: 15px;
|
left: var(--wrapper-padding);
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +88,10 @@
|
|||||||
&-header {
|
&-header {
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
margin-top: -10px;
|
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-top: -10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-height: 670px) {
|
@media only screen and (max-height: 670px) {
|
||||||
|
@ -16,43 +16,8 @@
|
|||||||
//max-height: unquote('min(640px, 100%)');
|
//max-height: unquote('min(640px, 100%)');
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
|
||||||
&.is-media:not(.is-album) {
|
img,
|
||||||
/* max-height: 425px; */
|
video {
|
||||||
|
|
||||||
#{$parent}-photo {
|
|
||||||
//max-height: 320px;
|
|
||||||
margin: 0 auto;
|
|
||||||
|
|
||||||
img {
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
> div {
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 0 auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-album {
|
|
||||||
#{$parent}-photo {
|
|
||||||
margin: 0 auto;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
.album-item {
|
|
||||||
position: absolute;
|
|
||||||
}
|
|
||||||
|
|
||||||
img, video {
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img, video {
|
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,45 +59,12 @@
|
|||||||
|
|
||||||
&-photo {
|
&-photo {
|
||||||
max-width: 380px;
|
max-width: 380px;
|
||||||
//display: flex;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
//justify-content: center;
|
// width: fit-content;
|
||||||
width: fit-content;
|
width: 100%;
|
||||||
border-radius: $border-radius-medium;
|
border-radius: $border-radius-medium;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
/* align-items: center; */
|
position: relative;
|
||||||
|
|
||||||
.document {
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
cursor: default;
|
|
||||||
padding-left: 3.75rem;
|
|
||||||
height: 4.5rem;
|
|
||||||
|
|
||||||
&-name {
|
|
||||||
font-weight: normal;
|
|
||||||
width: 100%;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
line-height: 1.5;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-ico {
|
|
||||||
height: 48px;
|
|
||||||
width: 48px;
|
|
||||||
font-size: 16px;
|
|
||||||
font-weight: normal;
|
|
||||||
line-height: 11px;
|
|
||||||
letter-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* &.photo {
|
|
||||||
.document-ico {
|
|
||||||
border-radius: $border-radius;
|
|
||||||
}
|
|
||||||
} */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,22 +107,85 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.popup-body {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
.checkbox-field {
|
.checkbox-field {
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-album,
|
.popup-item-album {
|
||||||
.popup-container:not(.is-album) .popup-item-media {
|
position: relative;
|
||||||
|
|
||||||
|
.album-item {
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
object-fit: cover;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-photo > .popup-item-media {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
|
img {
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.popup-photo > .popup-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-radius: inherit;
|
border-radius: inherit;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-album + .popup-album,
|
.popup-photo > .popup-item + .popup-item {
|
||||||
.popup-container:not(.is-album) .popup-item-media + .popup-item-media {
|
|
||||||
margin-top: .5rem;
|
margin-top: .5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drop {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.document {
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
cursor: default;
|
||||||
|
padding-left: 3.75rem;
|
||||||
|
height: 4.5rem;
|
||||||
|
|
||||||
|
&-name {
|
||||||
|
font-weight: normal;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-ico {
|
||||||
|
height: 48px;
|
||||||
|
width: 48px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: normal;
|
||||||
|
line-height: 11px;
|
||||||
|
letter-spacing: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* &.photo {
|
||||||
|
.document-ico {
|
||||||
|
border-radius: $border-radius;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.popup-create-contact {
|
.popup-create-contact {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user