diff --git a/QTCREATOR.md b/QTCREATOR.md
index 13baf5442e..d963f9badf 100644
--- a/QTCREATOR.md
+++ b/QTCREATOR.md
@@ -61,7 +61,7 @@ In Terminal go to **/home/user/TBuild/Libraries** and run
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libgpac-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texi2html zlib1g-dev
sudo apt-get install yasm
- ./configure --prefix=/usr/local --disable-programs --disable-pthreads --disable-doc --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
+ ./configure --prefix=/usr/local --disable-programs --disable-doc --disable-pthreads --disable-mmx --disable-everything --enable-libopus --enable-decoder=aac --enable-decoder=aac_latm --enable-decoder=aasc --enable-decoder=flac --enable-decoder=gif --enable-decoder=h264 --enable-decoder=h264_vdpau --enable-decoder=mp1 --enable-decoder=mp1float --enable-decoder=mp2 --enable-decoder=mp2float --enable-decoder=mp3 --enable-decoder=mp3adu --enable-decoder=mp3adufloat --enable-decoder=mp3float --enable-decoder=mp3on4 --enable-decoder=mp3on4float --enable-decoder=mpeg4 --enable-decoder=mpeg4_vdpau --enable-decoder=msmpeg4v2 --enable-decoder=msmpeg4v3 --enable-decoder=opus --enable-decoder=vorbis --enable-decoder=wavpack --enable-decoder=wmalossless --enable-decoder=wmapro --enable-decoder=wmav1 --enable-decoder=wmav2 --enable-decoder=wmavoice --enable-encoder=libopus --enable-hwaccel=h264_vaapi --enable-hwaccel=h264_vdpau --enable-hwaccel=mpeg4_vaapi --enable-hwaccel=mpeg4_vdpau --enable-parser=aac --enable-parser=aac_latm --enable-parser=flac --enable-parser=h264 --enable-parser=mpeg4video --enable-parser=mpegaudio --enable-parser=opus --enable-parser=vorbis --enable-demuxer=aac --enable-demuxer=flac --enable-demuxer=gif --enable-demuxer=h264 --enable-demuxer=mov --enable-demuxer=mp3 --enable-demuxer=ogg --enable-demuxer=wav --enable-muxer=ogg --enable-muxer=opus
make
sudo make install
diff --git a/Telegram/Resources/style.txt b/Telegram/Resources/style.txt
index 155785981b..a1f7a785cd 100644
--- a/Telegram/Resources/style.txt
+++ b/Telegram/Resources/style.txt
@@ -1197,6 +1197,18 @@ msgFileRedColor: #e47272;
msgFileYellowColor: #efc274;
msgFileGreenColor: #61b96e;
msgFileBlueColor: #72b1df;
+msgFileRedDark: #cd5b5e;
+msgFileYellowDark: #e6a561;
+msgFileGreenDark: #4da859;
+msgFileBlueDark: #5c9ece;
+msgFileRedOver: #c35154;
+msgFileYellowOver: #dc9c5a;
+msgFileGreenOver: #44a050;
+msgFileBlueOver: #5294c4;
+msgFileRedSelected: #9f6a82;
+msgFileYellowSelected: #b19d84;
+msgFileGreenSelected: #46a07e;
+msgFileBlueSelected: #5099d0;
msgFileMenuSize: size(36px, 36px);
msgFileSize: 44px;
@@ -2161,6 +2173,14 @@ overviewPhotoCheck: sprite(245px, 308px, 32px, 32px);
overviewPhotoChecked: sprite(278px, 308px, 32px, 32px);
overviewPhotoSelectOverlay: #0a7bb03f;
+overviewFilePadding: margins(0px, 3px, 16px, 3px);
+overviewFileSize: 70px;
+overviewFileNameTop: 7px;
+overviewFileStatusTop: 27px;
+overviewFileDateTop: 49px;
+overviewFileChecked: #2fa9e2;
+overviewFileCheck: #00000066;
+
// Mac specific
macAccessory: size(450, 90);
@@ -2346,11 +2366,12 @@ playlistPadding: 10px;
linksSearchMargin: margins(20px, 20px, 20px, 0px);
linksMaxWidth: 520px;
linksLetterFont: font(24px);
-linksMargin: 5px;
+linksMargin: margins(0px, 7px, 0px, 5px);
+linksTextTop: 6px;
linksBorder: 1px;
linksBorderFg: #eaeaea;
-linksDateColor: #000;
-linksDateMargin: 15px;
+linksDateColor: #808080;
+linksDateMargin: margins(0px, 15px, 0px, 2px);
linksPhotoCheck: sprite(184px, 196px, 16px, 16px);
linksPhotoChecked: sprite(168px, 196px, 16px, 16px);
diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp
index 9313e0b851..ca89de07c0 100644
--- a/Telegram/SourceFiles/application.cpp
+++ b/Telegram/SourceFiles/application.cpp
@@ -708,7 +708,7 @@ void Application::checkMapVersion() {
if (cDevVersion() && Local::oldMapVersion() < 9016) {
// versionFeatures = QString::fromUtf8("\xe2\x80\x94 Sticker management: manually rearrange your sticker packs, pack order is now synced across all your devices\n\xe2\x80\x94 Click and hold on a sticker to preview it before sending\n\xe2\x80\x94 New context menu for chats in chats list\n\xe2\x80\x94 Support for all existing emoji");// .replace('@', qsl("@") + QChar(0x200D));
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
- } else if (Local::oldMapVersion() < 9015) {
+ } else if (Local::oldMapVersion() < 9016) {
versionFeatures = lng_new_version_text(lt_gifs_link, qsl("https://telegram.org/blog/gif-revolution"), lt_bots_link, qsl("https://telegram.org/blog/inline-bots")).trimmed();
} else {
versionFeatures = lang(lng_new_version_minor).trimmed();
diff --git a/Telegram/SourceFiles/config.h b/Telegram/SourceFiles/config.h
index b78e8b3875..e41af83661 100644
--- a/Telegram/SourceFiles/config.h
+++ b/Telegram/SourceFiles/config.h
@@ -20,10 +20,10 @@ Copyright (c) 2014-2015 John Preston, https://desktop.telegram.org
*/
#pragma once
-static const int32 AppVersion = 9015;
-static const wchar_t *AppVersionStr = L"0.9.15";
+static const int32 AppVersion = 9016;
+static const wchar_t *AppVersionStr = L"0.9.16";
static const bool DevVersion = false;
-#define BETA_VERSION (9015007ULL) // just comment this line to build public version
+//#define BETA_VERSION (9015008ULL) // just comment this line to build public version
static const wchar_t *AppNameOld = L"Telegram Win (Unofficial)";
static const wchar_t *AppName = L"Telegram Desktop";
diff --git a/Telegram/SourceFiles/dropdown.cpp b/Telegram/SourceFiles/dropdown.cpp
index 0ccdfbf771..87d9fd97b2 100644
--- a/Telegram/SourceFiles/dropdown.cpp
+++ b/Telegram/SourceFiles/dropdown.cpp
@@ -1663,14 +1663,14 @@ void StickerPanInner::refreshStickers() {
updateSelected();
}
-void StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) {
+bool StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth) {
LayoutInlineItem *layout = 0;
if (savedGif) {
layout = layoutPrepareSavedGif(savedGif, (_inlineRows.size() * MatrixRowShift) + row.items.size());
} else if (result) {
layout = layoutPrepareInlineResult(result, (_inlineRows.size() * MatrixRowShift) + row.items.size());
}
- if (!layout) return;
+ if (!layout) return false;
layout->preload();
if (inlineRowFinalize(row, sumWidth, layout->fullLine())) {
@@ -1678,6 +1678,7 @@ void StickerPanInner::inlineRowsAddItem(DocumentData *savedGif, InlineResult *re
}
row.items.push_back(layout);
sumWidth += layout->maxWidth();
+ return true;
}
bool StickerPanInner::inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force) {
@@ -1770,7 +1771,7 @@ LayoutInlineItem *StickerPanInner::layoutPrepareInlineResult(InlineResult *resul
layout = new LayoutInlineGif(result, 0, false);
} else if (result->type == qstr("photo")) {
layout = new LayoutInlinePhoto(result, 0);
- } else if (result->type == qstr("web_player_video")) {
+ } else if (result->type == qstr("video")) {
layout = new LayoutInlineWebVideo(result);
} else if (result->type == qstr("article")) {
layout = new LayoutInlineArticle(result, _inlineWithThumb);
@@ -1901,14 +1902,14 @@ void StickerPanInner::clearInlineRowsPanel() {
clearInlineRows(false);
}
-void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) {
+int32 StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted) {
_inlineBot = bot;
if (results.isEmpty() && (!_inlineBot || _inlineBot->username != cInlineGifBotUsername())) {
if (resultsDeleted) {
clearInlineRows(true);
}
emit emptyInlineRows();
- return;
+ return 0;
}
if (_showingInlineItems) {
@@ -1921,7 +1922,7 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
_showingInlineItems = true;
_showingSavedGifs = false;
- int32 count = results.size(), from = validateExistingInlineRows(results);
+ int32 count = results.size(), from = validateExistingInlineRows(results), added = 0;
if (count) {
_inlineRows.reserve(count);
@@ -1929,7 +1930,9 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
row.items.reserve(SavedGifsMaxPerRow);
int32 sumWidth = 0;
for (int32 i = from; i < count; ++i) {
- inlineRowsAddItem(0, results.at(i), row, sumWidth);
+ if (inlineRowsAddItem(0, results.at(i), row, sumWidth)) {
+ ++added;
+ }
}
inlineRowFinalize(row, sumWidth, true);
}
@@ -1943,6 +1946,8 @@ void StickerPanInner::refreshInlineRows(UserData *bot, const InlineResults &resu
_lastMousePos = QCursor::pos();
updateSelected();
}
+
+ return added;
}
int32 StickerPanInner::validateExistingInlineRows(const InlineResults &results) {
@@ -3722,7 +3727,10 @@ void EmojiPan::inlineResultsDone(const MTPmessages_BotResults &result) {
} else if (adding) {
it.value()->nextOffset = QString();
}
- showInlineRows(!adding);
+
+ if (!showInlineRows(!adding)) {
+ it.value()->nextOffset = QString();
+ }
onScroll();
}
@@ -3782,7 +3790,7 @@ void EmojiPan::onEmptyInlineRows() {
}
}
-bool EmojiPan::refreshInlineRows() {
+bool EmojiPan::refreshInlineRows(int32 *added) {
bool clear = true;
InlineCache::const_iterator i = _inlineCache.constFind(_inlineQuery);
if (i != _inlineCache.cend()) {
@@ -3790,12 +3798,14 @@ bool EmojiPan::refreshInlineRows() {
_inlineNextOffset = i.value()->nextOffset;
}
if (clear) prepareShowHideCache();
- s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false);
+ int32 result = s_inner.refreshInlineRows(_inlineBot, clear ? InlineResults() : i.value()->results, false);
+ if (added) *added = result;
return !clear;
}
-void EmojiPan::showInlineRows(bool newResults) {
- bool clear = !refreshInlineRows();
+int32 EmojiPan::showInlineRows(bool newResults) {
+ int32 added = 0;
+ bool clear = !refreshInlineRows(&added);
if (newResults) s_scroll.scrollToY(0);
e_switch.updateText(clear ? QString() : _inlineBot->username);
@@ -3819,6 +3829,8 @@ void EmojiPan::showInlineRows(bool newResults) {
onSwitch();
}
}
+
+ return added;
}
void EmojiPan::recountContentMaxHeight() {
diff --git a/Telegram/SourceFiles/dropdown.h b/Telegram/SourceFiles/dropdown.h
index 9bbaf30ab2..b0cac7d405 100644
--- a/Telegram/SourceFiles/dropdown.h
+++ b/Telegram/SourceFiles/dropdown.h
@@ -344,7 +344,7 @@ public:
void refreshStickers();
void refreshRecentStickers(bool resize = true);
void refreshSavedGifs();
- void refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
+ int32 refreshInlineRows(UserData *bot, const InlineResults &results, bool resultsDeleted);
void refreshRecent();
void inlineBotChanged();
void hideInlineRowsPanel();
@@ -458,7 +458,7 @@ private:
InlineLayouts _inlineLayouts;
LayoutInlineItem *layoutPrepareInlineResult(InlineResult *result, int32 position);
- void inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
+ bool inlineRowsAddItem(DocumentData *savedGif, InlineResult *result, InlineRow &row, int32 &sumWidth);
bool inlineRowFinalize(InlineRow &row, int32 &sumWidth, bool force = false);
InlineRow &layoutInlineRow(InlineRow &row, int32 sumWidth = 0);
@@ -712,10 +712,10 @@ private:
QTimer _inlineRequestTimer;
void inlineBotChanged();
- void showInlineRows(bool newResults);
+ int32 showInlineRows(bool newResults);
bool hideOnNoInlineResults();
void recountContentMaxHeight();
- bool refreshInlineRows();
+ bool refreshInlineRows(int32 *added = 0);
UserData *_inlineBot;
QString _inlineQuery, _inlineNextQuery, _inlineNextOffset;
mtpRequestId _inlineRequestId;
diff --git a/Telegram/SourceFiles/gui/animation.cpp b/Telegram/SourceFiles/gui/animation.cpp
index e373f58a44..ee49bb92c1 100644
--- a/Telegram/SourceFiles/gui/animation.cpp
+++ b/Telegram/SourceFiles/gui/animation.cpp
@@ -225,7 +225,7 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
, _state(ClipReading)
, _width(0)
, _height(0)
-, _step(FirstFrameNotReadStep)
+, _step(WaitingForDimensionsStep)
, _paused(0)
, _autoplay(false)
, _private(0) {
@@ -248,47 +248,69 @@ ClipReader::ClipReader(const FileLocation &location, const QByteArray &data, Cal
_clipManagers.at(_threadIndex)->append(this, location, data);
}
-ClipReader::Frame *ClipReader::frameToShow() const { // 0 means not ready
- int32 step = _step.loadAcquire();
- if (step == FirstFrameNotReadStep) {
- return 0;
- } else if (step == WaitingForRequestStep) {
- return _frames;
- }
- return _frames + (((step + 1) / 2) % 3);
-}
-
-ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
- int32 step = _step.loadAcquire(), i = 0;
- if (step == WaitingForRequestStep) {
+ClipReader::Frame *ClipReader::frameToShow(int32 *index) const { // 0 means not ready
+ int32 step = _step.loadAcquire(), i;
+ if (step == WaitingForDimensionsStep) {
if (index) *index = 0;
return 0;
- } else if (step != FirstFrameNotReadStep) {
- i = (((step + 3) / 2) % 3);
+ } else if (step == WaitingForRequestStep) {
+ i = 0;
+ } else if (step == WaitingForFirstFrameStep) {
+ i = 0;
+ } else {
+ i = (step / 2) % 3;
}
if (index) *index = i;
return _frames + i;
}
-ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting) const {
- int32 step = _step.loadAcquire();
- if (step == FirstFrameNotReadStep || step == WaitingForRequestStep || (checkNotWriting && !(step % 2))) {
+ClipReader::Frame *ClipReader::frameToWrite(int32 *index) const { // 0 means not ready
+ int32 step = _step.loadAcquire(), i;
+ if (step == WaitingForDimensionsStep) {
+ i = 0;
+ } else if (step == WaitingForRequestStep) {
+ if (index) *index = 0;
+ return 0;
+ } else if (step == WaitingForFirstFrameStep) {
+ i = 0;
+ } else {
+ i = ((step + 2) / 2) % 3;
+ }
+ if (index) *index = i;
+ return _frames + i;
+}
+
+ClipReader::Frame *ClipReader::frameToWriteNext(bool checkNotWriting, int32 *index) const {
+ int32 step = _step.loadAcquire(), i;
+ if (step == WaitingForDimensionsStep || step == WaitingForRequestStep || (checkNotWriting && (step % 2))) {
+ if (index) *index = 0;
return 0;
}
- return _frames + (((step + 5) / 2) % 3);
+ i = ((step + 4) / 2) % 3;
+ if (index) *index = i;
+ return _frames + i;
}
void ClipReader::moveToNextShow() const {
int32 step = _step.loadAcquire();
- if (step % 2) {
- _step.storeRelease((step + 1) % 6);
+ if (step == WaitingForDimensionsStep) {
+ } else if (step == WaitingForRequestStep) {
+ _step.storeRelease(WaitingForFirstFrameStep);
+ } else if (step == WaitingForFirstFrameStep) {
+ } else if (!(step % 2)) {
+ _step.storeRelease(step + 1);
}
}
void ClipReader::moveToNextWrite() const {
int32 step = _step.loadAcquire();
- if (!(step % 2)) {
- _step.storeRelease(step + 1);
+ if (step == WaitingForDimensionsStep) {
+ _step.storeRelease(WaitingForRequestStep);
+ } else if (step == WaitingForRequestStep) {
+ } else if (step == WaitingForFirstFrameStep) {
+ _step.storeRelease(0);
+ } else if (step % 2) {
+ _step.storeRelease((step + 1) % 6);
}
}
@@ -313,7 +335,7 @@ void ClipReader::start(int32 framew, int32 frameh, int32 outerw, int32 outerh, b
request.outerh = outerh * factor;
request.rounded = rounded;
_frames[0].request = _frames[1].request = _frames[2].request = request;
- _step.storeRelease(0); // start working
+ moveToNextShow();
_clipManagers.at(_threadIndex)->start(this);
}
}
@@ -322,9 +344,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
Frame *frame = frameToShow();
t_assert(frame != 0);
- frame->displayed = true;
if (ms) {
- frame->when = ms;
+ frame->displayed.storeRelease(1);
if (_paused.loadAcquire()) {
_paused.storeRelease(0);
if (_clipManagers.size() <= _threadIndex) error();
@@ -332,6 +353,8 @@ QPixmap ClipReader::current(int32 framew, int32 frameh, int32 outerw, int32 oute
_clipManagers.at(_threadIndex)->update(this);
}
}
+ } else {
+ frame->displayed.storeRelease(-1); // displayed, but should be paused
}
int32 factor(cIntRetinaFactor());
@@ -412,7 +435,8 @@ public:
, _device(0)
, _dataSize(0) {
}
- virtual bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) = 0;
+ virtual bool readNextFrame() = 0;
+ virtual bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) = 0;
virtual int32 nextFrameDelay() = 0;
virtual bool start(bool onlyGifv) = 0;
virtual ~ClipReaderImplementation() {
@@ -459,30 +483,35 @@ public:
return false;
}
- QImage frame; // QGifHandler always reads first to internal QImage and returns it
- if (!_reader->read(&frame)) {
+ _frame = QImage(); // QGifHandler always reads first to internal QImage and returns it
+ if (!_reader->read(&_frame) || _frame.isNull()) {
return false;
}
--_framesLeft;
+ return true;
+ }
- if (size.isEmpty() || size == frame.size()) {
- int32 w = frame.width(), h = frame.height();
- if (to.width() == w && to.height() == h && to.format() == frame.format()) {
- if (to.byteCount() != frame.byteCount()) {
- int bpl = qMin(to.bytesPerLine(), frame.bytesPerLine());
+ bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) {
+ t_assert(!_frame.isNull());
+ if (size.isEmpty() || size == _frame.size()) {
+ int32 w = _frame.width(), h = _frame.height();
+ if (to.width() == w && to.height() == h && to.format() == _frame.format()) {
+ if (to.byteCount() != _frame.byteCount()) {
+ int bpl = qMin(to.bytesPerLine(), _frame.bytesPerLine());
for (int i = 0; i < h; ++i) {
- memcpy(to.scanLine(i), frame.constScanLine(i), bpl);
+ memcpy(to.scanLine(i), _frame.constScanLine(i), bpl);
}
} else {
- memcpy(to.bits(), frame.constBits(), frame.byteCount());
+ memcpy(to.bits(), _frame.constBits(), _frame.byteCount());
}
} else {
- to = frame.copy();
+ to = _frame.copy();
}
} else {
- to = frame.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ to = _frame.scaled(size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
- hasAlpha = frame.hasAlphaChannel();
+ hasAlpha = _frame.hasAlphaChannel();
+ _frame = QImage();
return true;
}
@@ -502,6 +531,7 @@ public:
private:
QImageReader *_reader;
int32 _framesLeft, _frameDelay;
+ QImage _frame;
bool jumpToStart() {
if (_reader && _reader->jumpToImage(0)) {
@@ -540,6 +570,7 @@ public:
, _frame(0)
, _opened(false)
, _hadFrame(false)
+ , _frameRead(false)
, _packetSize(0)
, _packetData(0)
, _packetWas(false)
@@ -555,7 +586,7 @@ public:
_avpkt.size = 0;
}
- bool readNextFrame(QImage &to, bool &hasAlpha, const QSize &size) {
+ bool readNextFrame() {
int res;
while (true) {
if (_avpkt.size > 0) { // previous packet not finished
@@ -607,56 +638,7 @@ public:
}
if (got_frame) {
- _hadFrame = true;
-
- if (!_width || !_height) {
- _width = _frame->width;
- _height = _frame->height;
- if (!_width || !_height) {
- LOG(("Gif Error: Bad frame size %1").arg(logData()));
- return false;
- }
- }
-
- QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
- if (to.isNull() || to.size() != toSize) {
- to = QImage(toSize, QImage::Format_ARGB32);
- }
- hasAlpha = (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA));
- if (_frame->width == toSize.width() && _frame->height == toSize.height() && hasAlpha) {
- int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl);
- uchar *s = _frame->data[0], *d = to.bits();
- for (int32 i = 0, l = _frame->height; i < l; ++i) {
- memcpy(d + i * dbpl, s + i * sbpl, bpl);
- }
- } else {
- if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
- _swsSize = toSize;
- _swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), toSize.width(), toSize.height(), AV_PIX_FMT_BGRA, 0, 0, 0, 0);
- }
- uint8_t * toData[1] = { to.bits() };
- int toLinesize[1] = { to.bytesPerLine() };
- if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _swsSize.height()) {
- LOG(("Gif Error: Unable to sws_scale to good size %1, height %2, should be %3").arg(logData()).arg(res).arg(_swsSize.height()));
- return false;
- }
- }
-
- int64 duration = av_frame_get_pkt_duration(_frame);
- int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
- int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
- _currentFrameDelay = _nextFrameDelay;
- if (_frameMs + _currentFrameDelay < frameMs) {
- _currentFrameDelay = int32(frameMs - _frameMs);
- }
- if (duration == AV_NOPTS_VALUE) {
- _nextFrameDelay = 0;
- } else {
- _nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
- }
- _frameMs = frameMs;
-
- av_frame_unref(_frame);
+ _hadFrame = _frameRead = true;
return true;
}
@@ -681,6 +663,61 @@ public:
return false;
}
+ bool renderFrame(QImage &to, bool &hasAlpha, const QSize &size) {
+ t_assert(_frameRead);
+ _frameRead = false;
+
+ if (!_width || !_height) {
+ _width = _frame->width;
+ _height = _frame->height;
+ if (!_width || !_height) {
+ LOG(("Gif Error: Bad frame size %1").arg(logData()));
+ return false;
+ }
+ }
+
+ QSize toSize(size.isEmpty() ? QSize(_width, _height) : size);
+ if (to.isNull() || to.size() != toSize) {
+ to = QImage(toSize, QImage::Format_ARGB32);
+ }
+ hasAlpha = (_frame->format == AV_PIX_FMT_BGRA || (_frame->format == -1 && _codecContext->pix_fmt == AV_PIX_FMT_BGRA));
+ if (_frame->width == toSize.width() && _frame->height == toSize.height() && hasAlpha) {
+ int32 sbpl = _frame->linesize[0], dbpl = to.bytesPerLine(), bpl = qMin(sbpl, dbpl);
+ uchar *s = _frame->data[0], *d = to.bits();
+ for (int32 i = 0, l = _frame->height; i < l; ++i) {
+ memcpy(d + i * dbpl, s + i * sbpl, bpl);
+ }
+ } else {
+ if ((_swsSize != toSize) || (_frame->format != -1 && _frame->format != _codecContext->pix_fmt) || !_swsContext) {
+ _swsSize = toSize;
+ _swsContext = sws_getCachedContext(_swsContext, _frame->width, _frame->height, AVPixelFormat(_frame->format), toSize.width(), toSize.height(), AV_PIX_FMT_BGRA, 0, 0, 0, 0);
+ }
+ uint8_t * toData[1] = { to.bits() };
+ int toLinesize[1] = { to.bytesPerLine() }, res;
+ if ((res = sws_scale(_swsContext, _frame->data, _frame->linesize, 0, _frame->height, toData, toLinesize)) != _swsSize.height()) {
+ LOG(("Gif Error: Unable to sws_scale to good size %1, height %2, should be %3").arg(logData()).arg(res).arg(_swsSize.height()));
+ return false;
+ }
+ }
+
+ int64 duration = av_frame_get_pkt_duration(_frame);
+ int64 framePts = (_frame->pkt_pts == AV_NOPTS_VALUE) ? _frame->pkt_dts : _frame->pkt_pts;
+ int64 frameMs = (framePts * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
+ _currentFrameDelay = _nextFrameDelay;
+ if (_frameMs + _currentFrameDelay < frameMs) {
+ _currentFrameDelay = int32(frameMs - _frameMs);
+ }
+ if (duration == AV_NOPTS_VALUE) {
+ _nextFrameDelay = 0;
+ } else {
+ _nextFrameDelay = (duration * 1000LL * _fmtContext->streams[_streamId]->time_base.num) / _fmtContext->streams[_streamId]->time_base.den;
+ }
+ _frameMs = frameMs;
+
+ av_frame_unref(_frame);
+ return true;
+ }
+
int32 nextFrameDelay() {
return _currentFrameDelay;
}
@@ -776,7 +813,7 @@ private:
AVCodecContext *_codecContext;
int32 _streamId;
AVFrame *_frame;
- bool _opened, _hadFrame;
+ bool _opened, _hadFrame, _frameRead;
AVPacket _avpkt;
int _packetSize;
@@ -835,9 +872,7 @@ public:
, _frame(0)
, _width(0)
, _height(0)
- , _previousMs(0)
- , _currentMs(0)
- , _nextUpdateMs(0)
+ , _nextFrameWhen(0)
, _paused(false) {
if (_data.isEmpty() && !_location->accessEnable()) {
error();
@@ -851,7 +886,10 @@ public:
return error();
}
if (frame() && frame()->original.isNull()) {
- if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize())) {
+ if (!_implementation->readNextFrame()) {
+ return error();
+ }
+ if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize())) {
return error();
}
_width = frame()->original.width();
@@ -868,23 +906,22 @@ public:
return start(ms);
}
- if (!_paused && ms >= _nextUpdateMs) {
+ if (!_paused && ms >= _nextFrameWhen) {
return ClipProcessRepaint;
}
return ClipProcessWait;
}
ClipProcessResult finishProcess(uint64 ms) {
- _previousMs = _currentMs;
- if (!prepareNextFrame()) {
+ if (!readNextFrame()) {
return error();
}
- if (ms >= _nextUpdateMs) {
- if (!prepareNextFrame()) {
- return error();
- }
+ if (ms >= _nextFrameWhen && !readNextFrame(true)) {
+ return error();
+ }
+ if (!renderFrame()) {
+ return error();
}
- _currentMs = qMax(ms, _nextUpdateMs);
return ClipProcessCopyFrame;
}
@@ -893,15 +930,26 @@ public:
return qMax(delay, 5);
}
- bool prepareNextFrame() {
- t_assert(frame() != 0 && _request.valid());
- if (!_implementation->readNextFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) {
+ bool readNextFrame(bool keepup = false) {
+ if (!_implementation->readNextFrame()) {
+ return false;
+ }
+ _nextFrameWhen += nextFrameDelay();
+ if (keepup) {
+ _nextFrameWhen = qMax(_nextFrameWhen, getms());
+ }
+ return true;
+ }
+
+ bool renderFrame() {
+ t_assert(frame() != 0 && _request.valid());
+ if (!_implementation->renderFrame(frame()->original, frame()->alpha, QSize(_request.framew, _request.frameh))) {
return false;
}
- _nextUpdateMs = _currentMs + nextFrameDelay();
frame()->original.setDevicePixelRatio(_request.factor);
frame()->pix = QPixmap();
frame()->pix = _prepareFrame(_request, frame()->original, frame()->alpha, frame()->cache);
+ frame()->when = _nextFrameWhen;
return true;
}
@@ -962,11 +1010,12 @@ private:
ClipFrameRequest _request;
struct Frame {
- Frame() : alpha(true) {
+ Frame() : alpha(true), when(0) {
}
QPixmap pix;
QImage original, cache;
bool alpha;
+ uint64 when;
};
Frame _frames[3];
int32 _frame;
@@ -976,7 +1025,7 @@ private:
int32 _width, _height;
- uint64 _previousMs, _currentMs, _nextUpdateMs;
+ uint64 _nextFrameWhen;
bool _paused;
@@ -1070,13 +1119,16 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
if (result == ClipProcessStarted) {
_loadLevel.fetchAndAddRelaxed(reader->_width * reader->_height - AverageGifSize);
}
- if (!reader->_paused && (result == ClipProcessRepaint || result == ClipProcessWait)) {
- ClipReader::Frame *other = it.key()->frameToWriteNext(false);
- t_assert(other != 0);
- if (other->when && other->when + WaitBeforeGifPause < qMax(reader->_previousMs, ms)) {
- reader->_paused = true;
- it.key()->_paused.storeRelease(1);
- result = ClipProcessPaused;
+ if (!reader->_paused && result == ClipProcessRepaint) {
+ int32 ishowing, iprevious;
+ ClipReader::Frame *showing = it.key()->frameToShow(&ishowing), *previous = it.key()->frameToWriteNext(false, &iprevious);
+ t_assert(previous != 0 && showing != 0 && ishowing >= 0 && iprevious >= 0);
+ if (reader->_frames[ishowing].when > 0 && showing->displayed.loadAcquire() <= 0) { // current frame was not shown
+ if (reader->_frames[ishowing].when + WaitBeforeGifPause < ms || (reader->_frames[iprevious].when && previous->displayed.loadAcquire() <= 0)) {
+ reader->_paused = true;
+ it.key()->_paused.storeRelease(1);
+ result = ClipProcessPaused;
+ }
}
}
if (result == ClipProcessStarted || result == ClipProcessCopyFrame) {
@@ -1085,14 +1137,17 @@ bool ClipReadManager::handleProcessResult(ClipReaderPrivate *reader, ClipProcess
frame->clear();
frame->pix = reader->frame()->pix;
frame->original = reader->frame()->original;
- frame->displayed = false;
- it.key()->moveToNextWrite();
+ frame->displayed.storeRelease(0);
if (result == ClipProcessStarted) {
+ reader->_nextFrameWhen = ms;
+ it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
}
} else if (result == ClipProcessPaused) {
+ it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderReinit);
} else if (result == ClipProcessRepaint) {
+ it.key()->moveToNextWrite();
emit callback(it.key(), it.key()->threadIndex(), ClipReaderRepaint);
}
return true;
@@ -1174,7 +1229,7 @@ void ClipReadManager::process() {
return;
}
ms = getms();
- i.value() = reader->_nextUpdateMs ? reader->_nextUpdateMs : (ms + 86400 * 1000ULL);
+ i.value() = reader->_nextFrameWhen ? reader->_nextFrameWhen : (ms + 86400 * 1000ULL);
}
if (!reader->_paused && i.value() < minms) {
minms = i.value();
@@ -1224,7 +1279,7 @@ MTPDocumentAttribute clipReadAnimatedAttributes(const QString &fname, const QByt
FFMpegReaderImplementation *reader = new FFMpegReaderImplementation(&localloc, &localdata);
if (reader->start(true)) {
bool hasAlpha = false;
- if (reader->readNextFrame(cover, hasAlpha, QSize())) {
+ if (reader->readNextFrame() && reader->renderFrame(cover, hasAlpha, QSize())) {
if (cover.width() > 0 && cover.height() > 0 && cover.width() < cover.height() * 10 && cover.height() < cover.width() * 10) {
if (hasAlpha) {
QImage cacheForResize;
diff --git a/Telegram/SourceFiles/gui/animation.h b/Telegram/SourceFiles/gui/animation.h
index d6edea257f..b3aa52afa0 100644
--- a/Telegram/SourceFiles/gui/animation.h
+++ b/Telegram/SourceFiles/gui/animation.h
@@ -497,8 +497,9 @@ enum ClipReaderNotification {
};
enum ClipReaderSteps {
- FirstFrameNotReadStep = -2,
- WaitingForRequestStep = -1,
+ WaitingForDimensionsStep = -3, // before ClipReaderPrivate read the first image and got the original frame size
+ WaitingForRequestStep = -2, // before ClipReader got the original frame size and prepared the frame request
+ WaitingForFirstFrameStep = -1, // before ClipReaderPrivate got the frame request and started waiting for the 1-2 delay
};
class ClipReaderPrivate;
@@ -528,7 +529,7 @@ public:
}
bool currentDisplayed() const {
Frame *frame = frameToShow();
- return frame ? frame->displayed : true;
+ return frame ? (frame->displayed.loadAcquire() != 0) : true;
}
bool paused() const {
return _paused.loadAcquire();
@@ -542,7 +543,8 @@ public:
ClipState state() const;
bool started() const {
- return _step.loadAcquire() >= 0;
+ int32 step = _step.loadAcquire();
+ return (step == WaitingForFirstFrameStep) || (step >= 0);
}
bool ready() const;
@@ -561,7 +563,7 @@ private:
mutable QAtomicInt _step; // -2, -1 - init, 0-5 - work, show ((state + 1) / 2) % 3 state, write ((state + 3) / 2) % 3
struct Frame {
- Frame() : displayed(false), when(0) {
+ Frame() : displayed(false) {
}
void clear() {
pix = QPixmap();
@@ -570,13 +572,12 @@ private:
QPixmap pix;
QImage original;
ClipFrameRequest request;
- bool displayed;
- uint64 when;
+ QAtomicInt displayed;
};
mutable Frame _frames[3];
- Frame *frameToShow() const; // 0 means not ready
+ Frame *frameToShow(int32 *index = 0) const; // 0 means not ready
Frame *frameToWrite(int32 *index = 0) const; // 0 means not ready
- Frame *frameToWriteNext(bool check) const;
+ Frame *frameToWriteNext(bool check, int32 *index = 0) const;
void moveToNextShow() const;
void moveToNextWrite() const;
diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp
index 4f4415bd8c..2096bd2474 100644
--- a/Telegram/SourceFiles/history.cpp
+++ b/Telegram/SourceFiles/history.cpp
@@ -1392,7 +1392,9 @@ HistoryItem *History::createItem(HistoryBlock *block, const MTPMessage &msg, boo
case mtpc_messageMediaUnsupported:
default: badMedia = 1; break;
}
- if (badMedia) {
+ if (false && badMedia == 1) {
+// QString text(lng_message_unsupported(lt_link, qsl("https://desktop.telegram.org")));
+ } else if (badMedia) {
result = new HistoryServiceMsg(this, block, m.vid.v, date(m.vdate), lang((badMedia == 2) ? lng_message_empty : lng_media_unsupported), m.vflags.v, 0, m.has_from_id() ? m.vfrom_id.v : 0);
} else {
if ((m.has_fwd_date() && m.vfwd_date.v > 0) || (m.has_fwd_from_id() && peerFromMTP(m.vfwd_from_id) != 0)) {
@@ -3352,11 +3354,16 @@ void HistoryPhoto::draw(Painter &p, const HistoryItem *parent, const QRect &r, b
p.setOpacity(radialOpacity);
style::sprite icon;
if (radial || _data->loading()) {
- icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
+ DelayedStorageImage *delayed = _data->full->toDelayedStorageImage();
+ if (!delayed || !delayed->location().isNull()) {
+ icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
+ }
} else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
- p.drawSpriteCenter(inner, icon);
+ if (!icon.isEmpty()) {
+ p.drawSpriteCenter(inner, icon);
+ }
if (radial) {
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
@@ -3401,8 +3408,15 @@ void HistoryPhoto::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x
if (x >= skipx && y >= skipy && x < skipx + width && y < skipy + height) {
if (_data->uploading()) {
lnk = _cancell;
+ } else if (_data->loaded()) {
+ lnk = _openl;
+ } else if (_data->loading()) {
+ DelayedStorageImage *delayed = _data->full->toDelayedStorageImage();
+ if (!delayed || !delayed->location().isNull()) {
+ lnk = _cancell;
+ }
} else {
- lnk = _data->loaded() ? _openl : (_data->loading() ? _cancell : _savel);
+ lnk = _savel;
}
if (_caption.isEmpty() && parent->getMedia() == this) {
int32 fullRight = skipx + width, fullBottom = skipy + height;
@@ -4561,11 +4575,15 @@ void HistoryGif::draw(Painter &p, const HistoryItem *parent, const QRect &r, boo
if (_data->loaded() && !radial) {
icon = (selected ? st::msgFileInPlaySelected : st::msgFileInPlay);
} else if (radial || _data->loading()) {
- icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
+ if (parent->id > 0) {
+ icon = (selected ? st::msgFileInCancelSelected : st::msgFileInCancel);
+ }
} else {
icon = (selected ? st::msgFileInDownloadSelected : st::msgFileInDownload);
}
- p.drawSpriteCenter(inner, icon);
+ if (!icon.isEmpty()) {
+ p.drawSpriteCenter(inner, icon);
+ }
if (radial) {
p.setOpacity(1);
QRect rinner(inner.marginsRemoved(QMargins(st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine, st::msgFileRadialLine)));
@@ -4762,6 +4780,16 @@ void HistorySticker::initDimensions(const HistoryItem *parent) {
_height = _minh;
}
+int32 HistorySticker::resize(int32 width, const HistoryItem *parent) { // return new height
+ _width = qMin(width, _maxw);
+ if (const HistoryReply *reply = toHistoryReply(parent)) {
+ int32 usew = _maxw - st::msgReplyPadding.left() - reply->replyToWidth();
+ int32 rw = _width - usew - st::msgReplyPadding.left() - st::msgReplyPadding.left() - st::msgReplyPadding.right();
+ reply->resizeVia(rw);
+ }
+ return _height;
+}
+
void HistorySticker::draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const {
if (_width < st::msgPadding.left() + st::msgPadding.right() + 1) return;
@@ -5958,7 +5986,7 @@ void ViaInlineBotLink::onClick(Qt::MouseButton button) const {
HistoryMessageVia::HistoryMessageVia(int32 userId)
: bot(App::userLoaded(peerFromUser(userId)))
, width(0)
- , fullWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username))
+ , maxWidth(st::msgServiceNameFont->width(qsl("via @") + bot->username))
, lnk(new ViaInlineBotLink(bot)) {
}
@@ -5967,13 +5995,21 @@ bool HistoryMessageVia::isNull() const {
}
void HistoryMessageVia::resize(int32 availw) {
- if (width < fullWidth && availw > width) {
- if (availw < fullWidth) {
+ if (width < maxWidth && availw > width) {
+ if (availw < maxWidth) {
text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw);
width = st::msgServiceNameFont->width(text);
} else {
text = qsl("via @") + bot->username;
- width = fullWidth;
+ width = maxWidth;
+ }
+ } else if (availw < width) {
+ if (availw > 0) {
+ text = st::msgServiceNameFont->elided(qsl("via @") + bot->username, availw);
+ width = st::msgServiceNameFont->width(text);
+ } else {
+ text = QString();
+ width = 0;
}
}
}
@@ -6165,9 +6201,9 @@ void HistoryMessage::initDimensions() {
if (maxw > _maxw) _maxw = maxw;
_minh += _media->minHeight();
}
- if (via()) {
- if (st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw) {
- _maxw = st::msgPadding.left() + via()->fullWidth + st::msgPadding.right() > _maxw;
+ if (!_media && !displayFromName() && via() && !toHistoryForwarded()) {
+ if (st::msgPadding.left() + via()->maxWidth + st::msgPadding.right() > _maxw) {
+ _maxw = st::msgPadding.left() + via()->maxWidth + st::msgPadding.right();
}
}
} else {
@@ -6200,8 +6236,11 @@ void HistoryMessage::countPositionAndSize(int32 &left, int32 &width) const {
void HistoryMessage::fromNameUpdated() const {
if (!_media && displayFromName()) {
- int32 _namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right();
- if (_namew > _maxw) _maxw = _namew;
+ int32 namew = st::msgPadding.left() + _from->nameText.maxWidth() + st::msgPadding.right();
+ if (via() && !toHistoryForwarded()) {
+ namew += st::msgServiceFont->spacew + via()->maxWidth;
+ }
+ if (namew > _maxw) _maxw = namew;
}
}
@@ -6437,7 +6476,7 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
}
if (_from->nameVersion > _fromVersion) {
- fromNameUpdated();
+// fromNameUpdated();
_fromVersion = _from->nameVersion;
}
@@ -6464,6 +6503,10 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
p.setPen(_from->color);
}
_from->nameText.drawElided(p, r.left() + st::msgPadding.left(), r.top() + st::msgPadding.top(), width - st::msgPadding.left() - st::msgPadding.right());
+ if (via() && !toHistoryForwarded() && width > st::msgPadding.left() + st::msgPadding.right() + _from->nameText.maxWidth() + st::msgServiceFont->spacew) {
+ p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
+ p.drawText(r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew, r.top() + st::msgPadding.top() + st::msgServiceFont->ascent, via()->text);
+ }
r.setTop(r.top() + st::msgNameFont->height);
}
@@ -6495,15 +6538,15 @@ void HistoryMessage::draw(Painter &p, const QRect &r, uint32 selection, uint64 m
void HistoryMessage::drawMessageText(Painter &p, QRect trect, uint32 selection) const {
bool outbg = out() && !fromChannel(), selected = (selection == FullSelection);
- if (via()) {
+ if (!displayFromName() && via() && !toHistoryForwarded()) {
p.setFont(st::msgServiceNameFont);
- p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p);
+ p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
p.drawTextLeft(trect.left(), trect.top(), _history->width, via()->text);
trect.setY(trect.y() + st::msgServiceNameFont->height);
}
- p.setPen(st::msgColor->p);
- p.setFont(st::msgFont->f);
+ p.setPen(st::msgColor);
+ p.setFont(st::msgFont);
uint16 selectedFrom = (selection == FullSelection) ? 0 : (selection >> 16) & 0xFFFF;
uint16 selectedTo = (selection == FullSelection) ? 0 : selection & 0xFFFF;
_text.draw(p, trect.x(), trect.y(), trect.width(), Qt::AlignLeft, 0, -1, selectedFrom, selectedTo);
@@ -6549,8 +6592,10 @@ int32 HistoryMessage::resize(int32 width) {
} else {
_height += st::msgNameFont->height;
}
- }
- if (via()) {
+ if (via() && !toHistoryForwarded()) {
+ via()->resize(width - st::msgPadding.left() - st::msgPadding.right() - _from->nameText.maxWidth() - st::msgServiceFont->spacew);
+ }
+ } else if (via() && !toHistoryForwarded()) {
via()->resize(width - st::msgPadding.left() - st::msgPadding.right());
if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgNameFont->height + st::mediaHeaderSkip;
@@ -6612,9 +6657,15 @@ void HistoryMessage::getState(TextLinkPtr &lnk, HistoryCursorState &state, int32
if (drawBubble()) {
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
if (displayFromName()) { // from user left name
- if (x >= r.left() + st::msgPadding.left() && y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) {
- lnk = _from->lnk;
- return;
+ if (y >= r.top() + st::msgPadding.top() && y < r.top() + st::msgPadding.top() + st::msgNameFont->height) {
+ if (x >= r.left() + st::msgPadding.left() && x < r.left() + r.width() - st::msgPadding.right() && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth()) {
+ lnk = _from->lnk;
+ return;
+ }
+ if (via() && !toHistoryForwarded() && x >= r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew && x < r.left() + st::msgPadding.left() + _from->nameText.maxWidth() + st::msgServiceFont->spacew + via()->width) {
+ lnk = via()->lnk;
+ return;
+ }
}
r.setTop(r.top() + st::msgNameFont->height);
}
@@ -6629,7 +6680,7 @@ void HistoryMessage::getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorStat
QRect trect(r.marginsAdded(-st::msgPadding));
- if (via()) {
+ if (!displayFromName() && via() && !toHistoryForwarded()) {
if (x >= trect.left() && y >= trect.top() && y < trect.top() + st::msgNameFont->height && x < trect.left() + via()->width) {
lnk = via()->lnk;
return;
@@ -6678,8 +6729,7 @@ void HistoryMessage::getSymbol(uint16 &symbol, bool &after, bool &upon, int32 x,
QRect r(left, st::msgMargin.top(), width, _height - st::msgMargin.top() - st::msgMargin.bottom());
if (displayFromName()) { // from user left name
r.setTop(r.top() + st::msgNameFont->height);
- }
- if (via()) {
+ } else if (via() && !toHistoryForwarded()) {
r.setTop(r.top() + st::msgNameFont->height);
}
QRect trect(r.marginsAdded(-st::msgPadding));
@@ -6765,12 +6815,16 @@ void HistoryForwarded::initDimensions() {
HistoryMessage::initDimensions();
if (!_media) {
int32 _namew = st::msgPadding.left() + fromWidth + fwdFromName.maxWidth() + st::msgPadding.right();
+ if (via()) {
+ _namew += st::msgServiceFont->spacew + via()->maxWidth;
+ }
if (_namew > _maxw) _maxw = _namew;
}
}
void HistoryForwarded::fwdNameUpdated() const {
- fwdFromName.setText(st::msgServiceNameFont, App::peerName(fwdFrom), _textNameOptions);
+ QString fwdName((via() && fwdFrom->isUser()) ? fwdFrom->asUser()->firstName : App::peerName(fwdFrom));
+ fwdFromName.setText(st::msgServiceNameFont, fwdName, _textNameOptions);
}
void HistoryForwarded::draw(Painter &p, const QRect &r, uint32 selection, uint64 ms) const {
@@ -6788,10 +6842,17 @@ void HistoryForwarded::drawForwardedFrom(Painter &p, int32 x, int32 y, int32 w,
p.setPen((selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg))->p);
p.setFont(serviceFont);
- if (w >= fromWidth) {
+ if (via() && w > fromWidth + fwdFromName.maxWidth() + serviceFont->spacew) {
p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
- p.setFont(serviceName->f);
+ p.setFont(serviceName);
+ fwdFromName.draw(p, x + fromWidth, y, w - fromWidth);
+
+ p.drawText(x + fromWidth + fwdFromName.maxWidth() + serviceFont->spacew, y + serviceFont->ascent, via()->text);
+ } else if (w > fromWidth) {
+ p.drawText(x, y + serviceFont->ascent, lang(lng_forwarded_from));
+
+ p.setFont(serviceName);
fwdFromName.drawElided(p, x + fromWidth, y, w - fromWidth);
} else {
p.drawText(x, y + serviceFont->ascent, serviceFont->elided(lang(lng_forwarded_from), w));
@@ -6810,11 +6871,14 @@ int32 HistoryForwarded::resize(int32 width) {
HistoryMessage::resize(width);
if (drawBubble()) {
if (displayForwardedFrom()) {
- if (emptyText() && !displayFromName() && !via()) {
+ if (emptyText() && !displayFromName()) {
_height += st::msgPadding.top() + st::msgServiceNameFont->height + st::mediaHeaderSkip;
} else {
_height += st::msgServiceNameFont->height;
}
+ if (via()) {
+ via()->resize(width - st::msgPadding.left() - st::msgPadding.right() - fromWidth - fwdFromName.maxWidth() - st::msgServiceFont->spacew);
+ }
}
}
return _height;
@@ -6876,6 +6940,8 @@ void HistoryForwarded::getForwardedState(TextLinkPtr &lnk, HistoryCursorState &s
state = HistoryDefaultCursorState;
if (x >= fromWidth && x < w && x < fromWidth + fwdFromName.maxWidth()) {
lnk = fwdFrom->lnk;
+ } else if (via() && x >= fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew && x < w && x < fromWidth + fwdFromName.maxWidth() + st::msgServiceFont->spacew + via()->maxWidth) {
+ lnk = via()->lnk;
} else {
lnk = TextLinkPtr();
}
@@ -6910,7 +6976,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, const MTPDmess
, replyToMsgId(msg.vreply_to_msg_id.v)
, replyToMsg(0)
, replyToVersion(0)
-, _maxReplyWidth(0) {
+, _maxReplyWidth(0)
+, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@@ -6921,7 +6988,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo)
, replyToMsg(0)
, replyToVersion(0)
-, _maxReplyWidth(0) {
+, _maxReplyWidth(0)
+, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@@ -6932,7 +7000,8 @@ HistoryReply::HistoryReply(History *history, HistoryBlock *block, MsgId msgId, i
, replyToMsgId(replyTo)
, replyToMsg(0)
, replyToVersion(0)
-, _maxReplyWidth(0) {
+, _maxReplyWidth(0)
+, _replyToVia(0) {
if (!updateReplyTo() && App::api()) {
App::api()->requestReplyTo(this, history->peer->asChannel(), replyToMsgId);
}
@@ -6952,6 +7021,9 @@ void HistoryReply::initDimensions() {
HistoryMessage::initDimensions();
if (!_media) {
int32 replyw = st::msgPadding.left() + _maxReplyWidth - st::msgReplyPadding.left() - st::msgReplyPadding.right() + st::msgPadding.right();
+ if (replyToVia()) {
+ replyw += st::msgServiceFont->spacew + via()->maxWidth;
+ }
if (replyw > _maxw) _maxw = replyw;
}
}
@@ -6959,6 +7031,7 @@ void HistoryReply::initDimensions() {
bool HistoryReply::updateReplyTo(bool force) {
if (replyToMsg || !replyToMsgId) return true;
replyToMsg = App::histItemById(channelId(), replyToMsgId);
+
if (replyToMsg) {
App::historyRegReply(this, replyToMsg);
replyToText.setText(st::msgFont, replyToMsg->inReplyText(), _textDlgOptions);
@@ -6966,6 +7039,11 @@ bool HistoryReply::updateReplyTo(bool force) {
replyToNameUpdated();
replyToLnk = TextLinkPtr(new MessageLink(replyToMsg->history()->peer->id, replyToMsg->id));
+ if (!replyToMsg->toHistoryForwarded()) {
+ if (UserData *bot = replyToMsg->viaBot()) {
+ _replyToVia = new HistoryMessageVia(peerToUser(bot->id));
+ }
+ }
} else if (force) {
replyToMsgId = 0;
}
@@ -6978,12 +7056,17 @@ bool HistoryReply::updateReplyTo(bool force) {
void HistoryReply::replyToNameUpdated() const {
if (replyToMsg) {
- replyToName.setText(st::msgServiceNameFont, App::peerName(replyToMsg->from()), _textNameOptions);
+ QString name = (replyToVia() && replyToMsg->from()->isUser()) ? replyToMsg->from()->asUser()->firstName : App::peerName(replyToMsg->from());
+ replyToName.setText(st::msgServiceNameFont, name, _textNameOptions);
replyToVersion = replyToMsg->from()->nameVersion;
bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
int32 previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
+ int32 w = replyToName.maxWidth();
+ if (replyToVia()) {
+ w += st::msgServiceFont->spacew + replyToVia()->maxWidth;
+ }
- _maxReplyWidth = previewSkip + qMax(replyToName.maxWidth(), qMin(replyToText.maxWidth(), 4 * replyToName.maxWidth()));
+ _maxReplyWidth = previewSkip + qMax(w, qMin(replyToText.maxWidth(), 4 * w));
} else {
_maxReplyWidth = st::msgDateFont->width(lang(replyToMsgId ? lng_profile_loading : lng_deleted_message));
}
@@ -7056,6 +7139,10 @@ void HistoryReply::drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selec
p.setPen(selected ? (outbg ? st::msgOutServiceFgSelected : st::msgInServiceFgSelected) : (outbg ? st::msgOutServiceFg : st::msgInServiceFg));
}
replyToName.drawLeftElided(p, x + st::msgReplyBarSkip + previewSkip, y + st::msgReplyPadding.top(), w - st::msgReplyBarSkip - previewSkip, w + 2 * x);
+ if (replyToVia() && w > st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew) {
+ p.setFont(st::msgServiceFont);
+ p.drawText(x + st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew, y + st::msgReplyPadding.top() + st::msgServiceFont->ascent, replyToVia()->text);
+ }
HistoryMessage *replyToAsMsg = replyToMsg->toHistoryMessage();
if (likeService) {
@@ -7094,10 +7181,23 @@ int32 HistoryReply::resize(int32 width) {
} else {
_height += st::msgReplyPadding.top() + st::msgReplyBarSize.height() + st::msgReplyPadding.bottom();
}
+ if (replyToVia()) {
+ bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
+ int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
+ replyToVia()->resize(width - st::msgPadding.left() - st::msgPadding.right() - st::msgReplyBarSkip + previewSkip + replyToName.maxWidth() + st::msgServiceFont->spacew);
+ }
}
return _height;
}
+void HistoryReply::resizeVia(int32 w) const {
+ if (!replyToVia()) return;
+
+ bool hasPreview = replyToMsg->getMedia() ? replyToMsg->getMedia()->hasReplyPreview() : false;
+ int previewSkip = hasPreview ? (st::msgReplyBarSize.height() + st::msgReplyBarSkip - st::msgReplyBarSize.width() - st::msgReplyBarPos.x()) : 0;
+ replyToVia()->resize(w - st::msgReplyBarSkip - previewSkip - replyToName.maxWidth() - st::msgServiceFont->spacew);
+}
+
bool HistoryReply::hasPoint(int32 x, int32 y) const {
if (drawBubble()) {
int32 left = 0, width = 0;
@@ -7186,6 +7286,7 @@ HistoryReply::~HistoryReply() {
} else if (replyToMsgId && App::api()) {
App::api()->itemRemoved(this);
}
+ deleteAndMark(_replyToVia);
}
void HistoryServiceMsg::setMessageByAction(const MTPmessageAction &action) {
diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h
index 326f631767..b6a3821696 100644
--- a/Telegram/SourceFiles/history.h
+++ b/Telegram/SourceFiles/history.h
@@ -1680,6 +1680,7 @@ public:
}
void initDimensions(const HistoryItem *parent);
+ int32 resize(int32 width, const HistoryItem *parent);
void draw(Painter &p, const HistoryItem *parent, const QRect &r, bool selected, uint64 ms) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const HistoryItem *parent) const;
@@ -1979,7 +1980,7 @@ public:
UserData *bot;
QString text;
- int32 width, fullWidth;
+ int32 width, maxWidth;
TextLinkPtr lnk;
};
@@ -2164,7 +2165,7 @@ public:
}
QString selectedText(uint32 selection) const;
bool displayForwardedFrom() const {
- return (!_media || !_media->isDisplayed() || !_media->hideForwardedFrom());
+ return via() || !_media || !_media->isDisplayed() || !_media->hideForwardedFrom();
}
HistoryForwarded *toHistoryForwarded() {
@@ -2207,6 +2208,7 @@ public:
void drawReplyTo(Painter &p, int32 x, int32 y, int32 w, bool selected, bool likeService = false) const;
void drawMessageText(Painter &p, QRect trect, uint32 selection) const;
int32 resize(int32 width);
+ void resizeVia(int32 w) const;
bool hasPoint(int32 x, int32 y) const;
void getState(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y) const;
void getStateFromMessageText(TextLinkPtr &lnk, HistoryCursorState &state, int32 x, int32 y, const QRect &r) const;
@@ -2234,6 +2236,10 @@ protected:
mutable Text replyToName, replyToText;
mutable int32 replyToVersion;
mutable int32 _maxReplyWidth;
+ HistoryMessageVia *_replyToVia;
+ HistoryMessageVia *replyToVia() const {
+ return (_replyToVia && !_replyToVia->isNull()) ? _replyToVia : 0;
+ }
int32 toWidth;
};
diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp
index a635b3fa2d..703aa35efb 100644
--- a/Telegram/SourceFiles/historywidget.cpp
+++ b/Telegram/SourceFiles/historywidget.cpp
@@ -2630,6 +2630,8 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
, _migrated(0)
, _history(0)
, _histInited(false)
+, _lastScroll(0)
+, _lastScrolled(0)
, _toHistoryEnd(this, st::historyToEnd)
, _collapseComments(this)
, _attachMention(this)
@@ -2722,6 +2724,9 @@ HistoryWidget::HistoryWidget(QWidget *parent) : TWidget(parent)
connect(audioCapture(), SIGNAL(onDone(QByteArray,qint32)), this, SLOT(onRecordDone(QByteArray,qint32)));
}
+ _updateHistoryItems.setSingleShot(true);
+ connect(&_updateHistoryItems, SIGNAL(timeout()), this, SLOT(onUpdateHistoryItems()));
+
_scrollTimer.setSingleShot(false);
_sendActionStopTimer.setSingleShot(true);
@@ -3508,6 +3513,8 @@ void HistoryWidget::showHistory(const PeerId &peerId, MsgId showAtMsgId, bool re
_scroll.setWidget(_list);
_list->show();
+ _updateHistoryItems.stop();
+
if (_history->lastWidth || _history->isReadyFor(_showAtMsgId, _fixedInScrollMsgId, _fixedInScrollMsgTop)) {
_fixedInScrollMsgId = 0;
_fixedInScrollMsgTop = 0;
@@ -4360,6 +4367,11 @@ void HistoryWidget::onListScroll() {
break;
}
}
+
+ if (st != _lastScroll) {
+ _lastScrolled = getms();
+ _lastScroll = st;
+ }
}
void HistoryWidget::onVisibleChanged() {
@@ -4407,8 +4419,9 @@ void HistoryWidget::onSend(bool ctrlShiftEnter, MsgId replyTo) {
_saveDraftStart = getms();
onDraftSave();
- onCheckMentionDropdown();
+ if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();
+ if (!_emojiPan.isHidden()) _emojiPan.hideStart();
if (replyTo < 0) cancelReply(lastKeyboardUsed);
if (_previewData && _previewData->pendingTill) previewCancel();
@@ -5834,7 +5847,23 @@ bool HistoryWidget::isItemVisible(HistoryItem *item) {
void HistoryWidget::ui_repaintHistoryItem(const HistoryItem *item) {
if (_peer && _list && (item->history() == _history || (_migrated && item->history() == _migrated))) {
- _list->repaintItem(item);
+ uint64 ms = getms();
+ if (_lastScrolled + 100 <= ms) {
+ _list->repaintItem(item);
+ } else {
+ _updateHistoryItems.start(_lastScrolled + 100 - ms);
+ }
+ }
+}
+
+void HistoryWidget::onUpdateHistoryItems() {
+ if (!_list) return;
+
+ uint64 ms = getms();
+ if (_lastScrolled + 100 <= ms) {
+ _list->update();
+ } else {
+ _updateHistoryItems.start(_lastScrolled + 100 - ms);
}
}
@@ -6459,8 +6488,9 @@ void HistoryWidget::onInlineResultSend(InlineResult *result, UserData *bot) {
Local::writeRecentHashtagsAndBots();
}
- onCheckMentionDropdown();
+ if (!_attachMention.isHidden()) _attachMention.hideStart();
if (!_attachType.isHidden()) _attachType.hideStart();
+ if (!_emojiPan.isHidden()) _emojiPan.hideStart();
_field.setFocus();
}
diff --git a/Telegram/SourceFiles/historywidget.h b/Telegram/SourceFiles/historywidget.h
index 826c84556e..24a9bdad5b 100644
--- a/Telegram/SourceFiles/historywidget.h
+++ b/Telegram/SourceFiles/historywidget.h
@@ -682,6 +682,8 @@ public slots:
void onRecordDone(QByteArray result, qint32 samples);
void onRecordUpdate(qint16 level, qint32 samples);
+ void onUpdateHistoryItems();
+
private:
MsgId _replyToId;
@@ -771,6 +773,10 @@ private:
History *_migrated, *_history;
bool _histInited; // initial updateListSize() called
+ int32 _lastScroll;
+ uint64 _lastScrolled;
+ QTimer _updateHistoryItems; // gifs optimization
+
IconedButton _toHistoryEnd;
CollapseButton _collapseComments;
diff --git a/Telegram/SourceFiles/layout.cpp b/Telegram/SourceFiles/layout.cpp
index e1ac813791..e987cb60e3 100644
--- a/Telegram/SourceFiles/layout.cpp
+++ b/Telegram/SourceFiles/layout.cpp
@@ -193,6 +193,21 @@ style::color documentColor(int32 colorIndex) {
return colors[colorIndex & 3];
}
+style::color documentDarkColor(int32 colorIndex) {
+ static style::color colors[] = { st::msgFileBlueDark, st::msgFileGreenDark, st::msgFileRedDark, st::msgFileYellowDark };
+ return colors[colorIndex & 3];
+}
+
+style::color documentOverColor(int32 colorIndex) {
+ static style::color colors[] = { st::msgFileBlueOver, st::msgFileGreenOver, st::msgFileRedOver, st::msgFileYellowOver };
+ return colors[colorIndex & 3];
+}
+
+style::color documentSelectedColor(int32 colorIndex) {
+ static style::color colors[] = { st::msgFileBlueSelected, st::msgFileGreenSelected, st::msgFileRedSelected, st::msgFileYellowSelected };
+ return colors[colorIndex & 3];
+}
+
style::sprite documentCorner(int32 colorIndex) {
static style::sprite corners[] = { st::msgFileBlue, st::msgFileGreen, st::msgFileRed, st::msgFileYellow };
return corners[colorIndex & 3];
@@ -285,14 +300,14 @@ LayoutOverviewDate::LayoutOverviewDate(const QDate &date, bool month)
void LayoutOverviewDate::initDimensions() {
_maxw = st::normalFont->width(_text);
- _minh = st::linksDateMargin + st::normalFont->height + st::linksDateMargin + st::linksBorder;
+ _minh = st::linksDateMargin.top() + st::normalFont->height + st::linksDateMargin.bottom() + st::linksBorder;
}
void LayoutOverviewDate::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
- if (clip.intersects(QRect(0, st::linksDateMargin, _width, st::normalFont->height))) {
+ if (clip.intersects(QRect(0, st::linksDateMargin.top(), _width, st::normalFont->height))) {
p.setPen(st::linksDateColor);
- p.setFont(st::normalFont);
- p.drawTextLeft(0, st::linksDateMargin, _width, _text);
+ p.setFont(st::semiboldFont);
+ p.drawTextLeft(0, st::linksDateMargin.top(), _width, _text);
}
}
@@ -629,12 +644,24 @@ void LayoutOverviewAudio::paint(Painter &p, const QRect &clip, uint32 selection,
if (clip.intersects(rtlrect(nameleft, statustop, namewidth, st::normalFont->height, _width))) {
p.setFont(st::normalFont);
p.setPen(selected ? st::mediaInFgSelected : st::mediaInFg);
+ int32 unreadx = nameleft;
if (_statusSize == FileStatusSizeLoaded || _statusSize == FileStatusSizeReady) {
textstyleSet(&(selected ? st::mediaInStyleSelected : st::mediaInStyle));
_details.drawLeftElided(p, nameleft, statustop, namewidth, _width);
textstyleRestore();
+ unreadx += _details.maxWidth();
} else {
- p.drawTextLeft(nameleft, statustop, _width, _statusText);
+ int32 statusw = st::normalFont->width(_statusText);
+ p.drawTextLeft(nameleft, statustop, _width, _statusText, statusw);
+ unreadx += statusw;
+ }
+ if (_parent->isMediaUnread() && unreadx + st::mediaUnreadSkip + st::mediaUnreadSize <= _width) {
+ p.setPen(Qt::NoPen);
+ p.setBrush(selected ? st::msgFileInBgSelected : st::msgFileInBg);
+
+ p.setRenderHint(QPainter::HighQualityAntialiasing, true);
+ p.drawEllipse(rtlrect(unreadx + st::mediaUnreadSkip, statustop + st::mediaUnreadTop, st::mediaUnreadSize, st::mediaUnreadSize, _width));
+ p.setRenderHint(QPainter::HighQualityAntialiasing, false);
}
}
}
@@ -715,6 +742,7 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
, _data(document)
, _msgl(new MessageLink(parent))
, _namel(new DocumentOpenLink(_data))
+, _thumbForLoaded(false)
, _name(documentName(_data))
, _date(langDateTime(date(_data->date)))
, _namew(st::semiboldFont->width(_name))
@@ -728,17 +756,17 @@ LayoutOverviewDocument::LayoutOverviewDocument(DocumentData *document, HistoryIt
_data->thumb->load();
int32 tw = _data->thumb->width(), th = _data->thumb->height();
if (tw > th) {
- _thumbw = (tw * st::msgFileThumbSize) / th;
+ _thumbw = (tw * st::overviewFileSize) / th;
} else {
- _thumbw = st::msgFileThumbSize;
+ _thumbw = st::overviewFileSize;
}
} else {
_thumbw = 0;
}
_extw = st::semiboldFont->width(_ext);
- if (_extw > st::msgFileThumbSize - st::msgFileExtPadding * 2) {
- _ext = st::semiboldFont->elided(_ext, st::msgFileThumbSize - st::msgFileExtPadding * 2, Qt::ElideMiddle);
+ if (_extw > st::overviewFileSize - st::msgFileExtPadding * 2) {
+ _ext = st::semiboldFont->elided(_ext, st::overviewFileSize - st::msgFileExtPadding * 2, Qt::ElideMiddle);
_extw = st::semiboldFont->width(_ext);
}
}
@@ -748,7 +776,7 @@ void LayoutOverviewDocument::initDimensions() {
if (_data->song()) {
_minh = st::msgFilePadding.top() + st::msgFileSize + st::msgFilePadding.bottom();
} else {
- _minh = st::msgFileThumbPadding.top() + st::msgFileThumbSize + st::msgFileThumbPadding.bottom() + st::lineWidth;
+ _minh = st::overviewFilePadding.top() + st::overviewFileSize + st::overviewFilePadding.bottom() + st::lineWidth;
}
}
@@ -817,39 +845,40 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
p.drawSpriteCenter(inner, icon);
}
} else {
- nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right();
- nametop = st::linksBorder + st::msgFileThumbNameTop;
- statustop = st::linksBorder + st::msgFileThumbStatusTop;
- datetop = st::linksBorder + st::msgFileThumbLinkTop;
+ nameleft = st::overviewFileSize + st::overviewFilePadding.right();
+ nametop = st::linksBorder + st::overviewFileNameTop;
+ statustop = st::linksBorder + st::overviewFileStatusTop;
+ datetop = st::linksBorder + st::overviewFileDateTop;
- QRect shadow(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width));
- if (clip.intersects(shadow)) {
- p.fillRect(clip.intersected(shadow), st::linksBorderFg);
+ const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
+ t_assert(pcontext != 0);
+ QRect border(rtlrect(nameleft, 0, _width - nameleft, st::linksBorder, _width));
+ if (!pcontext->isAfterDate && clip.intersects(border)) {
+ p.fillRect(clip.intersected(border), st::linksBorderFg);
}
- QRect rthumb(rtlrect(0, st::linksBorder + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
+ QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width));
if (clip.intersects(rthumb)) {
if (wthumb) {
if (_data->thumb->loaded()) {
- QPixmap thumb = loaded ? _data->thumb->pixSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize) : _data->thumb->pixBlurredSingle(_thumbw, 0, st::msgFileThumbSize, st::msgFileThumbSize);
- p.drawPixmap(rthumb.topLeft(), thumb);
+ if (_thumb.isNull() || loaded != _thumbForLoaded) {
+ _thumbForLoaded = loaded;
+ _thumb = _data->thumb->pixNoCache(_thumbw, 0, true, !_thumbForLoaded, false, st::overviewFileSize, st::overviewFileSize);
+ }
+ p.drawPixmap(rthumb.topLeft(), _thumb);
} else {
- App::roundRect(p, rthumb, st::black, BlackCorners);
+ p.fillRect(rthumb, st::black);
}
} else {
- App::roundRect(p, rthumb, documentColor(_colorIndex), documentCorners(_colorIndex));
- if (!radial && loaded) {
- style::sprite icon = documentCorner(_colorIndex);
- p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - icon.pxWidth()), 0), icon);
- if (!_ext.isEmpty()) {
- p.setFont(st::semiboldFont);
- p.setPen(st::white);
- p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::msgFileExtTop + st::semiboldFont->ascent, _ext);
- }
+ p.fillRect(rthumb, documentColor(_colorIndex));
+ if (!radial && loaded && !_ext.isEmpty()) {
+ p.setFont(st::semiboldFont);
+ p.setPen(st::white);
+ p.drawText(rthumb.left() + (rthumb.width() - _extw) / 2, rthumb.top() + st::msgFileExtTop + st::semiboldFont->ascent, _ext);
}
}
if (selected) {
- App::roundRect(p, rthumb, textstyleCurrent()->selectOverlay, SelectedOverlayCorners);
+ p.fillRect(rthumb, textstyleCurrent()->selectOverlay);
}
if (radial || (!loaded && !_data->loading())) {
@@ -858,15 +887,19 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
float64 radialOpacity = (radial && loaded && !_data->uploading()) ? _radial->opacity() : 1;
p.setPen(Qt::NoPen);
if (selected) {
- p.setBrush(st::msgDateImgBgSelected);
+ p.setBrush(wthumb ? st::msgDateImgBgSelected : documentSelectedColor(_colorIndex));
} else if (_a_iconOver.animating()) {
_a_iconOver.step(context->ms);
float64 over = a_iconOver.current();
- p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
- p.setBrush(st::black);
+ if (wthumb) {
+ p.setOpacity((st::msgDateImgBg->c.alphaF() * (1 - over)) + (st::msgDateImgBgOver->c.alphaF() * over));
+ p.setBrush(st::black);
+ } else {
+ p.setBrush(style::interpolate(documentDarkColor(_colorIndex), documentOverColor(_colorIndex), over));
+ }
} else {
bool over = textlnkDrawOver(_data->loading() ? _cancell : _savel);
- p.setBrush(over ? st::msgDateImgBgOver : st::msgDateImgBg);
+ p.setBrush(over ? (wthumb ? st::msgDateImgBgOver : documentOverColor(_colorIndex)) : (wthumb ? st::msgDateImgBg : documentDarkColor(_colorIndex)));
}
p.setOpacity(radialOpacity * p.opacity());
@@ -890,10 +923,10 @@ void LayoutOverviewDocument::paint(Painter &p, const QRect &clip, uint32 selecti
}
}
}
- if (selected) {
- p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoChecked.pxWidth()), rthumb.height() - st::linksPhotoChecked.pxHeight()), st::linksPhotoChecked);
- } else if (context->selecting) {
- p.drawSprite(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::linksPhotoCheck.pxWidth()), rthumb.height() - st::linksPhotoCheck.pxHeight()), st::linksPhotoCheck);
+ if (selected || context->selecting) {
+ QRect check(rthumb.topLeft() + QPoint(rtl() ? 0 : (rthumb.width() - st::defaultCheckbox.diameter), rthumb.height() - st::defaultCheckbox.diameter), QSize(st::defaultCheckbox.diameter, st::defaultCheckbox.diameter));
+ p.fillRect(check, selected ? st::overviewFileChecked : st::overviewFileCheck);
+ p.drawSpriteCenter(check, st::defaultCheckbox.checkIcon);
}
}
}
@@ -946,12 +979,12 @@ void LayoutOverviewDocument::getState(TextLinkPtr &link, HistoryCursorState &cur
return;
}
} else {
- nameleft = st::msgFileThumbSize + st::msgFileThumbPadding.right();
- nametop = st::linksBorder + st::msgFileThumbNameTop;
- statustop = st::linksBorder + st::msgFileThumbStatusTop;
- datetop = st::linksBorder + st::msgFileThumbLinkTop;
+ nameleft = st::overviewFileSize + st::overviewFilePadding.right();
+ nametop = st::linksBorder + st::overviewFileNameTop;
+ statustop = st::linksBorder + st::overviewFileStatusTop;
+ datetop = st::linksBorder + st::overviewFileDateTop;
- QRect rthumb(rtlrect(0, st::linksBorder + st::msgFileThumbPadding.top(), st::msgFileThumbSize, st::msgFileThumbSize, _width));
+ QRect rthumb(rtlrect(0, st::linksBorder + st::overviewFilePadding.top(), st::overviewFileSize, st::overviewFileSize, _width));
if (rthumb.contains(x, y)) {
link = loaded ? _openl : ((_data->loading() || _data->status == FileUploading) ? _cancell : _savel);
@@ -1150,7 +1183,7 @@ void LayoutOverviewLink::initDimensions() {
_minh += qMin(3 * st::normalFont->height, _text.countHeight(_maxw - st::dlgPhotoSize - st::dlgPhotoPadding));
}
_minh += _links.size() * st::normalFont->height;
- _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder;
+ _minh = qMax(_minh, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder;
}
int32 LayoutOverviewLink::resizeGetHeight(int32 width) {
@@ -1168,12 +1201,12 @@ int32 LayoutOverviewLink::resizeGetHeight(int32 width) {
_height += qMin(3 * st::normalFont->height, _text.countHeight(_width - st::dlgPhotoSize - st::dlgPhotoPadding));
}
_height += _links.size() * st::normalFont->height;
- _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin * 2 + st::linksBorder;
+ _height = qMax(_height, int32(st::dlgPhotoSize)) + st::linksMargin.top() + st::linksMargin.bottom() + st::linksBorder;
return _height;
}
void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const {
- int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left;
+ int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (clip.intersects(rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width))) {
if (_page && _page->photo) {
QPixmap pix;
@@ -1213,6 +1246,8 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
if (!_title.isEmpty() && _text.isEmpty() && _links.size() == 1) {
top += (st::dlgPhotoSize - st::semiboldFont->height - st::normalFont->height) / 2;
+ } else {
+ top = st::linksTextTop;
}
p.setPen(st::black);
@@ -1241,13 +1276,16 @@ void LayoutOverviewLink::paint(Painter &p, const QRect &clip, uint32 selection,
top += st::normalFont->height;
}
- if (clip.intersects(rtlrect(left, 0, w, st::linksBorder, _width))) {
- p.fillRect(clip.intersected(rtlrect(left, 0, w, st::linksBorder, _width)), st::linksBorderFg);
+ const OverviewPaintContext *pcontext = context->toOverviewPaintContext();
+ t_assert(pcontext != 0);
+ QRect border(rtlrect(left, 0, w, st::linksBorder, _width));
+ if (!pcontext->isAfterDate && clip.intersects(border)) {
+ p.fillRect(clip.intersected(border), st::linksBorderFg);
}
}
void LayoutOverviewLink::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
- int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin + st::linksBorder, w = _width - left;
+ int32 left = st::dlgPhotoSize + st::dlgPhotoPadding, top = st::linksMargin.top() + st::linksBorder, w = _width - left;
if (rtlrect(0, top, st::dlgPhotoSize, st::dlgPhotoSize, _width).contains(x, y)) {
link = _photol;
return;
@@ -1809,6 +1847,7 @@ void LayoutInlinePhoto::content_forget() {
LayoutInlineWebVideo::LayoutInlineWebVideo(InlineResult *result) : LayoutInlineItem(result, 0, 0)
, _send(new SendInlineItemLink())
+, _link(result->content_url.isEmpty() ? 0 : linkFromUrl(result->content_url))
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
if (_result->duration) {
@@ -1866,8 +1905,13 @@ void LayoutInlineWebVideo::paint(Painter &p, const QRect &clip, uint32 selection
}
void LayoutInlineWebVideo::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
- if (x >= 0 && x < _width && y >= 0 && y < _height) {
+ if (x >= 0 && x < st::inlineThumbSize && y >= st::inlineRowMargin && y < st::inlineRowMargin + st::inlineThumbSize) {
+ link = _link;
+ return;
+ }
+ if (x >= st::inlineThumbSize + st::inlineThumbSkip && x < _width && y >= 0 && y < _height) {
link = _send;
+ return;
}
}
@@ -1896,6 +1940,7 @@ void LayoutInlineWebVideo::prepareThumb(int32 width, int32 height) const {
LayoutInlineArticle::LayoutInlineArticle(InlineResult *result, bool withThumb) : LayoutInlineItem(result, 0, 0)
, _send(new SendInlineItemLink())
, _url(result->url.isEmpty() ? 0 : linkFromUrl(result->url))
+, _link(result->content_url.isEmpty() ? 0 : linkFromUrl(result->content_url))
, _withThumb(withThumb)
, _title(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip)
, _description(st::emojiPanWidth - st::emojiScroll.width - st::inlineResultsLeft - st::inlineThumbSize - st::inlineThumbSkip) {
@@ -1995,7 +2040,12 @@ void LayoutInlineArticle::paint(Painter &p, const QRect &clip, uint32 selection,
}
void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor, int32 x, int32 y) const {
- if (x >= 0 && x < _width && y >= 0 && y < _height) {
+ int32 left = _withThumb ? (st::inlineThumbSize + st::inlineThumbSkip) : 0;
+ if (x >= 0 && x < left - st::inlineThumbSkip && y >= st::inlineRowMargin && y < st::inlineRowMargin + st::inlineThumbSize) {
+ link = _link;
+ return;
+ }
+ if (x >= left && x < _width && y >= 0 && y < _height) {
if (_url) {
int32 left = st::inlineThumbSize + st::inlineThumbSkip;
int32 titleHeight = qMin(_title.countHeight(_width - left), st::semiboldFont->height * 2);
@@ -2007,6 +2057,7 @@ void LayoutInlineArticle::getState(TextLinkPtr &link, HistoryCursorState &cursor
}
}
link = _send;
+ return;
}
}
diff --git a/Telegram/SourceFiles/layout.h b/Telegram/SourceFiles/layout.h
index b069067382..0b346456c6 100644
--- a/Telegram/SourceFiles/layout.h
+++ b/Telegram/SourceFiles/layout.h
@@ -75,9 +75,13 @@ QString formatPlayedText(qint64 played, qint64 duration);
QString documentName(DocumentData *document);
int32 documentColorIndex(DocumentData *document, QString &ext);
style::color documentColor(int32 colorIndex);
+style::color documentDarkColor(int32 colorIndex);
+style::color documentOverColor(int32 colorIndex);
+style::color documentSelectedColor(int32 colorIndex);
style::sprite documentCorner(int32 colorIndex);
RoundCorners documentCorners(int32 colorIndex);
+class OverviewPaintContext;
class InlinePaintContext;
class PaintContext {
public:
@@ -86,6 +90,10 @@ public:
}
uint64 ms;
bool selecting;
+
+ virtual const OverviewPaintContext *toOverviewPaintContext() const {
+ return 0;
+ }
virtual const InlinePaintContext *toInlinePaintContext() const {
return 0;
}
@@ -257,6 +265,17 @@ protected:
};
+class OverviewPaintContext : public PaintContext {
+public:
+ OverviewPaintContext(uint64 ms, bool selecting) : PaintContext(ms, selecting), isAfterDate(false) {
+ }
+ const OverviewPaintContext *toOverviewPaintContext() const {
+ return this;
+ }
+ bool isAfterDate;
+
+};
+
class OverviewItemInfo {
public:
OverviewItemInfo() : _top(0) {
@@ -267,7 +286,7 @@ public:
void setTop(int32 top) {
_top = top;
}
-
+
private:
int32 _top;
@@ -276,7 +295,7 @@ private:
class LayoutOverviewDate : public LayoutItem {
public:
LayoutOverviewDate(const QDate &date, bool month);
-
+
virtual void initDimensions();
virtual void paint(Painter &p, const QRect &clip, uint32 selection, const PaintContext *context) const;
@@ -426,6 +445,9 @@ private:
DocumentData *_data;
TextLinkPtr _msgl, _namel;
+ mutable bool _thumbForLoaded;
+ mutable QPixmap _thumb;
+
QString _name, _date, _ext;
int32 _namew, _datew, _extw;
int32 _thumbw, _colorIndex;
@@ -492,7 +514,7 @@ class LayoutInlineItem : public LayoutItem {
public:
LayoutInlineItem(InlineResult *result, DocumentData *doc, PhotoData *photo);
-
+
virtual void setPosition(int32 position);
int32 position() const;
@@ -644,7 +666,7 @@ public:
private:
- TextLinkPtr _send;
+ TextLinkPtr _send, _link;
mutable QPixmap _thumb;
Text _title, _description;
@@ -667,7 +689,7 @@ public:
private:
- TextLinkPtr _send, _url;
+ TextLinkPtr _send, _url, _link;
bool _withThumb;
mutable QPixmap _thumb;
diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp
index d2889f7c6e..4f8f6dd03c 100644
--- a/Telegram/SourceFiles/overviewwidget.cpp
+++ b/Telegram/SourceFiles/overviewwidget.cpp
@@ -834,7 +834,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
p.setClipRect(r);
}
uint64 ms = getms();
- PaintContext context(ms, _selMode);
+ OverviewPaintContext context(ms, _selMode);
if (_history->overview[_type].isEmpty() && (!_migrated || !_history->overviewLoaded(_type) || _migrated->overview[_type].isEmpty())) {
QPoint dogPos((_width - st::msgDogImg.pxWidth()) / 2, ((height() - st::msgDogImg.pxHeight()) * 4) / 9);
@@ -887,6 +887,7 @@ void OverviewInner::paintEvent(QPaintEvent *e) {
if (_reversed) curY = _height - curY;
if (_marginTop + curY >= r.y() + r.height()) break;
+ context.isAfterDate = (j > 0) ? !_items.at(j - 1)->toLayoutMediaItem() : false;
p.translate(0, curY - y);
_items.at(i)->paint(p, r.translated(-_rowsLeft, -_marginTop - curY), itemSelectedValue(i), &context);
y = curY;
diff --git a/Telegram/Telegram.plist b/Telegram/Telegram.plist
index 5da30bd6da..544089e81f 100644
--- a/Telegram/Telegram.plist
+++ b/Telegram/Telegram.plist
@@ -11,7 +11,7 @@
CFBundlePackageType
APPL
CFBundleShortVersionString
- 0.9.15
+ 0.9.16
CFBundleSignature
????
CFBundleURLTypes
diff --git a/Telegram/Telegram.rc b/Telegram/Telegram.rc
index 944fa86c17..934f5c678e 100644
--- a/Telegram/Telegram.rc
+++ b/Telegram/Telegram.rc
@@ -34,8 +34,8 @@ IDI_ICON1 ICON "SourceFiles\\art\\icon256.ico"
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 0,9,15,7
- PRODUCTVERSION 0,9,15,7
+ FILEVERSION 0,9,16,0
+ PRODUCTVERSION 0,9,16,0
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -51,10 +51,10 @@ BEGIN
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Telegram Messenger LLP"
- VALUE "FileVersion", "0.9.15.7"
+ VALUE "FileVersion", "0.9.16.0"
VALUE "LegalCopyright", "Copyright (C) 2013"
VALUE "ProductName", "Telegram Desktop"
- VALUE "ProductVersion", "0.9.15.7"
+ VALUE "ProductVersion", "0.9.16.0"
END
END
BLOCK "VarFileInfo"
diff --git a/Telegram/Telegram.xcodeproj/project.pbxproj b/Telegram/Telegram.xcodeproj/project.pbxproj
index 6d3bd7db4d..c8738b710d 100644
--- a/Telegram/Telegram.xcodeproj/project.pbxproj
+++ b/Telegram/Telegram.xcodeproj/project.pbxproj
@@ -1701,7 +1701,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 0.9.15;
+ CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
@@ -1720,7 +1720,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
COPY_PHASE_STRIP = YES;
- CURRENT_PROJECT_VERSION = 0.9.15;
+ CURRENT_PROJECT_VERSION = 0.9.16;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_OPTIMIZATION_LEVEL = fast;
GCC_PREFIX_HEADER = ./SourceFiles/stdafx.h;
@@ -1747,10 +1747,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 0.9.15;
+ CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_COMPATIBILITY_VERSION = 0.9;
- DYLIB_CURRENT_VERSION = 0.9.15;
+ DYLIB_CURRENT_VERSION = 0.9.16;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = "";
GCC_GENERATE_DEBUGGING_SYMBOLS = YES;
@@ -1882,10 +1882,10 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "";
COPY_PHASE_STRIP = NO;
- CURRENT_PROJECT_VERSION = 0.9.15;
+ CURRENT_PROJECT_VERSION = 0.9.16;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 0.9;
- DYLIB_CURRENT_VERSION = 0.9.15;
+ DYLIB_CURRENT_VERSION = 0.9.16;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
FRAMEWORK_SEARCH_PATHS = "";
diff --git a/Telegram/Version b/Telegram/Version
index b944a37222..8f5c67a00c 100644
--- a/Telegram/Version
+++ b/Telegram/Version
@@ -1,6 +1,6 @@
-AppVersion 9015
+AppVersion 9016
AppVersionStrMajor 0.9
-AppVersionStrSmall 0.9.15
-AppVersionStr 0.9.15
+AppVersionStrSmall 0.9.16
+AppVersionStr 0.9.16
DevChannel 0
-BetaVersion 9015007
+BetaVersion 0 9015008