Browse Source

Handle webp sticker with message (animated webp)

Fix some types of messages for edit
Up arrow to edit
Maybe support Safari iOS 14 WebP
Fix title abbreviation again
master
Eduard Kuzmenko 4 years ago
parent
commit
9a5ffc2162
  1. 6
      src/components/chat/input.ts
  2. 6
      src/components/wrappers.ts
  3. 5
      src/lib/appManagers/appDocsManager.ts
  4. 39
      src/lib/appManagers/appImManager.ts
  5. 4
      src/lib/appManagers/appMessagesManager.ts
  6. 4
      src/lib/mtproto/apiFileManager.ts
  7. 8
      src/lib/mtproto/mtproto.worker.ts
  8. 4
      src/lib/mtproto/mtprotoworker.ts
  9. 14
      src/lib/richtextprocessor.ts
  10. 9
      src/lib/webp/webpWorkerController.ts
  11. 4
      src/scss/partials/_chatBubble.scss

6
src/components/chat/input.ts

@ -11,7 +11,7 @@ import apiManager from "../../lib/mtproto/mtprotoworker"; @@ -11,7 +11,7 @@ import apiManager from "../../lib/mtproto/mtprotoworker";
import opusDecodeController from "../../lib/opusDecodeController";
import { RichTextProcessor } from "../../lib/richtextprocessor";
import rootScope from '../../lib/rootScope';
import { cancelEvent, findUpClassName, getRichValue, isInputEmpty, serializeNodes } from "../../helpers/dom";
import { cancelEvent, findUpClassName, getRichValue, isInputEmpty, placeCaretAtEnd, serializeNodes } from "../../helpers/dom";
import ButtonMenu, { ButtonMenuItemOptions } from '../buttonMenu';
import emoticonsDropdown from "../emoticonsDropdown";
import PopupCreatePoll from "../popupCreatePoll";
@ -719,6 +719,10 @@ export class ChatInput { @@ -719,6 +719,10 @@ export class ChatInput {
if(input !== undefined) {
this.messageInput.innerHTML = input || '';
window.requestAnimationFrame(() => {
placeCaretAtEnd(this.messageInput);
this.inputScroll.scrollTop = this.inputScroll.scrollHeight;
});
}
setTimeout(() => {

6
src/components/wrappers.ts

@ -581,7 +581,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o @@ -581,7 +581,7 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
} else if('bytes' in thumb) {
img = new Image();
if((!isSafari || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {
if((webpWorkerController.isWebpSupported() || doc.pFlags.stickerThumbConverted || thumb.url)/* && false */) {
renderImageFromUrl(img, appPhotosManager.getPreviewURLFromThumb(thumb, true), afterRender);
} else {
webpWorkerController.convert(doc.id, thumb.bytes as Uint8Array).then(bytes => {
@ -692,6 +692,10 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o @@ -692,6 +692,10 @@ export function wrapSticker({doc, div, middleware, lazyLoadQueue, group, play, o
img.classList.add('fade-in-transition');
img.style.opacity = '0';
if(!div.firstElementChild) {
div.append(img);
}
img.addEventListener('load', () => {
doc.downloaded = true;

5
src/lib/appManagers/appDocsManager.ts

@ -1,10 +1,12 @@ @@ -1,10 +1,12 @@
import { FileURLType, getFileNameByLocation, getFileURL } from '../../helpers/fileName';
import { safeReplaceArrayInObject, defineNotNumerableProperties, isObject } from '../../helpers/object';
import { isSafari } from '../../helpers/userAgent';
import { Document, InputFileLocation, PhotoSize } from '../../layer';
import { MOUNT_CLASS_TO } from '../mtproto/mtproto_config';
import referenceDatabase, { ReferenceContext } from '../mtproto/referenceDatabase';
import opusDecodeController from '../opusDecodeController';
import { RichTextProcessor } from '../richtextprocessor';
import webpWorkerController from '../webp/webpWorkerController';
import appDownloadManager, { DownloadBlob } from './appDownloadManager';
import appPhotosManager from './appPhotosManager';
@ -99,7 +101,8 @@ class AppDocsManager { @@ -99,7 +101,8 @@ class AppDocsManager {
}
}
if(/* apiDoc.thumbs && */doc.mime_type == 'image/webp') {
// * there can be no thumbs, then it is a document
if(/* apiDoc.thumbs && */doc.mime_type == 'image/webp' && (doc.thumbs || webpWorkerController.isWebpSupported())) {
doc.type = 'sticker';
doc.sticker = 1;
}

39
src/lib/appManagers/appImManager.ts

@ -732,7 +732,7 @@ export class AppImManager { @@ -732,7 +732,7 @@ export class AppImManager {
//if(target.tagName == 'INPUT') return;
//this.log('onkeydown', e);
this.log('onkeydown', e);
if(e.key == 'Escape') {
/* if(AppMediaViewer.wholeDiv.classList.contains('active')) {
@ -750,6 +750,31 @@ export class AppImManager { @@ -750,6 +750,31 @@ export class AppImManager {
return;
} else if(e.code == "KeyC" && (e.ctrlKey || e.metaKey) && target.tagName != 'INPUT') {
return;
} else if(e.code == 'ArrowUp') {
if(!this.chatInputC.editMsgID) {
const history = appMessagesManager.historiesStorage[this.peerID];
if(history?.history) {
let goodMid: number;
for(const mid of history.history) {
const message = appMessagesManager.getMessage(mid);
const good = this.myID == this.peerID ? message.fromID == this.myID : message.pFlags.out;
if(good) {
if(appMessagesManager.canEditMessage(mid, 'text')) {
goodMid = mid;
}
break;
}
}
if(goodMid) {
this.chatInputC.initMessageEditing(goodMid);
}
}
}/* else {
this.scrollable.scrollTop -= 20;
} */
}
if(e.target != this.chatInputC.messageInput && target.tagName != 'INPUT' && !target.hasAttribute('contenteditable')) {
@ -1394,7 +1419,11 @@ export class AppImManager { @@ -1394,7 +1419,11 @@ export class AppImManager {
this.chatInput.style.display = '';
this.chatInput.classList.toggle('is-hidden', !canWrite);
this.bubblesContainer.classList.toggle('is-chat-input-hidden', !canWrite);
this.chatInputC.messageInput.toggleAttribute('contenteditable', canWrite);
if(!canWrite) {
this.chatInputC.messageInput.removeAttribute('contenteditable');
} else {
this.chatInputC.messageInput.setAttribute('contenteditable', 'true');
}
// const noTransition = [this.columnEl/* appSidebarRight.sidebarEl, this.backgroundEl,
// this.bubblesContainer, this.chatInput, this.chatInner,
@ -1765,12 +1794,14 @@ export class AppImManager { @@ -1765,12 +1794,14 @@ export class AppImManager {
return bubble;
}
let messageMedia = message.media;
let messageMessage: string, totalEntities: any[];
if(message.grouped_id) {
const t = appMessagesManager.getAlbumText(message.grouped_id);
messageMessage = t.message;
totalEntities = t.totalEntities;
} else {
} else if(messageMedia?.document?.type != 'sticker') {
messageMessage = message.message;
totalEntities = message.totalEntities;
}
@ -1779,8 +1810,6 @@ export class AppImManager { @@ -1779,8 +1810,6 @@ export class AppImManager {
entities: totalEntities
});
let messageMedia = message.media;
if(totalEntities && !messageMedia) {
let emojiEntities = totalEntities.filter((e: any) => e._ == 'messageEntityEmoji');
let strLength = messageMessage.length;

4
src/lib/appManagers/appMessagesManager.ts

@ -2142,6 +2142,7 @@ export class AppMessagesManager { @@ -2142,6 +2142,7 @@ export class AppMessagesManager {
messageText = '<i>Video message' + (message.message ? ', ' : '') + '</i>';
} else if(document.type == 'sticker') {
messageText = (document.stickerEmoji || '') + '<i>Sticker</i>';
text = '';
} else {
messageText = '<i>' + document.file_name + (message.message ? ', ' : '') + '</i>';
}
@ -2379,7 +2380,8 @@ export class AppMessagesManager { @@ -2379,7 +2380,8 @@ export class AppMessagesManager {
return false;
}
if(this.getMessagePeer(message) == appUsersManager.getSelf().id) {
// * second rule for saved messages, because there is no 'out' flag
if(message.pFlags.out || this.getMessagePeer(message) == appUsersManager.getSelf().id) {
return true;
}

4
src/lib/mtproto/apiFileManager.ts

@ -2,13 +2,13 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePr @@ -2,13 +2,13 @@ import { CancellablePromise, deferredPromise } from "../../helpers/cancellablePr
import { notifyAll, notifySomeone } from "../../helpers/context";
import { getFileNameByLocation } from "../../helpers/fileName";
import { nextRandomInt } from "../../helpers/random";
import { isSafari } from "../../helpers/userAgent";
import { FileLocation, InputFile, InputFileLocation, UploadFile } from "../../layer";
import cacheStorage from "../cacheStorage";
import cryptoWorker from "../crypto/cryptoworker";
import FileManager from "../filemanager";
import { logger, LogLevels } from "../logger";
import apiManager from "./apiManager";
import { isWebpSupported } from "./mtproto.worker";
import { MOUNT_CLASS_TO } from "./mtproto_config";
@ -182,7 +182,7 @@ export class ApiFileManager { @@ -182,7 +182,7 @@ export class ApiFileManager {
let process: ApiFileManager['uncompressTGS'] | ApiFileManager['convertWebp'];
if(options.mimeType == 'image/webp' && isSafari) {
if(options.mimeType == 'image/webp' && !isWebpSupported()) {
process = this.convertWebp;
options.mimeType = 'image/png';
} else if(options.mimeType == 'application/x-tgsticker') {

8
src/lib/mtproto/mtproto.worker.ts

@ -52,6 +52,11 @@ function respond(...args: any[]) { @@ -52,6 +52,11 @@ function respond(...args: any[]) {
} */
}
let webpSupported = false;
export const isWebpSupported = () => {
return webpSupported;
};
networkerFactory.setUpdatesProcessor((obj, bool) => {
respond({update: {obj, bool}});
});
@ -98,6 +103,9 @@ ctx.addEventListener('message', async(e) => { @@ -98,6 +103,9 @@ ctx.addEventListener('message', async(e) => {
respond(responseTask);
return;
} else if(task.type == 'webpSupport') {
webpSupported = task.payload;
return;
}
switch(task.task) {

4
src/lib/mtproto/mtprotoworker.ts

@ -106,6 +106,10 @@ export class ApiManagerProxy extends CryptoWorkerMethods { @@ -106,6 +106,10 @@ export class ApiManagerProxy extends CryptoWorkerMethods {
this.postMessage = this.worker.postMessage.bind(this.worker);
}
const isWebpSupported = webpWorkerController.isWebpSupported();
this.log('WebP supported:', isWebpSupported);
this.postMessage({type: 'webpSupport', payload: isWebpSupported});
this.releasePending();
}

14
src/lib/richtextprocessor.ts

@ -870,7 +870,7 @@ namespace RichTextProcessor { @@ -870,7 +870,7 @@ namespace RichTextProcessor {
return text.match(urlRegExp);
}
const el = document.createElement('span');
/* const el = document.createElement('span');
export function getAbbreviation(str: string, onlyFirst = false) {
const wrapped = wrapEmojiText(str);
el.innerHTML = wrapped;
@ -892,6 +892,18 @@ namespace RichTextProcessor { @@ -892,6 +892,18 @@ namespace RichTextProcessor {
}
return first + last;
} */
export function getAbbreviation(str: string, onlyFirst = false) {
const splitted = str.trim().split(' ');
if(!splitted[0]) return '';
const first = [...splitted[0]][0];
if(onlyFirst || splitted.length == 1) return wrapEmojiText(first);
const last = [...splitted[splitted.length - 1]][0];
return wrapEmojiText(first + last);
}
}

9
src/lib/webp/webpWorkerController.ts

@ -14,6 +14,7 @@ export type WebpConvertTask = { @@ -14,6 +14,7 @@ export type WebpConvertTask = {
export class WebpWorkerController {
private worker: Worker;
private convertPromises: {[fileName: string]: CancellablePromise<Uint8Array>} = {};
private isWebpSupportedCache: boolean;
init() {
this.worker = new WebpWorker();
@ -41,6 +42,14 @@ export class WebpWorkerController { @@ -41,6 +42,14 @@ export class WebpWorkerController {
this.worker.postMessage(data);
}
isWebpSupported() {
if(this.isWebpSupportedCache === undefined) {
this.isWebpSupportedCache = document.createElement('canvas').toDataURL('image/webp').startsWith('data:image/webp');
}
return this.isWebpSupportedCache;
}
convert(fileName: string, bytes: Uint8Array) {
fileName = 'main-' + fileName;

4
src/scss/partials/_chatBubble.scss

@ -1242,6 +1242,10 @@ $bubble-margin: .25rem; @@ -1242,6 +1242,10 @@ $bubble-margin: .25rem;
&__media-container {
cursor: pointer;
}
audio-element, poll-element {
white-space: nowrap; // * fix due to .message white-space prewrap
}
}
.bubble.service {

Loading…
Cancel
Save