From 7adfe93a8d1fc5d436fb9562311fe3b9cf8d8036 Mon Sep 17 00:00:00 2001 From: John Preston Date: Thu, 16 Feb 2017 19:47:50 +0300 Subject: [PATCH] Alpha 1.0.10: unpinning converted chat on demand. If we want to pin a chat and we have reached the limit we now check for a deactivated (converted to supergroup) chat that is pinned and is not in the chats list and just silently unpin it if it is found. Also possible UB fix for a waveform encoding and decoding. --- Telegram/Resources/uwp/AppX/AppxManifest.xml | 2 +- Telegram/Resources/winrc/Telegram.rc | 8 +-- Telegram/Resources/winrc/Updater.rc | 8 +-- Telegram/SourceFiles/application.cpp | 4 +- Telegram/SourceFiles/core/version.h | 4 +- .../SourceFiles/dialogs/dialogs_layout.cpp | 14 +++++- Telegram/SourceFiles/dialogswidget.cpp | 7 +-- Telegram/SourceFiles/history.cpp | 11 ++++ Telegram/SourceFiles/history.h | 1 + Telegram/SourceFiles/mainwidget.cpp | 20 +++++++- Telegram/SourceFiles/structs.cpp | 50 ++++++++++++++++--- Telegram/build/version | 6 +-- 12 files changed, 103 insertions(+), 32 deletions(-) diff --git a/Telegram/Resources/uwp/AppX/AppxManifest.xml b/Telegram/Resources/uwp/AppX/AppxManifest.xml index 040bb1cfa1..9a1695274e 100644 --- a/Telegram/Resources/uwp/AppX/AppxManifest.xml +++ b/Telegram/Resources/uwp/AppX/AppxManifest.xml @@ -9,7 +9,7 @@ + Version="1.0.10.0" /> Telegram Desktop Telegram Messenger LLP diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index a40279cd05..c714c554ae 100644 --- a/Telegram/Resources/winrc/Telegram.rc +++ b/Telegram/Resources/winrc/Telegram.rc @@ -34,8 +34,8 @@ IDI_ICON1 ICON "..\\art\\icon256.ico" // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,9,0 - PRODUCTVERSION 1,0,9,0 + FILEVERSION 1,0,10,0 + PRODUCTVERSION 1,0,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -52,10 +52,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Desktop official messenger" - VALUE "FileVersion", "1.0.9.0" + VALUE "FileVersion", "1.0.10.0" VALUE "LegalCopyright", "Copyright (C) 2014-2017" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.0.9.0" + VALUE "ProductVersion", "1.0.10.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 590ad6c18e..bd944d0257 100644 --- a/Telegram/Resources/winrc/Updater.rc +++ b/Telegram/Resources/winrc/Updater.rc @@ -25,8 +25,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,0,9,0 - PRODUCTVERSION 1,0,9,0 + FILEVERSION 1,0,10,0 + PRODUCTVERSION 1,0,10,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Desktop Updater" - VALUE "FileVersion", "1.0.9.0" + VALUE "FileVersion", "1.0.10.0" VALUE "LegalCopyright", "Copyright (C) 2014-2017" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "1.0.9.0" + VALUE "ProductVersion", "1.0.10.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 6bc4b8ded5..e277ecd41a 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -1069,8 +1069,8 @@ void AppClass::checkMapVersion() { if (Local::oldMapVersion() < AppVersion) { if (Local::oldMapVersion()) { QString versionFeatures; - if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000008) { - versionFeatures = QString::fromUtf8("\xe2\x80\x94 Click and drag on waveform to play audio from a chosen moment."); + if ((cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000010) { + versionFeatures = QString::fromUtf8("\xe2\x80\x94 More different emoticons supported.\n\xe2\x80\x94 Bug fixes and other minor improvements."); } else if (!(cAlphaVersion() || cBetaVersion()) && Local::oldMapVersion() < 1000005) { versionFeatures = langNewVersionText(); } else { diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index 0fe4fcd57c..3e6d529ed3 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #define BETA_VERSION_MACRO (0ULL) -constexpr int AppVersion = 1000009; -constexpr str_const AppVersionStr = "1.0.9"; +constexpr int AppVersion = 1000010; +constexpr str_const AppVersionStr = "1.0.10"; constexpr bool AppAlphaVersion = true; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; diff --git a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp index b4710d6a95..fff4097b30 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_layout.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_layout.cpp @@ -109,15 +109,27 @@ void paintRow(Painter &p, const RippleRow *row, History *history, HistoryItem *i p.restoreTextPalette(); } } else if (!item) { + auto availableWidth = namewidth; + if (history->isPinnedDialog()) { + auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon)); + icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth); + availableWidth -= icon.width() + st::dialogsUnreadPadding; + } + auto &color = active ? st::dialogsTextFgServiceActive : (selected ? st::dialogsTextFgServiceOver : st::dialogsTextFgService); p.setFont(st::dialogsTextFont); - if (!history->paintSendAction(p, nameleft, texttop, namewidth, fullWidth, color, ms)) { + if (!history->paintSendAction(p, nameleft, texttop, availableWidth, fullWidth, color, ms)) { // Empty history } } else if (!item->isEmpty()) { paintRowDate(p, date, rectForName, active, selected); paintItemCallback(nameleft, namewidth, item); + } else if (history->isPinnedDialog()) { + auto availableWidth = namewidth; + auto &icon = (active ? st::dialogsPinnedIconActive : (selected ? st::dialogsPinnedIconOver : st::dialogsPinnedIcon)); + icon.paint(p, fullWidth - st::dialogsPadding.x() - icon.width(), texttop, fullWidth); + availableWidth -= icon.width() + st::dialogsUnreadPadding; } auto sendStateIcon = ([draft, item, active, selected]() -> const style::icon* { if (draft) { diff --git a/Telegram/SourceFiles/dialogswidget.cpp b/Telegram/SourceFiles/dialogswidget.cpp index 6e7f1451c6..24a1e93811 100644 --- a/Telegram/SourceFiles/dialogswidget.cpp +++ b/Telegram/SourceFiles/dialogswidget.cpp @@ -643,17 +643,12 @@ void DialogsInner::savePinnedOrder() { if (newOrder.size() != _pinnedOrder.size()) { return; // Something has changed in the set of pinned chats. } - - auto peers = QVector(); - peers.reserve(newOrder.size()); for_const (auto history, newOrder) { if (_pinnedOrder.indexOf(history) < 0) { return; // Something has changed in the set of pinned chats. } - peers.push_back(history->peer->input); } - auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force; - MTP::send(MTPmessages_ReorderPinnedDialogs(MTP_flags(qFlags(flags)), MTP_vector(peers))); + App::histories().savePinnedToServer(); } void DialogsInner::finishReorderPinned() { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 63cc3a55c7..0c20417ba4 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -719,6 +719,17 @@ QList Histories::getPinnedOrder() const { return result; } +void Histories::savePinnedToServer() const { + auto order = getPinnedOrder(); + auto peers = QVector(); + peers.reserve(order.size()); + for_const (auto history, order) { + peers.push_back(history->peer->input); + } + auto flags = MTPmessages_ReorderPinnedDialogs::Flag::f_force; + MTP::send(MTPmessages_ReorderPinnedDialogs(MTP_flags(qFlags(flags)), MTP_vector(peers))); +} + HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, bool detachExistingItem) { auto msgId = MsgId(0); switch (msg.type()) { diff --git a/Telegram/SourceFiles/history.h b/Telegram/SourceFiles/history.h index 50c500c27c..1f424a1ef7 100644 --- a/Telegram/SourceFiles/history.h +++ b/Telegram/SourceFiles/history.h @@ -83,6 +83,7 @@ public: void clearPinned(); int pinnedCount() const; QList getPinnedOrder() const; + void savePinnedToServer() const; struct SendActionAnimationUpdate { History *history; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index b93bc1495b..f5192e0b9c 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1976,7 +1976,25 @@ void MainWidget::fillPeerMenu(PeerData *peer, base::lambdaisPinnedDialog(); if (isPinned && App::histories().pinnedCount() >= Global::PinnedDialogsCountMax()) { - Ui::show(Box(lng_error_pinned_max(lt_count, Global::PinnedDialogsCountMax()))); + // Some old chat, that was converted to supergroup, maybe is still pinned. + auto findWastedPin = []() -> History* { + auto order = App::histories().getPinnedOrder(); + for_const (auto pinned, order) { + if (pinned->peer->isChat() + && pinned->peer->asChat()->isDeactivated() + && !pinned->inChatList(Dialogs::Mode::All)) { + return pinned; + } + } + return nullptr; + }; + if (auto wasted = findWastedPin()) { + wasted->setPinnedDialog(false); + history->setPinnedDialog(isPinned); + App::histories().savePinnedToServer(); + } else { + Ui::show(Box(lng_error_pinned_max(lt_count, Global::PinnedDialogsCountMax()))); + } return; } diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index ed70ce7ca9..0bb0c04e63 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -1659,20 +1659,54 @@ void DocumentData::notifyLayoutChanged() const { } VoiceWaveform documentWaveformDecode(const QByteArray &encoded5bit) { - VoiceWaveform result((encoded5bit.size() * 8) / 5, 0); - for (int32 i = 0, l = result.size(); i < l; ++i) { // read each 5 bit of encoded5bit as 0-31 unsigned char - int32 byte = (i * 5) / 8, shift = (i * 5) % 8; - result[i] = (((*(uint16*)(encoded5bit.constData() + byte)) >> shift) & 0x1F); + auto bitsCount = static_cast(encoded5bit.size() * 8); + auto valuesCount = bitsCount / 5; + if (!valuesCount) { + return VoiceWaveform(); } + + // Read each 5 bit of encoded5bit as 0-31 unsigned char. + // We count the index of the byte in which the desired 5-bit sequence starts. + // And then we read a uint16 starting from that byte to guarantee to get all of those 5 bits. + // + // BUT! if it is the last byte we have, we're not allowed to read a uint16 starting with it. + // Because it will be an overflow (we'll access one byte after the available memory). + // We see, that only the last 5 bits could start in the last available byte and be problematic. + // So we read in a general way all the entries in a general way except the last one. + auto result = VoiceWaveform(valuesCount, 0); + auto bitsData = encoded5bit.constData(); + for (auto i = 0, l = valuesCount - 1; i != l; ++i) { + auto byteIndex = (i * 5) / 8; + auto bitShift = (i * 5) % 8; + auto value = *reinterpret_cast(bitsData + byteIndex); + result[i] = static_cast((value >> bitShift) & 0x1F); + } + auto lastByteIndex = ((valuesCount - 1) * 5) / 8; + auto lastBitShift = ((valuesCount - 1) * 5) % 8; + auto lastValue = (lastByteIndex == encoded5bit.size() - 1) + ? static_cast(*reinterpret_cast(bitsData + lastByteIndex)) + : *reinterpret_cast(bitsData + lastByteIndex); + result[valuesCount - 1] = static_cast((lastValue >> lastBitShift) & 0x1F); + return result; } QByteArray documentWaveformEncode5bit(const VoiceWaveform &waveform) { - QByteArray result((waveform.size() * 5 + 7) / 8, 0); - for (int32 i = 0, l = waveform.size(); i < l; ++i) { // write each 0-31 unsigned char as 5 bit to result - int32 byte = (i * 5) / 8, shift = (i * 5) % 8; - (*(uint16*)(result.data() + byte)) |= (uint16(waveform.at(i) & 0x1F) << shift); + auto bitsCount = waveform.size() * 5; + auto bytesCount = (bitsCount + 7) / 8; + auto result = QByteArray(bytesCount + 1, 0); + auto bitsData = result.data(); + + // Write each 0-31 unsigned char as 5 bit to result. + // We reserve one extra byte to be able to dereference any of required bytes + // as a uint16 without overflowing, even the byte with index "bytesCount - 1". + for (auto i = 0, l = waveform.size(); i < l; ++i) { + auto byteIndex = (i * 5) / 8; + auto bitShift = (i * 5) % 8; + auto value = (static_cast(waveform[i]) & 0x1F) << bitShift; + *reinterpret_cast(bitsData + byteIndex) |= value; } + result.resize(bytesCount); return result; } diff --git a/Telegram/build/version b/Telegram/build/version index 405397a642..3707807fa6 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,6 +1,6 @@ -AppVersion 1000009 +AppVersion 1000010 AppVersionStrMajor 1.0 -AppVersionStrSmall 1.0.9 -AppVersionStr 1.0.9 +AppVersionStrSmall 1.0.10 +AppVersionStr 1.0.10 AlphaChannel 1 BetaVersion 0