Albums almost done
This commit is contained in:
parent
c35fb83125
commit
901f8cf99b
442
src/components/groupedLayout.ts
Normal file
442
src/components/groupedLayout.ts
Normal file
@ -0,0 +1,442 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop application for the Telegram messaging service.
|
||||
For license and copyright information please follow this link:
|
||||
https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
||||
*/
|
||||
|
||||
type Size = {w: number, h: number};
|
||||
export type GroupMediaLayout = {
|
||||
geometry: {
|
||||
x: number,
|
||||
y: number,
|
||||
width: number,
|
||||
height: number
|
||||
},
|
||||
sides: number
|
||||
};
|
||||
type Attempt = {
|
||||
lineCounts: number[],
|
||||
heights: number[]
|
||||
};
|
||||
export const RectPart = {
|
||||
None: 0,
|
||||
Top: 1,
|
||||
Right: 2,
|
||||
Bottom: 4,
|
||||
Left: 8
|
||||
};
|
||||
|
||||
let accumulate = (arr: number[], initialValue: number) => arr.reduce((acc, value) => acc + value, initialValue);
|
||||
|
||||
// https://github.com/telegramdesktop/tdesktop/blob/74d848311b31ef0eb6d2c43a4d30ade8f1d2d9fb/Telegram/SourceFiles/core/utils.h#L128
|
||||
function snap<T>(v: T, _min: T, _max: T): T {
|
||||
return (v < _min) ? _min : ((v > _max) ? _max : v);
|
||||
}
|
||||
|
||||
// https://github.com/telegramdesktop/tdesktop/blob/4669c07dc5335cbf4795bbbe5b0ab7c007b9aee2/Telegram/SourceFiles/ui/grouped_layout.cpp
|
||||
export class Layouter {
|
||||
private count: number;
|
||||
private ratios: number[];
|
||||
private proportions: string;
|
||||
private averageRatio: number;
|
||||
private maxSizeRatio: number;
|
||||
|
||||
constructor(private sizes: Size[], private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth) {
|
||||
this.count = sizes.length;
|
||||
this.ratios = Layouter.countRatios(sizes);
|
||||
this.proportions = Layouter.countProportions(this.ratios);
|
||||
this.averageRatio = accumulate(this.ratios, 1) / this.count; // warn
|
||||
this.maxSizeRatio = maxWidth / this.maxHeight;
|
||||
}
|
||||
|
||||
public layout(): GroupMediaLayout[] {
|
||||
if(!this.count) return [];
|
||||
//else if(this.count == 1) return this.layoutOne();
|
||||
|
||||
if(this.count >= 5 || this.ratios.find(r => r > 2)) {
|
||||
return new ComplexLayouter(this.ratios, this.averageRatio, this.maxWidth, this.minWidth, this.spacing).layout();
|
||||
}
|
||||
|
||||
if(this.count == 2) return this.layoutTwo();
|
||||
else if(this.count == 3) return this.layoutThree();
|
||||
return this.layoutFour();
|
||||
}
|
||||
|
||||
private layoutTwo(): ReturnType<Layouter['layout']> {
|
||||
if((this.proportions == "ww")
|
||||
&& (this.averageRatio > 1.4 * this.maxSizeRatio)
|
||||
&& (this.ratios[1] - this.ratios[0] < 0.2)) {
|
||||
return this.layoutTwoTopBottom();
|
||||
} else if(this.proportions == "ww" || this.proportions == "qq") {
|
||||
return this.layoutTwoLeftRightEqual();
|
||||
}
|
||||
return this.layoutTwoLeftRight();
|
||||
}
|
||||
|
||||
private layoutThree(): ReturnType<Layouter['layout']> {
|
||||
console.log('layoutThree:', this);
|
||||
if(this.proportions[0] == 'n') {
|
||||
return this.layoutThreeLeftAndOther();
|
||||
}
|
||||
return this.layoutThreeTopAndOther();
|
||||
}
|
||||
|
||||
private layoutFour(): ReturnType<Layouter['layout']> {
|
||||
if(this.proportions[0] == 'w') {
|
||||
return this.layoutFourTopAndOther();
|
||||
}
|
||||
return this.layoutFourLeftAndOther();
|
||||
}
|
||||
|
||||
private layoutTwoTopBottom(): ReturnType<Layouter['layout']> {
|
||||
const width = this.maxWidth;
|
||||
const height = Math.round(Math.min(
|
||||
width / this.ratios[0],
|
||||
Math.min(
|
||||
width / this.ratios[1],
|
||||
(this.maxHeight - this.spacing) / 2)));
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width, height},
|
||||
sides: RectPart.Left | RectPart.Top | RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: 0, y: height + this.spacing, width, height},
|
||||
sides: RectPart.Left | RectPart.Bottom | RectPart.Right
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutTwoLeftRightEqual(): ReturnType<Layouter['layout']> {
|
||||
const width = (this.maxWidth - this.spacing) / 2;
|
||||
const height = Math.round(Math.min(
|
||||
width / this.ratios[0],
|
||||
Math.min(width / this.ratios[1], this.maxHeight * 1)));
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width, height},
|
||||
sides: RectPart.Top | RectPart.Left | RectPart.Bottom
|
||||
},
|
||||
{
|
||||
geometry: {x: width + this.spacing, y: 0, width, height},
|
||||
sides: RectPart.Top | RectPart.Right | RectPart.Bottom
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutTwoLeftRight(): ReturnType<Layouter['layout']> {
|
||||
const minimalWidth = Math.round(this.minWidth * 1.5);
|
||||
const secondWidth = Math.min(
|
||||
Math.round(Math.max(
|
||||
0.4 * (this.maxWidth - this.spacing),
|
||||
(this.maxWidth - this.spacing) / this.ratios[0]
|
||||
/ (1 / this.ratios[0] + 1 / this.ratios[1]))),
|
||||
this.maxWidth - this.spacing - minimalWidth);
|
||||
const firstWidth = this.maxWidth
|
||||
- secondWidth
|
||||
- this.spacing;
|
||||
const height = Math.min(
|
||||
this.maxHeight,
|
||||
Math.round(Math.min(
|
||||
firstWidth / this.ratios[0],
|
||||
secondWidth / this.ratios[1])));
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width: firstWidth, height},
|
||||
sides: RectPart.Top | RectPart.Left | RectPart.Bottom
|
||||
},
|
||||
{
|
||||
geometry: {x: firstWidth + this.spacing, y: 0, width: secondWidth, height},
|
||||
sides: RectPart.Top | RectPart.Right | RectPart.Bottom
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutThreeLeftAndOther(): ReturnType<Layouter['layout']> {
|
||||
const firstHeight = this.maxHeight;
|
||||
const thirdHeight = Math.round(Math.min(
|
||||
(this.maxHeight - this.spacing) / 2.,
|
||||
(this.ratios[1] * (this.maxWidth - this.spacing)
|
||||
/ (this.ratios[2] + this.ratios[1]))));
|
||||
const secondHeight = firstHeight
|
||||
- thirdHeight
|
||||
- this.spacing;
|
||||
const rightWidth = Math.max(
|
||||
this.minWidth,
|
||||
Math.round(Math.min(
|
||||
(this.maxWidth - this.spacing) / 2.,
|
||||
Math.min(
|
||||
thirdHeight * this.ratios[2],
|
||||
secondHeight * this.ratios[1]))));
|
||||
const leftWidth = Math.min(
|
||||
Math.round(firstHeight * this.ratios[0]),
|
||||
this.maxWidth - this.spacing - rightWidth);
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width: leftWidth, height: firstHeight},
|
||||
sides: RectPart.Top | RectPart.Left | RectPart.Bottom
|
||||
},
|
||||
{
|
||||
geometry: {x: leftWidth + this.spacing, y: 0, width: rightWidth, height: secondHeight},
|
||||
sides: RectPart.Top | RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: leftWidth + this.spacing, y: secondHeight + this.spacing, width: rightWidth, height: thirdHeight},
|
||||
sides: RectPart.Bottom | RectPart.Right
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutThreeTopAndOther(): ReturnType<Layouter['layout']> {
|
||||
const firstWidth = this.maxWidth;
|
||||
const firstHeight = Math.round(Math.min(
|
||||
firstWidth / this.ratios[0],
|
||||
(this.maxHeight - this.spacing) * 0.66));
|
||||
const secondWidth = (this.maxWidth - this.spacing) / 2;
|
||||
const secondHeight = Math.min(
|
||||
this.maxHeight - firstHeight - this.spacing,
|
||||
Math.round(Math.min(
|
||||
secondWidth / this.ratios[1],
|
||||
secondWidth / this.ratios[2])));
|
||||
const thirdWidth = firstWidth - secondWidth - this.spacing;
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width: firstWidth, height: firstHeight},
|
||||
sides: RectPart.Left | RectPart.Top | RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: 0, y: firstHeight + this.spacing, width: secondWidth, height: secondHeight},
|
||||
sides: RectPart.Bottom | RectPart.Left
|
||||
},
|
||||
{
|
||||
geometry: {x: secondWidth + this.spacing, y: firstHeight + this.spacing, width: thirdWidth, height: secondHeight},
|
||||
sides: RectPart.Bottom | RectPart.Right
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutFourTopAndOther(): ReturnType<Layouter['layout']> {
|
||||
const w = this.maxWidth;
|
||||
const h0 = Math.round(Math.min(
|
||||
w / this.ratios[0],
|
||||
(this.maxHeight - this.spacing) * 0.66));
|
||||
const h = Math.round(
|
||||
(this.maxWidth - 2 * this.spacing)
|
||||
/ (this.ratios[1] + this.ratios[2] + this.ratios[3]));
|
||||
const w0 = Math.max(
|
||||
this.minWidth,
|
||||
Math.round(Math.min(
|
||||
(this.maxWidth - 2 * this.spacing) * 0.4,
|
||||
h * this.ratios[1])));
|
||||
const w2 = Math.round(Math.max(
|
||||
Math.max(
|
||||
this.minWidth * 1.,
|
||||
(this.maxWidth - 2 * this.spacing) * 0.33),
|
||||
h * this.ratios[3]));
|
||||
const w1 = w - w0 - w2 - 2 * this.spacing;
|
||||
const h1 = Math.min(
|
||||
this.maxHeight - h0 - this.spacing,
|
||||
h);
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width: w, height: h0},
|
||||
sides: RectPart.Left | RectPart.Top | RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: 0, y: h0 + this.spacing, width: w0, height: h1},
|
||||
sides: RectPart.Bottom | RectPart.Left
|
||||
},
|
||||
{
|
||||
geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},
|
||||
sides: RectPart.Bottom,
|
||||
},
|
||||
{
|
||||
geometry: {x: w0 + this.spacing + w1 + this.spacing, y: h0 + this.spacing, width: w2, height: h1},
|
||||
sides: RectPart.Right | RectPart.Bottom
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private layoutFourLeftAndOther(): ReturnType<Layouter['layout']> {
|
||||
const h = this.maxHeight;
|
||||
const w0 = Math.round(Math.min(
|
||||
h * this.ratios[0],
|
||||
(this.maxWidth - this.spacing) * 0.6));
|
||||
|
||||
const w = Math.round(
|
||||
(this.maxHeight - 2 * this.spacing)
|
||||
/ (1. / this.ratios[1] + 1. / this.ratios[2] + 1. / this.ratios[3])
|
||||
);
|
||||
const h0 = Math.round(w / this.ratios[1]);
|
||||
const h1 = Math.round(w / this.ratios[2]);
|
||||
const h2 = h - h0 - h1 - 2 * this.spacing;
|
||||
const w1 = Math.max(
|
||||
this.minWidth,
|
||||
Math.min(this.maxWidth - w0 - this.spacing, w));
|
||||
|
||||
return [
|
||||
{
|
||||
geometry: {x: 0, y: 0, width: w0, height: h},
|
||||
sides: RectPart.Top | RectPart.Left | RectPart.Bottom
|
||||
},
|
||||
{
|
||||
geometry: {x: w0 + this.spacing, y: 0, width: w1, height: h0},
|
||||
sides: RectPart.Top | RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: w0 + this.spacing, y: h0 + this.spacing, width: w1, height: h1},
|
||||
sides: RectPart.Right
|
||||
},
|
||||
{
|
||||
geometry: {x: w0 + this.spacing, y: h0 + h1 + 2 * this.spacing, width: w1, height: h2},
|
||||
sides: RectPart.Bottom | RectPart.Right
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
private static countRatios(sizes: Size[]) {
|
||||
return sizes.map(size => size.w / size.h);
|
||||
}
|
||||
|
||||
private static countProportions(ratios: number[]) {
|
||||
return ratios.map(ratio => (ratio > 1.2) ? 'w' : (ratio < 0.8) ? 'n' : 'q').join('');
|
||||
}
|
||||
}
|
||||
|
||||
class ComplexLayouter {
|
||||
private ratios: number[];
|
||||
private count: number;
|
||||
|
||||
constructor(ratios: number[], private averageRatio: number, private maxWidth: number, private minWidth: number, private spacing: number, private maxHeight = maxWidth * 4 / 3) {
|
||||
this.ratios = ComplexLayouter.cropRatios(ratios, averageRatio);
|
||||
this.count = ratios.length;
|
||||
}
|
||||
|
||||
private static cropRatios(ratios: number[], averageRatio: number) {
|
||||
const kMaxRatio = 2.75;
|
||||
const kMinRatio = 0.6667;
|
||||
return ratios.map(ratio => {
|
||||
return averageRatio > 1.1
|
||||
? snap(ratio, 1., kMaxRatio)
|
||||
: snap(ratio, kMinRatio, 1.);
|
||||
});
|
||||
}
|
||||
|
||||
public layout(): GroupMediaLayout[] {
|
||||
let result = new Array<GroupMediaLayout>(this.count);
|
||||
|
||||
let attempts: Attempt[] = [];
|
||||
const multiHeight = (offset: number, count: number) => {
|
||||
const ratios = this.ratios.slice(offset, offset + count); // warn
|
||||
const sum = accumulate(ratios, 0);
|
||||
return (this.maxWidth - (count - 1) * this.spacing) / sum;
|
||||
};
|
||||
const pushAttempt = (lineCounts: number[]) => {
|
||||
let heights: number[] = [];
|
||||
let offset = 0;
|
||||
for(let count of lineCounts) {
|
||||
heights.push(multiHeight(offset, count));
|
||||
offset += count;
|
||||
}
|
||||
attempts.push({lineCounts, heights}); // warn
|
||||
};
|
||||
|
||||
for(let first = 1; first != this.count; ++first) {
|
||||
const second = this.count - first;
|
||||
if(first > 3 || second > 3) {
|
||||
continue;
|
||||
}
|
||||
pushAttempt([first, second]);
|
||||
}
|
||||
for(let first = 1; first != this.count - 1; ++first) {
|
||||
for(let second = 1; second != this.count - first; ++second) {
|
||||
const third = this.count - first - second;
|
||||
if((first > 3)
|
||||
|| (second > ((this.averageRatio < 0.85) ? 4 : 3))
|
||||
|| (third > 3)) {
|
||||
continue;
|
||||
}
|
||||
pushAttempt([first, second, third]);
|
||||
}
|
||||
}
|
||||
for(let first = 1; first != this.count - 1; ++first) {
|
||||
for(let second = 1; second != this.count - first; ++second) {
|
||||
for(let third = 1; third != this.count - first - second; ++third) {
|
||||
const fourth = this.count - first - second - third;
|
||||
if(first > 3 || second > 3 || third > 3 || fourth > 3) {
|
||||
continue;
|
||||
}
|
||||
pushAttempt([first, second, third, fourth]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let optimalAttempt: Attempt = null;
|
||||
let optimalDiff = 0;
|
||||
for(const attempt of attempts) {
|
||||
const {heights, lineCounts: counts} = attempt;
|
||||
const lineCount = counts.length;
|
||||
const totalHeight = accumulate(heights, 0)
|
||||
+ this.spacing * (lineCount - 1);
|
||||
const minLineHeight = Math.min(...heights);
|
||||
const maxLineHeight = Math.max(...heights);
|
||||
const bad1 = (minLineHeight < this.minWidth) ? 1.5 : 1;
|
||||
const bad2 = (() => {
|
||||
for(let line = 1; line != lineCount; ++line) {
|
||||
if(counts[line - 1] > counts[line]) {
|
||||
return 1.5;
|
||||
}
|
||||
}
|
||||
return 1.;
|
||||
})();
|
||||
const diff = Math.abs(totalHeight - this.maxHeight) * bad1 * bad2;
|
||||
if(!optimalAttempt || diff < optimalDiff) {
|
||||
optimalAttempt = attempt;
|
||||
optimalDiff = diff;
|
||||
}
|
||||
}
|
||||
|
||||
const optimalCounts = optimalAttempt.lineCounts;
|
||||
const optimalHeights = optimalAttempt.heights;
|
||||
const rowCount = optimalCounts.length;
|
||||
|
||||
let index = 0;
|
||||
let y = 0;
|
||||
for(let row = 0; row != rowCount; ++row) {
|
||||
const colCount = optimalCounts[row];
|
||||
const lineHeight = optimalHeights[row];
|
||||
const height = Math.round(lineHeight);
|
||||
|
||||
let x = 0;
|
||||
for(let col = 0; col != colCount; ++col) {
|
||||
const sides = RectPart.None
|
||||
| (row == 0 ? RectPart.Top : RectPart.None)
|
||||
| (row == rowCount - 1 ? RectPart.Bottom : RectPart.None)
|
||||
| (col == 0 ? RectPart.Left : RectPart.None)
|
||||
| (col == colCount - 1 ? RectPart.Right : RectPart.None);
|
||||
|
||||
const ratio = this.ratios[index];
|
||||
const width = (col == colCount - 1)
|
||||
? (this.maxWidth - x)
|
||||
: Math.round(ratio * lineHeight);
|
||||
result[index] = {
|
||||
geometry: {x, y, width, height},
|
||||
sides
|
||||
};
|
||||
|
||||
x += width + this.spacing;
|
||||
++index;
|
||||
}
|
||||
y += height + this.spacing;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
@ -17,14 +17,15 @@ import appSidebarLeft from "./appSidebarLeft";
|
||||
import appChatsManager from "./appChatsManager";
|
||||
import appMessagesIDsManager from "./appMessagesIDsManager";
|
||||
import apiUpdatesManager from './apiUpdatesManager';
|
||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply } from '../../components/wrappers';
|
||||
import { wrapDocument, wrapPhoto, wrapVideo, wrapSticker, wrapReply, MTPhotoSize } from '../../components/wrappers';
|
||||
import ProgressivePreloader from '../../components/preloader';
|
||||
import { openBtnMenu } from '../../components/misc';
|
||||
import { openBtnMenu, renderImageFromUrl } from '../../components/misc';
|
||||
import { ChatInput } from '../../components/chatInput';
|
||||
import Scrollable from '../../components/scrollable';
|
||||
import BubbleGroups from '../../components/bubbleGroups';
|
||||
import LazyLoadQueue from '../../components/lazyLoadQueue';
|
||||
import appDocsManager from './appDocsManager';
|
||||
import { Layouter, RectPart } from '../../components/groupedLayout';
|
||||
|
||||
console.log('appImManager included!');
|
||||
|
||||
@ -1195,6 +1196,13 @@ export class AppImManager {
|
||||
public renderMessage(message: any, reverse = false, multipleRender = false, bubble: HTMLDivElement = null, updatePosition = true) {
|
||||
this.log('message to render:', message);
|
||||
if(message.deleted) return;
|
||||
else if(message.grouped_id) { // will render only last album's message
|
||||
let storage = appMessagesManager.groupedMessagesStorage[message.grouped_id];
|
||||
let maxID = Math.max(...Object.keys(storage).map(i => +i));
|
||||
if(message.mid < maxID) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let peerID = this.peerID;
|
||||
let our = message.fromID == this.myID;
|
||||
@ -1409,9 +1417,110 @@ export class AppImManager {
|
||||
|
||||
bubble.classList.add('hide-name', 'photo');
|
||||
|
||||
if(message.grouped_id) {
|
||||
bubble.classList.add('is-album');
|
||||
|
||||
let items: {size: MTPhotoSize, media: any}[] = [];
|
||||
|
||||
// higher msgID will be the last in album
|
||||
let storage = appMessagesManager.groupedMessagesStorage[message.grouped_id];
|
||||
for(let mid in storage) {
|
||||
let m = appMessagesManager.getMessage(+mid);
|
||||
let media = m.media.photo || m.media.document;
|
||||
|
||||
let size = appPhotosManager.choosePhotoSize(media, 380, 380);
|
||||
items.push({size, media});
|
||||
}
|
||||
|
||||
let spacing = 2;
|
||||
let layouter = new Layouter(items.map(i => ({w: i.size.w, h: i.size.h})), 451, 100, spacing);
|
||||
let layout = layouter.layout();
|
||||
this.log('layout:', layout);
|
||||
|
||||
/* let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');
|
||||
let brSplitted = fillPropertyValue(borderRadius); */
|
||||
|
||||
for(let {geometry, sides} of layout) {
|
||||
let {size, media} = items.shift();
|
||||
let div = document.createElement('div');
|
||||
div.classList.add('album-item');
|
||||
|
||||
div.style.width = geometry.width + 'px';
|
||||
div.style.height = geometry.height + 'px';
|
||||
div.style.top = geometry.y + 'px';
|
||||
div.style.left = geometry.x + 'px';
|
||||
|
||||
if(sides & RectPart.Right) {
|
||||
attachmentDiv.style.width = geometry.width + geometry.x + 'px';
|
||||
}
|
||||
|
||||
if(sides & RectPart.Bottom) {
|
||||
attachmentDiv.style.height = geometry.height + geometry.y + 'px';
|
||||
}
|
||||
|
||||
if(sides & RectPart.Left && sides & RectPart.Top) {
|
||||
div.style.borderTopLeftRadius = 'inherit';
|
||||
}
|
||||
|
||||
if(sides & RectPart.Left && sides & RectPart.Bottom) {
|
||||
div.style.borderBottomLeftRadius = 'inherit';
|
||||
}
|
||||
|
||||
if(sides & RectPart.Right && sides & RectPart.Top) {
|
||||
div.style.borderTopRightRadius = 'inherit';
|
||||
}
|
||||
|
||||
if(sides & RectPart.Right && sides & RectPart.Bottom) {
|
||||
div.style.borderBottomRightRadius = 'inherit';
|
||||
}
|
||||
|
||||
/* if(geometry.y != 0) {
|
||||
div.style.marginTop = spacing + 'px';
|
||||
}
|
||||
|
||||
if(geometry.x != 0) {
|
||||
div.style.marginLeft = spacing + 'px';
|
||||
} */
|
||||
|
||||
let preloader = new ProgressivePreloader(div);
|
||||
|
||||
let load = () => appPhotosManager.preloadPhoto(media._ == 'photo' ? media.id : media, size)
|
||||
.then((blob) => {
|
||||
if(this.peerID != peerID) {
|
||||
this.log.warn('peer changed');
|
||||
return;
|
||||
}
|
||||
|
||||
preloader.detach();
|
||||
if(media && media.url) {
|
||||
renderImageFromUrl(div, media.url);
|
||||
}/* else {
|
||||
let url = URL.createObjectURL(blob);
|
||||
this.urlsToRevoke.push(url);
|
||||
|
||||
let img = new Image();
|
||||
img.src = url;
|
||||
img.onload = () => {
|
||||
div.style.backgroundImage = 'url(' + url + ')';
|
||||
};
|
||||
} */
|
||||
|
||||
//div.style.backgroundImage = 'url(' + url + ')';
|
||||
});
|
||||
|
||||
load();
|
||||
|
||||
// @ts-ignore
|
||||
//div.style.backgroundColor = '#' + Math.floor(Math.random() * (2 ** 24 - 1)).toString(16).padStart(6, '0');
|
||||
|
||||
attachmentDiv.append(div);
|
||||
}
|
||||
} else {
|
||||
wrapPhoto(photo.id, message, attachmentDiv, undefined, undefined, true, our, this.lazyLoadQueue, () => {
|
||||
return this.peerID == peerID;
|
||||
});
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ import appMessagesManager from "./appMessagesManager";
|
||||
import { RichTextProcessor } from "../richtextprocessor";
|
||||
import { logger } from "../polyfill";
|
||||
import ProgressivePreloader from "../../components/preloader";
|
||||
import { findUpClassName, $rootScope, generatePathData } from "../utils";
|
||||
import { findUpClassName, $rootScope, generatePathData, fillPropertyValue } from "../utils";
|
||||
import appDocsManager from "./appDocsManager";
|
||||
import VideoPlayer from "../mediaPlayer";
|
||||
import { renderImageFromUrl } from "../../components/misc";
|
||||
@ -213,13 +213,7 @@ export class AppMediaViewer {
|
||||
}
|
||||
|
||||
let borderRadius = window.getComputedStyle(realParent).getPropertyValue('border-radius');
|
||||
let brSplitted = borderRadius.split(' ');
|
||||
if(brSplitted.length != 4) {
|
||||
if(!brSplitted[0]) brSplitted[0] = '0px';
|
||||
for(let i = brSplitted.length; i < 4; ++i) {
|
||||
brSplitted[i] = brSplitted[i % 2] || brSplitted[0] || '0px';
|
||||
}
|
||||
}
|
||||
let brSplitted = fillPropertyValue(borderRadius) as string[];
|
||||
borderRadius = brSplitted.map(r => (parseInt(r) / scaleX) + 'px').join(' ');
|
||||
if(!wasActive) {
|
||||
mover.style.borderRadius = borderRadius;
|
||||
|
@ -632,6 +632,18 @@ export function encodeEntities (value) {
|
||||
}).replace(/</g, '<').replace(/>/g, '>')
|
||||
}
|
||||
|
||||
export function fillPropertyValue(str) {
|
||||
let splitted = str.split(' ');
|
||||
if(splitted.length != 4) {
|
||||
if(!splitted[0]) splitted[0] = '0px';
|
||||
for(let i = splitted.length; i < 4; ++i) {
|
||||
splitted[i] = splitted[i % 2] || splitted[0] || '0px';
|
||||
}
|
||||
}
|
||||
|
||||
return splitted;
|
||||
}
|
||||
|
||||
export function calcImageInBox (imageW, imageH, boxW, boxH, noZooom) {
|
||||
if(imageW < boxW && imageH < boxH) {
|
||||
return {w: imageW, h: imageH};
|
||||
|
@ -555,6 +555,23 @@ $chat-max-width: 696px;
|
||||
}
|
||||
}
|
||||
|
||||
&.is-album {
|
||||
.attachment {
|
||||
max-width: 451px;
|
||||
max-height: none;
|
||||
|
||||
> div {
|
||||
background-color: #000;
|
||||
background-size: cover;
|
||||
background-position: center center;
|
||||
/* flex: 1 0 auto; */
|
||||
max-width: 100%;
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//&.video {
|
||||
//.attachment {
|
||||
//max-height: fit-content;
|
||||
|
@ -59,15 +59,16 @@
|
||||
}
|
||||
|
||||
li {
|
||||
padding: 2px 0;
|
||||
//padding: 0 0 2px 0;
|
||||
padding-bottom: 4px;
|
||||
//overflow: hidden;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
li > .rp {
|
||||
height: 70px;
|
||||
max-height: 70px;
|
||||
border-radius: $border-radius;
|
||||
height: 72px;
|
||||
max-height: 72px;
|
||||
border-radius: $border-radius-medium;
|
||||
//align-items: center;
|
||||
/* display: grid;
|
||||
grid-template-columns: 64px calc(100% - 64px - 6.5px); */
|
||||
@ -76,8 +77,8 @@
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
padding: 7px 8.5px;
|
||||
margin: 0px 8px 2px 7px;
|
||||
padding: 9px 8.5px;
|
||||
margin: 0px 8px 0px 7px;
|
||||
overflow: hidden;
|
||||
|
||||
&:hover {
|
||||
@ -91,7 +92,7 @@
|
||||
|
||||
.pinned-delimiter {
|
||||
display: flex;
|
||||
padding: 6px 0 6px;
|
||||
padding: 8px 0 4px;
|
||||
|
||||
span {
|
||||
margin: 0;
|
||||
@ -271,6 +272,12 @@
|
||||
&-contacts {
|
||||
padding: 16px 0 7px;
|
||||
|
||||
li {
|
||||
//margin-bottom: 2px;
|
||||
padding-bottom: 4px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
li > .rp {
|
||||
padding: 9px 11.5px !important;
|
||||
height: 66px;
|
||||
|
Loading…
x
Reference in New Issue
Block a user