This commit is contained in:
John Preston 2015-04-25 16:55:12 +03:00
commit 67b46d9aac
78 changed files with 2361 additions and 1592 deletions

View File

@ -516,7 +516,7 @@
6DB9C3763D02B1415CD9D565 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
LastUpgradeCheck = 0630;
};
buildConfigurationList = DAC4C1AA5EDEA1C85E9CA5E6 /* Build configuration list for PBXProject "MetaStyle" */;
compatibilityVersion = "Xcode 3.2";
@ -603,6 +603,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
@ -691,6 +692,7 @@
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;

View File

@ -1,9 +1,9 @@
@echo OFF
set "AppVersion=8004"
set "AppVersionStrSmall=0.8.4"
set "AppVersionStr=0.8.4"
set "AppVersionStrFull=0.8.4.0"
set "AppVersion=8007"
set "AppVersionStrSmall=0.8.7"
set "AppVersionStr=0.8.7"
set "AppVersionStrFull=0.8.7.0"
set "DevChannel=0"
if %DevChannel% neq 0 goto preparedev

View File

@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:No messages found|Found # message|Found # messages}";
"lng_search_global_results" = "Global search results";
"lng_mediaview_save" = "Download";
"lng_media_save_progress" = "{ready} of {total} {mb}";
"lng_mediaview_save_as" = "Save As..";
"lng_mediaview_copy" = "Copy";
"lng_mediaview_forward" = "Forward";
"lng_mediaview_delete" = "Delete";
"lng_mediaview_photos_all" = "View all photos";
"lng_mediaview_files_all" = "View all files";
"lng_mediaview_single_photo" = "Single Photo";
"lng_mediaview_group_photo" = "Group Photo";
"lng_mediaview_profile_photo" = "Profile Photo";
"lng_mediaview_file_n_of_count" = "{file} {n} of {count}";
"lng_mediaview_n_of_count" = "Photo {n} of {count}";
"lng_mediaview_doc_image" = "File";
"lng_mediaview_today" = "today at {time}";
@ -545,7 +550,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" = "— Link previews for Twitter, YouTube, Instagram and certain other links\n— Two-step verification\n— View all your Telegram sessions, terminate specific sessions";
"lng_new_version_text" = "— New photo viewer design\n— Switch between files in the photo viewer\n— Grouped notifications when several messages are forwarded\n— New default chat background image (you can change it in Settings)";
"lng_menu_insert_unicode" = "Insert Unicode control character";

View File

