mirror of https://github.com/procxx/kepka.git
Merge branch 'master' of https://github.com/telegramdesktop/tdesktop
This commit is contained in:
commit
1f77e22ed2
|
@ -121,6 +121,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
"lng_bad_name" = "Please enter your first and last name.";
|
||||
"lng_bad_photo" = "Bad image selected.";
|
||||
|
||||
"lng_bad_image_for_photo" = "This image can't be sent that way.\nWould you like to send it as a document?";
|
||||
|
||||
"lng_signup_title" = "Information and photo";
|
||||
"lng_signup_desc" = "Please enter your name and\nupload a photo.";
|
||||
|
||||
|
@ -326,6 +328,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
"lng_in_dlg_audio" = "Audio";
|
||||
"lng_in_dlg_document" = "Document";
|
||||
"lng_in_dlg_sticker" = "Sticker";
|
||||
"lng_in_dlg_sticker_emoji" = "{emoji} (sticker)";
|
||||
|
||||
"lng_send_button" = "Send";
|
||||
"lng_message_ph" = "Write a message..";
|
||||
|
@ -450,6 +453,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
|||
"lng_new_authorization" = "{name},\nWe detected a login into your account from a new device on {day}, {date} at {time}\n\nDevice: {device}\nLocation: {location}\n\nIf this wasn't you, you can go to Settings — Terminate other sessions.\n\nThanks,\nThe Telegram Team";
|
||||
|
||||
"lng_new_version7005" = "Telegram Desktop was updated to version {version}\n\n — Stickers support\n — Local caching for voice messages\n — Added Portuguese language\n\nFull version history is available here:\n{link}";
|
||||
"lng_new_version7006_appstore" = "Telegram Desktop was updated to version {version}\n\n — Stickers support\n — Local caching for voice messages\n — Added new languages\n\nFull version history is available here:\n{link}";
|
||||
|
||||
// Mac specific
|
||||
|
||||
|
|
|
@ -1627,7 +1627,7 @@ btnContext: iconedButton(btnDefIconed) {
|
|||
opacity: 1;
|
||||
overOpacity: 1;
|
||||
|
||||
width: 172px;
|
||||
width: -32px;
|
||||
height: 36px;
|
||||
|
||||
color: black;
|
||||
|
@ -1655,9 +1655,9 @@ mediaviewLoader: size(78px, 33px);
|
|||
mediaviewLoaderPoint: size(9px, 9px);
|
||||
mediaviewLoaderSkip: 9px;
|
||||
|
||||
minPhotoWidth: 90px;
|
||||
minPhotoHeight: 90px;
|
||||
minPhotoSize: 90px;
|
||||
maxMediaSize: 420px;
|
||||
maxStickerSize: 256px;
|
||||
|
||||
usernameFont: font(14px);
|
||||
usernameColor: #777;
|
||||
|
|
|
@ -1292,6 +1292,8 @@ namespace App {
|
|||
documentsData.clear();
|
||||
cSetRecentStickers(RecentStickerPack());
|
||||
cSetStickersHash(QByteArray());
|
||||
cSetStickers(AllStickers());
|
||||
cSetEmojiStickers(EmojiStickersMap());
|
||||
::videoItems.clear();
|
||||
::audioItems.clear();
|
||||
::documentItems.clear();
|
||||
|
@ -2013,7 +2015,7 @@ namespace App {
|
|||
}
|
||||
exif_data_free(exifData);
|
||||
}
|
||||
} else if (opaque) {
|
||||
} else if (opaque && result.hasAlphaChannel()) {
|
||||
QImage solid(result.width(), result.height(), QImage::Format_ARGB32_Premultiplied);
|
||||
solid.fill(st::white->c);
|
||||
{
|
||||
|
|
|
@ -481,7 +481,7 @@ void Application::uploadProfilePhoto(const QImage &tosend, const PeerId &peerId)
|
|||
int32 filesize = 0;
|
||||
QByteArray data;
|
||||
|
||||
ReadyLocalMedia ready(ToPreparePhoto, file, filename, filesize, data, id, id, peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false);
|
||||
ReadyLocalMedia ready(ToPreparePhoto, file, filename, filesize, data, id, id, qsl("jpg"), peerId, photo, photoThumbs, MTP_documentEmpty(MTP_long(0)), jpeg, false);
|
||||
|
||||
connect(App::uploader(), SIGNAL(photoReady(MsgId, const MTPInputFile &)), App::app(), SLOT(photoUpdated(MsgId, const MTPInputFile &)), Qt::UniqueConnection);
|
||||
|
||||
|
|
|
@ -89,6 +89,7 @@ void ConfirmBox::mousePressEvent(QMouseEvent *e) {
|
|||
textlnkDown(textlnkOver());
|
||||
update();
|
||||
}
|
||||
return LayeredWidget::mousePressEvent(e);
|
||||
}
|
||||
|
||||
void ConfirmBox::mouseReleaseEvent(QMouseEvent *e) {
|
||||
|
|
|
@ -57,7 +57,7 @@ PhotoCropBox::PhotoCropBox(const QImage &img, const PeerId &peer) : _downState(0
|
|||
}
|
||||
|
||||
void PhotoCropBox::mousePressEvent(QMouseEvent *e) {
|
||||
if (e->button() != Qt::LeftButton) return;
|
||||
if (e->button() != Qt::LeftButton) return LayeredWidget::mousePressEvent(e);
|
||||
|
||||
_downState = mouseState(e->pos());
|
||||
_fromposx = e->pos().x();
|
||||
|
@ -65,6 +65,8 @@ void PhotoCropBox::mousePressEvent(QMouseEvent *e) {
|
|||
_fromcropx = _cropx;
|
||||
_fromcropy = _cropy;
|
||||
_fromcropw = _cropw;
|
||||
|
||||
return LayeredWidget::mousePressEvent(e);
|
||||
}
|
||||
|
||||
int32 PhotoCropBox::mouseState(QPoint p) {
|
||||
|
|
|
@ -86,7 +86,9 @@ enum {
|
|||
AudioVoiceMsgChannels = 2, // stereo
|
||||
AudioVoiceMsgBufferSize = 1024 * 1024, // 1 Mb buffers
|
||||
AudioVoiceMsgInMemory = 1024 * 1024, // 1 Mb audio is hold in memory and auto loaded
|
||||
StickerInMemory = 128 * 1024, // 128 Kb stickers hold in memory, auto loaded and displayed inline
|
||||
|
||||
StickerInMemory = 256 * 1024, // 128 Kb stickers hold in memory, auto loaded and displayed inline
|
||||
StickerMaxSize = 1280, // 1024x1024 is a max image size for sticker
|
||||
|
||||
MediaViewImageSizeLimit = 100 * 1024 * 1024, // show up to 100mb jpg/png/gif docs in app
|
||||
MaxZoomLevel = 7, // x8
|
||||
|
|
|
@ -365,13 +365,15 @@ void EmojiPanInner::paintEvent(QPaintEvent *e) {
|
|||
}
|
||||
|
||||
float64 coef = qMin((stickerWidth - st::stickerPanPadding * 2) / float64(sticker->dimensions.width()), (stickerSize - st::stickerPanPadding * 2) / float64(sticker->dimensions.height()));
|
||||
if (coef > 1) coef = 1;
|
||||
int32 w = qRound(coef * sticker->dimensions.width()), h = qRound(coef * sticker->dimensions.height());
|
||||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
QPoint ppos = pos + QPoint((stickerSize - w) / 2, (stickerSize - h) / 2);
|
||||
|
||||
if (sticker->sticker->isNull()) {
|
||||
p.drawPixmap(ppos, sticker->thumb->pix(w));
|
||||
p.drawPixmap(ppos, sticker->thumb->pix(w, h));
|
||||
} else {
|
||||
p.drawPixmap(ppos, sticker->sticker->pix(w));
|
||||
p.drawPixmap(ppos, sticker->sticker->pix(w, h));
|
||||
}
|
||||
|
||||
if (hover > 0 && _isUserGen[index]) {
|
||||
|
|
|
@ -116,7 +116,7 @@ void FileUploader::sendNext() {
|
|||
|
||||
MTPInputFile doc = (i->docSize > UseBigFilesFrom) ? MTP_inputFileBig(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename)) : MTP_inputFile(MTP_long(i->media.id), MTP_int(i->docPartsCount), MTP_string(i->media.filename), MTP_string(docMd5));
|
||||
if (i->partsCount) {
|
||||
emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->media.jpeg_id), MTP_int(i->partsCount), MTP_string(i->media.filename), MTP_string(i->media.jpeg_md5)));
|
||||
emit thumbDocumentReady(uploading, doc, MTP_inputFile(MTP_long(i->media.thumbId), MTP_int(i->partsCount), MTP_string(qsl("thumb.") + i->media.thumbExt), MTP_string(i->media.jpeg_md5)));
|
||||
} else {
|
||||
emit documentReady(uploading, doc);
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ void FileUploader::sendNext() {
|
|||
} else {
|
||||
LocalFileParts::iterator part = i->media.parts.begin();
|
||||
|
||||
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.jpeg_id), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
|
||||
mtpRequestId requestId = MTP::send(MTPupload_SaveFilePart(MTP_long(i->media.thumbId), MTP_int(part.key()), MTP_string(part.value())), rpcDone(&FileUploader::partLoaded), rpcFail(&FileUploader::partFailed), MTP::upl[todc]);
|
||||
requestsSent.insert(requestId, part.value());
|
||||
dcMap.insert(requestId, todc);
|
||||
sentSize += part.value().size();
|
||||
|
|
|
@ -47,6 +47,7 @@ QAction *ContextMenu::addAction(const QString &text, const QObject *receiver, co
|
|||
connect(b, SIGNAL(stateChanged(int,ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int,ButtonStateChangeSource)));
|
||||
|
||||
_width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + b->width()));
|
||||
for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height());
|
||||
_height += b->height();
|
||||
|
||||
resize(_width, _height);
|
||||
|
@ -61,6 +62,8 @@ ContextMenu::Actions &ContextMenu::actions() {
|
|||
void ContextMenu::actionChanged() {
|
||||
for (int32 i = 0, l = _actions.size(); i < l; ++i) {
|
||||
_buttons[i]->setText(_actions[i]->text());
|
||||
_width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + _buttons[i]->width()));
|
||||
_buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -297,21 +297,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
|
|||
uint32 index = imageName.mid(8).toUInt(0, 16);
|
||||
const EmojiData *emoji = getEmoji(index);
|
||||
if (emoji) {
|
||||
emojiText.reserve(emoji->len + (emoji->postfix ? 1 : 0));
|
||||
switch (emoji->len) {
|
||||
case 1: emojiText.append(QChar(emoji->code & 0xFFFF)); break;
|
||||
case 2:
|
||||
emojiText.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
emojiText.append(QChar(emoji->code & 0xFFFF));
|
||||
break;
|
||||
case 4:
|
||||
emojiText.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
emojiText.append(QChar(emoji->code & 0xFFFF));
|
||||
emojiText.append(QChar((emoji->code2 >> 16) & 0xFFFF));
|
||||
emojiText.append(QChar(emoji->code2 & 0xFFFF));
|
||||
break;
|
||||
}
|
||||
if (emoji->postfix) emojiText.append(QChar(emoji->postfix));
|
||||
emojiText = textEmojiString(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
|||
w *= cIntRetinaFactor();
|
||||
h *= cIntRetinaFactor();
|
||||
}
|
||||
uint64 k = 0x8000000000000000LL | (uint64(w) << 32) | uint64(h);
|
||||
uint64 k = 0x1000000000000000LL | (uint64(w) << 32) | uint64(h);
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend()) {
|
||||
QPixmap p(pixBlurredNoCache(w, h));
|
||||
|
@ -92,6 +92,52 @@ const QPixmap &Image::pixBlurred(int32 w, int32 h) const {
|
|||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixColored(const style::color &add, int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
w = width() * cIntRetinaFactor();
|
||||
} else if (cRetina()) {
|
||||
w *= cIntRetinaFactor();
|
||||
h *= cIntRetinaFactor();
|
||||
}
|
||||
uint64 k = 0x2000000000000000LL | (uint64(w) << 32) | uint64(h);
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend()) {
|
||||
QPixmap p(pixColoredNoCache(add, w, h, true));
|
||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixBlurredColored(const style::color &add, int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
||||
if (w <= 0 || !width() || !height()) {
|
||||
w = width() * cIntRetinaFactor();
|
||||
} else if (cRetina()) {
|
||||
w *= cIntRetinaFactor();
|
||||
h *= cIntRetinaFactor();
|
||||
}
|
||||
uint64 k = 0x3000000000000000LL | (uint64(w) << 32) | uint64(h);
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend()) {
|
||||
QPixmap p(pixBlurredColoredNoCache(add, w, h));
|
||||
if (cRetina()) p.setDevicePixelRatio(cRetinaFactor());
|
||||
i = _sizesCache.insert(k, p);
|
||||
if (!p.isNull()) {
|
||||
globalAquiredSize += int64(p.width()) * p.height() * 4;
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
const QPixmap &Image::pixSingle(int32 w, int32 h) const {
|
||||
restore();
|
||||
checkload();
|
||||
|
@ -128,7 +174,7 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h) const {
|
|||
w *= cIntRetinaFactor();
|
||||
h *= cIntRetinaFactor();
|
||||
}
|
||||
uint64 k = 0x8000000000000000LL | 0LL;
|
||||
uint64 k = 0x1000000000000000LL | 0LL;
|
||||
Sizes::const_iterator i = _sizesCache.constFind(k);
|
||||
if (i == _sizesCache.cend() || i->width() != w || (h && i->height() != h)) {
|
||||
if (i != _sizesCache.cend()) {
|
||||
|
@ -146,29 +192,40 @@ const QPixmap &Image::pixBlurredSingle(int32 w, int32 h) const {
|
|||
|
||||
namespace {
|
||||
static inline uint64 _blurGetColors(const uchar *p) {
|
||||
return p[0] + (p[1] << 16) + ((uint64)p[2] << 32);
|
||||
return (uint64)p[0] + ((uint64)p[1] << 16) + ((uint64)p[2] << 32) + ((uint64)p[3] << 48);
|
||||
}
|
||||
}
|
||||
|
||||
QImage imageBlur(QImage img) {
|
||||
QImage::Format fmt = img.format();
|
||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
||||
QImage tmp(img.width(), img.height(), QImage::Format_ARGB32);
|
||||
{
|
||||
QPainter p(&tmp);
|
||||
p.drawImage(0, 0, img);
|
||||
}
|
||||
img = tmp;
|
||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
||||
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
uchar *pix = img.bits();
|
||||
if (pix) {
|
||||
const int w = img.width(), h = img.height(), stride = w * 4;
|
||||
const int radius = 7;
|
||||
int w = img.width(), h = img.height(), wold = w, hold = h;
|
||||
const int radius = 3;
|
||||
const int r1 = radius + 1;
|
||||
const int div = radius * 2 + 1;
|
||||
|
||||
const int stride = w * 4;
|
||||
if (radius < 16 && div < w && div < h && stride <= w * 4) {
|
||||
bool withalpha = img.hasAlphaChannel();
|
||||
if (withalpha) {
|
||||
QImage imgsmall(w, h, img.format());
|
||||
{
|
||||
QPainter p(&imgsmall);
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
p.fillRect(0, 0, w, h, st::transparent->b);
|
||||
p.drawImage(QRect(radius, radius, w - 2 * radius, h - 2 * radius), img, QRect(0, 0, w, h));
|
||||
}
|
||||
QImage was = img;
|
||||
img = imgsmall;
|
||||
imgsmall = QImage();
|
||||
pix = img.bits();
|
||||
if (!pix) return was;
|
||||
}
|
||||
uint64 *rgb = new uint64[w * h];
|
||||
|
||||
int x, y, i;
|
||||
|
@ -189,7 +246,7 @@ QImage imageBlur(QImage img) {
|
|||
x = 0;
|
||||
|
||||
#define update(start, middle, end) \
|
||||
rgb[y * w + x] = (rgbsum >> 6) & 0x00FF00FF00FF00FFLL; \
|
||||
rgb[y * w + x] = (rgbsum >> 4) & 0x00FF00FF00FF00FFLL; \
|
||||
rgballsum += _blurGetColors(&pix[yw + (start) * 4]) - 2 * _blurGetColors(&pix[yw + (middle) * 4]) + _blurGetColors(&pix[yw + (end) * 4]); \
|
||||
rgbsum += rgballsum; \
|
||||
x++;
|
||||
|
@ -222,10 +279,11 @@ x++;
|
|||
int yi = x * 4;
|
||||
|
||||
#define update(start, middle, end) \
|
||||
uint64 res = rgbsum >> 6; \
|
||||
uint64 res = rgbsum >> 4; \
|
||||
pix[yi] = res & 0xFF; \
|
||||
pix[yi + 1] = (res >> 16) & 0xFF; \
|
||||
pix[yi + 2] = (res >> 32) & 0xFF; \
|
||||
pix[yi + 3] = (res >> 48) & 0xFF; \
|
||||
rgballsum += rgb[x + (start) * w] - 2 * rgb[x + (middle) * w] + rgb[x + (end) * w]; \
|
||||
rgbsum += rgballsum; \
|
||||
y++; \
|
||||
|
@ -250,6 +308,42 @@ yi += stride;
|
|||
return img;
|
||||
}
|
||||
|
||||
QImage imageColored(const style::color &add, QImage img) {
|
||||
QImage::Format fmt = img.format();
|
||||
if (fmt != QImage::Format_RGB32 && fmt != QImage::Format_ARGB32_Premultiplied) {
|
||||
img = img.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
}
|
||||
|
||||
uchar *pix = img.bits();
|
||||
if (pix) {
|
||||
int ca = int(add->c.alphaF() * 0xFF), cr = int(add->c.redF() * 0xFF), cg = int(add->c.greenF() * 0xFF), cb = int(add->c.blueF() * 0xFF);
|
||||
const int w = img.width(), h = img.height(), size = w * h * 4;
|
||||
for (int32 i = 0; i < size; i += 4) {
|
||||
int b = pix[i], g = pix[i + 1], r = pix[i + 2], a = pix[i + 3], aca = a * ca;
|
||||
pix[i + 0] = uchar(b + ((aca * (cb - b)) >> 16));
|
||||
pix[i + 1] = uchar(g + ((aca * (cg - g)) >> 16));
|
||||
pix[i + 2] = uchar(r + ((aca * (cr - r)) >> 16));
|
||||
pix[i + 3] = uchar(a + ((aca * (0xFF - a)) >> 16));
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth) const {
|
||||
restore();
|
||||
loaded();
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) {
|
||||
return blank()->pix();
|
||||
}
|
||||
if (w <= 0 || !width() || !height() || w == width() && (h <= 0 || h == height())) return p;
|
||||
if (h <= 0) {
|
||||
return QPixmap::fromImage(p.toImage().scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation), Qt::ColorOnly);
|
||||
}
|
||||
return QPixmap::fromImage(p.toImage().scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
QPixmap Image::pixBlurredNoCache(int32 w, int32 h) const {
|
||||
restore();
|
||||
loaded();
|
||||
|
@ -267,22 +361,36 @@ QPixmap Image::pixBlurredNoCache(int32 w, int32 h) const {
|
|||
return QPixmap::fromImage(img, Qt::ColorOnly);
|
||||
}
|
||||
|
||||
QPixmap Image::pixNoCache(int32 w, int32 h, bool smooth) const {
|
||||
QPixmap Image::pixColoredNoCache(const style::color &add, int32 w, int32 h, bool smooth) const {
|
||||
restore();
|
||||
loaded();
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) {
|
||||
if (this == blank()) {
|
||||
int a = 0;
|
||||
}
|
||||
return blank()->pix();
|
||||
}
|
||||
if (w <= 0 || !width() || !height() || w == width()) return p;
|
||||
if (w <= 0 || !width() || !height() || w == width() && (h <= 0 || h == height())) return QPixmap::fromImage(imageColored(add, p.toImage()));
|
||||
if (h <= 0) {
|
||||
return QPixmap::fromImage(p.toImage().scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation), Qt::ColorOnly);
|
||||
return QPixmap::fromImage(imageColored(add, p.toImage().scaledToWidth(w, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
}
|
||||
return QPixmap::fromImage(p.toImage().scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation), Qt::ColorOnly);
|
||||
return QPixmap::fromImage(imageColored(add, p.toImage().scaled(w, h, Qt::IgnoreAspectRatio, smooth ? Qt::SmoothTransformation : Qt::FastTransformation)), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
QPixmap Image::pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h) const {
|
||||
restore();
|
||||
loaded();
|
||||
|
||||
const QPixmap &p(pixData());
|
||||
if (p.isNull()) return blank()->pix();
|
||||
|
||||
QImage img = imageBlur(p.toImage());
|
||||
if (h <= 0) {
|
||||
img = img.scaledToWidth(w, Qt::SmoothTransformation);
|
||||
} else {
|
||||
img = img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
}
|
||||
|
||||
return QPixmap::fromImage(imageColored(add, img), Qt::ColorOnly);
|
||||
}
|
||||
|
||||
void Image::forget() const {
|
||||
|
|
|
@ -34,10 +34,14 @@ public:
|
|||
}
|
||||
const QPixmap &pix(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixBlurred(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixBlurredColored(const style::color &add, int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixSingle(int32 w = 0, int32 h = 0) const;
|
||||
const QPixmap &pixBlurredSingle(int32 w = 0, int32 h = 0) const;
|
||||
QPixmap pixNoCache(int32 w = 0, int32 h = 0, bool smooth = false) const;
|
||||
QPixmap pixBlurredNoCache(int32 w, int32 h = 0) const;
|
||||
QPixmap pixColoredNoCache(const style::color &add, int32 w = 0, int32 h = 0, bool smooth = false) const;
|
||||
QPixmap pixBlurredColoredNoCache(const style::color &add, int32 w, int32 h = 0) const;
|
||||
|
||||
virtual int32 width() const = 0;
|
||||
virtual int32 height() const = 0;
|
||||
|
|
|
@ -336,6 +336,26 @@ const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink)
|
|||
return (result < end && *result == TextCommand) ? (result + 1) : from;
|
||||
}
|
||||
|
||||
QString textEmojiString(EmojiPtr emoji) {
|
||||
QString result;
|
||||
result.reserve(emoji->len + (emoji->postfix ? 1 : 0));
|
||||
switch (emoji->len) {
|
||||
case 1: result.append(QChar(emoji->code & 0xFFFF)); break;
|
||||
case 2:
|
||||
result.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
break;
|
||||
case 4:
|
||||
result.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
result.append(QChar((emoji->code2 >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code2 & 0xFFFF));
|
||||
break;
|
||||
}
|
||||
if (emoji->postfix) result.append(QChar(emoji->postfix));
|
||||
return result;
|
||||
}
|
||||
|
||||
class TextParser {
|
||||
public:
|
||||
|
||||
|
|
|
@ -470,3 +470,5 @@ QString textcmdLink(const QString &url, const QString &text);
|
|||
QString textcmdStartColor(const style::color &color);
|
||||
QString textcmdStopColor();
|
||||
const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink = true);
|
||||
|
||||
QString textEmojiString(EmojiPtr emoji);
|
||||
|
|
|
@ -2147,12 +2147,14 @@ HistoryItem *regItem(HistoryItem *item, bool returnExisting) {
|
|||
}
|
||||
|
||||
HistoryPhoto::HistoryPhoto(const MTPDphoto &photo, int32 width) : HistoryMedia(width)
|
||||
, pixw(1), pixh(1)
|
||||
, data(App::feedPhoto(photo))
|
||||
, openl(new PhotoLink(data)) {
|
||||
init();
|
||||
}
|
||||
|
||||
HistoryPhoto::HistoryPhoto(PeerData *chat, const MTPDphoto &photo, int32 width) : HistoryMedia(width)
|
||||
, pixw(1), pixh(1)
|
||||
, data(App::feedPhoto(photo))
|
||||
, openl(new PhotoLink(data, chat)) {
|
||||
init();
|
||||
|
@ -2174,18 +2176,13 @@ void HistoryPhoto::initDimensions(const HistoryItem *parent) {
|
|||
} else {
|
||||
thumbh = w; // square chat photo updates
|
||||
}
|
||||
_maxw = w;
|
||||
_height = _minh = thumbh;
|
||||
if (_maxw < st::minPhotoWidth) {
|
||||
_maxw = st::minPhotoWidth;
|
||||
}
|
||||
if (_height < st::minPhotoHeight) {
|
||||
_height = st::minPhotoHeight;
|
||||
}
|
||||
_maxw = qMax(w, int32(st::minPhotoSize));
|
||||
_minh = qMax(thumbh, int32(st::minPhotoSize));
|
||||
_height = resize(w, true, parent);
|
||||
}
|
||||
|
||||
int32 HistoryPhoto::resize(int32 width, bool dontRecountText, const HistoryItem *parent) {
|
||||
w = qMin(width, _maxw);
|
||||
pixw = qMin(width, _maxw);
|
||||
|
||||
int32 tw = convertScale(data->full->width()), th = convertScale(data->full->height());
|
||||
if (tw > st::maxMediaSize) {
|
||||
|
@ -2196,22 +2193,20 @@ int32 HistoryPhoto::resize(int32 width, bool dontRecountText, const HistoryItem
|
|||
tw = (st::maxMediaSize * tw) / th;
|
||||
th = st::maxMediaSize;
|
||||
}
|
||||
_height = th;
|
||||
if (tw > w) {
|
||||
_height = (w * _height / tw);
|
||||
pixh = th;
|
||||
if (tw > pixw) {
|
||||
pixh = (pixw * pixh / tw);
|
||||
} else {
|
||||
w = tw;
|
||||
pixw = tw;
|
||||
}
|
||||
if (_height > width) {
|
||||
w = (w * width) / _height;
|
||||
_height = width;
|
||||
}
|
||||
if (w < st::minPhotoWidth) {
|
||||
w = st::minPhotoWidth;
|
||||
}
|
||||
if (_height < st::minPhotoHeight) {
|
||||
_height = st::minPhotoHeight;
|
||||
if (pixh > width) {
|
||||
pixw = (pixw * width) / pixh;
|
||||
pixh = width;
|
||||
}
|
||||
if (pixw < 1) pixw = 1;
|
||||
if (pixh < 1) pixh = 1;
|
||||
w = qMax(pixw, int16(st::minPhotoSize));
|
||||
_height = qMax(pixh, int16(st::minPhotoSize));
|
||||
return _height;
|
||||
}
|
||||
|
||||
|
@ -2281,16 +2276,14 @@ void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
bool full = data->full->loaded();
|
||||
QPixmap pix;
|
||||
if (full) {
|
||||
pix = data->full->pixSingle(width);
|
||||
pix = data->full->pixSingle(pixw, pixh);
|
||||
} else {
|
||||
pix = data->thumb->pixBlurredSingle(width);
|
||||
pix = data->thumb->pixBlurredSingle(pixw, pixh);
|
||||
}
|
||||
if (pix.height() >= _height * cIntRetinaFactor()) {
|
||||
p.drawPixmap(QPoint(0, 0), pix, QRect(0, (pix.height() - _height * cIntRetinaFactor()) / 2, width * cIntRetinaFactor(), _height * cIntRetinaFactor()));
|
||||
} else {
|
||||
int32 usewidth = (width * pix.height()) / (_height * cIntRetinaFactor());
|
||||
p.drawPixmap(QRect(0, 0, width, _height), pix, QRect((width - usewidth) * cIntRetinaFactor() / 2, 0, usewidth * cIntRetinaFactor(), pix.height()));
|
||||
if (pixw < width || pixh < _height) {
|
||||
p.fillRect(QRect(0, 0, width, _height), st::black->b);
|
||||
}
|
||||
p.drawPixmap(QPoint((width - pixw) / 2, (_height - pixh) / 2), pix);
|
||||
if (!full) {
|
||||
uint64 dt = itemAnimations().animate(parent, getms());
|
||||
int32 cnt = int32(st::photoLoaderCnt), period = int32(st::photoLoaderPeriod), t = dt % period, delta = int32(st::photoLoaderDelta);
|
||||
|
@ -2330,6 +2323,9 @@ void HistoryPhoto::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
int32 dateH = _height - dateY - st::msgDateImgDelta;
|
||||
|
||||
p.fillRect(dateX, dateY, dateW, dateH, st::msgDateImgBg->b);
|
||||
if (selected) {
|
||||
p.fillRect(dateX, dateY, dateW, dateH, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
p.setFont(st::msgDateFont->f);
|
||||
p.setPen(st::msgDateImgColor->p);
|
||||
p.drawText(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y() + st::msgDateFont->ascent, time);
|
||||
|
@ -2662,7 +2658,7 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, i
|
|||
}
|
||||
p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), App::sprite(), img);
|
||||
if (selected) {
|
||||
p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b);
|
||||
p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
|
||||
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
|
||||
|
@ -2844,7 +2840,7 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
|
|||
if (width >= animated.w) {
|
||||
p.drawPixmap(0, 0, animated.frames[animated.frame]);
|
||||
if (selected) {
|
||||
p.fillRect(0, 0, animated.w, animated.h, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b);
|
||||
p.fillRect(0, 0, animated.w, animated.h, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
} else {
|
||||
bool s = p.renderHints().testFlag(QPainter::SmoothPixmapTransform);
|
||||
|
@ -2854,7 +2850,7 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
|
|||
p.drawPixmap(QRect(0, 0, width, h), animated.frames[animated.frame]);
|
||||
if (!s) p.setRenderHint(QPainter::SmoothPixmapTransform, false);
|
||||
if (selected) {
|
||||
p.fillRect(0, 0, width, h, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b);
|
||||
p.fillRect(0, 0, width, h, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
}
|
||||
return;
|
||||
|
@ -2898,7 +2894,7 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
|
|||
p.drawPixmap(QPoint(st::mediaPadding.left(), st::mediaPadding.top()), App::sprite(), (out ? st::mediaDocOutImg : st::mediaDocInImg));
|
||||
}
|
||||
if (selected) {
|
||||
p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b);
|
||||
p.fillRect(st::mediaPadding.left(), st::mediaPadding.top(), st::mediaThumbSize, st::mediaThumbSize, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
|
||||
int32 tleft = st::mediaPadding.left() + st::mediaThumbSize + st::mediaPadding.right();
|
||||
|
@ -3058,22 +3054,38 @@ HistoryMedia *HistoryDocument::clone() const {
|
|||
}
|
||||
|
||||
HistorySticker::HistorySticker(DocumentData *document, int32 width) : HistoryMedia(width)
|
||||
, data(document)
|
||||
, pixw(1), pixh(1), data(document)
|
||||
{
|
||||
data->thumb->load();
|
||||
updateStickerEmoji();
|
||||
}
|
||||
|
||||
bool HistorySticker::updateStickerEmoji() {
|
||||
const EmojiStickersMap &stickers(cEmojiStickers());
|
||||
EmojiStickersMap::const_iterator i = stickers.constFind(data);
|
||||
QString emoji = (i == stickers.cend()) ? QString() : textEmojiString(i.value());
|
||||
if (emoji != _emoji) {
|
||||
_emoji = emoji;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void HistorySticker::initDimensions(const HistoryItem *parent) {
|
||||
_maxw = data->dimensions.width();
|
||||
_minh = data->dimensions.height();
|
||||
if (_maxw > st::msgMinWidth) {
|
||||
_minh = (st::msgMinWidth * _minh) / _maxw;
|
||||
_maxw = st::msgMinWidth;
|
||||
pixw = data->dimensions.width();
|
||||
pixh = data->dimensions.height();
|
||||
if (pixw > st::maxStickerSize) {
|
||||
pixh = (st::maxStickerSize * pixh) / pixw;
|
||||
pixw = st::maxStickerSize;
|
||||
}
|
||||
if (_minh > st::maxMediaSize) {
|
||||
_maxw = (st::maxMediaSize * _maxw) / _minh;
|
||||
_minh = st::maxMediaSize;
|
||||
if (pixh > st::maxStickerSize) {
|
||||
pixw = (st::maxStickerSize * pixw) / pixh;
|
||||
pixh = st::maxStickerSize;
|
||||
}
|
||||
if (pixw < 1) pixw = 1;
|
||||
if (pixh < 1) pixh = 1;
|
||||
_maxw = qMax(pixw, int16(st::minPhotoSize));
|
||||
_minh = qMax(pixh, int16(st::minPhotoSize));
|
||||
_height = resize(w, true, parent);
|
||||
}
|
||||
|
||||
|
@ -3093,13 +3105,18 @@ void HistorySticker::draw(QPainter &p, const HistoryItem *parent, bool selected,
|
|||
data->sticker = ImagePtr(data->data);
|
||||
}
|
||||
}
|
||||
if (data->sticker->isNull()) {
|
||||
p.drawPixmap(0, 0, data->thumb->pix(_maxw));
|
||||
} else {
|
||||
p.drawPixmap(0, 0, data->sticker->pix(_maxw));
|
||||
}
|
||||
if (selected) {
|
||||
p.fillRect(0, 0, _maxw, _minh, (out ? st::msgOutSelectOverlay : st::msgInSelectOverlay)->b);
|
||||
if (data->sticker->isNull()) {
|
||||
p.drawPixmap(QPoint((_maxw - pixw) / 2, (_minh - pixh) / 2), data->thumb->pixBlurredColored(textstyleCurrent()->selectOverlay, pixw, pixh));
|
||||
} else {
|
||||
p.drawPixmap(QPoint((_maxw - pixw) / 2, (_minh - pixh) / 2), data->sticker->pixColored(textstyleCurrent()->selectOverlay, pixw, pixh));
|
||||
}
|
||||
} else {
|
||||
if (data->sticker->isNull()) {
|
||||
p.drawPixmap(QPoint((_maxw - pixw) / 2, (_minh - pixh) / 2), data->thumb->pixBlurred(pixw, pixh));
|
||||
} else {
|
||||
p.drawPixmap(QPoint((_maxw - pixw) / 2, (_minh - pixh) / 2), data->sticker->pix(pixw, pixh));
|
||||
}
|
||||
}
|
||||
|
||||
// date
|
||||
|
@ -3114,6 +3131,9 @@ void HistorySticker::draw(QPainter &p, const HistoryItem *parent, bool selected,
|
|||
int32 dateH = _height - dateY - st::msgDateImgDelta;
|
||||
|
||||
p.fillRect(dateX, dateY, dateW, dateH, st::msgDateImgBg->b);
|
||||
if (selected) {
|
||||
p.fillRect(dateX, dateY, dateW, dateH, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
p.setFont(st::msgDateFont->f);
|
||||
p.setPen(st::msgDateImgColor->p);
|
||||
p.drawText(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y() + st::msgDateFont->ascent, time);
|
||||
|
@ -3155,11 +3175,11 @@ int32 HistorySticker::resize(int32 width, bool dontRecountText, const HistoryIte
|
|||
}
|
||||
|
||||
const QString HistorySticker::inDialogsText() const {
|
||||
return lang(lng_in_dlg_sticker);
|
||||
return _emoji.isEmpty() ? lang(lng_in_dlg_sticker) : lng_in_dlg_sticker_emoji(lt_emoji, _emoji);
|
||||
}
|
||||
|
||||
const QString HistorySticker::inHistoryText() const {
|
||||
return qsl("[ ") + lang(lng_in_dlg_sticker) + qsl(" ]");
|
||||
return qsl("[ ") + inDialogsText() + qsl(" ]");
|
||||
}
|
||||
|
||||
bool HistorySticker::hasPoint(int32 x, int32 y, const HistoryItem *parent, int32 width) const {
|
||||
|
@ -3715,7 +3735,7 @@ int32 HistoryImageLink::fullWidth() const {
|
|||
case GoogleMapsLink: return st::locationSize.width();
|
||||
}
|
||||
}
|
||||
return st::minPhotoWidth;
|
||||
return st::minPhotoSize;
|
||||
}
|
||||
|
||||
int32 HistoryImageLink::fullHeight() const {
|
||||
|
@ -3727,22 +3747,22 @@ int32 HistoryImageLink::fullHeight() const {
|
|||
case GoogleMapsLink: return st::locationSize.height();
|
||||
}
|
||||
}
|
||||
return st::minPhotoHeight;
|
||||
return st::minPhotoSize;
|
||||
}
|
||||
|
||||
void HistoryImageLink::initDimensions(const HistoryItem *parent) {
|
||||
int32 tw = convertScale(fullWidth()), th = convertScale(fullHeight());
|
||||
int32 thumbw = qMax(tw, int32(st::minPhotoWidth)), maxthumbh = thumbw;
|
||||
int32 thumbw = qMax(tw, int32(st::minPhotoSize)), maxthumbh = thumbw;
|
||||
int32 thumbh = qRound(th * float64(thumbw) / tw);
|
||||
if (thumbh > maxthumbh) {
|
||||
thumbw = qRound(thumbw * float64(maxthumbh) / thumbh);
|
||||
thumbh = maxthumbh;
|
||||
if (thumbw < st::minPhotoWidth) {
|
||||
thumbw = st::minPhotoWidth;
|
||||
if (thumbw < st::minPhotoSize) {
|
||||
thumbw = st::minPhotoSize;
|
||||
}
|
||||
}
|
||||
if (thumbh < st::minPhotoHeight) {
|
||||
thumbh = st::minPhotoHeight;
|
||||
if (thumbh < st::minPhotoSize) {
|
||||
thumbh = st::minPhotoSize;
|
||||
}
|
||||
if (!w) {
|
||||
w = thumbw;
|
||||
|
@ -3812,6 +3832,9 @@ void HistoryImageLink::draw(QPainter &p, const HistoryItem *parent, bool selecte
|
|||
int32 dateH = _height - dateY - st::msgDateImgDelta;
|
||||
|
||||
p.fillRect(dateX, dateY, dateW, dateH, st::msgDateImgBg->b);
|
||||
if (selected) {
|
||||
p.fillRect(dateX, dateY, dateW, dateH, textstyleCurrent()->selectOverlay->b);
|
||||
}
|
||||
p.setFont(st::msgDateFont->f);
|
||||
p.setPen(st::msgDateImgColor->p);
|
||||
p.drawText(dateX + st::msgDateImgPadding.x(), dateY + st::msgDateImgPadding.y() + st::msgDateFont->ascent, time);
|
||||
|
@ -3849,11 +3872,11 @@ int32 HistoryImageLink::resize(int32 width, bool dontRecountText, const HistoryI
|
|||
w = (w * width) / _height;
|
||||
_height = width;
|
||||
}
|
||||
if (w < st::minPhotoWidth) {
|
||||
w = st::minPhotoWidth;
|
||||
if (w < st::minPhotoSize) {
|
||||
w = st::minPhotoSize;
|
||||
}
|
||||
if (_height < st::minPhotoHeight) {
|
||||
_height = st::minPhotoHeight;
|
||||
if (_height < st::minPhotoSize) {
|
||||
_height = st::minPhotoSize;
|
||||
}
|
||||
return _height;
|
||||
}
|
||||
|
@ -4000,7 +4023,7 @@ void HistoryMessage::initMedia(const MTPMessageMedia &media, QString ¤tTex
|
|||
}
|
||||
|
||||
void HistoryMessage::initMediaFromDocument(DocumentData *doc) {
|
||||
if (doc->type == StickerDocument && doc->dimensions.width() > 0 && doc->dimensions.height() > 0 && doc->size < StickerInMemory) {
|
||||
if (doc->type == StickerDocument && doc->dimensions.width() > 0 && doc->dimensions.height() > 0 && doc->dimensions.width() <= StickerMaxSize && doc->dimensions.height() <= StickerMaxSize && doc->size < StickerInMemory) {
|
||||
_media = new HistorySticker(doc);
|
||||
} else {
|
||||
_media = new HistoryDocument(doc);
|
||||
|
@ -4318,6 +4341,15 @@ QString HistoryMessage::notificationText() const {
|
|||
return msg;
|
||||
}
|
||||
|
||||
void HistoryMessage::updateStickerEmoji() {
|
||||
if (_media) {
|
||||
if (_media->updateStickerEmoji()) {
|
||||
_history->textCachedFor = 0;
|
||||
if (App::wnd()) App::wnd()->update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HistoryMessage::~HistoryMessage() {
|
||||
if (_media) {
|
||||
_media->unregItem(this);
|
||||
|
|
|
@ -1166,6 +1166,8 @@ public:
|
|||
}
|
||||
virtual void updateMedia(const MTPMessageMedia &media) {
|
||||
}
|
||||
virtual void updateStickerEmoji() {
|
||||
}
|
||||
|
||||
virtual QString selectedText(uint32 selection) const {
|
||||
return qsl("[-]");
|
||||
|
@ -1240,6 +1242,10 @@ public:
|
|||
|
||||
virtual void updateFrom(const MTPMessageMedia &media) {
|
||||
}
|
||||
|
||||
virtual bool updateStickerEmoji() {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool animating() const {
|
||||
return false;
|
||||
|
@ -1291,6 +1297,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
int16 pixw, pixh;
|
||||
PhotoData *data;
|
||||
TextLinkPtr openl;
|
||||
|
||||
|
@ -1432,10 +1439,13 @@ public:
|
|||
void unregItem(HistoryItem *item);
|
||||
|
||||
void updateFrom(const MTPMessageMedia &media);
|
||||
bool updateStickerEmoji();
|
||||
|
||||
private:
|
||||
|
||||
int16 pixw, pixh;
|
||||
DocumentData *data;
|
||||
QString _emoji;
|
||||
|
||||
};
|
||||
|
||||
|
@ -1577,6 +1587,7 @@ public:
|
|||
void updateMedia(const MTPMessageMedia &media) {
|
||||
if (_media) _media->updateFrom(media);
|
||||
}
|
||||
void updateStickerEmoji();
|
||||
|
||||
QString selectedText(uint32 selection) const;
|
||||
HistoryMedia *getMedia(bool inOverview = false) const;
|
||||
|
|
|
@ -1774,9 +1774,11 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
|||
const MTPDmessages_allStickers &d(stickers.c_messages_allStickers());
|
||||
|
||||
AllStickers all;
|
||||
EmojiStickersMap map;
|
||||
|
||||
const QVector<MTPDocument> &docs(d.vdocuments.c_vector().v);
|
||||
|
||||
QSet<DocumentData*> found;
|
||||
const RecentStickerPack &recent(cRecentStickers());
|
||||
RecentStickerPack add;
|
||||
add.reserve(docs.size());
|
||||
|
@ -1786,13 +1788,32 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
|||
if (!doc) continue;
|
||||
int32 j = 0, s = recent.size();
|
||||
for (; j < s; ++j) {
|
||||
if (doc == recent.at(j).first) break;
|
||||
if (doc == recent.at(j).first) {
|
||||
found.insert(doc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < s) continue;
|
||||
add.push_back(qMakePair(doc, addValue));
|
||||
}
|
||||
if (!add.isEmpty()) {
|
||||
cSetRecentStickers(add + recent);
|
||||
bool needRemove = false;
|
||||
for (int32 i = 0, l = recent.size(); i < l; ++i) {
|
||||
if (recent.at(i).second > 0 && !found.contains(recent.at(i).first)) {
|
||||
needRemove = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!add.isEmpty() || needRemove) {
|
||||
if (needRemove) {
|
||||
for (int32 i = 0, l = recent.size(); i < l; ++i) {
|
||||
if (recent.at(i).second <= 0 || found.contains(recent.at(i).first)) {
|
||||
add.push_back(recent.at(i));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
add += recent;
|
||||
}
|
||||
cSetRecentStickers(add);
|
||||
Local::writeRecentStickers();
|
||||
_emojiPan.onTabChange();
|
||||
}
|
||||
|
@ -1828,7 +1849,9 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
|||
StickerPack &pack(all[e]);
|
||||
pack.reserve(pack.size() + docs.size());
|
||||
for (int32 j = 0, s = docs.size(); j < s; ++j) {
|
||||
pack.push_back(App::document(docs.at(j).v));
|
||||
DocumentData *doc = App::document(docs.at(j).v);
|
||||
pack.push_back(doc);
|
||||
map.insert(doc, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -1839,6 +1862,17 @@ void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
|||
|
||||
cSetStickers(all);
|
||||
cSetStickersHash(qba(d.vhash));
|
||||
cSetEmojiStickers(map);
|
||||
|
||||
const DocumentItems &items(App::documentItems());
|
||||
for (EmojiStickersMap::const_iterator i = map.cbegin(), e = map.cend(); i != e; ++i) {
|
||||
DocumentItems::const_iterator j = items.constFind(i.key());
|
||||
if (j != items.cend()) {
|
||||
for (HistoryItemsMap::const_iterator k = j->cbegin(), end = j->cend(); k != end; ++k) {
|
||||
k.key()->updateStickerEmoji();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// updateStickerPan();
|
||||
_emojiPan.onTabChange();
|
||||
|
@ -2995,11 +3029,11 @@ void HistoryWidget::uploadMedias(const QStringList &files, ToPrepareMediaType ty
|
|||
imageLoader.append(files, histPeer->id, type);
|
||||
}
|
||||
|
||||
void HistoryWidget::uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type) {
|
||||
if (!hist) return;
|
||||
void HistoryWidget::uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type, PeerId peer) {
|
||||
if (!peer && !hist) return;
|
||||
|
||||
App::wnd()->activateWindow();
|
||||
imageLoader.append(fileContent, histPeer->id, type);
|
||||
imageLoader.append(fileContent, peer ? peer : histPeer->id, type);
|
||||
}
|
||||
|
||||
void HistoryWidget::onPhotoReady() {
|
||||
|
@ -3089,7 +3123,7 @@ void HistoryWidget::onPhotoUploaded(MsgId newId, const MTPInputFile &file) {
|
|||
uint64 randomId = MTP::nonce<uint64>();
|
||||
App::historyRegRandom(randomId, newId);
|
||||
History *hist = item->history();
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedPhoto(file), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), RPCFailHandlerPtr(), 0, 0, hist->sendRequestId);
|
||||
hist->sendRequestId = MTP::send(MTPmessages_SendMedia(item->history()->peer->input, MTP_inputMediaUploadedPhoto(file), MTP_long(randomId)), App::main()->rpcDone(&MainWidget::sentFullDataReceived, randomId), App::main()->rpcFail(&MainWidget::sendPhotoFailed, randomId), 0, 0, hist->sendRequestId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -298,7 +298,7 @@ public:
|
|||
void shareContactConfirmation(const QString &phone, const QString &fname, const QString &lname, bool withText = false);
|
||||
void uploadConfirmImageUncompressed(bool ctrlShiftEnter);
|
||||
void uploadMedias(const QStringList &files, ToPrepareMediaType type);
|
||||
void uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type);
|
||||
void uploadMedia(const QByteArray &fileContent, ToPrepareMediaType type, PeerId peer = 0);
|
||||
void confirmShareContact(bool ctrlShiftEnter, const QString &phone, const QString &fname, const QString &lname);
|
||||
void confirmSendImage(const ReadyLocalMedia &img);
|
||||
void cancelSendImage();
|
||||
|
|
|
@ -40,6 +40,10 @@ public:
|
|||
return res;
|
||||
}
|
||||
|
||||
void mousePressEvent(QMouseEvent *e) {
|
||||
e->accept();
|
||||
}
|
||||
|
||||
signals:
|
||||
|
||||
void closed();
|
||||
|
|
|
@ -31,12 +31,13 @@ LocalImageLoaderPrivate::LocalImageLoaderPrivate(int32 currentUser, LocalImageLo
|
|||
};
|
||||
|
||||
void LocalImageLoaderPrivate::prepareImages() {
|
||||
QString file, filename, mime;
|
||||
QString file, filename, mime, stickerMime = qsl("image/webp");
|
||||
int32 filesize = 0;
|
||||
QImage img;
|
||||
QByteArray data;
|
||||
PeerId peer;
|
||||
uint64 id, jpeg_id = 0;
|
||||
uint64 id, thumbId = 0;
|
||||
QString thumbExt = "jpg";
|
||||
ToPrepareMediaType type;
|
||||
bool animated = false;
|
||||
bool ctrlShiftEnter = false;
|
||||
|
@ -72,12 +73,13 @@ void LocalImageLoaderPrivate::prepareImages() {
|
|||
type = ToPrepareDocument;
|
||||
}
|
||||
}
|
||||
if (type != ToPrepareAuto && info.size() < MaxUploadPhotoSize) {
|
||||
img = App::readImage(file, 0, true, &animated);
|
||||
}
|
||||
if (type == ToPrepareDocument) {
|
||||
mime = mimeTypeForFile(info).name();
|
||||
}
|
||||
if (type != ToPrepareAuto && info.size() < MaxUploadPhotoSize) {
|
||||
bool opaque = (mime != stickerMime);
|
||||
img = App::readImage(file, 0, opaque, &animated);
|
||||
}
|
||||
filename = info.fileName();
|
||||
filesize = info.size();
|
||||
} else if (!data.isEmpty()) {
|
||||
|
@ -95,10 +97,15 @@ void LocalImageLoaderPrivate::prepareImages() {
|
|||
if (type == ToPrepareDocument) {
|
||||
mime = mimeType.name();
|
||||
}
|
||||
filename = qsl("Document");
|
||||
QStringList patterns = mimeType.globPatterns();
|
||||
if (!patterns.isEmpty()) {
|
||||
filename = patterns.front().replace('*', filename);
|
||||
if (mime == "image/jpeg") {
|
||||
filename = filedialogDefaultName(qsl("image"), qsl(".jpg"), QString(), true);
|
||||
} else {
|
||||
QString ext;
|
||||
QStringList patterns = mimeType.globPatterns();
|
||||
if (!patterns.isEmpty()) {
|
||||
ext = patterns.front().replace('*', QString());
|
||||
}
|
||||
filename = filedialogDefaultName(qsl("doc"), ext, QString(), true);
|
||||
}
|
||||
filesize = data.size();
|
||||
}
|
||||
|
@ -113,7 +120,15 @@ void LocalImageLoaderPrivate::prepareImages() {
|
|||
}
|
||||
filesize = data.size();
|
||||
} else {
|
||||
type = ToPreparePhoto; // only photo from QImage
|
||||
if (img.hasAlphaChannel()) {
|
||||
QImage solid(img.width(), img.height(), QImage::Format_ARGB32_Premultiplied);
|
||||
solid.fill(st::white->c);
|
||||
{
|
||||
QPainter(&solid).drawImage(0, 0, img);
|
||||
}
|
||||
img = solid;
|
||||
}
|
||||
type = ToPreparePhoto;
|
||||
filename = qsl("Untitled.jpg");
|
||||
filesize = 0;
|
||||
}
|
||||
|
@ -163,29 +178,32 @@ void LocalImageLoaderPrivate::prepareImages() {
|
|||
|
||||
photo = MTP_photo(MTP_long(id), MTP_long(0), MTP_int(user), MTP_int(unixtime()), MTP_string(""), MTP_geoPointEmpty(), MTP_vector<MTPPhotoSize>(photoSizes));
|
||||
|
||||
jpeg_id = id;
|
||||
thumbId = id;
|
||||
} else if ((type == ToPrepareVideo || type == ToPrepareDocument) && !img.isNull()) {
|
||||
int32 w = img.width(), h = img.height();
|
||||
QByteArray thumbFormat = "JPG";
|
||||
int32 thumbQuality = 87;
|
||||
if (animated) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (mime == qsl("image/webp") && w > 0 && h > 0 && filesize < StickerInMemory) {
|
||||
} else if (mime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
|
||||
attributes.push_back(MTP_documentAttributeSticker());
|
||||
thumbFormat = "webp";
|
||||
thumbExt = qsl("webp");
|
||||
}
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(w), MTP_int(h)));
|
||||
if (w < 20 * h && h < 20 * w) {
|
||||
QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img, Qt::ColorOnly);
|
||||
|
||||
QPixmap full = (w > 90 || h > 90) ? QPixmap::fromImage(img.scaled(90, 90, Qt::KeepAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly) : QPixmap::fromImage(img, Qt::ColorOnly);
|
||||
{
|
||||
QBuffer jpegBuffer(&jpeg);
|
||||
full.save(&jpegBuffer, thumbFormat, thumbQuality);
|
||||
}
|
||||
|
||||
{
|
||||
QBuffer jpegBuffer(&jpeg);
|
||||
full.save(&jpegBuffer, thumbFormat, 87);
|
||||
photoThumbs.insert('0', full);
|
||||
thumb = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
|
||||
|
||||
thumbId = MTP::nonce<uint64>();
|
||||
}
|
||||
|
||||
photoThumbs.insert('0', full);
|
||||
thumb = MTP_photoSize(MTP_string(""), MTP_fileLocationUnavailable(MTP_long(0), MTP_int(0), MTP_long(0)), MTP_int(full.width()), MTP_int(full.height()), MTP_int(0));
|
||||
|
||||
jpeg_id = MTP::nonce<uint64>();
|
||||
}
|
||||
|
||||
if (type == ToPrepareDocument) {
|
||||
|
@ -194,7 +212,7 @@ void LocalImageLoaderPrivate::prepareImages() {
|
|||
|
||||
{
|
||||
QMutexLocker lock(loader->readyMutex());
|
||||
loader->readyList().push_back(ReadyLocalMedia(type, file, filename, filesize, data, id, jpeg_id, peer, photo, photoThumbs, document, jpeg, ctrlShiftEnter));
|
||||
loader->readyList().push_back(ReadyLocalMedia(type, file, filename, filesize, data, id, thumbId, thumbExt, peer, photo, photoThumbs, document, jpeg, ctrlShiftEnter));
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -43,8 +43,8 @@ typedef QList<ToPrepareMedia> ToPrepareMedias;
|
|||
|
||||
typedef QMap<int32, QByteArray> LocalFileParts;
|
||||
struct ReadyLocalMedia {
|
||||
ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &jpeg_id, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool ctrlShiftEnter) :
|
||||
type(type), file(file), filename(filename), filesize(filesize), data(data), id(id), jpeg_id(jpeg_id), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), ctrlShiftEnter(ctrlShiftEnter) {
|
||||
ReadyLocalMedia(ToPrepareMediaType type, const QString &file, const QString &filename, int32 filesize, const QByteArray &data, const uint64 &id, const uint64 &thumbId, const QString &thumbExt, const PeerId &peer, const MTPPhoto &photo, const PreparedPhotoThumbs &photoThumbs, const MTPDocument &document, const QByteArray &jpeg, bool ctrlShiftEnter) :
|
||||
type(type), file(file), filename(filename), filesize(filesize), data(data), id(id), thumbId(thumbId), thumbExt(thumbExt), peer(peer), photo(photo), document(document), photoThumbs(photoThumbs), ctrlShiftEnter(ctrlShiftEnter) {
|
||||
if (!jpeg.isEmpty()) {
|
||||
int32 size = jpeg.size();
|
||||
for (int32 i = 0, part = 0; i < size; i += UploadPartSize, ++part) {
|
||||
|
@ -58,7 +58,8 @@ struct ReadyLocalMedia {
|
|||
QString file, filename;
|
||||
int32 filesize;
|
||||
QByteArray data;
|
||||
uint64 id, jpeg_id; // id always file-id of media, jpeg_id is file-id of thumb ( == id for photos)
|
||||
QString thumbExt;
|
||||
uint64 id, thumbId; // id always file-id of media, thumbId is file-id of thumb ( == id for photos)
|
||||
PeerId peer;
|
||||
|
||||
MTPPhoto photo;
|
||||
|
|
|
@ -664,6 +664,52 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu
|
|||
}
|
||||
}
|
||||
|
||||
bool MainWidget::sendPhotoFailed(uint64 randomId, const RPCError &e) {
|
||||
if (e.type() == qsl("PHOTO_INVALID_DIMENSIONS")) {
|
||||
if (_resendImgRandomIds.isEmpty()) {
|
||||
ConfirmBox *box = new ConfirmBox(lang(lng_bad_image_for_photo));
|
||||
connect(box, SIGNAL(confirmed()), this, SLOT(onResendAsDocument()));
|
||||
connect(box, SIGNAL(cancelled()), this, SLOT(onCancelResend()));
|
||||
connect(box, SIGNAL(destroyed()), this, SLOT(onCancelResend()));
|
||||
App::wnd()->showLayer(box);
|
||||
}
|
||||
_resendImgRandomIds.push_back(randomId);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void MainWidget::onResendAsDocument() {
|
||||
QList<uint64> tmp = _resendImgRandomIds;
|
||||
_resendImgRandomIds.clear();
|
||||
for (int32 i = 0, l = tmp.size(); i < l; ++i) {
|
||||
if (HistoryItem *item = App::histItemById(App::histItemByRandom(tmp.at(i)))) {
|
||||
if (HistoryPhoto *media = dynamic_cast<HistoryPhoto*>(item->getMedia())) {
|
||||
PhotoData *photo = media->photo();
|
||||
if (!photo->full->isNull()) {
|
||||
photo->full->forget();
|
||||
QByteArray data = photo->full->savedData();
|
||||
if (!data.isEmpty()) {
|
||||
history.uploadMedia(data, ToPrepareDocument, item->history()->peer->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
App::wnd()->layerHidden();
|
||||
}
|
||||
|
||||
void MainWidget::onCancelResend() {
|
||||
QList<uint64> tmp = _resendImgRandomIds;
|
||||
_resendImgRandomIds.clear();
|
||||
for (int32 i = 0, l = tmp.size(); i < l; ++i) {
|
||||
if (HistoryItem *item = App::histItemById(App::histItemByRandom(tmp.at(i)))) {
|
||||
item->destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWidget::forwardSelectedItems() {
|
||||
if (overview) {
|
||||
overview->onForwardSelected();
|
||||
|
|
|
@ -277,6 +277,8 @@ public:
|
|||
void checkPeerHistory(PeerData *peer);
|
||||
void checkedHistory(PeerData *peer, const MTPmessages_Messages &result);
|
||||
|
||||
bool sendPhotoFailed(uint64 randomId, const RPCError &e);
|
||||
|
||||
void forwardSelectedItems();
|
||||
void deleteSelectedItems();
|
||||
void clearSelectedItems();
|
||||
|
@ -359,6 +361,9 @@ public slots:
|
|||
|
||||
void onForwardCancel(QObject *obj = 0);
|
||||
|
||||
void onResendAsDocument();
|
||||
void onCancelResend();
|
||||
|
||||
private:
|
||||
|
||||
void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result);
|
||||
|
@ -370,6 +375,8 @@ private:
|
|||
QString failedFileName;
|
||||
void loadFailed(mtpFileLoader *loader, bool started, const char *retrySlot);
|
||||
|
||||
QList<uint64> _resendImgRandomIds;
|
||||
|
||||
void gotDifference(const MTPupdates_Difference &diff);
|
||||
bool failDifference(const RPCError &e);
|
||||
void feedDifference(const MTPVector<MTPUser> &users, const MTPVector<MTPChat> &chats, const MTPVector<MTPMessage> &msgs, const MTPVector<MTPUpdate> &other);
|
||||
|
|
|
@ -74,6 +74,9 @@ RecentEmojiPreload gRecentEmojisPreload;
|
|||
|
||||
AllStickers gStickers;
|
||||
QByteArray gStickersHash;
|
||||
|
||||
EmojiStickersMap gEmojiStickers;
|
||||
|
||||
RecentStickerPack gRecentStickers;
|
||||
|
||||
int32 gLang = -2; // auto
|
||||
|
|
|
@ -150,6 +150,10 @@ typedef QVector<DocumentData*> StickerPack;
|
|||
typedef QMap<EmojiPtr, StickerPack> AllStickers;
|
||||
DeclareSetting(AllStickers, Stickers);
|
||||
DeclareSetting(QByteArray, StickersHash);
|
||||
|
||||
typedef QMap<DocumentData*, EmojiPtr> EmojiStickersMap;
|
||||
DeclareSetting(EmojiStickersMap, EmojiStickers);
|
||||
|
||||
typedef QList<QPair<DocumentData*, int16> > RecentStickerPack;
|
||||
DeclareSetting(RecentStickerPack, RecentStickers);
|
||||
|
||||
|
|
|
@ -944,7 +944,7 @@ void SettingsInner::onChangeLanguage() {
|
|||
connect(box, SIGNAL(confirmed()), this, SLOT(onSaveTestLang()));
|
||||
App::wnd()->showLayer(box);
|
||||
} else {
|
||||
App::wnd()->showLayer(new ConfirmBox("Custom lang failed :(\n\nError: " + cLangErrors(), true, lang(lng_close)));
|
||||
App::wnd()->showLayer(new ConfirmBox("Custom lang failed :(\n\nError: " + loader.errors(), true, lang(lng_close)));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
Loading…
Reference in New Issue