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