Fix deleting messages as secondary admin
Fix uploading video Fix canceling upload Scale down uploading thumb
This commit is contained in:
parent
84cf9e2d13
commit
a1e1690af6
@ -21,15 +21,20 @@ import isSendShortcutPressed from "../../helpers/dom/isSendShortcutPressed";
|
||||
import placeCaretAtEnd from "../../helpers/dom/placeCaretAtEnd";
|
||||
import rootScope from "../../lib/rootScope";
|
||||
import RichTextProcessor from "../../lib/richtextprocessor";
|
||||
import { MediaSize } from "../../helpers/mediaSizes";
|
||||
|
||||
type SendFileParams = Partial<{
|
||||
file: File,
|
||||
objectURL: string,
|
||||
thumbBlob: Blob,
|
||||
thumbURL: string,
|
||||
thumb: {
|
||||
blob: Blob,
|
||||
url: string,
|
||||
size: MediaSize
|
||||
},
|
||||
width: number,
|
||||
height: number,
|
||||
duration: number
|
||||
duration: number,
|
||||
noSound: boolean
|
||||
}>;
|
||||
|
||||
// TODO: .gif upload as video
|
||||
@ -263,11 +268,18 @@ export default class PopupNewMedia extends PopupElement {
|
||||
params.width = video.videoWidth;
|
||||
params.height = video.videoHeight;
|
||||
params.duration = Math.floor(video.duration);
|
||||
|
||||
const audioDecodedByteCount = (video as any).webkitAudioDecodedByteCount;
|
||||
if(audioDecodedByteCount !== undefined) {
|
||||
params.noSound = !audioDecodedByteCount;
|
||||
}
|
||||
|
||||
itemDiv.append(video);
|
||||
createPosterFromVideo(video).then(blob => {
|
||||
params.thumbBlob = blob;
|
||||
params.thumbURL = URL.createObjectURL(blob);
|
||||
createPosterFromVideo(video).then(thumb => {
|
||||
params.thumb = {
|
||||
url: URL.createObjectURL(thumb.blob),
|
||||
...thumb
|
||||
};
|
||||
resolve(itemDiv);
|
||||
});
|
||||
});
|
||||
|
@ -309,8 +309,9 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
|
||||
const cacheContext = appDownloadManager.getCacheContext(doc);
|
||||
|
||||
const isUpload = !!message?.media?.preloader;
|
||||
let preloader: ProgressivePreloader;
|
||||
if(message?.media?.preloader) { // means upload
|
||||
if(isUpload) { // means upload
|
||||
preloader = message.media.preloader as ProgressivePreloader;
|
||||
preloader.attach(container, false);
|
||||
noAutoDownload = undefined;
|
||||
@ -333,7 +334,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
}
|
||||
|
||||
let loadPromise: Promise<any> = Promise.resolve();
|
||||
if(preloader) {
|
||||
if(preloader && !isUpload) {
|
||||
if(!cacheContext.downloaded && !doc.supportsStreaming) {
|
||||
const promise = loadPromise = appDocsManager.downloadDoc(doc, lazyLoadQueue?.queueId, noAutoDownload);
|
||||
preloader.attach(container, false, promise);
|
||||
@ -354,7 +355,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
console.error("Error " + video.error.code + "; details: " + video.error.message);
|
||||
}
|
||||
|
||||
if(preloader) {
|
||||
if(preloader && !isUpload) {
|
||||
preloader.detach();
|
||||
}
|
||||
|
||||
@ -386,7 +387,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
animationIntersector.addAnimation(video, group);
|
||||
}
|
||||
|
||||
if(preloader) {
|
||||
if(preloader && !isUpload) {
|
||||
preloader.detach();
|
||||
}
|
||||
|
||||
@ -410,7 +411,7 @@ export function wrapVideo({doc, container, message, boxWidth, boxHeight, withTai
|
||||
return {download: loadPromise, render: deferred};
|
||||
};
|
||||
|
||||
if(preloader) {
|
||||
if(preloader && !isUpload) {
|
||||
preloader.setDownloadFunction(load);
|
||||
}
|
||||
|
||||
|
@ -4,38 +4,63 @@
|
||||
* https://github.com/morethanwords/tweb/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
import { makeMediaSize, MediaSize } from "./mediaSizes";
|
||||
import { pause } from "./schedulers/pause";
|
||||
import { isAppleMobile } from "./userAgent";
|
||||
|
||||
export function scaleMediaElement(options: {
|
||||
media: CanvasImageSource,
|
||||
mediaSize: MediaSize,
|
||||
boxSize: MediaSize,
|
||||
quality?: number,
|
||||
mimeType?: 'image/jpeg' | 'image/png'
|
||||
}): Promise<{blob: Blob, size: MediaSize}> {
|
||||
return new Promise((resolve) => {
|
||||
const canvas = document.createElement('canvas');
|
||||
const size = options.mediaSize.aspectFitted(options.boxSize);
|
||||
canvas.width = size.width * window.devicePixelRatio;
|
||||
canvas.height = size.height * window.devicePixelRatio;
|
||||
const ctx = canvas.getContext('2d');
|
||||
ctx.drawImage(options.media, 0, 0, canvas.width, canvas.height);
|
||||
canvas.toBlob(blob => {
|
||||
resolve({blob, size});
|
||||
}, options.mimeType ?? 'image/jpeg', options.quality ?? 1);
|
||||
});
|
||||
}
|
||||
|
||||
export function preloadVideo(url: string): Promise<HTMLVideoElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const video = document.createElement('video');
|
||||
video.volume = 0;
|
||||
video.onloadedmetadata = () => resolve(video);
|
||||
video.onerror = reject;
|
||||
video.addEventListener('loadedmetadata', () => resolve(video), {once: true});
|
||||
video.addEventListener('error', reject, {once: true});
|
||||
video.src = url;
|
||||
});
|
||||
}
|
||||
|
||||
export function createPosterFromVideo(video: HTMLVideoElement): Promise<Blob> {
|
||||
export function createPosterFromVideo(video: HTMLVideoElement): ReturnType<typeof scaleMediaElement> {
|
||||
return new Promise((resolve, reject) => {
|
||||
video.onseeked = () => {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = Math.min(1280, video.videoWidth);
|
||||
canvas.height = Math.min(720, video.videoHeight);
|
||||
const ctx = canvas.getContext('2d')!;
|
||||
ctx.drawImage(video, 0, 0);
|
||||
canvas.toBlob(blob => {
|
||||
resolve(blob);
|
||||
}, 'image/jpeg', 1);
|
||||
};
|
||||
video.onseeked = () => {
|
||||
scaleMediaElement({
|
||||
media: video,
|
||||
mediaSize: makeMediaSize(video.videoWidth, video.videoHeight),
|
||||
boxSize: makeMediaSize(320, 240),
|
||||
quality: .9
|
||||
}).then(resolve);
|
||||
|
||||
video.onseeked = undefined;
|
||||
};
|
||||
|
||||
video.currentTime = 0;
|
||||
};
|
||||
|
||||
video.onerror = reject;
|
||||
video.currentTime = Math.min(video.duration, 1);
|
||||
});
|
||||
}
|
||||
|
||||
export async function createPosterForVideo(url: string): Promise<Blob | undefined> {
|
||||
export async function createPosterForVideo(url: string) {
|
||||
const video = await preloadVideo(url);
|
||||
|
||||
return Promise.race([
|
||||
|
@ -58,6 +58,7 @@ import telegramMeWebManager from "../mtproto/telegramMeWebManager";
|
||||
import { getMiddleware } from "../../helpers/middleware";
|
||||
import assumeType from "../../helpers/assumeType";
|
||||
import appMessagesIdsManager from "./appMessagesIdsManager";
|
||||
import type { MediaSize } from "../../helpers/mediaSizes";
|
||||
|
||||
//console.trace('include');
|
||||
// TODO: если удалить сообщение в непрогруженном диалоге, то при обновлении, из-за стейта, последнего сообщения в чатлисте не будет
|
||||
@ -599,13 +600,17 @@ export class AppMessagesManager {
|
||||
width: number,
|
||||
height: number,
|
||||
objectURL: string,
|
||||
thumbBlob: Blob,
|
||||
thumbURL: string,
|
||||
thumb: {
|
||||
blob: Blob,
|
||||
url: string,
|
||||
size: MediaSize
|
||||
},
|
||||
duration: number,
|
||||
background: true,
|
||||
silent: true,
|
||||
clearDraft: true,
|
||||
scheduleDate: number,
|
||||
noSound: boolean,
|
||||
|
||||
waveform: Uint8Array,
|
||||
}> = {}) {
|
||||
@ -696,10 +701,11 @@ export class AppMessagesManager {
|
||||
apiFileName = 'video.mp4';
|
||||
actionName = 'sendMessageUploadVideoAction';
|
||||
|
||||
let videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
||||
const videoAttribute: DocumentAttribute.documentAttributeVideo = {
|
||||
_: 'documentAttributeVideo',
|
||||
pFlags: {
|
||||
round_message: options.isRoundMessage
|
||||
round_message: options.isRoundMessage,
|
||||
supports_streaming: true
|
||||
},
|
||||
duration: options.duration,
|
||||
w: options.width,
|
||||
@ -707,6 +713,15 @@ export class AppMessagesManager {
|
||||
};
|
||||
|
||||
attributes.push(videoAttribute);
|
||||
|
||||
// * must follow after video attribute
|
||||
if(options.noSound &&
|
||||
file.size > (10 * 1024) &&
|
||||
file.size < (10 * 1024 * 1024)) {
|
||||
attributes.push({
|
||||
_: 'documentAttributeAnimated'
|
||||
});
|
||||
}
|
||||
} else {
|
||||
attachType = 'document';
|
||||
apiFileName = 'document.' + fileType.split('/')[1];
|
||||
@ -749,18 +764,18 @@ export class AppMessagesManager {
|
||||
size: file.size
|
||||
};
|
||||
} else if(attachType === 'video') {
|
||||
if(options.thumbURL) {
|
||||
if(options.thumb) {
|
||||
thumb = {
|
||||
_: 'photoSize',
|
||||
w: options.width,
|
||||
h: options.height,
|
||||
type: 'full',
|
||||
size: options.thumbBlob.size
|
||||
w: options.thumb.size.width,
|
||||
h: options.thumb.size.height,
|
||||
type: 'local-thumb',
|
||||
size: options.thumb.blob.size
|
||||
};
|
||||
|
||||
const thumbCacheContext = appDownloadManager.getCacheContext(document, thumb.type);
|
||||
thumbCacheContext.downloaded = thumb.size;
|
||||
thumbCacheContext.url = options.thumbURL;
|
||||
thumbCacheContext.url = options.thumb.url;
|
||||
}
|
||||
}
|
||||
|
||||
@ -800,7 +815,6 @@ export class AppMessagesManager {
|
||||
if(err.name === 'AbortError' && !uploaded) {
|
||||
this.log('cancelling upload', media);
|
||||
|
||||
sentDeferred.reject(err);
|
||||
this.cancelPendingMessage(message.random_id);
|
||||
this.setTyping(peerId, {_: 'sendMessageCancelAction'});
|
||||
|
||||
@ -867,12 +881,12 @@ export class AppMessagesManager {
|
||||
let thumbUploadPromise: typeof uploadPromise;
|
||||
if(attachType === 'video' && options.objectURL) {
|
||||
thumbUploadPromise = new Promise((resolve, reject) => {
|
||||
const blobPromise = options.thumbBlob ? Promise.resolve(options.thumbBlob) : createPosterForVideo(options.objectURL);
|
||||
blobPromise.then(blob => {
|
||||
if(!blob) {
|
||||
const thumbPromise = options.thumb && options.thumb.blob ? Promise.resolve(options.thumb) : createPosterForVideo(options.objectURL);
|
||||
thumbPromise.then(thumb => {
|
||||
if(!thumb) {
|
||||
resolve(null);
|
||||
} else {
|
||||
appDownloadManager.upload(blob).then(resolve, reject);
|
||||
appDownloadManager.upload(thumb.blob).then(resolve, reject);
|
||||
}
|
||||
}, reject);
|
||||
});
|
||||
@ -3571,23 +3585,16 @@ export class AppMessagesManager {
|
||||
|
||||
if(peerId < 0 && appPeersManager.isChannel(peerId)) {
|
||||
const channelId = -peerId;
|
||||
const channel = appChatsManager.getChat(channelId);
|
||||
if(!channel.pFlags.creator && !(channel.pFlags.editor && channel.pFlags.megagroup)) {
|
||||
const goodMsgIds: number[] = [];
|
||||
if(channel.pFlags.editor || channel.pFlags.megagroup) {
|
||||
mids.forEach((msgId, i) => {
|
||||
const message = this.getMessageByPeer(peerId, mids[i]);
|
||||
if(message.pFlags.out) {
|
||||
goodMsgIds.push(msgId);
|
||||
}
|
||||
});
|
||||
}
|
||||
const channel: Chat.channel = appChatsManager.getChat(channelId);
|
||||
if(!channel.pFlags.creator && !channel.admin_rights?.pFlags?.delete_messages) {
|
||||
mids = mids.filter((mid) => {
|
||||
const message = this.getMessageByPeer(peerId, mid);
|
||||
return !!message.pFlags.out;
|
||||
});
|
||||
|
||||
if(!goodMsgIds.length) {
|
||||
if(!mids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
mids = goodMsgIds;
|
||||
}
|
||||
|
||||
promise = apiManager.invokeApi('channels.deleteMessages', {
|
||||
|
@ -175,7 +175,7 @@ export class ApiFileManager {
|
||||
}
|
||||
|
||||
public cancelDownload(fileName: string) {
|
||||
const promises = (this.cachedDownloadPromises[fileName] ? [this.cachedDownloadPromises[fileName]] : []) ||
|
||||
const promises = (this.cachedDownloadPromises[fileName] ? [this.cachedDownloadPromises[fileName]] : undefined) ||
|
||||
(this.uploadPromises[fileName] ? Array.from(this.uploadPromises[fileName]) : []);
|
||||
let canceled = false;
|
||||
for(let i = 0, length = promises.length; i < length; ++i) {
|
||||
|
@ -174,7 +174,8 @@ poll-element {
|
||||
&-votes-count {
|
||||
color: var(--secondary-text-color);
|
||||
font-size: .875rem;
|
||||
padding-top: .1875rem;
|
||||
// padding-top: .1875rem; // THIS IS MOCKUP!
|
||||
margin-top: -.5rem; // this is human-readable
|
||||
}
|
||||
|
||||
&-line {
|
||||
|
Loading…
Reference in New Issue
Block a user