mirror of https://github.com/procxx/kepka.git
beautiful sticker blur and selection, document and sticker thumbs fixed, sticker emojis in dialog list display done, send image as doc for bad image size done
This commit is contained in:
parent
5d54d48f70
commit
476ffca228
|
@ -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);
|
||||
{
|
||||
|
|
|
@ -479,7 +479,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