@ -831,7 +831,8 @@ msgLinkColor: #2a6dc2;
msgPressedLinkColor: #004bad;
msgSkip: 40px;
msgPtr: 8px;
msgBG: ':/gui/art/bg.png' / 2:':/gui/art/bg_125x.png' / 3:':/gui/art/bg_150x.png' / 4:':/gui/art/bg_200x.png';
msgBG: ':/gui/art/bg.jpg';
msgBG0: ':/gui/art/bg0.png';
msgSendingRect: sprite(260px, 20px, 20px, 20px);
msgCheckRect: sprite(320px, 0px, 20px, 20px);
@ -1361,12 +1362,16 @@ connectingBG: #fffe;
connectingColor: #777;
connectingPadding: margins(5px, 5px, 5px, 5px);
dropdownPadding: margins(10px, 10px, 10px, 10px);
dropdownShadow: sprite(241px, 46px, 6px, 6px);
dropdownBorder: 1px;
dropdownBorderColor: #ebebeb;
dropdownBackground: white;
dropdownDuration: 150;
dropdownDef: dropdown {
border: 1px;
borderColor: #ebebeb;
padding: margins(10px, 10px, 10px, 10px);
shadow: sprite(241px, 46px, 6px, 6px);
duration: 150;
width: 0px;
}
dropdownAttachDocument: iconedButton(btnAttachDocument) {
iconPos: point(14px, 13px);
@ -1555,18 +1560,92 @@ stickerPanPadding: 2px;
stickerPanDelete: sprite(158px, 197px, 12px, 12px);
stickerPanDeleteOpacity: 0.5;
medviewNavBarWidth: 132px;
medviewLightNav: 0.5;
medviewDarkNav: 1;
medviewHeaderFont: font(semibold 18px);
medviewNameFont: font(16px);
medviewDateFont: font(14px);
medviewNameTop: 13px;
medviewDateTop: 39px;
medviewLeft: sprite(340px, 79px, 28px, 48px);
medviewRight: sprite(368px, 79px, 28px, 48px);
medviewDeltaFromLastAction: 5px;
medviewSwipeDistance: 80px;
mvBgColor: #222;
mvBgOpacity: 0.92;
mvThickFont: font(fsize semibold);
mvFont: font(fsize);
mvTextLeft: 16px;
mvTextSkip: 10px;
mvHeaderTop: 48px;
mvTextTop: 24px;
mvTextColor: white;
mvTextOpacity: 0.5;
mvTextOverOpacity: 1;
mvIconOpacity: 0.45;
mvIconOverOpacity: 1;
mvControlBgColor: black;
mvControlBgOpacity: 0.3;
mvControlMargin: 0px;
mvControlSize: 90px;
mvIconSize: size(60px, 56px);
mvLeft: sprite(320px, 400px, 12px, 22px);
mvRight: sprite(332px, 400px, 12px, 22px);
mvClose: sprite(344px, 400px, 18px, 18px);
mvSave: sprite(362px, 400px, 14px, 19px);
mvMore: sprite(376px, 400px, 5px, 21px);
mvDropdown: dropdown(dropdownDef) {
shadow: sprite(0px, 0px, 0px, 0px);
padding: margins(11px, 12px, 11px, 12px);
border: 0;
width: 182px;
}
mvButton: iconedButton(btnDefIconed) {
bgColor: #383838;
overBgColor: #505050;
font: font(fsize);
opacity: 1;
overOpacity: 1;
width: -32px;
height: 36px;
color: white;
textPos: point(16px, 9px);
downTextPos: point(16px, 10px);
duration: 0;
}
mvContextButton: iconedButton(mvButton) {
bgColor: #383838E6;
overBgColor: #505050E7;
}
mvWaitHide: 2000;
mvHideDuration: 1000;
mvShowDuration: 200;
mvFadeDuration: 150;
mvDocPadding: 18px;
mvDocSize: size(340px, 116px);
mvDocBg: white;
mvDocNameTop: 4px;
mvDocNameFont: font(semibold 14px);
mvDocNameColor: black;
mvDocSizeTop: 29px;
mvDocSizeColor: #808080;
mvDocExtTop: 35px;
mvDocExtFont: font(semibold 18px);
mvDocExtColor: white;
mvDocExtPadding: 10px;
mvDocLinksTop: 57px;
mvDocRed: sprite(0px, 400px, 80px, 80px);
mvDocYellow: sprite(80px, 400px, 80px, 80px);
mvDocGreen: sprite(160px, 400px, 80px, 80px);
mvDocBlue: sprite(240px, 400px, 80px, 80px);
mvDocLink: linkButton(btnDefLink) {
color: #4595d3;
overColor: #4595d3;
downColor: #4595d3;
}
mvDeltaFromLastAction: 5px;
mvSwipeDistance: 80px;
medviewSaveMsgCheck: sprite(341px, 174px, 22px, 18px);
medviewSaveMsgFont: font(16px);
@ -1578,87 +1657,7 @@ medviewSaveMsgShown: 2000;
medviewSaveMsgHiding: 2500;
medviewSaveMsg: #000000b2;
medviewOverview: iconedButton(btnDefIconed) {
bgColor: #0000;
overBgColor: #00000040;
font: font(16px);
opacity: 0.77;
overOpacity: 1;
icon: sprite(340px, 129px, 19px, 19px);
iconPos: point(16px, 14px);
downIcon: sprite(340px, 129px, 19px, 19px);
downIconPos: point(16px, 14px);
width: -69px;
height: 47px;
color: white;
textPos: point(51px, 13px);
downTextPos: point(51px, 14px);
}
medviewForward: iconedButton(medviewOverview) {
icon: sprite(357px, 58px, 22px, 17px);
iconPos: point(16px, 15px);
downIcon: sprite(357px, 58px, 22px, 17px);
downIconPos: point(16px, 15px);
width: -69px;
}
medviewDelete: iconedButton(medviewForward) {
icon: sprite(340px, 58px, 15px, 19px);
iconPos: point(16px, 14px);
downIcon: sprite(340px, 58px, 15px, 19px);
downIconPos: point(16px, 14px);
}
medviewClose: iconedButton(medviewOverview) {
icon: sprite(340px, 0px, 56px, 56px);
iconPos: point(0px, 0px);
downIcon: sprite(340px, 0px, 56px, 56px);
downIconPos: point(0px, 0px);
opacity: 0.6;
width: 56px;
height: 56px;
}
medviewBottomBar: 87px;
medviewBG: #272727D9;
medviewBottomBG: #272727;
medviewNavOpacity: 0.6;
medviewCloseOpacity: 0.6;
medviewNavBGOpacity: 0.4;
medviewNavOverOpacity: 1;
medviewCloseOverOpacity: 1;
medviewNameColor: black;
medviewDateColor: #999;
medviewSaveAs: iconedButton(medviewOverview) {
bgColor: #38abe6;
overBgColor: #299fdc;
opacity: 1;
icon: sprite(361px, 129px, 12px, 19px);
iconPos: point(18px, 15px);
downIcon: sprite(361px, 129px, 12px, 19px);
downIconPos: point(18px, 15px);
width: -62px;
height: 47px;
textPos: point(44px, 13px);
downTextPos: point(44px, 14px);
}
medviewSaveAsDisabledOpacity: 0.8;
medviewPolaroid: margins(17px, 18px, 17px, 72px);
medviewPolaroidMin: size(480px, 360px);
medviewDocumentSprite: sprite(341px, 150px, 20px, 22px);
medviewDocumentSpritePos: point(16px, 13px);
medviewPhotoSprite: sprite(363px, 150px, 23px, 20px);
medviewPhotoSpritePos: point(14px, 14px);
medviewTransparentBrush: sprite(148px, 197px, 8px, 8px);
mvTransparentBrush: sprite(148px, 197px, 8px, 8px);
overviewPhotoSkip: 10px;
overviewPhotoMinSize: 100px;
@ -1704,6 +1703,16 @@ photoLoaderDuration1: 150; // ms fade in
photoLoaderDuration2: 150; // ms fade out
photoLoaderAlphaMin: 0.1; // not less than that
radialSize: size(50px, 50px);
radialLine: 2px;
radialDuration: 350;
radialPeriod: 3000;
radialBgOpacity: 0.4;
radialDownload: sprite(346px, 0px, 50px, 50px);
radialDownloadOpacity: 0.8;
radialCancel: sprite(378px, 50px, 18px, 18px);
radialCancelOpacity: 0.7;
overviewLoader: size(34px, 14px);
overviewLoaderPoint: size(4px, 4px);
overviewLoaderSkip: 4px;

View File

@ -246,3 +246,14 @@ switcher {
duration: number;
}
dropdown {
border: number;
borderColor: color;
padding: margins;
shadow: sprite;
duration: number;
width: number;
}

View File

@ -448,6 +448,7 @@ static const char *variantNames[] = { "dbisOne", "dbisOneAndQuarter", "dbisOneAn
static const char *variantPostfixes[] = { "", "_125x", "_150x", "_200x" };
QPixmap *spriteMax = 0;
QImage *variantSprites = 0;
int *spriteWidths = 0;
QImage *variantGrids = 0;
void readStyleGenToken(const char *&from, const char *end, StyleGenTokenType &tokenType, string &token) {
@ -1353,17 +1354,22 @@ bool genStyles(const QString &classes_in, const QString &classes_out, const QStr
}
QImage sprites[variantsCount];
int widths[variantsCount] = { 0 };
variantSprites = sprites;
spriteWidths = widths;
QString sprite0(path_to_sprites + "sprite" + QString(variantPostfixes[0]) + ".png"), spriteLast(path_to_sprites + "sprite" + QString(variantPostfixes[variantsCount - 1]) + ".png");
variantSprites[0] = QImage(sprite0);
spriteWidths[0] = variantSprites[0].width();
for (int i = 1; i < variantsCount - 1; ++i) {
variantSprites[i] = QImage(adjustPx(variants[i], variantSprites[0].width(), true), adjustPx(variants[i], variantSprites[0].height(), true), QImage::Format_ARGB32_Premultiplied);
spriteWidths[i] = variantSprites[i].width();
QPainter p(&variantSprites[i]);
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(0, 0, variantSprites[i].width(), variantSprites[i].height(), Qt::transparent);
}
variantSprites[variantsCount - 1] = QImage(spriteLast);
spriteWidths[variantsCount - 1] = variantSprites[variantsCount - 1].width();
QPixmap spriteMaxPix = QPixmap::fromImage(variantSprites[variantsCount - 1], Qt::ColorOnly);
spriteMax = &spriteMaxPix;
@ -1567,11 +1573,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\
tcpp << "\nnamespace style {\n\n";
tcpp << "\tFontFamilies _fontFamilies;\n";
tcpp << "\tFontDatas _fontsMap;\n";
tcpp << "\tColorDatas _colorsMap;\n\n";
tcpp << "\tColorDatas _colorsMap;\n";
tcpp << "int _spriteWidth = " << spriteWidths[0] << ";\n\n";
tcpp << "\tvoid startManager() {\n";
tcpp << "\n\t\tif (cRetina()) {\n";
tcpp << "\t\t\tcSetRealScale(dbisOne);\n\n";
tcpp << "\t\t\tcSetRealScale(dbisOne);\n";
tcpp << "\t\t\t_spriteWidth = " << spriteWidths[variantsCount - 1] << ";\n\n";
for (int i = 0, l = scalars.size(); i < l; ++i) {
Scalar &sc(scalars[i]);
if (sc.second.first == scSprite || sc.first == "spriteFile" || sc.first == "emojisFile" || sc.first == "emojiImgSize") {
@ -1594,6 +1602,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org\n\
const char *varName = variantNames[i];
tcpp << "\t\tcase " << varName << ":\n";
tcpp << "\t\t\t_spriteWidth = " << spriteWidths[i] << ";\n\n";
typedef QMap<string, int> FontFamilies;
FontFamilies fontFamilies;

View File

@ -1515,7 +1515,11 @@ namespace App {
audioInit();
if (!::sprite) {
::sprite = new QPixmap(st::spriteFile);
if (rtl()) {
::sprite = new QPixmap(QPixmap::fromImage(QImage(st::spriteFile).mirrored(true, false)));
} else {
::sprite = new QPixmap(st::spriteFile);
}
if (cRetina()) ::sprite->setDevicePixelRatio(cRetinaFactor());
}
if (!::emojis) {
@ -1598,11 +1602,11 @@ namespace App {
return ::mousedItem;
}
QPixmap &sprite() {
const QPixmap &sprite() {
return *::sprite;
}
QPixmap &emojis() {
const QPixmap &emojis() {
return *::emojis;
}
@ -1808,16 +1812,29 @@ namespace App {
if (Local::readBackground()) return;
QImage img(p);
bool remove = false;
if (p.isNull()) {
img.load(st::msgBG);
id = 0;
if (id == DefaultChatBackground) {
img.load(st::msgBG);
} else {
img.load(st::msgBG0);
if (cRetina()) {
img = img.scaledToWidth(img.width() * 2, Qt::SmoothTransformation);
} else if (cScale() != dbisOne) {
img = img.scaledToWidth(convertScale(img.width()), Qt::SmoothTransformation);
}
id = 0;
}
remove = true;
}
if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_ARGB32_Premultiplied && img.format() != QImage::Format_RGB32) {
img = img.convertToFormat(QImage::Format_RGB32);
}
img.setDevicePixelRatio(cRetinaFactor());
if (!nowrite) Local::writeBackground(id, img);
if (!nowrite) {
Local::writeBackground(id, remove ? QImage() : img);
}
delete cChatBackground();
cSetChatBackground(new QPixmap(QPixmap::fromImage(img, Qt::ColorOnly)));

View File

@ -154,8 +154,8 @@ namespace App {
void mousedItem(HistoryItem *item);
HistoryItem *mousedItem();
QPixmap &sprite();
QPixmap &emojis();
const QPixmap &sprite();
const QPixmap &emojis();
const QPixmap &emojiSingle(const EmojiData *emoji, int32 fontHeight);
void initMedia();
@ -196,7 +196,7 @@ namespace App {
void openUserByName(const QString &username, bool toProfile = false);
void openLocalUrl(const QString &url);
void initBackground(int32 id = 0, const QImage &p = QImage(), bool nowrite = false);
void initBackground(int32 id = DefaultChatBackground, const QImage &p = QImage(), bool nowrite = false);
style::color msgServiceBG();
style::color historyScrollBarColor();

View File

@ -59,7 +59,15 @@ namespace {
if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) {
App::wnd()->minimizeToTray();
return true;
} else {
App::wnd()->hide();
App::wnd()->updateIsActive(cOfflineBlurTimeout());
App::wnd()->updateGlobalMenu();
return true;
}
} else if (ev->key() == Qt::Key_M && (ev->modifiers() & (Qt::MetaModifier | Qt::ControlModifier))) {
App::wnd()->setWindowState(Qt::WindowMinimized);
return true;
}
}
return QObject::eventFilter(o, e);
@ -654,10 +662,10 @@ void Application::checkMapVersion() {
psRegisterCustomScheme();
if (Local::oldMapVersion()) {
QString versionFeatures;
if (DevChannel && Local::oldMapVersion() < 8002) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Link previews bugfixes\n\xe2\x80\x94 Links in preview descriptions are now clickable\n\xe2\x80\x94 Twitter and Instagram mentions and hashtags in previews are clickable\n\xe2\x80\x94 Fixed file uploading\n\xe2\x80\x94 Fixed photo, document and sticker forwarding").replace('@', qsl("@") + QChar(0x200D));
} else if (!DevChannel && Local::oldMapVersion() < 8004) {
versionFeatures = lang(lng_new_version_minor).trimmed();
if (DevChannel && Local::oldMapVersion() < 8006) {
versionFeatures = QString::fromUtf8("\xe2\x80\x94 Old default chat background image placed first in background Gallery\n\xe2\x80\x94 Forwarded files, videos, audios and contacts original sender name is displayed\n\xe2\x80\x94 Grouped notifications when several messages are forwarded").replace('@', qsl("@") + QChar(0x200D));
} else if (!DevChannel && Local::oldMapVersion() < 8007) {
versionFeatures = lang(lng_new_version_text).trimmed();
}
if (!versionFeatures.isEmpty()) {
versionFeatures = lng_new_version_wrap(lt_version, QString::fromStdWString(AppVersionStr), lt_changes, versionFeatures, lt_link, qsl("https://desktop.telegram.org/#changelog"));
@ -672,6 +680,8 @@ void Application::startApp() {
DEBUG_LOG(("Application Info: starting app.."));
QMimeDatabase().mimeTypeForName(qsl("text/plain")); // create mime database
window->createWinId();
window->init();

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 KiB

View File

Before

Width:  |  Height:  |  Size: 197 KiB

After

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 354 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 208 KiB

View File

@ -71,7 +71,7 @@ void AbstractBox::paintTitle(Painter &p, const QString &title, bool withShadow)
// paint box title
p.setFont(st::boxTitleFont->f);
p.setPen(st::black->p);
p.drawTextLeft(st::boxTitlePos.x(), st::boxTitlePos.y(), width() - 2 * st::boxTitlePos.x(), title);
p.drawTextLeft(st::boxTitlePos.x(), st::boxTitlePos.y(), width(), title);
}
void AbstractBox::paintGrayTitle(QPainter &p, const QString &title) {
@ -106,8 +106,10 @@ void AbstractBox::setMaxHeight(int32 maxHeight) {
void AbstractBox::resizeMaxHeight(int32 newWidth, int32 maxHeight) {
if (width() != newWidth || _maxHeight != maxHeight) {
QRect g(geometry());
_maxHeight = maxHeight;
resize(newWidth, countHeight());
if (parentWidget()) parentWidget()->update(geometry().united(g).marginsAdded(QMargins(st::boxShadow.pxWidth(), st::boxShadow.pxHeight(), st::boxShadow.pxWidth(), st::boxShadow.pxHeight())));
}
}

View File

@ -37,7 +37,7 @@ _bgCount(0), _rows(0), _over(-1), _overDown(-1) {
void BackgroundInner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
App::WallPapers wallpapers;
wallpapers.push_back(App::WallPaper(0, ImagePtr(st::msgBG), ImagePtr(st::msgBG)));
wallpapers.push_back(App::WallPaper(0, ImagePtr(st::msgBG0), ImagePtr(st::msgBG0)));
const QVector<MTPWallPaper> &v(result.c_vector().v);
for (int i = 0, l = v.size(); i < l; ++i) {
const MTPWallPaper w(v.at(i));
@ -78,7 +78,7 @@ void BackgroundInner::gotWallpapers(const MTPVector<MTPWallPaper> &result) {
}
}
if (thumb && full && full->type() != mtpc_photoSizeEmpty) {
wallpapers.push_back(App::WallPaper(d.vid.v, App::image(*thumb), App::image(*full)));
wallpapers.push_back(App::WallPaper(d.vid.v ? d.vid.v : INT_MAX, App::image(*thumb), App::image(*full)));
}
} break;

View File

@ -37,7 +37,7 @@ void SessionsInner::paintEvent(QPaintEvent *e) {
p.fillRect(r, st::white->b);
p.setFont(st::linkFont->f);
int32 x = st::sessionPadding.left(), xact = st::sessionTerminateSkip + st::sessionTerminate.iconPos.x();// st::sessionTerminateSkip + st::sessionTerminate.width + st::sessionTerminateSkip;
int32 w = width() - 2 * x, availw = width() - 2 * xact;
int32 w = width();
int32 from = (r.top() >= 0) ? qFloor(r.top() / st::sessionHeight) : 0, count = _list->size();
if (from < count) {
int32 to = (r.bottom() >= 0 ? qFloor(r.bottom() / st::sessionHeight) : 0) + 1;
@ -52,7 +52,7 @@ void SessionsInner::paintEvent(QPaintEvent *e) {
p.setFont(st::sessionActiveFont->f);
p.setPen(st::sessionActiveColor->p);
p.drawTextRight(xact, st::sessionPadding.top(), availw, auth.active, auth.activeWidth);
p.drawTextRight(xact, st::sessionPadding.top(), w, auth.active, auth.activeWidth);
p.setFont(st::sessionInfoFont->f);
p.setPen(st::black->p);
@ -132,7 +132,7 @@ void SessionsInner::listUpdated() {
j = _terminateButtons.insert(_list->at(i).hash, new IconedButton(this, st::sessionTerminate));
connect(j.value(), SIGNAL(clicked()), this, SLOT(onTerminate()));
}
j.value()->moveToRight(st::sessionTerminateSkip, i * st::sessionHeight + st::sessionTerminateTop, width() - 2 * st::sessionTerminateSkip);
j.value()->moveToRight(st::sessionTerminateSkip, i * st::sessionHeight + st::sessionTerminateTop, width());
}
for (TerminateButtons::iterator i = _terminateButtons.begin(); i != _terminateButtons.cend();) {
if (i.value()->y() >= 0) {
@ -175,7 +175,7 @@ _terminateAll(this, lang(lng_sessions_terminate_all)), _terminateBox(0), _shortP
void SessionsBox::resizeEvent(QResizeEvent *e) {
ScrollableBox::resizeEvent(e);
_done.move(0, height() - _done.height());
_terminateAll.moveToRight(st::sessionPadding.left(), st::boxTitleHeight + st::sessionHeight + st::boxTitlePos.y() + st::boxTitleFont->ascent - st::linkFont->ascent, width() - 2 * st::sessionPadding.left());
_terminateAll.moveToRight(st::sessionPadding.left(), st::boxTitleHeight + st::sessionHeight + st::boxTitlePos.y() + st::boxTitleFont->ascent - st::linkFont->ascent, width());
}
void SessionsBox::hideAll() {
@ -212,7 +212,7 @@ void SessionsBox::paintEvent(QPaintEvent *e) {
p.drawText(QRect(0, 0, width(), st::noContactsHeight), lang(lng_contacts_loading), style::al_center);
} else {
int32 x = st::sessionPadding.left();
int32 w = width() - x - st::sessionPadding.right();
int32 w = width();
p.setFont(st::sessionNameFont->f);
p.setPen(st::black->p);

View File

@ -17,8 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
static const int32 AppVersion = 8004;
static const wchar_t *AppVersionStr = L"0.8.4";
static const int32 AppVersion = 8007;
static const wchar_t *AppVersionStr = L"0.8.7";
static const bool DevChannel = false;
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
@ -255,6 +255,8 @@ static const char *DefaultCountry = "US";
static const char *DefaultLanguage = "en";
enum {
DefaultChatBackground = 21,
DialogsFirstLoad = 20, // first dialogs part size requested
DialogsPerPage = 40, // next dialogs part size
@ -279,8 +281,8 @@ enum {
UploadRequestInterval = 500, // one part each half second, if not uploaded faster
MaxPhotosInMemory = 50, // try to clear some memory after 50 photos are created
NoUpdatesTimeout = 180 * 1000, // if nothing is received in 3 min we getDifference
NoUpdatesAfterSleepTimeout = 60 * 1000, // if nothing is received in 1 min when was a sleepmode we getDifference
NoUpdatesTimeout = 60 * 1000, // if nothing is received in 1 min we ping
NoUpdatesAfterSleepTimeout = 60 * 1000, // if nothing is received in 1 min when was a sleepmode we ping
WaitForSkippedTimeout = 1000, // 1s wait for skipped seq or pts in updates
MemoryForImageCache = 64 * 1024 * 1024, // after 64mb of unpacked images we try to clear some memory

View File

@ -67,11 +67,11 @@ void DialogsListWidget::paintEvent(QPaintEvent *e) {
QRect r(e->rect());
bool trivial = (rect() == r);
QPainter p(this);
Painter p(this);
if (!trivial) {
p.setClipRect(r);
}
if (_state == DefaultState) {
int32 otherStart = dialogs.list.count * st::dlgHeight;
PeerData *active = App::main()->activePeer(), *selected = sel ? sel->history->peer : 0;

View File

@ -26,8 +26,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "window.h"
#include "apiwrap.h"
Dropdown::Dropdown(QWidget *parent) : TWidget(parent),
_hiding(false), a_opacity(0), _shadow(st::dropdownShadow) {
Dropdown::Dropdown(QWidget *parent, const style::dropdown &st) : TWidget(parent),
_ignore(false), _selected(-1), _st(st), _width(_st.width), _hiding(false), a_opacity(0), _shadow(_st.shadow) {
resetButtons();
_hideTimer.setSingleShot(true);
@ -38,6 +38,10 @@ Dropdown::Dropdown(QWidget *parent) : TWidget(parent),
}
}
void Dropdown::ignoreShow(bool ignore) {
_ignore = ignore;
}
void Dropdown::onWndActiveChanged() {
if (!App::wnd()->windowHandle()->isActive() && !isHidden()) {
leaveEvent(0);
@ -47,13 +51,21 @@ void Dropdown::onWndActiveChanged() {
IconedButton *Dropdown::addButton(IconedButton *button) {
button->setParent(this);
_width = qMax(_width, st::dropdownPadding.left() + st::dropdownPadding.right() + button->width());
if (!_buttons.isEmpty()) {
_height += st::dropdownBorder;
int32 nw = _st.padding.left() + _st.padding.right() + button->width();
if (nw > _width) {
_width = nw;
for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - _st.padding.left() - _st.padding.right(), _buttons[i]->height());
} else {
button->resize(_width - _st.padding.left() - _st.padding.right(), button->height());
}
if (!button->isHidden()) {
if (_height > _st.padding.top() + _st.padding.bottom()) {
_height += _st.border;
}
_height += button->height();
}
_height += button->height();
_buttons.push_back(button);
connect(button, SIGNAL(stateChanged(int, ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int, ButtonStateChangeSource)));
resize(_width, _height);
@ -61,20 +73,39 @@ IconedButton *Dropdown::addButton(IconedButton *button) {
}
void Dropdown::resetButtons() {
_width = st::dropdownPadding.left() + st::dropdownPadding.right();
_height = st::dropdownPadding.top() + st::dropdownPadding.bottom();
resize(_width, _height);
_width = qMax(_st.padding.left() + _st.padding.right(), int(_st.width));
_height = _st.padding.top() + _st.padding.bottom();
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
delete _buttons[i];
}
_buttons.clear();
resize(_width, _height);
_selected = -1;
}
void Dropdown::updateButtons() {
int32 top = _st.padding.top(), starttop = top;
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
if (!(*i)->isHidden()) {
(*i)->move(_st.padding.left(), top);
if ((*i)->width() != _width - _st.padding.left() - _st.padding.right()) {
(*i)->resize(_width - _st.padding.left() - _st.padding.right(), (*i)->height());
}
top += (*i)->height() + _st.border;
}
}
_height = top + _st.padding.bottom() - (top > starttop ? _st.border : 0);
resize(_width, _height);
}
void Dropdown::resizeEvent(QResizeEvent *e) {
int32 top = st::dropdownPadding.top();
int32 top = _st.padding.top();
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
(*i)->move(st::dropdownPadding.left(), top);
top += st::dropdownBorder + (*i)->height();
if (!(*i)->isHidden()) {
(*i)->move(_st.padding.left(), top);
top += (*i)->height() + _st.border;
}
}
}
@ -85,16 +116,24 @@ void Dropdown::paintEvent(QPaintEvent *e) {
p.setOpacity(a_opacity.current());
}
QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom());
// draw shadow
QRect r(_st.padding.left(), _st.padding.top(), _width - _st.padding.left() - _st.padding.right(), _height - _st.padding.top() - _st.padding.bottom());
_shadow.paint(p, r);
if (!_buttons.isEmpty()) { // paint separators
int32 top = st::dropdownPadding.top() + _buttons.front()->height();
p.setPen(st::dropdownBorderColor->p);
for (int32 i = 1, s = _buttons.size(); i < s; ++i) {
p.fillRect(st::dropdownPadding.left(), top, _width - st::dropdownPadding.left() - st::dropdownPadding.right(), st::dropdownBorder, st::dropdownBorderColor->b);
top += st::dropdownBorder + _buttons[i]->height();
if (!_buttons.isEmpty() && _st.border > 0) { // paint separators
p.setPen(_st.borderColor->p);
int32 top = _st.padding.top(), i = 0, l = _buttons.size();
for (; i < l; ++i) {
if (!_buttons.at(i)->isHidden()) break;
}
if (i < l) {
top += _buttons.at(i)->height();
for (++i; i < l; ++i) {
if (!_buttons.at(i)->isHidden()) {
p.fillRect(_st.padding.left(), top, _width - _st.padding.left() - _st.padding.right(), _st.border, _st.borderColor->b);
top += _st.border + _buttons.at(i)->height();
}
}
}
}
}
@ -102,6 +141,7 @@ void Dropdown::paintEvent(QPaintEvent *e) {
void Dropdown::enterEvent(QEvent *e) {
_hideTimer.stop();
if (_hiding) showStart();
return TWidget::enterEvent(e);
}
void Dropdown::leaveEvent(QEvent *e) {
@ -110,6 +150,73 @@ void Dropdown::leaveEvent(QEvent *e) {
} else {
_hideTimer.start(300);
}
return TWidget::leaveEvent(e);
}
void Dropdown::keyPressEvent(QKeyEvent *e) {
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) {
if (_selected >= 0 && _selected < _buttons.size()) {
emit _buttons[_selected]->clicked();
return;
}
} else if (e->key() == Qt::Key_Escape) {
hideStart();
return;
}
if ((e->key() != Qt::Key_Up && e->key() != Qt::Key_Down) || _buttons.size() < 1) return;
bool none = (_selected < 0 || _selected >= _buttons.size());
int32 delta = (e->key() == Qt::Key_Down ? 1 : -1);
int32 newSelected = none ? (e->key() == Qt::Key_Down ? 0 : _buttons.size() - 1) : (_selected + delta);
if (newSelected < 0) {
newSelected = _buttons.size() - 1;
} else if (newSelected >= _buttons.size()) {
newSelected = 0;
}
int32 startFrom = newSelected;
while (_buttons.at(newSelected)->isHidden()) {
newSelected += delta;
if (newSelected < 0) {
newSelected = _buttons.size() - 1;
} else if (newSelected >= _buttons.size()) {
newSelected = 0;
}
if (newSelected == startFrom) return;
}
if (!none) {
_buttons[_selected]->setOver(false);
}
_selected = newSelected;
_buttons[_selected]->setOver(true);
}
void Dropdown::buttonStateChanged(int oldState, ButtonStateChangeSource source) {
if (source == ButtonByUser) {
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
if (_buttons[i]->getState() & Button::StateOver) {
if (i != _selected) {
_buttons[i]->setOver(false);
}
}
}
} else if (source == ButtonByHover) {
bool found = false;
for (int32 i = 0, l = _buttons.size(); i < l; ++i) {
if (_buttons[i]->getState() & Button::StateOver) {
found = true;
if (i != _selected) {
int32 sel = _selected;
_selected = i;
if (sel >= 0 && sel < _buttons.size()) {
_buttons[sel]->setOver(false);
}
}
}
}
if (!found) {
_selected = -1;
}
}
}
void Dropdown::otherEnter() {
@ -147,13 +254,19 @@ void Dropdown::hideStart() {
}
void Dropdown::hideFinish() {
emit hiding();
hide();
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
(*i)->clearState();
}
_selected = -1;
}
void Dropdown::showStart() {
if (!isHidden() && a_opacity.current() == 1) {
return;
}
_selected = -1;
_hiding = false;
show();
a_opacity.start(1);
@ -161,7 +274,7 @@ void Dropdown::showStart() {
}
bool Dropdown::animStep(float64 ms) {
float64 dt = ms / st::dropdownDuration;
float64 dt = ms / _st.duration;
bool res = true;
if (dt >= 1) {
a_opacity.finish();
@ -312,7 +425,7 @@ void DragArea::showStart() {
}
bool DragArea::animStep(float64 ms) {
float64 dt = ms / st::dropdownDuration;
float64 dt = ms / st::dropdownDef.duration;
bool res = true;
if (dt >= 1) {
a_opacity.finish();
@ -648,7 +761,7 @@ void EmojiPanInner::showEmojiPack(DBIEmojiTab packIndex) {
}
EmojiPan::EmojiPan(QWidget *parent) : TWidget(parent),
_hiding(false), a_opacity(0), _shadow(st::dropdownShadow),
_hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow),
_recent (this, qsl("emoji_group"), dbietRecent , QString(), cEmojiTab() == dbietRecent , st::rbEmojiRecent),
_people (this, qsl("emoji_group"), dbietPeople , QString(), cEmojiTab() == dbietPeople , st::rbEmojiPeople),
_nature (this, qsl("emoji_group"), dbietNature , QString(), cEmojiTab() == dbietNature , st::rbEmojiNature),
@ -665,15 +778,15 @@ _scroll(this, st::emojiScroll), _inner() {
_inner.showEmojiPack(cEmojiTab());
}
_scroll.setGeometry(st::dropdownPadding.left() + st::emojiPanPadding.left(), st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
_scroll.setGeometry(st::dropdownDef.padding.left() + st::emojiPanPadding.left(), st::dropdownDef.padding.top() + _recent.height() + st::emojiPanPadding.top(), st::emojiPanPadding.left() + _inner.width() + st::emojiPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
_scroll.setWidget(&_inner);
_width = st::dropdownPadding.left() + st::emojiPanPadding.left() + _scroll.width() + st::emojiPanPadding.right() + st::dropdownPadding.right();
_height = st::dropdownPadding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownPadding.bottom();
_width = st::dropdownDef.padding.left() + st::emojiPanPadding.left() + _scroll.width() + st::emojiPanPadding.right() + st::dropdownDef.padding.right();
_height = st::dropdownDef.padding.top() + _recent.height() + st::emojiPanPadding.top() + _scroll.height() + st::emojiPanPadding.bottom() + st::dropdownDef.padding.bottom();
resize(_width, _height);
int32 left = st::dropdownPadding.left() + (_width - st::dropdownPadding.left() - st::dropdownPadding.right() - 7 * _recent.width()) / 2;
int32 top = st::dropdownPadding.top();
int32 left = st::dropdownDef.padding.left() + (_width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right() - 7 * _recent.width()) / 2;
int32 top = st::dropdownDef.padding.top();
_recent.move(left, top); left += _recent.width();
_people.move(left, top); left += _people.width();
_nature.move(left, top); left += _nature.width();
@ -716,7 +829,7 @@ void EmojiPan::paintEvent(QPaintEvent *e) {
p.setOpacity(a_opacity.current());
}
QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom());
QRect r(st::dropdownDef.padding.left(), st::dropdownDef.padding.top(), _width - st::dropdownDef.padding.left() - st::dropdownDef.padding.right(), _height - st::dropdownDef.padding.top() - st::dropdownDef.padding.bottom());
// draw shadow
_shadow.paint(p, r);
@ -765,7 +878,7 @@ void EmojiPan::fastHide() {
}
bool EmojiPan::animStep(float64 ms) {
float64 dt = ms / st::dropdownDuration;
float64 dt = ms / st::dropdownDef.duration;
bool res = true;
if (dt >= 1) {
a_opacity.finish();
@ -786,7 +899,7 @@ bool EmojiPan::animStep(float64 ms) {
void EmojiPan::hideStart() {
if (_cache.isNull()) {
showAll();
_cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
_cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
}
hideAll();
_hiding = true;
@ -806,7 +919,7 @@ void EmojiPan::showStart() {
}
if (_cache.isNull()) {
showAll();
_cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
_cache = myGrab(this, rect().marginsRemoved(st::dropdownDef.padding));
}
hideAll();
_hiding = false;
@ -1048,7 +1161,7 @@ void MentionsInner::onParentGeometryChanged() {
}
MentionsDropdown::MentionsDropdown(QWidget *parent) : QWidget(parent),
_scroll(this, st::mentionScroll), _inner(this, &_rows, &_hrows), _chat(0), _hiding(false), a_opacity(0), _shadow(st::dropdownShadow) {
_scroll(this, st::mentionScroll), _inner(this, &_rows, &_hrows), _chat(0), _hiding(false), a_opacity(0), _shadow(st::dropdownDef.shadow) {
_hideTimer.setSingleShot(true);
connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
connect(&_inner, SIGNAL(chosen(QString)), this, SIGNAL(chosen(QString)));
@ -1235,7 +1348,7 @@ void MentionsDropdown::showStart() {
}
bool MentionsDropdown::animStep(float64 ms) {
float64 dt = ms / st::dropdownDuration;
float64 dt = ms / st::dropdownDef.duration;
bool res = true;
if (dt >= 1) {
a_opacity.finish();
@ -1284,330 +1397,3 @@ bool MentionsDropdown::eventFilter(QObject *obj, QEvent *e) {
MentionsDropdown::~MentionsDropdown() {
}
//StickerPanInner::StickerPanInner(QWidget *parent) : QWidget(parent), _emoji(0), _selected(-1), _pressedSel(-1) {
// resize(StickerPadPerRow * st::stickerPanSize.width(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
// setMouseTracking(true);
// setFocusPolicy(Qt::NoFocus);
//}
//
//void StickerPanInner::paintEvent(QPaintEvent *e) {
// QPainter p(this);
// int32 size = _stickers.size();
//
// QRect r = e ? e->rect() : rect();
//
// int32 rows = (size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0);
// int32 fromrow = qMax(qFloor(r.top() / st::stickerPanSize.height()), 0), torow = qMin(qCeil(r.bottom() / st::stickerPanSize.height()) + 1, rows);
// for (int32 i = fromrow; i < torow; ++i) {
// for (int32 j = 0; j < StickerPadPerRow; ++j) {
// int32 index = i * StickerPadPerRow + j;
// if (index >= size) break;
//
// float64 hover = _hovers[index];
// QPoint pos(j * st::stickerPanSize.width(), i * st::stickerPanSize.height());
// if (hover > 0) {
// p.setOpacity(hover);
// p.setBrush(st::stickerPanHover->b);
// p.setPen(Qt::NoPen);
// p.drawRoundedRect(QRect(pos, st::stickerPanSize), st::stickerPanRound, st::stickerPanRound);
// p.setOpacity(1);
// }
//
// DocumentData *data = _stickers[index];
// bool already = !data->already().isEmpty(), hasdata = !data->data.isEmpty();
// if (!data->loader && data->status != FileFailed && !already && !hasdata) {
// data->save(QString());
// }
// if (data->sticker->isNull() && (already || hasdata)) {
// if (already) {
// data->sticker = ImagePtr(data->already());
// } else {
// data->sticker = ImagePtr(data->data);
// }
// }
//
// float64 coef = qMin(st::stickerPanSize.width() / float64(data->dimensions.width()), st::stickerPanSize.height() / float64(data->dimensions.height()));
// int32 w = qRound(coef * data->dimensions.width()), h = qRound(coef * data->dimensions.height());
// pos += QPoint((st::stickerPanSize.width() - w) / 2, (st::stickerPanSize.height() - h) / 2);
//
// if (data->sticker->isNull()) {
// p.drawPixmap(pos, data->thumb->pix(w));
// } else {
// p.drawPixmap(pos, data->sticker->pix(w));
// }
// }
// }
//}
//
//void StickerPanInner::mousePressEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
// _pressedSel = _selected;
//}
//
//void StickerPanInner::mouseReleaseEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
// if (_selected == _pressedSel && _selected >= 0 && _selected < _stickers.size()) {
// emit stickerSelected(_stickers[_selected]);
// }
//}
//
//void StickerPanInner::mouseMoveEvent(QMouseEvent *e) {
// _lastMousePos = e->globalPos();
// updateSelected();
//}
//
//void StickerPanInner::leaveEvent(QEvent *e) {
// _lastMousePos = QCursor::pos();
// updateSelected();
//}
//
//void StickerPanInner::updateSelected() {
// int32 selIndex = -1;
// QPoint p(mapFromGlobal(_lastMousePos));
// if (p.x() >= 0 && p.y() >= 0 && p.x() < StickerPadPerRow * st::stickerPanSize.width()) {
// selIndex = qFloor(p.y() / st::stickerPanSize.height()) * StickerPadPerRow + qFloor(p.x() / st::stickerPanSize.width());
// if (selIndex >= _stickers.size()) {
// selIndex = -1;
// }
// }
// if (selIndex != _selected) {
// bool startanim = false;
// if (_selected >= 0) {
// _stickerAnimations.remove(_selected + 1);
// if (_stickerAnimations.find(-_selected - 1) == _stickerAnimations.end()) {
// if (_stickerAnimations.isEmpty()) startanim = true;
// _stickerAnimations.insert(-_selected - 1, getms());
// }
// }
// _selected = selIndex;
// if (_selected >= 0) {
// _stickerAnimations.remove(-_selected - 1);
// if (_stickerAnimations.find(_selected + 1) == _stickerAnimations.end()) {
// if (_stickerAnimations.isEmpty()) startanim = true;
// _stickerAnimations.insert(_selected + 1, getms());
// }
// }
// if (startanim) anim::start(this);
// setCursor((_selected >= 0) ? style::cur_pointer : style::cur_default);
// }
//}
//
//bool StickerPanInner::animStep(float64 ms) {
// uint64 now = getms();
// for (StickerAnimations::iterator i = _stickerAnimations.begin(); i != _stickerAnimations.end();) {
// float64 dt = float64(now - i.value()) / st::emojiPanDuration;
// if (dt >= 1) {
// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? 1 : 0;
// i = _stickerAnimations.erase(i);
// } else {
// _hovers[qAbs(i.key()) - 1] = (i.key() > 0) ? dt : (1 - dt);
// ++i;
// }
// }
// update();
// return !_stickerAnimations.isEmpty();
//}
//
//void StickerPanInner::showStickerPack(EmojiPtr emoji) {
// StickerPack stickers = cStickers().value(emoji);
// if (stickers.isEmpty()) {
// _emoji = 0;
// } else {
// _emoji = emoji;
// _stickers = stickers;
// _hovers = QVector<float64>(_stickers.size(), 0);
// _stickerAnimations.clear();
// _selected = _pressedSel = -1;
// int32 size = _stickers.size();
// int32 h = qMax(((size / StickerPadPerRow) + ((size % StickerPadPerRow) ? 1 : 0)) * st::stickerPanSize.height(), EmojiPadRowsPerPage * st::emojiPanSize.height() - int(st::emojiPanSub));
// resize(width(), h);
// _lastMousePos = QCursor::pos();
// updateSelected();
// update();
// }
//}
//
//bool StickerPanInner::hasContent() const {
// return !!_emoji;
//}
//
//StickerPan::StickerPan(QWidget *parent) : TWidget(parent),
//_hiding(false), a_opacity(0), _shadow(st::dropdownShadow),
//_scroll(this, st::emojiScroll), _emoji(0), _inner() {
// setFocusPolicy(Qt::NoFocus);
// _scroll.setFocusPolicy(Qt::NoFocus);
// _scroll.viewport()->setFocusPolicy(Qt::NoFocus);
//
// _inner.showStickerPack(0);
// _scroll.setGeometry(st::dropdownPadding.left() + st::stickerPanPadding.left(), st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top(), st::stickerPanPadding.left() + _inner.width() + st::stickerPanPadding.right(), EmojiPadRowsPerPage * st::emojiPanSize.height() - st::emojiPanSub);
// _scroll.setWidget(&_inner);
//
// _width = st::dropdownPadding.left() + st::stickerPanPadding.left() + _scroll.width() + st::stickerPanPadding.right() + st::dropdownPadding.right();
// _height = st::dropdownPadding.top() + st::rbEmoji.height + st::stickerPanPadding.top() + _scroll.height() + st::stickerPanPadding.bottom() + st::dropdownPadding.bottom();
// resize(_width, _height);
//
// _hideTimer.setSingleShot(true);
// connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(hideStart()));
//
// connect(&_scroll, SIGNAL(scrolled()), &_inner, SLOT(updateSelected()));
//
// connect(&_inner, SIGNAL(stickerSelected(DocumentData*)), this, SIGNAL(stickerSelected(DocumentData*)));
//}
//
//void StickerPan::setStickerPack(EmojiPtr emoji, bool show) {
// _emoji = emoji;
// _inner.showStickerPack(_emoji);
// if (!_hiding && !isHidden() && !_inner.hasContent()) {
// _hideTimer.stop();
// hideStart();
// } else if ((_hiding || isHidden()) && _inner.hasContent() && show) {
// _hideTimer.stop();
// showStart();
// }
//}
//
//void StickerPan::paintEvent(QPaintEvent *e) {
// QPainter p(this);
//
// if (!_cache.isNull()) {
// p.setOpacity(a_opacity.current());
// }
//
// QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom());
//
// // draw shadow
// _shadow.paint(p, r);
//
// if (_cache.isNull()) {
// p.fillRect(r, st::white->b);
//
// p.setFont(st::stickerPanFont->f);
// p.setPen(st::stickerPanColor->p);
// p.drawText(QRect(st::dropdownPadding.left(), st::dropdownPadding.top(), width() - st::dropdownPadding.left() - st::dropdownPadding.right(), st::rbEmoji.height), lang(lng_attach_stickers_header), style::al_center);
// } else {
// p.drawPixmap(r.left(), r.top(), _cache);
// }
//}
//
//void StickerPan::enterEvent(QEvent *e) {
// _hideTimer.stop();
// if (_hiding) showStart();
//}
//
//void StickerPan::leaveEvent(QEvent *e) {
// if (animating()) {
// hideStart();
// } else {
// _hideTimer.start(300);
// }
//}
//
//void StickerPan::otherEnter() {
// _hideTimer.stop();
// showStart();
//}
//
//void StickerPan::otherLeave() {
// if (animating()) {
// hideStart();
// } else {
// _hideTimer.start(0);
// }
//}
//
//void StickerPan::fastHide() {
// if (animating()) {
// anim::stop(this);
// }
// a_opacity = anim::fvalue(0, 0);
// _hideTimer.stop();
// hide();
// _cache = QPixmap();
//}
//
//bool StickerPan::animStep(float64 ms) {
// float64 dt = ms / st::dropdownDuration;
// bool res = true;
// if (dt >= 1) {
// a_opacity.finish();
// if (_hiding) {
// hideFinish();
// } else {
// showAll();
// _cache = QPixmap();
// }
// res = false;
// } else {
// a_opacity.update(dt, anim::linear);
// }
// update();
// return res;
//}
//
//void StickerPan::hideStart() {
// if (_cache.isNull()) {
// showAll();
// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
// }
// hideAll();
// _hiding = true;
// a_opacity.start(0);
// anim::start(this);
//}
//
//void StickerPan::hideFinish() {
// hide();
// _cache = QPixmap();
//}
//
//void StickerPan::showStart() {
// if (!isHidden() && a_opacity.current() == 1) {
// return;
// }
// if (!_inner.hasContent()) {
// return;
// }
// if (_cache.isNull()) {
// showAll();
// _cache = myGrab(this, rect().marginsRemoved(st::dropdownPadding));
// }
// hideAll();
// _hiding = false;
// show();
// a_opacity.start(1);
// anim::start(this);
//}
//
//bool StickerPan::eventFilter(QObject *obj, QEvent *e) {
// if (e->type() == QEvent::Enter) {
// if (dynamic_cast<EmojiPan*>(obj)) {
// enterEvent(e);
// } else {
// otherEnter();
// }
// } else if (e->type() == QEvent::Leave) {
// if (dynamic_cast<EmojiPan*>(obj)) {
// leaveEvent(e);
// } else {
// otherLeave();
// }
// } else if (e->type() == QEvent::MouseButtonPress && static_cast<QMouseEvent*>(e)->button() == Qt::LeftButton && !dynamic_cast<EmojiPan*>(obj)) {
// if (isHidden() || _hiding) {
// otherEnter();
// } else {
// otherLeave();
// }
// }
// return false;
//}
//
//void StickerPan::showAll() {
// _scroll.show();
//}
//
//void StickerPan::hideAll() {
// _scroll.hide();
//}

View File

@ -25,25 +25,32 @@ class Dropdown : public TWidget, public Animated {
public:
Dropdown(QWidget *parent);
Dropdown(QWidget *parent, const style::dropdown &st = st::dropdownDef);
IconedButton *addButton(IconedButton *button);
void resetButtons();
void updateButtons();
void resizeEvent(QResizeEvent *e);
void paintEvent(QPaintEvent *e);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
void keyPressEvent(QKeyEvent *e);
void otherEnter();
void otherLeave();
void fastHide();
void ignoreShow(bool ignore = true);
bool animStep(float64 ms);
bool eventFilter(QObject *obj, QEvent *e);
signals:
void hiding();
public slots:
void hideStart();
@ -52,13 +59,21 @@ public slots:
void showStart();
void onWndActiveChanged();
void buttonStateChanged(int oldState, ButtonStateChangeSource source);
private:
void adjustButtons();
bool _ignore;
typedef QVector<IconedButton*> Buttons;
Buttons _buttons;
int32 _selected;
const style::dropdown &_st;
int32 _width, _height;
bool _hiding;
@ -336,97 +351,3 @@ private:
BoxShadow _shadow;
};
//class StickerPanInner : public QWidget, 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);
//
// bool animStep(float64 ms);
//
// void showStickerPack(EmojiPtr emoji);
// bool hasContent() const;
//
//public slots:
//
// void updateSelected();
//
//signals:
//
// void stickerSelected(DocumentData *sticker);
//
//private:
//
// typedef QMap<int32, uint64> StickerAnimations; // index - showing, -index - hiding
// StickerAnimations _stickerAnimations;
//
// StickerPack _stickers;
// QVector<float64> _hovers;
//
// EmojiPtr _emoji;
// int32 _selected, _pressedSel;
// QPoint _lastMousePos;
//
//};
//
//class StickerPan : public TWidget, public Animated {
// Q_OBJECT
//
//public:
//
// StickerPan(QWidget *parent);
//
// void setStickerPack(EmojiPtr emoji, bool show);
// void paintEvent(QPaintEvent *e);
//
// void enterEvent(QEvent *e);
// void leaveEvent(QEvent *e);
// void otherEnter();
// void otherLeave();
//
// void fastHide();
//
// bool animStep(float64 ms);
//
// bool eventFilter(QObject *obj, QEvent *e);
//
//public slots:
//
// void hideStart();
// void hideFinish();
//
// void showStart();
//
//signals:
//
// void stickerSelected(DocumentData *sticker);
//
//private:
//
// void showAll();
// void hideAll();
//
// int32 _width, _height;
// bool _hiding;
// QPixmap _cache;
//
// anim::fvalue a_opacity;
//
// QTimer _hideTimer;
//
// BoxShadow _shadow;
//
// EmojiPtr _emoji;
// ScrollArea _scroll;
// StickerPanInner _inner;
//
//};

View File

@ -18,7 +18,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "stdafx.h"
#include "animation.h"
#include <QtCore/QTimer>
#include "mainwidget.h"
#include "window.h"
namespace {
AnimationManager *manager = 0;
@ -78,6 +80,11 @@ namespace anim {
manager->start(obj);
}
void step(Animated *obj) {
if (!manager) return;
manager->step(obj);
}
void stop(Animated *obj) {
if (!manager) return;
manager->stop(obj);
@ -94,3 +101,113 @@ namespace anim {
}
}
bool AnimatedGif::animStep(float64 ms) {
int32 f = frame;
while (f < frames.size() && ms > delays[f]) {
++f;
if (f == frames.size() && frames.size() < framesCount) {
if (reader->read(&img)) {
int64 d = reader->nextImageDelay(), delay = delays[f - 1];
if (!d) d = 1;
delay += d;
frames.push_back(QPixmap::fromImage(img.size() == QSize(w, h) ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly));
delays.push_back(delay);
for (int32 i = 0; i < frames.size(); ++i) {
if (!frames[i].isNull()) {
frames[i] = QPixmap();
break;
}
}
} else {
framesCount = frames.size();
}
}
if (f == frames.size()) {
if (!duration) {
duration = delays.isEmpty() ? 1 : delays.back();
}
f = 0;
for (int32 i = 0, s = delays.size() - 1; i <= s; ++i) {
delays[i] += duration;
}
if (frames[f].isNull()) {
QString fname = reader->fileName();
delete reader;
reader = new QImageReader(fname);
}
}
if (frames[f].isNull() && reader->read(&img)) {
frames[f] = QPixmap::fromImage(img.size() == QSize(w, h) ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly);
}
}
if (frame != f) {
frame = f;
if (msg && App::main()) {
App::main()->msgUpdated(msg->history()->peer->id, msg);
} else {
emit updated();
}
}
return true;
}
void AnimatedGif::start(HistoryItem *row, const QString &file) {
stop();
reader = new QImageReader(file);
if (!reader->canRead() || !reader->supportsAnimation()) {
stop();
return;
}
QSize s = reader->size();
w = s.width();
h = s.height();
framesCount = reader->imageCount();
if (!w || !h || !framesCount) {
stop();
return;
}
frames.reserve(framesCount);
delays.reserve(framesCount);
int32 sizeLeft = MediaViewImageSizeLimit, delay = 0;
for (bool read = reader->read(&img); read; read = reader->read(&img)) {
sizeLeft -= w * h * 4;
frames.push_back(QPixmap::fromImage(img.size() == s ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly));
int32 d = reader->nextImageDelay();
if (!d) d = 1;
delay += d;
delays.push_back(delay);
if (sizeLeft < 0) break;
}
msg = row;
anim::start(this);
if (msg) {
msg->initDimensions();
if (App::main()) App::main()->itemResized(msg, true);
}
}
void AnimatedGif::stop(bool onItemRemoved) {
if (isNull()) return;
delete reader;
reader = 0;
HistoryItem *row = msg;
msg = 0;
frames.clear();
delays.clear();
w = h = frame = framesCount = duration = 0;
anim::stop(this);
if (row && !onItemRemoved) {
row->initDimensions();
if (App::main()) App::main()->itemResized(row, true);
}
}

View File

@ -185,6 +185,7 @@ namespace anim {
};
void start(Animated *obj);
void step(Animated *obj);
void stop(Animated *obj);
void startManager();
@ -248,6 +249,23 @@ public:
obj->animInProcess = true;
}
void step(Animated *obj) {
if (iterating) return;
float64 ms = float64(getms());
AnimObjs::iterator i = objs.find(obj);
if (i != objs.cend()) {
Animated *obj = *i;
if (!obj->animStep(ms - obj->animStarted)) {
objs.erase(i);
if (!objs.size()) {
timer.stop();
}
obj->animInProcess = false;
}
}
}
void stop(Animated *obj) {
if (iterating) {
toStop.insert(obj);
@ -307,3 +325,39 @@ private:
bool iterating;
};
class HistoryItem;
class AnimatedGif : public QObject, public Animated {
Q_OBJECT
public:
AnimatedGif() : msg(0), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
}
bool animStep(float64 ms);
void start(HistoryItem *row, const QString &file);
void stop(bool onItemRemoved = false);
bool isNull() const {
return !reader;
}
~AnimatedGif() {
stop(true);
}
signals:
void updated();
public:
HistoryItem *msg;
QImage img;
QImageReader *reader;
QVector<QPixmap> frames;
QVector<int64> delays;
int32 w, h, frame, framesCount, duration;
};

View File

@ -20,11 +20,14 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "boxshadow.h"
BoxShadow::BoxShadow(const style::rect &topLeft) : _size(topLeft.width() / cIntRetinaFactor()) {
if (!_size) return;
QImage cornersImage(_size * 2, _size * 2, QImage::Format_ARGB32_Premultiplied);
{
QPainter p(&cornersImage);
p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft);
p.drawPixmap(QPoint(rtl() ? _size : 0, 0), App::sprite(), topLeft);
}
if (rtl()) cornersImage = cornersImage.mirrored(true, false);
uchar *bits = cornersImage.bits();
if (bits) {
for (
@ -58,6 +61,8 @@ BoxShadow::BoxShadow(const style::rect &topLeft) : _size(topLeft.width() / cIntR
}
void BoxShadow::paint(QPainter &p, const QRect &box, const QPoint &shift, int32 flags) {
if (!_size) return;
int32 count = _colors.size(), minus = _size - count + 1;
bool left = (flags & Left), top = (flags & Top), right = (flags & Right), bottom = (flags & Bottom);
if (left && top) p.drawPixmap(box.left() - _size + minus + shift.x(), box.top() - _size + minus + shift.y(), _corners, 0, 0, _size, _size);

View File

@ -77,6 +77,7 @@ void Button::mouseReleaseEvent(QMouseEvent *e) {
}
void Button::setOver(bool over, ButtonStateChangeSource source) {
// LOG(("Set over: %1, by: %2 AT %3").arg(logBool(over)).arg(source).arg(dynamic_cast<IconedButton*>(this) ? dynamic_cast<IconedButton*>(this)->getText() : qsl("Unknown")));
if (over && !(_state & StateOver)) {
int oldState = _state;
_state |= StateOver;

View File

@ -25,8 +25,8 @@
#include "lang.h"
ContextMenu::ContextMenu(QWidget *parent, const style::iconedButton &st) : TWidget(0),
_hiding(false), _buttonStyle(st), _shadow(st::dropdownShadow), _selected(-1), a_opacity(0), _deleteOnHide(false) {
ContextMenu::ContextMenu(QWidget *parent, const style::dropdown &st, const style::iconedButton &btnst) : TWidget(0),
_width(st.width), _hiding(false), _st(st), _btnst(btnst), _shadow(_st.shadow), _selected(-1), a_opacity(0), _deleteOnHide(false) {
resetActions();
setWindowFlags(Qt::FramelessWindowHint | Qt::BypassWindowManagerHint | Qt::Tool | Qt::NoDropShadowWindowHint | Qt::WindowStaysOnTopHint);
@ -43,13 +43,13 @@ QAction *ContextMenu::addAction(const QString &text, const QObject *receiver, co
connect(a, SIGNAL(changed()), this, SLOT(actionChanged()));
IconedButton *b = 0;
_buttons.push_back(b = new IconedButton(this, _buttonStyle, a->text()));
_buttons.push_back(b = new IconedButton(this, _btnst, a->text()));
connect(b, SIGNAL(clicked()), this, SLOT(hideStart()));
connect(b, SIGNAL(clicked()), a, SIGNAL(triggered()));
connect(b, SIGNAL(stateChanged(int,ButtonStateChangeSource)), this, SLOT(buttonStateChanged(int,ButtonStateChangeSource)));
_width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + b->width()));
for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height());
_width = qMax(_width, int(_st.padding.left() + _st.padding.right() + b->width()));
for (int32 i = 0, l = _buttons.size(); i < l; ++i) _buttons[i]->resize(_width - int(_st.padding.left() + _st.padding.right()), _buttons[i]->height());
_height += b->height();
resize(_width, _height);
@ -64,8 +64,8 @@ ContextMenu::Actions &ContextMenu::actions() {
void ContextMenu::actionChanged() {
for (int32 i = 0, l = _actions.size(); i < l; ++i) {
_buttons[i]->setText(_actions[i]->text());
_width = qMax(_width, int(st::dropdownPadding.left() + st::dropdownPadding.right() + _buttons[i]->width()));
_buttons[i]->resize(_width - int(st::dropdownPadding.left() + st::dropdownPadding.right()), _buttons[i]->height());
_width = qMax(_width, int(_st.padding.left() + _st.padding.right() + _buttons[i]->width()));
_buttons[i]->resize(_width - int(_st.padding.left() + _st.padding.right()), _buttons[i]->height());
}
}
@ -100,8 +100,8 @@ void ContextMenu::buttonStateChanged(int oldState, ButtonStateChangeSource sourc
}
void ContextMenu::resetActions() {
_width = st::dropdownPadding.left() + st::dropdownPadding.right();
_height = st::dropdownPadding.top() + st::dropdownPadding.bottom();
_width = qMax(_st.padding.left() + _st.padding.right(), int(_st.width));
_height = _st.padding.top() + _st.padding.bottom();
resize(_width, _height);
clearActions();
@ -122,9 +122,9 @@ void ContextMenu::clearActions() {
}
void ContextMenu::resizeEvent(QResizeEvent *e) {
int32 top = st::dropdownPadding.top();
int32 top = _st.padding.top();
for (Buttons::const_iterator i = _buttons.cbegin(), e = _buttons.cend(); i != e; ++i) {
(*i)->move(st::dropdownPadding.left(), top);
(*i)->move(_st.padding.left(), top);
top += (*i)->height();
}
}
@ -132,6 +132,7 @@ void ContextMenu::resizeEvent(QResizeEvent *e) {
void ContextMenu::paintEvent(QPaintEvent *e) {
QPainter p(this);
p.setClipRect(e->rect());
QPainter::CompositionMode m = p.compositionMode();
p.setCompositionMode(QPainter::CompositionMode_Source);
p.fillRect(e->rect(), st::transparent->b);
@ -141,7 +142,7 @@ void ContextMenu::paintEvent(QPaintEvent *e) {
p.setOpacity(a_opacity.current());
}
QRect r(st::dropdownPadding.left(), st::dropdownPadding.top(), _width - st::dropdownPadding.left() - st::dropdownPadding.right(), _height - st::dropdownPadding.top() - st::dropdownPadding.bottom());
QRect r(_st.padding.left(), _st.padding.top(), _width - _st.padding.left() - _st.padding.right(), _height - _st.padding.top() - _st.padding.bottom());
// draw shadow
_shadow.paint(p, r);
}
@ -245,13 +246,19 @@ void ContextMenu::deleteOnHide() {
}
void ContextMenu::popup(const QPoint &p) {
QPoint w = p - QPoint(st::dropdownPadding.left(), st::dropdownPadding.top());
QPoint w = p - QPoint(_st.padding.left(), _st.padding.top());
QRect r = App::app() ? App::app()->desktop()->screenGeometry(p) : QDesktopWidget().screenGeometry(p);
if (w.x() + width() - st::dropdownPadding.right() > r.x() + r.width()) {
w.setX(r.x() + r.width() - width() + st::dropdownPadding.right());
if (rtl()) {
if (w.x() - width() + 2 * _st.padding.left() < r.x() - _st.padding.left()) {
w.setX(r.x() - _st.padding.left());
} else {
w.setX(w.x() - width() + 2 * _st.padding.left());
}
} else if (w.x() + width() - _st.padding.right() > r.x() + r.width()) {
w.setX(r.x() + r.width() - width() + _st.padding.right());
}
if (w.y() + height() - st::dropdownPadding.bottom() > r.y() + r.height()) {
w.setY(p.y() - height() + st::dropdownPadding.bottom());
if (w.y() + height() - _st.padding.bottom() > r.y() + r.height()) {
w.setY(p.y() - height() + _st.padding.bottom());
}
if (w.y() < r.y()) {
w.setY(r.y());

View File

@ -25,7 +25,7 @@ class ContextMenu : public TWidget, public Animated {
public:
ContextMenu(QWidget *parent, const style::iconedButton &st = st::btnContext);
ContextMenu(QWidget *parent, const style::dropdown &st = st::dropdownDef, const style::iconedButton &btnst = st::btnContext);
QAction *addAction(const QString &text, const QObject *receiver, const char* member);
void resetActions();
@ -72,7 +72,8 @@ private:
int32 _width, _height;
bool _hiding;
const style::iconedButton &_buttonStyle;
const style::dropdown &_st;
const style::iconedButton &_btnst;
BoxShadow _shadow;
int32 _selected;

View File

@ -172,16 +172,26 @@ void IconedButton::setText(const QString &text) {
}
}
QString IconedButton::getText() const {
return _text;
}
bool IconedButton::animStep(float64 ms) {
float64 dt = ms / _st.duration;
bool res = true;
if (dt >= 1) {
if (_st.duration <= 1) {
a_opacity.finish();
a_bg.finish();
res = false;
} else {
a_opacity.update(dt, anim::linear);
a_bg.update(dt, anim::linear);
float64 dt = ms / _st.duration;
if (dt >= 1) {
a_opacity.finish();
a_bg.finish();
res = false;
} else {
a_opacity.update(dt, anim::linear);
a_bg.update(dt, anim::linear);
}
}
update();
return res;

View File

@ -100,6 +100,7 @@ public:
void setOpacity(float64 o);
void setText(const QString &text);
QString getText() const;
public slots:

View File

@ -26,6 +26,13 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include <QtGui/QCursor>
#include <QtGui/QFont>
inline QRect rtlrect(int x, int y, int w, int h, int outerw) {
return rtl() ? QRect(outerw - x - w, y, w, h) : QRect(x, y, w, h);
}
inline QRect centerrect(const QRect &inRect, const QRect &rect) {
return QRect(inRect.x() + (inRect.width() - rect.width()) / 2, inRect.y() + (inRect.height() - rect.height()) / 2, rect.width(), rect.height());
}
namespace style {
class FontData;
@ -197,14 +204,17 @@ inline bool operator!=(const Font &a, const Font &b) {
typedef QMap<uint32, ColorData*> ColorDatas;
extern ColorDatas _colorsMap;
extern int _spriteWidth;
typedef float64 number;
typedef QString string;
typedef QRect rect;
class sprite : public rect {
class sprite : public rect {
public:
sprite() {
}
sprite(int left, int top, int width, int height) : rect(left, top, width, height) {
sprite(int left, int top, int width, int height) : rect(rtl() ? (_spriteWidth - left - width) : left, top, width, height) {
}
inline int pxWidth() const {
return rect::width() / cIntRetinaFactor();
@ -260,3 +270,7 @@ inline bool operator!=(const Font &a, const Font &b) {
void stopManager();
};
inline QRect centersprite(const QRect &inRect, const style::sprite &sprite) {
return centerrect(inRect, QRect(QPoint(0, 0), sprite.pxSize()));
}

View File

@ -24,8 +24,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
namespace {
const QRegularExpression _reDomain(QString::fromUtf8("(?<![A-Za-z\\$0-9А-Яа-яёЁ\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"));
const QRegularExpression _reExplicitDomain(QString::fromUtf8("(?<![A-Za-z\\$0-9А-Яа-яёЁ\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){0,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"));
const QRegularExpression _reDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)?((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){1,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression _reExplicitDomain(QString::fromUtf8("(?<![\\w\\$\\-\\_%=\\.])(?:([a-zA-Z]+)://)((?:[A-Za-zА-яА-ЯёЁ0-9\\-\\_]+\\.){0,5}([A-Za-zрф\\-\\d]{2,22})(\\:\\d+)?)"), QRegularExpression::UseUnicodePropertiesOption);
const QRegularExpression _reMailName(qsl("[a-zA-Z\\-_\\.0-9]{1,256}$"));
const QRegularExpression _reMailStart(qsl("^[a-zA-Z\\-_\\.0-9]{1,256}\\@"));
const QRegularExpression _reHashtag(qsl("(^|[\\s\\.,:;<>|'\"\\[\\]\\{\\}`\\~\\!\\%\\^\\*\\(\\)\\-\\+=\\x10])#[\\w]{2,64}([\\W]|$)"), QRegularExpression::UseUnicodePropertiesOption);
@ -887,7 +887,7 @@ public:
_align = align;
_parDirection = _t->_startDir;
if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = langDir();
if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = cLangDir();
if ((*_t->_blocks.cbegin())->type() != TextBlockNewline) {
initNextParagraph(_t->_blocks.cbegin());
}
@ -926,7 +926,7 @@ public:
}
_parDirection = static_cast<NewlineBlock*>(b)->nextDirection();
if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = langDir();
if (_parDirection == Qt::LayoutDirectionAuto) _parDirection = cLangDir();
initNextParagraph(i + 1);
longWordLine = true;
@ -2613,7 +2613,7 @@ QString Text::original(uint16 selectedFrom, uint16 selectedTo, bool expandLinks)
result += r;
} else {
QUrl u(url);
if (r.size() > 3 && _text.midRef(lnkFrom, r.size() - 3) == (u.isValid() ? u.toDisplayString() : url).midRef(0, r.size() - 3)) { // same link
if (r.size() <= 3 || _text.midRef(lnkFrom, r.size() - 3) == (u.isValid() ? u.toDisplayString() : url).midRef(0, r.size() - 3)) { // same link
result += url;
} else {
result.append(r).append(qsl(" ( ")).append(url).append(qsl(" )"));
@ -4090,7 +4090,7 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich) { // some
initLinkSets();
int32 len = text.size(), nextCmd = rich ? 0 : len;
const QChar *start = text.unicode(), *end = start + text.size();
for (int32 offset = 0, matchOffset = offset; offset < len;) {
for (int32 offset = 0, matchOffset = offset, mentionSkip = 0; offset < len;) {
if (nextCmd <= offset) {
for (nextCmd = offset; nextCmd < len; ++nextCmd) {
if (*(start + nextCmd) == TextCommand) {
@ -4101,8 +4101,7 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich) { // some
QRegularExpressionMatch mDomain = _reDomain.match(text, matchOffset);
QRegularExpressionMatch mExplicitDomain = _reExplicitDomain.match(text, matchOffset);
QRegularExpressionMatch mHashtag = withHashtags ? _reHashtag.match(text, matchOffset) : QRegularExpressionMatch();
QRegularExpressionMatch mMention = withMentions ? _reMention.match(text, matchOffset) : QRegularExpressionMatch();
if (!mDomain.hasMatch() && !mExplicitDomain.hasMatch() && !mHashtag.hasMatch() && !mMention.hasMatch()) break;
QRegularExpressionMatch mMention = withMentions ? _reMention.match(text, qMax(mentionSkip, matchOffset)) : QRegularExpressionMatch();
LinkRange link;
int32 domainOffset = mDomain.hasMatch() ? mDomain.capturedStart() : INT_MAX,
@ -4121,7 +4120,7 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich) { // some
--hashtagEnd;
}
}
if (mMention.hasMatch()) {
while (mMention.hasMatch()) {
if (!mMention.capturedRef(1).isEmpty()) {
++mentionOffset;
}
@ -4129,10 +4128,21 @@ LinkRanges textParseLinks(const QString &text, int32 flags, bool rich) { // some
--mentionEnd;
}
if (!(start + mentionOffset + 1)->isLetter() || !(start + mentionEnd - 1)->isLetterOrNumber()) {
mentionOffset = mentionEnd = INT_MAX;
if (!mDomain.hasMatch() && !mExplicitDomain.hasMatch() && !mHashtag.hasMatch()) break;
mentionSkip = mentionEnd;
mMention = _reMention.match(text, qMax(mentionSkip, matchOffset));
if (mMention.hasMatch()) {
mentionOffset = mMention.capturedStart();
mentionEnd = mMention.capturedEnd();
} else {
mentionOffset = INT_MAX;
mentionEnd = INT_MAX;
}
} else {
break;
}
}
if (!mMention.hasMatch() && !mDomain.hasMatch() && !mExplicitDomain.hasMatch() && !mHashtag.hasMatch()) break;
if (explicitDomainOffset < domainOffset) {
domainOffset = explicitDomainOffset;
domainEnd = explicitDomainEnd;

View File

@ -20,9 +20,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "application.h"
namespace {
Qt::LayoutDirection _dir = Qt::LeftToRight;
bool _rtl = false;
void _sendResizeEvents(QWidget *target) {
QResizeEvent e(target->size(), QSize());
QApplication::sendEvent(target, &e);
@ -37,19 +34,6 @@ namespace {
}
}
void rtl(bool is) {
_rtl = is;
_dir = _rtl ? Qt::RightToLeft : Qt::LeftToRight;
}
bool rtl() {
return _rtl;
}
Qt::LayoutDirection langDir() { // current lang dependent
return _dir;
}
QPixmap myGrab(QWidget *target, const QRect &rect) {
if (!cRetina()) return target->grab(rect);

View File

@ -17,38 +17,71 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
void rtl(bool is);
bool rtl();
Qt::LayoutDirection langDir();
class Widget : public QWidget {
public:
Widget(QWidget *parent = 0) : QWidget(parent) {
}
void moveToLeft(int x, int y, int w) {
move(rtl() ? (x + w - width()) : x, y);
void moveToLeft(int x, int y, int outerw) {
move(rtl() ? (outerw - x - width()) : x, y);
}
void moveToRight(int x, int y, int w) {
move(rtl() ? x : (x + w - width()), y);
void moveToRight(int x, int y, int outerw) {
move(rtl() ? x : (outerw - x - width()), y);
}
};
namespace App {
const QPixmap &sprite();
}
class Painter : public QPainter {
public:
explicit Painter(QPaintDevice *device) : QPainter(device) {
}
void drawTextLeft(int x, int y, int w, const QString &text, int textWidth = -1) {
void drawTextLeft(int x, int y, int outerw, const QString &text, int textWidth = -1) {
QFontMetrics m(fontMetrics());
if (rtl() && textWidth < 0) textWidth = m.width(text);
drawText(x + (rtl() ? (w - textWidth) : 0), y + m.ascent(), text);
drawText(rtl() ? (outerw - x - textWidth) : x, y + m.ascent(), text);
}
void drawTextRight(int x, int y, int w, const QString &text, int textWidth = -1) {
void drawTextRight(int x, int y, int outerw, const QString &text, int textWidth = -1) {
QFontMetrics m(fontMetrics());
if (!rtl() && textWidth < 0) textWidth = m.width(text);
drawText(x + (rtl() ? 0 : (w - textWidth)), y + m.ascent(), text);
drawText(rtl() ? x : (outerw - x - textWidth), y + m.ascent(), text);
}
void drawPixmapLeft(int x, int y, int outerw, const QPixmap &pix, const QRect &from) {
drawPixmap(QPoint(rtl() ? (outerw - x - (from.width() / pix.devicePixelRatio())) : x, y), pix, from);
}
void drawPixmapLeft(const QPoint &p, int outerw, const QPixmap &pix, const QRect &from) {
return drawPixmapLeft(p.x(), p.y(), outerw, pix, from);
}
void drawPixmapRight(int x, int y, int outerw, const QPixmap &pix, const QRect &from) {
drawPixmap(QPoint(rtl() ? x : (outerw - x - (from.width() / pix.devicePixelRatio())), y), pix, from);
}
void drawPixmapRight(const QPoint &p, int outerw, const QPixmap &pix, const QRect &from) {
return drawPixmapRight(p.x(), p.y(), outerw, pix, from);
}
void drawSprite(int x, int y, const style::sprite &sprite) {
return drawPixmap(QPoint(x, y), App::sprite(), sprite);
}
void drawSprite(const QPoint &p, const style::sprite &sprite) {
return drawPixmap(p, App::sprite(), sprite);
}
void drawSpriteLeft(int x, int y, int outerw, const style::sprite &sprite) {
return drawPixmapLeft(x, y, outerw, App::sprite(), sprite);
}
void drawSpriteLeft(const QPoint &p, int outerw, const style::sprite &sprite) {
return drawPixmapLeft(p, outerw, App::sprite(), sprite);
}
void drawSpriteRight(int x, int y, int outerw, const style::sprite &sprite) {
return drawPixmapRight(x, y, outerw, App::sprite(), sprite);
}
void drawSpriteRight(const QPoint &p, int outerw, const style::sprite &sprite) {
return drawPixmapRight(p, outerw, App::sprite(), sprite);
}
void drawSpriteCenter(const QRect &in, const style::sprite &sprite) {
return drawPixmap(QPoint(in.x() + (in.width() - sprite.pxWidth()) / 2, in.y() + (in.height() - sprite.pxHeight()) / 2), App::sprite(), sprite);
}
};
@ -80,10 +113,12 @@ protected:
void enterEvent(QEvent *e) {
TWidget *p(tparent());
if (p) p->leaveToChildEvent(e);
return Widget::enterEvent(e);
}
void leaveEvent(QEvent *e) {
TWidget *p(tparent());
if (p) p->enterFromChildEvent(e);
return Widget::leaveEvent(e);
}
private:

View File

@ -81,7 +81,7 @@ namespace {
};
inline void _initTextOptions() {
_historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = langDir();
_historySrvOptions.dir = _textNameOptions.dir = _textDlgOptions.dir = cLangDir();
_textDlgOptions.maxw = st::dlgMaxWidth * 2;
_webpageTitleOptions.maxw = st::msgMaxWidth - st::msgPadding.left() - st::msgPadding.right() - st::webPageLeft;
_webpageTitleOptions.maxh = st::webPageTitleFont->height * 2;
@ -89,127 +89,6 @@ namespace {
_webpageDescriptionOptions.maxh = st::webPageDescriptionFont->height * 3;
}
class AnimatedGif : public Animated {
public:
AnimatedGif() : msg(0), reader(0), w(0), h(0), frame(0), framesCount(0), duration(0) {
}
bool animStep(float64 ms) {
int32 f = frame;
while (f < frames.size() && ms > delays[f]) {
++f;
if (f == frames.size() && frames.size() < framesCount) {
if (reader->read(&img)) {
int64 d = reader->nextImageDelay(), delay = delays[f - 1];
if (!d) d = 1;
delay += d;
frames.push_back(QPixmap::fromImage(img.size() == QSize(w, h) ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly));
delays.push_back(delay);
for (int32 i = 0; i < frames.size(); ++i) {
if (!frames[i].isNull()) {
frames[i] = QPixmap();
break;
}
}
} else {
framesCount = frames.size();
}
}
if (f == frames.size()) {
if (!duration) {
duration = delays.isEmpty() ? 1 : delays.back();
}
f = 0;
for (int32 i = 0, s = delays.size() - 1; i <= s; ++i) {
delays[i] += duration;
}
if (frames[f].isNull()) {
QString fname = reader->fileName();
delete reader;
reader = new QImageReader(fname);
}
}
if (frames[f].isNull() && reader->read(&img)) {
frames[f] = QPixmap::fromImage(img.size() == QSize(w, h) ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly);
}
}
if (frame != f) {
frame = f;
if (App::main()) App::main()->msgUpdated(msg->history()->peer->id, msg);
}
return true;
}
void start(HistoryItem *row, const QString &file) {
if (reader) {
stop();
}
reader = new QImageReader(file);
if (!reader->canRead() || !reader->supportsAnimation()) {
stop();
return;
}
QSize s = reader->size();
w = s.width();
h = s.height();
framesCount = reader->imageCount();
if (!w || !h || !framesCount) {
stop();
return;
}
frames.reserve(framesCount);
delays.reserve(framesCount);
int32 sizeLeft = MediaViewImageSizeLimit, delay = 0;
for (bool read = reader->read(&img); read; read = reader->read(&img)) {
sizeLeft -= w * h * 4;
frames.push_back(QPixmap::fromImage(img.size() == s ? img : img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation), Qt::ColorOnly));
int32 d = reader->nextImageDelay();
if (!d) d = 1;
delay += d;
delays.push_back(delay);
if (sizeLeft < 0) break;
}
msg = row;
anim::start(this);
msg->initDimensions();
App::main()->itemResized(msg, true);
}
void stop(bool onItemRemoved = false) {
delete reader;
reader = 0;
HistoryItem *row = msg;
msg = 0;
frames.clear();
delays.clear();
w = h = frame = framesCount = duration = 0;
anim::stop(this);
if (row && !onItemRemoved) {
row->initDimensions();
if (App::main()) App::main()->itemResized(row, true);
}
}
~AnimatedGif() {
stop(true);
}
HistoryItem *msg;
QImage img;
QImageReader *reader;
QVector<QPixmap> frames;
QVector<int64> delays;
int32 w, h, frame, framesCount, duration;
};
AnimatedGif animated;
inline HistoryReply *toHistoryReply(HistoryItem *item) {
@ -218,6 +97,12 @@ namespace {
inline const HistoryReply *toHistoryReply(const HistoryItem *item) {
return item ? item->toHistoryReply() : 0;
}
inline HistoryForwarded *toHistoryForwarded(HistoryItem *item) {
return item ? item->toHistoryForwarded() : 0;
}
inline const HistoryForwarded *toHistoryForwarded(const HistoryItem *item) {
return item ? item->toHistoryForwarded() : 0;
}
}
void historyInit() {
@ -1783,7 +1668,7 @@ void HistoryPhoto::updateFrom(const MTPMessageMedia &media) {
case mtpc_photoCachedSize: {
const string &s(i->c_photoCachedSize().vtype.c_string().v);
loc = &i->c_photoSize().vlocation;
loc = &i->c_photoCachedSize().vlocation;
if (s.size()) size = s[0];
} break;
}
@ -1976,12 +1861,16 @@ void HistoryVideo::initDimensions(const HistoryItem *parent) {
_maxw += st::mediaSaveDelta + _buttonWidth;
}
_minh = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
}
if (const HistoryReply *reply = toHistoryReply(parent)) {
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
_minh += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
} else if (const HistoryForwarded *fwd = toHistoryForwarded(parent)) {
if (parent->out() || !parent->history()->peer->chat) {
_minh += st::msgPadding.top();
}
_minh += st::msgServiceNameFont->height;
}
_height = _minh;
}
@ -2015,13 +1904,20 @@ void HistoryVideo::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, co
if (width < 1) return;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
bool out = parent->out(), hovered, pressed;
@ -2038,17 +1934,21 @@ void HistoryVideo::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, co
width -= btnw + st::mediaSaveDelta;
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
}
if (reply) {
if (x >= 0 && y >= replyFrom + st::msgReplyPadding.top() && x < width && y < skipy - st::msgReplyPadding.bottom()) {
lnk = reply->replyToLink();
return;
}
} else if (fwd) {
if (y >= fwdFrom && y < skipy) {
return fwd->getForwardedState(lnk, inText, x - st::mediaPadding.left(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
}
if (x >= 0 && y >= skipy && x < width && y < _height && !data->loader && data->access) {
@ -2066,13 +1966,20 @@ void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, bool selected, i
if (width < 1) return;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
data->thumb->checkload();
@ -2107,13 +2014,15 @@ void HistoryVideo::draw(QPainter &p, const HistoryItem *parent, bool selected, i
style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow));
p.fillRect(0, _height, width, st::msgShadow, shadow->b);
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
reply->drawReplyTo(p, st::msgReplyPadding.left(), replyFrom, width - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected);
} else if (fwd) {
fwd->drawForwardedFrom(p, st::mediaPadding.left(), fwdFrom, width - st::mediaPadding.left() - st::mediaPadding.right(), selected);
}
if (_thumbw) {
@ -2223,12 +2132,16 @@ void HistoryAudio::initDimensions(const HistoryItem *parent) {
}
_minh = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
}
if (const HistoryReply *reply = toHistoryReply(parent)) {
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
_minh += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
} else if (const HistoryForwarded *fwd = toHistoryForwarded(parent)) {
if (parent->out() || !parent->history()->peer->chat) {
_minh += st::msgPadding.top();
}
_minh += st::msgServiceNameFont->height;
}
_height = _minh;
}
@ -2238,13 +2151,20 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, i
if (width < 1) return;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
bool out = parent->out(), hovered, pressed, already = !data->already().isEmpty(), hasdata = !data->data.isEmpty();
@ -2282,13 +2202,15 @@ void HistoryAudio::draw(QPainter &p, const HistoryItem *parent, bool selected, i
style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow));
p.fillRect(0, _height, width, st::msgShadow, shadow->b);
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
reply->drawReplyTo(p, st::msgReplyPadding.left(), replyFrom, width - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected);
} else if (fwd) {
fwd->drawForwardedFrom(p, st::mediaPadding.left(), fwdFrom, width - st::mediaPadding.left() - st::mediaPadding.right(), selected);
}
AudioData *playing = 0;
@ -2401,13 +2323,20 @@ void HistoryAudio::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, co
if (width < 1) return;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
bool out = parent->out(), hovered, pressed;
@ -2424,17 +2353,21 @@ void HistoryAudio::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y, co
width -= btnw + st::mediaSaveDelta;
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
}
if (reply) {
if (x >= 0 && y >= replyFrom + st::msgReplyPadding.top() && x < width && y < skipy - st::msgReplyPadding.bottom()) {
lnk = reply->replyToLink();
return;
}
} else if (fwd) {
if (y >= fwdFrom && y < skipy) {
return fwd->getForwardedState(lnk, inText, x - st::mediaPadding.left(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
}
if (x >= 0 && y >= skipy && x < width && y < _height && !data->loader && data->access) {
@ -2500,14 +2433,19 @@ void HistoryDocument::initDimensions(const HistoryItem *parent) {
}
_minh = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
}
if (const HistoryReply *reply = toHistoryReply(parent)) {
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
_minh += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
} else if (const HistoryForwarded *fwd = toHistoryForwarded(parent)) {
if (parent->out() || !parent->history()->peer->chat) {
_minh += st::msgPadding.top();
}
_minh += st::msgServiceNameFont->height;
}
}
_height = _minh;
}
void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
@ -2536,13 +2474,20 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
}
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
data->thumb->checkload();
@ -2576,15 +2521,16 @@ void HistoryDocument::draw(QPainter &p, const HistoryItem *parent, bool selected
style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow));
p.fillRect(0, _height, width, st::msgShadow, shadow->b);
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
reply->drawReplyTo(p, st::msgReplyPadding.left(), replyFrom, width - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected);
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
if (reply) {
reply->drawReplyTo(p, st::msgReplyPadding.left(), replyFrom, width - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected);
} else if (fwd) {
fwd->drawForwardedFrom(p, st::mediaPadding.left(), fwdFrom, width - st::mediaPadding.left() - st::mediaPadding.right(), selected);
}
if (_thumbw) {
int32 rf(cIntRetinaFactor());
p.drawPixmap(QPoint(st::mediaPadding.left(), skipy + st::mediaPadding.top()), data->thumb->pix(_thumbw), QRect(_thumbx * rf, _thumby * rf, st::mediaThumbSize * rf, st::mediaThumbSize * rf));
@ -2737,13 +2683,20 @@ void HistoryDocument::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y,
}
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
if (!out) { // draw Download / Save As button
@ -2755,17 +2708,21 @@ void HistoryDocument::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y,
width -= btnw + st::mediaSaveDelta;
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
}
if (reply) {
if (x >= 0 && y >= replyFrom + st::msgReplyPadding.top() && x < width && y < skipy - st::msgReplyPadding.bottom()) {
lnk = reply->replyToLink();
return;
}
} else if (fwd) {
if (y >= fwdFrom && y < skipy) {
return fwd->getForwardedState(lnk, inText, x - st::mediaPadding.left(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
}
if (x >= 0 && y >= skipy && x < width && y < _height && !data->loader && data->access) {
@ -3016,12 +2973,16 @@ void HistoryContact::initDimensions(const HistoryItem *parent) {
_maxw = phonew + tleft + st::mediaPadding.right();
}
_minh = st::mediaPadding.top() + st::mediaThumbSize + st::mediaPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
}
if (const HistoryReply *reply = toHistoryReply(parent)) {
_maxw += st::mediaPadding.left() + st::mediaPadding.right();
_minh += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
} else if (const HistoryForwarded *fwd = toHistoryForwarded(parent)) {
if (parent->out() || !parent->history()->peer->chat) {
_minh += st::msgPadding.top();
}
_minh += st::msgServiceNameFont->height;
}
_height = _minh;
}
@ -3043,26 +3004,37 @@ void HistoryContact::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y,
if (width < 0) width = w;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
if (!parent->out() && parent->history()->peer->chat) {
if (x >= st::mediaPadding.left() && y >= st::msgPadding.top() && x < width - st::mediaPadding.left() - st::mediaPadding.right() && x < st::mediaPadding.left() + parent->from()->nameText.maxWidth() && y < replyFrom) {
lnk = parent->from()->lnk;
return;
}
}
if (reply) {
if (x >= 0 && y >= replyFrom + st::msgReplyPadding.top() && x < width && y < skipy - st::msgReplyPadding.bottom()) {
lnk = reply->replyToLink();
return;
}
} else if (fwd) {
if (y >= fwdFrom && y < skipy) {
return fwd->getForwardedState(lnk, inText, x - st::mediaPadding.left(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
}
if (x >= 0 && y >= skipy && x < w && y < _height && contact) {
@ -3087,13 +3059,20 @@ void HistoryContact::draw(QPainter &p, const HistoryItem *parent, bool selected,
if (width < 1) return;
const HistoryReply *reply = toHistoryReply(parent);
int skipy = 0, replyFrom = 0;
const HistoryForwarded *fwd = reply ? 0 : toHistoryForwarded(parent);
int skipy = 0, replyFrom = 0, fwdFrom = 0;
if (reply) {
skipy = st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
}
} else if (fwd) {
skipy = st::msgServiceNameFont->height;
}
if (!parent->out() && parent->history()->peer->chat) {
replyFrom = st::msgPadding.top() + st::msgNameFont->height;
fwdFrom = st::msgPadding.top() + st::msgNameFont->height;
skipy += replyFrom;
} else if (fwd) {
fwdFrom = st::msgPadding.top();
skipy += fwdFrom;
}
bool out = parent->out();
@ -3107,13 +3086,15 @@ void HistoryContact::draw(QPainter &p, const HistoryItem *parent, bool selected,
style::color shadow(selected ? (out ? st::msgOutSelectShadow : st::msgInSelectShadow) : (out ? st::msgOutShadow : st::msgInShadow));
p.fillRect(0, _height, width, st::msgShadow, shadow->b);
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
if (reply) {
if (!parent->out() && parent->history()->peer->chat) {
p.setFont(st::msgNameFont->f);
p.setPen(parent->from()->color->p);
parent->from()->nameText.drawElided(p, st::mediaPadding.left(), st::msgPadding.top(), width - st::mediaPadding.left() - st::mediaPadding.right());
}
reply->drawReplyTo(p, st::msgReplyPadding.left(), replyFrom, width - st::msgReplyPadding.left() - st::msgReplyPadding.right(), selected);
} else if (fwd) {
fwd->drawForwardedFrom(p, st::mediaPadding.left(), fwdFrom, width - st::mediaPadding.left() - st::mediaPadding.right(), selected);
}
p.drawPixmap(st::mediaPadding.left(), skipy + st::mediaPadding.top(), (contact ? contact->photo : userDefPhoto(1))->pix(st::mediaThumbSize));
@ -3191,6 +3172,7 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
if (data->pendingTill) {
_maxw = st::webPageLeft + st::linkFont->m.width(lang((data->pendingTill < 0) ? lng_attach_failed : lng_profile_loading));
_minh = st::replyHeight;
_height = _minh;
return;
}
if (!_openl && !data->url.isEmpty()) _openl = TextLinkPtr(new TextLink(data->url));
@ -3280,6 +3262,7 @@ void HistoryWebPage::initDimensions(const HistoryItem *parent) {
_duration = formatDurationText(data->duration);
_durationWidth = st::msgDateFont->m.width(_duration);
}
_height = _minh;
}
void HistoryWebPage::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
@ -4054,6 +4037,7 @@ void HistoryImageLink::initDimensions(const HistoryItem *parent) {
_minh += st::msgPadding.top() + st::msgNameFont->height;
}
}
_height = _minh;
}
void HistoryImageLink::draw(QPainter &p, const HistoryItem *parent, bool selected, int32 width) const {
@ -4797,8 +4781,8 @@ void HistoryForwarded::initDimensions(const HistoryItem *parent) {
}
void HistoryForwarded::fwdNameUpdated() const {
if (justMedia()) return;
fwdFromName.setText(st::msgServiceNameFont, App::peerName(fwdFrom), _textNameOptions);
if (justMedia()) return;
int32 _namew = fromWidth + fwdFromName.maxWidth() + st::msgPadding.left() + st::msgPadding.right();
if (_namew > _maxw) _maxw = _namew;
}
@ -4811,22 +4795,26 @@ void HistoryForwarded::draw(QPainter &p, uint32 selection) const {
HistoryMessage::draw(p, selection);
}
void HistoryForwarded::drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const {
void HistoryForwarded::drawForwardedFrom(QPainter &p, int32 x, int32 y, int32 w, bool selected) const {
style::font serviceFont(st::msgServiceFont), serviceName(st::msgServiceNameFont);
bool selected = (selection == FullItemSel);
p.setPen((selected ? (out() ? st::msgOutServiceSelColor : st::msgInServiceSelColor) : (out() ? st::msgOutServiceColor : st::msgInServiceColor))->p);
p.setFont(serviceFont->f);
int32 h1 = 0, h2 = serviceName->height, h = h1 + (h1 > h2 ? h1 : h2);
if (trect.width() >= fromWidth) {
p.drawText(trect.x(), trect.y() + h1 + serviceFont->ascent, lang(lng_forwarded_from));
if (w >= fromWidth) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
p.setFont(serviceName->f);
fwdFromName.drawElided(p, trect.x() + fromWidth, trect.y() + h1, trect.width() - fromWidth);
fwdFromName.drawElided(p, x + fromWidth, y, w - fromWidth);
} else {
p.drawText(trect.x(), trect.y() + h1 + serviceFont->ascent, serviceFont->m.elidedText(lang(lng_forwarded_from), Qt::ElideRight, trect.width()));
p.drawText(x, y + serviceFont->ascent, serviceFont->m.elidedText(lang(lng_forwarded_from), Qt::ElideRight, 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);
@ -4900,16 +4888,22 @@ void HistoryForwarded::getState(TextLinkPtr &lnk, bool &inText, int32 x, int32 y
QRect trect(r.marginsAdded(-st::msgPadding));
if (y >= trect.top() && y < trect.top() + st::msgServiceNameFont->height) {
if (x >= trect.left() + fromWidth && x < trect.right() && x < trect.left() + fromWidth + fwdFromName.maxWidth()) {
lnk = fwdFrom->lnk;
}
return;
return getForwardedState(lnk, inText, x - trect.left(), trect.right() - trect.left());
}
y -= st::msgServiceNameFont->height;
}
return HistoryMessage::getState(lnk, inText, x, y);
}
void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, bool &inText, int32 x, int32 w) const {
inText = false;
if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
lnk = fwdFrom->lnk;
} else {
lnk = TextLinkPtr();
}
}
void HistoryForwarded::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const {
symbol = 0;
after = false;
@ -5096,8 +5090,9 @@ void HistoryReply::drawReplyTo(QPainter &p, int32 x, int32 y, int32 w, bool sele
}
replyToName.drawElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip);
HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage();
if (likeService) {
} else if (replyToMsg->getMedia() || replyToMsg->serviceMsg()) {
} else if ((replyToAsMsg && replyToAsMsg->justMedia()) || replyToMsg->serviceMsg()) {
style::color date(selected ? (out() ? st::msgOutSelectDateColor : st::msgInSelectDateColor) : (out() ? st::msgOutDateColor : st::msgInDateColor));
p.setPen(date->p);
} else {

View File

@ -218,6 +218,9 @@ struct History : public QList<HistoryBlock*> {
HistoryItem *currentNotification() {
return notifies.isEmpty() ? 0 : notifies.front();
}
bool hasNotification() const {
return !notifies.isEmpty();
}
void skipNotification() {
if (!notifies.isEmpty()) {
notifies.pop_front();
@ -620,6 +623,8 @@ private:
ItemAnimations &itemAnimations();
class HistoryReply; // dynamic_cast optimize
class HistoryMessage; // dynamic_cast optimize
class HistoryForwarded; // dynamic_cast optimize
class HistoryMedia;
class HistoryItem : public HistoryElem {
@ -729,6 +734,18 @@ public:
return false;
}
virtual HistoryMessage *toHistoryMessage() { // dynamic_cast optimize
return 0;
}
virtual const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
return 0;
}
virtual HistoryForwarded *toHistoryForwarded() { // dynamic_cast optimize
return 0;
}
virtual const HistoryForwarded *toHistoryForwarded() const { // dynamic_cast optimize
return 0;
}
virtual HistoryReply *toHistoryReply() { // dynamic_cast optimize
return 0;
}
@ -1244,6 +1261,13 @@ public:
return from();
}
HistoryMessage *toHistoryMessage() { // dynamic_cast optimize
return this;
}
const HistoryMessage *toHistoryMessage() const { // dynamic_cast optimize
return this;
}
~HistoryMessage();
protected:
@ -1268,10 +1292,12 @@ public:
void fwdNameUpdated() const;
void draw(QPainter &p, uint32 selection) const;
void drawForwardedFrom(QPainter &p, int32 x, int32 y, int32 w, bool selected) const;
void drawMessageText(QPainter &p, const QRect &trect, uint32 selection) const;
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 getForwardedState(TextLinkPtr &lnk, bool &inText, int32 x, int32 w) const;
void getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x, int32 y) const;
QDateTime dateForwarded() const {
@ -1282,6 +1308,13 @@ public:
}
QString selectedText(uint32 selection) const;
HistoryForwarded *toHistoryForwarded() {
return this;
}
const HistoryForwarded *toHistoryForwarded() const {
return this;
}
protected:
QDateTime fwdDate;

View File

@ -842,9 +842,9 @@ void HistoryList::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoSaveLink(lnkVideo->video()).doSave(true);
if (lnkAudio) AudioSaveLink(lnkAudio->audio()).doSave(true);
if (lnkDocument) DocumentSaveLink(lnkDocument->document()).doSave(true);
if (lnkVideo) VideoSaveLink::doSave(lnkVideo->video(), true);
if (lnkAudio) AudioSaveLink::doSave(lnkAudio->audio(), true);
if (lnkDocument) DocumentSaveLink::doSave(lnkDocument->document(), true);
}
void HistoryList::copyContextText() {

View File

@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:Keine Nachrichten|# Nachricht|# Nachrichten}";
"lng_search_global_results" = "Globale Suchergebnisse";
"lng_mediaview_save" = "Download";
"lng_media_save_progress" = "{ready} von {total} {mb}";
"lng_mediaview_save_as" = "Speichern unter…";
"lng_mediaview_copy" = "Kopieren";
"lng_mediaview_forward" = "Weiterleiten";
"lng_mediaview_delete" = "Löschen";
"lng_mediaview_photos_all" = "Alle Fotos anzeigen";
"lng_mediaview_files_all" = "Alle Dateien anzeigen";
"lng_mediaview_single_photo" = "Bild";
"lng_mediaview_group_photo" = "Bild";
"lng_mediaview_profile_photo" = "Profilbild";
"lng_mediaview_file_n_of_count" = "{file} {n} von {count}";
"lng_mediaview_n_of_count" = "Bild {n} von {count}";
"lng_mediaview_doc_image" = "Datei";
"lng_mediaview_today" = "heute um {time}";
@ -545,7 +550,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" = "— Linkvorschau: Erhalte eine Zusammenfassung für Tweets, YouTube Videos, Instagram Fotos und sonstigen Inhalten.\n— Zweistufige Bestätigung: Lege ein zusätzliches Kennwort fest, das du für die Anmeldung bei deinem Telegram-Konto benötigst.\n— Sitzungslisten: Betrachte alle deine aktiven Telegram-Sitzungen (auf dem Desktop, Tablet und mobilen Geräten) und beende sie.";
"lng_new_version_text" = "— Bildbetrachter in neuer Optik\n— Zwischen Dateien im Bildbetrachter wechseln\n— Gruppierte Benachrichtigungen, sofern mehrere Nachrichten weitergeleitet werden\n— Neuer Standard-Chathintergrund (kann man über die Einstellungen ändern)";
"lng_menu_insert_unicode" = "Unicode-Steuerzeichen einfügen";

View File

@ -263,7 +263,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_passcode_enter_old" = "Pon tu código actual";
"lng_passcode_enter_first" = "Pon un código de acceso";
"lng_passcode_enter_new" = "Pon tu nuevo código";
"lng_passcode_confirm_new" = "Pon, otra vez, el código";
"lng_passcode_confirm_new" = "Repite el nuevo código";
"lng_passcode_about" = "Cuando configuras un código, aparece un candado en el menú. Pulsa sobre él para bloquear la aplicación.\n\nNota: si olvidas el código, tendrás que reiniciar la sesión en Telegram Desktop.";
"lng_passcode_differ" = "Los códigos de acceso son diferentes";
"lng_passcode_wrong" = "Código de acceso equivocado";
@ -281,7 +281,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_cloud_password_enter_old" = "Pon la vieja contraseña";
"lng_cloud_password_enter_first" = "Pon una contraseña";
"lng_cloud_password_enter_new" = "Pon la nueva contraseña";
"lng_cloud_password_confirm_new" = "Pon, otra vez, la contraseña";
"lng_cloud_password_confirm_new" = "Repite la nueva contraseña";
"lng_cloud_password_hint" = "Pon una pista para la contraseña";
"lng_cloud_password_bad" = "La contraseña y la pista no pueden ser iguales.";
"lng_cloud_password_email" = "Pon un e-mail de recuperación";
@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:No se encontraron mensajes|Found # mensaje|Found # mensajes}";
"lng_search_global_results" = "Resultados de la búsqueda global";
"lng_mediaview_save" = "Descargar";
"lng_media_save_progress" = "{ready} de {total} {mb}";
"lng_mediaview_save_as" = "Guardar como...";
"lng_mediaview_copy" = "Copiar";
"lng_mediaview_forward" = "Reenviar";
"lng_mediaview_delete" = "Eliminar";
"lng_mediaview_photos_all" = "Ver todas las fotos";
"lng_mediaview_files_all" = "Ver todos los archivos";
"lng_mediaview_single_photo" = "Foto";
"lng_mediaview_group_photo" = "Foto del grupo";
"lng_mediaview_profile_photo" = "Foto de perfil";
"lng_mediaview_file_n_of_count" = "{file} {n} de {count}";
"lng_mediaview_n_of_count" = "Foto {n} de {count}";
"lng_mediaview_doc_image" = "Archivo";
"lng_mediaview_today" = "hoy a las {time}";
@ -545,7 +550,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" = "— Vista previa de enlaces de Twitter, YouTube, Instagram y otros\n— Verificación en dos pasos\n— Ve todas tus sesiones de Telegram y cierra sesiones específicas";
"lng_new_version_text" = "— Visor de fotos con un nuevo diseño\n— Cambia entre archivos en el visor de fotos\n— Notificaciones agrupadas cuando se reenvían varios mensajes\n— Nuevo fondo de chat por defecto (puedes cambiarlo en Ajustes)";
"lng_menu_insert_unicode" = "Insertar caracteres de control Unicode";

View File

@ -287,7 +287,7 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_cloud_password_email" = "Inserisci email di recupero";
"lng_cloud_password_bad_email" = "E-mail non valida, riprova con un'altra.";
"lng_cloud_password_about" = "La password verrà richiesta quando ti connetti da un nuovo dispositivo in aggiunta al codice.";
"lng_cloud_password_about_recover" = "Attenzione! Sei sicuro di non voler \naggiungere un'e-mail di recupero?\n\nSe dimentichi la tua password, perderai\nl'accesso al tuo account Telegram.";
"lng_cloud_password_about_recover" = "Attenzione! Sei sicuro di non voler\naggiungere un'e-mail di recupero?\n\nSe dimentichi la tua password, perderai\nl'accesso al tuo account Telegram.";
"lng_cloud_password_almost" = "Abbiamo inviato un link di conferma\nall'e-mail che ci hai fornito.\n\nLa verifica in due passaggi sarà attivata\nnon appena aprirai quel link.";
"lng_cloud_password_was_set" = "Verifica in due passaggi abilitata.";
"lng_cloud_password_updated" = "La tua password è stata aggiornata.";
@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:Nessun messaggio trovato|# messaggio trovato|# messaggi trovati}";
"lng_search_global_results" = "Risultati ricerca globale";
"lng_mediaview_save" = "Download";
"lng_media_save_progress" = "{ready} di {total} {mb}";
"lng_mediaview_save_as" = "Salva come..";
"lng_mediaview_copy" = "Copia";
"lng_mediaview_forward" = "Inoltra";
"lng_mediaview_delete" = "Elimina";
"lng_mediaview_photos_all" = "Visualizza tutte le foto";
"lng_mediaview_files_all" = "Visualizza tutti i file";
"lng_mediaview_single_photo" = "Foto singola";
"lng_mediaview_group_photo" = "Foto gruppo";
"lng_mediaview_profile_photo" = "Foto profilo";
"lng_mediaview_file_n_of_count" = "{file} {n} di {count}";
"lng_mediaview_n_of_count" = "Foto {n} di {count}";
"lng_mediaview_doc_image" = "File";
"lng_mediaview_today" = "oggi alle {time}";
@ -545,7 +550,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" = "— Anteprima dei link per Twitter, Youtube, Instagram e altri contenuti.\n— Verifica in due passaggi.\n— Visualizza le sessioni attive di Telegram e termina sessioni specifiche.";
"lng_new_version_text" = "— Nuovo design per il visualizzatore delle foto\n— Passa tra i file nel visualizzatore foto\n— Notifiche raggruppate quando più messaggi sono inoltrati\n— Nuovo sfondo chat di default (puoi cambiarlo nelle Impostazioni)";
"lng_menu_insert_unicode" = "Inserisci carattere di controllo Unicode";

View File

@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:메시지를 찾을 수 없습니다.|# 개의 메시지를 찾았습니다.|# 개의 메시지를 찾았습니다.}";
"lng_search_global_results" = "아이디 검색 결과";
"lng_mediaview_save" = "다운로드";
"lng_media_save_progress" = "{ready} / {total} {mb}";
"lng_mediaview_save_as" = "다른 이름으로 저장하기";
"lng_mediaview_copy" = "복사하기";
"lng_mediaview_forward" = "전달";
"lng_mediaview_delete" = "삭제";
"lng_mediaview_photos_all" = "모든 사진 보기";
"lng_mediaview_files_all" = "모든 파일 보기";
"lng_mediaview_single_photo" = "단일 사진";
"lng_mediaview_group_photo" = "그룹 사진";
"lng_mediaview_profile_photo" = "프로필 사진";
"lng_mediaview_file_n_of_count" = "{file} {n} 중 {count}";
"lng_mediaview_n_of_count" = "사진 {n} 중 {count}";
"lng_mediaview_doc_image" = "파일";
"lng_mediaview_today" = "오늘 {time}";
@ -545,7 +550,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— 2단계 인증\n— 활성화된 모든 텔레그램 세션 확인 및 특정 세션 종료 기능";
"lng_new_version_text" = "— 새로운 사진 뷰어 디자인\n— 사진 뷰어에서 파일간 이동 기능\n— 여러 메시지가 전달되었을시 그룹 알림 기능\n— 새로운 채팅 배경 이미지 (설정에서 변경 가능)";
"lng_menu_insert_unicode" = "유니코드 문자를 입력하세요.";

View File

@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:geen berichten gevonden|# berichten gevonden|# berichten gevonden}";
"lng_search_global_results" = "Wereldwijde zoekresultaten";
"lng_mediaview_save" = "Downloaden";
"lng_media_save_progress" = "{ready} van {total} {mb}";
"lng_mediaview_save_as" = "Opslaan als";
"lng_mediaview_copy" = "Kopiëren";
"lng_mediaview_forward" = "Doorsturen";
"lng_mediaview_delete" = "Verwijder";
"lng_mediaview_photos_all" = "Alle foto's weergeven";
"lng_mediaview_files_all" = "Alle bestanden weergeven";
"lng_mediaview_single_photo" = "Foto";
"lng_mediaview_group_photo" = "Groepsafbeelding";
"lng_mediaview_profile_photo" = "Profielfoto";
"lng_mediaview_file_n_of_count" = "{file} {n} van {count}";
"lng_mediaview_n_of_count" = "Foto {n} van {count}";
"lng_mediaview_doc_image" = "Bestand";
"lng_mediaview_today" = "vandaag om {time}";
@ -545,7 +550,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" = "— Link-preview voor Twitter, YouTube, Instagram en diverse andere links\n— Twee-staps-verificatie\n— Bekijk al je Telegram-sessies, beëindig specifieke sessies.";
"lng_new_version_text" = "— Nieuw ontwerp voor foto-weergave\n— Omschakelen naar bestanden in de foto-weergave\n— Gegroepeerde meldingen als meerdere berichten worden doorgestuurd\n— Nieuwe standaard chat-achtergrond (aan te passen via instellingen)";
"lng_menu_insert_unicode" = "Unicode-besturingsteken invoegen";

View File

@ -527,12 +527,17 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
"lng_search_found_results" = "{count:Nenhuma mensagem encontrada|Encontrada # mensagem|Encontradas # mensagens}";
"lng_search_global_results" = "Resultados da busca global";
"lng_mediaview_save" = "Baixar";
"lng_media_save_progress" = "{ready} de {total} {mb}";
"lng_mediaview_save_as" = "Salvar Como..";
"lng_mediaview_copy" = "Copiar";
"lng_mediaview_forward" = "Encaminhar";
"lng_mediaview_delete" = "Apagar";
"lng_mediaview_photos_all" = "Visualizar Fotos";
"lng_mediaview_files_all" = "Visualizar Arquivos";
"lng_mediaview_single_photo" = "Foto Única";
"lng_mediaview_group_photo" = "Grupo de Fotos";
"lng_mediaview_profile_photo" = "Foto de Perfil";
"lng_mediaview_file_n_of_count" = "{file} {n} de {count}";
"lng_mediaview_n_of_count" = "Foto {n} de {count}";
"lng_mediaview_doc_image" = "Arquivo";
"lng_mediaview_today" = "hoje às {time}";
@ -545,7 +550,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" = "— Pré-visualização de links para o Twitter, YouTube, Instagram e alguns outros links\n— Verificação em duas etapas\n— Visualizar todas as suas sessões do Telegram, encerrar sessões específicas.";
"lng_new_version_text" = "— Novo design do visualizador de fotos\n— Navegue pelos arquivos no visualizador de fotos\n— Notificações agrupadas quando muitas mensagens são encaminhadas \n— Novo plano de fundo padrão (você pode alterar nas Configurações)";
"lng_menu_insert_unicode" = "Inserir caractere de controle Unicode";

View File

@ -831,6 +831,9 @@ namespace {
if (!_checkStreamStatus(stream)) return false;
cSetTileBackground(v == 1);
if (version < 8005 && !_backgroundKey) {
cSetTileBackground(false);
}
} break;
case dbiAutoLock: {
@ -2179,7 +2182,7 @@ namespace Local {
if (!_working()) return;
QByteArray png;
{
if (!img.isNull()) {
QBuffer buf(&png);
if (!img.save(&buf, "BMP")) return;
}
@ -2188,9 +2191,10 @@ namespace Local {
_mapChanged = true;
_writeMap(WriteMapFast);
}
quint32 size = sizeof(qint32) + sizeof(quint32) + sizeof(quint32) + png.size();
quint32 size = sizeof(qint32) + sizeof(quint32) + (png.isEmpty() ? 0 : (sizeof(quint32) + png.size()));
EncryptedDescriptor data(size);
data.stream << qint32(id) << png;
data.stream << qint32(id);
if (!png.isEmpty()) data.stream << png;
FileWriteDescriptor file(_backgroundKey);
file.writeEncrypted(data);
@ -2210,7 +2214,17 @@ namespace Local {
QByteArray pngData;
qint32 id;
bg.stream >> id >> pngData;
bg.stream >> id;
if (!id || id == DefaultChatBackground) {
if (bg.version < 8005) {
if (!id) cSetTileBackground(!DefaultChatBackground);
App::initBackground(DefaultChatBackground, QImage(), true);
} else {
App::initBackground(id, QImage(), true);
}
return true;
}
bg.stream >> pngData;
QImage img;
QBuffer buf(&pngData);

View File

@ -360,7 +360,7 @@ _failDifferenceTimeout(1), _lastUpdateTime(0), _cachedX(0), _cachedY(0), _backgr
connect(&dialogs, SIGNAL(cancelled()), this, SLOT(dialogsCancelled()));
connect(&history, SIGNAL(cancelled()), &dialogs, SLOT(activate()));
connect(this, SIGNAL(peerPhotoChanged(PeerData*)), this, SIGNAL(dialogsUpdated()));
connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(getDifference()));
connect(&noUpdatesTimer, SIGNAL(timeout()), this, SLOT(mtpPing()));
connect(&_onlineTimer, SIGNAL(timeout()), this, SLOT(updateOnline()));
connect(&_onlineUpdater, SIGNAL(timeout()), this, SLOT(updateOnlineDisplay()));
connect(&_idleFinishTimer, SIGNAL(timeout()), this, SLOT(checkIdleFinish()));
@ -1195,7 +1195,8 @@ void MainWidget::peerUsernameChanged(PeerData *peer) {
void MainWidget::checkLastUpdate(bool afterSleep) {
uint64 n = getms(true);
if (_lastUpdateTime && n > _lastUpdateTime + (afterSleep ? NoUpdatesAfterSleepTimeout : NoUpdatesTimeout)) {
getDifference();
_lastUpdateTime = n;
MTP::ping();
}
}
@ -1407,7 +1408,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
if (reader.supportsAnimation() && reader.imageCount() > 1 && item) {
startGif(item, already);
} else {
App::wnd()->showDocument(document, QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly), item);
App::wnd()->showDocument(document, item);
}
} else {
psOpenFile(already);
@ -1430,6 +1431,7 @@ void MainWidget::documentLoadProgress(mtpFileLoader *loader) {
msgUpdated(j.key()->history()->peer->id, j.key());
}
}
App::wnd()->documentUpdated(document);
}
void MainWidget::documentLoadFailed(mtpFileLoader *loader, bool started) {
@ -1590,6 +1592,8 @@ void MainWidget::checkChatBackground() {
if (_background->full->loaded()) {
if (_background->full->isNull()) {
App::initBackground();
} else if (_background->id == 0 || _background->id == DefaultChatBackground) {
App::initBackground(_background->id);
} else {
App::initBackground(_background->id, _background->full->pix().toImage());
}
@ -2296,6 +2300,7 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) {
updInited = true;
MTP_LOG(0, ("getDifference { good - after a slice of difference was received }"));
getDifference();
} break;
case mtpc_updates_difference: {
@ -2373,6 +2378,7 @@ bool MainWidget::failDifference(const RPCError &error) {
void MainWidget::getDifferenceForce() {
if (MTP::authedId()) {
updInited = true;
MTP_LOG(0, ("getDifference { force - after get difference failed }"));
getDifference();
}
}
@ -2398,6 +2404,10 @@ void MainWidget::getDifference() {
MTP::send(MTPupdates_GetDifference(MTP_int(updGoodPts), MTP_int(updDate), MTP_int(updQts)), rpcDone(&MainWidget::gotDifference), rpcFail(&MainWidget::failDifference));
}
void MainWidget::mtpPing() {
MTP::ping();
}
void MainWidget::start(const MTPUser &user) {
int32 uid = user.c_userSelf().vid.v;
if (MTP::authedId() != uid) {
@ -2425,9 +2435,16 @@ bool MainWidget::started() {
}
void MainWidget::openLocalUrl(const QString &url) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://resolve/?\\?domain=([a-zA-Z0-9\\.\\_]+)$"), QRegularExpression::CaseInsensitiveOption).match(url.trimmed());
if (m.hasMatch()) {
openUserByName(m.captured(1));
QString u(url.trimmed());
if (u.startsWith(QLatin1String("tg://resolve"), Qt::CaseInsensitive)) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://resolve/?\\?domain=([a-zA-Z0-9\\.\\_]+)$"), QRegularExpression::CaseInsensitiveOption).match(u);
if (m.hasMatch()) {
openUserByName(m.captured(1));
}
} else if (u.startsWith(QLatin1String("tg://join"), Qt::CaseInsensitive)) {
QRegularExpressionMatch m = QRegularExpression(qsl("^tg://join/?\\?invite=([a-zA-Z0-9\\.\\_]+)$"), QRegularExpression::CaseInsensitiveOption).match(u);
if (m.hasMatch()) {
}
}
}
@ -2743,6 +2760,7 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) {
if (mtpTypeId(*from) == mtpc_new_session_created) {
MTPNewSession newSession(from, end);
updSeq = 0;
MTP_LOG(0, ("getDifference { after new_session_created }"));
return getDifference();
} else {
try {
@ -2805,6 +2823,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
case mtpc_updateShortMessage: {
const MTPDupdateShortMessage &d(updates.c_updateShortMessage());
if (!App::userLoaded(d.vuser_id.v) || (d.has_fwd_from_id() && !App::userLoaded(d.vfwd_from_id.v))) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortMessage }"));
return getDifference();
}
if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) {
@ -2823,6 +2842,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
case mtpc_updateShortChatMessage: {
const MTPDupdateShortChatMessage &d(updates.c_updateShortChatMessage());
if (!App::chatLoaded(d.vchat_id.v) || !App::userLoaded(d.vfrom_id.v) || (d.has_fwd_from_id() && !App::userLoaded(d.vfwd_from_id.v))) {
MTP_LOG(0, ("getDifference { good - getting user for updateShortChatMessage }"));
return getDifference();
}
if (!updPtsUpdated(d.vpts.v, d.vpts_count.v)) {
@ -2838,6 +2858,7 @@ void MainWidget::handleUpdates(const MTPUpdates &updates) {
} break;
case mtpc_updatesTooLong: {
MTP_LOG(0, ("getDifference { good - updatesTooLong received }"));
return getDifference();
} break;
}

View File

@ -367,6 +367,7 @@ public slots:
void onParentResize(const QSize &newSize);
void getDifference();
void mtpPing();
void getDifferenceForce();
void updateOnline(bool gotOtherOffline = false);

File diff suppressed because it is too large Load Diff

View File

@ -17,6 +17,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
*/
#pragma once
#include "dropdown.h"
class MediaView : public TWidget, public RPCSender, public Animated {
Q_OBJECT
@ -37,30 +39,48 @@ public:
void hide();
void updateOver(const QPoint &mpos);
void updateOver(QPoint mpos);
void showPhoto(PhotoData *photo, HistoryItem *context);
void showPhoto(PhotoData *photo, PeerData *context);
void showDocument(DocumentData *doc, QPixmap pix, HistoryItem *context);
void showDocument(DocumentData *doc, HistoryItem *context);
void moveToScreen();
void moveToPhoto(int32 delta);
void preloadPhotos(int32 delta);
void moveToNext(int32 delta);
void preloadData(int32 delta);
void leaveToChildEvent(QEvent *e) { // e -- from enterEvent() of child TWidget
updateOverState(OverNone);
}
void enterFromChildEvent(QEvent *e) { // e -- from leaveEvent() of child TWidget
updateOver(mapFromGlobal(QCursor::pos()));
}
void mediaOverviewUpdated(PeerData *peer);
void documentUpdated(DocumentData *doc);
void changingMsgId(HistoryItem *row, MsgId newId);
void updateDocSize();
void updateControls();
void updateDropdown();
bool animStep(float64 dt);
void showSaveMsgFile();
void close();
void activateControls();
void onDocClick();
~MediaView();
public slots:
void onClose();
void onSave();
void onHideControls(bool force = false);
void onDropdownHiding();
void onToMessage();
void onSaveAs();
void onDownload();
void onSaveCancel();
void onShowInFolder();
void onForward();
void onDelete();
@ -69,52 +89,73 @@ public slots:
void onMenuDestroy(QObject *obj);
void receiveMouse();
void onDropdown();
void onCheckActive();
void onTouchTimer();
void updateImage();
void onGifUpdated();
private:
void showPhoto(PhotoData *photo);
void loadPhotosBack();
void displayPhoto(PhotoData *photo);
void displayDocument(DocumentData *doc, HistoryItem *item);
void findCurrent();
void loadBack();
void photosLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
void userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mtpRequestId req);
void filesLoaded(History *h, const MTPmessages_Messages &msgs, mtpRequestId req);
void updateHeader();
void updatePolaroid();
void snapXY();
QBrush _transparentBrush;
QTimer _timer;
PhotoData *_photo;
DocumentData *_doc;
QRect _avail, _leftNav, _rightNav, _bottomBar, _nameNav, _dateNav, _polaroidOut, _polaroidIn;
int32 _availBottom;
bool _leftNavVisible, _rightNavVisible;
MediaOverviewType _overview;
QRect _closeNav, _closeNavIcon;
QRect _leftNav, _leftNavIcon, _rightNav, _rightNavIcon;
QRect _headerNav, _nameNav, _dateNav;
QRect _saveNav, _saveNavIcon, _moreNav, _moreNavIcon;
bool _leftNavVisible, _rightNavVisible, _saveVisible, _headerHasLink;
QString _dateText;
QString _headerText;
uint64 _animStarted;
int32 _maxWidth, _maxHeight, _width, _x, _y, _w, _h, _xStart, _yStart;
int32 _width, _x, _y, _w, _h, _xStart, _yStart;
int32 _zoom; // < 0 - out, 0 - none, > 0 - in
float64 _zoomToScreen; // for documents
QPoint _mStart;
bool _pressed;
int32 _dragging;
QPixmap _current;
AnimatedGif _currentGif;
int32 _full; // -1 - thumb, 0 - medium, 1 - full
History *_history; // if conversation photos overview
PeerData *_peer;
UserData *_user, *_from; // if user profile photos overview
Text _fromName;
int32 _index; // index in photos array, -1 if just photo
MsgId _msgid; // msgId of current photo
style::sprite _docIcon;
QString _docName, _docSize, _docExt;
int32 _docNameWidth, _docSizeWidth, _docExtWidth;
QRect _docRect, _docIconRect;
int32 _docThumbx, _docThumby, _docThumbw;
uint64 _docRadialFirst, _docRadialStart, _docRadialLast;
float64 _docRadialOpacity;
QPen _docRadialPen;
anim::fvalue a_docRadial, a_docRadialStart;
LinkButton _docDownload, _docSaveAs, _docCancel;
QString _header;
History *_history; // if conversation photos or files overview
PeerData *_peer;
UserData *_user; // if user profile photos overview
UserData *_from;
Text _fromName;
int32 _index; // index in photos or files array, -1 if just photo
MsgId _msgid; // msgId of current photo or file
mtpRequestId _loadRequest;
@ -122,14 +163,34 @@ private:
OverNone,
OverLeftNav,
OverRightNav,
OverClose,
OverHeader,
OverName,
OverDate
OverDate,
OverSave,
OverMore,
OverIcon,
};
OverState _over, _down;
QPoint _lastAction;
QPoint _lastAction, _lastMouseMovePos;
bool _ignoringDropdown;
enum ControlsState {
ControlsShowing,
ControlsShown,
ControlsHiding,
ControlsHidden,
};
ControlsState _controlsState;
uint64 _controlsAnimStarted;
QTimer _controlsHideTimer;
anim::fvalue a_cOpacity;
IconedButton _close, _save, _forward, _delete, _overview;
ContextMenu *_menu;
Dropdown _dropdown;
IconedButton *_btnSaveCancel, *_btnToMessage, *_btnShowInFolder, *_btnSaveAs, *_btnCopy, *_btnForward, *_btnDelete, *_btnViewAll;
QList<IconedButton*> _btns;
bool _receiveMouse;
bool _touchPress, _touchMove, _touchRightButton;
@ -149,6 +210,7 @@ private:
typedef QMap<OverState, anim::fvalue> ShowingOpacities;
ShowingOpacities _animOpacities;
void updateOverRect(OverState state);
bool updateOverState(OverState newState);
float64 overLevel(OverState control);
QColor overColor(const QColor &a, float64 ca, const QColor &b, float64 cb);

View File

@ -684,6 +684,13 @@ namespace MTP {
_mtp_internal::getSession(dc);
}
void ping() {
MTProtoSessionPtr session = _mtp_internal::getSession(0);
if (!session) return;
return session->ping();
}
void cancel(mtpRequestId requestId) {
mtpMsgId msgId = 0;
requestsDelays.remove(requestId);

View File

@ -101,6 +101,7 @@ namespace MTP {
inline mtpRequestId send(const TRequest &request, RPCDoneHandlerPtr onDone, RPCFailHandlerPtr onFail = RPCFailHandlerPtr(), int32 dc = 0, uint64 msCanWait = 0, mtpRequestId after = 0) {
return send(request, RPCResponseHandler(onDone, onFail), dc, msCanWait, after);
}
void ping();
void cancel(mtpRequestId req);
void killSession(int32 dc);
void stopSession(int32 dc);

View File

@ -1096,7 +1096,7 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
, firstSentAt(-1)
, _pingId(0)
, _pingIdToSend(0)
, _pingSent(0)
, _pingSendAt(0)
, _pingMsgId(0)
, restarted(false)
, keyId(0)
@ -1137,6 +1137,7 @@ MTProtoConnectionPrivate::MTProtoConnectionPrivate(QThread *thread, MTProtoConne
connect(this, SIGNAL(needToReceive()), sessionData->owner(), SLOT(tryToReceive()), Qt::QueuedConnection);
connect(this, SIGNAL(stateChanged(qint32)), sessionData->owner(), SLOT(onConnectionStateChange(qint32)), Qt::QueuedConnection);
connect(sessionData->owner(), SIGNAL(needToSend()), this, SLOT(tryToSend()), Qt::QueuedConnection);
connect(sessionData->owner(), SIGNAL(needToPing()), this, SLOT(onPingSendForce()), Qt::QueuedConnection);
connect(this, SIGNAL(sessionResetDone()), sessionData->owner(), SLOT(onResetDone()), Qt::QueuedConnection);
static bool _registered = false;
@ -1425,7 +1426,7 @@ void MTProtoConnectionPrivate::tryToSend() {
bool prependOnly = (state != MTProtoConnection::Connected);
mtpRequest pingRequest;
if (dc < _mtp_internal::dcShift) { // main session
if (!prependOnly && !_pingIdToSend && !_pingId && _pingSent + (MTPPingSendAfterAuto * 1000ULL) <= getms(true)) {
if (!prependOnly && !_pingIdToSend && !_pingId && _pingSendAt <= getms(true)) {
_pingIdToSend = MTP::nonce<mtpPingId>();
}
}
@ -1444,7 +1445,8 @@ void MTProtoConnectionPrivate::tryToSend() {
DEBUG_LOG(("MTP Info: sending ping_delay_disconnect, ping_id: %1").arg(_pingIdToSend));
}
_pingSent = pingRequest->msDate = getms(true); // > 0 - can send without container
pingRequest->msDate = getms(true); // > 0 - can send without container
_pingSendAt = pingRequest->msDate + (MTPPingSendAfterAuto * 1000ULL);
pingRequest->requestId = 0; // dont add to haveSent / wereAcked maps
if (dc < _mtp_internal::dcShift && !prependOnly) { // main session
@ -1733,7 +1735,7 @@ void MTProtoConnectionPrivate::socketStart(bool afterConfig) {
return;
}
setState(MTProtoConnection::Connecting);
_pingId = _pingMsgId = _pingIdToSend = _pingSent = 0;
_pingId = _pingMsgId = _pingIdToSend = _pingSendAt = 0;
_pingSender.stop();
const mtpDcOption *dcOption = 0;
@ -1840,17 +1842,25 @@ void MTProtoConnectionPrivate::onOldConnection() {
void MTProtoConnectionPrivate::onPingSender() {
if (_pingId) {
if (_pingSent + (MTPPingSendAfter - 1) * 1000 < getms(true)) {
if (_pingSendAt + (MTPPingSendAfter - MTPPingSendAfterAuto - 1) * 1000ULL < getms(true)) {
LOG(("Could not send ping for MTPPingSendAfter seconds, restarting.."));
return restart();
} else {
_pingSender.start(_pingSent + (MTPPingSendAfter * 1000) - getms(true));
_pingSender.start(_pingSendAt + (MTPPingSendAfter - MTPPingSendAfterAuto) * 1000ULL - getms(true));
}
} else {
emit needToSendAsync();
}
}
void MTProtoConnectionPrivate::onPingSendForce() {
if (!_pingId) {
_pingSendAt = 0;
DEBUG_LOG(("Will send ping!"));
tryToSend();
}
}
void MTProtoConnectionPrivate::onBadConnection() {
if (cConnectionType() != dbictAuto && cConnectionType() != dbictTcpProxy) {
return;
@ -2493,6 +2503,7 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
case mtpc_new_session_created: {
if (badTime) return 0;
const mtpPrime *start = from;
MTPNewSession msg(from, end);
const MTPDnew_session_created &data(msg.c_new_session_created());
DEBUG_LOG(("Message Info: new server session created, unique_id %1, first_msg_id %2, server_salt %3").arg(data.vunique_id.v).arg(data.vfirst_msg_id.v).arg(data.vserver_salt.v));
@ -2511,8 +2522,8 @@ int32 MTProtoConnectionPrivate::handleOneReceived(const mtpPrime *from, const mt
}
resendMany(toResend, 10, true);
mtpBuffer update(end - from);
if (end > from) memcpy(update.data(), from, (end - from) * sizeof(mtpPrime));
mtpBuffer update(from - start);
if (from > start) memcpy(update.data(), start, (from - start) * sizeof(mtpPrime));
QWriteLocker locker(sessionData->haveReceivedMutex());
mtpResponseMap &haveReceived(sessionData->haveReceivedMap());

View File

@ -341,6 +341,7 @@ public slots:
void restart(bool maybeBadKey = false);
void onPingSender();
void onPingSendForce();
void onBadConnection();
void onOldConnection();
void onSentSome(uint64 size);
@ -416,7 +417,7 @@ private:
void requestsAcked(const QVector<MTPlong> &ids, bool byResponse = false);
mtpPingId _pingId, _pingIdToSend;
uint64 _pingSent;
uint64 _pingSendAt;
mtpMsgId _pingMsgId;
SingleTimer _pingSender;

View File

@ -184,6 +184,7 @@ bool mtpFileLoader::loadPart() {
}
void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRequestId req) {
// uint64 ms = getms();
Requests::iterator i = requests.find(req);
if (i == requests.cend()) return loadNext();
@ -269,6 +270,7 @@ void mtpFileLoader::partLoaded(int32 offset, const MTPupload_File &result, mtpRe
}
emit progress(this);
loadNext();
// LOG(("Part loaded, handle time: %1").arg(getms() - ms));
}
bool mtpFileLoader::partFailed(const RPCError &error) {

View File

@ -63,7 +63,7 @@ void MTPSessionData::clear() {
}
MTProtoSession::MTProtoSession() : data(this), dcId(0), dc(0), msSendCall(0), msWait(0) {
MTProtoSession::MTProtoSession() : data(this), dcId(0), dc(0), msSendCall(0), msWait(0), _ping(false) {
}
void MTProtoSession::start(int32 dcenter) {
@ -171,7 +171,12 @@ void MTProtoSession::needToResumeAndSend() {
}
}
}
emit needToSend();
if (_ping) {
_ping = false;
emit needToPing();
} else {
emit needToSend();
}
}
void MTProtoSession::sendPong(quint64 msgId, quint64 pingId) {
@ -272,6 +277,11 @@ void MTProtoSession::cancel(mtpRequestId requestId, mtpMsgId msgId) {
}
}
void MTProtoSession::ping() {
_ping = true;
sendAnything(0);
}
int32 MTProtoSession::requestState(mtpRequestId requestId) const {
MTProtoConnections::const_iterator j = connections.cbegin(), e = connections.cend();
int32 result = MTP::RequestSent;
@ -471,7 +481,9 @@ void MTProtoSession::tryToReceive() {
responses.erase(i);
}
if (requestId <= 0) {
_mtp_internal::globalCallback(response.constData(), response.constData() + response.size());
if (dcId < int(_mtp_internal::dcShift)) { // call globalCallback only in main session
_mtp_internal::globalCallback(response.constData(), response.constData() + response.size());
}
} else {
_mtp_internal::execCallback(requestId, response.constData(), response.constData() + response.size());
}

View File

@ -236,6 +236,7 @@ public:
template <typename TRequest>
mtpRequestId send(const TRequest &request, RPCResponseHandler callbacks = RPCResponseHandler(), uint64 msCanWait = 0, bool needsLayer = false, bool toMainDC = false, mtpRequestId after = 0); // send mtp request
void ping();
void cancel(mtpRequestId requestId, mtpMsgId msgId);
int32 requestState(mtpRequestId requestId) const;
int32 getState() const;
@ -247,6 +248,7 @@ signals:
void authKeyCreated();
void needToSend();
void needToPing();
void needToRestart();
public slots:
@ -281,6 +283,8 @@ private:
uint64 msSendCall, msWait;
bool _ping;
QTimer timeouter;
SingleTimer sender;

View File

@ -1225,9 +1225,9 @@ void OverviewInner::saveContextFile() {
VideoLink *lnkVideo = dynamic_cast<VideoLink*>(_contextMenuLnk.data());
AudioLink *lnkAudio = dynamic_cast<AudioLink*>(_contextMenuLnk.data());
DocumentLink *lnkDocument = dynamic_cast<DocumentLink*>(_contextMenuLnk.data());
if (lnkVideo) VideoSaveLink(lnkVideo->video()).doSave(true);
if (lnkAudio) AudioSaveLink(lnkAudio->audio()).doSave(true);
if (lnkDocument) DocumentSaveLink(lnkDocument->document()).doSave(true);
if (lnkVideo) VideoSaveLink::doSave(lnkVideo->video(), true);
if (lnkAudio) AudioSaveLink::doSave(lnkAudio->audio(), true);
if (lnkDocument) DocumentSaveLink::doSave(lnkDocument->document(), true);
}
void OverviewInner::openContextFile() {
@ -1355,6 +1355,7 @@ void OverviewInner::mediaOverviewUpdated() {
prevDate = date;
}
int32 w = _width - st::msgMargin.left() - st::msgMargin.right();
media->initDimensions(item);
y += media->countHeight(item, w) + st::msgMargin.top() + st::msgMargin.bottom(); // item height
if (_items.size() > in) {
_items[in].msgid = msgid;

View File

@ -906,7 +906,7 @@ void PsMainWindow::psClearNotifies(PeerId peerId) {
void PsMainWindow::psNotifyShown(NotifyWindow *w) {
}
void PsMainWindow::psPlatformNotify(HistoryItem *item) {
void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
PsApplication::PsApplication(int &argc, char **argv) : QApplication(argc, argv) {

View File

@ -64,7 +64,7 @@ public:
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);
void psPlatformNotify(HistoryItem *item);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter();

View File

@ -489,11 +489,11 @@ void PsMainWindow::psNotifyShown(NotifyWindow *w) {
psShowOverAll(w, false);
}
void PsMainWindow::psPlatformNotify(HistoryItem *item) {
void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
QString title = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->name : qsl("Telegram Desktop");
QString subtitle = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->notificationHeader() : QString();
QPixmap pix = (!App::passcoded() && cNotifyView() <= dbinvShowName) ? item->history()->peer->photo->pix(st::notifyMacPhotoSize) : QPixmap();
QString msg = (!App::passcoded() && cNotifyView() <= dbinvShowPreview) ? item->notificationText() : lang(lng_notification_preview);
QString msg = (!App::passcoded() && cNotifyView() <= dbinvShowPreview) ? (fwdCount < 2 ? item->notificationText() : lng_forward_messages(lt_count, fwdCount)) : lang(lng_notification_preview);
_private.showNotify(item->history()->peer->id, item->id, pix, title, subtitle, msg, !App::passcoded() && (cNotifyView() <= dbinvShowPreview));
}

View File

@ -75,7 +75,7 @@ public:
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);
void psPlatformNotify(HistoryItem *item);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
bool eventFilter(QObject *obj, QEvent *evt);

View File

@ -159,6 +159,7 @@ namespace {
QPainter p(&cornersImage);
p.drawPixmap(QPoint(0, 0), App::sprite(), topLeft);
}
if (rtl()) cornersImage = cornersImage.mirrored(true, false);
uchar *bits = cornersImage.bits();
if (bits) {
for (
@ -1371,7 +1372,7 @@ void PsMainWindow::psClearNotifies(PeerId peerId) {
void PsMainWindow::psNotifyShown(NotifyWindow *w) {
}
void PsMainWindow::psPlatformNotify(HistoryItem *item) {
void PsMainWindow::psPlatformNotify(HistoryItem *item, int32 fwdCount) {
}
PsApplication::PsApplication(int &argc, char **argv) : QApplication(argc, argv) {
@ -1594,6 +1595,21 @@ void PsUpdateDownloader::clearAll() {
deleteDir(cWorkingDir() + qsl("tupdates"));
}
QString winapiErrorWrap() {
WCHAR errMsg[2048];
DWORD errorCode = GetLastError();
LPTSTR errorText = NULL, errorTextDefault = L"(Unknown error)";
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&errorText, 0, 0);
if (!errorText) {
errorText = errorTextDefault;
}
StringCbPrintf(errMsg, sizeof(errMsg), L"Error code: %d, error message: %s", errorCode, errorText);
if (errorText != errorTextDefault) {
LocalFree(errorText);
}
return QString::fromWCharArray(errMsg);
}
void PsUpdateDownloader::unpackUpdate() {
QByteArray packed;
if (!outputFile.open(QIODevice::ReadOnly)) {
@ -1615,49 +1631,53 @@ void PsUpdateDownloader::unpackUpdate() {
deleteDir(tempDirPath);
deleteDir(readyDirPath);
QDir tempDir(tempDirPath), readyDir(readyDirPath);
if (tempDir.exists() || readyDir.exists()) {
LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!"));
return fatalFail();
}
uchar sha1Buffer[20];
bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen);
if (!goodSha1) {
LOG(("Update Error: bad SHA1 hash of update file!"));
return fatalFail();
}
RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(DevChannel ? UpdatesPublicDevKey : UpdatesPublicKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
RSA_free(pbKey);
QByteArray uncompressed;
int32 uncompressedLen;
memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen);
uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size();
SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return fatalFail();
}
tempDir.mkdir(tempDir.absolutePath());
quint32 version;
{
QDir tempDir(tempDirPath), readyDir(readyDirPath);
if (tempDir.exists() || readyDir.exists()) {
LOG(("Update Error: cant clear tupdates/temp or tupdates/ready dir!"));
return fatalFail();
}
tempDirPath = tempDir.absolutePath();
readyDirPath = readyDir.absolutePath();
uchar sha1Buffer[20];
bool goodSha1 = !memcmp(compressed.constData() + hSigLen, hashSha1(compressed.constData() + hSigLen + hShaLen, compressedLen + hPropsLen + hOriginalSizeLen, sha1Buffer), hShaLen);
if (!goodSha1) {
LOG(("Update Error: bad SHA1 hash of update file!"));
return fatalFail();
}
RSA *pbKey = PEM_read_bio_RSAPublicKey(BIO_new_mem_buf(const_cast<char*>(DevChannel ? UpdatesPublicDevKey : UpdatesPublicKey), -1), 0, 0, 0);
if (!pbKey) {
LOG(("Update Error: cant read public rsa key!"));
return fatalFail();
}
if (RSA_verify(NID_sha1, (const uchar*)(compressed.constData() + hSigLen), hShaLen, (const uchar*)(compressed.constData()), hSigLen, pbKey) != 1) { // verify signature
RSA_free(pbKey);
LOG(("Update Error: bad RSA signature of update file!"));
return fatalFail();
}
RSA_free(pbKey);
QByteArray uncompressed;
int32 uncompressedLen;
memcpy(&uncompressedLen, compressed.constData() + hSigLen + hShaLen + hPropsLen, hOriginalSizeLen);
uncompressed.resize(uncompressedLen);
size_t resultLen = uncompressed.size();
SizeT srcLen = compressedLen;
int uncompressRes = LzmaUncompress((uchar*)uncompressed.data(), &resultLen, (const uchar*)(compressed.constData() + hSize), &srcLen, (const uchar*)(compressed.constData() + hSigLen + hShaLen), LZMA_PROPS_SIZE);
if (uncompressRes != SZ_OK) {
LOG(("Update Error: could not uncompress lzma, code: %1").arg(uncompressRes));
return fatalFail();
}
QDir().mkdir(tempDirPath);
quint32 version;
QBuffer buffer(&uncompressed);
buffer.open(QIODevice::ReadOnly);
QDataStream stream(&buffer);
@ -1712,15 +1732,15 @@ void PsUpdateDownloader::unpackUpdate() {
}
// create tdata/version file
tempDir.mkdir(QDir(tempDirPath + qsl("/tdata")).absolutePath());
QDir().mkdir(tempDirPath + qsl("/tdata"));
std::wstring versionString = ((version % 1000) ? QString("%1.%2.%3").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000)).arg(int(version % 1000)) : QString("%1.%2").arg(int(version / 1000000)).arg(int((version % 1000000) / 1000))).toStdWString();
DWORD versionNum = DWORD(version), versionLen = DWORD(versionString.size() * sizeof(WCHAR));
WCHAR versionStr[32];
memcpy(versionStr, versionString.c_str(), versionLen);
QFile fVersion(tempDirPath + qsl("/tdata/version"));
QFile fVersion(tempDirPath + qsl("/tdata/version"));
if (!fVersion.open(QIODevice::WriteOnly)) {
LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/version")));
LOG(("Update Error: cant write version file '%1'").arg(tempDirPath + qsl("/tdata/version")));
return fatalFail();
}
fVersion.write((const char*)&versionNum, sizeof(DWORD));
@ -1728,10 +1748,10 @@ void PsUpdateDownloader::unpackUpdate() {
fVersion.write((const char*)&versionStr[0], versionLen);
fVersion.close();
}
QFile tempDirFile(tempDir.absolutePath());
if (!tempDirFile.rename(readyDir.absolutePath())) {
LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2', error %3: %4").arg(tempDir.absolutePath()).arg(readyDir.absolutePath()).arg(tempDirFile.error()).arg(tempDirFile.errorString()));
std::wstring tempDirNative = QDir::toNativeSeparators(tempDirPath).toStdWString(), readyDirNative = QDir::toNativeSeparators(readyDirPath).toStdWString();
if (!MoveFile(tempDirNative.c_str(), readyDirNative.c_str())) {
LOG(("Update Error: cant rename temp dir '%1' to ready dir '%2'. %3").arg(QString::fromStdWString(tempDirNative)).arg(QString::fromStdWString(readyDirNative)).arg(winapiErrorWrap()));
return fatalFail();
}
deleteDir(tempDirPath);

View File

@ -63,7 +63,7 @@ public:
void psActivateNotify(NotifyWindow *w);
void psClearNotifies(PeerId peerId = 0);
void psNotifyShown(NotifyWindow *w);
void psPlatformNotify(HistoryItem *item);
void psPlatformNotify(HistoryItem *item, int32 fwdCount);
void psUpdateCounter();

View File

@ -20,6 +20,9 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "settings.h"
#include "lang.h"
bool gRtl = false;
Qt::LayoutDirection gLangDir = Qt::LeftToRight;
mtpDcOptions gDcOptions;
bool gTestMode = false;
@ -67,7 +70,7 @@ bool gCtrlEnter = false;
QPixmapPointer gChatBackground = 0;
int32 gChatBackgroundId = 0;
QPixmapPointer gChatDogImage = 0;
bool gTileBackground = true;
bool gTileBackground = false;
uint32 gConnectionsInSession = 1;
QString gLoggedPhoneNumber;

View File

@ -41,6 +41,12 @@ inline void cSet##Name(const Type &Name) { \
g##Name = Name; \
}
DeclareSetting(bool, Rtl);
DeclareSetting(Qt::LayoutDirection, LangDir);
inline bool rtl() {
return cRtl();
}
struct mtpDcOption {
mtpDcOption(int _id, const string &_host, const string &_ip, int _port) : id(_id), host(_host), ip(_ip), port(_port) {
}

View File

@ -22,9 +22,6 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin)
Q_IMPORT_PLUGIN(QWebpPlugin)
#elif defined Q_OS_MAC
Q_IMPORT_PLUGIN(AVFMediaPlayerServicePlugin)
Q_IMPORT_PLUGIN(AudioCaptureServicePlugin)
Q_IMPORT_PLUGIN(QM3uPlaylistPlugin)
Q_IMPORT_PLUGIN(QCoreWlanEnginePlugin)
Q_IMPORT_PLUGIN(QGenericEnginePlugin)
Q_IMPORT_PLUGIN(QCocoaIntegrationPlugin)

View File

@ -51,9 +51,8 @@ Copyright (c) 2014 John Preston, https://desktop.telegram.org
#include "mtproto/mtp.h"
#include "gui/twidget.h"
#include "gui/style_core.h"
#include "gui/twidget.h"
#include "gui/animation.h"
#include "gui/flatinput.h"
#include "gui/flattextarea.h"

View File

@ -230,7 +230,7 @@ void PhotoLink::onClick(Qt::MouseButton button) const {
}
}
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir()) {
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir) {
#ifdef Q_OS_WIN
name = name.replace(QRegularExpression(qsl("[\\\\\\/\\:\\*\\?\\\"\\<\\>\\|]")), qsl("_"));
#elif defined Q_OS_MAC
@ -307,8 +307,7 @@ void VideoOpenLink::onClick(Qt::MouseButton button) const {
}
}
void VideoSaveLink::doSave(bool forceSavingAs) const {
VideoData *data = video();
void VideoSaveLink::doSave(VideoData *data, bool forceSavingAs) {
if (!data->user && !data->date) return;
QString already = data->already(true);
@ -336,7 +335,7 @@ void VideoSaveLink::doSave(bool forceSavingAs) const {
void VideoSaveLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doSave();
doSave(video());
}
void VideoCancelLink::onClick(Qt::MouseButton button) const {
@ -399,8 +398,7 @@ void AudioOpenLink::onClick(Qt::MouseButton button) const {
}
}
void AudioSaveLink::doSave(bool forceSavingAs) const {
AudioData *data = audio();
void AudioSaveLink::doSave(AudioData *data, bool forceSavingAs) {
if (!data->user && !data->date) return;
QString already = data->already(true);
@ -429,7 +427,7 @@ void AudioSaveLink::doSave(bool forceSavingAs) const {
void AudioSaveLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doSave();
doSave(audio());
}
void AudioCancelLink::onClick(Qt::MouseButton button) const {
@ -470,7 +468,7 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
if (reader.supportsAnimation() && reader.imageCount() > 1 && App::hoveredLinkItem()) {
startGif(App::hoveredLinkItem(), already);
} else {
App::wnd()->showDocument(data, QPixmap::fromImage(App::readImage(already, 0, false), Qt::ColorOnly), App::hoveredLinkItem());
App::wnd()->showDocument(data, App::hoveredLinkItem());
}
} else {
psOpenFile(already);
@ -505,8 +503,7 @@ void DocumentOpenLink::onClick(Qt::MouseButton button) const {
}
}
void DocumentSaveLink::doSave(bool forceSavingAs) const {
DocumentData *data = document();
void DocumentSaveLink::doSave(DocumentData *data, bool forceSavingAs) {
if (!data->date) return;
QString already = data->already(true);
@ -547,7 +544,7 @@ void DocumentSaveLink::doSave(bool forceSavingAs) const {
void DocumentSaveLink::onClick(Qt::MouseButton button) const {
if (button != Qt::LeftButton) return;
doSave();
doSave(document());
}
void DocumentCancelLink::onClick(Qt::MouseButton button) const {

View File

@ -291,7 +291,7 @@ class VideoSaveLink : public VideoLink {
public:
VideoSaveLink(VideoData *video) : VideoLink(video) {
}
void doSave(bool forceSavingAs = false) const;
static void doSave(VideoData *video, bool forceSavingAs = false);
void onClick(Qt::MouseButton button) const;
};
@ -378,7 +378,7 @@ class AudioSaveLink : public AudioLink {
public:
AudioSaveLink(AudioData *audio) : AudioLink(audio) {
}
void doSave(bool forceSavingAs = false) const;
static void doSave(AudioData *audio, bool forceSavingAs = false);
void onClick(Qt::MouseButton button) const;
};
@ -481,7 +481,7 @@ class DocumentSaveLink : public DocumentLink {
public:
DocumentSaveLink(DocumentData *document) : DocumentLink(document) {
}
void doSave(bool forceSavingAs = false) const;
static void doSave(DocumentData *document, bool forceSavingAs = false);
void onClick(Qt::MouseButton button) const;
};
@ -528,6 +528,7 @@ struct WebPageData {
int32 pendingTill;
};
QString saveFileName(const QString &title, const QString &filter, const QString &prefix, QString name, bool savingAs, const QDir &dir = QDir());
MsgId clientMsgId();
struct MessageCursor {

View File

@ -4,10 +4,8 @@
<file>art/fonts/OpenSans-Bold.ttf</file>
<file>art/fonts/OpenSans-Semibold.ttf</file>
<file>art/newmsg.wav</file>
<file>art/bg.png</file>
<file>art/bg_125x.png</file>
<file>art/bg_150x.png</file>
<file>art/bg_200x.png</file>
<file>art/bg.jpg</file>
<file>art/bg0.png</file>
<file>art/sprite.png</file>
<file>art/sprite_125x.png</file>
<file>art/sprite_150x.png</file>

View File

@ -4,10 +4,8 @@
<file>art/fonts/OpenSans-Bold.ttf</file>
<file>art/fonts/OpenSans-Semibold.ttf</file>
<file>art/newmsg.wav</file>
<file>art/bg.png</file>
<file>art/bg_125x.png</file>
<file>art/bg_150x.png</file>
<file>art/bg_200x.png</file>
<file>art/bg.jpg</file>
<file>art/bg0.png</file>
<file>art/sprite.png</file>
<file>art/sprite_125x.png</file>
<file>art/sprite_150x.png</file>

View File

@ -68,7 +68,7 @@ void ConnectingWidget::onReconnect() {
MTP::restart();
}
NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y) : history(msg->history()), item(msg)
NotifyWindow::NotifyWindow(HistoryItem *msg, int32 x, int32 y, int32 fwdCount) : history(msg->history()), item(msg), fwdCount(fwdCount)
#ifdef Q_OS_WIN
, started(GetTickCount())
#endif
@ -192,8 +192,21 @@ void NotifyWindow::updateNotifyDisplay() {
if (!App::passcoded() && cNotifyView() <= dbinvShowPreview) {
const HistoryItem *textCachedFor = 0;
Text itemTextCache(itemWidth);
bool active = false;
item->drawInDialog(p, QRect(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height), active, textCachedFor, itemTextCache);
QRect r(st::notifyPhotoPos.x() + st::notifyPhotoSize + st::notifyTextLeft, st::notifyItemTop + st::msgNameFont->height, itemWidth, 2 * st::dlgFont->height);
if (fwdCount < 2) {
bool active = false;
item->drawInDialog(p, r, active, textCachedFor, itemTextCache);
} else {
p.setFont(st::dlgHistFont->f);
if (history->peer->chat) {
itemTextCache.setText(st::dlgHistFont, item->from()->name);
p.setPen(st::dlgSystemColor->p);
itemTextCache.drawElided(p, r.left(), r.top(), r.width(), st::dlgHistFont->height);
r.setTop(r.top() + st::dlgHistFont->height);
}
p.setPen(st::dlgTextColor->p);
p.drawText(r.left(), r.top() + st::dlgHistFont->ascent, lng_forward_messages(lt_count, fwdCount));
}
} else {
static QString notifyText = st::dlgHistFont->m.elidedText(lang(lng_notification_preview), Qt::ElideRight, itemWidth);
p.setPen(st::dlgSystemColor->p);
@ -739,9 +752,9 @@ void Window::showPhoto(PhotoData *photo, PeerData *peer) {
_mediaView->setFocus();
}
void Window::showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item) {
void Window::showDocument(DocumentData *doc, HistoryItem *item) {
layerHidden();
_mediaView->showDocument(doc, pix, item);
_mediaView->showDocument(doc, item);
_mediaView->activateWindow();
_mediaView->setFocus();
}
@ -1237,7 +1250,8 @@ void Window::notifySchedule(History *history, HistoryItem *item) {
App::wnd()->getNotifySetting(MTP_inputNotifyPeer(history->peer->input));
}
int delay = 100, t = unixtime();
HistoryForwarded *fwd = item->toHistoryForwarded();
int delay = fwd ? 500 : 100, t = unixtime();
uint64 ms = getms(true);
bool isOnline = main->lastWasOnline(), otherNotOld = ((cOtherOnline() * uint64(1000)) + cOnlineCloudTimeout() > t * uint64(1000));
bool otherLaterThanMe = (cOtherOnline() * uint64(1000) + (ms - main->lastSetOnline()) > t * uint64(1000));
@ -1354,7 +1368,9 @@ void Window::notifyShowNext(NotifyWindow *remove) {
for (NotifyWhenAlerts::iterator i = notifyWhenAlerts.begin(); i != notifyWhenAlerts.end();) {
while (!i.value().isEmpty() && i.value().begin().key() <= ms) {
NotifySettingsPtr n = i.key()->peer->notify, f = i.value().begin().value() ? i.value().begin().value()->notify : UnknownNotifySettings;
i.value().erase(i.value().begin());
while (!i.value().isEmpty() && i.value().begin().key() <= ms + 500) { // not more than one sound in 500ms from one peer - grouping
i.value().erase(i.value().begin());
}
if (n == EmptyNotifySettings || (n != UnknownNotifySettings && n->mute <= now)) {
alert = true;
} else if (f == EmptyNotifySettings || (f != UnknownNotifySettings && f->mute <= now)) { // notify by from()
@ -1435,40 +1451,64 @@ void Window::notifyShowNext(NotifyWindow *remove) {
notifyWaitTimer.start(next - ms);
break;
} else {
if (cCustomNotifies()) {
NotifyWindow *notify = new NotifyWindow(notifyItem, x, y);
notifyWindows.push_back(notify);
psNotifyShown(notify);
--count;
} else {
psPlatformNotify(notifyItem);
}
HistoryForwarded *fwd = notifyItem->toHistoryForwarded(); // forwarded notify grouping
int32 fwdCount = 1;
uint64 ms = getms(true);
History *history = notifyItem->history();
history->skipNotification();
NotifyWhenMaps::iterator j = notifyWhenMaps.find(history);
if (j == notifyWhenMaps.end() || !history->currentNotification()) {
if (j == notifyWhenMaps.end()) {
history->clearNotifications();
} else {
HistoryItem *nextNotify = 0;
do {
history->skipNotification();
if (!history->hasNotification()) {
break;
}
j.value().remove((fwd ? fwd : notifyItem)->id);
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
nextNotify = history->currentNotification();
notifyWaiter.value().msg = k.key();
notifyWaiter.value().when = k.value();
break;
}
history->skipNotification();
} while (history->hasNotification());
if (nextNotify) {
if (fwd) {
HistoryForwarded *nextFwd = nextNotify->toHistoryForwarded();
if (nextFwd && fwd->from() == nextFwd->from() && qAbs(int64(nextFwd->date.toTime_t()) - int64(fwd->date.toTime_t())) < 2) {
fwd = nextFwd;
++fwdCount;
} else {
nextNotify = 0;
}
} else {
nextNotify = 0;
}
}
} while (nextNotify);
}
if (cCustomNotifies()) {
NotifyWindow *notify = new NotifyWindow(notifyItem, x, y, fwdCount);
notifyWindows.push_back(notify);
psNotifyShown(notify);
--count;
} else {
psPlatformNotify(notifyItem, fwdCount);
}
if (!history->hasNotification()) {
notifyWaiters.erase(notifyWaiter);
if (j != notifyWhenMaps.end()) notifyWhenMaps.erase(j);
continue;
}
j.value().remove(notifyItem->id);
do {
NotifyWhenMap::const_iterator k = j.value().constFind(history->currentNotification()->id);
if (k != j.value().cend()) {
notifyWaiter.value().msg = k.key();
notifyWaiter.value().when = k.value();
break;
}
history->skipNotification();
} while (history->currentNotification());
if (!history->currentNotification()) {
notifyWaiters.erase(notifyWaiter);
notifyWhenMaps.erase(j);
continue;
}
}
} else {
break;
@ -1667,6 +1707,11 @@ void Window::mediaOverviewUpdated(PeerData *peer) {
_mediaView->mediaOverviewUpdated(peer);
}
void Window::documentUpdated(DocumentData *doc) {
if (!_mediaView || _mediaView->isHidden()) return;
_mediaView->documentUpdated(doc);
}
void Window::changingMsgId(HistoryItem *row, MsgId newId) {
if (main) main->changingMsgId(row, newId);
if (!_mediaView || _mediaView->isHidden()) return;

View File

@ -61,7 +61,7 @@ class NotifyWindow : public QWidget, public Animated {
public:
NotifyWindow(HistoryItem *item, int32 x, int32 y);
NotifyWindow(HistoryItem *item, int32 x, int32 y, int32 fwdCount);
void enterEvent(QEvent *e);
void leaveEvent(QEvent *e);
@ -101,6 +101,7 @@ private:
#endif
History *history;
HistoryItem *item;
int32 fwdCount;
IconedButton close;
QPixmap pm;
float64 alphaDuration, posDuration;
@ -176,7 +177,7 @@ public:
void showPhoto(const PhotoLink *lnk, HistoryItem *item = 0);
void showPhoto(PhotoData *photo, HistoryItem *item);
void showPhoto(PhotoData *photo, PeerData *item);
void showDocument(DocumentData *doc, QPixmap pix, HistoryItem *item);
void showDocument(DocumentData *doc, HistoryItem *item);
void showLayer(LayeredWidget *w, bool fast = false);
void replaceLayer(LayeredWidget *w);
void hideLayer(bool fast = false);
@ -227,6 +228,7 @@ public:
void sendPaths();
void mediaOverviewUpdated(PeerData *peer);
void documentUpdated(DocumentData *doc);
void changingMsgId(HistoryItem *row, MsgId newId);
bool isActive(bool cached = true) const;

View File

@ -11,7 +11,7 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.8.4</string>
<string>0.8.7</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleURLTypes</key>

Binary file not shown.

View File

@ -62,6 +62,7 @@
07BE85121A20961F008ACB9F /* moc_localstorage.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07BE85111A20961F008ACB9F /* moc_localstorage.cpp */; };
07C4753B1967DF1C00CAAFE9 /* switcher.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07C475391967DF1C00CAAFE9 /* switcher.cpp */; };
07C4753F1967E37300CAAFE9 /* moc_switcher.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07C4753E1967E37300CAAFE9 /* moc_switcher.cpp */; };
07CAACD81AEA64F00058E508 /* AudioUnit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 07CAACD71AEA64F00058E508 /* AudioUnit.framework */; };
07D7034B19B8755A00C4EED2 /* audio.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07D7034919B8755A00C4EED2 /* audio.cpp */; };
07D703BB19B88FB900C4EED2 /* moc_audio.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 07D703BA19B88FB900C4EED2 /* moc_audio.cpp */; };
07D7EABA1A597DD000838BA2 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 07D7EABC1A597DD000838BA2 /* Localizable.strings */; };
@ -92,7 +93,6 @@
1DF53374E3B6A31661548D08 /* historywidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = A83D2C19F756D3371E5999A8 /* historywidget.cpp */; settings = {ATTRIBUTES = (); }; };
26A81090DC8B5BCF7278FDFF /* qrc_telegram.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = D6FF6676816C4E374D374060 /* qrc_telegram.cpp */; settings = {ATTRIBUTES = (); }; };
298BFAB73BF182297584F96F /* contactsbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8C800AAC9549E6E9E7046BED /* contactsbox.cpp */; settings = {ATTRIBUTES = (); }; };
2A20C3BF118707980A2493E1 /* qtmultimedia_m3u in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 4EC011DBE92DD1FD208D94D2 /* qtmultimedia_m3u */; };
2A500B102B7CE80F3EB6E13E /* moc_mtpFileLoader.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 5591A965D1DC024FBDB40151 /* moc_mtpFileLoader.cpp */; settings = {ATTRIBUTES = (); }; };
2EF5D0AC9A18F9FE9B8A1ACA /* moc_introsignup.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 58A7114F60E7D09E73283983 /* moc_introsignup.cpp */; settings = {ATTRIBUTES = (); }; };
328FD74542F6E2C873EE4D4B /* ApplicationServices.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = DFD7912080BC557230093752 /* ApplicationServices.framework */; };
@ -116,7 +116,6 @@
4FEA8F51B7BC7CAC71347A1A /* connectionbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 51355181C0E6689B0B764543 /* connectionbox.cpp */; settings = {ATTRIBUTES = (); }; };
5058CB9D7BFFCE9F404A3700 /* Qt5Network in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 6700DD555BF1C0FC338FB959 /* Qt5Network */; };
565F748438E6CE0148C54AFE /* moc_flatinput.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 1E5EEB5782B6357057356F9E /* moc_flatinput.cpp */; settings = {ATTRIBUTES = (); }; };
597623A24AE744145BE84968 /* qtmedia_audioengine in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = A490341D0650372A5757B367 /* qtmedia_audioengine */; };
59789101736112A570B8EFE6 /* qjp2 in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = F0681BC551FC8A2B132FC646 /* qjp2 */; };
5CE57D44510AB2A11886AB52 /* title.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 2BB2A1BB8DB0993F78F4E3C7 /* title.cpp */; settings = {ATTRIBUTES = (); }; };
5FC914F652D1B16FDA8F0634 /* moc_contactsbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 26083D8E535AFF927591E1A5 /* moc_contactsbox.cpp */; settings = {ATTRIBUTES = (); }; };
@ -156,7 +155,6 @@
99F0A9B2AFE5ABDCBFC04510 /* mtpRPC.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 89F92B278CA31C393E245056 /* mtpRPC.cpp */; settings = {ATTRIBUTES = (); }; };
9A0D5DDC7816FC2538EB6A96 /* moc_window.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6B46A0EE3C3B9D3B5A24946E /* moc_window.cpp */; settings = {ATTRIBUTES = (); }; };
9A523F51135FD4E2464673A6 /* moc_mtpSession.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 63AF8520023B4EA40306CB03 /* moc_mtpSession.cpp */; settings = {ATTRIBUTES = (); }; };
9B6E32D1B74A14273D68E439 /* Qt5MultimediaWidgets in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 833B45FEF5DC4AD0E8ADA64A /* Qt5MultimediaWidgets */; };
9D294F23E02CFDF22C288382 /* moc_emojibox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 0C0DC15EB416789673526AA5 /* moc_emojibox.cpp */; settings = {ATTRIBUTES = (); }; };
9F33AC0693BC81B27D8F518D /* Qt5Gui in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 04391BE7A8B9D811E255100A /* Qt5Gui */; };
A0A6B97F7DBEC81004EC9461 /* confirmbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6610564B876E47D289A596DB /* confirmbox.cpp */; settings = {ATTRIBUTES = (); }; };
@ -169,7 +167,6 @@
ADE99904299B99EB6135E8D9 /* scrollarea.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 6E1859D714E4471E053D90C9 /* scrollarea.cpp */; settings = {ATTRIBUTES = (); }; };
B0B88EFE444C0DE673389418 /* moc_flatbutton.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = C9FFCCE4FCB845744636795F /* moc_flatbutton.cpp */; settings = {ATTRIBUTES = (); }; };
B2F5B08BFFBBE7E37D3863BB /* moc_button.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 46292F489228B60010794CE4 /* moc_button.cpp */; settings = {ATTRIBUTES = (); }; };
B3C3392253201C328D9C6736 /* qtaudio_coreaudio in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 3BBB805F6180E363BF89151A /* qtaudio_coreaudio */; };
B3CD52E504409DC1B560024F /* countrycodeinput.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 751C8D0E0BE6D16937B77A2C /* countrycodeinput.cpp */; settings = {ATTRIBUTES = (); }; };
B460F624007324313696BE86 /* QuartzCore.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 7EC00404ACD5AB0E97726B0E /* QuartzCore.framework */; };
B6346B66B0A2228A91D8A5D9 /* mtpDC.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 315C7FACB4A9E18AA95486CA /* mtpDC.cpp */; settings = {ATTRIBUTES = (); }; };
@ -185,11 +182,9 @@
BE6AB9DF1C4880624131C669 /* Qt5Widgets in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 4689C06178B60B84E7F3A3B7 /* Qt5Widgets */; };
C03447C9A7D9FF73463B8BB5 /* countryinput.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 3E329D4547CC23585307FA32 /* countryinput.cpp */; settings = {ATTRIBUTES = (); }; };
C06DDE378A7AC1FA9E6FF69A /* qtiff in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = F2453BA07315EB9F34F1CD57 /* qtiff */; };
C0D2E925FB8B08D9AA280753 /* Qt5Multimedia in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 112159B026FDEF9CD4E24175 /* Qt5Multimedia */; };
C14E6C902F6435B3149ECD64 /* moc_profilewidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 48003469151B9DDE82E851FB /* moc_profilewidget.cpp */; settings = {ATTRIBUTES = (); }; };
C1F9D5CA8AF3AD8EBC9D7310 /* moc_application.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = E181C525E21A16F2D4396CA7 /* moc_application.cpp */; settings = {ATTRIBUTES = (); }; };
C329997D36D34D568CE16C9A /* moc_animation.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = A1479F94376F9732B57C69DB /* moc_animation.cpp */; settings = {ATTRIBUTES = (); }; };
C9CC5CE020283D113D81179C /* Qt5OpenGL in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = AA5379CB06E908AC80BE7B82 /* Qt5OpenGL */; };
CCA737EE379CDB10CC9A0F23 /* AVFoundation.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 21F907AB8D19BD779147A085 /* AVFoundation.framework */; };
CDB0266A8B7CB20A95266BCD /* emoji_config.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = B3062303CE8F4EB9325CB3DC /* emoji_config.cpp */; settings = {ATTRIBUTES = (); }; };
D0EECF370C58DDCACBC71BAD /* CoreWLAN.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = F26998DF735BCE5F975508ED /* CoreWLAN.framework */; };
@ -201,7 +196,6 @@
D7EF8F129FCCE9AB3F3F081F /* button.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 4D55B83DFDFE3D492CDBD27A /* button.cpp */; settings = {ATTRIBUTES = (); }; };
D846C6F212B438DC2FD5FF71 /* moc_dialogswidget.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 3B3ED09AB00290D78CF1181B /* moc_dialogswidget.cpp */; settings = {ATTRIBUTES = (); }; };
D87463318C8E5211C8C8670A /* stdafx.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 5A5431331A13AA7B07414240 /* stdafx.cpp */; settings = {ATTRIBUTES = (); }; };
DAD6F5593C3427F014531342 /* AudioUnit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 186D09F4CB713AD4B8BDD260 /* AudioUnit.framework */; };
DE6A34CA3A5561888FA01AF1 /* flatlabel.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 763ED3C6815ED6C89E352652 /* flatlabel.cpp */; settings = {ATTRIBUTES = (); }; };
DF259E9677CC63AF8754032B /* mtpConnection.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = B8D9AFA42E8633154A9817A2 /* mtpConnection.cpp */; settings = {ATTRIBUTES = (); }; };
DF36EA42D67ED39E58CB7DF9 /* settings.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8A28F7789408AA839F48A5F2 /* settings.cpp */; settings = {ATTRIBUTES = (); }; };
@ -216,7 +210,6 @@
EBE29731916DB43BF49FE7A4 /* aboutbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = C194EDD00F76216057D48A5C /* aboutbox.cpp */; settings = {ATTRIBUTES = (); }; };
ED2557A57C6782721DC494AF /* moc_connectionbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = FEC58F9D8A0963E5A9D4BE6F /* moc_connectionbox.cpp */; settings = {ATTRIBUTES = (); }; };
EDFF7E777D3A3730A9BB3FC2 /* QTKit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 2AC1C71FA3CD6FD909ED0276 /* QTKit.framework */; };
EEBE9C2FA7C9F066508EF99B /* qavfmediaplayer in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = EDD43CF4FA85D97A1140E973 /* qavfmediaplayer */; };
F26454630C80841CBDCFE1CA /* Foundation.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = FCC237CA5AD60B9BA4447615 /* Foundation.framework */; };
F278C423357CA99797EA30AB /* photosendbox.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = D1C9C77F1318F5A55C9BF289 /* photosendbox.cpp */; settings = {ATTRIBUTES = (); }; };
F2A75ACAC9DF6A3F4E5711E7 /* AppKit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 723F90793B2C195E2CCB2233 /* AppKit.framework */; };
@ -309,6 +302,7 @@
07C475391967DF1C00CAAFE9 /* switcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = switcher.cpp; path = SourceFiles/gui/switcher.cpp; sourceTree = SOURCE_ROOT; };
07C4753A1967DF1C00CAAFE9 /* switcher.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = switcher.h; path = SourceFiles/gui/switcher.h; sourceTree = SOURCE_ROOT; };
07C4753E1967E37300CAAFE9 /* moc_switcher.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_switcher.cpp; path = GeneratedFiles/Debug/moc_switcher.cpp; sourceTree = SOURCE_ROOT; };
07CAACD71AEA64F00058E508 /* AudioUnit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioUnit.framework; path = System/Library/Frameworks/AudioUnit.framework; sourceTree = SDKROOT; };
07D7034919B8755A00C4EED2 /* audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = audio.cpp; path = SourceFiles/audio.cpp; sourceTree = SOURCE_ROOT; };
07D7034A19B8755A00C4EED2 /* audio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = audio.h; path = SourceFiles/audio.h; sourceTree = SOURCE_ROOT; };
07D703BA19B88FB900C4EED2 /* moc_audio.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = moc_audio.cpp; path = GeneratedFiles/Debug/moc_audio.cpp; sourceTree = SOURCE_ROOT; };
@ -691,6 +685,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
07CAACD81AEA64F00058E508 /* AudioUnit.framework in Link Binary With Libraries */,
1BB705CDB741E2B7450201A5 /* Cocoa.framework in Link Binary With Libraries */,
328FD74542F6E2C873EE4D4B /* ApplicationServices.framework in Link Binary With Libraries */,
668DDDA0C55405E7FCFD6CA5 /* CoreServices.framework in Link Binary With Libraries */,
@ -707,15 +702,7 @@
CCA737EE379CDB10CC9A0F23 /* AVFoundation.framework in Link Binary With Libraries */,
B78304F135DEF1F7A68393A6 /* CoreMedia.framework in Link Binary With Libraries */,
F2A75ACAC9DF6A3F4E5711E7 /* AppKit.framework in Link Binary With Libraries */,
DAD6F5593C3427F014531342 /* AudioUnit.framework in Link Binary With Libraries */,
EEBE9C2FA7C9F066508EF99B /* qavfmediaplayer in Link Binary With Libraries */,
EDFF7E777D3A3730A9BB3FC2 /* QTKit.framework in Link Binary With Libraries */,
9B6E32D1B74A14273D68E439 /* Qt5MultimediaWidgets in Link Binary With Libraries */,
C9CC5CE020283D113D81179C /* Qt5OpenGL in Link Binary With Libraries */,
597623A24AE744145BE84968 /* qtmedia_audioengine in Link Binary With Libraries */,
B3C3392253201C328D9C6736 /* qtaudio_coreaudio in Link Binary With Libraries */,
2A20C3BF118707980A2493E1 /* qtmultimedia_m3u in Link Binary With Libraries */,
C0D2E925FB8B08D9AA280753 /* Qt5Multimedia in Link Binary With Libraries */,
EBA5E17368D2BBC6014E92B9 /* qcorewlanbearer in Link Binary With Libraries */,
D0EECF370C58DDCACBC71BAD /* CoreWLAN.framework in Link Binary With Libraries */,
8883FF366F2623E89D90A9E6 /* qgenericbearer in Link Binary With Libraries */,
@ -1212,6 +1199,7 @@
AF39DD055C3EF8226FBE929D /* Frameworks */ = {
isa = PBXGroup;
children = (
07CAACD71AEA64F00058E508 /* AudioUnit.framework */,
07055CC3194EE85B0008DEF6 /* libcrypto.a */,
AEA456A2F75ED9F5CDA7BCBE /* Cocoa.framework */,
4AF15B5A0A43EB62D6DAF211 /* libexif.a */,
@ -1683,7 +1671,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.4;
CURRENT_PROJECT_VERSION = 0.8.7;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@ -1701,7 +1689,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
CURRENT_PROJECT_VERSION = 0.8.4;
CURRENT_PROJECT_VERSION = 0.8.7;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@ -1727,10 +1715,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.4;
CURRENT_PROJECT_VERSION = 0.8.7;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.4;
DYLIB_CURRENT_VERSION = 0.8.7;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@ -1869,10 +1857,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.8.4;
CURRENT_PROJECT_VERSION = 0.8.7;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.8;
DYLIB_CURRENT_VERSION = 0.8.4;
DYLIB_CURRENT_VERSION = 0.8.7;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;

View File

@ -63,19 +63,16 @@ compiler_rcc_clean:
GeneratedFiles/qrc_telegram.cpp: SourceFiles/telegram.qrc \
SourceFiles/art/emoji.png \
SourceFiles/art/blank.gif \
SourceFiles/art/bg.png \
SourceFiles/art/bg.jpg \
SourceFiles/art/sprite_150x.png \
SourceFiles/art/sprite.png \
SourceFiles/art/icon256.png \
SourceFiles/art/emoji_150x.png \
SourceFiles/art/bg_150x.png \
SourceFiles/art/sprite_200x.png \
SourceFiles/art/newmsg.wav \
SourceFiles/art/sprite_125x.png \
SourceFiles/art/emoji_200x.png \
SourceFiles/art/bg_200x.png \
SourceFiles/art/emoji_125x.png \
SourceFiles/art/bg_125x.png \
SourceFiles/art/fonts/OpenSans-Regular.ttf \
SourceFiles/art/fonts/OpenSans-Bold.ttf \
SourceFiles/art/fonts/OpenSans-Semibold.ttf \

View File

@ -1,2 +1,2 @@
echo 8004 0.8.4 0
echo 8007 0.8.7 0
# AppVersion AppVersionStr DevChannel