Browse Source

Documents improve

Set uploaded source to new message media
master
Eduard Kuzmenko 4 years ago
parent
commit
730bd1168d
  1. 14
      src/components/chat/bubbles.ts
  2. 12
      src/components/popups/newMedia.ts
  3. 3
      src/components/preloader.ts
  4. 75
      src/components/wrappers.ts
  5. 4
      src/helpers/cancellablePromise.ts
  6. 2
      src/helpers/number.ts
  7. 22
      src/lib/appManagers/appDocsManager.ts
  8. 15
      src/lib/appManagers/appDownloadManager.ts
  9. 28
      src/lib/appManagers/appMessagesManager.ts
  10. 98
      src/scss/partials/_document.scss
  11. 8
      src/scss/partials/popups/_mediaAttacher.scss

14
src/components/chat/bubbles.ts

@ -215,12 +215,14 @@ export default class ChatBubbles { @@ -215,12 +215,14 @@ export default class ChatBubbles {
}
if(message.media?.document) {
if(['audio', 'voice'].includes(message.media.document.type)) {
const audio = bubble.querySelector(`audio-element[message-id="${tempId}"]`) as AudioElement;
audio.setAttribute('doc-id', message.media.document.id);
audio.setAttribute('message-id', '' + mid);
audio.message = message;
audio.onLoad(true);
const element = bubble.querySelector(`audio-element[message-id="${tempId}"], .document[data-doc-id="${tempId}"]`) as HTMLElement;
if(element instanceof AudioElement) {
element.setAttribute('doc-id', message.media.document.id);
element.setAttribute('message-id', '' + mid);
element.message = message;
element.onLoad(true);
} else {
element.dataset.docId = message.media.document.id;
}
}

12
src/components/popups/newMedia.ts

@ -8,7 +8,8 @@ import { toast } from "../toast"; @@ -8,7 +8,8 @@ import { toast } from "../toast";
import { prepareAlbum, wrapDocument } from "../wrappers";
import CheckboxField from "../checkbox";
import SendContextMenu from "../chat/sendContextMenu";
import { createPosterForVideo, createPosterFromVideo } from "../../helpers/files";
import { createPosterForVideo, createPosterFromVideo, onVideoLoad } from "../../helpers/files";
import { MyDocument } from "../../lib/appManagers/appDocsManager";
type SendFileParams = Partial<{
file: File,
@ -241,7 +242,7 @@ export default class PopupNewMedia extends PopupElement { @@ -241,7 +242,7 @@ export default class PopupNewMedia extends PopupElement {
video.muted = true;
video.setAttribute('playsinline', 'true');
video.onloadeddata = () => {
onVideoLoad(video).then(() => {
params.width = video.videoWidth;
params.height = video.videoHeight;
params.duration = Math.floor(video.duration);
@ -252,7 +253,7 @@ export default class PopupNewMedia extends PopupElement { @@ -252,7 +253,7 @@ export default class PopupNewMedia extends PopupElement {
params.thumbURL = URL.createObjectURL(blob);
resolve(itemDiv);
});
};
});
video.append(source);
} else {
@ -293,8 +294,9 @@ export default class PopupNewMedia extends PopupElement { @@ -293,8 +294,9 @@ export default class PopupNewMedia extends PopupElement {
file_name: file.name || '',
size: file.size,
type: isPhoto ? 'photo' : 'doc',
url: params.objectURL
}
url: params.objectURL,
downloaded: true
} as MyDocument
}
} as any
});

3
src/components/preloader.ts

@ -14,8 +14,7 @@ export default class ProgressivePreloader { @@ -14,8 +14,7 @@ export default class ProgressivePreloader {
private tempId = 0;
private detached = true;
private promise: CancellablePromise<any> = null;
public onCancel: () => any = null;
public promise: CancellablePromise<any> = null;
public isUpload = false;
private cancelable = true;

75
src/components/wrappers.ts

@ -385,8 +385,6 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS @@ -385,8 +385,6 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
}): HTMLElement {
if(!fontWeight) fontWeight = 500;
const uploading = message.pFlags.is_outgoing;
const doc = (message.media.document || message.media.webpage.document) as MyDocument;
if(doc.type === 'audio' || doc.type === 'voice') {
const audioElement = new AudioElement();
@ -409,23 +407,28 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS @@ -409,23 +407,28 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
return audioElement;
}
const uploading = message.pFlags.is_outgoing && message.media?.preloader;
let extSplitted = doc.file_name ? doc.file_name.split('.') : '';
let ext = '';
ext = extSplitted.length > 1 && Array.isArray(extSplitted) ? extSplitted.pop().toLowerCase() : 'file';
let docDiv = document.createElement('div');
docDiv.classList.add('document', `ext-${ext}`);
docDiv.dataset.docId = doc.id;
const icoDiv = document.createElement('div');
icoDiv.classList.add('document-ico');
if(doc.thumbs?.length || (uploading && doc.url && doc.type === 'photo')) {
if(doc.thumbs?.length || (message.pFlags.is_outgoing && doc.url && doc.type === 'photo')) {
docDiv.classList.add('document-with-thumb');
if(uploading) {
let imgs: HTMLImageElement[] = [];
if(message.pFlags.is_outgoing) {
icoDiv.innerHTML = `<img src="${doc.url}">`;
imgs.push(icoDiv.firstElementChild as HTMLImageElement);
} else {
wrapPhoto({
const wrapped = wrapPhoto({
photo: doc,
message: null,
container: icoDiv,
@ -435,10 +438,11 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS @@ -435,10 +438,11 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
withoutPreloader: true
});
icoDiv.style.width = icoDiv.style.height = '';
if(wrapped.images.thumb) imgs.push(wrapped.images.thumb);
if(wrapped.images.full) imgs.push(wrapped.images.full);
}
const img = icoDiv.querySelector('img');
if(img) img.classList.add('document-thumb');
imgs.forEach(img => img.classList.add('document-thumb'));
} else {
icoDiv.innerText = ext;
}
@ -461,48 +465,69 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS @@ -461,48 +465,69 @@ export function wrapDocument({message, withTime, fontWeight, voiceAsMusic, showS
}
docDiv.innerHTML = `
${!uploading ? `<div class="document-download"></div>` : ''}
${doc.downloaded && !uploading ? '' : `<div class="document-download"></div>`}
<div class="document-name"><middle-ellipsis-element data-font-weight="${fontWeight}">${fileName}</middle-ellipsis-element>${titleAdditionHTML}</div>
<div class="document-size">${size}</div>
`;
docDiv.prepend(icoDiv);
if(!uploading) {
const downloadDiv = docDiv.querySelector('.document-download') as HTMLDivElement;
const preloader = new ProgressivePreloader();
const load = () => {
const download = appDocsManager.saveDocFile(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
if(!uploading && message.pFlags.is_outgoing) {
return docDiv;
}
download.then(() => {
let downloadDiv: HTMLElement, preloader: ProgressivePreloader = null;
const onLoad = () => {
if(downloadDiv) {
downloadDiv.classList.add('downloaded');
const _downloadDiv = downloadDiv;
setTimeout(() => {
downloadDiv.remove();
_downloadDiv.remove();
}, 200);
});
downloadDiv = null;
}
if(preloader) {
preloader = null;
}
};
const load = () => {
const doc = appDocsManager.getDoc(docDiv.dataset.docId);
const download = appDocsManager.saveDocFile(doc, appImManager.chat.bubbles ? appImManager.chat.bubbles.lazyLoadQueue.queueId : 0);
if(downloadDiv) {
download.then(onLoad);
preloader.attach(downloadDiv, true, download);
}
return {download};
};
if(!(doc.downloaded && !uploading)) {
downloadDiv = docDiv.querySelector('.document-download');
preloader = message.media.preloader as ProgressivePreloader;
if(!preloader) {
preloader = new ProgressivePreloader();
preloader.construct();
preloader.setManual();
preloader.attach(downloadDiv);
preloader.setDownloadFunction(load);
} else {
preloader.attach(downloadDiv);
message.media.promise.then(onLoad);
}
}
attachClickEvent(docDiv, (e) => {
if(preloader) {
preloader.onClick(e);
});
/* if(doc.downloaded) {
downloadDiv.classList.add('downloaded');
} */
} else if(message.media?.preloader) {
const icoDiv = docDiv.querySelector('.document-ico');
message.media.preloader.attach(icoDiv, false);
} else {
load();
}
});
return docDiv;
}

4
src/helpers/cancellablePromise.ts

@ -61,6 +61,10 @@ export function deferredPromise<T>() { @@ -61,6 +61,10 @@ export function deferredPromise<T>() {
deferred.notify = null;
deferred.listeners.length = 0;
deferred.lastNotify = null;
if(deferred.cancel) {
deferred.cancel = () => {};
}
});
Object.assign(deferred, deferredHelper);

2
src/helpers/number.ts

@ -5,7 +5,7 @@ export function numberThousandSplitter(x: number, joiner = ',') { @@ -5,7 +5,7 @@ export function numberThousandSplitter(x: number, joiner = ',') {
}
export function formatBytes(bytes: number, decimals = 2) {
if (bytes === 0) return '0 Bytes';
if(bytes === 0) return '0 Bytes';
const k = 1024;
const dm = decimals < 0 ? 0 : decimals;

22
src/lib/appManagers/appDocsManager.ts

@ -278,27 +278,20 @@ export class AppDocsManager { @@ -278,27 +278,20 @@ export class AppDocsManager {
return getFileNameByLocation(this.getInput(doc, thumbSize), {fileName: doc.file_name});
}
public downloadDoc(doc: MyDocument/* , thumb?: PhotoSize.photoSize */, queueId?: number): DownloadBlob {
const fileName = this.getInputFileName(doc/* , thumb?.type */);
public downloadDoc(doc: MyDocument, queueId?: number): DownloadBlob {
const fileName = this.getInputFileName(doc);
let download: DownloadBlob = appDownloadManager.getDownload(fileName);
if(download) {
return download;
}
const downloadOptions = this.getFileDownloadOptions(doc, undefined/* thumb */, queueId);
const downloadOptions = this.getFileDownloadOptions(doc, undefined, queueId);
download = appDownloadManager.download(downloadOptions);
const originalPromise = download;
originalPromise.then((blob) => {
/* if(thumb) {
defineNotNumerableProperties(thumb, ['url']);
thumb.url = URL.createObjectURL(blob);
return;
} else */if(!doc.supportsStreaming) {
doc.url = URL.createObjectURL(blob);
}
doc.downloaded = true;
});
@ -390,8 +383,13 @@ export class AppDocsManager { @@ -390,8 +383,13 @@ export class AppDocsManager {
}
public saveDocFile(doc: MyDocument, queueId?: number) {
const options = this.getFileDownloadOptions(doc, undefined, queueId);
return appDownloadManager.downloadToDisc(options, doc.file_name);
/* const options = this.getFileDownloadOptions(doc, undefined, queueId);
return appDownloadManager.downloadToDisc(options, doc.file_name); */
const promise = this.downloadDoc(doc, queueId);
promise.then(() => {
appDownloadManager.createDownloadAnchor(doc.url, doc.file_name);
});
return promise;
}
}

15
src/lib/appManagers/appDownloadManager.ts

@ -77,6 +77,19 @@ export class AppDownloadManager { @@ -77,6 +77,19 @@ export class AppDownloadManager {
delete this.downloads[fileName];
}
public fakeDownload(fileName: string, value: Blob | string) {
const deferred = this.getNewDeferred(fileName);
if(typeof(value) === 'string') {
fetch(value)
.then(response => response.blob())
.then(blob => deferred.resolve(blob));
} else {
deferred.resolve(value);
}
return deferred;
}
public download(options: DownloadOptions): DownloadBlob {
const fileName = getFileNameByLocation(options.location, {fileName: options.fileName});
if(this.downloads.hasOwnProperty(fileName)) return this.downloads[fileName];
@ -174,7 +187,7 @@ export class AppDownloadManager { @@ -174,7 +187,7 @@ export class AppDownloadManager {
}
}
private createDownloadAnchor(url: string, fileName: string, onRemove?: () => void) {
public createDownloadAnchor(url: string, fileName: string, onRemove?: () => void) {
const a = document.createElement('a');
a.href = url;
a.download = fileName;

28
src/lib/appManagers/appMessagesManager.ts

@ -34,6 +34,7 @@ import appUsersManager from "./appUsersManager"; @@ -34,6 +34,7 @@ import appUsersManager from "./appUsersManager";
import appWebPagesManager from "./appWebPagesManager";
import appDraftsManager from "./appDraftsManager";
import pushHeavyTask from "../../helpers/heavyQueue";
import { getFileNameByLocation } from "../../helpers/fileName";
//console.trace('include');
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
@ -786,18 +787,21 @@ export class AppMessagesManager { @@ -786,18 +787,21 @@ export class AppMessagesManager {
this.log('sendFile', attachType, apiFileName, file.type, options);
const preloader = new ProgressivePreloader({
const preloader = isDocument ? undefined : new ProgressivePreloader({
attachMethod: 'prepend',
tryAgainOnFail: false,
isUpload: true
});
const media = {
const sentDeferred = deferredPromise<InputMedia>();
const media = isDocument ? undefined : {
_: photo ? 'messageMediaPhoto' : 'messageMediaDocument',
pFlags: {},
preloader,
photo,
document
document,
promise: sentDeferred
};
const message: any = {
@ -833,7 +837,6 @@ export class AppMessagesManager { @@ -833,7 +837,6 @@ export class AppMessagesManager {
let uploaded = false,
uploadPromise: ReturnType<ApiFileManager['uploadFile']> = null;
const sentDeferred = deferredPromise<InputMedia>();
message.send = () => {
if(isDocument) {
const {id, access_hash, file_reference} = file as MyDocument;
@ -4394,18 +4397,31 @@ export class AppMessagesManager { @@ -4394,18 +4397,31 @@ export class AppMessagesManager {
if(message.media.photo) {
const photo = appPhotosManager.getPhoto('' + tempId);
if(/* photo._ !== 'photoEmpty' */photo) {
const newPhoto = message.media.photo;
const newPhoto = message.media.photo as MyPhoto;
// костыль
defineNotNumerableProperties(newPhoto, ['downloaded', 'url']);
newPhoto.downloaded = photo.downloaded;
newPhoto.url = photo.url;
const photoSize = newPhoto.sizes[newPhoto.sizes.length - 1] as PhotoSize.photoSize;
defineNotNumerableProperties(photoSize, ['url']);
photoSize.url = photo.url;
const downloadOptions = appPhotosManager.getPhotoDownloadOptions(newPhoto, photoSize);
const fileName = getFileNameByLocation(downloadOptions.location);
appDownloadManager.fakeDownload(fileName, photo.url);
}
} else if(message.media.document) {
const doc = appDocsManager.getDoc('' + tempId);
if(/* doc._ !== 'documentEmpty' && */doc?.type && doc.type !== 'sticker') {
if(doc) {
if(/* doc._ !== 'documentEmpty' && */doc.type && doc.type !== 'sticker') {
const newDoc = message.media.document;
newDoc.downloaded = doc.downloaded;
newDoc.url = doc.url;
const fileName = appDocsManager.getInputFileName(newDoc);
appDownloadManager.fakeDownload(fileName, doc.url);
}
}
} else if(message.media.poll) {
delete appPollsManager.polls[tempId];

98
src/scss/partials/_document.scss

@ -1,15 +1,17 @@ @@ -1,15 +1,17 @@
.document {
--background-color: #{$color-blue};
$border-radius: .375rem;
padding-left: 4.25rem;
height: 70px;
&-ico {
background-color: $color-blue;
border-radius: .5rem;
line-height: 10px;
background-color: var(--background-color);
border-radius: $border-radius;
line-height: 1;
text-align: center;
.document:not(.document-with-thumb) & {
padding: 1.5rem .25rem 0 .25rem;
padding: 1.5625rem .25rem 0 .25rem;
@include respond-to(handhelds) {
padding: 14px 0px 0px 0px;
@ -34,9 +36,7 @@ @@ -34,9 +36,7 @@
}
&-ico, &-download {
font-weight: 500;
letter-spacing: 1px;
font-size: 1.1rem;
font-size: 1.125rem;
background-size: contain;
}
@ -47,39 +47,26 @@ @@ -47,39 +47,26 @@
}
&-download {
background-color: $color-blue;
border-radius: .5rem;
background-color: var(--background-color);
border-radius: $border-radius;
}
&.ext-zip {
.document-ico, .document-download {
background-color: #FB8C00;
}
--background-color: #FB8C00;
}
&.ext-pdf {
.document-ico, .document-download {
background-color: #DF3F40;
}
--background-color: #DF3F40;
}
&.ext-apk {
.document-ico, .document-download {
background-color: #43A047;
}
--background-color: #43A047;
}
&.document-with-thumb {
.document-ico {
background: #fff;
border-radius: $border-radius;
.document-thumb {
object-fit: cover;
width: 100%;
height: 100%;
}
--background-color: #fff;
.document-ico {
&:after {
display: none;
}
@ -88,6 +75,22 @@ @@ -88,6 +75,22 @@
.document-download {
background-color: rgba(0, 0, 0, .15);
}
.preloader-circular {
transition: background-color .2s;
}
.preloader-container:not(.manual) {
.preloader-circular {
background-color: rgba(0, 0, 0, .3) !important;
}
}
}
&-thumb {
object-fit: cover;
width: 100%;
height: 100%;
}
&-name {
@ -106,13 +109,21 @@ @@ -106,13 +109,21 @@
}
.preloader-container {
width: 2.375rem;
height: 2.375rem;
width: 2.5rem;
height: 2.5rem;
@include respond-to(handhelds) {
width: 26px;
height: 26px;
width: 1.625rem;
height: 1.625rem;
}
}
.preloader-circular {
background-color: transparent !important;
}
.preloader-path-new {
stroke-width: 2.5;
}
}
@ -127,20 +138,20 @@ @@ -127,20 +138,20 @@
&-ico, &-download {
position: absolute;
left: 0;
width: 54px;
height: 54px;
width: 3.375rem;
height: 3.375rem;
color: #fff;
@include respond-to(handhelds) {
height: 36px;
width: 36px;
height: 2.25rem;
width: 2.25rem;
}
}
&-download {
z-index: 1;
align-items: center;
font-size: 24px;
font-size: 1.5rem;
cursor: pointer;
display: flex;
justify-content: center;
@ -155,14 +166,8 @@ @@ -155,14 +166,8 @@
}
.preloader-container:not(.preloader-streamable) {
width: 100%;
height: 100%;
transform: scale(1) !important;
}
.preloader-circular {
background-color: transparent !important;
}
}
.audio {
@ -174,4 +179,13 @@ @@ -174,4 +179,13 @@
margin-right: -1px;
}
}
.preloader-circular {
background-color: transparent !important;
}
.preloader-container:not(.preloader-streamable) {
width: 100%;
height: 100%;
}
}

8
src/scss/partials/popups/_mediaAttacher.scss

@ -167,16 +167,18 @@ @@ -167,16 +167,18 @@
.checkbox-field {
margin-bottom: 0;
padding-left: 0;
margin-left: 0;
}
.popup-album, .popup-container:not(.is-album) .popup-item-media {
.popup-album,
.popup-container:not(.is-album) .popup-item-media {
position: relative;
border-radius: inherit;
overflow: hidden;
}
.popup-album + .popup-album, .popup-container:not(.is-album) .popup-item-media + .popup-item-media {
.popup-album + .popup-album,
.popup-container:not(.is-album) .popup-item-media + .popup-item-media {
margin-top: .5rem;
}
}
Loading…
Cancel
Save