Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
147eaab59a | ||
|
|
890ec34202 | ||
|
|
92858dc7d3 | ||
|
|
4440b42848 | ||
|
|
136fd5c8e1 | ||
|
|
d92356ce28 | ||
|
|
47f673aa69 | ||
|
|
64d4a3e8a8 | ||
|
|
87e72fc7aa | ||
|
|
6d44a3ec95 | ||
|
|
eb47eabba4 | ||
|
|
cfb0de69f0 | ||
|
|
2d46cc4c11 |
@@ -1,9 +1,9 @@
|
||||
@echo OFF
|
||||
|
||||
set "AppVersion=8012"
|
||||
set "AppVersionStrSmall=0.8.12"
|
||||
set "AppVersionStr=0.8.12"
|
||||
set "AppVersionStrFull=0.8.12.0"
|
||||
set "AppVersion=8014"
|
||||
set "AppVersionStrSmall=0.8.14"
|
||||
set "AppVersionStr=0.8.14"
|
||||
set "AppVersionStrFull=0.8.14.0"
|
||||
set "DevChannel=1"
|
||||
|
||||
if %DevChannel% neq 0 goto preparedev
|
||||
|
||||
@@ -389,16 +389,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_action_changed_title" = "{from} changed group name to «{title}»";
|
||||
"lng_action_created_chat" = "{from} created group «{title}»";
|
||||
|
||||
"lng_group_invite_bad_link" = "This invite link is broken\nor it has expired.";
|
||||
"lng_group_invite_bad_link" = "This invite link is broken\nor has expired.";
|
||||
"lng_group_invite_want_join" = "Do you want to join the group «{title}»?";
|
||||
"lng_group_invite_join" = "Join";
|
||||
|
||||
"lng_group_invite_link" = "Invite link";
|
||||
"lng_group_invite_create" = "Create an invite link";
|
||||
"lng_group_invite_about" = "You can create a link for joining this group.\nAnyone who has that link can join.";
|
||||
"lng_group_invite_create_new" = "Create new link";
|
||||
"lng_group_invite_about_new" = "Current invite link will stop working\nwhen you create a new one.";
|
||||
"lng_group_invite_copied" = "Invite link was copied to clipboard.";
|
||||
"lng_group_invite_about" = "Telegram users will be able to join\nyour group by following this link.";
|
||||
"lng_group_invite_create_new" = "Revoke invite link";
|
||||
"lng_group_invite_about_new" = "Your previous link will be deactivated\nand we'll generate a new invite link for you.";
|
||||
"lng_group_invite_copied" = "Invite link copied to clipboard.";
|
||||
"lng_group_invite_no_room" = "Unable to join this group because there are\ntoo many members in it already.";
|
||||
|
||||
"lng_forwarded_from" = "Forwarded from";
|
||||
@@ -428,7 +428,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_emoji_category5" = "Activity";
|
||||
"lng_emoji_category6" = "Travel & Places";
|
||||
"lng_emoji_category7" = "Objects & Symbols";
|
||||
"lng_emoji_category8" = "Stickers";
|
||||
|
||||
"lng_switch_stickers" = "Stickers";
|
||||
"lng_switch_emoji" = "Emoji";
|
||||
|
||||
"lng_custom_stickers" = "Custom stickers";
|
||||
"lng_stickers_remove_pack" = "Remove «{sticker_pack}»?";
|
||||
"lng_stickers_add_pack" = "Add {count:_not_used_|# Sticker|# Stickers}";
|
||||
"lng_stickers_share_pack" = "Share Stickers";
|
||||
"lng_stickers_not_found" = "Sticker pack not found.";
|
||||
"lng_stickers_copied" = "Sticker pack link copied to clipboard.";
|
||||
|
||||
"lng_in_dlg_photo" = "Photo";
|
||||
"lng_in_dlg_video" = "Video";
|
||||
@@ -481,6 +490,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_context_save_video" = "Save Video As..";
|
||||
"lng_context_open_audio" = "Open Audio";
|
||||
"lng_context_save_audio" = "Save Audio As..";
|
||||
"lng_context_pack_info" = "Pack Info";
|
||||
"lng_context_open_file" = "Open File";
|
||||
"lng_context_save_file" = "Save File As..";
|
||||
"lng_context_forward_file" = "Forward File";
|
||||
@@ -573,7 +583,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram Desktop was updated to version {version}\n\n{changes}\n\nFull version history is available here:\n{link}";
|
||||
"lng_new_version_minor" = "— Bug fixes and other minor improvements";
|
||||
"lng_new_version_text" = "— Invite links for group chats\n— Gray unread badge for muted conversations";
|
||||
"lng_new_version_text" = "— Added support for new emoji\n— Improved emoji and stickers panel";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insert Unicode control character";
|
||||
|
||||
|
||||
@@ -308,7 +308,8 @@ scrollDef: flatScroll {
|
||||
width: 10px;
|
||||
minHeight: 20px;
|
||||
deltax: 3px;
|
||||
deltay: 3px;
|
||||
deltat: 3px;
|
||||
deltab: 3px;
|
||||
|
||||
topsh: 2px;
|
||||
bottomsh: 2px;
|
||||
@@ -983,12 +984,12 @@ btnAttachPhoto: iconedButton(btnAttachDocument) {
|
||||
}
|
||||
btnAttachEmoji: iconedButton(btnAttachDocument) {
|
||||
overBgColor: white;
|
||||
icon: sprite(311px, 221px, 20px, 20px);
|
||||
icon: sprite(363px, 344px, 21px, 22px);
|
||||
iconPos: point(6px, 13px);
|
||||
downIcon: sprite(311px, 221px, 20px, 20px);
|
||||
downIcon: sprite(363px, 344px, 21px, 22px);
|
||||
downIconPos: point(6px, 13px);
|
||||
|
||||
width: 32px;
|
||||
width: 33px;
|
||||
}
|
||||
|
||||
replySkip: 51px;
|
||||
@@ -1020,7 +1021,8 @@ historyScroll: flatScroll(scrollDef) {
|
||||
|
||||
width: 12px;
|
||||
deltax: 3px;
|
||||
deltay: 3px;
|
||||
deltat: 3px;
|
||||
deltab: 3px;
|
||||
|
||||
topsh: 0px;
|
||||
bottomsh: -1px;
|
||||
@@ -1362,7 +1364,7 @@ btnInfoClose: flatButton(aboutCloseButton) {
|
||||
emojiTextFont: font(16px);
|
||||
emojiReplaceWidth: 56px;
|
||||
emojiReplaceHeight: 56px;
|
||||
emojiReplaceInnerHeight: 38px;
|
||||
emojiReplaceInnerHeight: 42px;
|
||||
|
||||
connectingBG: #fffe;
|
||||
connectingColor: #777;
|
||||
@@ -1452,47 +1454,90 @@ dpiFont2: linkFont;
|
||||
dpiFont3: linkFont;
|
||||
dpiFont4: linkFont;
|
||||
|
||||
emojiScroll: flatScroll(scrollDef) {
|
||||
width: 5px;
|
||||
deltax: 2px;
|
||||
deltay: 1px;
|
||||
newScroll: flatScroll(scrollDef) {
|
||||
barColor: #3f729734;
|
||||
bgColor: #214f751a;
|
||||
barOverColor: #3f729734;
|
||||
bgOverColor: #214f751a;
|
||||
|
||||
deltax: 5px;
|
||||
width: 14px;
|
||||
deltat: 6px;
|
||||
deltab: 6px;
|
||||
|
||||
topsh: 0px;
|
||||
bottomsh: 0px;
|
||||
|
||||
hiding: 0;
|
||||
}
|
||||
emojiRecent: sprite(6px, 197px, 20px, 20px);
|
||||
emojiRecentOver: sprite(290px, 221px, 20px, 20px);
|
||||
emojiRecentActive: sprite(290px, 242px, 20px, 20px);
|
||||
emojiPeople: sprite(27px, 197px, 20px, 20px);
|
||||
emojiPeopleOver: sprite(311px, 221px, 20px, 20px);
|
||||
emojiPeopleActive: sprite(311px, 242px, 20px, 20px);
|
||||
emojiNature: sprite(48px, 197px, 20px, 20px);
|
||||
emojiNatureOver: sprite(245px, 266px, 20px, 20px);
|
||||
emojiNatureActive: sprite(245px, 287px, 20px, 20px);
|
||||
emojiFood: sprite(69px, 197px, 20px, 20px);
|
||||
emojiFoodOver: sprite(266px, 266px, 20px, 20px);
|
||||
emojiFoodActive: sprite(266px, 287px, 20px, 20px);
|
||||
emojiCelebration: sprite(90px, 197px, 20px, 20px);
|
||||
emojiCelebrationOver: sprite(290px, 266px, 20px, 20px);
|
||||
emojiCelebrationActive: sprite(290px, 287px, 20px, 20px);
|
||||
emojiActivity: sprite(111px, 197px, 20px, 20px);
|
||||
emojiActivityOver: sprite(311px, 266px, 20px, 20px);
|
||||
emojiActivityActive: sprite(311px, 287px, 20px, 20px);
|
||||
emojiTravel: sprite(132px, 197px, 20px, 20px);
|
||||
emojiTravelOver: sprite(321px, 344px, 20px, 20px);
|
||||
emojiTravelActive: sprite(321px, 365px, 20px, 20px);
|
||||
emojiObjects: sprite(153px, 197px, 20px, 20px);
|
||||
emojiObjectsOver: sprite(342px, 344px, 20px, 20px);
|
||||
emojiObjectsActive: sprite(342px, 365px, 20px, 20px);
|
||||
emojiStickers: sprite(174px, 197px, 20px, 20px);
|
||||
emojiStickersOver: sprite(363px, 344px, 20px, 20px);
|
||||
emojiStickersActive: sprite(363px, 365px, 20px, 20px);
|
||||
|
||||
stickersMaxHeight: 340px;
|
||||
stickersAddOrShare: 70px;
|
||||
btnStickersAdd: flatButton(btnDefNext, btnDefBig) {
|
||||
width: 180px;
|
||||
height: 42px;
|
||||
|
||||
textTop: 9px;
|
||||
overTextTop: 9px;
|
||||
downTextTop: 10px;
|
||||
|
||||
font: font(17px);
|
||||
overFont: font(17px);
|
||||
|
||||
bgColor: #15c23c;
|
||||
overBgColor: #13a835;
|
||||
downBgColor: #13a835;
|
||||
}
|
||||
btnStickersClose: iconedButton(notifyClose) {
|
||||
iconPos: point(21px, 21px);
|
||||
downIconPos: point(21px, 22px);
|
||||
width: 52px;
|
||||
height: 48px;
|
||||
}
|
||||
stickersWidth: 344px;
|
||||
stickersPadding: 10px;
|
||||
stickersSize: size(64px, 64px);
|
||||
stickersScroll: flatScroll(newScroll) {
|
||||
deltab: 76px;
|
||||
}
|
||||
|
||||
emojiScroll: flatScroll(newScroll) {
|
||||
deltat: 48px;
|
||||
}
|
||||
emojiRecent: sprite(0px, 196px, 21px, 22px);
|
||||
emojiRecentOver: sprite(287px, 220px, 21px, 22px);
|
||||
emojiRecentActive: sprite(287px, 242px, 21px, 22px);
|
||||
emojiPeople: sprite(21px, 196px, 21px, 22px);
|
||||
emojiPeopleOver: sprite(308px, 220px, 21px, 22px);
|
||||
emojiPeopleActive: sprite(308px, 242px, 21px, 22px);
|
||||
emojiNature: sprite(42px, 196px, 21px, 22px);
|
||||
emojiNatureOver: sprite(245px, 264px, 21px, 22px);
|
||||
emojiNatureActive: sprite(245px, 286px, 21px, 22px);
|
||||
emojiFood: sprite(63px, 196px, 21px, 22px);
|
||||
emojiFoodOver: sprite(266px, 264px, 21px, 22px);
|
||||
emojiFoodActive: sprite(266px, 286px, 21px, 22px);
|
||||
emojiCelebration: sprite(84px, 196px, 21px, 22px);
|
||||
emojiCelebrationOver: sprite(287px, 264px, 21px, 22px);
|
||||
emojiCelebrationActive: sprite(287px, 286px, 21px, 22px);
|
||||
emojiActivity: sprite(105px, 196px, 21px, 22px);
|
||||
emojiActivityOver: sprite(308px, 264px, 21px, 22px);
|
||||
emojiActivityActive: sprite(308px, 286px, 21px, 22px);
|
||||
emojiTravel: sprite(126px, 196px, 21px, 22px);
|
||||
emojiTravelOver: sprite(321px, 344px, 21px, 22px);
|
||||
emojiTravelActive: sprite(321px, 366px, 21px, 22px);
|
||||
emojiObjects: sprite(147px, 196px, 21px, 22px);
|
||||
emojiObjectsOver: sprite(342px, 344px, 21px, 22px);
|
||||
emojiObjectsActive: sprite(342px, 366px, 21px, 22px);
|
||||
|
||||
emojiPanCategories: #f7f7f7;
|
||||
|
||||
rbEmoji: flatCheckbox {
|
||||
textColor: transparent;
|
||||
bgColor: transparent;
|
||||
disColor: transparent;
|
||||
bgColor: emojiPanCategories;
|
||||
disColor: emojiPanCategories;
|
||||
|
||||
width: 28px;
|
||||
height: 36px;
|
||||
width: 36px;
|
||||
height: 46px;
|
||||
|
||||
textTop: 0px;
|
||||
textLeft: 0px;
|
||||
@@ -1502,7 +1547,7 @@ rbEmoji: flatCheckbox {
|
||||
cursor: cursor(pointer);
|
||||
|
||||
disabledCursor: cursor(default);
|
||||
imagePos: point(5px, 8px);
|
||||
imagePos: point(8px, 12px);
|
||||
}
|
||||
rbEmojiRecent: flatCheckbox(rbEmoji) {
|
||||
imageRect: emojiRecent;
|
||||
@@ -1568,33 +1613,33 @@ rbEmojiObjects: flatCheckbox(rbEmoji) {
|
||||
disImageRect: emojiObjects;
|
||||
chkDisImageRect: emojiObjectsActive;
|
||||
}
|
||||
rbEmojiStickers: flatCheckbox(rbEmojiRecent) {
|
||||
imageRect: emojiStickers;
|
||||
chkImageRect: emojiStickersActive;
|
||||
overImageRect: emojiStickersOver;
|
||||
chkOverImageRect: emojiStickersActive;
|
||||
disImageRect: emojiStickers;
|
||||
chkDisImageRect: emojiStickersActive;
|
||||
}
|
||||
emojiPanPadding: margins(5px, 0px, 0px, 5px);
|
||||
emojiPanSize: size(35px, 35px);
|
||||
emojiPanPadding: 10px;
|
||||
emojiPanSize: size(39px, 35px);
|
||||
emojiPanFullSize: size(300px, 321px);
|
||||
emojiPanDuration: 200;
|
||||
emojiPanHover: #f0f0f0;
|
||||
emojiPanHover: #f0f4f7;
|
||||
emojiPanRound: 2px;
|
||||
|
||||
emojiPanHeader: 25px;
|
||||
emojiPanHeader: 42px;
|
||||
emojiPanHeaderFont: font(fsize semibold);
|
||||
emojiPanHeaderColor: #999;
|
||||
emojiPanHeaderLeft: 5px;
|
||||
emojiPanHeaderTop: 5px;
|
||||
emojiPanHeaderBg: #fffd;
|
||||
emojiPanHeaderLeft: 17px;
|
||||
emojiPanHeaderTop: 12px;
|
||||
emojiPanHeaderBg: #fffffff2;
|
||||
|
||||
emojiColorsPadding: 5px;
|
||||
emojiColorsSep: 1px;
|
||||
emojiColorsSepColor: #d5d5d5;
|
||||
|
||||
emojiSwitchSkip: 27px;
|
||||
emojiSwitchImgSkip: 21px;
|
||||
emojiSwitchStickers: sprite(318px, 328px, 8px, 12px);
|
||||
emojiSwitchEmoji: sprite(310px, 328px, 8px, 12px);
|
||||
emojiSwitchColor: #42a8db;
|
||||
|
||||
stickerPanSize: size(55px, 55px);
|
||||
stickerPanRound: 3px;
|
||||
stickerPanPadding: 2px;
|
||||
stickerPanPadding: 11px;
|
||||
stickerPanDelete: sprite(123px, 132px, 12px, 12px);
|
||||
stickerPanDeleteOpacity: 0.5;
|
||||
|
||||
|
||||
@@ -173,7 +173,8 @@ flatScroll {
|
||||
width: number;
|
||||
minHeight: number;
|
||||
deltax: number;
|
||||
deltay: number;
|
||||
deltat: number;
|
||||
deltab: number;
|
||||
|
||||
topsh: number;
|
||||
bottomsh: number;
|
||||
|
||||
@@ -96,9 +96,9 @@ const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace);
|
||||
typedef QMap<QString, uint32> ReplaceMap;
|
||||
ReplaceMap replaceMap;
|
||||
|
||||
static const int variantsCount = 5, inRow = 40, imSizes[] = { 18, 22, 27, 36, 45 };
|
||||
static const int emojiFontSizes[] = { 14, 20, 27, 36, 45 };
|
||||
static const int emojiDeltas[] = { 15, 20, 25, 34, 42 };
|
||||
static const int variantsCount = 5, inRow = 40, imSizes[] = { 18, 22, 27, 36, 45, 180 }, badSizes[] = { 1, 1, 0, 0, 0 };
|
||||
static const int emojiFontSizes[] = { 14, 20, 27, 36, 45, 180 };
|
||||
static const int emojiDeltas[] = { 15, 20, 25, 34, 42, 167 };
|
||||
static const char *variantPostfix[] = { "", "_125x", "_150x", "_200x", "_250x" };
|
||||
static const char *variantNames[] = { "dbisOne", "dbisOneAndQuarter", "dbisOneAndHalf", "dbisTwo" };
|
||||
|
||||
@@ -1382,23 +1382,32 @@ bool genEmoji(QString, const QString &emoji_out, const QString &emoji_png) {
|
||||
QStringList str = QFontDatabase::applicationFontFamilies(QFontDatabase::addApplicationFont(QStringLiteral("/System/Library/Fonts/Apple Color Emoji.ttf")));
|
||||
|
||||
for (int variantIndex = 0; variantIndex < variantsCount; variantIndex++) {
|
||||
int imSize = imSizes[variantIndex];
|
||||
int imSize = imSizes[variantIndex], bad = badSizes[variantIndex], badSize = (bad ? imSizes[5] : imSize);
|
||||
|
||||
QFont f(QGuiApplication::font());
|
||||
f.setFamily(QStringLiteral("Apple Color Emoji"));
|
||||
f.setPixelSize(emojiFontSizes[variantIndex]);
|
||||
f.setPixelSize(emojiFontSizes[bad ? 5 : variantIndex]);
|
||||
|
||||
int s = 4 + imSize;
|
||||
int s = 4 + badSize;
|
||||
QImage badImg(inRow * badSize, currentRow * badSize, QImage::Format_ARGB32);
|
||||
QImage emojisImg(inRow * imSize, currentRow * imSize, QImage::Format_ARGB32), emojiImg(s, s, QImage::Format_ARGB32);
|
||||
{
|
||||
QPainter p(&emojisImg);
|
||||
QPainter p(&emojisImg), q(&badImg);
|
||||
QPainter::CompositionMode m = p.compositionMode();
|
||||
p.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
p.fillRect(0, 0, emojisImg.width(), emojisImg.height(), Qt::transparent);
|
||||
p.setCompositionMode(m);
|
||||
p.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
if (bad) {
|
||||
QPainter::CompositionMode m = q.compositionMode();
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q.fillRect(0, 0, emojisImg.width(), emojisImg.height(), Qt::transparent);
|
||||
q.setCompositionMode(m);
|
||||
q.setRenderHint(QPainter::SmoothPixmapTransform);
|
||||
}
|
||||
for (EmojisData::const_iterator it = emojisData.cbegin(), e = emojisData.cend(); it != e; ++it) {
|
||||
QRect drawFrom(2, 2, imSize, imSize);
|
||||
QRect drawFrom(2, 2, badSize, badSize);
|
||||
QString es = textEmojiString(&it.value());
|
||||
{
|
||||
QPainter q(&emojiImg);
|
||||
q.setPen(QColor(0, 0, 0, 255));
|
||||
@@ -1407,7 +1416,7 @@ bool genEmoji(QString, const QString &emoji_out, const QString &emoji_png) {
|
||||
q.setCompositionMode(QPainter::CompositionMode_Source);
|
||||
q.fillRect(0, 0, emojiImg.width(), emojiImg.height(), Qt::transparent);
|
||||
q.setCompositionMode(m);
|
||||
q.drawText(2, 2 + emojiDeltas[variantIndex], textEmojiString(&it.value()));
|
||||
q.drawText(2, 2 + emojiDeltas[bad ? 5 : variantIndex], es);
|
||||
}
|
||||
int top = 1, bottom = 1, left = 1, right = 1;
|
||||
QRgb *b = (QRgb*)emojiImg.bits();
|
||||
@@ -1455,10 +1464,17 @@ bool genEmoji(QString, const QString &emoji_out, const QString &emoji_png) {
|
||||
drawFrom.setX(drawFrom.x() - 1);
|
||||
}
|
||||
}
|
||||
p.drawImage(QRect(it->x * imSize, it->y * imSize, imSize, imSize), emojiImg, drawFrom);
|
||||
if (bad) {
|
||||
p.drawImage(QRect(it->x * imSize, it->y * imSize, imSize, imSize), emojiImg.copy(2, 2, badSize, badSize).scaled(imSize, imSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));
|
||||
q.drawImage(QRect(it->x * badSize, it->y * badSize, badSize, badSize), emojiImg, QRect(2, 2, badSize, badSize));
|
||||
} else {
|
||||
p.drawImage(QRect(it->x * imSize, it->y * imSize, imSize, imSize), emojiImg, drawFrom);
|
||||
}
|
||||
}
|
||||
}
|
||||
QString postfix = variantPostfix[variantIndex], emojif = emoji_png + postfix + ".webp";
|
||||
// emojisImg.save(emoji_png + postfix + ".png");
|
||||
// if (bad) badImg.save(emoji_png + "_bad.png");
|
||||
QByteArray emojib;
|
||||
{
|
||||
QBuffer ebuf(&emojib);
|
||||
|
||||
@@ -34,7 +34,6 @@ ApiWrap::ApiWrap(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
void ApiWrap::init() {
|
||||
App::initMedia();
|
||||
}
|
||||
|
||||
void ApiWrap::itemRemoved(HistoryItem *item) {
|
||||
|
||||
@@ -633,7 +633,7 @@ namespace App {
|
||||
const MTPDphotoSize &d(size.c_photoSize());
|
||||
if (d.vlocation.type() == mtpc_fileLocation) {
|
||||
const MTPDfileLocation &l(d.vlocation.c_fileLocation());
|
||||
return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v, d.vsize.v);
|
||||
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), d.vsize.v);
|
||||
}
|
||||
} break;
|
||||
case mtpc_photoCachedSize: {
|
||||
@@ -642,17 +642,43 @@ namespace App {
|
||||
const MTPDfileLocation &l(d.vlocation.c_fileLocation());
|
||||
const string &s(d.vbytes.c_string().v);
|
||||
QByteArray bytes(s.data(), s.size());
|
||||
return ImagePtr(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v, bytes);
|
||||
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v), bytes);
|
||||
} else if (d.vlocation.type() == mtpc_fileLocationUnavailable) {
|
||||
const string &s(d.vbytes.c_string().v);
|
||||
QByteArray bytes(s.data(), s.size());
|
||||
return ImagePtr(d.vw.v, d.vh.v, 0, 0, 0, 0, bytes);
|
||||
return ImagePtr(StorageImageLocation(d.vw.v, d.vh.v, 0, 0, 0, 0), bytes);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return ImagePtr();
|
||||
}
|
||||
|
||||
StorageImageLocation imageLocation(const MTPPhotoSize &size) {
|
||||
switch (size.type()) {
|
||||
case mtpc_photoSize: {
|
||||
const MTPDphotoSize &d(size.c_photoSize());
|
||||
if (d.vlocation.type() == mtpc_fileLocation) {
|
||||
const MTPDfileLocation &l(d.vlocation.c_fileLocation());
|
||||
return StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v);
|
||||
}
|
||||
} break;
|
||||
case mtpc_photoCachedSize: {
|
||||
const MTPDphotoCachedSize &d(size.c_photoCachedSize());
|
||||
if (d.vlocation.type() == mtpc_fileLocation) {
|
||||
const MTPDfileLocation &l(d.vlocation.c_fileLocation());
|
||||
const string &s(d.vbytes.c_string().v);
|
||||
QByteArray bytes(s.data(), s.size());
|
||||
return StorageImageLocation(d.vw.v, d.vh.v, l.vdc_id.v, l.vvolume_id.v, l.vlocal_id.v, l.vsecret.v);
|
||||
} else if (d.vlocation.type() == mtpc_fileLocationUnavailable) {
|
||||
const string &s(d.vbytes.c_string().v);
|
||||
QByteArray bytes(s.data(), s.size());
|
||||
return StorageImageLocation(d.vw.v, d.vh.v, 0, 0, 0, 0);
|
||||
}
|
||||
} break;
|
||||
}
|
||||
return StorageImageLocation();
|
||||
}
|
||||
|
||||
void feedWereRead(const QVector<MTPint> &msgsIds) {
|
||||
for (QVector<MTPint>::const_iterator i = msgsIds.cbegin(), e = msgsIds.cend(); i != e; ++i) {
|
||||
MsgsData::const_iterator j = msgsData.constFind(i->v);
|
||||
@@ -874,7 +900,7 @@ namespace App {
|
||||
switch (document.type()) {
|
||||
case mtpc_document: {
|
||||
const MTPDdocument &d(document.c_document());
|
||||
return App::document(d.vid.v, 0, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v);
|
||||
return App::documentSet(d.vid.v, 0, d.vaccess_hash.v, d.vdate.v, d.vattributes.c_vector().v, qs(d.vmime_type), ImagePtr(thumb, "JPG"), d.vdc_id.v, d.vsize.v, StorageImageLocation());
|
||||
} break;
|
||||
case mtpc_documentEmpty: return App::document(document.c_documentEmpty().vid.v);
|
||||
}
|
||||
@@ -887,14 +913,14 @@ namespace App {
|
||||
return feedDocument(document.c_document(), convert);
|
||||
} break;
|
||||
case mtpc_documentEmpty: {
|
||||
return App::document(document.c_documentEmpty().vid.v, convert);
|
||||
return App::documentSet(document.c_documentEmpty().vid.v, convert, 0, 0, QVector<MTPDocumentAttribute>(), QString(), ImagePtr(), 0, 0, StorageImageLocation());
|
||||
} break;
|
||||
}
|
||||
return App::document(0);
|
||||
}
|
||||
|
||||
DocumentData *feedDocument(const MTPDdocument &document, DocumentData *convert) {
|
||||
return App::document(document.vid.v, convert, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v);
|
||||
return App::documentSet(document.vid.v, convert, document.vaccess_hash.v, document.vdate.v, document.vattributes.c_vector().v, qs(document.vmime_type), App::image(document.vthumb), document.vdc_id.v, document.vsize.v, App::imageLocation(document.vthumb));
|
||||
}
|
||||
|
||||
WebPageData *feedWebPage(const MTPDwebPage &webpage, WebPageData *convert) {
|
||||
@@ -1128,7 +1154,15 @@ namespace App {
|
||||
return result;
|
||||
}
|
||||
|
||||
DocumentData *document(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) {
|
||||
DocumentData *document(const DocumentId &document) {
|
||||
DocumentsData::const_iterator i = documentsData.constFind(document);
|
||||
if (i == documentsData.cend()) {
|
||||
i = documentsData.insert(document, new DocumentData(document));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation) {
|
||||
if (convert) {
|
||||
if (convert->id != document) {
|
||||
DocumentsData::iterator i = documentsData.find(convert->id);
|
||||
@@ -1146,12 +1180,28 @@ namespace App {
|
||||
convert->thumb = thumb;
|
||||
convert->dc = dc;
|
||||
convert->size = size;
|
||||
} else if (convert->thumb->isNull() && !thumb->isNull()) {
|
||||
convert->thumb = thumb;
|
||||
} else {
|
||||
if (!thumb->isNull() && (convert->thumb->isNull() || convert->thumb->width() < thumb->width() || convert->thumb->height() < thumb->height())) {
|
||||
convert->thumb = thumb;
|
||||
}
|
||||
if (convert->sticker && !attributes.isEmpty() && (convert->sticker->alt.isEmpty() || convert->sticker->set.type() == mtpc_inputStickerSetEmpty)) {
|
||||
for (QVector<MTPDocumentAttribute>::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) {
|
||||
if (i->type() == mtpc_documentAttributeSticker) {
|
||||
const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker());
|
||||
if (d.valt.c_string().v.length() > 0) {
|
||||
convert->sticker->alt = qs(d.valt);
|
||||
convert->sticker->set = d.vstickerset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (convert->sticker && !convert->sticker->loc.dc && thumbLocation.dc) {
|
||||
convert->sticker->loc = thumbLocation;
|
||||
}
|
||||
|
||||
if (convert->location.check()) {
|
||||
Local::writeFileLocation(mediaKey(mtpc_inputDocumentFileLocation, convert->dc, convert->id), convert->location);
|
||||
Local::writeFileLocation(mediaKey(DocumentFileLocation, convert->dc, convert->id), convert->location);
|
||||
}
|
||||
}
|
||||
DocumentsData::const_iterator i = documentsData.constFind(document);
|
||||
@@ -1161,6 +1211,7 @@ namespace App {
|
||||
result = convert;
|
||||
} else {
|
||||
result = new DocumentData(document, access, date, attributes, mime, thumb, dc, size);
|
||||
if (result->sticker) result->sticker->loc = thumbLocation;
|
||||
}
|
||||
documentsData.insert(document, result);
|
||||
} else {
|
||||
@@ -1175,19 +1226,23 @@ namespace App {
|
||||
result->dc = dc;
|
||||
result->size = size;
|
||||
} else {
|
||||
if (result->thumb->isNull() && !thumb->isNull()) {
|
||||
if (!thumb->isNull() && (result->thumb->isNull() || result->thumb->width() < thumb->width() || result->thumb->height() < thumb->height())) {
|
||||
result->thumb = thumb;
|
||||
}
|
||||
if (result->alt.isEmpty()) {
|
||||
if (result->sticker && !attributes.isEmpty() && (result->sticker->alt.isEmpty() || result->sticker->set.type() == mtpc_inputStickerSetEmpty)) {
|
||||
for (QVector<MTPDocumentAttribute>::const_iterator i = attributes.cbegin(), e = attributes.cend(); i != e; ++i) {
|
||||
if (i->type() == mtpc_documentAttributeSticker) {
|
||||
const MTPDdocumentAttributeSticker &d(i->c_documentAttributeSticker());
|
||||
if (d.valt.c_string().v.length() > 0) {
|
||||
result->alt = qs(d.valt);
|
||||
result->sticker->alt = qs(d.valt);
|
||||
result->sticker->set = d.vstickerset;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result->sticker && !result->sticker->loc.dc && thumbLocation.dc) {
|
||||
result->sticker->loc = thumbLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1464,8 +1519,9 @@ namespace App {
|
||||
if (api()) api()->clearWebPageRequests();
|
||||
cSetRecentStickers(RecentStickerPack());
|
||||
cSetStickersHash(QByteArray());
|
||||
cSetStickers(AllStickers());
|
||||
cSetEmojiStickers(EmojiStickersMap());
|
||||
cSetStickerSets(StickerSets());
|
||||
cSetLastStickersUpdate(0);
|
||||
::videoItems.clear();
|
||||
::audioItems.clear();
|
||||
::documentItems.clear();
|
||||
@@ -1854,6 +1910,12 @@ namespace App {
|
||||
}
|
||||
}
|
||||
|
||||
void stickersBox(const QString &name) {
|
||||
if (App::main()) {
|
||||
App::main()->stickersBox(MTP_inputStickerSetShortName(MTP_string(name)));
|
||||
}
|
||||
}
|
||||
|
||||
void openLocalUrl(const QString &url) {
|
||||
if (App::main()) {
|
||||
App::main()->openLocalUrl(url);
|
||||
|
||||
@@ -87,6 +87,7 @@ namespace App {
|
||||
int32 maxMsgId();
|
||||
|
||||
ImagePtr image(const MTPPhotoSize &size);
|
||||
StorageImageLocation imageLocation(const MTPPhotoSize &size);
|
||||
|
||||
PhotoData *feedPhoto(const MTPPhoto &photo, const PreparedPhotoThumbs &thumbs);
|
||||
PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert = 0);
|
||||
@@ -117,7 +118,8 @@ namespace App {
|
||||
PhotoData *photo(const PhotoId &photo, PhotoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const ImagePtr &thumb = ImagePtr(), const ImagePtr &medium = ImagePtr(), const ImagePtr &full = ImagePtr());
|
||||
VideoData *video(const VideoId &video, VideoData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, int32 duration = 0, int32 w = 0, int32 h = 0, const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
|
||||
AudioData *audio(const AudioId &audio, AudioData *convert = 0, const uint64 &access = 0, int32 user = 0, int32 date = 0, const QString &mime = QString(), int32 duration = 0, int32 dc = 0, int32 size = 0);
|
||||
DocumentData *document(const DocumentId &document, DocumentData *convert = 0, const uint64 &access = 0, int32 date = 0, const QVector<MTPDocumentAttribute> &attributes = QVector<MTPDocumentAttribute>(), const QString &mime = QString(), const ImagePtr &thumb = ImagePtr(), int32 dc = 0, int32 size = 0);
|
||||
DocumentData *document(const DocumentId &document);
|
||||
DocumentData *documentSet(const DocumentId &document, DocumentData *convert, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size, const StorageImageLocation &thumbLocation);
|
||||
WebPageData *webPage(const WebPageId &webPage, WebPageData *convert = 0, const QString &type = QString(), const QString &url = QString(), const QString &displayUrl = QString(), const QString &siteName = QString(), const QString &title = QString(), const QString &description = QString(), PhotoData *photo = 0, int32 duration = 0, const QString &author = QString(), int32 pendingTill = -2);
|
||||
ImageLinkData *imageLink(const QString &imageLink, ImageLinkType type = InvalidImageLink, const QString &url = QString());
|
||||
void forgetMedia();
|
||||
@@ -200,6 +202,7 @@ namespace App {
|
||||
void searchByHashtag(const QString &tag);
|
||||
void openUserByName(const QString &username, bool toProfile = false);
|
||||
void joinGroupByHash(const QString &hash);
|
||||
void stickersBox(const QString &name);
|
||||
void openLocalUrl(const QString &url);
|
||||
|
||||
void initBackground(int32 id = DefaultChatBackground, const QImage &p = QImage(), bool nowrite = false);
|
||||
|
||||
@@ -662,9 +662,9 @@ void Application::checkMapVersion() {
|
||||
psRegisterCustomScheme();
|
||||
if (Local::oldMapVersion()) {
|
||||
QString versionFeatures;
|
||||
if (DevChannel && Local::oldMapVersion() < 8012) {
|
||||
versionFeatures = QString::fromUtf8("\xe2\x80\x94 New emojis support added\n\xe2\x80\x94 Emojis and stickers panel improved").replace('@', qsl("@") + QChar(0x200D));
|
||||
} else if (!DevChannel && Local::oldMapVersion() < 8011) {
|
||||
if (DevChannel && Local::oldMapVersion() < 8014) {
|
||||
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Added support for sticker packs\n\xe2\x80\x94 New emoji and sticker panel").replace('@', qsl("@") + QChar(0x200D));
|
||||
} else if (!DevChannel && Local::oldMapVersion() < 8013) {
|
||||
versionFeatures = lang(lng_new_version_text).trimmed();
|
||||
}
|
||||
if (!versionFeatures.isEmpty()) {
|
||||
|
||||
|
Before Width: | Height: | Size: 684 KiB After Width: | Height: | Size: 586 KiB |
|
Before Width: | Height: | Size: 947 KiB After Width: | Height: | Size: 789 KiB |
|
Before Width: | Height: | Size: 164 KiB After Width: | Height: | Size: 164 KiB |
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 215 KiB |
@@ -68,12 +68,12 @@ namespace {
|
||||
const uint32 replacesCount = sizeof(replaces) / sizeof(EmojiReplace), replacesInRow = 7;
|
||||
}
|
||||
|
||||
EmojiBox::EmojiBox() : _done(this, lang(lng_about_done), st::aboutCloseButton) {
|
||||
EmojiBox::EmojiBox() : _esize(EmojiSizes[EIndex + 1]), _done(this, lang(lng_about_done), st::aboutCloseButton) {
|
||||
fillBlocks();
|
||||
|
||||
_blockHeight = st::emojiReplaceInnerHeight;
|
||||
|
||||
resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + (st::emojiReplaceWidth - st::emojiSize), st::boxPadding.top() + st::boxFont->height + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + _done.height());
|
||||
resizeMaxHeight(_blocks[0].size() * st::emojiReplaceWidth + (st::emojiReplaceWidth - _esize), st::boxPadding.top() + st::boxFont->height + _blocks.size() * st::emojiReplaceHeight + (st::emojiReplaceHeight - _blockHeight) + _done.height());
|
||||
|
||||
connect(&_done, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
|
||||
@@ -84,7 +84,21 @@ void EmojiBox::fillBlocks() {
|
||||
BlockRow currentRow;
|
||||
currentRow.reserve(replacesInRow);
|
||||
for (uint32 i = 0; i < replacesCount; ++i) {
|
||||
Block block(emojiGet(replaces[i].code), QString::fromUtf8(replaces[i].replace));
|
||||
EmojiPtr emoji = emojiGet(replaces[i].code);
|
||||
if (!emoji || emoji == TwoSymbolEmoji) continue;
|
||||
if (emoji->color) {
|
||||
EmojiColorVariants::const_iterator it = cEmojiVariants().constFind(emoji->code);
|
||||
if (it != cEmojiVariants().cend()) {
|
||||
EmojiPtr replace = emojiFromKey(it.value());
|
||||
if (replace) {
|
||||
if (replace != TwoSymbolEmoji && replace->code == emoji->code && replace->code2 == emoji->code2) {
|
||||
emoji = replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Block block(emoji, QString::fromUtf8(replaces[i].replace));
|
||||
currentRow.push_back(block);
|
||||
if (uint32(currentRow.size()) == replacesInRow) {
|
||||
_blocks.push_back(currentRow);
|
||||
@@ -125,7 +139,7 @@ void EmojiBox::paintEvent(QPaintEvent *e) {
|
||||
int32 rowSize = i->size(), left = (width() - rowSize * st::emojiReplaceWidth) / 2;
|
||||
for (BlockRow::const_iterator j = i->cbegin(), en = i->cend(); j != en; ++j) {
|
||||
if (j->emoji) {
|
||||
emojiDraw(p, j->emoji, left + (st::emojiReplaceWidth - st::emojiSize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2);
|
||||
p.drawPixmap(QPoint(left + (st::emojiReplaceWidth - _esize) / 2, top + (st::emojiReplaceHeight - _blockHeight) / 2), App::emojisLarge(), QRect(j->emoji->x * _esize, j->emoji->y * _esize, _esize, _esize));
|
||||
}
|
||||
QRect trect(left, top + (st::emojiReplaceHeight + _blockHeight) / 2 - st::emojiTextFont->height, st::emojiReplaceWidth, st::emojiTextFont->height);
|
||||
p.drawText(trect, j->text, QTextOption(Qt::AlignHCenter | Qt::AlignTop));
|
||||
|
||||
@@ -38,6 +38,7 @@ private:
|
||||
|
||||
void fillBlocks();
|
||||
|
||||
int32 _esize;
|
||||
BottomButton _done;
|
||||
|
||||
int32 _blockHeight;
|
||||
|
||||
275
Telegram/SourceFiles/boxes/stickersetbox.cpp
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#include "stdafx.h"
|
||||
#include "lang.h"
|
||||
|
||||
#include "stickersetbox.h"
|
||||
#include "mainwidget.h"
|
||||
#include "window.h"
|
||||
#include "settingswidget.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
StickerSetInner::StickerSetInner(const MTPInputStickerSet &set) :
|
||||
_loaded(false), _setId(0), _setAccess(0), _bottom(0),
|
||||
_input(set), _installRequest(0) {
|
||||
switch (set.type()) {
|
||||
case mtpc_inputStickerSetID: _setId = set.c_inputStickerSetID().vid.v; _setAccess = set.c_inputStickerSetID().vaccess_hash.v; break;
|
||||
case mtpc_inputStickerSetShortName: _setShortName = qs(set.c_inputStickerSetShortName().vshort_name); break;
|
||||
}
|
||||
MTP::send(MTPmessages_GetStickerSet(_input), rpcDone(&StickerSetInner::gotSet), rpcFail(&StickerSetInner::failedSet));
|
||||
cSetLastStickersUpdate(0);
|
||||
App::main()->updateStickers();
|
||||
}
|
||||
|
||||
void StickerSetInner::gotSet(const MTPmessages_StickerSet &set) {
|
||||
_pack.clear();
|
||||
if (set.type() == mtpc_messages_stickerSet) {
|
||||
const MTPDmessages_stickerSet &d(set.c_messages_stickerSet());
|
||||
const QVector<MTPDocument> &v(d.vdocuments.c_vector().v);
|
||||
_pack.reserve(v.size());
|
||||
for (int32 i = 0, l = v.size(); i < l; ++i) {
|
||||
DocumentData *doc = App::feedDocument(v.at(i));
|
||||
if (!doc || !doc->sticker) continue;
|
||||
|
||||
_pack.push_back(doc);
|
||||
}
|
||||
if (d.vset.type() == mtpc_stickerSet) {
|
||||
const MTPDstickerSet &s(d.vset.c_stickerSet());
|
||||
_setTitle = qs(s.vtitle);
|
||||
_title = st::boxTitleFont->m.elidedText(_setTitle, Qt::ElideRight, width() - st::btnStickersClose.width - st::boxTitlePos.x());
|
||||
_setShortName = qs(s.vshort_name);
|
||||
_setId = s.vid.v;
|
||||
_setAccess = s.vaccess_hash.v;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pack.isEmpty() || _setShortName.isEmpty()) {
|
||||
App::wnd()->showLayer(new ConfirmBox(lang(lng_stickers_not_found), true), true);
|
||||
} else {
|
||||
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
|
||||
resize(st::stickersPadding + StickerPanPerRow * st::stickersSize.width(), rows * st::stickersSize.height() + st::stickersAddOrShare);
|
||||
}
|
||||
_loaded = true;
|
||||
|
||||
emit updateButtons();
|
||||
}
|
||||
|
||||
bool StickerSetInner::failedSet(const RPCError &error) {
|
||||
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
|
||||
|
||||
_loaded = true;
|
||||
|
||||
App::wnd()->showLayer(new ConfirmBox(lang(lng_stickers_not_found), true), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StickerSetInner::installDone(const MTPBool &result) {
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
sets.insert(_setId, StickerSet(_setId, _setAccess, _setTitle, _setShortName)).value().stickers = _pack;
|
||||
cSetStickersHash(QByteArray());
|
||||
Local::writeStickers();
|
||||
emit installed(_setId);
|
||||
App::wnd()->hideLayer();
|
||||
}
|
||||
|
||||
bool StickerSetInner::installFailed(const RPCError &error) {
|
||||
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
|
||||
|
||||
App::wnd()->showLayer(new ConfirmBox(lang(lng_stickers_not_found), true), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StickerSetInner::paintEvent(QPaintEvent *e) {
|
||||
QRect r(e->rect());
|
||||
Painter p(this);
|
||||
|
||||
if (_pack.isEmpty()) return;
|
||||
|
||||
int32 rows = _pack.size() / StickerPanPerRow + ((_pack.size() % StickerPanPerRow) ? 1 : 0);
|
||||
int32 from = qFloor(e->rect().top() / st::stickersSize.height()), to = qFloor(e->rect().bottom() / st::stickersSize.height()) + 1;
|
||||
|
||||
for (int32 i = from; i < to; ++i) {
|
||||
for (int32 j = 0; j < StickerPanPerRow; ++j) {
|
||||
int32 index = i * StickerPanPerRow + j;
|
||||
if (index >= _pack.size()) break;
|
||||
|
||||
DocumentData *doc = _pack.at(index);
|
||||
QPoint pos(st::stickerPanPadding + j * st::stickersSize.width(), i * st::stickersSize.height());
|
||||
|
||||
bool goodThumb = !doc->thumb->isNull() && ((doc->thumb->width() >= 128) || (doc->thumb->height() >= 128));
|
||||
if (goodThumb) {
|
||||
doc->thumb->load();
|
||||
} else {
|
||||
bool already = !doc->already().isEmpty(), hasdata = !doc->data.isEmpty();
|
||||
if (!doc->loader && doc->status != FileFailed && !already && !hasdata) {
|
||||
doc->save(QString());
|
||||
}
|
||||
if (doc->sticker->img->isNull() && (already || hasdata)) {
|
||||
if (already) {
|
||||
doc->sticker->img = ImagePtr(doc->already());
|
||||
} else {
|
||||
doc->sticker->img = ImagePtr(doc->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float64 coef = qMin((st::stickersSize.width() - st::stickerPanRound * 2) / float64(doc->dimensions.width()), (st::stickersSize.height() - st::stickerPanRound * 2) / float64(doc->dimensions.height()));
|
||||
if (coef > 1) coef = 1;
|
||||
int32 w = qRound(coef * doc->dimensions.width()), h = qRound(coef * doc->dimensions.height());
|
||||
if (w < 1) w = 1;
|
||||
if (h < 1) h = 1;
|
||||
QPoint ppos = pos + QPoint((st::stickersSize.width() - w) / 2, (st::stickersSize.height() - h) / 2);
|
||||
if (goodThumb) {
|
||||
p.drawPixmapLeft(ppos, width(), doc->thumb->pix(w, h));
|
||||
} else if (!doc->sticker->img->isNull()) {
|
||||
p.drawPixmapLeft(ppos, width(), doc->sticker->img->pix(w, h));
|
||||
}
|
||||
}
|
||||
}
|
||||
p.fillRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare, st::emojiPanHeaderBg->b);
|
||||
}
|
||||
|
||||
void StickerSetInner::setScrollBottom(int32 bottom) {
|
||||
if (bottom == _bottom) return;
|
||||
|
||||
QRegion upd = QRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare);
|
||||
_bottom = bottom;
|
||||
upd += QRect(0, _bottom - st::stickersAddOrShare, width(), st::stickersAddOrShare);
|
||||
repaint(upd);
|
||||
}
|
||||
|
||||
bool StickerSetInner::loaded() const {
|
||||
return _loaded && !_pack.isEmpty();
|
||||
}
|
||||
|
||||
int32 StickerSetInner::notInstalled() const {
|
||||
return (_loaded && (cStickerSets().constFind(_setId) == cStickerSets().cend())) ? _pack.size() : 0;
|
||||
}
|
||||
|
||||
QString StickerSetInner::title() const {
|
||||
return _loaded ? (_pack.isEmpty() ? lang(lng_attach_failed) : _title) : lang(lng_contacts_loading);
|
||||
}
|
||||
|
||||
QString StickerSetInner::shortName() const {
|
||||
return _setShortName;
|
||||
}
|
||||
|
||||
void StickerSetInner::install() {
|
||||
if (_installRequest) return;
|
||||
_installRequest = MTP::send(MTPmessages_InstallStickerSet(_input), rpcDone(&StickerSetInner::installDone), rpcFail(&StickerSetInner::installFailed));
|
||||
}
|
||||
|
||||
StickerSetInner::~StickerSetInner() {
|
||||
}
|
||||
|
||||
StickerSetBox::StickerSetBox(const MTPInputStickerSet &set) : ScrollableBox(st::stickersScroll), _inner(set),
|
||||
_close(this, st::btnStickersClose),
|
||||
_addStickers(this, lng_stickers_add_pack(lt_count, 0), st::btnStickersAdd),
|
||||
_shareStickers(this, lang(lng_stickers_share_pack), st::btnStickersAdd) {
|
||||
resize(st::stickersWidth, height());
|
||||
setMaxHeight(st::stickersMaxHeight);
|
||||
connect(App::main(), SIGNAL(stickersUpdated()), this, SLOT(onStickersUpdated()));
|
||||
|
||||
init(&_inner, 0, st::boxFont->height + st::newGroupNamePadding.top() + st::newGroupNamePadding.bottom());
|
||||
|
||||
connect(&_close, SIGNAL(clicked()), this, SLOT(onClose()));
|
||||
connect(&_addStickers, SIGNAL(clicked()), this, SLOT(onAddStickers()));
|
||||
connect(&_shareStickers, SIGNAL(clicked()), this, SLOT(onShareStickers()));
|
||||
|
||||
connect(&_inner, SIGNAL(updateButtons()), this, SLOT(onUpdateButtons()));
|
||||
connect(&_scroll, SIGNAL(scrolled()), this, SLOT(onScroll()));
|
||||
|
||||
connect(&_inner, SIGNAL(installed(uint64)), this, SIGNAL(installed(uint64)));
|
||||
|
||||
onStickersUpdated();
|
||||
|
||||
onScroll();
|
||||
|
||||
prepare();
|
||||
}
|
||||
|
||||
void StickerSetBox::onStickersUpdated() {
|
||||
showAll();
|
||||
}
|
||||
|
||||
void StickerSetBox::onAddStickers() {
|
||||
_inner.install();
|
||||
}
|
||||
|
||||
void StickerSetBox::onShareStickers() {
|
||||
QString url = qsl("https://telegram.me/addstickers/") + _inner.shortName();
|
||||
DEBUG_LOG(("Setting text to clipboard from stickerset box: %1").arg(url));
|
||||
QApplication::clipboard()->setText(url);
|
||||
App::wnd()->showLayer(new ConfirmBox(lang(lng_stickers_copied), true), true);
|
||||
}
|
||||
|
||||
void StickerSetBox::onUpdateButtons() {
|
||||
if (!_close.isHidden()) showAll();
|
||||
}
|
||||
|
||||
void StickerSetBox::onScroll() {
|
||||
_inner.setScrollBottom(_scroll.scrollTop() + _scroll.height());
|
||||
}
|
||||
|
||||
void StickerSetBox::hideAll() {
|
||||
ScrollableBox::hideAll();
|
||||
_close.hide();
|
||||
_addStickers.hide();
|
||||
_shareStickers.hide();
|
||||
}
|
||||
|
||||
void StickerSetBox::showAll() {
|
||||
ScrollableBox::showAll();
|
||||
_close.show();
|
||||
int32 cnt = _inner.notInstalled();
|
||||
if (_inner.loaded()) {
|
||||
if (_inner.notInstalled()) {
|
||||
_addStickers.setText(lng_stickers_add_pack(lt_count, cnt));
|
||||
_addStickers.show();
|
||||
_addStickers.raise();
|
||||
_shareStickers.hide();
|
||||
} else {
|
||||
_shareStickers.show();
|
||||
_shareStickers.raise();
|
||||
_addStickers.hide();
|
||||
}
|
||||
} else {
|
||||
_addStickers.hide();
|
||||
_shareStickers.hide();
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void StickerSetBox::paintEvent(QPaintEvent *e) {
|
||||
Painter p(this);
|
||||
if (paint(p)) return;
|
||||
|
||||
paintTitle(p, _inner.title(), false);
|
||||
}
|
||||
|
||||
void StickerSetBox::resizeEvent(QResizeEvent *e) {
|
||||
ScrollableBox::resizeEvent(e);
|
||||
_inner.resize(width(), _inner.height());
|
||||
_close.moveToRight(0, 0, width());
|
||||
_addStickers.move((width() - _addStickers.width()) / 2, height() - (st::stickersAddOrShare + _addStickers.height()) / 2);
|
||||
_shareStickers.move((width() - _shareStickers.width()) / 2, height() - (st::stickersAddOrShare + _shareStickers.height()) / 2);
|
||||
}
|
||||
100
Telegram/SourceFiles/boxes/stickersetbox.h
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
This file is part of Telegram Desktop,
|
||||
the official desktop version of Telegram messaging app, see https://telegram.org
|
||||
|
||||
Telegram Desktop is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
It is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE
|
||||
Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "abstractbox.h"
|
||||
|
||||
class StickerSetInner : public QWidget, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
StickerSetInner(const MTPInputStickerSet &set);
|
||||
|
||||
void init();
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
bool loaded() const;
|
||||
int32 notInstalled() const;
|
||||
QString title() const;
|
||||
QString shortName() const;
|
||||
|
||||
void setScrollBottom(int32 bottom);
|
||||
void install();
|
||||
|
||||
~StickerSetInner();
|
||||
|
||||
signals:
|
||||
|
||||
void updateButtons();
|
||||
void installed(uint64 id);
|
||||
|
||||
private:
|
||||
|
||||
void gotSet(const MTPmessages_StickerSet &set);
|
||||
bool failedSet(const RPCError &error);
|
||||
|
||||
void installDone(const MTPBool &result);
|
||||
bool installFailed(const RPCError &error);
|
||||
|
||||
StickerPack _pack;
|
||||
bool _loaded;
|
||||
uint64 _setId, _setAccess;
|
||||
QString _title, _setTitle, _setShortName;
|
||||
|
||||
int32 _bottom;
|
||||
MTPInputStickerSet _input;
|
||||
|
||||
mtpRequestId _installRequest;
|
||||
};
|
||||
|
||||
class StickerSetBox : public ScrollableBox, public RPCSender {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
StickerSetBox(const MTPInputStickerSet &set);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
void resizeEvent(QResizeEvent *e);
|
||||
|
||||
public slots:
|
||||
|
||||
void onStickersUpdated();
|
||||
void onAddStickers();
|
||||
void onShareStickers();
|
||||
void onUpdateButtons();
|
||||
|
||||
void onScroll();
|
||||
|
||||
signals:
|
||||
|
||||
void installed(uint64 id);
|
||||
|
||||
protected:
|
||||
|
||||
void hideAll();
|
||||
void showAll();
|
||||
|
||||
private:
|
||||
|
||||
StickerSetInner _inner;
|
||||
IconedButton _close;
|
||||
FlatButton _addStickers, _shareStickers;
|
||||
};
|
||||
@@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const int32 AppVersion = 8012;
|
||||
static const wchar_t *AppVersionStr = L"0.8.12";
|
||||
static const int32 AppVersion = 8014;
|
||||
static const wchar_t *AppVersionStr = L"0.8.14";
|
||||
static const bool DevChannel = true;
|
||||
|
||||
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
|
||||
@@ -101,9 +101,10 @@ enum {
|
||||
ZoomToScreenLevel = 1024, // just constant
|
||||
|
||||
PreloadHeightsCount = 3, // when 3 screens to scroll left make a preload request
|
||||
EmojiPadPerRow = 7,
|
||||
EmojiPadRowsPerPage = 6,
|
||||
StickerPadPerRow = 3,
|
||||
EmojiPanPerRow = 7,
|
||||
EmojiPanRowsPerPage = 6,
|
||||
StickerPanPerRow = 5,
|
||||
StickerPanRowsPerPage = 4,
|
||||
StickersUpdateTimeout = 3600000, // update not more than once in an hour
|
||||
|
||||
SearchPeopleLimit = 5,
|
||||
|
||||
@@ -1122,7 +1122,7 @@ void DialogsListWidget::saveRecentHashtags(const QString &text) {
|
||||
}
|
||||
}
|
||||
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
|
||||
Local::readRecentStickers();
|
||||
Local::readRecentHashtags();
|
||||
recent = cRecentSearchHashtags();
|
||||
}
|
||||
found = true;
|
||||
|
||||
@@ -193,6 +193,8 @@ private:
|
||||
|
||||
};
|
||||
|
||||
static const int32 SwitcherSelected = (INT_MAX / 2);
|
||||
|
||||
class EmojiPanInner : public TWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
@@ -218,7 +220,6 @@ public:
|
||||
|
||||
DBIEmojiTab currentTab(int yOffset) const;
|
||||
|
||||
void refreshStickers();
|
||||
void refreshRecent();
|
||||
|
||||
void setScrollTop(int top);
|
||||
@@ -234,30 +235,27 @@ public slots:
|
||||
|
||||
signals:
|
||||
|
||||
void emojiSelected(EmojiPtr emoji);
|
||||
void stickerSelected(DocumentData *sticker);
|
||||
void selected(EmojiPtr emoji);
|
||||
|
||||
void switchToStickers();
|
||||
|
||||
void scrollToY(int y);
|
||||
void disableScroll(bool dis);
|
||||
|
||||
private:
|
||||
|
||||
int countHeight();
|
||||
int32 countHeight();
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
|
||||
typedef QMap<int32, uint64> EmojiAnimations; // index - showing, -index - hiding
|
||||
EmojiAnimations _emojiAnimations;
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
|
||||
int _top;
|
||||
int _counts[emojiTabCount], _count;
|
||||
int32 _top, _counts[emojiTabCount];
|
||||
|
||||
StickerPack _stickers;
|
||||
QVector<bool> _isUserGen;
|
||||
QVector<EmojiPtr> _emojis[emojiTabCount];
|
||||
QVector<float64> _hovers[emojiTabCount + 1]; // + stickers hovers and stickers-x hovers
|
||||
QVector<float64> _hovers[emojiTabCount];
|
||||
|
||||
float64 _stickerWidth;
|
||||
int32 _esize, _stickerSize;
|
||||
int32 _esize;
|
||||
|
||||
int32 _selected, _pressedSel, _pickerSel;
|
||||
QPoint _lastMousePos;
|
||||
@@ -267,6 +265,74 @@ private:
|
||||
EmojiColorPicker _picker;
|
||||
QTimer _showPickerTimer;
|
||||
|
||||
float64 _switcherHover;
|
||||
int32 _stickersWidth;
|
||||
};
|
||||
|
||||
class StickerPanInner : public TWidget, public Animated {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
StickerPanInner(QWidget *parent = 0);
|
||||
|
||||
void paintEvent(QPaintEvent *e);
|
||||
|
||||
void mousePressEvent(QMouseEvent *e);
|
||||
void mouseReleaseEvent(QMouseEvent *e);
|
||||
void mouseMoveEvent(QMouseEvent *e);
|
||||
void leaveEvent(QEvent *e);
|
||||
void leaveToChildEvent(QEvent *e);
|
||||
void enterFromChildEvent(QEvent *e);
|
||||
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void showStickerSet(uint64 setId);
|
||||
|
||||
void clearSelection(bool fast = false);
|
||||
|
||||
void refreshStickers();
|
||||
void refreshRecent(bool resize = true);
|
||||
|
||||
void setScrollTop(int top);
|
||||
void preloadImages();
|
||||
|
||||
public slots:
|
||||
|
||||
void updateSelected();
|
||||
|
||||
signals:
|
||||
|
||||
void selected(DocumentData *sticker);
|
||||
void removing(uint64 setId);
|
||||
|
||||
void switchToEmoji();
|
||||
|
||||
void scrollToY(int y);
|
||||
void disableScroll(bool dis);
|
||||
|
||||
private:
|
||||
|
||||
void appendSet(StickerSets::const_iterator it);
|
||||
|
||||
int32 countHeight();
|
||||
void selectEmoji(EmojiPtr emoji);
|
||||
|
||||
typedef QMap<int32, uint64> Animations; // index - showing, -index - hiding
|
||||
Animations _animations;
|
||||
|
||||
int32 _top;
|
||||
|
||||
QList<QString> _titles;
|
||||
QList<uint64> _setIds;
|
||||
QList<StickerPack> _sets;
|
||||
QList<QVector<float64> > _hovers;
|
||||
|
||||
int32 _selected, _pressedSel;
|
||||
QPoint _lastMousePos;
|
||||
|
||||
float64 _switcherHover;
|
||||
int32 _emojiWidth;
|
||||
};
|
||||
|
||||
class EmojiPan : public TWidget, public Animated {
|
||||
@@ -291,11 +357,12 @@ public:
|
||||
bool animStep(float64 ms);
|
||||
|
||||
bool eventFilter(QObject *obj, QEvent *e);
|
||||
|
||||
void refreshStickers();
|
||||
void stickersInstalled(uint64 setId);
|
||||
|
||||
public slots:
|
||||
|
||||
void refreshStickers();
|
||||
|
||||
void hideStart();
|
||||
void hideFinish();
|
||||
|
||||
@@ -304,6 +371,11 @@ public slots:
|
||||
|
||||
void onTabChange();
|
||||
void onScroll();
|
||||
void onSwitch();
|
||||
|
||||
void onRemoveSet(uint64 setId);
|
||||
void onRemoveSetSure();
|
||||
void onDelayedHide();
|
||||
|
||||
signals:
|
||||
|
||||
@@ -313,6 +385,8 @@ signals:
|
||||
|
||||
private:
|
||||
|
||||
void prepareTab(int32 &left, int32 top, int32 _width, FlatRadiobutton &tab);
|
||||
|
||||
void showAll();
|
||||
void hideAll();
|
||||
|
||||
@@ -328,11 +402,20 @@ private:
|
||||
|
||||
BoxShadow _shadow;
|
||||
|
||||
FlatRadiobutton _recent, _people, _nature, _food, _celebration, _activity, _travel, _objects, _stickers;
|
||||
FlatRadiobutton _recent, _people, _nature, _food, _celebration, _activity, _travel, _objects;
|
||||
|
||||
int32 _emojiPack;
|
||||
ScrollArea _scroll;
|
||||
EmojiPanInner _inner;
|
||||
bool _stickersShown;
|
||||
QPixmap _fromCache, _toCache;
|
||||
anim::ivalue a_fromCoord, a_toCoord;
|
||||
anim::fvalue a_fromAlpha, a_toAlpha;
|
||||
uint64 _moveStart;
|
||||
|
||||
ScrollArea e_scroll;
|
||||
EmojiPanInner e_inner;
|
||||
ScrollArea s_scroll;
|
||||
StickerPanInner s_inner;
|
||||
|
||||
uint64 _removingSetId;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ void FileUploader::uploadMedia(MsgId msgId, const ReadyLocalMedia &media) {
|
||||
}
|
||||
document->status = FileUploading;
|
||||
if (!media.file.isEmpty()) {
|
||||
document->location = FileLocation(mtpc_storage_filePartial, media.file);
|
||||
document->location = FileLocation(StorageFilePartial, media.file);
|
||||
}
|
||||
}
|
||||
queue.insert(msgId, File(media));
|
||||
|
||||
@@ -26,6 +26,31 @@ EmojiPtr emojiGet(EmojiPtr emoji, uint32 color);
|
||||
EmojiPtr emojiGet(const QChar *from, const QChar *end);
|
||||
QString emojiGetSequence(int index);
|
||||
|
||||
inline QString emojiString(EmojiPtr emoji) {
|
||||
if ((emoji->code & 0xFFFF0000U) == 0xFFFF0000U) { // sequence
|
||||
return emojiGetSequence(emoji->code & 0xFFFFU);
|
||||
}
|
||||
|
||||
QString result;
|
||||
result.reserve(emoji->len + (emoji->postfix ? 1 : 0));
|
||||
if (!(emoji->code >> 16)) {
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
} else {
|
||||
result.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
if (emoji->code2) {
|
||||
result.append(QChar((emoji->code2 >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code2 & 0xFFFF));
|
||||
}
|
||||
}
|
||||
if (emoji->color && ((emoji->color & 0xFFFF0000U) != 0xFFFF0000U)) {
|
||||
result.append(QChar((emoji->color >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->color & 0xFFFF));
|
||||
}
|
||||
if (emoji->postfix) result.append(QChar(emoji->postfix));
|
||||
return result;
|
||||
}
|
||||
|
||||
inline uint64 emojiKey(EmojiPtr emoji) {
|
||||
uint64 key = emoji->code;
|
||||
if (emoji->code2) {
|
||||
@@ -138,7 +163,8 @@ inline QString replaceEmojis(const QString &text) {
|
||||
while (currentLink < lnkCount && ch >= lnkRanges[currentLink].from + lnkRanges[currentLink].len) {
|
||||
++currentLink;
|
||||
}
|
||||
if (emojiCode &&
|
||||
EmojiPtr emoji = emojiCode ? emojiGet(emojiCode) : 0;
|
||||
if (emoji && emoji != TwoSymbolEmoji &&
|
||||
(ch == emojiStart || !ch->isLetterOrNumber() || !(ch - 1)->isLetterOrNumber()) &&
|
||||
(newEmojiEnd == e || !newEmojiEnd->isLetterOrNumber() || newEmojiEnd == emojiStart || !(newEmojiEnd - 1)->isLetterOrNumber()) &&
|
||||
(currentLink >= lnkCount || (ch < lnkRanges[currentLink].from && newEmojiEnd <= lnkRanges[currentLink].from) || (ch >= lnkRanges[currentLink].from + lnkRanges[currentLink].len && newEmojiEnd > lnkRanges[currentLink].from + lnkRanges[currentLink].len))
|
||||
@@ -148,10 +174,18 @@ inline QString replaceEmojis(const QString &text) {
|
||||
if (ch > emojiEnd + (consumePrevious ? 1 : 0)) {
|
||||
result.append(emojiEnd, ch - emojiEnd - (consumePrevious ? 1 : 0));
|
||||
}
|
||||
if (emojiCode > 65535) {
|
||||
result.append(QChar((emojiCode >> 16) & 0xFFFF));
|
||||
if (emoji->color) {
|
||||
EmojiColorVariants::const_iterator it = cEmojiVariants().constFind(emoji->code);
|
||||
if (it != cEmojiVariants().cend()) {
|
||||
EmojiPtr replace = emojiFromKey(it.value());
|
||||
if (replace) {
|
||||
if (replace != TwoSymbolEmoji && replace->code == emoji->code && replace->code2 == emoji->code2) {
|
||||
emoji = replace;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
result.append(QChar(emojiCode & 0xFFFF));
|
||||
result.append(emojiString(emoji));
|
||||
|
||||
ch = emojiEnd = newEmojiEnd;
|
||||
canFindEmoji = true;
|
||||
|
||||
@@ -373,7 +373,7 @@ QString FlatTextarea::getText(int32 start, int32 end) const {
|
||||
QString imageName = static_cast<QTextImageFormat*>(&f)->name();
|
||||
if (imageName.startsWith(QLatin1String("emoji://e."))) {
|
||||
if (EmojiPtr emoji = emojiFromUrl(imageName)) {
|
||||
emojiText = textEmojiString(emoji);
|
||||
emojiText = emojiString(emoji);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
#include "gui/images.h"
|
||||
|
||||
#include "mainwidget.h"
|
||||
#include "localstorage.h"
|
||||
|
||||
namespace {
|
||||
typedef QMap<QString, LocalImage*> LocalImages;
|
||||
@@ -43,7 +44,7 @@ ImagePtr::ImagePtr() : Parent(blank()) {
|
||||
}
|
||||
|
||||
ImagePtr::ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def) :
|
||||
Parent((location.type() == mtpc_fileLocation) ? (Image*)(getImage(width, height, location.c_fileLocation().vdc_id.v, location.c_fileLocation().vvolume_id.v, location.c_fileLocation().vlocal_id.v, location.c_fileLocation().vsecret.v)) : def.v()) {
|
||||
Parent((location.type() == mtpc_fileLocation) ? (Image*)(getImage(StorageImageLocation(width, height, location.c_fileLocation()))) : def.v()) {
|
||||
}
|
||||
|
||||
const QPixmap &Image::pix(int32 w, int32 h) const {
|
||||
@@ -517,11 +518,14 @@ int64 imageCacheSize() {
|
||||
return globalAquiredSize;
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : w(width), h(height), loader(new mtpFileLoader(dc, volume, local, secret, size)) {
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, int32 size) : w(location.width), h(location.height), loader(new mtpFileLoader(location.dc, location.volume, location.local, location.secret, size)) {
|
||||
}
|
||||
|
||||
StorageImage::StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes) : w(width), h(height), loader(0) {
|
||||
StorageImage::StorageImage(const StorageImageLocation &location, QByteArray &bytes) : w(location.width), h(location.height), loader(0) {
|
||||
setData(bytes);
|
||||
if (location.dc) {
|
||||
Local::writeImage(storageKey(location.dc, location.volume, location.local), StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
}
|
||||
}
|
||||
|
||||
const QPixmap &StorageImage::pixData() const {
|
||||
@@ -608,24 +612,27 @@ bool StorageImage::loaded() const {
|
||||
return check();
|
||||
}
|
||||
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) {
|
||||
StorageKey key(storageKey(dc, volume, local));
|
||||
StorageImage *getImage(const StorageImageLocation &location, int32 size) {
|
||||
StorageKey key(storageKey(location.dc, location.volume, location.local));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret, size));
|
||||
i = storageImages.insert(key, new StorageImage(location, size));
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) {
|
||||
StorageKey key(storageKey(dc, volume, local));
|
||||
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes) {
|
||||
StorageKey key(storageKey(location.dc, location.volume, location.local));
|
||||
StorageImages::const_iterator i = storageImages.constFind(key);
|
||||
if (i == storageImages.cend()) {
|
||||
QByteArray bytesArr(bytes);
|
||||
i = storageImages.insert(key, new StorageImage(width, height, dc, volume, local, secret, bytesArr));
|
||||
i = storageImages.insert(key, new StorageImage(location, bytesArr));
|
||||
} else if (!i.value()->loaded()) {
|
||||
QByteArray bytesArr(bytes);
|
||||
i.value()->setData(bytesArr);
|
||||
if (location.dc) {
|
||||
Local::writeImage(storageKey(location.dc, location.volume, location.local), StorageImageSaved(mtpToStorageType(mtpc_storage_filePartial), bytes));
|
||||
}
|
||||
}
|
||||
return i.value();
|
||||
}
|
||||
|
||||
@@ -21,6 +21,20 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
QImage imageBlur(QImage img);
|
||||
|
||||
struct StorageImageLocation {
|
||||
StorageImageLocation() : width(0), height(0), dc(0), volume(0), local(0), secret(0) {
|
||||
}
|
||||
StorageImageLocation(int32 width, int32 height, int32 dc, const uint64 &volume, int32 local, const uint64 &secret) : width(width), height(height), dc(dc), volume(volume), local(local), secret(secret) {
|
||||
}
|
||||
StorageImageLocation(int32 width, int32 height, const MTPDfileLocation &location) : width(width), height(height), dc(location.vdc_id.v), volume(location.vvolume_id.v), local(location.vlocal_id.v), secret(location.vsecret.v) {
|
||||
}
|
||||
int32 width, height;
|
||||
int32 dc;
|
||||
uint64 volume;
|
||||
int32 local;
|
||||
uint64 secret;
|
||||
};
|
||||
|
||||
class Image {
|
||||
public:
|
||||
|
||||
@@ -123,25 +137,66 @@ typedef QPair<uint64, uint64> StorageKey;
|
||||
inline uint64 storageMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
}
|
||||
inline StorageKey storageKey(int32 dc, const int64 &volume, int32 local) {
|
||||
inline StorageKey storageKey(int32 dc, const uint64 &volume, int32 local) {
|
||||
return StorageKey(storageMix32To64(dc, local), volume);
|
||||
}
|
||||
inline StorageKey storageKey(const MTPDfileLocation &location) {
|
||||
return storageKey(location.vdc_id.v, location.vvolume_id.v, location.vlocal_id.v);
|
||||
}
|
||||
enum StorageFileType {
|
||||
StorageFileUnknown = 0xaa963b05, // mtpc_storage_fileUnknown
|
||||
StorageFileJpeg = 0x7efe0e, // mtpc_storage_fileJpeg
|
||||
StorageFileGif = 0xcae1aadf, // mtpc_storage_fileGif
|
||||
StorageFilePng = 0xa4f63c0, // mtpc_storage_filePng
|
||||
StorageFilePdf = 0xae1e508d, // mtpc_storage_filePdf
|
||||
StorageFileMp3 = 0x528a0677, // mtpc_storage_fileMp3
|
||||
StorageFileMov = 0x4b09ebbc, // mtpc_storage_fileMov
|
||||
StorageFilePartial = 0x40bc6f52, // mtpc_storage_filePartial
|
||||
StorageFileMp4 = 0xb3cea0e4, // mtpc_storage_fileMp4
|
||||
StorageFileWebp = 0x1081464c, // mtpc_storage_fileWebp
|
||||
};
|
||||
inline StorageFileType mtpToStorageType(mtpTypeId type) {
|
||||
switch (type) {
|
||||
case mtpc_storage_fileJpeg: return StorageFileJpeg;
|
||||
case mtpc_storage_fileGif: return StorageFileGif;
|
||||
case mtpc_storage_filePng: return StorageFilePng;
|
||||
case mtpc_storage_filePdf: return StorageFilePdf;
|
||||
case mtpc_storage_fileMp3: return StorageFileMp3;
|
||||
case mtpc_storage_fileMov: return StorageFileMov;
|
||||
case mtpc_storage_filePartial: return StorageFilePartial;
|
||||
case mtpc_storage_fileMp4: return StorageFileMp4;
|
||||
case mtpc_storage_fileWebp: return StorageFileWebp;
|
||||
case mtpc_storage_fileUnknown:
|
||||
default: return StorageFileUnknown;
|
||||
}
|
||||
}
|
||||
inline mtpTypeId mtpFromStorageType(StorageFileType type) {
|
||||
switch (type) {
|
||||
case StorageFileGif: return mtpc_storage_fileGif;
|
||||
case StorageFilePng: return mtpc_storage_filePng;
|
||||
case StorageFilePdf: return mtpc_storage_filePdf;
|
||||
case StorageFileMp3: return mtpc_storage_fileMp3;
|
||||
case StorageFileMov: return mtpc_storage_fileMov;
|
||||
case StorageFilePartial: return mtpc_storage_filePartial;
|
||||
case StorageFileMp4: return mtpc_storage_fileMp4;
|
||||
case StorageFileWebp: return mtpc_storage_fileWebp;
|
||||
case StorageFileUnknown:
|
||||
default: return mtpc_storage_fileUnknown;
|
||||
}
|
||||
}
|
||||
struct StorageImageSaved {
|
||||
StorageImageSaved() : type(mtpc_storage_fileUnknown) {
|
||||
StorageImageSaved() : type(StorageFileUnknown) {
|
||||
}
|
||||
StorageImageSaved(mtpTypeId type, const QByteArray &data) : type(type), data(data) {
|
||||
StorageImageSaved(StorageFileType type, const QByteArray &data) : type(type), data(data) {
|
||||
}
|
||||
mtpTypeId type;
|
||||
StorageFileType type;
|
||||
QByteArray data;
|
||||
};
|
||||
class StorageImage : public Image {
|
||||
public:
|
||||
|
||||
StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0);
|
||||
StorageImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, QByteArray &bytes);
|
||||
StorageImage(const StorageImageLocation &location, int32 size = 0);
|
||||
StorageImage(const StorageImageLocation &location, QByteArray &bytes);
|
||||
|
||||
int32 width() const;
|
||||
int32 height() const;
|
||||
@@ -188,8 +243,8 @@ private:
|
||||
mutable mtpFileLoader *loader;
|
||||
};
|
||||
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0);
|
||||
StorageImage *getImage(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes);
|
||||
StorageImage *getImage(const StorageImageLocation &location, int32 size = 0);
|
||||
StorageImage *getImage(const StorageImageLocation &location, const QByteArray &bytes);
|
||||
Image *getImage(int32 width, int32 height, const MTPFileLocation &location);
|
||||
|
||||
class ImagePtr : public ManagedPtr<Image> {
|
||||
@@ -201,9 +256,9 @@ public:
|
||||
}
|
||||
ImagePtr(const QPixmap &pixmap, QByteArray format) : Parent(getImage(pixmap, format)) {
|
||||
}
|
||||
ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0) : Parent(getImage(width, height, dc, volume, local, secret, size)) {
|
||||
ImagePtr(const StorageImageLocation &location, int32 size = 0) : Parent(getImage(location, size)) {
|
||||
}
|
||||
ImagePtr(int32 width, int32 height, int32 dc, const int64 &volume, int32 local, const int64 &secret, const QByteArray &bytes) : Parent(getImage(width, height, dc, volume, local, secret, bytes)) {
|
||||
ImagePtr(const StorageImageLocation &location, const QByteArray &bytes) : Parent(getImage(location, bytes)) {
|
||||
}
|
||||
ImagePtr(int32 width, int32 height, const MTPFileLocation &location, ImagePtr def = ImagePtr());
|
||||
};
|
||||
@@ -213,16 +268,16 @@ void clearAllImages();
|
||||
int64 imageCacheSize();
|
||||
|
||||
struct FileLocation {
|
||||
FileLocation(mtpTypeId type, const QString &name, const QDateTime &modified, qint32 size) : type(type), name(name), modified(modified), size(size) {
|
||||
FileLocation(StorageFileType type, const QString &name, const QDateTime &modified, qint32 size) : type(type), name(name), modified(modified), size(size) {
|
||||
}
|
||||
FileLocation(mtpTypeId type, const QString &name) : type(type), name(name) {
|
||||
FileLocation(StorageFileType type, const QString &name) : type(type), name(name) {
|
||||
QFileInfo f(name);
|
||||
if (f.exists()) {
|
||||
qint64 s = f.size();
|
||||
if (s > INT_MAX) {
|
||||
this->name = QString();
|
||||
size = 0;
|
||||
type = mtpc_storage_fileUnknown;
|
||||
type = StorageFileUnknown;
|
||||
} else {
|
||||
modified = f.lastModified();
|
||||
size = qint32(s);
|
||||
@@ -230,7 +285,7 @@ struct FileLocation {
|
||||
} else {
|
||||
this->name = QString();
|
||||
size = 0;
|
||||
type = mtpc_storage_fileUnknown;
|
||||
type = StorageFileUnknown;
|
||||
}
|
||||
}
|
||||
FileLocation() : size(0) {
|
||||
@@ -245,7 +300,7 @@ struct FileLocation {
|
||||
|
||||
return (f.lastModified() == modified) && (qint32(s) == size);
|
||||
}
|
||||
mtpTypeId type;
|
||||
StorageFileType type;
|
||||
QString name;
|
||||
QDateTime modified;
|
||||
qint32 size;
|
||||
@@ -257,11 +312,34 @@ inline bool operator!=(const FileLocation &a, const FileLocation &b) {
|
||||
return !(a == b);
|
||||
}
|
||||
|
||||
enum LocationType {
|
||||
UnknownFileLocation = 0,
|
||||
DocumentFileLocation = 0x4e45abe9, // mtpc_inputDocumentFileLocation
|
||||
AudioFileLocation = 0x74dc404d, // mtpc_inputAudioFileLocation
|
||||
VideoFileLocation = 0x3d0364ec, // mtpc_inputVideoFileLocation
|
||||
};
|
||||
inline LocationType mtpToLocationType(mtpTypeId type) {
|
||||
switch (type) {
|
||||
case mtpc_inputDocumentFileLocation: return DocumentFileLocation;
|
||||
case mtpc_inputAudioFileLocation: return AudioFileLocation;
|
||||
case mtpc_inputVideoFileLocation: return VideoFileLocation;
|
||||
default: return UnknownFileLocation;
|
||||
}
|
||||
}
|
||||
inline mtpTypeId mtpFromLocationType(LocationType type) {
|
||||
switch (type) {
|
||||
case DocumentFileLocation: return mtpc_inputDocumentFileLocation;
|
||||
case AudioFileLocation: return mtpc_inputAudioFileLocation;
|
||||
case VideoFileLocation: return mtpc_inputVideoFileLocation;
|
||||
case UnknownFileLocation:
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
typedef QPair<uint64, uint64> MediaKey;
|
||||
inline uint64 mediaMix32To64(mtpTypeId a, int32 b) {
|
||||
inline uint64 mediaMix32To64(int32 a, int32 b) {
|
||||
return (uint64(*reinterpret_cast<uint32*>(&a)) << 32) | uint64(*reinterpret_cast<uint32*>(&b));
|
||||
}
|
||||
inline MediaKey mediaKey(mtpTypeId type, int32 dc, const int64 &id) {
|
||||
inline MediaKey mediaKey(LocationType type, int32 dc, const uint64 &id) {
|
||||
return MediaKey(mediaMix32To64(type, dc), id);
|
||||
}
|
||||
inline StorageKey mediaKey(const MTPDfileLocation &location) {
|
||||
|
||||
@@ -54,7 +54,7 @@ ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::flatScroll *st)
|
||||
}
|
||||
|
||||
void ScrollBar::recountSize() {
|
||||
setGeometry(_vertical ? QRect(rtl() ? 0 : (_area->width() - _st->width), 0, _st->width, _area->height()) : QRect(0, _area->height() - _st->width, _area->width(), _st->width));
|
||||
setGeometry(_vertical ? QRect(rtl() ? 0 : (_area->width() - _st->width), _st->deltat, _st->width, _area->height() - _st->deltat - _st->deltab) : QRect(_st->deltat, _area->height() - _st->width, _area->width() - _st->deltat - _st->deltab, _st->width));
|
||||
}
|
||||
|
||||
void ScrollBar::updateBar(bool force) {
|
||||
@@ -65,7 +65,7 @@ void ScrollBar::updateBar(bool force) {
|
||||
_area->rangeChanged(oldMax, newMax, _vertical);
|
||||
}
|
||||
if (_vertical) {
|
||||
int sh = _area->scrollHeight(), rh = height() - 2 * _st->deltay, h = sh ? int32((rh * int64(_area->height())) / sh) : 0;
|
||||
int sh = _area->scrollHeight(), rh = height(), h = sh ? int32((rh * int64(_area->height())) / sh) : 0;
|
||||
if (h >= rh || !_area->scrollTopMax() || rh < _st->minHeight) {
|
||||
if (!isHidden()) hide();
|
||||
bool newTopSh = (_st->topsh < 0), newBottomSh = (_st->bottomsh < 0);
|
||||
@@ -78,9 +78,9 @@ void ScrollBar::updateBar(bool force) {
|
||||
int stm = _area->scrollTopMax(), y = stm ? int32(((rh - h) * int64(_area->scrollTop())) / stm) : 0;
|
||||
if (y > rh - h) y = rh - h;
|
||||
|
||||
newBar = QRect(_st->deltax, y + _st->deltay, width() - 2 * _st->deltax, h);
|
||||
newBar = QRect(_st->deltax, y, width() - 2 * _st->deltax, h);
|
||||
} else {
|
||||
int sw = _area->scrollWidth(), rw = width() - 2 * _st->deltay, w = sw ? int32((rw * int64(_area->width())) / sw) : 0;
|
||||
int sw = _area->scrollWidth(), rw = width(), w = sw ? int32((rw * int64(_area->width())) / sw) : 0;
|
||||
if (w >= rw || !_area->scrollLeftMax() || rw < _st->minHeight) {
|
||||
if (!isHidden()) hide();
|
||||
return;
|
||||
@@ -90,11 +90,11 @@ void ScrollBar::updateBar(bool force) {
|
||||
int slm = _area->scrollLeftMax(), x = slm ? int32(((rw - w) * int64(_area->scrollLeft())) / slm) : 0;
|
||||
if (x > rw - w) x = rw - w;
|
||||
|
||||
newBar = QRect(x + _st->deltay, _st->deltax, w, height() - 2 * _st->deltax);
|
||||
newBar = QRect(x, _st->deltax, w, height() - 2 * _st->deltax);
|
||||
}
|
||||
if (newBar != _bar) {
|
||||
_bar = newBar;
|
||||
parentWidget()->update(geometry());
|
||||
update();// parentWidget()->update(geometry());
|
||||
}
|
||||
if (_vertical) {
|
||||
bool newTopSh = (_st->topsh < 0) || (_area->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (_area->scrollTop() < _area->scrollTopMax() - _st->bottomsh);
|
||||
@@ -119,15 +119,16 @@ void ScrollBar::paintEvent(QPaintEvent *e) {
|
||||
if (!a_bg.current().alpha() && !a_bar.current().alpha()) return;
|
||||
QPainter p(this);
|
||||
|
||||
int32 deltax = _vertical ? _st->deltax : _st->deltay, deltay = _vertical ? _st->deltay : _st->deltax;
|
||||
int32 deltal = _vertical ? _st->deltax : 0, deltar = _vertical ? _st->deltax : 0;
|
||||
int32 deltat = _vertical ? 0 : _st->deltax, deltab = _vertical ? 0 : _st->deltax;
|
||||
p.setPen(Qt::NoPen);
|
||||
if (_st->round) {
|
||||
p.setBrush(a_bg.current());
|
||||
p.drawRoundedRect(QRect(deltax, deltay, width() - 2 * deltax, height() - 2 * deltay), _st->round, _st->round);
|
||||
p.drawRoundedRect(QRect(deltal, deltat, width() - deltal - deltar, height() - deltat - deltab), _st->round, _st->round);
|
||||
p.setBrush(a_bar.current());
|
||||
p.drawRoundedRect(_bar, _st->round, _st->round);
|
||||
} else {
|
||||
p.fillRect(QRect(deltax, deltay, width() - 2 * deltax, height() - 2 * deltay), a_bg.current());
|
||||
p.fillRect(QRect(deltal, deltat, width() - deltal - deltar, height() - deltat - deltab), a_bg.current());
|
||||
p.fillRect(_bar, a_bar.current());
|
||||
}
|
||||
}
|
||||
@@ -143,7 +144,7 @@ bool ScrollBar::animStep(float64 ms) {
|
||||
a_bg.update(dt, anim::linear);
|
||||
a_bar.update(dt, anim::linear);
|
||||
}
|
||||
parentWidget()->update(geometry());
|
||||
update();// parentWidget()->update(geometry());
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -176,6 +177,8 @@ void ScrollBar::leaveEvent(QEvent *e) {
|
||||
anim::start(this);
|
||||
if (_hideIn >= 0) {
|
||||
_hideTimer.start(_hideIn);
|
||||
} else if (_st->hiding) {
|
||||
hideTimeout(_st->hiding);
|
||||
}
|
||||
}
|
||||
_over = _overbar = false;
|
||||
@@ -193,7 +196,7 @@ void ScrollBar::mouseMoveEvent(QMouseEvent *e) {
|
||||
}
|
||||
if (_moving) {
|
||||
int delta = 0, barDelta = _vertical ? (_area->height() - _bar.height()) : (_area->width() - _bar.width());
|
||||
if (barDelta) {
|
||||
if (barDelta > 0) {
|
||||
QPoint d = (e->globalPos() - _dragStart);
|
||||
delta = int32((_vertical ? (d.y() * int64(_area->scrollTopMax())) : (d.x() * int64(_area->scrollLeftMax()))) / barDelta);
|
||||
}
|
||||
@@ -209,7 +212,10 @@ void ScrollBar::mousePressEvent(QMouseEvent *e) {
|
||||
if (_overbar) {
|
||||
_startFrom = _connected->value();
|
||||
} else {
|
||||
_startFrom = _vertical ? int32((e->pos().y() * int64(_area->scrollTopMax())) / height()) : ((e->pos().x() * int64(_area->scrollLeftMax())) / width());
|
||||
int32 val = _vertical ? e->pos().y() : e->pos().x(), div = _vertical ? height() : width();
|
||||
val = (val <= _st->deltat) ? 0 : (val - _st->deltat);
|
||||
div = (div <= _st->deltat + _st->deltab) ? 1 : (div - _st->deltat - _st->deltab);
|
||||
_startFrom = _vertical ? int32((val * int64(_area->scrollTopMax())) / div) : ((val * int64(_area->scrollLeftMax())) / div);
|
||||
_connected->setValue(_startFrom);
|
||||
if (!_overbar) {
|
||||
_overbar = true;
|
||||
|
||||
@@ -239,31 +239,6 @@ const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink)
|
||||
return (result < end && *result == TextCommand) ? (result + 1) : from;
|
||||
}
|
||||
|
||||
QString textEmojiString(EmojiPtr emoji) {
|
||||
if ((emoji->code & 0xFFFF0000U) == 0xFFFF0000U) { // sequence
|
||||
return emojiGetSequence(emoji->code & 0xFFFFU);
|
||||
}
|
||||
|
||||
QString result;
|
||||
result.reserve(emoji->len + (emoji->postfix ? 1 : 0));
|
||||
if (!(emoji->code >> 16)) {
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
} else {
|
||||
result.append(QChar((emoji->code >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code & 0xFFFF));
|
||||
if (emoji->code2) {
|
||||
result.append(QChar((emoji->code2 >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->code2 & 0xFFFF));
|
||||
}
|
||||
}
|
||||
if (emoji->color && ((emoji->color & 0xFFFF0000U) != 0xFFFF0000U)) {
|
||||
result.append(QChar((emoji->color >> 16) & 0xFFFF));
|
||||
result.append(QChar(emoji->color & 0xFFFF));
|
||||
}
|
||||
if (emoji->postfix) result.append(QChar(emoji->postfix));
|
||||
return result;
|
||||
}
|
||||
|
||||
class TextParser {
|
||||
public:
|
||||
|
||||
@@ -527,6 +502,10 @@ public:
|
||||
for (int l = len - skipped - 1; l > 0; --l) {
|
||||
_t->_text.push_back(*++ptr);
|
||||
}
|
||||
if (e->postfix && _t->_text.at(_t->_text.size() - 1).unicode() != e->postfix) {
|
||||
_t->_text.push_back(e->postfix);
|
||||
++len;
|
||||
}
|
||||
|
||||
createBlock(-len);
|
||||
emoji = e;
|
||||
@@ -757,10 +736,13 @@ void TextLink::onClick(Qt::MouseButton button) const {
|
||||
QString url = TextLink::encoded();
|
||||
QRegularExpressionMatch telegramMeUser = QRegularExpression(qsl("^https?://telegram\\.me/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption).match(url);
|
||||
QRegularExpressionMatch telegramMeGroup = QRegularExpression(qsl("^https?://telegram\\.me/joinchat/([a-zA-Z0-9\\.\\_\\-]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption).match(url);
|
||||
QRegularExpressionMatch telegramMeStickers = QRegularExpression(qsl("^https?://telegram\\.me/addstickers/([a-zA-Z0-9\\.\\_]+)(\\?|$)"), QRegularExpression::CaseInsensitiveOption).match(url);
|
||||
if (telegramMeUser.hasMatch()) {
|
||||
App::openUserByName(telegramMeUser.captured(1));
|
||||
} else if (telegramMeGroup.hasMatch()) {
|
||||
App::joinGroupByHash(telegramMeGroup.captured(1));
|
||||
} else if (telegramMeStickers.hasMatch()) {
|
||||
App::stickersBox(telegramMeStickers.captured(1));
|
||||
} else if (QRegularExpression(qsl("^tg://[a-zA-Z0-9]+"), QRegularExpression::CaseInsensitiveOption).match(url).hasMatch()) {
|
||||
App::openLocalUrl(url);
|
||||
} else {
|
||||
|
||||
@@ -534,8 +534,6 @@ QString textcmdStartColor(const style::color &color);
|
||||
QString textcmdStopColor();
|
||||
const QChar *textSkipCommand(const QChar *from, const QChar *end, bool canLink = true);
|
||||
|
||||
QString textEmojiString(EmojiPtr emoji);
|
||||
|
||||
inline bool chIsSpace(QChar ch, bool rich = false) {
|
||||
return ch.isSpace() || (ch < 32 && !(rich && ch == TextCommand)) || (ch == QChar::ParagraphSeparator) || (ch == QChar::LineSeparator) || (ch == QChar::ObjectReplacementCharacter) || (ch == QChar::SoftHyphen) || (ch == QChar::CarriageReturn) || (ch == QChar::Tabulation);
|
||||
}
|
||||
@@ -546,10 +544,11 @@ inline bool chIsTrimmed(QChar ch, bool rich = false) {
|
||||
return (!rich || ch != TextCommand) && (chIsSpace(ch) || chIsBad(ch));
|
||||
}
|
||||
inline bool chIsDiac(QChar ch) { // diac and variation selectors
|
||||
return (ch >= 768 && ch < 880) || (ch >= 7616 && ch < 7680) || (ch >= 8400 && ch < 8448) || (ch >= 65056 && ch < 65072);
|
||||
QChar::Category c = ch.category();
|
||||
return (c == QChar::Mark_NonSpacing);
|
||||
}
|
||||
inline int32 chMaxDiacAfterSymbol() {
|
||||
return 4;
|
||||
return 2;
|
||||
}
|
||||
inline bool chIsNewline(QChar ch) {
|
||||
return (ch == QChar::LineFeed || ch == 156);
|
||||
|
||||
@@ -2894,13 +2894,13 @@ HistorySticker::HistorySticker(DocumentData *document) : HistoryMedia()
|
||||
}
|
||||
|
||||
bool HistorySticker::updateStickerEmoji() {
|
||||
if (!data->alt.isEmpty()) {
|
||||
_emoji = data->alt;
|
||||
if (!data->sticker->alt.isEmpty()) {
|
||||
_emoji = data->sticker->alt;
|
||||
return true;
|
||||
}
|
||||
const EmojiStickersMap &stickers(cEmojiStickers());
|
||||
EmojiStickersMap::const_iterator i = stickers.constFind(data);
|
||||
QString emoji = (i == stickers.cend()) ? QString() : textEmojiString(i.value());
|
||||
QString emoji = (i == stickers.cend()) ? QString() : emojiString(i.value());
|
||||
if (emoji != _emoji) {
|
||||
_emoji = emoji;
|
||||
return true;
|
||||
@@ -2948,24 +2948,24 @@ void HistorySticker::draw(QPainter &p, const HistoryItem *parent, bool selected,
|
||||
if (!data->loader && data->status != FileFailed && !already && !hasdata) {
|
||||
data->save(QString());
|
||||
}
|
||||
if (data->sticker->isNull() && (already || hasdata)) {
|
||||
if (data->sticker->img->isNull() && (already || hasdata)) {
|
||||
if (already) {
|
||||
data->sticker = ImagePtr(data->already());
|
||||
data->sticker->img = ImagePtr(data->already());
|
||||
} else {
|
||||
data->sticker = ImagePtr(data->data);
|
||||
data->sticker->img = ImagePtr(data->data);
|
||||
}
|
||||
}
|
||||
if (selected) {
|
||||
if (data->sticker->isNull()) {
|
||||
if (data->sticker->img->isNull()) {
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->thumb->pixBlurredColored(st::msgStickerOverlay, pixw, pixh));
|
||||
} else {
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->sticker->pixColored(st::msgStickerOverlay, pixw, pixh));
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->sticker->img->pixColored(st::msgStickerOverlay, pixw, pixh));
|
||||
}
|
||||
} else {
|
||||
if (data->sticker->isNull()) {
|
||||
if (data->sticker->img->isNull()) {
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->thumb->pixBlurred(pixw, pixh));
|
||||
} else {
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->sticker->pix(pixw, pixh));
|
||||
p.drawPixmap(QPoint(usex + (usew - pixw) / 2, (_minh - pixh) / 2), data->sticker->img->pix(pixw, pixh));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4606,7 +4606,7 @@ void HistoryMessage::initMediaFromText(QString ¤tText) {
|
||||
}
|
||||
|
||||
void HistoryMessage::initMediaFromDocument(DocumentData *doc) {
|
||||
if (doc->type == StickerDocument && doc->dimensions.width() > 0 && doc->dimensions.height() > 0 && doc->dimensions.width() <= StickerMaxSize && doc->dimensions.height() <= StickerMaxSize && doc->size < StickerInMemory) {
|
||||
if (doc->type == StickerDocument && doc->sticker && 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);
|
||||
@@ -4879,7 +4879,7 @@ void HistoryMessage::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y)
|
||||
lnk = _from->lnk;
|
||||
return;
|
||||
}
|
||||
// width -= st::msgPhotoSkip;
|
||||
// width -= st::msgPhotoSkip;
|
||||
left += st::msgPhotoSkip;
|
||||
}
|
||||
if (width < 1) return;
|
||||
@@ -4900,6 +4900,10 @@ void HistoryMessage::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y)
|
||||
}
|
||||
r.setTop(r.top() + st::msgNameFont->height);
|
||||
}
|
||||
return getStateFromMessageText(lnk, inText, x, y, r);
|
||||
}
|
||||
|
||||
void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const {
|
||||
QRect trect(r.marginsAdded(-st::msgPadding));
|
||||
TextLinkPtr medialnk;
|
||||
if (_media) {
|
||||
@@ -5056,12 +5060,10 @@ void HistoryForwarded::drawForwardedFrom(QPainter &p, int32 x, int32 y, int32 w,
|
||||
}
|
||||
|
||||
void HistoryForwarded::drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const {
|
||||
int32 h = st::msgServiceNameFont->height;
|
||||
|
||||
drawForwardedFrom(p, trect.x(), trect.y(), trect.width(), (selection == FullItemSel));
|
||||
|
||||
QRect realtrect(trect);
|
||||
realtrect.setY(trect.y() + h);
|
||||
realtrect.setY(trect.y() + st::msgServiceNameFont->height);
|
||||
HistoryMessage::drawMessageText(p, realtrect, selection);
|
||||
}
|
||||
|
||||
@@ -5139,6 +5141,12 @@ void HistoryForwarded::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y
|
||||
return HistoryMessage::getState(lnk, inText, x, y);
|
||||
}
|
||||
|
||||
void HistoryForwarded::getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const {
|
||||
QRect realr(r);
|
||||
realr.setHeight(r.height() - st::msgServiceNameFont->height);
|
||||
HistoryMessage::getStateFromMessageText(lnk, inText, x, y, realr);
|
||||
}
|
||||
|
||||
void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, bool &inText, int32 x, int32 w) const {
|
||||
inText = false;
|
||||
if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
|
||||
@@ -5445,6 +5453,14 @@ void HistoryReply::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) co
|
||||
return HistoryMessage::getState(lnk, inText, x, y);
|
||||
}
|
||||
|
||||
void HistoryReply::getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const {
|
||||
int32 h = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
|
||||
|
||||
QRect realr(r);
|
||||
realr.setHeight(r.height() - h);
|
||||
HistoryMessage::getStateFromMessageText(lnk, inText, x, y, realr);
|
||||
}
|
||||
|
||||
void HistoryReply::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const {
|
||||
symbol = 0;
|
||||
after = false;
|
||||
|
||||
@@ -1238,7 +1238,10 @@ public:
|
||||
|
||||
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
|
||||
bool hasPoint(int32 x, int32 y) const;
|
||||
|
||||
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
|
||||
virtual void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
|
||||
|
||||
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
|
||||
uint32 adjustSelection(uint16 from, uint16 to, TextSelectType type) const {
|
||||
return _text.adjustSelection(from, to, type);
|
||||
@@ -1311,6 +1314,7 @@ public:
|
||||
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
|
||||
bool hasPoint(int32 x, int32 y) const;
|
||||
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
|
||||
void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
|
||||
void getForwardedState(TextLinkPtr &lnk, bool &inText, int32 x, int32 w) const;
|
||||
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
|
||||
|
||||
@@ -1363,6 +1367,7 @@ public:
|
||||
int32 resize(int32 width, bool dontRecountText = false, const HistoryItem *parent = 0);
|
||||
bool hasPoint(int32 x, int32 y) const;
|
||||
void getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y) const;
|
||||
void getStateFromMessageText(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, const QRect &r) const;
|
||||
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
|
||||
|
||||
UserData *replyTo() const {
|
||||
|
||||
@@ -701,6 +701,13 @@ void HistoryList::showContextMenu(QContextMenuEvent *e, bool showFromTouch) {
|
||||
_menu->addAction(lang(lng_context_reply_msg), historyWidget, SLOT(onReplyToMessage()));
|
||||
}
|
||||
if (item && !isUponSelected && !_contextMenuLnk) {
|
||||
if (HistorySticker *sticker = dynamic_cast<HistorySticker*>(msg->getMedia())) {
|
||||
DocumentData *doc = sticker->document();
|
||||
if (doc && doc->sticker && doc->sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
_menu->addAction(lang(lng_context_pack_info), historyWidget, SLOT(onStickerPackInfo()));
|
||||
}
|
||||
}
|
||||
QString contextMenuText = item->selectedText(FullItemSel);
|
||||
if (!contextMenuText.isEmpty() && (!msg || !msg->getMedia() || msg->getMedia()->type() != MediaTypeSticker)) {
|
||||
if (!_menu) _menu = new ContextMenu(this);
|
||||
@@ -771,7 +778,9 @@ void HistoryList::onMenuDestroy(QObject *obj) {
|
||||
}
|
||||
|
||||
void HistoryList::copySelectedText() {
|
||||
QApplication::clipboard()->setText(getSelectedText());
|
||||
QString sel = getSelectedText();
|
||||
DEBUG_LOG(("Setting selected text to clipboard: %1").arg(sel));
|
||||
QApplication::clipboard()->setText(sel);
|
||||
}
|
||||
|
||||
void HistoryList::openContextUrl() {
|
||||
@@ -784,6 +793,7 @@ void HistoryList::openContextUrl() {
|
||||
void HistoryList::copyContextUrl() {
|
||||
QString enc = _contextMenuLnk->encoded();
|
||||
if (!enc.isEmpty()) {
|
||||
DEBUG_LOG(("Setting text to clipboard from context url: %1").arg(enc));
|
||||
QApplication::clipboard()->setText(enc);
|
||||
}
|
||||
}
|
||||
@@ -857,6 +867,7 @@ void HistoryList::copyContextText() {
|
||||
|
||||
QString contextMenuText = item->selectedText(FullItemSel);
|
||||
if (!contextMenuText.isEmpty()) {
|
||||
DEBUG_LOG(("Setting text to clipboard from context menu: %1").arg(contextMenuText));
|
||||
QApplication::clipboard()->setText(contextMenuText);
|
||||
}
|
||||
}
|
||||
@@ -1569,7 +1580,6 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
, _previewCancelled(false)
|
||||
, _replyForwardPressed(false)
|
||||
, _replyReturn(0)
|
||||
, _lastStickersUpdate(0)
|
||||
, _stickersUpdateRequest(0)
|
||||
, _loadingMessages(false)
|
||||
, histRequestsCount(0)
|
||||
@@ -1687,6 +1697,7 @@ HistoryWidget::HistoryWidget(QWidget *parent) : QWidget(parent)
|
||||
}
|
||||
|
||||
void HistoryWidget::start() {
|
||||
connect(App::main(), SIGNAL(stickersUpdated()), &_emojiPan, SLOT(refreshStickers()));
|
||||
updateRecentStickers();
|
||||
connect(App::api(), SIGNAL(fullPeerLoaded(PeerData*)), this, SLOT(onPeerLoaded(PeerData*)));
|
||||
}
|
||||
@@ -1766,6 +1777,10 @@ void HistoryWidget::updateRecentStickers() {
|
||||
_emojiPan.refreshStickers();
|
||||
}
|
||||
|
||||
void HistoryWidget::stickersInstalled(uint64 setId) {
|
||||
_emojiPan.stickersInstalled(setId);
|
||||
}
|
||||
|
||||
void HistoryWidget::typingDone(const MTPBool &result, mtpRequestId req) {
|
||||
if (_typingRequest == req) {
|
||||
_typingRequest = 0;
|
||||
@@ -1795,116 +1810,210 @@ void HistoryWidget::activate() {
|
||||
}
|
||||
|
||||
void HistoryWidget::updateStickers() {
|
||||
if (_lastStickersUpdate && getms(true) < _lastStickersUpdate + StickersUpdateTimeout) return;
|
||||
if (cLastStickersUpdate() && getms(true) < cLastStickersUpdate() + StickersUpdateTimeout) return;
|
||||
if (_stickersUpdateRequest) return;
|
||||
|
||||
_stickersUpdateRequest = MTP::send(MTPmessages_GetAllStickers(MTP_string(cStickersHash())), rpcDone(&HistoryWidget::stickersGot), rpcFail(&HistoryWidget::stickersFailed));
|
||||
}
|
||||
|
||||
void HistoryWidget::stickersGot(const MTPmessages_AllStickers &stickers) {
|
||||
_lastStickersUpdate = getms(true);
|
||||
cSetLastStickersUpdate(getms(true));
|
||||
_stickersUpdateRequest = 0;
|
||||
|
||||
if (stickers.type() == mtpc_messages_allStickers) {
|
||||
const MTPDmessages_allStickers &d(stickers.c_messages_allStickers());
|
||||
if (stickers.type() != mtpc_messages_allStickers) return;
|
||||
const MTPDmessages_allStickers &d(stickers.c_messages_allStickers());
|
||||
|
||||
EmojiStickersMap map;
|
||||
|
||||
AllStickers all;
|
||||
EmojiStickersMap map;
|
||||
const QVector<MTPDocument> &d_docs(d.vdocuments.c_vector().v);
|
||||
const QVector<MTPStickerSet> &d_sets(d.vsets.c_vector().v);
|
||||
|
||||
const QVector<MTPDocument> &docs(d.vdocuments.c_vector().v);
|
||||
QByteArray wasHash = cStickersHash();
|
||||
cSetStickersHash(qba(d.vhash));
|
||||
|
||||
QSet<DocumentData*> found;
|
||||
const RecentStickerPack &recent(cRecentStickers());
|
||||
RecentStickerPack add;
|
||||
add.reserve(docs.size());
|
||||
ushort addValue = recent.isEmpty() ? 1 : qAbs(recent.front().second);
|
||||
for (int32 i = 0, l = docs.size(); i < l; ++i) {
|
||||
DocumentData *doc = App::feedDocument(docs.at(i));
|
||||
if (!doc) continue;
|
||||
int32 j = 0, s = recent.size();
|
||||
for (; j < s; ++j) {
|
||||
if (doc == recent.at(j).first) {
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
StickerSets::iterator def = sets.find(DefaultStickerSetId);
|
||||
if (def == sets.cend()) {
|
||||
def = sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, qsl("Great Minds"), QString()));
|
||||
}
|
||||
for (int32 i = 0; i < d_sets.size(); ++i) {
|
||||
if (d_sets.at(i).type() == mtpc_stickerSet) {
|
||||
const MTPDstickerSet &set(d_sets.at(i).c_stickerSet());
|
||||
StickerSets::iterator i = sets.find(set.vid.v);
|
||||
if (i == sets.cend()) {
|
||||
i = sets.insert(set.vid.v, StickerSet(set.vid.v, set.vaccess_hash.v, qs(set.vtitle), qs(set.vshort_name)));
|
||||
} else {
|
||||
i->access = set.vaccess_hash.v;
|
||||
i->title = qs(set.vtitle);
|
||||
i->shortName = qs(set.vshort_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StickerSets::iterator custom = sets.find(CustomStickerSetId);
|
||||
|
||||
bool added = false, removed = false;
|
||||
QSet<DocumentData*> found;
|
||||
QMap<uint64, int32> wasCount;
|
||||
for (int32 i = 0, l = d_docs.size(); i < l; ++i) {
|
||||
DocumentData *doc = App::feedDocument(d_docs.at(i));
|
||||
if (!doc || !doc->sticker) continue;
|
||||
|
||||
switch (doc->sticker->set.type()) {
|
||||
case mtpc_inputStickerSetEmpty: { // default set - great minds
|
||||
if (!wasCount.contains(DefaultStickerSetId)) wasCount.insert(DefaultStickerSetId, def->stickers.size());
|
||||
if (def->stickers.indexOf(doc) < 0) {
|
||||
def->stickers.push_back(doc);
|
||||
added = true;
|
||||
} else {
|
||||
found.insert(doc);
|
||||
}
|
||||
} break;
|
||||
case mtpc_inputStickerSetID: {
|
||||
StickerSets::iterator it = sets.find(doc->sticker->set.c_inputStickerSetID().vid.v);
|
||||
if (it == sets.cend()) {
|
||||
LOG(("Sticker Set not found by ID: %1").arg(doc->sticker->set.c_inputStickerSetID().vid.v));
|
||||
} else {
|
||||
if (!wasCount.contains(it->id)) wasCount.insert(it->id, it->stickers.size());
|
||||
if (it->stickers.indexOf(doc) < 0) {
|
||||
it->stickers.push_back(doc);
|
||||
added = true;
|
||||
} else {
|
||||
found.insert(doc);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
QString name = qs(doc->sticker->set.c_inputStickerSetShortName().vshort_name).toLower().trimmed();
|
||||
StickerSets::iterator it = sets.begin();
|
||||
for (; it != sets.cend(); ++it) {
|
||||
if (it->shortName.toLower().trimmed() == name) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (j < s) continue;
|
||||
add.push_back(qMakePair(doc, addValue));
|
||||
if (it == sets.cend()) {
|
||||
LOG(("Sticker Set not found by name: %1").arg(name));
|
||||
} else {
|
||||
if (!wasCount.contains(it->id)) wasCount.insert(it->id, it->stickers.size());
|
||||
if (it->stickers.indexOf(doc) < 0) {
|
||||
it->stickers.push_back(doc);
|
||||
added = true;
|
||||
} else {
|
||||
found.insert(doc);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
}
|
||||
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 (custom != sets.cend()) {
|
||||
int32 index = custom->stickers.indexOf(doc);
|
||||
if (index >= 0) {
|
||||
custom->stickers.removeAt(index);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
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));
|
||||
}
|
||||
if (custom != sets.cend() && custom->stickers.isEmpty()) {
|
||||
sets.erase(custom);
|
||||
custom = sets.end();
|
||||
}
|
||||
bool writeRecent = false;
|
||||
RecentStickerPack &recent(cGetRecentStickers());
|
||||
for (StickerSets::iterator it = sets.begin(); it != sets.cend();) {
|
||||
if (it->id == CustomStickerSetId || it->id == RecentStickerSetId) {
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
QMap<uint64, int32>::const_iterator was = wasCount.constFind(it->id);
|
||||
if (was == wasCount.cend()) { // no such stickers added
|
||||
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
|
||||
if (it->stickers.indexOf(i->first) >= 0) {
|
||||
i = recent.erase(i);
|
||||
writeRecent = true;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
it = sets.erase(it);
|
||||
removed = true;
|
||||
} else {
|
||||
for (int32 j = 0, l = was.value(); j < l;) {
|
||||
if (found.contains(it->stickers.at(j))) {
|
||||
++j;
|
||||
} else {
|
||||
for (RecentStickerPack::iterator i = recent.begin(); i != recent.cend();) {
|
||||
if (it->stickers.at(j) == i->first) {
|
||||
i = recent.erase(i);
|
||||
writeRecent = true;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
it->stickers.removeAt(j);
|
||||
--l;
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
if (it->stickers.isEmpty()) {
|
||||
it = sets.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (added || removed || cStickersHash() != wasHash) {
|
||||
Local::writeStickers();
|
||||
}
|
||||
if (writeRecent) {
|
||||
Local::writeUserSettings();
|
||||
}
|
||||
|
||||
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
|
||||
for (int32 i = 0, l = packs.size(); i < l; ++i) {
|
||||
if (packs.at(i).type() == mtpc_stickerPack) {
|
||||
const MTPDstickerPack &p(packs.at(i).c_stickerPack());
|
||||
QString emoticon(qs(p.vemoticon));
|
||||
EmojiPtr e = 0;
|
||||
for (const QChar *ch = emoticon.constData(), *end = emoticon.constEnd(); ch != end; ++ch) {
|
||||
int len = 0;
|
||||
e = emojiFromText(ch, end, len);
|
||||
if (e) break;
|
||||
|
||||
if (ch + 1 < end && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
|
||||
}
|
||||
if (e) {
|
||||
const QVector<MTPlong> docs(p.vdocuments.c_vector().v);
|
||||
if (!docs.isEmpty()) {
|
||||
for (int32 j = 0, s = docs.size(); j < s; ++j) {
|
||||
DocumentData *doc = App::document(docs.at(j).v);
|
||||
map.insert(doc, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
add += recent;
|
||||
}
|
||||
cSetRecentStickers(add);
|
||||
Local::writeRecentStickers();
|
||||
}
|
||||
|
||||
const QVector<MTPStickerPack> &packs(d.vpacks.c_vector().v);
|
||||
for (int32 i = 0, l = packs.size(); i < l; ++i) {
|
||||
if (packs.at(i).type() == mtpc_stickerPack) {
|
||||
const MTPDstickerPack &p(packs.at(i).c_stickerPack());
|
||||
QString emoticon(qs(p.vemoticon));
|
||||
EmojiPtr e = 0;
|
||||
for (const QChar *ch = emoticon.constData(), *end = emoticon.constEnd(); ch != end; ++ch) {
|
||||
int len = 0;
|
||||
e = emojiFromText(ch, end, len);
|
||||
if (e) break;
|
||||
|
||||
if (ch + 1 < end && ch->isHighSurrogate() && (ch + 1)->isLowSurrogate()) ++ch;
|
||||
}
|
||||
if (e) {
|
||||
const QVector<MTPlong> docs(p.vdocuments.c_vector().v);
|
||||
if (!docs.isEmpty()) {
|
||||
StickerPack &pack(all[e]);
|
||||
pack.reserve(pack.size() + docs.size());
|
||||
for (int32 j = 0, s = docs.size(); j < s; ++j) {
|
||||
DocumentData *doc = App::document(docs.at(j).v);
|
||||
pack.push_back(doc);
|
||||
map.insert(doc, e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
LOG(("Sticker Error: Could not find emoji for string: %1").arg(emoticon));
|
||||
}
|
||||
LOG(("Sticker Error: Could not find emoji for string: %1").arg(emoticon));
|
||||
}
|
||||
}
|
||||
|
||||
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.refreshStickers();
|
||||
}
|
||||
|
||||
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();
|
||||
if (App::main()) emit App::main()->stickersUpdated();
|
||||
}
|
||||
|
||||
bool HistoryWidget::stickersFailed(const RPCError &error) {
|
||||
if (error.type().startsWith(qsl("FLOOD_WAIT_"))) return false;
|
||||
|
||||
_lastStickersUpdate = getms(true);
|
||||
cSetLastStickersUpdate(getms(true));
|
||||
_stickersUpdateRequest = 0;
|
||||
return true;
|
||||
}
|
||||
@@ -3256,8 +3365,8 @@ namespace {
|
||||
}
|
||||
if (document->type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (document->type == StickerDocument) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(document->alt)));
|
||||
} else if (document->type == StickerDocument && document->sticker) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(document->sticker->alt), document->sticker->set));
|
||||
}
|
||||
return MTP_vector<MTPDocumentAttribute>(attributes);
|
||||
}
|
||||
@@ -3683,6 +3792,16 @@ void HistoryWidget::onReplyForwardPreviewCancel() {
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::onStickerPackInfo() {
|
||||
if (HistoryMessage *item = dynamic_cast<HistoryMessage*>(App::contextItem())) {
|
||||
if (HistorySticker *sticker = dynamic_cast<HistorySticker*>(item->getMedia())) {
|
||||
if (sticker->document() && sticker->document()->sticker && sticker->document()->sticker->set.type() != mtpc_inputStickerSetEmpty) {
|
||||
App::main()->stickersBox(sticker->document()->sticker->set);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HistoryWidget::previewCancel() {
|
||||
MTP::cancel(_previewRequest);
|
||||
_previewRequest = 0;
|
||||
|
||||
@@ -298,6 +298,7 @@ public:
|
||||
void updateTyping(bool typing = true);
|
||||
// void updateStickerPan();
|
||||
void updateRecentStickers();
|
||||
void stickersInstalled(uint64 setId);
|
||||
void typingDone(const MTPBool &result, mtpRequestId req);
|
||||
|
||||
void destroyData();
|
||||
@@ -379,6 +380,8 @@ public slots:
|
||||
void onReplyToMessage();
|
||||
void onReplyForwardPreviewCancel();
|
||||
|
||||
void onStickerPackInfo();
|
||||
|
||||
void onPreviewParse();
|
||||
void onPreviewCheck();
|
||||
void onPreviewTimeout();
|
||||
@@ -473,7 +476,6 @@ private:
|
||||
void stickersGot(const MTPmessages_AllStickers &stickers);
|
||||
bool stickersFailed(const RPCError &error);
|
||||
|
||||
uint64 _lastStickersUpdate;
|
||||
mtpRequestId _stickersUpdateRequest;
|
||||
|
||||
void writeDraft(MsgId *replyTo = 0, const QString *text = 0, const MessageCursor *cursor = 0, bool *previewCancelled = 0);
|
||||
|
||||
@@ -153,6 +153,7 @@ void IntroCode::activate() {
|
||||
callTimer.start(1000);
|
||||
error = "";
|
||||
errorAlpha = anim::fvalue(0);
|
||||
sentCode = QString();
|
||||
show();
|
||||
code.setDisabled(false);
|
||||
code.setFocus();
|
||||
|
||||
@@ -389,17 +389,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_action_changed_title" = "{from} hat den Gruppennamen zu «{title}» geändert";
|
||||
"lng_action_created_chat" = "{from} hat die Gruppe «{title}» erstellt";
|
||||
|
||||
"lng_group_invite_bad_link" = "Der Einladungslink\nist nicht mehr gültig.";
|
||||
"lng_group_invite_bad_link" = "Der Einladungslink ist \nnicht mehr gültig.";
|
||||
"lng_group_invite_want_join" = "Möchtest du der Gruppe «{title}» beitreten?";
|
||||
"lng_group_invite_join" = "Beitreten";
|
||||
|
||||
"lng_group_invite_link" = "Einladungslink";
|
||||
"lng_group_invite_create" = "Neuer Link";
|
||||
"lng_group_invite_about" = "Jeder, der Telegram installiert hat, kann \nüber diesen Links in deine Gruppe.";
|
||||
"lng_group_invite_create_new" = "Neuer Link";
|
||||
"lng_group_invite_about_new" = "Aktueller Link wird ungültig, wenn \ndu einen neuen erstellst.";
|
||||
"lng_group_invite_copied" = "Einladungslink in die Zwischenablage kopiert.";
|
||||
"lng_group_invite_no_room" = "Leider kannst du dieser Gruppe nicht\nmehr beitreten, da sie bereits voll ist.";
|
||||
"lng_group_invite_about" = "Jeder, der Telegram installiert hat,\nkann anhand dieses Links in deine Gruppe.";
|
||||
"lng_group_invite_create_new" = "Link widerrufen";
|
||||
"lng_group_invite_about_new" = "Dein vorheriger Link wird ungültig,\nwenn du einen neuen erstellst.";
|
||||
"lng_group_invite_copied" = "Der Einladungslink für die Gruppe\nwurde in die Zwischenablage kopiert.";
|
||||
"lng_group_invite_no_room" = "Leider kannst du dieser Gruppe nicht mehr\nbeitreten, da sie bereits voll ist.";
|
||||
|
||||
"lng_forwarded_from" = "Weitergeleitet von";
|
||||
"lng_in_reply_to" = "Antwort auf";
|
||||
@@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_video" = "Videodatei";
|
||||
"lng_media_audio" = "Sprachnachricht";
|
||||
|
||||
"lng_emoji_category0" = "Häufig genutzt";
|
||||
"lng_emoji_category1" = "Personen";
|
||||
"lng_emoji_category2" = "Natur";
|
||||
"lng_emoji_category3" = "Essen & Trinken";
|
||||
"lng_emoji_category4" = "Feiern";
|
||||
"lng_emoji_category5" = "Aktivität";
|
||||
"lng_emoji_category6" = "Reisen & Orte";
|
||||
"lng_emoji_category7" = "Objekte & Symbole";
|
||||
"lng_emoji_category8" = "Sticker";
|
||||
|
||||
"lng_in_dlg_photo" = "Bild";
|
||||
"lng_in_dlg_video" = "Video";
|
||||
"lng_in_dlg_contact" = "Kontakt";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram Desktop wurde aktualisiert auf Version {version}\n\n{changes}\n\nGesamter Versionsverlauf:\n{link}";
|
||||
"lng_new_version_minor" = "— Fehlerbehebungen und Softwareoptimierungen";
|
||||
"lng_new_version_text" = "— Einladungslinks für Gruppenchats\n— Graues Kennzeichnungssymbol für stummgeschaltete Chats";
|
||||
"lng_new_version_text" = "— Neue Emoji hinzugefügt\n— Emoji- und Sticker-Panel wurden verbessert";
|
||||
|
||||
"lng_menu_insert_unicode" = "Unicode-Steuerzeichen einfügen";
|
||||
|
||||
|
||||
@@ -389,16 +389,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_action_changed_title" = "{from} cambió el nombre del grupo a «{title}»";
|
||||
"lng_action_created_chat" = "{from} creó el grupo «{title}»";
|
||||
|
||||
"lng_group_invite_bad_link" = "El enlace de invitación está roto\no ha expirado.";
|
||||
"lng_group_invite_bad_link" = "El enlace de invitación está \nroto o ha expirado.";
|
||||
"lng_group_invite_want_join" = "¿Quieres unirte al grupo «{title}»?";
|
||||
"lng_group_invite_join" = "Unirme";
|
||||
|
||||
"lng_group_invite_link" = "Invitación";
|
||||
"lng_group_invite_create" = "Crear un enlace de invitación";
|
||||
"lng_group_invite_about" = "Puedes crear un enlace para unirse a este grupo.\nCualquiera que tenga ese enlace puede unirse.";
|
||||
"lng_group_invite_create_new" = "Nuevo enlace";
|
||||
"lng_group_invite_about_new" = "El enlace actual dejará de funcionar\ncuando crees uno nuevo.";
|
||||
"lng_group_invite_copied" = "El enlace de invitación fue copiado al portapapeles.";
|
||||
"lng_group_invite_about" = "Los usuarios de Telegram podrán unirse\na tu grupo a través de este enlace.";
|
||||
"lng_group_invite_create_new" = "Anular enlace de invitación";
|
||||
"lng_group_invite_about_new" = "El enlace previo será desactivado\ny generaremos uno nuevo para ti.";
|
||||
"lng_group_invite_copied" = "Enlace de invitación copiado al portapapeles.";
|
||||
"lng_group_invite_no_room" = "No puedes unirte a este grupo porque\nhay muchos miembros en él.";
|
||||
|
||||
"lng_forwarded_from" = "Reenviado desde";
|
||||
@@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_video" = "Vídeo";
|
||||
"lng_media_audio" = "Mensaje de voz";
|
||||
|
||||
"lng_emoji_category0" = "Usados frecuentemente";
|
||||
"lng_emoji_category1" = "Gente";
|
||||
"lng_emoji_category2" = "Naturaleza";
|
||||
"lng_emoji_category3" = "Comida y bebidas";
|
||||
"lng_emoji_category4" = "Celebración";
|
||||
"lng_emoji_category5" = "Actividad";
|
||||
"lng_emoji_category6" = "Viajes y lugares";
|
||||
"lng_emoji_category7" = "Objetos y símbolos";
|
||||
"lng_emoji_category8" = "Stickers";
|
||||
|
||||
"lng_in_dlg_photo" = "Foto";
|
||||
"lng_in_dlg_video" = "Vídeo";
|
||||
"lng_in_dlg_contact" = "Contacto";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram Desktop fue actualizada a la versión {version}\n\n{changes}\n\nEl historial completo está disponible aquí:\n{link}";
|
||||
"lng_new_version_minor" = "— Corrección de errores y otras mejoras menores";
|
||||
"lng_new_version_text" = "— Enlaces de invitación para chats grupales\n— Globo en el ícono gris para conversaciones silenciadas";
|
||||
"lng_new_version_text" = "— Añadido el soporte para nuevos emojis\n— Pestañas de stickers y emojis mejoradas ";
|
||||
|
||||
"lng_menu_insert_unicode" = "Insertar caracteres de control Unicode";
|
||||
|
||||
|
||||
@@ -240,7 +240,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_settings_section_cache" = "Archivio locale";
|
||||
"lng_settings_no_data_cached" = "Non ci sono dati nella cache!";
|
||||
"lng_settings_images_cached" = "{count:_not_used_|# immagine|# immagini}, {size}";
|
||||
"lng_settings_audios_cached" = "{count:_not_used_|# messaggio vocale|# messaggi vocali}, {size}";
|
||||
"lng_settings_audios_cached" = "{count:_not_used_|# nota vocale|# note vocali}, {size}";
|
||||
"lng_local_storage_clear" = "Elimina tutto";
|
||||
"lng_local_storage_clearing" = "Eliminando..";
|
||||
"lng_local_storage_cleared" = "Eliminato!";
|
||||
@@ -347,7 +347,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_profile_set_group_photo" = "Imposta foto";
|
||||
"lng_profile_add_participant" = "Aggiungi membro";
|
||||
"lng_profile_delete_and_exit" = "Esci";
|
||||
"lng_profile_kick" = "Espelli";
|
||||
"lng_profile_kick" = "Rimuovi";
|
||||
"lng_profile_sure_kick" = "Espellere {user} dal gruppo?";
|
||||
"lng_profile_loading" = "Caricamento..";
|
||||
"lng_profile_shared_media" = "Media condivisi";
|
||||
@@ -358,8 +358,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_profile_videos_header" = "Panoramica video";
|
||||
"lng_profile_files" = "{count:_not_used_|# file|# file} »";
|
||||
"lng_profile_files_header" = "Panoramica file";
|
||||
"lng_profile_audios" = "{count:_not_used_|# messaggio vocale|# messaggi vocali} »";
|
||||
"lng_profile_audios_header" = "Panoramica messaggi vocali";
|
||||
"lng_profile_audios" = "{count:_not_used_|# nota vocale|# note vocali} »";
|
||||
"lng_profile_audios_header" = "Panoramica note vocali";
|
||||
"lng_profile_show_all_types" = "Mostra tutti i tipi";
|
||||
"lng_profile_copy_phone" = "Copia numero di telefono";
|
||||
|
||||
@@ -379,7 +379,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_message_empty" = "(vuoto)";
|
||||
|
||||
"lng_action_add_user" = "{from} ha aggiunto {user}";
|
||||
"lng_action_kick_user" = "{from} ha espulso {user}";
|
||||
"lng_action_kick_user" = "{from} ha rimosso {user}";
|
||||
"lng_action_user_left" = "{from} ha lasciato il gruppo";
|
||||
"lng_action_user_joined" = "{from} si è unito al gruppo";
|
||||
"lng_action_user_joined_by_link" = "{from} si è unito al gruppo tramite link di invito";
|
||||
@@ -389,16 +389,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_action_changed_title" = "{from} ha cambiato il nome del gruppo in «{title}»";
|
||||
"lng_action_created_chat" = "{from} ha creato il gruppo «{title}»";
|
||||
|
||||
"lng_group_invite_bad_link" = "Questo link non funziona\no è scaduto.";
|
||||
"lng_group_invite_bad_link" = "Questo link di invito non funziona\no è scaduto.";
|
||||
"lng_group_invite_want_join" = "Vuoi unirti al gruppo «{title}»?";
|
||||
"lng_group_invite_join" = "Unisciti";
|
||||
|
||||
"lng_group_invite_link" = "Link di invito";
|
||||
"lng_group_invite_create" = "Crea un link di invito";
|
||||
"lng_group_invite_about" = "Puoi creare un link per unirsi a questo gruppo.\nChiunque abbia quel link potrà unirsi.";
|
||||
"lng_group_invite_create_new" = "Crea nuovo link";
|
||||
"lng_group_invite_about_new" = "Il link attuale smetterà di funzionare\nquando ne viene creato uno nuovo.";
|
||||
"lng_group_invite_copied" = "Il link di invito è stato copiato negli appunti.";
|
||||
"lng_group_invite_about" = "Gli utenti di Telegram saranno in grado di \naggiungersi al tuo gruppo aprendo il link.";
|
||||
"lng_group_invite_create_new" = "Revoca link";
|
||||
"lng_group_invite_about_new" = "Il link precedente smetterà di funzionare\ne ne sarà creato uno nuovo per te.";
|
||||
"lng_group_invite_copied" = "Link di invito copiato negli appunti.";
|
||||
"lng_group_invite_no_room" = "Impossibile unirsi a questo gruppo\nperché ci sono già troppi membri.";
|
||||
|
||||
"lng_forwarded_from" = "Inoltrato da";
|
||||
@@ -412,13 +412,23 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_type_photos" = "Foto";
|
||||
"lng_media_type_videos" = "Video";
|
||||
"lng_media_type_files" = "File";
|
||||
"lng_media_type_audios" = "Messaggi vocali";
|
||||
"lng_media_type_audios" = "Note vocali";
|
||||
|
||||
"lng_media_open_with" = "Apri con";
|
||||
"lng_media_download" = "Download";
|
||||
"lng_media_cancel" = "Annulla";
|
||||
"lng_media_video" = "Video";
|
||||
"lng_media_audio" = "Messaggio vocale";
|
||||
"lng_media_audio" = "Nota vocale";
|
||||
|
||||
"lng_emoji_category0" = "Utilizzate di frequente";
|
||||
"lng_emoji_category1" = "Persone";
|
||||
"lng_emoji_category2" = "Natura";
|
||||
"lng_emoji_category3" = "Cibo e bevande";
|
||||
"lng_emoji_category4" = "Festeggiamenti";
|
||||
"lng_emoji_category5" = "Attività";
|
||||
"lng_emoji_category6" = "Viaggi e luoghi";
|
||||
"lng_emoji_category7" = "Oggetti e simboli";
|
||||
"lng_emoji_category8" = "Sticker";
|
||||
|
||||
"lng_in_dlg_photo" = "Foto";
|
||||
"lng_in_dlg_video" = "Video";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram Desktop si è aggiornato alla versione {version}\n\n{changes}\n\nLa cronologia degli update è disponibile qui:\n{link}";
|
||||
"lng_new_version_minor" = "— Bug fix e altri miglioramenti minori";
|
||||
"lng_new_version_text" = "— Link di invito per le chat di gruppo\n— Icona badge grigia per le conversazioni silenziate";
|
||||
"lng_new_version_text" = "— Aggiunto il supporto per nuove emoji\n— Pannello emoji e sticker migliorato";
|
||||
|
||||
"lng_menu_insert_unicode" = "Inserisci carattere di controllo Unicode";
|
||||
|
||||
|
||||
@@ -395,9 +395,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_group_invite_link" = "초대링크";
|
||||
"lng_group_invite_create" = "초대링크 생성";
|
||||
"lng_group_invite_about" = "이 그룹방으로 초대할 수 있는 링크를 생성 할 수 있습니다.\n링크가 노출되는 모든 회원이 참여가 가능합니다.";
|
||||
"lng_group_invite_create_new" = "새로운 링크 생성";
|
||||
"lng_group_invite_about_new" = "새로 생성하실 경우\n현재 초대링크는 폐기됩니다.";
|
||||
"lng_group_invite_about" = "이 링크를 통하여,\n그룹방에 초대가 가능합니다.";
|
||||
"lng_group_invite_create_new" = "초대링크 폐기";
|
||||
"lng_group_invite_about_new" = "기존 링크는 비활성화 될 예정이며,\n새로운 링크가 재생성이 될 예정입니다.";
|
||||
"lng_group_invite_copied" = "클립보드에 초대링크가 복사 되었습니다.";
|
||||
"lng_group_invite_no_room" = "그룹방 인원 최대치가 도달하여\n더이상 참여가 안됩니다.";
|
||||
|
||||
@@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_video" = "비디오 파일";
|
||||
"lng_media_audio" = "음성 메시지";
|
||||
|
||||
"lng_emoji_category0" = "자주 사용";
|
||||
"lng_emoji_category1" = "사람";
|
||||
"lng_emoji_category2" = "자연";
|
||||
"lng_emoji_category3" = "음식점";
|
||||
"lng_emoji_category4" = "기념일";
|
||||
"lng_emoji_category5" = "활동";
|
||||
"lng_emoji_category6" = "여행 및 장소";
|
||||
"lng_emoji_category7" = "오브제 & 상징";
|
||||
"lng_emoji_category8" = "스티커";
|
||||
|
||||
"lng_in_dlg_photo" = "사진";
|
||||
"lng_in_dlg_video" = "비디오";
|
||||
"lng_in_dlg_contact" = "연락처";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "텔레그램 데스크탑은 {version} 버전으로 업데이트 되었습니다.\n\n{changes}\n\n전체 버전 히스토리는 아래에서 확인 가능합니다:\n{link}";
|
||||
"lng_new_version_minor" = "— 버그 수정 및 일부 기능 향상";
|
||||
"lng_new_version_text" = "— 그룹방 초대링크 활성화\n— 음소거된 대화는 회식 뱃지로 표기";
|
||||
"lng_new_version_text" = "— 새로운 이모티콘 지원\n— 이모티콘 및 스티커 패널 향상";
|
||||
|
||||
"lng_menu_insert_unicode" = "유니코드 문자를 입력하세요.";
|
||||
|
||||
|
||||
@@ -395,9 +395,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_group_invite_link" = "Uitnodigingslink";
|
||||
"lng_group_invite_create" = "Uitnodigingslink maken";
|
||||
"lng_group_invite_about" = "Andere gebruikers kunnen aan je groep\ndeelnemen door deze link te openen.";
|
||||
"lng_group_invite_create_new" = "Nieuwe link";
|
||||
"lng_group_invite_about_new" = "Als je een nieuwe link maakt zal \nde huidige inactief worden.";
|
||||
"lng_group_invite_about" = "Gebruikers kunnen aan je groep \ndeelnemen met deze link.";
|
||||
"lng_group_invite_create_new" = "Uitnodigingslink intrekken";
|
||||
"lng_group_invite_about_new" = "Je uitnodigingslink zal inactief worden\neen nieuwe link zal worden gegenereerd.";
|
||||
"lng_group_invite_copied" = "Link gekopieerd naar klembord.";
|
||||
"lng_group_invite_no_room" = "Sorry, deze groep is al vol.";
|
||||
|
||||
@@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_video" = "Video";
|
||||
"lng_media_audio" = "Spraakbericht";
|
||||
|
||||
"lng_emoji_category0" = "Veelgebruikt";
|
||||
"lng_emoji_category1" = "Mensen";
|
||||
"lng_emoji_category2" = "Natuur";
|
||||
"lng_emoji_category3" = "Eten & drinken";
|
||||
"lng_emoji_category4" = "Feestelijkheid";
|
||||
"lng_emoji_category5" = "Actviteit";
|
||||
"lng_emoji_category6" = "Reizen & plekken";
|
||||
"lng_emoji_category7" = "Objecten & symbolen";
|
||||
"lng_emoji_category8" = "Stickers";
|
||||
|
||||
"lng_in_dlg_photo" = "Foto";
|
||||
"lng_in_dlg_video" = "Video";
|
||||
"lng_in_dlg_contact" = "Contact";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram is bijgewerkt naar versie {version}\n\n{changes} \n\nVolledige versiegeschiedenis is hier te vinden:\n{link}";
|
||||
"lng_new_version_minor" = "— Probleemoplossing en andere kleine verbeteringen";
|
||||
"lng_new_version_text" = "— Uitnodigingslinks voor groepschats\n— Grijs Badgenummer voor gesprekken die op stil staan";
|
||||
"lng_new_version_text" = "— Ondersteuning voor nieuwe emoji toegevoegd\n— Verbeterd emoji- en stickerspaneel";
|
||||
|
||||
"lng_menu_insert_unicode" = "Unicode-besturingsteken invoegen";
|
||||
|
||||
|
||||
@@ -389,15 +389,15 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_action_changed_title" = "{from} alterou o título do grupo para «{title}»";
|
||||
"lng_action_created_chat" = "{from} criou o grupo «{title}»";
|
||||
|
||||
"lng_group_invite_bad_link" = "Link de convite quebrado ou expirado.";
|
||||
"lng_group_invite_bad_link" = "Link de convite quebrado\nou expirado.";
|
||||
"lng_group_invite_want_join" = "Você deseja entrar no grupo «{title}»?";
|
||||
"lng_group_invite_join" = "Entrar";
|
||||
|
||||
"lng_group_invite_link" = "Link de convite";
|
||||
"lng_group_invite_create" = "Criar um link de convite";
|
||||
"lng_group_invite_about" = "Você pode criar um link de convite.\nQuem abrir o link poderá entrar no grupo.";
|
||||
"lng_group_invite_create_new" = "Criar novo link";
|
||||
"lng_group_invite_about_new" = "O link de convite atual será desativado\nquando você criar um novo.";
|
||||
"lng_group_invite_about" = "Usuários do Telegram poderão entrar\nem seu grupo clicando no link.";
|
||||
"lng_group_invite_create_new" = "Desativar link";
|
||||
"lng_group_invite_about_new" = "Seu link de convite será desativado\ne iremos gerar um novo link para você.";
|
||||
"lng_group_invite_copied" = "Link copiado para área de transferência.";
|
||||
"lng_group_invite_no_room" = "Não foi possível entrar no grupo porque\nele já possui muitos membros.";
|
||||
|
||||
@@ -420,6 +420,16 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
"lng_media_video" = "Arquivo de vídeo";
|
||||
"lng_media_audio" = "Mensagem de voz";
|
||||
|
||||
"lng_emoji_category0" = "Frequentemente usado";
|
||||
"lng_emoji_category1" = "Pessoas";
|
||||
"lng_emoji_category2" = "Natureza";
|
||||
"lng_emoji_category3" = "Comidas e Bebidas";
|
||||
"lng_emoji_category4" = "Celebração";
|
||||
"lng_emoji_category5" = "Atividade";
|
||||
"lng_emoji_category6" = "Viagens e Lugares";
|
||||
"lng_emoji_category7" = "Objetos e Símbolos";
|
||||
"lng_emoji_category8" = "Stickers";
|
||||
|
||||
"lng_in_dlg_photo" = "Foto";
|
||||
"lng_in_dlg_video" = "Vídeo";
|
||||
"lng_in_dlg_contact" = "Contato";
|
||||
@@ -563,7 +573,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
|
||||
"lng_new_version_wrap" = "Telegram Desktop foi atualizado para a versão {version}\n\n{changes}\n\nHistórico completo de mudanças disponível aqui:\n{link}";
|
||||
"lng_new_version_minor" = "— Resolução de bugs e outras menores melhorias";
|
||||
"lng_new_version_text" = "— Link de convite para chats em grupo\n— Contador cinza de mensagens não lidas para conversas silenciadas.";
|
||||
"lng_new_version_text" = "— Adicionado suporte para novos emojis\n— Painel de emojis e stickers melhorado";
|
||||
|
||||
"lng_menu_insert_unicode" = "Inserir caractere de controle Unicode";
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ void LocalImageLoaderPrivate::prepareImages() {
|
||||
if (animated) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (mime == stickerMime && w > 0 && h > 0 && w <= StickerMaxSize && h <= StickerMaxSize && filesize < StickerInMemory) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string("")));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(""), MTP_inputStickerSetEmpty()));
|
||||
thumbFormat = "webp";
|
||||
thumbExt = qsl("webp");
|
||||
}
|
||||
|
||||
@@ -21,6 +21,11 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
#include "lang.h"
|
||||
|
||||
namespace {
|
||||
enum StickerSetType {
|
||||
StickerSetTypeEmpty = 0,
|
||||
StickerSetTypeID = 1,
|
||||
StickerSetTypeShortName = 2,
|
||||
};
|
||||
|
||||
typedef quint64 FileKey;
|
||||
|
||||
@@ -140,6 +145,10 @@ namespace {
|
||||
return sizeof(quint32) + str.size() * sizeof(ushort);
|
||||
}
|
||||
|
||||
uint32 _bytearraySize(const QByteArray &arr) {
|
||||
return sizeof(quint32) + arr.size();
|
||||
}
|
||||
|
||||
QByteArray _settingsSalt, _passKeySalt, _passKeyEncrypted;
|
||||
|
||||
mtpAuthKey _oldKey, _settingsKey, _passKey, _localKey;
|
||||
@@ -484,17 +493,18 @@ namespace {
|
||||
FileKey _dataNameKey = 0;
|
||||
|
||||
enum { // Local Storage Keys
|
||||
lskUserMap = 0,
|
||||
lskDraft, // data: PeerId peer
|
||||
lskDraftPosition, // data: PeerId peer
|
||||
lskImages, // data: StorageKey location
|
||||
lskLocations, // no data
|
||||
lskStickers, // data: StorageKey location
|
||||
lskAudios, // data: StorageKey location
|
||||
lskRecentStickers, // no data
|
||||
lskBackground, // no data
|
||||
lskUserSettings, // no data
|
||||
lskRecentHashtags, // no data
|
||||
lskUserMap = 0x00,
|
||||
lskDraft = 0x01, // data: PeerId peer
|
||||
lskDraftPosition = 0x02, // data: PeerId peer
|
||||
lskImages = 0x03, // data: StorageKey location
|
||||
lskLocations = 0x04, // no data
|
||||
lskStickerImages = 0x05, // data: StorageKey location
|
||||
lskAudios = 0x06, // data: StorageKey location
|
||||
lskRecentStickersOld = 0x07, // no data
|
||||
lskBackground = 0x08, // no data
|
||||
lskUserSettings = 0x09, // no data
|
||||
lskRecentHashtags = 0x0a, // no data
|
||||
lskStickers = 0x0b, // no data
|
||||
};
|
||||
|
||||
typedef QMap<PeerId, FileKey> DraftsMap;
|
||||
@@ -509,7 +519,7 @@ namespace {
|
||||
FileLocationPairs _fileLocationPairs;
|
||||
FileKey _locationsKey = 0;
|
||||
|
||||
FileKey _recentStickersKey = 0;
|
||||
FileKey _recentStickersKeyOld = 0, _stickersKey = 0;
|
||||
|
||||
FileKey _backgroundKey = 0;
|
||||
bool _backgroundWasRead = false;
|
||||
@@ -520,7 +530,7 @@ namespace {
|
||||
|
||||
typedef QPair<FileKey, qint32> FileDesc; // file, size
|
||||
typedef QMap<StorageKey, FileDesc> StorageMap;
|
||||
StorageMap _imagesMap, _stickersMap, _audiosMap;
|
||||
StorageMap _imagesMap, _stickerImagesMap, _audiosMap;
|
||||
int32 _storageImagesSize = 0, _storageStickersSize = 0, _storageAudiosSize = 0;
|
||||
|
||||
bool _mapChanged = false;
|
||||
@@ -585,7 +595,7 @@ namespace {
|
||||
locations.stream >> first >> second >> type >> loc.name >> loc.modified >> loc.size;
|
||||
|
||||
MediaKey key(first, second);
|
||||
loc.type = type;
|
||||
loc.type = StorageFileType(type);
|
||||
|
||||
if (loc.check()) {
|
||||
_fileLocations.insert(key, loc);
|
||||
@@ -953,6 +963,14 @@ namespace {
|
||||
cSetRecentEmojisPreload(v);
|
||||
} break;
|
||||
|
||||
case dbiRecentStickers: {
|
||||
RecentStickerPreload v;
|
||||
stream >> v;
|
||||
if (!_checkStreamStatus(stream)) return false;
|
||||
|
||||
cSetRecentStickersPreload(v);
|
||||
} break;
|
||||
|
||||
case dbiEmojiVariants: {
|
||||
EmojiColorVariants v;
|
||||
stream >> v;
|
||||
@@ -1077,10 +1095,17 @@ namespace {
|
||||
LOG(("App Info: reading old user config.."));
|
||||
qint32 version = 0;
|
||||
|
||||
mtpDcOptions dcOpts(cDcOptions());
|
||||
mtpDcOptions dcOpts;
|
||||
{
|
||||
QReadLocker lock(MTP::dcOptionsMutex());
|
||||
dcOpts = cDcOptions();
|
||||
}
|
||||
_dcOpts = &dcOpts;
|
||||
_readOldUserSettingsFields(&file, version);
|
||||
cSetDcOptions(dcOpts);
|
||||
{
|
||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
||||
cSetDcOptions(dcOpts);
|
||||
}
|
||||
|
||||
file.close();
|
||||
result = true;
|
||||
@@ -1157,10 +1182,17 @@ namespace {
|
||||
LOG(("App Info: reading old keys.."));
|
||||
qint32 version = 0;
|
||||
|
||||
mtpDcOptions dcOpts(cDcOptions());
|
||||
mtpDcOptions dcOpts;
|
||||
{
|
||||
QReadLocker lock(MTP::dcOptionsMutex());
|
||||
dcOpts = cDcOptions();
|
||||
}
|
||||
_dcOpts = &dcOpts;
|
||||
_readOldMtpDataFields(&file, version);
|
||||
cSetDcOptions(dcOpts);
|
||||
{
|
||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
||||
cSetDcOptions(dcOpts);
|
||||
}
|
||||
|
||||
file.close();
|
||||
result = true;
|
||||
@@ -1178,8 +1210,9 @@ namespace {
|
||||
|
||||
uint32 size = 11 * (sizeof(quint32) + sizeof(qint32));
|
||||
size += sizeof(quint32) + _stringSize(cAskDownloadPath() ? QString() : cDownloadPath());
|
||||
size += sizeof(quint32) + sizeof(qint32) + cGetRecentEmojis().size() * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentEmojisPreload().isEmpty() ? cGetRecentEmojis().size() : cRecentEmojisPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + sizeof(qint32) + cEmojiVariants().size() * (sizeof(uint32) + sizeof(uint64));
|
||||
size += sizeof(quint32) + sizeof(qint32) + (cRecentStickersPreload().isEmpty() ? cGetRecentStickers().size() : cRecentStickersPreload().size()) * (sizeof(uint64) + sizeof(ushort));
|
||||
size += sizeof(quint32) + _stringSize(cDialogLastPath());
|
||||
|
||||
EncryptedDescriptor data(size);
|
||||
@@ -1197,14 +1230,27 @@ namespace {
|
||||
data.stream << quint32(dbiEmojiTab) << qint32(cEmojiTab());
|
||||
data.stream << quint32(dbiDialogLastPath) << cDialogLastPath();
|
||||
|
||||
RecentEmojisPreload v;
|
||||
v.reserve(cGetRecentEmojis().size());
|
||||
for (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) {
|
||||
v.push_back(qMakePair(emojiKey(i->first), i->second));
|
||||
{
|
||||
RecentEmojisPreload v(cRecentEmojisPreload());
|
||||
if (v.isEmpty()) {
|
||||
v.reserve(cGetRecentEmojis().size());
|
||||
for (RecentEmojiPack::const_iterator i = cGetRecentEmojis().cbegin(), e = cGetRecentEmojis().cend(); i != e; ++i) {
|
||||
v.push_back(qMakePair(emojiKey(i->first), i->second));
|
||||
}
|
||||
}
|
||||
data.stream << quint32(dbiRecentEmojis) << v;
|
||||
}
|
||||
data.stream << quint32(dbiRecentEmojis) << v;
|
||||
|
||||
data.stream << quint32(dbiEmojiVariants) << cEmojiVariants();
|
||||
{
|
||||
RecentStickerPreload v(cRecentStickersPreload());
|
||||
if (v.isEmpty()) {
|
||||
v.reserve(cGetRecentStickers().size());
|
||||
for (RecentStickerPack::const_iterator i = cGetRecentStickers().cbegin(), e = cGetRecentStickers().cend(); i != e; ++i) {
|
||||
v.push_back(qMakePair(i->first->id, i->second));
|
||||
}
|
||||
}
|
||||
data.stream << quint32(dbiRecentStickers) << v;
|
||||
}
|
||||
|
||||
FileWriteDescriptor file(_userSettingsKey);
|
||||
file.writeEncrypted(data);
|
||||
@@ -1326,9 +1372,9 @@ namespace {
|
||||
|
||||
DraftsMap draftsMap, draftsPositionsMap;
|
||||
DraftsNotReadMap draftsNotReadMap;
|
||||
StorageMap imagesMap, stickersMap, audiosMap;
|
||||
StorageMap imagesMap, stickerImagesMap, audiosMap;
|
||||
qint64 storageImagesSize = 0, storageStickersSize = 0, storageAudiosSize = 0;
|
||||
quint64 locationsKey = 0, recentStickersKey = 0, backgroundKey = 0, userSettingsKey = 0, recentHashtagsKey = 0;
|
||||
quint64 locationsKey = 0, recentStickersKeyOld = 0, stickersKey = 0, backgroundKey = 0, userSettingsKey = 0, recentHashtagsKey = 0;
|
||||
while (!map.stream.atEnd()) {
|
||||
quint32 keyType;
|
||||
map.stream >> keyType;
|
||||
@@ -1366,7 +1412,7 @@ namespace {
|
||||
storageImagesSize += size;
|
||||
}
|
||||
} break;
|
||||
case lskStickers: {
|
||||
case lskStickerImages: {
|
||||
quint32 count = 0;
|
||||
map.stream >> count;
|
||||
for (quint32 i = 0; i < count; ++i) {
|
||||
@@ -1374,7 +1420,7 @@ namespace {
|
||||
quint64 first, second;
|
||||
qint32 size;
|
||||
map.stream >> key >> first >> second >> size;
|
||||
stickersMap.insert(StorageKey(first, second), FileDesc(key, size));
|
||||
stickerImagesMap.insert(StorageKey(first, second), FileDesc(key, size));
|
||||
storageStickersSize += size;
|
||||
}
|
||||
} break;
|
||||
@@ -1393,8 +1439,8 @@ namespace {
|
||||
case lskLocations: {
|
||||
map.stream >> locationsKey;
|
||||
} break;
|
||||
case lskRecentStickers: {
|
||||
map.stream >> recentStickersKey;
|
||||
case lskRecentStickersOld: {
|
||||
map.stream >> recentStickersKeyOld;
|
||||
} break;
|
||||
case lskBackground: {
|
||||
map.stream >> backgroundKey;
|
||||
@@ -1405,6 +1451,9 @@ namespace {
|
||||
case lskRecentHashtags: {
|
||||
map.stream >> recentHashtagsKey;
|
||||
} break;
|
||||
case lskStickers: {
|
||||
map.stream >> stickersKey;
|
||||
} break;
|
||||
default:
|
||||
LOG(("App Error: unknown key type in encrypted map: %1").arg(keyType));
|
||||
return Local::ReadMapFailed;
|
||||
@@ -1420,13 +1469,14 @@ namespace {
|
||||
|
||||
_imagesMap = imagesMap;
|
||||
_storageImagesSize = storageImagesSize;
|
||||
_stickersMap = stickersMap;
|
||||
_stickerImagesMap = stickerImagesMap;
|
||||
_storageStickersSize = storageStickersSize;
|
||||
_audiosMap = audiosMap;
|
||||
_storageAudiosSize = storageAudiosSize;
|
||||
|
||||
_locationsKey = locationsKey;
|
||||
_recentStickersKey = recentStickersKey;
|
||||
_recentStickersKeyOld = recentStickersKeyOld;
|
||||
_stickersKey = stickersKey;
|
||||
_backgroundKey = backgroundKey;
|
||||
_userSettingsKey = userSettingsKey;
|
||||
_recentHashtagsKey = recentHashtagsKey;
|
||||
@@ -1486,10 +1536,11 @@ namespace {
|
||||
if (!_draftsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsMap.size() * sizeof(quint64) * 2;
|
||||
if (!_draftsPositionsMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _draftsPositionsMap.size() * sizeof(quint64) * 2;
|
||||
if (!_imagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _imagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
|
||||
if (!_stickersMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickersMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
|
||||
if (!_stickerImagesMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _stickerImagesMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
|
||||
if (!_audiosMap.isEmpty()) mapSize += sizeof(quint32) * 2 + _audiosMap.size() * (sizeof(quint64) * 3 + sizeof(qint32));
|
||||
if (_locationsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_recentStickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_recentStickersKeyOld) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_stickersKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_backgroundKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_userSettingsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
if (_recentHashtagsKey) mapSize += sizeof(quint32) + sizeof(quint64);
|
||||
@@ -1512,9 +1563,9 @@ namespace {
|
||||
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
|
||||
}
|
||||
}
|
||||
if (!_stickersMap.isEmpty()) {
|
||||
mapData.stream << quint32(lskStickers) << quint32(_stickersMap.size());
|
||||
for (StorageMap::const_iterator i = _stickersMap.cbegin(), e = _stickersMap.cend(); i != e; ++i) {
|
||||
if (!_stickerImagesMap.isEmpty()) {
|
||||
mapData.stream << quint32(lskStickerImages) << quint32(_stickerImagesMap.size());
|
||||
for (StorageMap::const_iterator i = _stickerImagesMap.cbegin(), e = _stickerImagesMap.cend(); i != e; ++i) {
|
||||
mapData.stream << quint64(i.value().first) << quint64(i.key().first) << quint64(i.key().second) << qint32(i.value().second);
|
||||
}
|
||||
}
|
||||
@@ -1527,8 +1578,11 @@ namespace {
|
||||
if (_locationsKey) {
|
||||
mapData.stream << quint32(lskLocations) << quint64(_locationsKey);
|
||||
}
|
||||
if (_recentStickersKey) {
|
||||
mapData.stream << quint32(lskRecentStickers) << quint64(_recentStickersKey);
|
||||
if (_recentStickersKeyOld) {
|
||||
mapData.stream << quint32(lskRecentStickersOld) << quint64(_recentStickersKeyOld);
|
||||
}
|
||||
if (_stickersKey) {
|
||||
mapData.stream << quint32(lskStickers) << quint64(_stickersKey);
|
||||
}
|
||||
if (_backgroundKey) {
|
||||
mapData.stream << quint32(lskBackground) << quint64(_backgroundKey);
|
||||
@@ -1648,7 +1702,11 @@ namespace Local {
|
||||
LOG(("App Error: could not decrypt settings from settings file, maybe bad passcode.."));
|
||||
return writeSettings();
|
||||
}
|
||||
mtpDcOptions dcOpts(cDcOptions());
|
||||
mtpDcOptions dcOpts;
|
||||
{
|
||||
QReadLocker lock(MTP::dcOptionsMutex());
|
||||
dcOpts = cDcOptions();
|
||||
}
|
||||
_dcOpts = &dcOpts;
|
||||
LOG(("App Info: reading encrypted settings.."));
|
||||
while (!settings.stream.atEnd()) {
|
||||
@@ -1669,7 +1727,10 @@ namespace Local {
|
||||
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
|
||||
}
|
||||
}
|
||||
cSetDcOptions(dcOpts);
|
||||
{
|
||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
||||
cSetDcOptions(dcOpts);
|
||||
}
|
||||
|
||||
_settingsSalt = salt;
|
||||
}
|
||||
@@ -1690,13 +1751,19 @@ namespace Local {
|
||||
}
|
||||
settings.writeData(_settingsSalt);
|
||||
|
||||
mtpDcOptions dcOpts(cDcOptions());
|
||||
mtpDcOptions dcOpts;
|
||||
{
|
||||
QReadLocker lock(MTP::dcOptionsMutex());
|
||||
dcOpts = cDcOptions();
|
||||
}
|
||||
if (dcOpts.isEmpty()) {
|
||||
const BuiltInDc *bdcs = builtInDcs();
|
||||
for (int i = 0, l = builtInDcsCount(); i < l; ++i) {
|
||||
dcOpts.insert(bdcs[i].id, mtpDcOption(bdcs[i].id, "", bdcs[i].ip, bdcs[i].port));
|
||||
DEBUG_LOG(("MTP Info: adding built in DC %1 connect option: %2:%3").arg(bdcs[i].id).arg(bdcs[i].ip).arg(bdcs[i].port));
|
||||
}
|
||||
|
||||
QWriteLocker lock(MTP::dcOptionsMutex());
|
||||
cSetDcOptions(dcOpts);
|
||||
}
|
||||
|
||||
@@ -1759,9 +1826,9 @@ namespace Local {
|
||||
_draftsPositionsMap.clear();
|
||||
_imagesMap.clear();
|
||||
_draftsNotReadMap.clear();
|
||||
_stickersMap.clear();
|
||||
_stickerImagesMap.clear();
|
||||
_audiosMap.clear();
|
||||
_locationsKey = _recentStickersKey = _backgroundKey = _userSettingsKey = _recentHashtagsKey = 0;
|
||||
_locationsKey = _recentStickersKeyOld = _stickersKey = _backgroundKey = _userSettingsKey = _recentHashtagsKey = 0;
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapNow);
|
||||
|
||||
@@ -1969,13 +2036,13 @@ namespace Local {
|
||||
if (_imagesMap.constFind(location) != _imagesMap.cend()) return;
|
||||
|
||||
QByteArray fmt = image->savedFormat();
|
||||
mtpTypeId format = 0;
|
||||
StorageFileType format = StorageFileUnknown;
|
||||
if (fmt == "JPG") {
|
||||
format = mtpc_storage_fileJpeg;
|
||||
format = StorageFileJpeg;
|
||||
} else if (fmt == "PNG") {
|
||||
format = mtpc_storage_filePng;
|
||||
format = StorageFilePng;
|
||||
} else if (fmt == "GIF") {
|
||||
format = mtpc_storage_fileGif;
|
||||
format = StorageFileGif;
|
||||
}
|
||||
if (format) {
|
||||
image->forget();
|
||||
@@ -2025,7 +2092,7 @@ namespace Local {
|
||||
quint32 imageType;
|
||||
draft.stream >> locFirst >> locSecond >> imageType >> imageData;
|
||||
|
||||
return (locFirst == location.first && locSecond == location.second) ? StorageImageSaved(imageType, imageData) : StorageImageSaved();
|
||||
return (locFirst == location.first && locSecond == location.second) ? StorageImageSaved(StorageFileType(imageType), imageData) : StorageImageSaved();
|
||||
}
|
||||
|
||||
int32 hasImages() {
|
||||
@@ -2036,13 +2103,13 @@ namespace Local {
|
||||
return _storageImagesSize;
|
||||
}
|
||||
|
||||
void writeSticker(const StorageKey &location, const QByteArray &sticker, bool overwrite) {
|
||||
void writeStickerImage(const StorageKey &location, const QByteArray &sticker, bool overwrite) {
|
||||
if (!_working()) return;
|
||||
|
||||
qint32 size = _storageStickerSize(sticker.size());
|
||||
StorageMap::const_iterator i = _stickersMap.constFind(location);
|
||||
if (i == _stickersMap.cend()) {
|
||||
i = _stickersMap.insert(location, FileDesc(genKey(UserPath), size));
|
||||
StorageMap::const_iterator i = _stickerImagesMap.constFind(location);
|
||||
if (i == _stickerImagesMap.cend()) {
|
||||
i = _stickerImagesMap.insert(location, FileDesc(genKey(UserPath), size));
|
||||
_storageStickersSize += size;
|
||||
_mapChanged = true;
|
||||
_writeMap();
|
||||
@@ -2056,20 +2123,20 @@ namespace Local {
|
||||
if (i.value().second != size) {
|
||||
_storageStickersSize += size;
|
||||
_storageStickersSize -= i.value().second;
|
||||
_stickersMap[location].second = size;
|
||||
_stickerImagesMap[location].second = size;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray readSticker(const StorageKey &location) {
|
||||
StorageMap::iterator j = _stickersMap.find(location);
|
||||
if (j == _stickersMap.cend()) {
|
||||
QByteArray readStickerImage(const StorageKey &location) {
|
||||
StorageMap::iterator j = _stickerImagesMap.find(location);
|
||||
if (j == _stickerImagesMap.cend()) {
|
||||
return QByteArray();
|
||||
}
|
||||
FileReadDescriptor draft;
|
||||
if (!readEncryptedFile(draft, j.value().first, UserPath)) {
|
||||
clearKey(j.value().first, UserPath);
|
||||
_storageStickersSize -= j.value().second;
|
||||
_stickersMap.erase(j);
|
||||
_stickerImagesMap.erase(j);
|
||||
return QByteArray();
|
||||
}
|
||||
|
||||
@@ -2081,7 +2148,7 @@ namespace Local {
|
||||
}
|
||||
|
||||
int32 hasStickers() {
|
||||
return _stickersMap.size();
|
||||
return _stickerImagesMap.size();
|
||||
}
|
||||
|
||||
qint64 storageStickersSize() {
|
||||
@@ -2140,56 +2207,91 @@ namespace Local {
|
||||
return _storageAudiosSize;
|
||||
}
|
||||
|
||||
void writeRecentStickers() {
|
||||
void writeStickers() {
|
||||
if (!_working()) return;
|
||||
|
||||
const RecentStickerPack &recent(cRecentStickers());
|
||||
if (recent.isEmpty()) {
|
||||
if (_recentStickersKey) {
|
||||
clearKey(_recentStickersKey);
|
||||
_recentStickersKey = 0;
|
||||
|
||||
const StickerSets &sets(cStickerSets());
|
||||
if (sets.isEmpty()) {
|
||||
if (_stickersKey) {
|
||||
clearKey(_stickersKey);
|
||||
_stickersKey = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
_writeMap();
|
||||
} else {
|
||||
if (!_recentStickersKey) {
|
||||
_recentStickersKey = genKey();
|
||||
if (!_stickersKey) {
|
||||
_stickersKey = genKey();
|
||||
_mapChanged = true;
|
||||
_writeMap(WriteMapFast);
|
||||
}
|
||||
quint32 size = 0;
|
||||
for (RecentStickerPack::const_iterator i = recent.cbegin(); i != recent.cend(); ++i) {
|
||||
DocumentData *doc = i->first;
|
||||
if (doc->status == FileFailed) continue;
|
||||
quint32 size = sizeof(quint32) + _bytearraySize(cStickersHash());
|
||||
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
|
||||
if (i->stickers.isEmpty()) continue;
|
||||
|
||||
// id + value + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + alt
|
||||
size += sizeof(quint64) + sizeof(qint16) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(doc->alt);
|
||||
// id + access + title + shortName + stickersCount
|
||||
size += sizeof(quint64) * 2 + _stringSize(i->title) + _stringSize(i->shortName) + sizeof(quint32);
|
||||
for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) {
|
||||
DocumentData *doc = *j;
|
||||
|
||||
// id + access + date + namelen + name + mimelen + mime + dc + size + width + height + type + alt + type-of-set
|
||||
size += sizeof(quint64) + sizeof(quint64) + sizeof(qint32) + _stringSize(doc->name) + _stringSize(doc->mime) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + _stringSize(doc->sticker->alt) + sizeof(qint32);
|
||||
|
||||
// thumb-width + thumb-height + thumb-dc + thumb-volume + thumb-local + thumb-secret
|
||||
size += sizeof(qint32) + sizeof(qint32) + sizeof(qint32) + sizeof(quint64) + sizeof(qint32) + sizeof(quint64);
|
||||
}
|
||||
}
|
||||
EncryptedDescriptor data(size);
|
||||
for (RecentStickerPack::const_iterator i = recent.cbegin(); i != recent.cend(); ++i) {
|
||||
DocumentData *doc = i->first;
|
||||
if (doc->status == FileFailed) continue;
|
||||
data.stream << quint32(sets.size()) << cStickersHash();
|
||||
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
|
||||
if (i->stickers.isEmpty()) continue;
|
||||
|
||||
data.stream << quint64(doc->id) << qint16(i->second) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << doc->alt;
|
||||
data.stream << quint64(i->id) << quint64(i->access) << i->title << i->shortName << quint32(i->stickers.size());
|
||||
for (StickerPack::const_iterator j = i->stickers.cbegin(), e = i->stickers.cend(); j != e; ++j) {
|
||||
DocumentData *doc = *j;
|
||||
data.stream << quint64(doc->id) << quint64(doc->access) << qint32(doc->date) << doc->name << doc->mime << qint32(doc->dc) << qint32(doc->size) << qint32(doc->dimensions.width()) << qint32(doc->dimensions.height()) << qint32(doc->type) << doc->sticker->alt;
|
||||
switch (doc->sticker->set.type()) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
data.stream << qint32(StickerSetTypeID);
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
data.stream << qint32(StickerSetTypeShortName);
|
||||
} break;
|
||||
case mtpc_inputStickerSetEmpty:
|
||||
default: {
|
||||
data.stream << qint32(StickerSetTypeEmpty);
|
||||
} break;
|
||||
}
|
||||
const StorageImageLocation &loc(doc->sticker->loc);
|
||||
data.stream << qint32(loc.width) << qint32(loc.height) << qint32(loc.dc) << quint64(loc.volume) << qint32(loc.local) << quint64(loc.secret);
|
||||
}
|
||||
}
|
||||
FileWriteDescriptor file(_recentStickersKey);
|
||||
FileWriteDescriptor file(_stickersKey);
|
||||
file.writeEncrypted(data);
|
||||
}
|
||||
}
|
||||
|
||||
void readRecentStickers() {
|
||||
if (!_recentStickersKey) return;
|
||||
void importOldRecentStickers() {
|
||||
if (!_recentStickersKeyOld) return;
|
||||
|
||||
FileReadDescriptor stickers;
|
||||
if (!readEncryptedFile(stickers, _recentStickersKey)) {
|
||||
clearKey(_recentStickersKey);
|
||||
_recentStickersKey = 0;
|
||||
if (!readEncryptedFile(stickers, _recentStickersKeyOld)) {
|
||||
clearKey(_recentStickersKeyOld);
|
||||
_recentStickersKeyOld = 0;
|
||||
_writeMap();
|
||||
return;
|
||||
}
|
||||
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
sets.clear();
|
||||
RecentStickerPack &recent(cRefRecentStickers());
|
||||
recent.clear();
|
||||
|
||||
cSetStickersHash(QByteArray());
|
||||
|
||||
StickerSet &def(sets.insert(DefaultStickerSetId, StickerSet(DefaultStickerSetId, 0, qsl("Great Minds"), QString())).value());
|
||||
StickerSet &custom(sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString())).value());
|
||||
|
||||
QMap<uint64, bool> read;
|
||||
RecentStickerPack recent;
|
||||
while (!stickers.stream.atEnd()) {
|
||||
quint64 id, access;
|
||||
QString name, mime, alt;
|
||||
@@ -2199,7 +2301,7 @@ namespace Local {
|
||||
if (stickers.version >= 7021) {
|
||||
stickers.stream >> alt;
|
||||
}
|
||||
if (read.contains(id)) continue;
|
||||
if (!value || read.contains(id)) continue;
|
||||
read.insert(id, true);
|
||||
|
||||
QVector<MTPDocumentAttribute> attributes;
|
||||
@@ -2207,16 +2309,115 @@ namespace Local {
|
||||
if (type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (type == StickerDocument) {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt)));
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||
}
|
||||
|
||||
recent.push_back(qMakePair(App::document(id, 0, access, date, attributes, mime, ImagePtr(), dc, size), value));
|
||||
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, ImagePtr(), dc, size, StorageImageLocation());
|
||||
if (!doc->sticker) continue;
|
||||
|
||||
if (value > 0) {
|
||||
def.stickers.push_back(doc);
|
||||
} else {
|
||||
custom.stickers.push_back(doc);
|
||||
}
|
||||
if (recent.size() < StickerPanPerRow * StickerPanRowsPerPage && qAbs(value) > 1) recent.push_back(qMakePair(doc, qAbs(value)));
|
||||
}
|
||||
if (def.stickers.isEmpty()) sets.remove(DefaultStickerSetId);
|
||||
if (custom.stickers.isEmpty()) sets.remove(CustomStickerSetId);
|
||||
|
||||
writeStickers();
|
||||
writeUserSettings();
|
||||
|
||||
clearKey(_recentStickersKeyOld);
|
||||
_recentStickersKeyOld = 0;
|
||||
_writeMap();
|
||||
}
|
||||
|
||||
void readStickers() {
|
||||
if (!_stickersKey) {
|
||||
return importOldRecentStickers();
|
||||
}
|
||||
|
||||
cSetRecentStickers(recent);
|
||||
FileReadDescriptor stickers;
|
||||
if (!readEncryptedFile(stickers, _stickersKey)) {
|
||||
clearKey(_stickersKey);
|
||||
_stickersKey = 0;
|
||||
_writeMap();
|
||||
return;
|
||||
}
|
||||
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
sets.clear();
|
||||
|
||||
quint32 cnt;
|
||||
QByteArray hash;
|
||||
stickers.stream >> cnt >> hash;
|
||||
for (int32 i = 0; i < cnt; ++i) {
|
||||
quint64 setId = 0, setAccess = 0;
|
||||
QString setTitle, setShortName;
|
||||
quint32 scnt = 0;
|
||||
stickers.stream >> setId >> setAccess >> setTitle >> setShortName >> scnt;
|
||||
|
||||
if (setId == DefaultStickerSetId) {
|
||||
setTitle = qsl("Great Minds");
|
||||
} else if (setId == CustomStickerSetId) {
|
||||
setTitle = lang(lng_custom_stickers);
|
||||
}
|
||||
StickerSet &set(sets.insert(setId, StickerSet(setId, setAccess, setTitle, setShortName)).value());
|
||||
set.stickers.reserve(scnt);
|
||||
|
||||
QMap<uint64, bool> read;
|
||||
for (int32 j = 0; j < scnt; ++j) {
|
||||
quint64 id, access;
|
||||
QString name, mime, alt;
|
||||
qint32 date, dc, size, width, height, type, typeOfSet;
|
||||
stickers.stream >> id >> access >> date >> name >> mime >> dc >> size >> width >> height >> type >> alt >> typeOfSet;
|
||||
|
||||
qint32 thumbWidth, thumbHeight, thumbDc, thumbLocal;
|
||||
quint64 thumbVolume, thumbSecret;
|
||||
stickers.stream >> thumbWidth >> thumbHeight >> thumbDc >> thumbVolume >> thumbLocal >> thumbSecret;
|
||||
|
||||
if (read.contains(id)) continue;
|
||||
read.insert(id, true);
|
||||
|
||||
if (setId == DefaultStickerSetId || setId == CustomStickerSetId) {
|
||||
typeOfSet = StickerSetTypeEmpty;
|
||||
}
|
||||
|
||||
QVector<MTPDocumentAttribute> attributes;
|
||||
if (!name.isEmpty()) attributes.push_back(MTP_documentAttributeFilename(MTP_string(name)));
|
||||
if (type == AnimatedDocument) {
|
||||
attributes.push_back(MTP_documentAttributeAnimated());
|
||||
} else if (type == StickerDocument) {
|
||||
switch (typeOfSet) {
|
||||
case StickerSetTypeID: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetID(MTP_long(setId), MTP_long(setAccess))));
|
||||
} break;
|
||||
case StickerSetTypeShortName: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetShortName(MTP_string(setShortName))));
|
||||
} break;
|
||||
case StickerSetTypeEmpty:
|
||||
default: {
|
||||
attributes.push_back(MTP_documentAttributeSticker(MTP_string(alt), MTP_inputStickerSetEmpty()));
|
||||
} break;
|
||||
}
|
||||
}
|
||||
if (width > 0 && height > 0) {
|
||||
attributes.push_back(MTP_documentAttributeImageSize(MTP_int(width), MTP_int(height)));
|
||||
}
|
||||
|
||||
StorageImageLocation thumb(thumbWidth, thumbHeight, thumbDc, thumbVolume, thumbLocal, thumbSecret);
|
||||
DocumentData *doc = App::documentSet(id, 0, access, date, attributes, mime, thumb.dc ? ImagePtr(thumb) : ImagePtr(), dc, size, thumb);
|
||||
if (!doc->sticker) continue;
|
||||
|
||||
set.stickers.push_back(doc);
|
||||
}
|
||||
}
|
||||
|
||||
cSetStickersHash(hash);
|
||||
}
|
||||
|
||||
void writeBackground(int32 id, const QImage &img) {
|
||||
@@ -2385,8 +2586,8 @@ namespace Local {
|
||||
_storageImagesSize = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
if (!_stickersMap.isEmpty()) {
|
||||
_stickersMap.clear();
|
||||
if (!_stickerImagesMap.isEmpty()) {
|
||||
_stickerImagesMap.clear();
|
||||
_storageStickersSize = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
@@ -2407,8 +2608,12 @@ namespace Local {
|
||||
_locationsKey = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
if (_recentStickersKey) {
|
||||
_recentStickersKey = 0;
|
||||
if (_recentStickersKeyOld) {
|
||||
_recentStickersKeyOld = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
if (_stickersKey) {
|
||||
_stickersKey = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
if (_recentHashtagsKey) {
|
||||
@@ -2435,9 +2640,9 @@ namespace Local {
|
||||
_mapChanged = true;
|
||||
}
|
||||
if (data->stickers.isEmpty()) {
|
||||
data->stickers = _stickersMap;
|
||||
data->stickers = _stickerImagesMap;
|
||||
} else {
|
||||
for (StorageMap::const_iterator i = _stickersMap.cbegin(), e = _stickersMap.cend(); i != e; ++i) {
|
||||
for (StorageMap::const_iterator i = _stickerImagesMap.cbegin(), e = _stickerImagesMap.cend(); i != e; ++i) {
|
||||
StorageKey k = i.key();
|
||||
while (data->stickers.constFind(k) != data->stickers.cend()) {
|
||||
++k.second;
|
||||
@@ -2445,8 +2650,8 @@ namespace Local {
|
||||
data->stickers.insert(k, i.value());
|
||||
}
|
||||
}
|
||||
if (!_stickersMap.isEmpty()) {
|
||||
_stickersMap.clear();
|
||||
if (!_stickerImagesMap.isEmpty()) {
|
||||
_stickerImagesMap.clear();
|
||||
_storageStickersSize = 0;
|
||||
_mapChanged = true;
|
||||
}
|
||||
|
||||
@@ -122,8 +122,8 @@ namespace Local {
|
||||
int32 hasImages();
|
||||
qint64 storageImagesSize();
|
||||
|
||||
void writeSticker(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
QByteArray readSticker(const StorageKey &location);
|
||||
void writeStickerImage(const StorageKey &location, const QByteArray &data, bool overwrite = true);
|
||||
QByteArray readStickerImage(const StorageKey &location);
|
||||
int32 hasStickers();
|
||||
qint64 storageStickersSize();
|
||||
|
||||
@@ -132,8 +132,8 @@ namespace Local {
|
||||
int32 hasAudios();
|
||||
qint64 storageAudiosSize();
|
||||
|
||||
void writeRecentStickers();
|
||||
void readRecentStickers();
|
||||
void writeStickers();
|
||||
void readStickers();
|
||||
|
||||
void writeBackground(int32 id, const QImage &img);
|
||||
bool readBackground();
|
||||
|
||||
@@ -26,6 +26,8 @@ int main(int argc, char *argv[]) {
|
||||
_oldWndExceptionFilter = SetUnhandledExceptionFilter(_exceptionFilter);
|
||||
#endif
|
||||
|
||||
InitOpenSSL _init;
|
||||
|
||||
settingsParseArgs(argc, argv);
|
||||
for (int32 i = 0; i < argc; ++i) {
|
||||
if (string("-fixprevious") == argv[i]) {
|
||||
@@ -61,7 +63,12 @@ int main(int argc, char *argv[]) {
|
||||
psStart();
|
||||
int result = 0;
|
||||
{
|
||||
Application app(argc, argv);
|
||||
QByteArray args[] = { "-style=0" }; // prepare fake args
|
||||
static const int a_cnt = sizeof(args) / sizeof(args[0]);
|
||||
int a_argc = a_cnt + 1;
|
||||
char *a_argv[a_cnt + 1] = { argv[0], args[0].data() };
|
||||
|
||||
Application app(a_argc, a_argv);
|
||||
if (!App::quiting()) {
|
||||
result = app.exec();
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
#include "settingswidget.h"
|
||||
#include "mainwidget.h"
|
||||
#include "boxes/confirmbox.h"
|
||||
#include "boxes/stickersetbox.h"
|
||||
|
||||
#include "localstorage.h"
|
||||
|
||||
@@ -549,6 +550,10 @@ void MainWidget::updateMutedIn(int32 seconds) {
|
||||
_updateMutedTimer.start(ms);
|
||||
}
|
||||
|
||||
void MainWidget::updateStickers() {
|
||||
history.updateStickers();
|
||||
}
|
||||
|
||||
void MainWidget::onUpdateMuted() {
|
||||
App::updateMuted();
|
||||
}
|
||||
@@ -977,7 +982,7 @@ void MainWidget::saveRecentHashtags(const QString &text) {
|
||||
}
|
||||
}
|
||||
if (!found && cRecentWriteHashtags().isEmpty() && cRecentSearchHashtags().isEmpty()) {
|
||||
Local::readRecentStickers();
|
||||
Local::readRecentHashtags();
|
||||
recent = cRecentWriteHashtags();
|
||||
}
|
||||
found = true;
|
||||
@@ -2473,7 +2478,7 @@ void MainWidget::start(const MTPUser &user) {
|
||||
}
|
||||
_started = true;
|
||||
App::wnd()->sendServiceHistoryRequest();
|
||||
Local::readRecentStickers();
|
||||
Local::readStickers();
|
||||
history.start();
|
||||
}
|
||||
|
||||
@@ -2493,6 +2498,11 @@ void MainWidget::openLocalUrl(const QString &url) {
|
||||
if (m.hasMatch()) {
|
||||
joinGroupByHash(m.captured(1));
|
||||
}
|
||||
} else if (u.startsWith(QLatin1String("tg://addstickers"), Qt::CaseInsensitive)) {
|
||||
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://addstickers/?\\?set=([a-zA-Z0-9\\.\\_]+)$"), QRegularExpression::CaseInsensitiveOption).match(u);
|
||||
if (m.hasMatch()) {
|
||||
stickersBox(MTP_inputStickerSetShortName(MTP_string(m.captured(1))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2513,6 +2523,17 @@ void MainWidget::joinGroupByHash(const QString &hash) {
|
||||
MTP::send(MTPmessages_CheckChatInvite(MTP_string(hash)), rpcDone(&MainWidget::inviteCheckDone, hash), rpcFail(&MainWidget::inviteCheckFail));
|
||||
}
|
||||
|
||||
void MainWidget::stickersBox(const MTPInputStickerSet &set) {
|
||||
StickerSetBox *box = new StickerSetBox(set);
|
||||
connect(box, SIGNAL(installed(uint64)), this, SLOT(onStickersInstalled(uint64)));
|
||||
App::wnd()->showLayer(box);
|
||||
}
|
||||
|
||||
void MainWidget::onStickersInstalled(uint64 setId) {
|
||||
emit stickersUpdated();
|
||||
history.stickersInstalled(setId);
|
||||
}
|
||||
|
||||
void MainWidget::usernameResolveDone(bool toProfile, const MTPUser &user) {
|
||||
App::wnd()->hideLayer();
|
||||
UserData *u = App::feedUsers(MTP_vector<MTPUser>(1, user));
|
||||
@@ -2733,28 +2754,24 @@ void MainWidget::updateNotifySetting(PeerData *peer, bool enabled) {
|
||||
}
|
||||
|
||||
void MainWidget::incrementSticker(DocumentData *sticker) {
|
||||
RecentStickerPack recent(cRecentStickers());
|
||||
if (!sticker || !sticker->sticker) return;
|
||||
|
||||
RecentStickerPack &recent(cGetRecentStickers());
|
||||
RecentStickerPack::iterator i = recent.begin(), e = recent.end();
|
||||
for (; i != e; ++i) {
|
||||
if (i->first == sticker) {
|
||||
if (i->second > 0) {
|
||||
++i->second;
|
||||
} else {
|
||||
--i->second;
|
||||
}
|
||||
if (qAbs(i->second) > 0x4000) {
|
||||
++i->second;
|
||||
if (i->second > 0x8000) {
|
||||
for (RecentStickerPack::iterator j = recent.begin(); j != e; ++j) {
|
||||
if (qAbs(j->second) > 1) {
|
||||
if (j->second > 1) {
|
||||
j->second /= 2;
|
||||
} else if (j->second > 0) {
|
||||
j->second = 1;
|
||||
} else {
|
||||
j->second = -1;
|
||||
j->second = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (; i != recent.begin(); --i) {
|
||||
if (qAbs((i - 1)->second) > qAbs(i->second)) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
@@ -2763,11 +2780,45 @@ void MainWidget::incrementSticker(DocumentData *sticker) {
|
||||
}
|
||||
}
|
||||
if (i == e) {
|
||||
recent.push_front(qMakePair(sticker, -(recent.isEmpty() ? 1 : qAbs(recent.front().second))));
|
||||
while (recent.size() >= StickerPanPerRow * StickerPanRowsPerPage) recent.pop_back();
|
||||
recent.push_back(qMakePair(sticker, 1));
|
||||
for (i = recent.end() - 1; i != recent.begin(); --i) {
|
||||
if ((i - 1)->second > i->second) {
|
||||
break;
|
||||
}
|
||||
qSwap(*i, *(i - 1));
|
||||
}
|
||||
}
|
||||
cSetRecentStickers(recent);
|
||||
Local::writeRecentStickers();
|
||||
|
||||
Local::writeUserSettings();
|
||||
|
||||
bool found = false;
|
||||
uint64 setId = 0;
|
||||
QString setName;
|
||||
switch (sticker->sticker->set.type()) {
|
||||
case mtpc_inputStickerSetID: setId = sticker->sticker->set.c_inputStickerSetID().vid.v; break;
|
||||
case mtpc_inputStickerSetShortName: setName = qs(sticker->sticker->set.c_inputStickerSetShortName().vshort_name).toLower().trimmed(); break;
|
||||
}
|
||||
StickerSets &sets(cRefStickerSets());
|
||||
for (StickerSets::const_iterator i = sets.cbegin(); i != sets.cend(); ++i) {
|
||||
if (i->id == CustomStickerSetId || (setId && i->id == setId) || (!setName.isEmpty() && i->shortName.toLower().trimmed() == setName) || (!setId && setName.isEmpty() && i->id == DefaultStickerSetId)) {
|
||||
for (int32 j = 0, l = i->stickers.size(); j < l; ++j) {
|
||||
if (i->stickers.at(j) == sticker) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
StickerSets::iterator it = sets.find(CustomStickerSetId);
|
||||
if (it == sets.cend()) {
|
||||
it = sets.insert(CustomStickerSetId, StickerSet(CustomStickerSetId, 0, lang(lng_custom_stickers), QString()));
|
||||
}
|
||||
it->stickers.push_back(sticker);
|
||||
Local::writeStickers();
|
||||
}
|
||||
history.updateRecentStickers();
|
||||
}
|
||||
|
||||
|
||||
@@ -185,9 +185,12 @@ public:
|
||||
bool animStep(float64 ms);
|
||||
|
||||
void start(const MTPUser &user);
|
||||
|
||||
void openLocalUrl(const QString &str);
|
||||
void openUserByName(const QString &name, bool toProfile = false);
|
||||
void joinGroupByHash(const QString &hash);
|
||||
void stickersBox(const MTPInputStickerSet &set);
|
||||
|
||||
void startFull(const MTPVector<MTPUser> &users);
|
||||
bool started();
|
||||
void applyNotifySetting(const MTPNotifyPeer &peer, const MTPPeerNotifySettings &settings, History *history = 0);
|
||||
@@ -341,6 +344,8 @@ public:
|
||||
void webPageUpdated(WebPageData *page);
|
||||
void updateMutedIn(int32 seconds);
|
||||
|
||||
void updateStickers();
|
||||
|
||||
~MainWidget();
|
||||
|
||||
signals:
|
||||
@@ -352,6 +357,7 @@ signals:
|
||||
void dialogToTop(const History::DialogLinks &links);
|
||||
void dialogsUpdated();
|
||||
void showPeerAsync(quint64 peer, qint32 msgId, bool back, bool force);
|
||||
void stickersUpdated();
|
||||
|
||||
public slots:
|
||||
|
||||
@@ -402,6 +408,8 @@ public slots:
|
||||
|
||||
void onUpdateMuted();
|
||||
|
||||
void onStickersInstalled(uint64 setId);
|
||||
|
||||
private:
|
||||
|
||||
void partWasRead(PeerData *peer, const MTPmessages_AffectedHistory &result);
|
||||
|
||||
@@ -775,9 +775,9 @@ void MediaView::displayDocument(DocumentData *doc, HistoryItem *item) {
|
||||
_doc = doc;
|
||||
|
||||
QString already = _doc->already(true);
|
||||
if (!_doc->sticker->isNull() && _doc->sticker->loaded()) {
|
||||
if (_doc->sticker && !_doc->sticker->img->isNull() && _doc->sticker->img->loaded()) {
|
||||
_currentGif.stop();
|
||||
_current = _doc->sticker->pix();
|
||||
_current = _doc->sticker->img->pix();
|
||||
} else if (!already.isEmpty()) {
|
||||
QImageReader reader(already);
|
||||
if (reader.canRead()) {
|
||||
@@ -980,7 +980,7 @@ void MediaView::paintEvent(QPaintEvent *e) {
|
||||
QRect imgRect(_x, _y, _w, _h);
|
||||
const QPixmap *toDraw = _currentGif.isNull() ? &_current : &_currentGif.frames[_currentGif.frame];
|
||||
if (imgRect.intersects(r)) {
|
||||
if (toDraw->hasAlpha() && (!_doc || _doc->sticker->isNull())) {
|
||||
if (toDraw->hasAlpha() && (!_doc || !_doc->sticker || _doc->sticker->img->isNull())) {
|
||||
p.fillRect(imgRect, _transparentBrush);
|
||||
}
|
||||
if (_zoom) {
|
||||
@@ -1368,7 +1368,7 @@ void MediaView::preloadData(int32 delta) {
|
||||
switch (media->type()) {
|
||||
case MediaTypePhoto: static_cast<HistoryPhoto*>(media)->photo()->full->load(); break;
|
||||
case MediaTypeDocument: static_cast<HistoryDocument*>(media)->document()->thumb->load(); break;
|
||||
case MediaTypeSticker: static_cast<HistorySticker*>(media)->document()->sticker->load(); break;
|
||||
case MediaTypeSticker: static_cast<HistorySticker*>(media)->document()->sticker->img->load(); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ with open('scheme.tl') as f:
|
||||
prms = {};
|
||||
conditions = {};
|
||||
prmsList = [];
|
||||
conditionsList = [];
|
||||
isTemplate = hasFlags = hasTemplate = '';
|
||||
for param in paramsList:
|
||||
if (re.match(r'^\s*$', param)):
|
||||
@@ -149,7 +150,9 @@ with open('scheme.tl') as f:
|
||||
print('Bad param found: "' + param + '" in line: ' + line);
|
||||
continue;
|
||||
ptype = pmasktype.group(3);
|
||||
conditions[pname] = pmasktype.group(2);
|
||||
if (not pname in conditions):
|
||||
conditionsList.append(pname);
|
||||
conditions[pname] = pmasktype.group(2);
|
||||
elif (ptype.find('<') >= 0):
|
||||
templ = re.match(r'^([vV]ector<)([A-Za-z0-9\._]+)>$', ptype);
|
||||
if (templ):
|
||||
@@ -198,11 +201,11 @@ with open('scheme.tl') as f:
|
||||
if (len(conditions)):
|
||||
funcsText += '\n';
|
||||
funcsText += '\tenum {\n';
|
||||
for paramName in conditions.keys():
|
||||
for paramName in conditionsList:
|
||||
funcsText += '\t\tflag_' + paramName + ' = (1 << ' + conditions[paramName] + '),\n';
|
||||
funcsText += '\t};\n';
|
||||
funcsText += '\n';
|
||||
for paramName in conditions.keys():
|
||||
for paramName in conditionsList:
|
||||
funcsText += '\tbool has_' + paramName + '() const { return v' + hasFlags + '.v & flag_' + paramName + '; }\n';
|
||||
|
||||
funcsText += '\n';
|
||||
@@ -210,7 +213,7 @@ with open('scheme.tl') as f:
|
||||
size = [];
|
||||
for k in prmsList:
|
||||
v = prms[k];
|
||||
if (k in conditions.keys()):
|
||||
if (k in conditionsList):
|
||||
size.append('(has_' + k + '() ? v' + k + '.innerLength() : 0)');
|
||||
else:
|
||||
size.append('v' + k + '.innerLength()');
|
||||
@@ -224,7 +227,7 @@ with open('scheme.tl') as f:
|
||||
funcsText += '\tvoid read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_' + name + ') {\n'; # read method
|
||||
for k in prmsList:
|
||||
v = prms[k];
|
||||
if (k in conditions.keys()):
|
||||
if (k in conditionsList):
|
||||
funcsText += '\t\tif (has_' + k + '()) { v' + k + '.read(from, end); } else { v' + k + ' = MTP' + v + '(); }\n';
|
||||
else:
|
||||
funcsText += '\t\tv' + k + '.read(from, end);\n';
|
||||
@@ -233,7 +236,7 @@ with open('scheme.tl') as f:
|
||||
funcsText += '\tvoid write(mtpBuffer &to) const {\n'; # write method
|
||||
for k in prmsList:
|
||||
v = prms[k];
|
||||
if (k in conditions.keys()):
|
||||
if (k in conditionsList):
|
||||
funcsText += '\t\tif (has_' + k + '()) v' + k + '.write(to);\n';
|
||||
else:
|
||||
funcsText += '\t\tv' + k + '.write(to);\n';
|
||||
@@ -269,7 +272,7 @@ with open('scheme.tl') as f:
|
||||
funcsList.append(restype);
|
||||
funcsDict[restype] = [];
|
||||
# TypesDict[restype] = resType;
|
||||
funcsDict[restype].append([name, typeid, prmsList, prms, hasFlags, conditions]);
|
||||
funcsDict[restype].append([name, typeid, prmsList, prms, hasFlags, conditionsList, conditions]);
|
||||
else:
|
||||
if (isTemplate != ''):
|
||||
print('Template types not allowed: "' + resType + '" in line: ' + line);
|
||||
@@ -278,7 +281,7 @@ with open('scheme.tl') as f:
|
||||
typesList.append(restype);
|
||||
typesDict[restype] = [];
|
||||
TypesDict[restype] = resType;
|
||||
typesDict[restype].append([name, typeid, prmsList, prms, hasFlags, conditions]);
|
||||
typesDict[restype].append([name, typeid, prmsList, prms, hasFlags, conditionsList, conditions]);
|
||||
|
||||
consts = consts + 1;
|
||||
|
||||
@@ -292,7 +295,8 @@ def addTextSerialize(lst, dct, dataLetter):
|
||||
prmsList = data[2];
|
||||
prms = data[3];
|
||||
hasFlags = data[4];
|
||||
conditions = data[5];
|
||||
conditionsList = data[5];
|
||||
conditions = data[6];
|
||||
|
||||
if len(result):
|
||||
result += '\n';
|
||||
@@ -311,7 +315,7 @@ def addTextSerialize(lst, dct, dataLetter):
|
||||
result += '\t\t\t\tcase ' + str(stage) + ': to.add(" ' + k + ': "); ++stages.back(); ';
|
||||
if (k == hasFlags):
|
||||
result += 'if (start >= end) throw Exception("start >= end in flags"); else flags.back() = *start; ';
|
||||
if (k in conditions.keys()):
|
||||
if (k in conditionsList):
|
||||
result += 'if (flag & MTP' + dataLetter + name + '::flag_' + k + ') { ';
|
||||
result += 'types.push_back(';
|
||||
vtypeget = re.match(r'^[Vv]ector<MTP([A-Za-z0-9\._]+)>', v);
|
||||
@@ -355,7 +359,7 @@ def addTextSerialize(lst, dct, dataLetter):
|
||||
else:
|
||||
result += '0); vtypes.push_back(0';
|
||||
result += '); stages.push_back(0); flags.push_back(0); ';
|
||||
if (k in conditions.keys()):
|
||||
if (k in conditionsList):
|
||||
result += '} else { to.add("[ SKIPPED BY BIT ' + conditions[k] + ' IN FIELD ' + hasFlags + ' ]"); } ';
|
||||
result += 'break;\n';
|
||||
stage = stage + 1;
|
||||
@@ -396,7 +400,8 @@ for restype in typesList:
|
||||
prmsList = data[2];
|
||||
prms = data[3];
|
||||
hasFlags = data[4];
|
||||
conditions = data[5];
|
||||
conditionsList = data[5];
|
||||
conditions = data[6];
|
||||
|
||||
dataText = '';
|
||||
dataText += '\nclass MTPD' + name + ' : public mtpDataImpl<MTPD' + name + '> {\n'; # data class
|
||||
@@ -451,7 +456,7 @@ for restype in typesList:
|
||||
if (withType):
|
||||
readText += '\t\t';
|
||||
writeText += '\t\t';
|
||||
if (paramName in conditions.keys()):
|
||||
if (paramName in conditionsList):
|
||||
readText += '\tif (v.has_' + paramName + '()) { v.v' + paramName + '.read(from, end); } else { v.v' + paramName + ' = MTP' + paramType + '(); }\n';
|
||||
writeText += '\tif (v.has_' + paramName + '()) v.v' + paramName + '.write(to);\n';
|
||||
sizeList.append('(v.has_' + paramName + '() ? v.v' + paramName + '.innerLength() : 0)');
|
||||
@@ -482,11 +487,11 @@ for restype in typesList:
|
||||
if (len(conditions)):
|
||||
dataText += '\n';
|
||||
dataText += '\tenum {\n';
|
||||
for paramName in conditions.keys():
|
||||
for paramName in conditionsList:
|
||||
dataText += '\t\tflag_' + paramName + ' = (1 << ' + conditions[paramName] + '),\n';
|
||||
dataText += '\t};\n';
|
||||
dataText += '\n';
|
||||
for paramName in conditions.keys():
|
||||
for paramName in conditionsList:
|
||||
dataText += '\tbool has_' + paramName + '() const { return v' + hasFlags + '.v & flag_' + paramName + '; }\n';
|
||||
dataText += '};\n'; # class ending
|
||||
|
||||
|
||||
@@ -23,13 +23,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
|
||||
namespace {
|
||||
typedef QMap<int32, MTProtoSessionPtr> Sessions;
|
||||
Sessions sessions;
|
||||
QVector<MTProtoSessionPtr> sessionsToKill;
|
||||
MTProtoSessionPtr mainSession;
|
||||
|
||||
typedef QMap<mtpRequestId, int32> RequestsByDC; // holds dc for request to this dc or -dc for request to main dc
|
||||
typedef QMap<mtpRequestId, int32> RequestsByDC; // holds dcWithShift for request to this dc or -dc for request to main dc
|
||||
RequestsByDC requestsByDC;
|
||||
QMutex requestByDCLock;
|
||||
|
||||
typedef QMap<mtpRequestId, int32> AuthExportRequests; // holds target dc for auth export request
|
||||
typedef QMap<mtpRequestId, int32> AuthExportRequests; // holds target dcWithShift for auth export request
|
||||
AuthExportRequests authExportRequests;
|
||||
|
||||
bool _started = false;
|
||||
@@ -55,7 +56,7 @@ namespace {
|
||||
BadGuestDCRequests badGuestDCRequests;
|
||||
|
||||
typedef QVector<mtpRequestId> DCAuthWaiters;
|
||||
typedef QMap<int32, DCAuthWaiters> AuthWaiters;
|
||||
typedef QMap<int32, DCAuthWaiters> AuthWaiters; // holds request ids waiting for auth import to specific dc
|
||||
AuthWaiters authWaiters;
|
||||
|
||||
QMutex toClearLock;
|
||||
@@ -76,12 +77,11 @@ namespace {
|
||||
if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
||||
return;
|
||||
}
|
||||
int32 newdc = i.value();
|
||||
int32 newdc = i.value() % _mtp_internal::dcShift;
|
||||
|
||||
DEBUG_LOG(("MTP Info: auth import to dc %1 succeeded").arg(newdc));
|
||||
|
||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
||||
MTProtoSessionPtr session(_mtp_internal::getSession(newdc));
|
||||
if (waiters.size()) {
|
||||
QReadLocker locker(&requestMapLock);
|
||||
for (DCAuthWaiters::iterator i = waiters.begin(), e = waiters.end(); i != e; ++i) {
|
||||
@@ -91,6 +91,7 @@ namespace {
|
||||
LOG(("MTP Error: could not find request %1 for resending").arg(requestId));
|
||||
continue;
|
||||
}
|
||||
int32 dcWithShift = newdc;
|
||||
{
|
||||
RequestsByDC::iterator k = requestsByDC.find(requestId);
|
||||
if (k == requestsByDC.cend()) {
|
||||
@@ -101,11 +102,15 @@ namespace {
|
||||
MTP::setdc(newdc);
|
||||
k.value() = -newdc;
|
||||
} else {
|
||||
k.value() = k.value() - (k.value() % _mtp_internal::dcShift) + newdc;
|
||||
int32 shift = k.value() - (k.value() % _mtp_internal::dcShift);
|
||||
dcWithShift += shift;
|
||||
k.value() = dcWithShift;
|
||||
}
|
||||
DEBUG_LOG(("MTP Info: resending request %1 to dc %2 after import auth").arg(requestId).arg(k.value()));
|
||||
}
|
||||
session->sendPrepared(j.value());
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift)) {
|
||||
session->sendPrepared(j.value());
|
||||
}
|
||||
}
|
||||
waiters.clear();
|
||||
}
|
||||
@@ -121,8 +126,8 @@ namespace {
|
||||
void exportDone(const MTPauth_ExportedAuthorization &result, mtpRequestId req) {
|
||||
AuthExportRequests::const_iterator i = authExportRequests.constFind(req);
|
||||
if (i == authExportRequests.cend()) {
|
||||
LOG(("MTP Error: auth export request target dc not found, requestId: %1").arg(req));
|
||||
RPCError error(rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dc, request %1").arg(req)));
|
||||
LOG(("MTP Error: auth export request target dcWithShift not found, requestId: %1").arg(req));
|
||||
RPCError error(rpcClientError("AUTH_IMPORT_FAIL", QString("did not find target dcWithShift, request %1").arg(req)));
|
||||
if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
||||
return;
|
||||
}
|
||||
@@ -137,7 +142,7 @@ namespace {
|
||||
|
||||
AuthExportRequests::const_iterator i = authExportRequests.constFind(req);
|
||||
if (i != authExportRequests.cend()) {
|
||||
authWaiters[i.value()].clear();
|
||||
authWaiters[i.value() % _mtp_internal::dcShift].clear();
|
||||
}
|
||||
if (globalHandler.onFail && MTP::authedId()) (*globalHandler.onFail)(req, error); // auth failed in main dc
|
||||
return true;
|
||||
@@ -151,31 +156,34 @@ namespace {
|
||||
if ((m = QRegularExpression("^(FILE|PHONE|NETWORK|USER)_MIGRATE_(\\d+)$").match(err)).hasMatch()) {
|
||||
if (!requestId) return false;
|
||||
|
||||
int32 dc = 0, newdc = m.captured(2).toInt();
|
||||
int32 dcWithShift = 0, newdcWithShift = m.captured(2).toInt();
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
||||
if (i == requestsByDC.end()) {
|
||||
LOG(("MTP Error: could not find request %1 for migrating to %2").arg(requestId).arg(newdc));
|
||||
LOG(("MTP Error: could not find request %1 for migrating to %2").arg(requestId).arg(newdcWithShift));
|
||||
} else {
|
||||
dc = i.value();
|
||||
dcWithShift = i.value();
|
||||
}
|
||||
}
|
||||
if (!dc || !newdc) return false;
|
||||
if (!dcWithShift || !newdcWithShift) return false;
|
||||
|
||||
DEBUG_LOG(("MTP Info: changing request %1 dc%2 to %3").arg(requestId).arg((dc > 0) ? "" : " and main dc").arg(newdc));
|
||||
if (dc < 0) {
|
||||
if (MTP::authedId() && !authExportRequests.contains(requestId)) { // import auth, set dc and resend
|
||||
DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(newdc));
|
||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
||||
DEBUG_LOG(("MTP Info: changing request %1 from dcWithShift%2 to dc%3").arg(requestId).arg(dcWithShift).arg(newdcWithShift));
|
||||
if (dcWithShift < 0) { // newdc shift = 0
|
||||
if (false && MTP::authedId() && !authExportRequests.contains(requestId)) { // migrate not supported at this moment
|
||||
DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(newdcWithShift));
|
||||
DCAuthWaiters &waiters(authWaiters[newdcWithShift]);
|
||||
if (!waiters.size()) {
|
||||
authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), newdc);
|
||||
authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdcWithShift)), rpcDone(exportDone), rpcFail(exportFail)), newdcWithShift);
|
||||
}
|
||||
waiters.push_back(requestId);
|
||||
return true;
|
||||
} else {
|
||||
MTP::setdc(newdc);
|
||||
MTP::setdc(newdcWithShift);
|
||||
}
|
||||
} else {
|
||||
int32 shift = dcWithShift - (dcWithShift % _mtp_internal::dcShift);
|
||||
newdcWithShift += shift;
|
||||
}
|
||||
|
||||
mtpRequest req;
|
||||
@@ -188,8 +196,10 @@ namespace {
|
||||
}
|
||||
req = i.value();
|
||||
}
|
||||
_mtp_internal::registerRequest(requestId, (dc < 0) ? -newdc : newdc);
|
||||
_mtp_internal::getSession(newdc)->sendPrepared(req);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(newdcWithShift)) {
|
||||
_mtp_internal::registerRequest(requestId, (dcWithShift < 0) ? -newdcWithShift : newdcWithShift);
|
||||
session->sendPrepared(req);
|
||||
}
|
||||
return true;
|
||||
} else if (code < 0 || code >= 500 || (m = QRegularExpression("^FLOOD_WAIT_(\\d+)$").match(err)).hasMatch()) {
|
||||
if (!requestId) return false;
|
||||
@@ -218,26 +228,26 @@ namespace {
|
||||
|
||||
return true;
|
||||
} else if (code == 401 || (badGuestDC && badGuestDCRequests.constFind(requestId) == badGuestDCRequests.cend())) {
|
||||
int32 dc = 0;
|
||||
int32 dcWithShift = 0;
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
||||
if (i != requestsByDC.end()) {
|
||||
dc = i.value();
|
||||
dcWithShift = i.value();
|
||||
} else {
|
||||
LOG(("MTP Error: unauthorized request without dc info, requestId %1").arg(requestId));
|
||||
}
|
||||
}
|
||||
int32 newdc = abs(dc) % _mtp_internal::dcShift;
|
||||
int32 newdc = abs(dcWithShift) % _mtp_internal::dcShift;
|
||||
if (!newdc || newdc == mtpMainDC() || !MTP::authedId()) {
|
||||
if (!badGuestDC && globalHandler.onFail) (*globalHandler.onFail)(requestId, error); // auth failed in main dc
|
||||
return false;
|
||||
}
|
||||
|
||||
DEBUG_LOG(("MTP Info: importing auth to dc %1").arg(dc));
|
||||
DEBUG_LOG(("MTP Info: importing auth to dcWithShift %1").arg(dcWithShift));
|
||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
||||
if (!waiters.size()) {
|
||||
authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), newdc);
|
||||
authExportRequests.insert(MTP::send(MTPauth_ExportAuthorization(MTP_int(newdc)), rpcDone(exportDone), rpcFail(exportFail)), abs(dcWithShift));
|
||||
}
|
||||
waiters.push_back(requestId);
|
||||
if (badGuestDC) badGuestDCRequests.insert(requestId);
|
||||
@@ -253,20 +263,22 @@ namespace {
|
||||
}
|
||||
req = i.value();
|
||||
}
|
||||
int32 dc = 0;
|
||||
int32 dcWithShift = 0;
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
||||
if (i == requestsByDC.end()) {
|
||||
LOG(("MTP Error: could not find request %1 for resending with init connection").arg(requestId));
|
||||
} else {
|
||||
dc = i.value();
|
||||
dcWithShift = i.value();
|
||||
}
|
||||
}
|
||||
if (!dc) return false;
|
||||
if (!dcWithShift) return false;
|
||||
|
||||
req->needsLayer = true;
|
||||
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(req);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) {
|
||||
req->needsLayer = true;
|
||||
session->sendPrepared(req);
|
||||
}
|
||||
return true;
|
||||
} else if (err == qsl("MSG_WAIT_FAILED")) {
|
||||
mtpRequest req;
|
||||
@@ -283,7 +295,7 @@ namespace {
|
||||
LOG(("MTP Error: wait failed for not dependent request %1").arg(requestId));
|
||||
return false;
|
||||
}
|
||||
int32 dc = 0;
|
||||
int32 dcWithShift = 0;
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId), j = requestsByDC.find(req->after->requestId);
|
||||
@@ -292,19 +304,21 @@ namespace {
|
||||
} else if (j == requestsByDC.end()) {
|
||||
LOG(("MTP Error: could not find dependent request %1 by dc").arg(req->after->requestId));
|
||||
} else {
|
||||
dc = i.value();
|
||||
dcWithShift = i.value();
|
||||
if (i.value() != j.value()) {
|
||||
req->after = mtpRequest();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dc) return false;
|
||||
if (!dcWithShift) return false;
|
||||
|
||||
if (!req->after) {
|
||||
req->needsLayer = true;
|
||||
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(req);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) {
|
||||
req->needsLayer = true;
|
||||
session->sendPrepared(req);
|
||||
}
|
||||
} else {
|
||||
int32 newdc = abs(dc) % _mtp_internal::dcShift;
|
||||
int32 newdc = abs(dcWithShift) % _mtp_internal::dcShift;
|
||||
DCAuthWaiters &waiters(authWaiters[newdc]);
|
||||
if (waiters.indexOf(req->after->requestId) >= 0) {
|
||||
if (waiters.indexOf(requestId) < 0) {
|
||||
@@ -338,27 +352,27 @@ namespace {
|
||||
}
|
||||
|
||||
namespace _mtp_internal {
|
||||
MTProtoSessionPtr getSession(int32 dc) {
|
||||
MTProtoSessionPtr getSession(int32 dcWithShift) {
|
||||
if (!_started) return MTProtoSessionPtr();
|
||||
if (!dc) return mainSession;
|
||||
if (!(dc % _mtp_internal::dcShift)) {
|
||||
dc += mainSession->getDC();
|
||||
if (!dcWithShift) return mainSession;
|
||||
if (!(dcWithShift % _mtp_internal::dcShift)) {
|
||||
dcWithShift += (mainSession->getDcWithShift() % _mtp_internal::dcShift);
|
||||
}
|
||||
|
||||
Sessions::const_iterator i = sessions.constFind(dc);
|
||||
Sessions::const_iterator i = sessions.constFind(dcWithShift);
|
||||
if (i != sessions.cend()) return *i;
|
||||
|
||||
MTProtoSessionPtr result(new MTProtoSession());
|
||||
result->start(dc);
|
||||
result->start(dcWithShift);
|
||||
|
||||
sessions.insert(dc, result);
|
||||
sessions.insert(dcWithShift, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void registerRequest(mtpRequestId requestId, int32 dc) {
|
||||
void registerRequest(mtpRequestId requestId, int32 dcWithShift) {
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
requestsByDC.insert(requestId, dc);
|
||||
requestsByDC.insert(requestId, dcWithShift);
|
||||
}
|
||||
_mtp_internal::performDelayedClear(); // need to do it somewhere..
|
||||
}
|
||||
@@ -530,12 +544,12 @@ namespace _mtp_internal {
|
||||
if (globalHandler.onDone) (*globalHandler.onDone)(0, from, end); // some updates were received
|
||||
}
|
||||
|
||||
void onStateChange(int32 dc, int32 state) {
|
||||
if (stateChangedHandler) stateChangedHandler(dc, state);
|
||||
void onStateChange(int32 dcWithShift, int32 state) {
|
||||
if (stateChangedHandler) stateChangedHandler(dcWithShift, state);
|
||||
}
|
||||
|
||||
void onSessionReset(int32 dc) {
|
||||
if (sessionResetHandler) sessionResetHandler(dc);
|
||||
void onSessionReset(int32 dcWithShift) {
|
||||
if (sessionResetHandler) sessionResetHandler(dcWithShift);
|
||||
}
|
||||
|
||||
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err) { // return true if need to clean request data
|
||||
@@ -561,12 +575,12 @@ namespace _mtp_internal {
|
||||
mtpRequestId requestId = delayedRequests.front().first;
|
||||
delayedRequests.pop_front();
|
||||
|
||||
int32 dc = 0;
|
||||
int32 dcWithShift = 0;
|
||||
{
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::const_iterator i = requestsByDC.constFind(requestId);
|
||||
if (i != requestsByDC.cend()) {
|
||||
dc = i.value();
|
||||
dcWithShift = i.value();
|
||||
} else {
|
||||
LOG(("MTP Error: could not find request dc for delayed resend, requestId %1").arg(requestId));
|
||||
continue;
|
||||
@@ -583,7 +597,9 @@ namespace _mtp_internal {
|
||||
}
|
||||
req = j.value();
|
||||
}
|
||||
_mtp_internal::getSession(dc < 0 ? (-dc) : dc)->sendPrepared(req);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(dcWithShift < 0 ? (-dcWithShift) : dcWithShift)) {
|
||||
session->sendPrepared(req);
|
||||
}
|
||||
}
|
||||
|
||||
if (!delayedRequests.isEmpty()) {
|
||||
@@ -595,13 +611,15 @@ namespace _mtp_internal {
|
||||
namespace MTP {
|
||||
|
||||
void start() {
|
||||
if (started()) return;
|
||||
|
||||
unixtimeInit();
|
||||
|
||||
MTProtoDCMap &dcs(mtpDCMap());
|
||||
|
||||
mainSession = MTProtoSessionPtr(new MTProtoSession());
|
||||
mainSession->start(mtpMainDC());
|
||||
sessions[mainSession->getDC()] = mainSession;
|
||||
sessions[mainSession->getDcWithShift()] = mainSession;
|
||||
|
||||
_started = true;
|
||||
resender = new _mtp_internal::RequestResender();
|
||||
@@ -625,8 +643,9 @@ namespace MTP {
|
||||
void restart(int32 dcMask) {
|
||||
if (!_started) return;
|
||||
|
||||
dcMask %= _mtp_internal::dcShift;
|
||||
for (Sessions::const_iterator i = sessions.cbegin(), e = sessions.cend(); i != e; ++i) {
|
||||
if ((*i)->getDC() % _mtp_internal::dcShift == dcMask % _mtp_internal::dcShift) {
|
||||
if (((*i)->getDcWithShift() % _mtp_internal::dcShift) == dcMask) {
|
||||
(*i)->restart();
|
||||
}
|
||||
}
|
||||
@@ -641,8 +660,9 @@ namespace MTP {
|
||||
void setdc(int32 dc, bool fromZeroOnly) {
|
||||
if (!dc || !_started) return;
|
||||
mtpSetDC(dc, fromZeroOnly);
|
||||
if (maindc() != mainSession->getDC()) {
|
||||
mainSession = _mtp_internal::getSession(maindc());
|
||||
int32 oldMainDc = mainSession->getDcWithShift();
|
||||
if (maindc() != oldMainDc) {
|
||||
killSession(oldMainDc);
|
||||
}
|
||||
Local::writeMtpData();
|
||||
}
|
||||
@@ -656,7 +676,7 @@ namespace MTP {
|
||||
|
||||
if (!dc) return mainSession->getState();
|
||||
if (!(dc % _mtp_internal::dcShift)) {
|
||||
dc += mainSession->getDC();
|
||||
dc += (mainSession->getDcWithShift() % _mtp_internal::dcShift);
|
||||
}
|
||||
|
||||
Sessions::const_iterator i = sessions.constFind(dc);
|
||||
@@ -670,7 +690,7 @@ namespace MTP {
|
||||
|
||||
if (!dc) return mainSession->transport();
|
||||
if (!(dc % _mtp_internal::dcShift)) {
|
||||
dc += mainSession->getDC();
|
||||
dc += (mainSession->getDcWithShift() % _mtp_internal::dcShift);
|
||||
}
|
||||
|
||||
Sessions::const_iterator i = sessions.constFind(dc);
|
||||
@@ -679,16 +699,10 @@ namespace MTP {
|
||||
return QString();
|
||||
}
|
||||
|
||||
void initdc(int32 dc) {
|
||||
if (!_started) return;
|
||||
_mtp_internal::getSession(dc);
|
||||
}
|
||||
|
||||
void ping() {
|
||||
MTProtoSessionPtr session = _mtp_internal::getSession(0);
|
||||
if (!session) return;
|
||||
|
||||
return session->ping();
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(0)) {
|
||||
session->ping();
|
||||
}
|
||||
}
|
||||
|
||||
void cancel(mtpRequestId requestId) {
|
||||
@@ -706,25 +720,35 @@ namespace MTP {
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
||||
if (i != requestsByDC.end()) {
|
||||
_mtp_internal::getSession(abs(i.value()))->cancel(requestId, msgId);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(abs(i.value()))) {
|
||||
session->cancel(requestId, msgId);
|
||||
}
|
||||
requestsByDC.erase(i);
|
||||
}
|
||||
}
|
||||
_mtp_internal::clearCallbacks(requestId);
|
||||
}
|
||||
|
||||
void killSessionsDelayed() {
|
||||
if (!sessionsToKill.isEmpty()) {
|
||||
sessionsToKill.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void killSession(int32 dc) {
|
||||
Sessions::iterator i = sessions.find(dc);
|
||||
if (i != sessions.end()) {
|
||||
bool wasMain = (i.value() == mainSession);
|
||||
|
||||
i.value()->stop();
|
||||
i.value()->kill();
|
||||
if (sessionsToKill.isEmpty()) QTimer::singleShot(0, killSessionsDelayed);
|
||||
sessionsToKill.push_back(i.value());
|
||||
sessions.erase(i);
|
||||
|
||||
if (wasMain) {
|
||||
mainSession = MTProtoSessionPtr(new MTProtoSession());
|
||||
mainSession->start(mtpMainDC());
|
||||
sessions[mainSession->getDC()] = mainSession;
|
||||
sessions[mainSession->getDcWithShift()] = mainSession;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -743,22 +767,30 @@ namespace MTP {
|
||||
QMutexLocker locker(&requestByDCLock);
|
||||
RequestsByDC::iterator i = requestsByDC.find(requestId);
|
||||
if (i != requestsByDC.end()) {
|
||||
return _mtp_internal::getSession(abs(i.value()))->requestState(requestId);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(abs(i.value()))) {
|
||||
return session->requestState(requestId);
|
||||
}
|
||||
return MTP::RequestConnecting;
|
||||
}
|
||||
return MTP::RequestSent;
|
||||
}
|
||||
return _mtp_internal::getSession(-requestId)->requestState(0);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(-requestId)) {
|
||||
return session->requestState(0);
|
||||
}
|
||||
return MTP::RequestConnecting;
|
||||
}
|
||||
|
||||
void stop() {
|
||||
for (Sessions::iterator i = sessions.begin(), e = sessions.end(); i != e; ++i) {
|
||||
i.value()->stop();
|
||||
i.value()->kill();
|
||||
}
|
||||
sessions.clear();
|
||||
mainSession = MTProtoSessionPtr();
|
||||
delete resender;
|
||||
resender = 0;
|
||||
mtpDestroyConfigLoader();
|
||||
|
||||
_started = false;
|
||||
}
|
||||
|
||||
void authed(int32 uid) {
|
||||
@@ -810,4 +842,8 @@ namespace MTP {
|
||||
return mtpSetKey(dc, key);
|
||||
}
|
||||
|
||||
QReadWriteLock *dcOptionsMutex() {
|
||||
return mtpDcOptionsMutex();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace _mtp_internal {
|
||||
void execCallback(mtpRequestId requestId, const mtpPrime *from, const mtpPrime *end);
|
||||
bool hasCallbacks(mtpRequestId requestId);
|
||||
void globalCallback(const mtpPrime *from, const mtpPrime *end);
|
||||
void onStateChange(int32 dc, int32 state);
|
||||
void onSessionReset(int32 dc);
|
||||
void onStateChange(int32 dcWithShift, int32 state);
|
||||
void onSessionReset(int32 dcWithShift);
|
||||
bool rpcErrorOccured(mtpRequestId requestId, const RPCFailHandlerPtr &onFail, const RPCError &err); // return true if need to clean request data
|
||||
inline bool rpcErrorOccured(mtpRequestId requestId, const RPCResponseHandler &handler, const RPCError &err) {
|
||||
return rpcErrorOccured(requestId, handler.onFail, err);
|
||||
@@ -64,6 +64,7 @@ namespace _mtp_internal {
|
||||
namespace MTP {
|
||||
|
||||
static const uint32 cfg = 1 * _mtp_internal::dcShift; // send(MTPhelp_GetConfig(), MTP::cfg + dc) - for dc enum
|
||||
static const uint32 lgt = 2 * _mtp_internal::dcShift; // send(MTPauth_LogOut(), MTP::lgt + dc) - for logout of guest dcs enum
|
||||
static const uint32 dld[MTPDownloadSessionsCount] = { // send(req, callbacks, MTP::dld[i] + dc) - for download
|
||||
0x10 * _mtp_internal::dcShift,
|
||||
0x11 * _mtp_internal::dcShift,
|
||||
@@ -89,13 +90,13 @@ namespace MTP {
|
||||
|
||||
int32 dcstate(int32 dc = 0);
|
||||
QString dctransport(int32 dc = 0);
|
||||
void initdc(int32 dc);
|
||||
|
||||
template <typename TRequest>
|
||||
inline mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
|
||||
MTProtoSessionPtr session = _mtp_internal::getSession(dc);
|
||||
if (!session) return 0;
|
||||
|
||||
return session->send(request, callbacks, msCanWait, true, !dc, after);
|
||||
if (MTProtoSessionPtr session = _mtp_internal::getSession(dc)) {
|
||||
return session->send(request, callbacks, msCanWait, true, !dc, after);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
template <typename TRequest>
|
||||
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
|
||||
@@ -139,6 +140,8 @@ namespace MTP {
|
||||
mtpKeysMap getKeys();
|
||||
void setKey(int32 dc, mtpAuthKeyPtr key);
|
||||
|
||||
QReadWriteLock *dcOptionsMutex();
|
||||
|
||||
};
|
||||
|
||||
#include "mtproto/mtpSessionImpl.h"
|
||||
|
||||
@@ -1114,6 +1114,7 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
|
||||
// createConn();
|
||||
|
||||
if (!dc) {
|
||||
QReadLocker lock(mtpDcOptionsMutex());
|
||||
const mtpDcOptions &options(cDcOptions());
|
||||
if (options.isEmpty()) {
|
||||
LOG(("MTP Error: connect failed, no DCs"));
|
||||
@@ -1713,6 +1714,8 @@ void MTProtoConnectionPrivate::retryByTimer() {
|
||||
}
|
||||
if (keyId == mtpAuthKey::RecreateKeyId) {
|
||||
if (sessionData->getKey()) {
|
||||
unlockKey();
|
||||
|
||||
QWriteLocker lock(sessionData->keyMutex());
|
||||
sessionData->owner()->destroyKey();
|
||||
}
|
||||
@@ -1738,31 +1741,34 @@ void MTProtoConnectionPrivate::socketStart(bool afterConfig) {
|
||||
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
|
||||
_pingSender.stop();
|
||||
|
||||
const mtpDcOption *dcOption = 0;
|
||||
const mtpDcOptions &options(cDcOptions());
|
||||
mtpDcOptions::const_iterator dcIndex = options.constFind(dc % _mtp_internal::dcShift);
|
||||
DEBUG_LOG(("MTP Info: connecting to DC %1..").arg(dc));
|
||||
if (dcIndex == options.cend()) {
|
||||
std::string ip;
|
||||
uint32 port = 0;
|
||||
{
|
||||
QReadLocker lock(mtpDcOptionsMutex());
|
||||
const mtpDcOptions &options(cDcOptions());
|
||||
mtpDcOptions::const_iterator dcIndex = options.constFind(dc % _mtp_internal::dcShift);
|
||||
DEBUG_LOG(("MTP Info: connecting to DC %1..").arg(dc));
|
||||
if (dcIndex != options.cend()) {
|
||||
ip = dcIndex->ip;
|
||||
port = dcIndex->port;
|
||||
}
|
||||
}
|
||||
if (!port || ip.empty()) {
|
||||
if (afterConfig) {
|
||||
LOG(("MTP Error: DC %1 options not found right after config load!").arg(dc));
|
||||
return restart();
|
||||
} else {
|
||||
DEBUG_LOG(("MTP Info: DC %1 options not found, waiting for config").arg(dc));
|
||||
connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
|
||||
mtpConfigLoader()->load();
|
||||
return;
|
||||
}
|
||||
DEBUG_LOG(("MTP Info: DC %1 options not found, waiting for config").arg(dc));
|
||||
connect(mtpConfigLoader(), SIGNAL(loaded()), this, SLOT(onConfigLoaded()));
|
||||
mtpConfigLoader()->load();
|
||||
return;
|
||||
}
|
||||
dcOption = &dcIndex.value();
|
||||
|
||||
const char *ip(dcOption->ip.c_str());
|
||||
uint32 port(dcOption->port);
|
||||
DEBUG_LOG(("MTP Info: socket connection to %1:%2..").arg(ip).arg(port));
|
||||
DEBUG_LOG(("MTP Info: socket connection to %1:%2..").arg(ip.c_str()).arg(port));
|
||||
|
||||
connect(conn, SIGNAL(connected()), this, SLOT(onConnected()));
|
||||
connect(conn, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
|
||||
conn->connectToServer(ip, port);
|
||||
conn->connectToServer(ip.c_str(), port);
|
||||
}
|
||||
|
||||
void MTProtoConnectionPrivate::restart(bool maybeBadKey) {
|
||||
@@ -2824,12 +2830,36 @@ void MTProtoConnectionPrivate::onConnected() {
|
||||
|
||||
TCP_LOG(("Connection Info: connection succeed."));
|
||||
|
||||
if (updateAuthKey()) {
|
||||
DEBUG_LOG(("MTP Info: returning from socketConnected.."));
|
||||
return;
|
||||
updateAuthKey();
|
||||
}
|
||||
|
||||
void MTProtoConnectionPrivate::updateAuthKey() {
|
||||
QReadLocker lockFinished(&sessionDataMutex);
|
||||
if (!sessionData || !conn) return;
|
||||
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoConnection updating key from MTProtoSession, dc %1").arg(dc));
|
||||
uint64 newKeyId = 0;
|
||||
{
|
||||
ReadLockerAttempt lock(sessionData->keyMutex());
|
||||
if (!lock) {
|
||||
DEBUG_LOG(("MTP Info: could not lock auth_key for read, waiting signal emit"));
|
||||
clearMessages();
|
||||
keyId = newKeyId;
|
||||
return; // some other connection is getting key
|
||||
}
|
||||
const mtpAuthKeyPtr &key(sessionData->getKey());
|
||||
newKeyId = key ? key->keyId() : 0;
|
||||
}
|
||||
if (keyId != newKeyId) {
|
||||
clearMessages();
|
||||
keyId = newKeyId;
|
||||
}
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoConnection update key from MTProtoSession, dc %1 result: %2").arg(dc).arg(mb(&keyId, sizeof(keyId)).str()));
|
||||
if (keyId) {
|
||||
return authKeyCreated();
|
||||
}
|
||||
|
||||
DEBUG_LOG(("MTP Info: will be creating auth_key"));
|
||||
DEBUG_LOG(("AuthKey Info: No key in updateAuthKey(), will be creating auth_key"));
|
||||
lockKey();
|
||||
|
||||
const mtpAuthKeyPtr &key(sessionData->getKey());
|
||||
@@ -2854,36 +2884,6 @@ void MTProtoConnectionPrivate::onConnected() {
|
||||
sendRequestNotSecure(req_pq);
|
||||
}
|
||||
|
||||
bool MTProtoConnectionPrivate::updateAuthKey() {
|
||||
QReadLocker lockFinished(&sessionDataMutex);
|
||||
if (!sessionData || !conn) return false;
|
||||
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoConnection updating key from MTProtoSession, dc %1").arg(dc));
|
||||
uint64 newKeyId = 0;
|
||||
{
|
||||
ReadLockerAttempt lock(sessionData->keyMutex());
|
||||
if (!lock) {
|
||||
DEBUG_LOG(("MTP Info: could not lock auth_key for read, waiting signal emit"));
|
||||
clearMessages();
|
||||
keyId = newKeyId;
|
||||
return true; // some other connection is getting key
|
||||
}
|
||||
const mtpAuthKeyPtr &key(sessionData->getKey());
|
||||
newKeyId = key ? key->keyId() : 0;
|
||||
}
|
||||
if (keyId != newKeyId) {
|
||||
clearMessages();
|
||||
keyId = newKeyId;
|
||||
}
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoConnection update key from MTProtoSession, dc %1 result: %2").arg(dc).arg(mb(&keyId, sizeof(keyId)).str()));
|
||||
if (keyId) {
|
||||
authKeyCreated();
|
||||
return true;
|
||||
}
|
||||
DEBUG_LOG(("AuthKey Info: Key update failed"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void MTProtoConnectionPrivate::clearMessages() {
|
||||
if (keyId && keyId != mtpAuthKey::RecreateKeyId && conn) {
|
||||
conn->received().clear();
|
||||
@@ -3481,7 +3481,14 @@ MTProtoConnectionPrivate::~MTProtoConnectionPrivate() {
|
||||
|
||||
void MTProtoConnectionPrivate::stop() {
|
||||
QWriteLocker lockFinished(&sessionDataMutex);
|
||||
sessionData = 0;
|
||||
if (sessionData) {
|
||||
if (myKeyLock) {
|
||||
sessionData->owner()->notifyKeyCreated(mtpAuthKeyPtr()); // release key lock, let someone else create it
|
||||
sessionData->keyMutex()->unlock();
|
||||
myKeyLock = false;
|
||||
}
|
||||
sessionData = 0;
|
||||
}
|
||||
}
|
||||
|
||||
MTProtoConnection::~MTProtoConnection() {
|
||||
|
||||
@@ -366,7 +366,7 @@ public slots:
|
||||
// Sessions signals, when we need to send something
|
||||
void tryToSend();
|
||||
|
||||
bool updateAuthKey();
|
||||
void updateAuthKey();
|
||||
|
||||
void onConfigLoaded();
|
||||
|
||||
|
||||
@@ -366,7 +366,7 @@ static const mtpTypeId mtpLayers[] = {
|
||||
mtpc_invokeWithLayer17,
|
||||
mtpc_invokeWithLayer18,
|
||||
}, mtpLayerMaxSingle = sizeof(mtpLayers) / sizeof(mtpLayers[0]);
|
||||
static const mtpPrime mtpCurrentLayer = 28;
|
||||
static const mtpPrime mtpCurrentLayer = 29;
|
||||
|
||||
template <typename bareT>
|
||||
class MTPBoxed : public bareT {
|
||||
|
||||
@@ -56,6 +56,20 @@ int32 mtpMainDC() {
|
||||
return mainDC;
|
||||
}
|
||||
|
||||
namespace {
|
||||
QMap<int32, mtpRequestId> logoutGuestMap; // dcWithShift to logout request id
|
||||
bool logoutDone(mtpRequestId req) {
|
||||
for (QMap<int32, mtpRequestId>::iterator i = logoutGuestMap.begin(); i != logoutGuestMap.end(); ++i) {
|
||||
if (i.value() == req) {
|
||||
MTP::killSession(i.key());
|
||||
logoutGuestMap.erase(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void mtpLogoutOtherDCs() {
|
||||
QList<int32> dcs;
|
||||
{
|
||||
@@ -64,7 +78,7 @@ void mtpLogoutOtherDCs() {
|
||||
}
|
||||
for (int32 i = 0, cnt = dcs.size(); i != cnt; ++i) {
|
||||
if (dcs[i] != MTP::maindc()) {
|
||||
MTP::send(MTPauth_LogOut(), RPCResponseHandler(), dcs[i]);
|
||||
logoutGuestMap.insert(MTP::lgt + dcs[i], MTP::send(MTPauth_LogOut(), rpcDone(&logoutDone), rpcFail(&logoutDone), MTP::lgt + dcs[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +168,11 @@ namespace {
|
||||
void mtpUpdateDcOptions(const QVector<MTPDcOption> &options) {
|
||||
QSet<int32> already, restart;
|
||||
{
|
||||
mtpDcOptions opts(cDcOptions());
|
||||
mtpDcOptions opts;
|
||||
{
|
||||
QReadLocker lock(mtpDcOptionsMutex());
|
||||
opts = cDcOptions();
|
||||
}
|
||||
for (QVector<MTPDcOption>::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
||||
const MTPDdcOption &optData(i->c_dcOption());
|
||||
if (already.constFind(optData.vid.v) == already.cend()) {
|
||||
@@ -168,16 +186,26 @@ void mtpUpdateDcOptions(const QVector<MTPDcOption> &options) {
|
||||
opts.insert(optData.vid.v, mtpDcOption(optData.vid.v, optData.vhostname.c_string().v, optData.vip_address.c_string().v, optData.vport.v));
|
||||
}
|
||||
}
|
||||
cSetDcOptions(opts);
|
||||
{
|
||||
QWriteLocker lock(mtpDcOptionsMutex());
|
||||
cSetDcOptions(opts);
|
||||
}
|
||||
}
|
||||
for (QSet<int32>::const_iterator i = restart.cbegin(), e = restart.cend(); i != e; ++i) {
|
||||
MTP::restart(*i);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
QReadWriteLock _dcOptionsMutex;
|
||||
}
|
||||
|
||||
QReadWriteLock *mtpDcOptionsMutex() {
|
||||
return &_dcOptionsMutex;
|
||||
}
|
||||
|
||||
MTProtoConfigLoader::MTProtoConfigLoader() : _enumCurrent(0), _enumRequest(0) {
|
||||
connect(&_enumDCTimer, SIGNAL(timeout()), this, SLOT(enumDC()));
|
||||
connect(this, SIGNAL(killCurrentSession(qint32,qint32)), this, SLOT(onKillCurrentSession(qint32,qint32)), Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void MTProtoConfigLoader::load() {
|
||||
@@ -189,23 +217,15 @@ void MTProtoConfigLoader::load() {
|
||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
||||
}
|
||||
|
||||
void MTProtoConfigLoader::onKillCurrentSession(qint32 request, qint32 current) {
|
||||
if (request == _enumRequest && current == _enumCurrent) {
|
||||
if (_enumRequest) {
|
||||
MTP::cancel(_enumRequest);
|
||||
_enumRequest = 0;
|
||||
}
|
||||
if (_enumCurrent) {
|
||||
MTP::killSession(MTP::cfg + _enumCurrent);
|
||||
_enumCurrent = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MTProtoConfigLoader::done() {
|
||||
_enumDCTimer.stop();
|
||||
if (_enumRequest || _enumCurrent) {
|
||||
emit killCurrentSession(_enumRequest, _enumCurrent);
|
||||
if (_enumRequest) {
|
||||
MTP::cancel(_enumRequest);
|
||||
_enumRequest = 0;
|
||||
}
|
||||
if (_enumCurrent) {
|
||||
MTP::killSession(MTP::cfg + _enumCurrent);
|
||||
_enumCurrent = 0;
|
||||
}
|
||||
emit loaded();
|
||||
}
|
||||
@@ -220,14 +240,16 @@ void MTProtoConfigLoader::enumDC() {
|
||||
} else {
|
||||
MTP::killSession(MTP::cfg + _enumCurrent);
|
||||
}
|
||||
const mtpDcOptions &options(cDcOptions());
|
||||
for (mtpDcOptions::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
||||
if (i.key() == _enumCurrent) {
|
||||
_enumCurrent = (++i == e) ? options.cbegin().key() : i.key();
|
||||
break;
|
||||
{
|
||||
QReadLocker lock(mtpDcOptionsMutex());
|
||||
const mtpDcOptions &options(cDcOptions());
|
||||
for (mtpDcOptions::const_iterator i = options.cbegin(), e = options.cend(); i != e; ++i) {
|
||||
if (i.key() == _enumCurrent) {
|
||||
_enumCurrent = (++i == e) ? options.cbegin().key() : i.key();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_enumRequest = MTP::send(MTPhelp_GetConfig(), rpcDone(configLoaded), rpcFail(configFailed), MTP::cfg + _enumCurrent);
|
||||
|
||||
_enumDCTimer.start(MTPEnumDCTimeout);
|
||||
|
||||
@@ -72,12 +72,10 @@ public:
|
||||
public slots:
|
||||
|
||||
void enumDC();
|
||||
void onKillCurrentSession(qint32 request, qint32 session);
|
||||
|
||||
signals:
|
||||
|
||||
void loaded();
|
||||
void killCurrentSession(qint32 request, qint32 session);
|
||||
|
||||
private:
|
||||
|
||||
@@ -104,3 +102,4 @@ mtpKeysMap mtpGetKeys();
|
||||
void mtpSetKey(int32 dc, mtpAuthKeyPtr key);
|
||||
|
||||
void mtpUpdateDcOptions(const QVector<MTPDcOption> &options);
|
||||
QReadWriteLock *mtpDcOptionsMutex();
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace {
|
||||
LoaderQueues queues;
|
||||
}
|
||||
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size) : prev(0), next(0),
|
||||
mtpFileLoader::mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const uint64 &secret, int32 size) : prev(0), next(0),
|
||||
priority(0), inQueue(false), complete(false), triedLocal(false), skippedBytes(0), nextRequestOffset(0), lastComplete(false),
|
||||
dc(dc), locationType(0), volume(volume), local(local), secret(secret),
|
||||
id(0), access(0), fileIsOpen(false), size(size), type(mtpc_storage_fileUnknown) {
|
||||
@@ -247,23 +247,24 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
|
||||
psPostprocessFile(QFileInfo(file).absoluteFilePath());
|
||||
}
|
||||
removeFromQueue();
|
||||
App::wnd()->update();
|
||||
App::wnd()->notifyUpdateAllPhotos();
|
||||
|
||||
emit App::wnd()->imageLoaded();
|
||||
|
||||
if (!queue->queries) {
|
||||
App::app()->killDownloadSessionsStart(dc);
|
||||
}
|
||||
|
||||
if (!locationType && triedLocal && (fname.isEmpty() || duplicateInData)) {
|
||||
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(type, data));
|
||||
Local::writeImage(storageKey(dc, volume, local), StorageImageSaved(mtpToStorageType(type), data));
|
||||
} else if (locationType && triedLocal) {
|
||||
if (!fname.isEmpty()) {
|
||||
Local::writeFileLocation(mediaKey(locationType, dc, id), FileLocation(type, fname));
|
||||
Local::writeFileLocation(mediaKey(mtpToLocationType(locationType), dc, id), FileLocation(mtpToStorageType(type), fname));
|
||||
}
|
||||
if (duplicateInData) {
|
||||
if (locationType == mtpc_inputDocumentFileLocation) {
|
||||
Local::writeSticker(mediaKey(locationType, dc, id), data);
|
||||
Local::writeStickerImage(mediaKey(mtpToLocationType(locationType), dc, id), data);
|
||||
} else if (locationType == mtpc_inputAudioFileLocation) {
|
||||
Local::writeAudio(mediaKey(locationType, dc, id), data);
|
||||
Local::writeAudio(mediaKey(mtpToLocationType(locationType), dc, id), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -308,9 +309,9 @@ void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
if (!locationType) {
|
||||
triedLocal = true;
|
||||
StorageImageSaved cached = Local::readImage(storageKey(dc, volume, local));
|
||||
if (cached.type != mtpc_storage_fileUnknown) {
|
||||
if (cached.type != StorageFileUnknown) {
|
||||
data = cached.data;
|
||||
type = cached.type;
|
||||
type = mtpFromStorageType(cached.type);
|
||||
}
|
||||
} else if (locationType) {
|
||||
if (!fname.isEmpty()) {
|
||||
@@ -319,11 +320,11 @@ void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
if (duplicateInData) {
|
||||
if (locationType == mtpc_inputDocumentFileLocation) {
|
||||
triedLocal = true;
|
||||
data = Local::readSticker(mediaKey(locationType, dc, id));
|
||||
data = Local::readStickerImage(mediaKey(mtpToLocationType(locationType), dc, id));
|
||||
if (!data.isEmpty()) type = mtpc_storage_filePartial;
|
||||
} else if (locationType == mtpc_inputAudioFileLocation) {
|
||||
triedLocal = true;
|
||||
data = Local::readAudio(mediaKey(locationType, dc, id));
|
||||
data = Local::readAudio(mediaKey(mtpToLocationType(locationType), dc, id));
|
||||
if (!data.isEmpty()) type = mtpc_storage_filePartial;
|
||||
}
|
||||
}
|
||||
@@ -344,8 +345,7 @@ void mtpFileLoader::start(bool loadFirst, bool prior) {
|
||||
fileIsOpen = false;
|
||||
psPostprocessFile(QFileInfo(file).absoluteFilePath());
|
||||
}
|
||||
App::wnd()->update();
|
||||
App::wnd()->notifyUpdateAllPhotos();
|
||||
emit App::wnd()->imageLoaded();
|
||||
emit progress(this);
|
||||
return loadNext();
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ class mtpFileLoader : public QObject, public RPCSender {
|
||||
|
||||
public:
|
||||
|
||||
mtpFileLoader(int32 dc, const int64 &volume, int32 local, const int64 &secret, int32 size = 0);
|
||||
mtpFileLoader(int32 dc, const uint64 &volume, int32 local, const uint64 &secret, int32 size = 0);
|
||||
mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size);
|
||||
mtpFileLoader(int32 dc, const uint64 &id, const uint64 &access, mtpTypeId locType, const QString &to, int32 size, bool todata);
|
||||
bool done() const;
|
||||
@@ -82,9 +82,9 @@ private:
|
||||
int32 dc;
|
||||
mtpTypeId locationType; // 0 or mtpc_inputVideoFileLocation / mtpc_inputAudioFileLocation / mtpc_inputDocumentFileLocation
|
||||
|
||||
int64 volume; // for photo locations
|
||||
uint64 volume; // for photo locations
|
||||
int32 local;
|
||||
int64 secret;
|
||||
uint64 secret;
|
||||
|
||||
uint64 id; // for other locations
|
||||
uint64 access;
|
||||
|
||||
@@ -3926,6 +3926,7 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" alt: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
@@ -4017,7 +4018,8 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
||||
switch (stage) {
|
||||
case 0: to.add(" hash: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" packs: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" documents: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" sets: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" documents: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
@@ -4289,6 +4291,68 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_inputStickerSetEmpty:
|
||||
to.add("{ inputStickerSetEmpty }"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back();
|
||||
break;
|
||||
|
||||
case mtpc_inputStickerSetID:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ inputStickerSetID");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_inputStickerSetShortName:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ inputStickerSetShortName");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_stickerSet:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ stickerSet");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" id: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" access_hash: "); ++stages.back(); types.push_back(mtpc_long); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" title: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 3: to.add(" short_name: "); ++stages.back(); types.push_back(mtpc_string); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_messages_stickerSet:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_stickerSet");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" set: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 1: to.add(" packs: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
case 2: to.add(" documents: "); ++stages.back(); types.push_back(00); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_req_pq:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
@@ -4779,6 +4843,32 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_messages_installStickerSet:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_installStickerSet");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_messages_uninstallStickerSet:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_uninstallStickerSet");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_invokeAfterMsg:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
@@ -6027,6 +6117,19 @@ void mtpTextSerializeType(MTPStringLogger &to, const mtpPrime *&from, const mtpP
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_messages_getStickerSet:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
} else {
|
||||
to.add("{ messages_getStickerSet");
|
||||
to.add("\n").addSpaces(lev);
|
||||
}
|
||||
switch (stage) {
|
||||
case 0: to.add(" stickerset: "); ++stages.back(); types.push_back(0); vtypes.push_back(0); stages.push_back(0); flags.push_back(0); break;
|
||||
default: to.add("}"); types.pop_back(); vtypes.pop_back(); stages.pop_back(); flags.pop_back(); break;
|
||||
}
|
||||
break;
|
||||
|
||||
case mtpc_rpc_result:
|
||||
if (stage) {
|
||||
to.add(",\n").addSpaces(lev);
|
||||
|
||||
@@ -340,7 +340,7 @@ enum {
|
||||
mtpc_updateUserPhone = 0x12b9417b,
|
||||
mtpc_documentAttributeImageSize = 0x6c37c15c,
|
||||
mtpc_documentAttributeAnimated = 0x11b58939,
|
||||
mtpc_documentAttributeSticker = 0x994c9882,
|
||||
mtpc_documentAttributeSticker = 0x3a556302,
|
||||
mtpc_documentAttributeVideo = 0x5910cccb,
|
||||
mtpc_documentAttributeAudio = 0x51448e5,
|
||||
mtpc_documentAttributeFilename = 0x15590068,
|
||||
@@ -348,7 +348,7 @@ enum {
|
||||
mtpc_messages_stickers = 0x8a8ecd32,
|
||||
mtpc_stickerPack = 0x12b299d4,
|
||||
mtpc_messages_allStickersNotModified = 0xe86602c3,
|
||||
mtpc_messages_allStickers = 0xdcef3102,
|
||||
mtpc_messages_allStickers = 0x5ce352ec,
|
||||
mtpc_disabledFeature = 0xae636f24,
|
||||
mtpc_updateReadHistoryInbox = 0x9961fd5c,
|
||||
mtpc_updateReadHistoryOutbox = 0x2f2f21bf,
|
||||
@@ -378,6 +378,11 @@ enum {
|
||||
mtpc_chatInvite = 0xce917dcd,
|
||||
mtpc_messageActionChatJoinedByLink = 0xf89cf5e8,
|
||||
mtpc_updateReadMessagesContents = 0x68c13933,
|
||||
mtpc_inputStickerSetEmpty = 0xffb62b95,
|
||||
mtpc_inputStickerSetID = 0x9de7a269,
|
||||
mtpc_inputStickerSetShortName = 0x861cc8a0,
|
||||
mtpc_stickerSet = 0xa7a43b17,
|
||||
mtpc_messages_stickerSet = 0xb60a24a6,
|
||||
mtpc_invokeAfterMsg = 0xcb9f372d,
|
||||
mtpc_invokeAfterMsgs = 0x3dc4b4f0,
|
||||
mtpc_auth_checkPhone = 0x6fe51dfb,
|
||||
@@ -500,7 +505,10 @@ enum {
|
||||
mtpc_invokeWithoutUpdates = 0xbf9459b7,
|
||||
mtpc_messages_exportChatInvite = 0x7d885289,
|
||||
mtpc_messages_checkChatInvite = 0x3eadb1bb,
|
||||
mtpc_messages_importChatInvite = 0x6c50051c
|
||||
mtpc_messages_importChatInvite = 0x6c50051c,
|
||||
mtpc_messages_getStickerSet = 0x2619a90e,
|
||||
mtpc_messages_installStickerSet = 0xefbbfae9,
|
||||
mtpc_messages_uninstallStickerSet = 0xf96e55de
|
||||
};
|
||||
|
||||
// Type forward declarations
|
||||
@@ -1045,6 +1053,16 @@ class MTPchatInvite;
|
||||
class MTPDchatInviteAlready;
|
||||
class MTPDchatInvite;
|
||||
|
||||
class MTPinputStickerSet;
|
||||
class MTPDinputStickerSetID;
|
||||
class MTPDinputStickerSetShortName;
|
||||
|
||||
class MTPstickerSet;
|
||||
class MTPDstickerSet;
|
||||
|
||||
class MTPmessages_stickerSet;
|
||||
class MTPDmessages_stickerSet;
|
||||
|
||||
|
||||
// Boxed types definitions
|
||||
typedef MTPBoxed<MTPresPQ> MTPResPQ;
|
||||
@@ -1188,6 +1206,9 @@ typedef MTPBoxed<MTPauth_passwordRecovery> MTPauth_PasswordRecovery;
|
||||
typedef MTPBoxed<MTPreceivedNotifyMessage> MTPReceivedNotifyMessage;
|
||||
typedef MTPBoxed<MTPexportedChatInvite> MTPExportedChatInvite;
|
||||
typedef MTPBoxed<MTPchatInvite> MTPChatInvite;
|
||||
typedef MTPBoxed<MTPinputStickerSet> MTPInputStickerSet;
|
||||
typedef MTPBoxed<MTPstickerSet> MTPStickerSet;
|
||||
typedef MTPBoxed<MTPmessages_stickerSet> MTPmessages_StickerSet;
|
||||
|
||||
// Type classes definitions
|
||||
|
||||
@@ -7153,7 +7174,7 @@ private:
|
||||
|
||||
friend MTPdocumentAttribute MTP_documentAttributeImageSize(MTPint _w, MTPint _h);
|
||||
friend MTPdocumentAttribute MTP_documentAttributeAnimated();
|
||||
friend MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt);
|
||||
friend MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt, const MTPInputStickerSet &_stickerset);
|
||||
friend MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h);
|
||||
friend MTPdocumentAttribute MTP_documentAttributeAudio(MTPint _duration);
|
||||
friend MTPdocumentAttribute MTP_documentAttributeFilename(const MTPstring &_file_name);
|
||||
@@ -7263,7 +7284,7 @@ private:
|
||||
explicit MTPmessages_allStickers(MTPDmessages_allStickers *_data);
|
||||
|
||||
friend MTPmessages_allStickers MTP_messages_allStickersNotModified();
|
||||
friend MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents);
|
||||
friend MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents);
|
||||
|
||||
mtpTypeId _type;
|
||||
};
|
||||
@@ -7749,6 +7770,120 @@ private:
|
||||
};
|
||||
typedef MTPBoxed<MTPchatInvite> MTPChatInvite;
|
||||
|
||||
class MTPinputStickerSet : private mtpDataOwner {
|
||||
public:
|
||||
MTPinputStickerSet() : mtpDataOwner(0), _type(0) {
|
||||
}
|
||||
MTPinputStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) : mtpDataOwner(0), _type(0) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
|
||||
MTPDinputStickerSetID &_inputStickerSetID() {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
if (_type != mtpc_inputStickerSetID) throw mtpErrorWrongTypeId(_type, mtpc_inputStickerSetID);
|
||||
split();
|
||||
return *(MTPDinputStickerSetID*)data;
|
||||
}
|
||||
const MTPDinputStickerSetID &c_inputStickerSetID() const {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
if (_type != mtpc_inputStickerSetID) throw mtpErrorWrongTypeId(_type, mtpc_inputStickerSetID);
|
||||
return *(const MTPDinputStickerSetID*)data;
|
||||
}
|
||||
|
||||
MTPDinputStickerSetShortName &_inputStickerSetShortName() {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
if (_type != mtpc_inputStickerSetShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputStickerSetShortName);
|
||||
split();
|
||||
return *(MTPDinputStickerSetShortName*)data;
|
||||
}
|
||||
const MTPDinputStickerSetShortName &c_inputStickerSetShortName() const {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
if (_type != mtpc_inputStickerSetShortName) throw mtpErrorWrongTypeId(_type, mtpc_inputStickerSetShortName);
|
||||
return *(const MTPDinputStickerSetShortName*)data;
|
||||
}
|
||||
|
||||
uint32 innerLength() const;
|
||||
mtpTypeId type() const;
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons);
|
||||
void write(mtpBuffer &to) const;
|
||||
|
||||
typedef void ResponseType;
|
||||
|
||||
private:
|
||||
explicit MTPinputStickerSet(mtpTypeId type);
|
||||
explicit MTPinputStickerSet(MTPDinputStickerSetID *_data);
|
||||
explicit MTPinputStickerSet(MTPDinputStickerSetShortName *_data);
|
||||
|
||||
friend MTPinputStickerSet MTP_inputStickerSetEmpty();
|
||||
friend MTPinputStickerSet MTP_inputStickerSetID(const MTPlong &_id, const MTPlong &_access_hash);
|
||||
friend MTPinputStickerSet MTP_inputStickerSetShortName(const MTPstring &_short_name);
|
||||
|
||||
mtpTypeId _type;
|
||||
};
|
||||
typedef MTPBoxed<MTPinputStickerSet> MTPInputStickerSet;
|
||||
|
||||
class MTPstickerSet : private mtpDataOwner {
|
||||
public:
|
||||
MTPstickerSet();
|
||||
MTPstickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerSet) : mtpDataOwner(0) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
|
||||
MTPDstickerSet &_stickerSet() {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
split();
|
||||
return *(MTPDstickerSet*)data;
|
||||
}
|
||||
const MTPDstickerSet &c_stickerSet() const {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
return *(const MTPDstickerSet*)data;
|
||||
}
|
||||
|
||||
uint32 innerLength() const;
|
||||
mtpTypeId type() const;
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_stickerSet);
|
||||
void write(mtpBuffer &to) const;
|
||||
|
||||
typedef void ResponseType;
|
||||
|
||||
private:
|
||||
explicit MTPstickerSet(MTPDstickerSet *_data);
|
||||
|
||||
friend MTPstickerSet MTP_stickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name);
|
||||
};
|
||||
typedef MTPBoxed<MTPstickerSet> MTPStickerSet;
|
||||
|
||||
class MTPmessages_stickerSet : private mtpDataOwner {
|
||||
public:
|
||||
MTPmessages_stickerSet();
|
||||
MTPmessages_stickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_stickerSet) : mtpDataOwner(0) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
|
||||
MTPDmessages_stickerSet &_messages_stickerSet() {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
split();
|
||||
return *(MTPDmessages_stickerSet*)data;
|
||||
}
|
||||
const MTPDmessages_stickerSet &c_messages_stickerSet() const {
|
||||
if (!data) throw mtpErrorUninitialized();
|
||||
return *(const MTPDmessages_stickerSet*)data;
|
||||
}
|
||||
|
||||
uint32 innerLength() const;
|
||||
mtpTypeId type() const;
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_stickerSet);
|
||||
void write(mtpBuffer &to) const;
|
||||
|
||||
typedef void ResponseType;
|
||||
|
||||
private:
|
||||
explicit MTPmessages_stickerSet(MTPDmessages_stickerSet *_data);
|
||||
|
||||
friend MTPmessages_stickerSet MTP_messages_stickerSet(const MTPStickerSet &_set, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents);
|
||||
};
|
||||
typedef MTPBoxed<MTPmessages_stickerSet> MTPmessages_StickerSet;
|
||||
|
||||
// Type constructors with data
|
||||
|
||||
class MTPDresPQ : public mtpDataImpl<MTPDresPQ> {
|
||||
@@ -8777,13 +8912,13 @@ public:
|
||||
|
||||
enum {
|
||||
flag_fwd_from_id = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
flag_fwd_date = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
};
|
||||
|
||||
bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
};
|
||||
|
||||
class MTPDmessageService : public mtpDataImpl<MTPDmessageService> {
|
||||
@@ -9886,13 +10021,13 @@ public:
|
||||
|
||||
enum {
|
||||
flag_fwd_from_id = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
flag_fwd_date = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
};
|
||||
|
||||
bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
};
|
||||
|
||||
class MTPDupdateShortChatMessage : public mtpDataImpl<MTPDupdateShortChatMessage> {
|
||||
@@ -9916,13 +10051,13 @@ public:
|
||||
|
||||
enum {
|
||||
flag_fwd_from_id = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
flag_fwd_date = (1 << 2),
|
||||
flag_reply_to_msg_id = (1 << 3),
|
||||
};
|
||||
|
||||
bool has_fwd_from_id() const { return vflags.v & flag_fwd_from_id; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
bool has_fwd_date() const { return vflags.v & flag_fwd_date; }
|
||||
bool has_reply_to_msg_id() const { return vflags.v & flag_reply_to_msg_id; }
|
||||
};
|
||||
|
||||
class MTPDupdateShort : public mtpDataImpl<MTPDupdateShort> {
|
||||
@@ -10630,10 +10765,11 @@ class MTPDdocumentAttributeSticker : public mtpDataImpl<MTPDdocumentAttributeSti
|
||||
public:
|
||||
MTPDdocumentAttributeSticker() {
|
||||
}
|
||||
MTPDdocumentAttributeSticker(const MTPstring &_alt) : valt(_alt) {
|
||||
MTPDdocumentAttributeSticker(const MTPstring &_alt, const MTPInputStickerSet &_stickerset) : valt(_alt), vstickerset(_stickerset) {
|
||||
}
|
||||
|
||||
MTPstring valt;
|
||||
MTPInputStickerSet vstickerset;
|
||||
};
|
||||
|
||||
class MTPDdocumentAttributeVideo : public mtpDataImpl<MTPDdocumentAttributeVideo> {
|
||||
@@ -10694,11 +10830,12 @@ class MTPDmessages_allStickers : public mtpDataImpl<MTPDmessages_allStickers> {
|
||||
public:
|
||||
MTPDmessages_allStickers() {
|
||||
}
|
||||
MTPDmessages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) : vhash(_hash), vpacks(_packs), vdocuments(_documents) {
|
||||
MTPDmessages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents) : vhash(_hash), vpacks(_packs), vsets(_sets), vdocuments(_documents) {
|
||||
}
|
||||
|
||||
MTPstring vhash;
|
||||
MTPVector<MTPStickerPack> vpacks;
|
||||
MTPVector<MTPStickerSet> vsets;
|
||||
MTPVector<MTPDocument> vdocuments;
|
||||
};
|
||||
|
||||
@@ -10769,30 +10906,30 @@ public:
|
||||
MTPstring vauthor;
|
||||
|
||||
enum {
|
||||
flag_photo = (1 << 4),
|
||||
flag_embed_type = (1 << 5),
|
||||
flag_author = (1 << 8),
|
||||
flag_embed_width = (1 << 6),
|
||||
flag_type = (1 << 0),
|
||||
flag_duration = (1 << 7),
|
||||
flag_embed_height = (1 << 6),
|
||||
flag_description = (1 << 3),
|
||||
flag_site_name = (1 << 1),
|
||||
flag_title = (1 << 2),
|
||||
flag_description = (1 << 3),
|
||||
flag_photo = (1 << 4),
|
||||
flag_embed_url = (1 << 5),
|
||||
flag_embed_type = (1 << 5),
|
||||
flag_embed_width = (1 << 6),
|
||||
flag_embed_height = (1 << 6),
|
||||
flag_duration = (1 << 7),
|
||||
flag_author = (1 << 8),
|
||||
};
|
||||
|
||||
bool has_photo() const { return vflags.v & flag_photo; }
|
||||
bool has_embed_type() const { return vflags.v & flag_embed_type; }
|
||||
bool has_author() const { return vflags.v & flag_author; }
|
||||
bool has_embed_width() const { return vflags.v & flag_embed_width; }
|
||||
bool has_type() const { return vflags.v & flag_type; }
|
||||
bool has_duration() const { return vflags.v & flag_duration; }
|
||||
bool has_embed_height() const { return vflags.v & flag_embed_height; }
|
||||
bool has_description() const { return vflags.v & flag_description; }
|
||||
bool has_site_name() const { return vflags.v & flag_site_name; }
|
||||
bool has_title() const { return vflags.v & flag_title; }
|
||||
bool has_description() const { return vflags.v & flag_description; }
|
||||
bool has_photo() const { return vflags.v & flag_photo; }
|
||||
bool has_embed_url() const { return vflags.v & flag_embed_url; }
|
||||
bool has_embed_type() const { return vflags.v & flag_embed_type; }
|
||||
bool has_embed_width() const { return vflags.v & flag_embed_width; }
|
||||
bool has_embed_height() const { return vflags.v & flag_embed_height; }
|
||||
bool has_duration() const { return vflags.v & flag_duration; }
|
||||
bool has_author() const { return vflags.v & flag_author; }
|
||||
};
|
||||
|
||||
class MTPDauthorization : public mtpDataImpl<MTPDauthorization> {
|
||||
@@ -10877,15 +11014,15 @@ public:
|
||||
|
||||
enum {
|
||||
flag_new_salt = (1 << 0),
|
||||
flag_email = (1 << 1),
|
||||
flag_new_password_hash = (1 << 0),
|
||||
flag_hint = (1 << 0),
|
||||
flag_email = (1 << 1),
|
||||
};
|
||||
|
||||
bool has_new_salt() const { return vflags.v & flag_new_salt; }
|
||||
bool has_email() const { return vflags.v & flag_email; }
|
||||
bool has_new_password_hash() const { return vflags.v & flag_new_password_hash; }
|
||||
bool has_hint() const { return vflags.v & flag_hint; }
|
||||
bool has_email() const { return vflags.v & flag_email; }
|
||||
};
|
||||
|
||||
class MTPDauth_passwordRecovery : public mtpDataImpl<MTPDauth_passwordRecovery> {
|
||||
@@ -10939,6 +11076,52 @@ public:
|
||||
MTPstring vtitle;
|
||||
};
|
||||
|
||||
class MTPDinputStickerSetID : public mtpDataImpl<MTPDinputStickerSetID> {
|
||||
public:
|
||||
MTPDinputStickerSetID() {
|
||||
}
|
||||
MTPDinputStickerSetID(const MTPlong &_id, const MTPlong &_access_hash) : vid(_id), vaccess_hash(_access_hash) {
|
||||
}
|
||||
|
||||
MTPlong vid;
|
||||
MTPlong vaccess_hash;
|
||||
};
|
||||
|
||||
class MTPDinputStickerSetShortName : public mtpDataImpl<MTPDinputStickerSetShortName> {
|
||||
public:
|
||||
MTPDinputStickerSetShortName() {
|
||||
}
|
||||
MTPDinputStickerSetShortName(const MTPstring &_short_name) : vshort_name(_short_name) {
|
||||
}
|
||||
|
||||
MTPstring vshort_name;
|
||||
};
|
||||
|
||||
class MTPDstickerSet : public mtpDataImpl<MTPDstickerSet> {
|
||||
public:
|
||||
MTPDstickerSet() {
|
||||
}
|
||||
MTPDstickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name) : vid(_id), vaccess_hash(_access_hash), vtitle(_title), vshort_name(_short_name) {
|
||||
}
|
||||
|
||||
MTPlong vid;
|
||||
MTPlong vaccess_hash;
|
||||
MTPstring vtitle;
|
||||
MTPstring vshort_name;
|
||||
};
|
||||
|
||||
class MTPDmessages_stickerSet : public mtpDataImpl<MTPDmessages_stickerSet> {
|
||||
public:
|
||||
MTPDmessages_stickerSet() {
|
||||
}
|
||||
MTPDmessages_stickerSet(const MTPStickerSet &_set, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) : vset(_set), vpacks(_packs), vdocuments(_documents) {
|
||||
}
|
||||
|
||||
MTPStickerSet vset;
|
||||
MTPVector<MTPStickerPack> vpacks;
|
||||
MTPVector<MTPDocument> vdocuments;
|
||||
};
|
||||
|
||||
// RPC methods
|
||||
|
||||
class MTPreq_pq { // RPC method 'req_pq'
|
||||
@@ -16433,6 +16616,123 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class MTPmessages_getStickerSet { // RPC method 'messages.getStickerSet'
|
||||
public:
|
||||
MTPInputStickerSet vstickerset;
|
||||
|
||||
MTPmessages_getStickerSet() {
|
||||
}
|
||||
MTPmessages_getStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getStickerSet) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
MTPmessages_getStickerSet(const MTPInputStickerSet &_stickerset) : vstickerset(_stickerset) {
|
||||
}
|
||||
|
||||
uint32 innerLength() const {
|
||||
return vstickerset.innerLength();
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
return mtpc_messages_getStickerSet;
|
||||
}
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_getStickerSet) {
|
||||
vstickerset.read(from, end);
|
||||
}
|
||||
void write(mtpBuffer &to) const {
|
||||
vstickerset.write(to);
|
||||
}
|
||||
|
||||
typedef MTPmessages_StickerSet ResponseType;
|
||||
};
|
||||
class MTPmessages_GetStickerSet : public MTPBoxed<MTPmessages_getStickerSet> {
|
||||
public:
|
||||
MTPmessages_GetStickerSet() {
|
||||
}
|
||||
MTPmessages_GetStickerSet(const MTPmessages_getStickerSet &v) : MTPBoxed<MTPmessages_getStickerSet>(v) {
|
||||
}
|
||||
MTPmessages_GetStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_getStickerSet>(from, end, cons) {
|
||||
}
|
||||
MTPmessages_GetStickerSet(const MTPInputStickerSet &_stickerset) : MTPBoxed<MTPmessages_getStickerSet>(MTPmessages_getStickerSet(_stickerset)) {
|
||||
}
|
||||
};
|
||||
|
||||
class MTPmessages_installStickerSet { // RPC method 'messages.installStickerSet'
|
||||
public:
|
||||
MTPInputStickerSet vstickerset;
|
||||
|
||||
MTPmessages_installStickerSet() {
|
||||
}
|
||||
MTPmessages_installStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
MTPmessages_installStickerSet(const MTPInputStickerSet &_stickerset) : vstickerset(_stickerset) {
|
||||
}
|
||||
|
||||
uint32 innerLength() const {
|
||||
return vstickerset.innerLength();
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
return mtpc_messages_installStickerSet;
|
||||
}
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_installStickerSet) {
|
||||
vstickerset.read(from, end);
|
||||
}
|
||||
void write(mtpBuffer &to) const {
|
||||
vstickerset.write(to);
|
||||
}
|
||||
|
||||
typedef MTPBool ResponseType;
|
||||
};
|
||||
class MTPmessages_InstallStickerSet : public MTPBoxed<MTPmessages_installStickerSet> {
|
||||
public:
|
||||
MTPmessages_InstallStickerSet() {
|
||||
}
|
||||
MTPmessages_InstallStickerSet(const MTPmessages_installStickerSet &v) : MTPBoxed<MTPmessages_installStickerSet>(v) {
|
||||
}
|
||||
MTPmessages_InstallStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_installStickerSet>(from, end, cons) {
|
||||
}
|
||||
MTPmessages_InstallStickerSet(const MTPInputStickerSet &_stickerset) : MTPBoxed<MTPmessages_installStickerSet>(MTPmessages_installStickerSet(_stickerset)) {
|
||||
}
|
||||
};
|
||||
|
||||
class MTPmessages_uninstallStickerSet { // RPC method 'messages.uninstallStickerSet'
|
||||
public:
|
||||
MTPInputStickerSet vstickerset;
|
||||
|
||||
MTPmessages_uninstallStickerSet() {
|
||||
}
|
||||
MTPmessages_uninstallStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_uninstallStickerSet) {
|
||||
read(from, end, cons);
|
||||
}
|
||||
MTPmessages_uninstallStickerSet(const MTPInputStickerSet &_stickerset) : vstickerset(_stickerset) {
|
||||
}
|
||||
|
||||
uint32 innerLength() const {
|
||||
return vstickerset.innerLength();
|
||||
}
|
||||
mtpTypeId type() const {
|
||||
return mtpc_messages_uninstallStickerSet;
|
||||
}
|
||||
void read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = mtpc_messages_uninstallStickerSet) {
|
||||
vstickerset.read(from, end);
|
||||
}
|
||||
void write(mtpBuffer &to) const {
|
||||
vstickerset.write(to);
|
||||
}
|
||||
|
||||
typedef MTPBool ResponseType;
|
||||
};
|
||||
class MTPmessages_UninstallStickerSet : public MTPBoxed<MTPmessages_uninstallStickerSet> {
|
||||
public:
|
||||
MTPmessages_UninstallStickerSet() {
|
||||
}
|
||||
MTPmessages_UninstallStickerSet(const MTPmessages_uninstallStickerSet &v) : MTPBoxed<MTPmessages_uninstallStickerSet>(v) {
|
||||
}
|
||||
MTPmessages_UninstallStickerSet(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons = 0) : MTPBoxed<MTPmessages_uninstallStickerSet>(from, end, cons) {
|
||||
}
|
||||
MTPmessages_UninstallStickerSet(const MTPInputStickerSet &_stickerset) : MTPBoxed<MTPmessages_uninstallStickerSet>(MTPmessages_uninstallStickerSet(_stickerset)) {
|
||||
}
|
||||
};
|
||||
|
||||
// Inline methods definition
|
||||
|
||||
inline MTPresPQ::MTPresPQ() : mtpDataOwner(new MTPDresPQ()) {
|
||||
@@ -24350,7 +24650,7 @@ inline uint32 MTPdocumentAttribute::innerLength() const {
|
||||
}
|
||||
case mtpc_documentAttributeSticker: {
|
||||
const MTPDdocumentAttributeSticker &v(c_documentAttributeSticker());
|
||||
return v.valt.innerLength();
|
||||
return v.valt.innerLength() + v.vstickerset.innerLength();
|
||||
}
|
||||
case mtpc_documentAttributeVideo: {
|
||||
const MTPDdocumentAttributeVideo &v(c_documentAttributeVideo());
|
||||
@@ -24385,6 +24685,7 @@ inline void MTPdocumentAttribute::read(const mtpPrime *&from, const mtpPrime *en
|
||||
if (!data) setData(new MTPDdocumentAttributeSticker());
|
||||
MTPDdocumentAttributeSticker &v(_documentAttributeSticker());
|
||||
v.valt.read(from, end);
|
||||
v.vstickerset.read(from, end);
|
||||
} break;
|
||||
case mtpc_documentAttributeVideo: _type = cons; {
|
||||
if (!data) setData(new MTPDdocumentAttributeVideo());
|
||||
@@ -24416,6 +24717,7 @@ inline void MTPdocumentAttribute::write(mtpBuffer &to) const {
|
||||
case mtpc_documentAttributeSticker: {
|
||||
const MTPDdocumentAttributeSticker &v(c_documentAttributeSticker());
|
||||
v.valt.write(to);
|
||||
v.vstickerset.write(to);
|
||||
} break;
|
||||
case mtpc_documentAttributeVideo: {
|
||||
const MTPDdocumentAttributeVideo &v(c_documentAttributeVideo());
|
||||
@@ -24460,8 +24762,8 @@ inline MTPdocumentAttribute MTP_documentAttributeImageSize(MTPint _w, MTPint _h)
|
||||
inline MTPdocumentAttribute MTP_documentAttributeAnimated() {
|
||||
return MTPdocumentAttribute(mtpc_documentAttributeAnimated);
|
||||
}
|
||||
inline MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt) {
|
||||
return MTPdocumentAttribute(new MTPDdocumentAttributeSticker(_alt));
|
||||
inline MTPdocumentAttribute MTP_documentAttributeSticker(const MTPstring &_alt, const MTPInputStickerSet &_stickerset) {
|
||||
return MTPdocumentAttribute(new MTPDdocumentAttributeSticker(_alt, _stickerset));
|
||||
}
|
||||
inline MTPdocumentAttribute MTP_documentAttributeVideo(MTPint _duration, MTPint _w, MTPint _h) {
|
||||
return MTPdocumentAttribute(new MTPDdocumentAttributeVideo(_duration, _w, _h));
|
||||
@@ -24557,7 +24859,7 @@ inline uint32 MTPmessages_allStickers::innerLength() const {
|
||||
switch (_type) {
|
||||
case mtpc_messages_allStickers: {
|
||||
const MTPDmessages_allStickers &v(c_messages_allStickers());
|
||||
return v.vhash.innerLength() + v.vpacks.innerLength() + v.vdocuments.innerLength();
|
||||
return v.vhash.innerLength() + v.vpacks.innerLength() + v.vsets.innerLength() + v.vdocuments.innerLength();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
@@ -24575,6 +24877,7 @@ inline void MTPmessages_allStickers::read(const mtpPrime *&from, const mtpPrime
|
||||
MTPDmessages_allStickers &v(_messages_allStickers());
|
||||
v.vhash.read(from, end);
|
||||
v.vpacks.read(from, end);
|
||||
v.vsets.read(from, end);
|
||||
v.vdocuments.read(from, end);
|
||||
} break;
|
||||
default: throw mtpErrorUnexpected(cons, "MTPmessages_allStickers");
|
||||
@@ -24586,6 +24889,7 @@ inline void MTPmessages_allStickers::write(mtpBuffer &to) const {
|
||||
const MTPDmessages_allStickers &v(c_messages_allStickers());
|
||||
v.vhash.write(to);
|
||||
v.vpacks.write(to);
|
||||
v.vsets.write(to);
|
||||
v.vdocuments.write(to);
|
||||
} break;
|
||||
}
|
||||
@@ -24602,8 +24906,8 @@ inline MTPmessages_allStickers::MTPmessages_allStickers(MTPDmessages_allStickers
|
||||
inline MTPmessages_allStickers MTP_messages_allStickersNotModified() {
|
||||
return MTPmessages_allStickers(mtpc_messages_allStickersNotModified);
|
||||
}
|
||||
inline MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) {
|
||||
return MTPmessages_allStickers(new MTPDmessages_allStickers(_hash, _packs, _documents));
|
||||
inline MTPmessages_allStickers MTP_messages_allStickers(const MTPstring &_hash, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPStickerSet> &_sets, const MTPVector<MTPDocument> &_documents) {
|
||||
return MTPmessages_allStickers(new MTPDmessages_allStickers(_hash, _packs, _sets, _documents));
|
||||
}
|
||||
|
||||
inline MTPdisabledFeature::MTPdisabledFeature() : mtpDataOwner(new MTPDdisabledFeature()) {
|
||||
@@ -25199,6 +25503,140 @@ inline MTPchatInvite MTP_chatInvite(const MTPstring &_title) {
|
||||
return MTPchatInvite(new MTPDchatInvite(_title));
|
||||
}
|
||||
|
||||
inline uint32 MTPinputStickerSet::innerLength() const {
|
||||
switch (_type) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
const MTPDinputStickerSetID &v(c_inputStickerSetID());
|
||||
return v.vid.innerLength() + v.vaccess_hash.innerLength();
|
||||
}
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
const MTPDinputStickerSetShortName &v(c_inputStickerSetShortName());
|
||||
return v.vshort_name.innerLength();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
inline mtpTypeId MTPinputStickerSet::type() const {
|
||||
if (!_type) throw mtpErrorUninitialized();
|
||||
return _type;
|
||||
}
|
||||
inline void MTPinputStickerSet::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
|
||||
if (cons != _type) setData(0);
|
||||
switch (cons) {
|
||||
case mtpc_inputStickerSetEmpty: _type = cons; break;
|
||||
case mtpc_inputStickerSetID: _type = cons; {
|
||||
if (!data) setData(new MTPDinputStickerSetID());
|
||||
MTPDinputStickerSetID &v(_inputStickerSetID());
|
||||
v.vid.read(from, end);
|
||||
v.vaccess_hash.read(from, end);
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: _type = cons; {
|
||||
if (!data) setData(new MTPDinputStickerSetShortName());
|
||||
MTPDinputStickerSetShortName &v(_inputStickerSetShortName());
|
||||
v.vshort_name.read(from, end);
|
||||
} break;
|
||||
default: throw mtpErrorUnexpected(cons, "MTPinputStickerSet");
|
||||
}
|
||||
}
|
||||
inline void MTPinputStickerSet::write(mtpBuffer &to) const {
|
||||
switch (_type) {
|
||||
case mtpc_inputStickerSetID: {
|
||||
const MTPDinputStickerSetID &v(c_inputStickerSetID());
|
||||
v.vid.write(to);
|
||||
v.vaccess_hash.write(to);
|
||||
} break;
|
||||
case mtpc_inputStickerSetShortName: {
|
||||
const MTPDinputStickerSetShortName &v(c_inputStickerSetShortName());
|
||||
v.vshort_name.write(to);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
inline MTPinputStickerSet::MTPinputStickerSet(mtpTypeId type) : mtpDataOwner(0), _type(type) {
|
||||
switch (type) {
|
||||
case mtpc_inputStickerSetEmpty: break;
|
||||
case mtpc_inputStickerSetID: setData(new MTPDinputStickerSetID()); break;
|
||||
case mtpc_inputStickerSetShortName: setData(new MTPDinputStickerSetShortName()); break;
|
||||
default: throw mtpErrorBadTypeId(type, "MTPinputStickerSet");
|
||||
}
|
||||
}
|
||||
inline MTPinputStickerSet::MTPinputStickerSet(MTPDinputStickerSetID *_data) : mtpDataOwner(_data), _type(mtpc_inputStickerSetID) {
|
||||
}
|
||||
inline MTPinputStickerSet::MTPinputStickerSet(MTPDinputStickerSetShortName *_data) : mtpDataOwner(_data), _type(mtpc_inputStickerSetShortName) {
|
||||
}
|
||||
inline MTPinputStickerSet MTP_inputStickerSetEmpty() {
|
||||
return MTPinputStickerSet(mtpc_inputStickerSetEmpty);
|
||||
}
|
||||
inline MTPinputStickerSet MTP_inputStickerSetID(const MTPlong &_id, const MTPlong &_access_hash) {
|
||||
return MTPinputStickerSet(new MTPDinputStickerSetID(_id, _access_hash));
|
||||
}
|
||||
inline MTPinputStickerSet MTP_inputStickerSetShortName(const MTPstring &_short_name) {
|
||||
return MTPinputStickerSet(new MTPDinputStickerSetShortName(_short_name));
|
||||
}
|
||||
|
||||
inline MTPstickerSet::MTPstickerSet() : mtpDataOwner(new MTPDstickerSet()) {
|
||||
}
|
||||
|
||||
inline uint32 MTPstickerSet::innerLength() const {
|
||||
const MTPDstickerSet &v(c_stickerSet());
|
||||
return v.vid.innerLength() + v.vaccess_hash.innerLength() + v.vtitle.innerLength() + v.vshort_name.innerLength();
|
||||
}
|
||||
inline mtpTypeId MTPstickerSet::type() const {
|
||||
return mtpc_stickerSet;
|
||||
}
|
||||
inline void MTPstickerSet::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
|
||||
if (cons != mtpc_stickerSet) throw mtpErrorUnexpected(cons, "MTPstickerSet");
|
||||
|
||||
if (!data) setData(new MTPDstickerSet());
|
||||
MTPDstickerSet &v(_stickerSet());
|
||||
v.vid.read(from, end);
|
||||
v.vaccess_hash.read(from, end);
|
||||
v.vtitle.read(from, end);
|
||||
v.vshort_name.read(from, end);
|
||||
}
|
||||
inline void MTPstickerSet::write(mtpBuffer &to) const {
|
||||
const MTPDstickerSet &v(c_stickerSet());
|
||||
v.vid.write(to);
|
||||
v.vaccess_hash.write(to);
|
||||
v.vtitle.write(to);
|
||||
v.vshort_name.write(to);
|
||||
}
|
||||
inline MTPstickerSet::MTPstickerSet(MTPDstickerSet *_data) : mtpDataOwner(_data) {
|
||||
}
|
||||
inline MTPstickerSet MTP_stickerSet(const MTPlong &_id, const MTPlong &_access_hash, const MTPstring &_title, const MTPstring &_short_name) {
|
||||
return MTPstickerSet(new MTPDstickerSet(_id, _access_hash, _title, _short_name));
|
||||
}
|
||||
|
||||
inline MTPmessages_stickerSet::MTPmessages_stickerSet() : mtpDataOwner(new MTPDmessages_stickerSet()) {
|
||||
}
|
||||
|
||||
inline uint32 MTPmessages_stickerSet::innerLength() const {
|
||||
const MTPDmessages_stickerSet &v(c_messages_stickerSet());
|
||||
return v.vset.innerLength() + v.vpacks.innerLength() + v.vdocuments.innerLength();
|
||||
}
|
||||
inline mtpTypeId MTPmessages_stickerSet::type() const {
|
||||
return mtpc_messages_stickerSet;
|
||||
}
|
||||
inline void MTPmessages_stickerSet::read(const mtpPrime *&from, const mtpPrime *end, mtpTypeId cons) {
|
||||
if (cons != mtpc_messages_stickerSet) throw mtpErrorUnexpected(cons, "MTPmessages_stickerSet");
|
||||
|
||||
if (!data) setData(new MTPDmessages_stickerSet());
|
||||
MTPDmessages_stickerSet &v(_messages_stickerSet());
|
||||
v.vset.read(from, end);
|
||||
v.vpacks.read(from, end);
|
||||
v.vdocuments.read(from, end);
|
||||
}
|
||||
inline void MTPmessages_stickerSet::write(mtpBuffer &to) const {
|
||||
const MTPDmessages_stickerSet &v(c_messages_stickerSet());
|
||||
v.vset.write(to);
|
||||
v.vpacks.write(to);
|
||||
v.vdocuments.write(to);
|
||||
}
|
||||
inline MTPmessages_stickerSet::MTPmessages_stickerSet(MTPDmessages_stickerSet *_data) : mtpDataOwner(_data) {
|
||||
}
|
||||
inline MTPmessages_stickerSet MTP_messages_stickerSet(const MTPStickerSet &_set, const MTPVector<MTPStickerPack> &_packs, const MTPVector<MTPDocument> &_documents) {
|
||||
return MTPmessages_stickerSet(new MTPDmessages_stickerSet(_set, _packs, _documents));
|
||||
}
|
||||
|
||||
// Human-readable text serialization
|
||||
#if (defined _DEBUG || defined _WITH_DEBUG)
|
||||
|
||||
|
||||
@@ -63,11 +63,15 @@ void MTPSessionData::clear() {
|
||||
}
|
||||
|
||||
|
||||
MTProtoSession::MTProtoSession() : data(this), dcId(0), dc(0), msSendCall(0), msWait(0), _ping(false) {
|
||||
MTProtoSession::MTProtoSession() : _killed(false), data(this), dcWithShift(0), dc(0), msSendCall(0), msWait(0), _ping(false) {
|
||||
}
|
||||
|
||||
void MTProtoSession::start(int32 dcenter) {
|
||||
if (dcId) {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't start a killed session"));
|
||||
return;
|
||||
}
|
||||
if (dcWithShift) {
|
||||
DEBUG_LOG(("Session Info: MTProtoSession::start called on already started session"));
|
||||
return;
|
||||
}
|
||||
@@ -84,8 +88,8 @@ void MTProtoSession::start(int32 dcenter) {
|
||||
connections.reserve(cConnectionsInSession());
|
||||
for (uint32 i = 0; i < cConnectionsInSession(); ++i) {
|
||||
connections.push_back(new MTProtoConnection());
|
||||
dcId = connections.back()->start(&data, dcenter);
|
||||
if (!dcId) {
|
||||
dcWithShift = connections.back()->start(&data, dcenter);
|
||||
if (!dcWithShift) {
|
||||
for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) {
|
||||
delete *j;
|
||||
}
|
||||
@@ -94,11 +98,12 @@ void MTProtoSession::start(int32 dcenter) {
|
||||
return;
|
||||
}
|
||||
if (!dc) {
|
||||
dcenter = dcId;
|
||||
MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId % _mtp_internal::dcShift);
|
||||
dcenter = dcWithShift;
|
||||
int32 dcId = dcWithShift % _mtp_internal::dcShift;
|
||||
MTProtoDCMap::const_iterator dcIndex = dcs.constFind(dcId);
|
||||
if (dcIndex == dcs.cend()) {
|
||||
dc = MTProtoDCPtr(new MTProtoDC(dcId % _mtp_internal::dcShift, mtpAuthKeyPtr()));
|
||||
dcs.insert(dcId % _mtp_internal::dcShift, dc);
|
||||
dc = MTProtoDCPtr(new MTProtoDC(dcId, mtpAuthKeyPtr()));
|
||||
dcs.insert(dcWithShift % _mtp_internal::dcShift, dc);
|
||||
} else {
|
||||
dc = dcIndex.value();
|
||||
}
|
||||
@@ -115,18 +120,32 @@ void MTProtoSession::start(int32 dcenter) {
|
||||
}
|
||||
|
||||
void MTProtoSession::restart() {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't restart a killed session"));
|
||||
return;
|
||||
}
|
||||
emit needToRestart();
|
||||
}
|
||||
|
||||
void MTProtoSession::stop() {
|
||||
DEBUG_LOG(("Session Info: stopping session %1").arg(dcId));
|
||||
DEBUG_LOG(("Session Info: stopping session dcWithShift %1").arg(dcWithShift));
|
||||
while (!connections.isEmpty()) {
|
||||
connections.back()->stop();
|
||||
connections.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void MTProtoSession::kill() {
|
||||
stop();
|
||||
_killed = true;
|
||||
DEBUG_LOG(("Session Info: marked session dcWithShift %1 as killed").arg(dcWithShift));
|
||||
}
|
||||
|
||||
void MTProtoSession::sendAnything(quint64 msCanWait) {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Error: can't send anything in a killed session"));
|
||||
return;
|
||||
}
|
||||
uint64 ms = getms(true);
|
||||
if (msSendCall) {
|
||||
if (ms > msSendCall + msWait) {
|
||||
@@ -141,11 +160,11 @@ void MTProtoSession::sendAnything(quint64 msCanWait) {
|
||||
msWait = msCanWait;
|
||||
}
|
||||
if (msWait) {
|
||||
DEBUG_LOG(("MTP Info: dc %1 can wait for %2ms from current %3").arg(dcId).arg(msWait).arg(msSendCall));
|
||||
DEBUG_LOG(("MTP Info: dcWithShift %1 can wait for %2ms from current %3").arg(dcWithShift).arg(msWait).arg(msSendCall));
|
||||
msSendCall = ms;
|
||||
sender.start(msWait);
|
||||
} else {
|
||||
DEBUG_LOG(("MTP Info: dc %1 stopped send timer, can wait for %2ms from current %3").arg(dcId).arg(msWait).arg(msSendCall));
|
||||
DEBUG_LOG(("MTP Info: dcWithShift %1 stopped send timer, can wait for %2ms from current %3").arg(dcWithShift).arg(msWait).arg(msSendCall));
|
||||
sender.stop();
|
||||
msSendCall = 0;
|
||||
needToResumeAndSend();
|
||||
@@ -153,20 +172,24 @@ void MTProtoSession::sendAnything(quint64 msCanWait) {
|
||||
}
|
||||
|
||||
void MTProtoSession::needToResumeAndSend() {
|
||||
if (_killed) {
|
||||
DEBUG_LOG(("Session Info: can't resume a killed session"));
|
||||
return;
|
||||
}
|
||||
if (connections.isEmpty()) {
|
||||
DEBUG_LOG(("Session Info: resuming session %1").arg(dcId));
|
||||
DEBUG_LOG(("Session Info: resuming session dcWithShift %1").arg(dcWithShift));
|
||||
MTProtoDCMap &dcs(mtpDCMap());
|
||||
|
||||
connections.reserve(cConnectionsInSession());
|
||||
for (uint32 i = 0; i < cConnectionsInSession(); ++i) {
|
||||
connections.push_back(new MTProtoConnection());
|
||||
if (!connections.back()->start(&data, dcId)) {
|
||||
if (!connections.back()->start(&data, dcWithShift)) {
|
||||
for (MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend(); j != e; ++j) {
|
||||
delete *j;
|
||||
}
|
||||
connections.clear();
|
||||
DEBUG_LOG(("Session Info: could not start connection %1 to dc %2").arg(i).arg(dcId));
|
||||
dcId = 0;
|
||||
DEBUG_LOG(("Session Info: could not start connection %1 to dcWithShift %2").arg(i).arg(dcWithShift));
|
||||
dcWithShift = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -259,11 +282,11 @@ void MTProtoSession::checkRequestsByTimer() {
|
||||
}
|
||||
|
||||
void MTProtoSession::onConnectionStateChange(qint32 newState) {
|
||||
_mtp_internal::onStateChange(dcId, newState);
|
||||
_mtp_internal::onStateChange(dcWithShift, newState);
|
||||
}
|
||||
|
||||
void MTProtoSession::onResetDone() {
|
||||
_mtp_internal::onSessionReset(dcId);
|
||||
_mtp_internal::onSessionReset(dcWithShift);
|
||||
}
|
||||
|
||||
void MTProtoSession::cancel(mtpRequestId requestId, mtpMsgId msgId) {
|
||||
@@ -428,23 +451,23 @@ QReadWriteLock *MTProtoSession::keyMutex() const {
|
||||
}
|
||||
|
||||
void MTProtoSession::authKeyCreatedForDC() {
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::authKeyCreatedForDC slot, emitting authKeyCreated(), dc %1").arg(dcId));
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::authKeyCreatedForDC slot, emitting authKeyCreated(), dcWithShift %1").arg(dcWithShift));
|
||||
data.setKey(dc->getKey());
|
||||
emit authKeyCreated();
|
||||
}
|
||||
|
||||
void MTProtoSession::notifyKeyCreated(const mtpAuthKeyPtr &key) {
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dc %1").arg(dcId));
|
||||
DEBUG_LOG(("AuthKey Info: MTProtoSession::keyCreated(), setting, dcWithShift %1").arg(dcWithShift));
|
||||
dc->setKey(key);
|
||||
}
|
||||
|
||||
void MTProtoSession::layerWasInitedForDC(bool wasInited) {
|
||||
DEBUG_LOG(("MTP Info: MTProtoSession::layerWasInitedForDC slot, dc %1").arg(dcId));
|
||||
DEBUG_LOG(("MTP Info: MTProtoSession::layerWasInitedForDC slot, dcWithShift %1").arg(dcWithShift));
|
||||
data.setLayerWasInited(wasInited);
|
||||
}
|
||||
|
||||
void MTProtoSession::notifyLayerInited(bool wasInited) {
|
||||
DEBUG_LOG(("MTP Info: emitting MTProtoDC::layerWasInited(%1), dc %2").arg(logBool(wasInited)).arg(dcId));
|
||||
DEBUG_LOG(("MTP Info: emitting MTProtoDC::layerWasInited(%1), dcWithShift %2").arg(logBool(wasInited)).arg(dcWithShift));
|
||||
dc->setConnectionInited(wasInited);
|
||||
emit dc->layerWasInited(wasInited);
|
||||
}
|
||||
@@ -453,7 +476,7 @@ void MTProtoSession::destroyKey() {
|
||||
if (!dc) return;
|
||||
|
||||
if (data.getKey()) {
|
||||
DEBUG_LOG(("MTP Info: destroying auth_key for dc %1").arg(dcId));
|
||||
DEBUG_LOG(("MTP Info: destroying auth_key for dcWithShift %1").arg(dcWithShift));
|
||||
if (data.getKey() == dc->getKey()) {
|
||||
dc->destroyKey();
|
||||
}
|
||||
@@ -461,8 +484,8 @@ void MTProtoSession::destroyKey() {
|
||||
}
|
||||
}
|
||||
|
||||
int32 MTProtoSession::getDC() const {
|
||||
return dcId;
|
||||
int32 MTProtoSession::getDcWithShift() const {
|
||||
return dcWithShift;
|
||||
}
|
||||
|
||||
void MTProtoSession::tryToReceive() {
|
||||
@@ -481,7 +504,7 @@ void MTProtoSession::tryToReceive() {
|
||||
responses.erase(i);
|
||||
}
|
||||
if (requestId <= 0) {
|
||||
if (dcId < int(_mtp_internal::dcShift)) { // call globalCallback only in main session
|
||||
if (dcWithShift < int(_mtp_internal::dcShift)) { // call globalCallback only in main session
|
||||
_mtp_internal::globalCallback(response.constData(), response.constData() + response.size());
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -224,8 +224,9 @@ public:
|
||||
void start(int32 dcenter = 0);
|
||||
void restart();
|
||||
void stop();
|
||||
void kill();
|
||||
|
||||
int32 getDC() const;
|
||||
int32 getDcWithShift() const;
|
||||
~MTProtoSession();
|
||||
|
||||
QReadWriteLock *keyMutex() const;
|
||||
@@ -275,10 +276,12 @@ private:
|
||||
|
||||
typedef QList<MTProtoConnection*> MTProtoConnections;
|
||||
MTProtoConnections connections;
|
||||
|
||||
bool _killed;
|
||||
|
||||
MTPSessionData data;
|
||||
|
||||
int32 dcId;
|
||||
int32 dcWithShift;
|
||||
MTProtoDCPtr dc;
|
||||
|
||||
uint64 msSendCall, msWait;
|
||||
|
||||
@@ -37,6 +37,6 @@ mtpRequestId MTProtoSession::send(const TRequest &request, RPCResponseHandler ca
|
||||
requestId = 0;
|
||||
_mtp_internal::rpcErrorOccured(requestId, callbacks, rpcClientError("NO_REQUEST_ID", QString("send() failed to queue request, exception: %1").arg(e.what())));
|
||||
}
|
||||
if (requestId) _mtp_internal::registerRequest(requestId, toMainDC ? -getDC() : getDC());
|
||||
if (requestId) _mtp_internal::registerRequest(requestId, toMainDC ? -getDcWithShift() : getDcWithShift());
|
||||
return requestId;
|
||||
}
|
||||
|
||||
@@ -526,7 +526,7 @@ updateUserPhone#12b9417b user_id:int phone:string = Update;
|
||||
|
||||
documentAttributeImageSize#6c37c15c w:int h:int = DocumentAttribute;
|
||||
documentAttributeAnimated#11b58939 = DocumentAttribute;
|
||||
documentAttributeSticker#994c9882 alt:string = DocumentAttribute;
|
||||
documentAttributeSticker#3a556302 alt:string stickerset:InputStickerSet = DocumentAttribute;
|
||||
documentAttributeVideo#5910cccb duration:int w:int h:int = DocumentAttribute;
|
||||
documentAttributeAudio#51448e5 duration:int = DocumentAttribute;
|
||||
documentAttributeFilename#15590068 file_name:string = DocumentAttribute;
|
||||
@@ -537,7 +537,7 @@ messages.stickers#8a8ecd32 hash:string stickers:Vector<Document> = messages.Stic
|
||||
stickerPack#12b299d4 emoticon:string documents:Vector<long> = StickerPack;
|
||||
|
||||
messages.allStickersNotModified#e86602c3 = messages.AllStickers;
|
||||
messages.allStickers#dcef3102 hash:string packs:Vector<StickerPack> documents:Vector<Document> = messages.AllStickers;
|
||||
messages.allStickers#5ce352ec hash:string packs:Vector<StickerPack> sets:Vector<StickerSet> documents:Vector<Document> = messages.AllStickers;
|
||||
|
||||
disabledFeature#ae636f24 feature:string description:string = DisabledFeature;
|
||||
|
||||
@@ -588,6 +588,14 @@ messageActionChatJoinedByLink#f89cf5e8 inviter_id:int = MessageAction;
|
||||
|
||||
updateReadMessagesContents#68c13933 messages:Vector<int> pts:int pts_count:int = Update;
|
||||
|
||||
inputStickerSetEmpty#ffb62b95 = InputStickerSet;
|
||||
inputStickerSetID#9de7a269 id:long access_hash:long = InputStickerSet;
|
||||
inputStickerSetShortName#861cc8a0 short_name:string = InputStickerSet;
|
||||
|
||||
stickerSet#a7a43b17 id:long access_hash:long title:string short_name:string = StickerSet;
|
||||
|
||||
messages.stickerSet#b60a24a6 set:StickerSet packs:Vector<StickerPack> documents:Vector<Document> = messages.StickerSet;
|
||||
|
||||
---functions---
|
||||
|
||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||
@@ -744,4 +752,7 @@ invokeWithoutUpdates#bf9459b7 {X:Type} query:!X = X;
|
||||
|
||||
messages.exportChatInvite#7d885289 chat_id:int = ExportedChatInvite;
|
||||
messages.checkChatInvite#3eadb1bb hash:string = ChatInvite;
|
||||
messages.importChatInvite#6c50051c hash:string = Updates;
|
||||
messages.importChatInvite#6c50051c hash:string = Updates;
|
||||
messages.getStickerSet#2619a90e stickerset:InputStickerSet = messages.StickerSet;
|
||||
messages.installStickerSet#efbbfae9 stickerset:InputStickerSet = Bool;
|
||||
messages.uninstallStickerSet#f96e55de stickerset:InputStickerSet = Bool;
|
||||
|
||||
@@ -256,6 +256,7 @@ void ProfileInner::onMediaAudios() {
|
||||
}
|
||||
|
||||
void ProfileInner::onInvitationLink() {
|
||||
DEBUG_LOG(("Setting text to clipboard from invite url: %1").arg(_peerChat->invitationUrl));
|
||||
QApplication::clipboard()->setText(_peerChat->invitationUrl);
|
||||
App::wnd()->showLayer(new ConfirmBox(lang(lng_group_invite_copied), true));
|
||||
}
|
||||
@@ -769,10 +770,12 @@ void ProfileInner::onMenuDestroy(QObject *obj) {
|
||||
}
|
||||
|
||||
void ProfileInner::onCopyPhone() {
|
||||
DEBUG_LOG(("Setting text to clipboard from user phone: %1").arg(_phoneText));
|
||||
QApplication::clipboard()->setText(_phoneText);
|
||||
}
|
||||
|
||||
void ProfileInner::onCopyUsername() {
|
||||
DEBUG_LOG(("Setting text to clipboard from username: @%1").arg(_peerUser->username));
|
||||
QApplication::clipboard()->setText('@' + _peerUser->username);
|
||||
}
|
||||
|
||||
|
||||
@@ -89,12 +89,15 @@ RecentEmojiPack gRecentEmojis;
|
||||
RecentEmojisPreload gRecentEmojisPreload;
|
||||
EmojiColorVariants gEmojiVariants;
|
||||
|
||||
AllStickers gStickers;
|
||||
QByteArray gStickersHash;
|
||||
|
||||
EmojiStickersMap gEmojiStickers;
|
||||
|
||||
RecentStickerPreload gRecentStickersPreload;
|
||||
RecentStickerPack gRecentStickers;
|
||||
StickerSets gStickerSets;
|
||||
|
||||
uint64 gLastStickersUpdate = 0;
|
||||
|
||||
RecentHashtagPack gRecentWriteHashtags, gRecentSearchHashtags;
|
||||
|
||||
@@ -249,7 +252,7 @@ RecentEmojiPack &cGetRecentEmojis() {
|
||||
0xD83DDE15LLU,
|
||||
};
|
||||
for (int32 i = 0, s = sizeof(defaultRecent) / sizeof(defaultRecent[0]); i < s; ++i) {
|
||||
if (r.size() >= EmojiPadPerRow * EmojiPadRowsPerPage) break;
|
||||
if (r.size() >= EmojiPanPerRow * EmojiPanRowsPerPage) break;
|
||||
|
||||
EmojiPtr ep(emojiGet(defaultRecent[i]));
|
||||
if (!ep || ep == TwoSymbolEmoji) continue;
|
||||
@@ -268,3 +271,20 @@ RecentEmojiPack &cGetRecentEmojis() {
|
||||
}
|
||||
return cRefRecentEmojis();
|
||||
}
|
||||
|
||||
RecentStickerPack &cGetRecentStickers() {
|
||||
if (cRecentStickers().isEmpty() && !cRecentStickersPreload().isEmpty()) {
|
||||
RecentStickerPreload p(cRecentStickersPreload());
|
||||
cSetRecentStickersPreload(RecentStickerPreload());
|
||||
|
||||
RecentStickerPack &recent(cRefRecentStickers());
|
||||
recent.reserve(p.size());
|
||||
for (RecentStickerPreload::const_iterator i = p.cbegin(), e = p.cend(); i != e; ++i) {
|
||||
DocumentData *doc = App::document(i->first);
|
||||
if (!doc || !doc->sticker) continue;
|
||||
|
||||
recent.push_back(qMakePair(doc, i->second));
|
||||
}
|
||||
}
|
||||
return cRefRecentStickers();
|
||||
}
|
||||
|
||||
@@ -183,15 +183,31 @@ RecentEmojiPack &cGetRecentEmojis();
|
||||
|
||||
struct DocumentData;
|
||||
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);
|
||||
typedef QList<QPair<DocumentData*, int16> > RecentStickerPackOld;
|
||||
typedef QVector<QPair<uint64, ushort> > RecentStickerPreload;
|
||||
typedef QVector<QPair<DocumentData*, ushort> > RecentStickerPack;
|
||||
DeclareSetting(RecentStickerPreload, RecentStickersPreload);
|
||||
DeclareRefSetting(RecentStickerPack, RecentStickers);
|
||||
|
||||
RecentStickerPack &cGetRecentStickers();
|
||||
|
||||
DeclareSetting(uint64, LastStickersUpdate);
|
||||
|
||||
static const uint64 DefaultStickerSetId = 0, CustomStickerSetId = 0xFFFFFFFFFFFFFFFFLLU, RecentStickerSetId = 0xFFFFFFFFFFFFFFFELLU;
|
||||
struct StickerSet {
|
||||
StickerSet(uint64 id, uint64 access, const QString &title, const QString &shortName) : id(id), access(access), title(title), shortName(shortName) {
|
||||
}
|
||||
uint64 id, access;
|
||||
QString title, shortName;
|
||||
StickerPack stickers;
|
||||
};
|
||||
typedef QMap<uint64, StickerSet> StickerSets;
|
||||
DeclareRefSetting(StickerSets, StickerSets);
|
||||
|
||||
typedef QList<QPair<QString, ushort> > RecentHashtagPack;
|
||||
DeclareSetting(RecentHashtagPack, RecentWriteHashtags);
|
||||
|
||||
@@ -348,7 +348,7 @@ void VideoCancelLink::onClick(Qt::MouseButton button) const {
|
||||
|
||||
VideoData::VideoData(const VideoId &id, const uint64 &access, int32 user, int32 date, int32 duration, int32 w, int32 h, const ImagePtr &thumb, int32 dc, int32 size) :
|
||||
id(id), access(access), user(user), date(date), duration(duration), w(w), h(h), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), fileType(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
|
||||
location = Local::readFileLocation(mediaKey(mtpc_inputVideoFileLocation, dc, id));
|
||||
location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
|
||||
}
|
||||
|
||||
void VideoData::save(const QString &toFile) {
|
||||
@@ -361,7 +361,7 @@ void VideoData::save(const QString &toFile) {
|
||||
|
||||
QString VideoData::already(bool check) {
|
||||
if (!check) return location.name;
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputVideoFileLocation, dc, id));
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(VideoFileLocation, dc, id));
|
||||
return location.name;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ void AudioCancelLink::onClick(Qt::MouseButton button) const {
|
||||
|
||||
AudioData::AudioData(const AudioId &id, const uint64 &access, int32 user, int32 date, const QString &mime, int32 duration, int32 dc, int32 size) :
|
||||
id(id), access(access), user(user), date(date), mime(mime), duration(duration), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
|
||||
location = Local::readFileLocation(mediaKey(mtpc_inputAudioFileLocation, dc, id));
|
||||
location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
|
||||
}
|
||||
|
||||
void AudioData::save(const QString &toFile) {
|
||||
@@ -455,7 +455,7 @@ void AudioData::save(const QString &toFile) {
|
||||
|
||||
QString AudioData::already(bool check) {
|
||||
if (!check) return location.name;
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputAudioFileLocation, dc, id));
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(AudioFileLocation, dc, id));
|
||||
return location.name;
|
||||
}
|
||||
|
||||
@@ -558,9 +558,9 @@ void DocumentCancelLink::onClick(Qt::MouseButton button) const {
|
||||
}
|
||||
|
||||
DocumentData::DocumentData(const DocumentId &id, const uint64 &access, int32 date, const QVector<MTPDocumentAttribute> &attributes, const QString &mime, const ImagePtr &thumb, int32 dc, int32 size) :
|
||||
id(id), type(FileDocument), duration(0), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0) {
|
||||
id(id), type(FileDocument), duration(0), access(access), date(date), mime(mime), thumb(thumb), dc(dc), size(size), status(FileReady), uploadOffset(0), openOnSave(0), openOnSaveMsgId(0), loader(0), sticker(0) {
|
||||
setattributes(attributes);
|
||||
location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id));
|
||||
location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
|
||||
}
|
||||
|
||||
void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes) {
|
||||
@@ -574,7 +574,11 @@ void DocumentData::setattributes(const QVector<MTPDocumentAttribute> &attributes
|
||||
case mtpc_documentAttributeSticker: {
|
||||
const MTPDdocumentAttributeSticker &d(attributes[i].c_documentAttributeSticker());
|
||||
if (type == FileDocument) type = StickerDocument;
|
||||
alt = qs(d.valt);
|
||||
if (type == StickerDocument && !sticker) sticker = new StickerData();
|
||||
if (sticker) {
|
||||
sticker->alt = qs(d.valt);
|
||||
sticker->set = d.vstickerset;
|
||||
}
|
||||
} break;
|
||||
case mtpc_documentAttributeVideo: {
|
||||
const MTPDdocumentAttributeVideo &d(attributes[i].c_documentAttributeVideo());
|
||||
@@ -603,7 +607,7 @@ void DocumentData::save(const QString &toFile) {
|
||||
|
||||
QString DocumentData::already(bool check) {
|
||||
if (!check) return location.name;
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(mtpc_inputDocumentFileLocation, dc, id));
|
||||
if (!location.check()) location = Local::readFileLocation(mediaKey(DocumentFileLocation, dc, id));
|
||||
return location.name;
|
||||
}
|
||||
|
||||
|
||||
@@ -253,7 +253,7 @@ struct VideoData {
|
||||
|
||||
void finish() {
|
||||
if (loader->done()) {
|
||||
location = FileLocation(loader->fileType(), loader->fileName());
|
||||
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
|
||||
}
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
@@ -339,7 +339,7 @@ struct AudioData {
|
||||
|
||||
void finish() {
|
||||
if (loader->done()) {
|
||||
location = FileLocation(loader->fileType(), loader->fileName());
|
||||
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
|
||||
data = loader->bytes();
|
||||
}
|
||||
loader->deleteLater();
|
||||
@@ -402,6 +402,16 @@ public:
|
||||
void onClick(Qt::MouseButton button) const;
|
||||
};
|
||||
|
||||
struct StickerData {
|
||||
StickerData() : set(MTP_inputStickerSetEmpty()) {
|
||||
}
|
||||
ImagePtr img;
|
||||
QString alt;
|
||||
|
||||
MTPInputStickerSet set;
|
||||
StorageImageLocation loc; // doc thumb location
|
||||
};
|
||||
|
||||
enum DocumentType {
|
||||
FileDocument,
|
||||
VideoDocument,
|
||||
@@ -415,7 +425,7 @@ struct DocumentData {
|
||||
|
||||
void forget() {
|
||||
thumb->forget();
|
||||
sticker->forget();
|
||||
if (sticker) sticker->img->forget();
|
||||
replyPreview->forget();
|
||||
}
|
||||
|
||||
@@ -437,13 +447,16 @@ struct DocumentData {
|
||||
|
||||
void finish() {
|
||||
if (loader->done()) {
|
||||
location = FileLocation(loader->fileType(), loader->fileName());
|
||||
location = FileLocation(mtpToStorageType(loader->fileType()), loader->fileName());
|
||||
data = loader->bytes();
|
||||
}
|
||||
loader->deleteLater();
|
||||
loader->rpcInvalidate();
|
||||
loader = 0;
|
||||
}
|
||||
~DocumentData() {
|
||||
delete sticker;
|
||||
}
|
||||
|
||||
QString already(bool check = false);
|
||||
|
||||
@@ -453,7 +466,7 @@ struct DocumentData {
|
||||
int32 duration;
|
||||
uint64 access;
|
||||
int32 date;
|
||||
QString name, mime, alt; // alt - for stickers
|
||||
QString name, mime;
|
||||
ImagePtr thumb, replyPreview;
|
||||
int32 dc;
|
||||
int32 size;
|
||||
@@ -466,7 +479,7 @@ struct DocumentData {
|
||||
FileLocation location;
|
||||
|
||||
QByteArray data;
|
||||
ImagePtr sticker;
|
||||
StickerData *sticker;
|
||||
|
||||
int32 md5[8];
|
||||
};
|
||||
|
||||
@@ -149,7 +149,39 @@ MTPint toServerTime(const int32 &clientTime) {
|
||||
|
||||
// Precise timing functions / rand init
|
||||
|
||||
struct CRYPTO_dynlock_value {
|
||||
QMutex mutex;
|
||||
};
|
||||
|
||||
namespace {
|
||||
bool _sslInited = false;
|
||||
QMutex *_sslLocks = 0;
|
||||
void _sslLockingCallback(int mode, int type, const char *file, int line) {
|
||||
if (!_sslLocks) return; // not inited
|
||||
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
_sslLocks[type].lock();
|
||||
} else {
|
||||
_sslLocks[type].unlock();
|
||||
}
|
||||
}
|
||||
void _sslThreadId(CRYPTO_THREADID *id) {
|
||||
CRYPTO_THREADID_set_pointer(id, QThread::currentThreadId());
|
||||
}
|
||||
CRYPTO_dynlock_value *_sslCreateFunction(const char *file, int line) {
|
||||
return new CRYPTO_dynlock_value();
|
||||
}
|
||||
void _sslLockFunction(int mode, CRYPTO_dynlock_value *l, const char *file, int line) {
|
||||
if (mode & CRYPTO_LOCK) {
|
||||
l->mutex.lock();
|
||||
} else {
|
||||
l->mutex.unlock();
|
||||
}
|
||||
}
|
||||
void _sslDestroyFunction(CRYPTO_dynlock_value *l, const char *file, int line) {
|
||||
delete l;
|
||||
}
|
||||
|
||||
float64 _msFreq;
|
||||
float64 _msgIdCoef;
|
||||
int64 _msStart = 0, _msAddToMsStart = 0, _msAddToUnixtime = 0;
|
||||
@@ -185,16 +217,6 @@ namespace {
|
||||
#endif
|
||||
_timeStart = myunixtime();
|
||||
srand((uint32)(_msStart & 0xFFFFFFFFL));
|
||||
if (!RAND_status()) { // should be always inited in all modern OS
|
||||
char buf[16];
|
||||
memcpy(buf, &_msStart, 8);
|
||||
memcpy(buf + 8, &_msFreq, 8);
|
||||
uchar sha256Buffer[32];
|
||||
RAND_seed(hashSha256(buf, 16, sha256Buffer), 32);
|
||||
if (!RAND_status()) {
|
||||
LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0.."));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -211,6 +233,38 @@ namespace {
|
||||
_MsStarter _msStarter;
|
||||
}
|
||||
|
||||
InitOpenSSL::InitOpenSSL() {
|
||||
if (!RAND_status()) { // should be always inited in all modern OS
|
||||
char buf[16];
|
||||
memcpy(buf, &_msStart, 8);
|
||||
memcpy(buf + 8, &_msFreq, 8);
|
||||
uchar sha256Buffer[32];
|
||||
RAND_seed(hashSha256(buf, 16, sha256Buffer), 32);
|
||||
if (!RAND_status()) {
|
||||
LOG(("MTP Error: Could not init OpenSSL rand, RAND_status() is 0.."));
|
||||
}
|
||||
}
|
||||
|
||||
int32 numLocks = CRYPTO_num_locks();
|
||||
if (numLocks) {
|
||||
_sslLocks = new QMutex[numLocks];
|
||||
CRYPTO_set_locking_callback(_sslLockingCallback);
|
||||
} else {
|
||||
LOG(("MTP Error: Could not init OpenSSL threads, CRYPTO_num_locks() returned zero!"));
|
||||
}
|
||||
CRYPTO_THREADID_set_callback(_sslThreadId);
|
||||
CRYPTO_set_dynlock_create_callback(_sslCreateFunction);
|
||||
CRYPTO_set_dynlock_lock_callback(_sslLockFunction);
|
||||
CRYPTO_set_dynlock_destroy_callback(_sslDestroyFunction);
|
||||
|
||||
_sslInited = true;
|
||||
}
|
||||
|
||||
InitOpenSSL::~InitOpenSSL() {
|
||||
delete[] _sslLocks;
|
||||
_sslLocks = 0;
|
||||
}
|
||||
|
||||
bool checkms() {
|
||||
int64 unixms = (myunixtime() - _timeStart) * 1000LL + _msAddToUnixtime;
|
||||
int64 ms = int64(getms(true));
|
||||
@@ -578,7 +632,10 @@ char *hashMd5Hex(const int32 *hashmd5, void *dest) {
|
||||
}
|
||||
|
||||
void memset_rand(void *data, uint32 len) {
|
||||
_msInitialize();
|
||||
if (!_sslInited) {
|
||||
LOG(("Critical Error: memset_rand() called before OpenSSL init!"));
|
||||
exit(-1);
|
||||
}
|
||||
RAND_bytes((uchar*)data, len);
|
||||
}
|
||||
|
||||
|
||||
@@ -98,6 +98,12 @@ inline void mylocaltime(struct tm * _Tm, const time_t * _Time) {
|
||||
#endif
|
||||
}
|
||||
|
||||
class InitOpenSSL {
|
||||
public:
|
||||
InitOpenSSL();
|
||||
~InitOpenSSL();
|
||||
};
|
||||
|
||||
bool checkms(); // returns true if time has changed
|
||||
uint64 getms(bool checked = false);
|
||||
|
||||
@@ -225,51 +231,52 @@ QString translitRusEng(const QString &rus);
|
||||
QString rusKeyboardLayoutSwitch(const QString &from);
|
||||
|
||||
enum DataBlockId {
|
||||
dbiKey = 0,
|
||||
dbiUser = 1,
|
||||
dbiDcOption = 2,
|
||||
dbiMaxGroupCount = 3,
|
||||
dbiMutePeer = 4,
|
||||
dbiSendKey = 5,
|
||||
dbiAutoStart = 6,
|
||||
dbiStartMinimized = 7,
|
||||
dbiSoundNotify = 8,
|
||||
dbiWorkMode = 9,
|
||||
dbiSeenTrayTooltip = 10,
|
||||
dbiDesktopNotify = 11,
|
||||
dbiAutoUpdate = 12,
|
||||
dbiLastUpdateCheck = 13,
|
||||
dbiWindowPosition = 14,
|
||||
dbiConnectionType = 15,
|
||||
dbiKey = 0x00,
|
||||
dbiUser = 0x01,
|
||||
dbiDcOption = 0x02,
|
||||
dbiMaxGroupCount = 0x03,
|
||||
dbiMutePeer = 0x04,
|
||||
dbiSendKey = 0x05,
|
||||
dbiAutoStart = 0x06,
|
||||
dbiStartMinimized = 0x07,
|
||||
dbiSoundNotify = 0x08,
|
||||
dbiWorkMode = 0x09,
|
||||
dbiSeenTrayTooltip = 0x0a,
|
||||
dbiDesktopNotify = 0x0b,
|
||||
dbiAutoUpdate = 0x0c,
|
||||
dbiLastUpdateCheck = 0x0d,
|
||||
dbiWindowPosition = 0x0e,
|
||||
dbiConnectionType = 0x0f,
|
||||
// 16 reserved
|
||||
dbiDefaultAttach = 17,
|
||||
dbiCatsAndDogs = 18,
|
||||
dbiReplaceEmojis = 19,
|
||||
dbiAskDownloadPath = 20,
|
||||
dbiDownloadPath = 21,
|
||||
dbiScale = 22,
|
||||
dbiEmojiTab = 23,
|
||||
dbiRecentEmojisOld = 24,
|
||||
dbiLoggedPhoneNumber = 25,
|
||||
dbiMutedPeers = 26,
|
||||
dbiDefaultAttach = 0x11,
|
||||
dbiCatsAndDogs = 0x12,
|
||||
dbiReplaceEmojis = 0x13,
|
||||
dbiAskDownloadPath = 0x14,
|
||||
dbiDownloadPath = 0x15,
|
||||
dbiScale = 0x16,
|
||||
dbiEmojiTab = 0x17,
|
||||
dbiRecentEmojisOld = 0x18,
|
||||
dbiLoggedPhoneNumber = 0x19,
|
||||
dbiMutedPeers = 0x1a,
|
||||
// 27 reserved
|
||||
dbiNotifyView = 28,
|
||||
dbiSendToMenu = 29,
|
||||
dbiCompressPastedImage = 30,
|
||||
dbiLang = 31,
|
||||
dbiLangFile = 32,
|
||||
dbiTileBackground = 33,
|
||||
dbiAutoLock = 34,
|
||||
dbiDialogLastPath = 35,
|
||||
dbiRecentEmojis = 36,
|
||||
dbiEmojiVariants = 37,
|
||||
dbiNotifyView = 0x1c,
|
||||
dbiSendToMenu = 0x1d,
|
||||
dbiCompressPastedImage = 0x1e,
|
||||
dbiLang = 0x1f,
|
||||
dbiLangFile = 0x20,
|
||||
dbiTileBackground = 0x21,
|
||||
dbiAutoLock = 0x22,
|
||||
dbiDialogLastPath = 0x23,
|
||||
dbiRecentEmojis = 0x24,
|
||||
dbiEmojiVariants = 0x25,
|
||||
dbiRecentStickers = 0x26,
|
||||
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
dbiEncryptedWithSalt = 333,
|
||||
dbiEncrypted = 444,
|
||||
|
||||
// 500-600 reserved
|
||||
|
||||
dbiVersion = 666,
|
||||
dbiVersion = 666,
|
||||
};
|
||||
|
||||
enum DBISendKey {
|
||||
|
||||
@@ -381,6 +381,9 @@ _connecting(0), _clearManager(0), dragging(false), _inactivePress(false), _shoul
|
||||
connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive()));
|
||||
|
||||
connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock()));
|
||||
|
||||
connect(this, SIGNAL(imageLoaded()), this, SLOT(update()));
|
||||
connect(this, SIGNAL(imageLoaded()), this, SLOT(notifyUpdateAllPhotos()));
|
||||
}
|
||||
|
||||
void Window::inactivePress(bool inactive) {
|
||||
@@ -609,7 +612,7 @@ void Window::sendServiceHistoryRequest() {
|
||||
}
|
||||
|
||||
void Window::setupMain(bool anim, const MTPUser *self) {
|
||||
Local::readRecentStickers();
|
||||
Local::readStickers();
|
||||
|
||||
QPixmap bg = anim ? myGrab(this, QRect(0, st::titleHeight, width(), height() - st::titleHeight)) : QPixmap();
|
||||
clearWidgets();
|
||||
|
||||
@@ -219,7 +219,6 @@ public:
|
||||
void notifyItemRemoved(HistoryItem *item);
|
||||
void notifyStopHiding();
|
||||
void notifyStartHiding();
|
||||
void notifyUpdateAllPhotos();
|
||||
void notifyUpdateAll();
|
||||
void notifyActivateAll();
|
||||
|
||||
@@ -270,6 +269,8 @@ public slots:
|
||||
|
||||
QImage iconWithCounter(int size, int count, style::color bg, bool smallIcon);
|
||||
|
||||
void notifyUpdateAllPhotos();
|
||||
|
||||
signals:
|
||||
|
||||
void resized(const QSize &size);
|
||||
@@ -277,6 +278,8 @@ signals:
|
||||
void tempDirClearFailed(int task);
|
||||
void newAuthorization();
|
||||
|
||||
void imageLoaded();
|
||||
|
||||
private:
|
||||
|
||||
void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color);
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.8.12</string>
|
||||
<string>0.8.14</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleURLTypes</key>
|
||||
|
||||
@@ -74,6 +74,7 @@
|
||||
<PrecompiledHeaderOutputFile>$(IntDir)$(TargetName).pch</PrecompiledHeaderOutputFile>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalOptions>/Zm110 %(AdditionalOptions)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
@@ -376,6 +377,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_stickersetbox.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_switcher.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -634,6 +639,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_stickersetbox.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_switcher.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">true</ExcludedFromBuild>
|
||||
@@ -917,6 +926,10 @@
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_stickersetbox.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_switcher.cpp">
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">true</ExcludedFromBuild>
|
||||
@@ -965,6 +978,7 @@
|
||||
<ClCompile Include="SourceFiles\boxes\photocropbox.cpp" />
|
||||
<ClCompile Include="SourceFiles\boxes\photosendbox.cpp" />
|
||||
<ClCompile Include="SourceFiles\boxes\sessionsbox.cpp" />
|
||||
<ClCompile Include="SourceFiles\boxes\stickersetbox.cpp" />
|
||||
<ClCompile Include="SourceFiles\boxes\usernamebox.cpp" />
|
||||
<ClCompile Include="SourceFiles\dialogswidget.cpp" />
|
||||
<ClCompile Include="SourceFiles\dropdown.cpp" />
|
||||
@@ -1354,6 +1368,20 @@
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/abstractbox.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="SourceFiles\boxes\stickersetbox.h">
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">Moc%27ing stickersetbox.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Deploy|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/stickersetbox.h" -DAL_LIBTYPE_STATIC -DCUSTOM_API_ID -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing stickersetbox.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/stickersetbox.h" -DAL_LIBTYPE_STATIC -DUNICODE -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
<AdditionalInputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(QTDIR)\bin\moc.exe;%(FullPath)</AdditionalInputs>
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Moc%27ing stickersetbox.h...</Message>
|
||||
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
|
||||
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp" "-fstdafx.h" "-f../../SourceFiles/boxes/stickersetbox.h" -DAL_LIBTYPE_STATIC -DUNICODE -D_WITH_DEBUG -DWIN32 -DWIN64 -DHAVE_STDINT_H -DZLIB_WINAPI -DQT_NO_DEBUG -DNDEBUG "-I.\..\..\Libraries\lzma\C" "-I.\..\..\Libraries\libexif-0.6.20" "-I.\..\..\Libraries\zlib-1.2.8" "-I.\..\..\Libraries\OpenSSL-Win32\include" "-I.\..\..\Libraries\libogg-1.3.2\include" "-I.\..\..\Libraries\opus\include" "-I.\..\..\Libraries\opusfile\include" "-I.\..\..\Libraries\openal-soft\include" "-I.\SourceFiles" "-I.\GeneratedFiles" "-I." "-I$(QTDIR)\include" "-I.\GeneratedFiles\$(ConfigurationName)\." "-I.\..\..\Libraries\QtStatic\qtbase\include\QtCore\5.4.0\QtCore" "-I.\..\..\Libraries\QtStatic\qtbase\include\QtGui\5.4.0\QtGui"</Command>
|
||||
</CustomBuild>
|
||||
<ClInclude Include="SourceFiles\config.h" />
|
||||
<CustomBuild Include="SourceFiles\gui\animation.h">
|
||||
<Message Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Moc%27ing animation.h...</Message>
|
||||
|
||||
@@ -879,6 +879,18 @@
|
||||
<ClCompile Include="SourceFiles\structs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Deploy\moc_stickersetbox.cpp">
|
||||
<Filter>Generated Files\Deploy</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Debug\moc_stickersetbox.cpp">
|
||||
<Filter>Generated Files\Debug</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GeneratedFiles\Release\moc_stickersetbox.cpp">
|
||||
<Filter>Generated Files\Release</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SourceFiles\boxes\stickersetbox.cpp">
|
||||
<Filter>boxes</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SourceFiles\stdafx.h">
|
||||
@@ -1168,6 +1180,9 @@
|
||||
<CustomBuild Include="SourceFiles\intro\intropwdcheck.h">
|
||||
<Filter>intro</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="SourceFiles\boxes\stickersetbox.h">
|
||||
<Filter>boxes</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="SourceFiles\art\icon256.ico" />
|
||||
|
||||
@@ -1687,7 +1687,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.12;
|
||||
CURRENT_PROJECT_VERSION = 0.8.14;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
@@ -1705,7 +1705,7 @@
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
CURRENT_PROJECT_VERSION = 0.8.12;
|
||||
CURRENT_PROJECT_VERSION = 0.8.14;
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
|
||||
@@ -1731,10 +1731,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.12;
|
||||
CURRENT_PROJECT_VERSION = 0.8.14;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.8;
|
||||
DYLIB_CURRENT_VERSION = 0.8.12;
|
||||
DYLIB_CURRENT_VERSION = 0.8.14;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
@@ -1873,10 +1873,10 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_IDENTITY = "";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 0.8.12;
|
||||
CURRENT_PROJECT_VERSION = 0.8.14;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DYLIB_COMPATIBILITY_VERSION = 0.8;
|
||||
DYLIB_CURRENT_VERSION = 0.8.12;
|
||||
DYLIB_CURRENT_VERSION = 0.8.14;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
FRAMEWORK_SEARCH_PATHS = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
echo 8012 0.8.12 1
|
||||
echo 8014 0.8.14 1
|
||||
# AppVersion AppVersionStr DevChannel
|
||||
|
||||