Media spoilers in shared media

This commit is contained in:
Eduard Kuzmenko 2023-01-12 19:13:22 +04:00
parent e207ea088f
commit 5d7dbbab77
6 changed files with 78 additions and 43 deletions

View File

@ -74,6 +74,7 @@ import wrapDocument from './wrappers/document';
import wrapPhoto from './wrappers/photo';
import wrapVideo from './wrappers/video';
import noop from '../helpers/noop';
import wrapMediaSpoiler, {onMediaSpoilerClick} from './wrappers/mediaSpoiler';
// const testScroll = false;
@ -549,6 +550,15 @@ export default class AppSearchSuper {
return;
}
const mediaSpoiler: HTMLElement = target.querySelector('.media-spoiler-container');
if(mediaSpoiler) {
onMediaSpoilerClick({
event: e,
mediaSpoiler
})
return;
}
const peerId = target.dataset.peerId.toPeerId();
const targets = (Array.from(this.tabs[inputFilter].querySelectorAll('.' + targetClassName)) as HTMLElement[]).map((el) => {
@ -666,7 +676,23 @@ export default class AppSearchSuper {
});
}
[wrapped.images.thumb, wrapped.images.full].filter(Boolean).forEach((image) => {
if((message.media as MessageMedia.messageMediaPhoto).pFlags.spoiler) {
const mediaSpoiler = await wrapMediaSpoiler({
animationGroup: 'chat',
media,
middleware,
width: 140,
height: 140,
multiply: 0.3
});
div.append(mediaSpoiler);
}
[
wrapped.images.thumb,
wrapped.images.full
].filter(Boolean).forEach((image) => {
image.classList.add('grid-item-media');
});
@ -1645,6 +1671,7 @@ export default class AppSearchSuper {
}
public destroy() {
this.cleanup();
this.listenerSetter.removeAll();
this.scrollable.destroy();
this.swipeHandler?.removeListeners();

View File

@ -127,7 +127,7 @@ import {BatchProcessor} from '../../helpers/sortedList';
import wrapUrl from '../../lib/richTextProcessor/wrapUrl';
import getMessageThreadId from '../../lib/appManagers/utils/messages/getMessageThreadId';
import wrapTopicNameButton from '../wrappers/topicNameButton';
import wrapMediaSpoiler, {toggleMediaSpoiler} from '../wrappers/mediaSpoiler';
import wrapMediaSpoiler, {onMediaSpoilerClick, toggleMediaSpoiler} from '../wrappers/mediaSpoiler';
import confirmationPopup from '../confirmationPopup';
import wrapPeerTitle from '../wrappers/peerTitle';
import {PopupPeerCheckboxOptions} from '../popups/peer';
@ -1642,24 +1642,10 @@ export default class ChatBubbles {
const mediaSpoiler: HTMLElement = findUpClassName(target, 'media-spoiler-container');
if(mediaSpoiler) {
cancelEvent(e);
if(mediaSpoiler.classList.contains('is-revealing')) {
return;
}
const video = mediaSpoiler.parentElement.querySelector('video');
if(video && !mediaSpoiler.parentElement.querySelector('.video-play')) {
video.autoplay = true;
video.play().catch(noop);
}
toggleMediaSpoiler({
mediaSpoiler,
reveal: true,
destroyAfter: true
onMediaSpoilerClick({
event: e,
mediaSpoiler
});
return;
}

View File

@ -6,7 +6,6 @@
import {IS_MOBILE} from '../environment/userAgent';
import {animate} from '../helpers/animation';
import drawCircle, {drawCircleFromStart} from '../helpers/canvas/drawCircle';
import {Middleware} from '../helpers/middleware';
import clamp from '../helpers/number/clamp';
import animationIntersector, {AnimationItemGroup, AnimationItemWrapper} from './animationIntersector';
@ -32,7 +31,11 @@ export default class DotRenderer implements AnimationItemWrapper {
private dpr: number;
constructor(private width: number, private height: number) {
constructor(
private width: number,
private height: number,
private multiply?: number
) {
const canvas = this.canvas = document.createElement('canvas');
const dpr = this.dpr = window.devicePixelRatio;
canvas.width = width * dpr;
@ -47,7 +50,9 @@ export default class DotRenderer implements AnimationItemWrapper {
private prepare() {
let count = Math.round(this.width * this.height / (35 * (IS_MOBILE ? 2 : 1)));
count *= this.multiply || 1;
count = Math.min(IS_MOBILE ? 1000 : 2200, count);
count = Math.round(count);
const dots: DotRendererDot[] = this.dots = new Array(count);
for(let i = 0; i < count; ++i) {
@ -151,18 +156,20 @@ export default class DotRenderer implements AnimationItemWrapper {
width,
height,
middleware,
animationGroup
animationGroup,
multiply
}: {
width: number,
height: number,
middleware: Middleware,
animationGroup: AnimationItemGroup
animationGroup: AnimationItemGroup,
multiply?: number
}) {
middleware.onClean(() => {
animationIntersector.removeAnimationByPlayer(dotRenderer);
});
const dotRenderer = new DotRenderer(width, height);
const dotRenderer = new DotRenderer(width, height, multiply);
dotRenderer.renderFirstFrame();
animationIntersector.addAnimation(dotRenderer, animationGroup, dotRenderer.canvas, true);

View File

@ -16,6 +16,7 @@ export const RIGHT_COLUMN_ACTIVE_CLASSNAME = 'is-right-column-shown';
export class AppSidebarRight extends SidebarSlider {
private isColumnProportionSet = false;
private sharedMediaTab: AppSharedMediaTab;
// public rect: DOMRect;
constructor() {
super({
@ -91,6 +92,7 @@ export class AppSidebarRight extends SidebarSlider {
private setColumnProportion() {
const proportion = this.sidebarEl.scrollWidth / this.sidebarEl.previousElementSibling.scrollWidth;
document.documentElement.style.setProperty('--right-column-proportion', '' + proportion);
// this.rect = this.sidebarEl.getBoundingClientRect();
}
public toggleSidebar(enable?: boolean, animate?: boolean) {

View File

@ -4,10 +4,10 @@
* https://github.com/morethanwords/tweb/blob/master/LICENSE
*/
import cancelEvent from '../../helpers/dom/cancelEvent';
import getImageFromStrippedThumb from '../../helpers/getImageFromStrippedThumb';
import {Middleware} from '../../helpers/middleware';
import noop from '../../helpers/noop';
import {Document, Photo, PhotoSize} from '../../layer';
import {AnimationItemGroup} from '../animationIntersector';
import DotRenderer from '../dotRenderer';
import SetTransition from '../singleTransition';
@ -31,19 +31,34 @@ export function toggleMediaSpoiler(options: {
});
}
export function wrapMediaSpoilerWithImage({
middleware,
width,
height,
animationGroup,
image
}: {
middleware: Middleware,
width: number,
height: number,
animationGroup: AnimationItemGroup,
image: Awaited<ReturnType<typeof getImageFromStrippedThumb>>['image']
export function onMediaSpoilerClick(options: {
mediaSpoiler: HTMLElement,
event: Event
}) {
const {mediaSpoiler, event} = options;
cancelEvent(event);
if(mediaSpoiler.classList.contains('is-revealing')) {
return;
}
const video = mediaSpoiler.parentElement.querySelector('video');
if(video && !mediaSpoiler.parentElement.querySelector('.video-play')) {
video.autoplay = true;
video.play().catch(noop);
}
toggleMediaSpoiler({
mediaSpoiler,
reveal: true,
destroyAfter: true
});
}
export function wrapMediaSpoilerWithImage(options: {
image: Awaited<ReturnType<typeof getImageFromStrippedThumb>>['image']
} & Parameters<typeof DotRenderer['create']>[0]) {
const {middleware, image} = options;
if(!middleware()) {
return;
}
@ -55,10 +70,8 @@ export function wrapMediaSpoilerWithImage({
container.middlewareHelper = middleware.create();
const dotRenderer = DotRenderer.create({
width,
height,
middleware: container.middlewareHelper.get(),
animationGroup
...options,
middleware: container.middlewareHelper.get()
});
container.append(image, dotRenderer.canvas);

View File

@ -364,7 +364,7 @@
border-radius: 4px;
background-color: var(--message-time-background);
padding: 0px 6px 0px 5px;
z-index: 1;
z-index: 2;
font-size: 12px;
color: white;
line-height: 18px;