From c65a280b9d687c5b6056dfa1e228ba91d293233b Mon Sep 17 00:00:00 2001 From: John Preston Date: Sun, 1 Jan 2017 20:45:20 +0400 Subject: [PATCH] Alpha 0.10.23: small tiled background performance improved. Also some error texts improved. Also Ctrl+W closes MediaView now. --- Telegram/Resources/langs/lang.strings | 6 +- Telegram/Resources/winrc/Telegram.rc | 8 +- Telegram/Resources/winrc/Updater.rc | 8 +- Telegram/SourceFiles/boxes/contactsbox.cpp | 14 ++- Telegram/SourceFiles/boxes/contactsbox.h | 7 +- Telegram/SourceFiles/core/version.h | 4 +- Telegram/SourceFiles/facades.cpp | 2 +- Telegram/SourceFiles/history.cpp | 20 ++-- Telegram/SourceFiles/historywidget.cpp | 22 ++-- Telegram/SourceFiles/localstorage.cpp | 2 +- Telegram/SourceFiles/mainwidget.cpp | 67 +++++++---- Telegram/SourceFiles/mainwidget.h | 12 +- Telegram/SourceFiles/mainwindow.cpp | 110 ++++-------------- Telegram/SourceFiles/mainwindow.h | 28 +---- Telegram/SourceFiles/mediaview.cpp | 30 +++-- Telegram/SourceFiles/mediaview.h | 6 +- Telegram/SourceFiles/observer_peer.h | 7 ++ Telegram/SourceFiles/overviewwidget.cpp | 5 +- Telegram/SourceFiles/overviewwidget.h | 6 +- .../platform/linux/main_window_linux.cpp | 2 +- .../platform/linux/main_window_linux.h | 2 +- .../platform/mac/main_window_mac.h | 4 +- .../platform/mac/main_window_mac.mm | 15 +-- .../platform/win/main_window_win.cpp | 10 +- .../platform/win/main_window_win.h | 4 +- .../profile/profile_block_shared_media.cpp | 4 +- .../settings/settings_background_widget.cpp | 2 +- .../settings/settings_general_widget.cpp | 19 ++- Telegram/SourceFiles/ui/widgets/tooltip.cpp | 8 +- Telegram/SourceFiles/window/main_window.cpp | 86 ++++++++++++-- Telegram/SourceFiles/window/main_window.h | 45 +++++++ Telegram/SourceFiles/window/window_theme.cpp | 47 ++++++-- Telegram/SourceFiles/window/window_theme.h | 10 +- .../window/window_theme_preview.cpp | 28 +++-- Telegram/build/version | 6 +- 35 files changed, 419 insertions(+), 237 deletions(-) diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index fda096e052..f6e24d9c2f 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -126,6 +126,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_edit_error" = "You cannot edit this message"; "lng_join_channel_error" = "Sorry, you have joined too many channels and supergroups. Please leave some before joining."; "lng_error_phone_flood" = "Sorry, you have deleted and re-created your account too many times recently. Please wait for a few days before signing up again."; +"lng_error_start_minimized_passcoded" = "You have set a local passcode, so the app can't be launched minimized. App will ask you to enter the passcode before it can start working."; "lng_edit_deleted" = "This message was deleted"; "lng_edit_too_long" = "Your message text is too long"; @@ -753,9 +754,8 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org "lng_report_spam_sure_group" = "Are you sure you want to report spam in this group?"; "lng_report_spam_sure_channel" = "Are you sure you want to report spam in this channel?"; "lng_report_spam_ok" = "Report"; -"lng_cant_send_to_not_contact" = "Sorry, you can only send messages to\nmutual contacts at the moment.\n{more_info}"; -"lng_cant_invite_not_contact" = "Sorry, you can only add mutual contacts\nto groups at the moment.\n{more_info}"; -"lng_cant_invite_not_contact_channel" = "Sorry, you can only add mutual contacts\nto channels at the moment.\n{more_info}"; +"lng_cant_send_to_not_contact" = "You have contacted too many non-contacts today, please try again tomorrow. You will be able to reply today if this user messages you first. {more_info}"; +"lng_cant_invite_not_contact" = "You can't add this user because you have contacted too many non-contacts today. Please try again tomorrow. You can ask another member to add this user to the group. {more_info}"; "lng_cant_more_info" = "More info ยป"; "lng_cant_invite_banned" = "Sorry, only admin can add this user."; "lng_cant_invite_privacy" = "Sorry, you cannot add this user to groups because of their privacy settings."; diff --git a/Telegram/Resources/winrc/Telegram.rc b/Telegram/Resources/winrc/Telegram.rc index 71326f092f..dceb619320 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 0,10,22,0 - PRODUCTVERSION 0,10,22,0 + FILEVERSION 0,10,23,0 + PRODUCTVERSION 0,10,23,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -51,10 +51,10 @@ BEGIN BLOCK "040904b0" BEGIN VALUE "CompanyName", "Telegram Messenger LLP" - VALUE "FileVersion", "0.10.22.0" + VALUE "FileVersion", "0.10.23.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.22.0" + VALUE "ProductVersion", "0.10.23.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/Resources/winrc/Updater.rc b/Telegram/Resources/winrc/Updater.rc index 8a22fa97ea..5fdc6fdb1d 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 0,10,22,0 - PRODUCTVERSION 0,10,22,0 + FILEVERSION 0,10,23,0 + PRODUCTVERSION 0,10,23,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -43,10 +43,10 @@ BEGIN BEGIN VALUE "CompanyName", "Telegram Messenger LLP" VALUE "FileDescription", "Telegram Updater" - VALUE "FileVersion", "0.10.22.0" + VALUE "FileVersion", "0.10.23.0" VALUE "LegalCopyright", "Copyright (C) 2014-2016" VALUE "ProductName", "Telegram Desktop" - VALUE "ProductVersion", "0.10.22.0" + VALUE "ProductVersion", "0.10.23.0" END END BLOCK "VarFileInfo" diff --git a/Telegram/SourceFiles/boxes/contactsbox.cpp b/Telegram/SourceFiles/boxes/contactsbox.cpp index a4a3dee209..ca144d3b3d 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.cpp +++ b/Telegram/SourceFiles/boxes/contactsbox.cpp @@ -44,8 +44,12 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "observer_peer.h" #include "apiwrap.h" -QString cantInviteError() { - return lng_cant_invite_not_contact(lt_more_info, textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info))); +QString PeerFloodErrorText(PeerFloodType type) { + auto link = textcmdLink(qsl("https://telegram.me/spambot"), lang(lng_cant_more_info)); + if (type == PeerFloodType::InviteGroup) { + return lng_cant_invite_not_contact(lt_more_info, link); + } + return lng_cant_send_to_not_contact(lt_more_info, link); } ContactsBox::ContactsBox(QWidget*, ChatData *chat, MembersFilter filter) @@ -360,6 +364,8 @@ void ContactsBox::inviteParticipants() { void ContactsBox::createGroup() { if (_saveRequestId) return; + Ui::show(Box(PeerFloodErrorText(PeerFloodType::Send)), KeepOtherLayers); + return; auto users = _inner->selectedInputs(); if (users.isEmpty() || (users.size() == 1 && users.at(0).type() == mtpc_inputUserSelf)) { @@ -512,7 +518,7 @@ bool ContactsBox::creationFail(const RPCError &error) { _select->entity()->setInnerFocus(); return true; } else if (error.type() == "PEER_FLOOD") { - Ui::show(Box(cantInviteError()), KeepOtherLayers); + Ui::show(Box(PeerFloodErrorText(PeerFloodType::InviteGroup)), KeepOtherLayers); return true; } else if (error.type() == qstr("USER_RESTRICTED")) { Ui::show(Box(lang(lng_cant_do_this))); @@ -718,7 +724,7 @@ void ContactsBox::Inner::addBot() { history->sendRequestId = requestId; } } else if (!info->startGroupToken.isEmpty()) { - MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value()), MTP_string(info->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _bot)); + MTP::send(MTPmessages_StartBot(_bot->inputUser, _addToPeer->input, MTP_long(rand_value()), MTP_string(info->startGroupToken)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, { _bot, _addToPeer })); } else { App::main()->addParticipants(_addToPeer, QVector(1, _bot)); } diff --git a/Telegram/SourceFiles/boxes/contactsbox.h b/Telegram/SourceFiles/boxes/contactsbox.h index 6078ec410e..830fe3c5c4 100644 --- a/Telegram/SourceFiles/boxes/contactsbox.h +++ b/Telegram/SourceFiles/boxes/contactsbox.h @@ -39,7 +39,12 @@ template class WidgetSlideWrap; } // namespace Ui -QString cantInviteError(); +enum class PeerFloodType { + Send, + InviteGroup, + InviteChannel, +}; +QString PeerFloodErrorText(PeerFloodType type); inline Ui::RoundImageCheckbox::PaintRoundImage PaintUserpicCallback(PeerData *peer) { return [peer](Painter &p, int x, int y, int outerWidth, int size) { diff --git a/Telegram/SourceFiles/core/version.h b/Telegram/SourceFiles/core/version.h index d0baa5682b..6486a425aa 100644 --- a/Telegram/SourceFiles/core/version.h +++ b/Telegram/SourceFiles/core/version.h @@ -24,7 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #define BETA_VERSION_MACRO (0ULL) -constexpr int AppVersion = 10022; -constexpr str_const AppVersionStr = "0.10.22"; +constexpr int AppVersion = 10023; +constexpr str_const AppVersionStr = "0.10.23"; constexpr bool AppAlphaVersion = true; constexpr uint64 AppBetaVersion = BETA_VERSION_MACRO; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index 5e25ab95f1..c6f98166ca 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -316,7 +316,7 @@ PeerData *getPeerForMouseAction() { bool hideWindowNoQuit() { if (!App::quitting()) { if (auto w = App::wnd()) { - w->hideNoQuit(); + return w->hideNoQuit(); } } return false; diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index e1bc12fbf8..3f05e0a3e1 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1089,7 +1089,7 @@ bool History::addToOverview(MediaOverviewType type, MsgId msgId, AddToOverviewMe if (overviewCountData[type] > 0) { ++overviewCountData[type]; } - if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, type); + Notify::mediaOverviewUpdated(peer, type); } return true; } @@ -1110,7 +1110,7 @@ void History::eraseFromOverview(MediaOverviewType type, MsgId msgId) { break; } } - if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, type); + Notify::mediaOverviewUpdated(peer, type); } HistoryItem *History::addNewItem(HistoryItem *adding, bool newMsg) { @@ -1375,8 +1375,11 @@ void History::addOlderSlice(const QVector &slice) { } } } - for (int32 t = 0; t < OverviewCount; ++t) { - if ((mask & (1 << t)) && App::wnd()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(t)); + if (mask) { + Notify::PeerUpdate update(peer); + update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged; + update.mediaTypesMask |= mask; + Notify::peerUpdatedDelayed(update); } } @@ -1453,8 +1456,11 @@ void History::checkAddAllToOverview() { mask |= item->addToOverview(AddToOverviewBack); } } - for (int32 t = 0; t < OverviewCount; ++t) { - if ((mask & (1 << t)) && App::wnd()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(t)); + if (mask) { + Notify::PeerUpdate update(peer); + update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged; + update.mediaTypesMask |= mask; + Notify::peerUpdatedDelayed(update); } } @@ -2009,7 +2015,7 @@ void History::clear(bool leaveItems) { } overview[i].clear(); overviewIds[i].clear(); - if (App::wnd() && !App::quitting()) App::wnd()->mediaOverviewUpdated(peer, MediaOverviewType(i)); + if (!App::quitting()) Notify::mediaOverviewUpdated(peer, MediaOverviewType(i)); } } clearBlocks(leaveItems); diff --git a/Telegram/SourceFiles/historywidget.cpp b/Telegram/SourceFiles/historywidget.cpp index 1e14a55cca..b4320a1c80 100644 --- a/Telegram/SourceFiles/historywidget.cpp +++ b/Telegram/SourceFiles/historywidget.cpp @@ -5294,7 +5294,7 @@ void HistoryWidget::onBotStart() { sendBotCommand(_peer, _peer->asUser(), qsl("/start"), 0); } else { uint64 randomId = rand_value(); - MTP::send(MTPmessages_StartBot(_peer->asUser()->inputUser, MTP_inputPeerEmpty(), MTP_long(randomId), MTP_string(token)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, _peer->asUser())); + MTP::send(MTPmessages_StartBot(_peer->asUser()->inputUser, MTP_inputPeerEmpty(), MTP_long(randomId), MTP_string(token)), App::main()->rpcDone(&MainWidget::sentUpdatesReceived), App::main()->rpcFail(&MainWidget::addParticipantFail, { _peer->asUser(), (PeerData*)nullptr })); _peer->asUser()->botInfo->startToken = QString(); if (_keyboard->hasMarkup()) { @@ -8791,19 +8791,27 @@ void HistoryWidget::paintEvent(QPaintEvent *e) { int fromy = App::main()->backgroundFromY(), x = 0, y = 0; QPixmap cached = App::main()->cachedBackground(fill, x, y); if (cached.isNull()) { - auto &pix = Window::Theme::Background()->image(); if (Window::Theme::Background()->tile()) { - int left = r.left(), top = r.top(), right = r.left() + r.width(), bottom = r.top() + r.height(); - float64 w = pix.width() / cRetinaFactor(), h = pix.height() / cRetinaFactor(); - int sx = qFloor(left / w), sy = qFloor((top - fromy) / h), cx = qCeil(right / w), cy = qCeil((bottom - fromy) / h); - for (int i = sx; i < cx; ++i) { - for (int j = sy; j < cy; ++j) { + auto &pix = Window::Theme::Background()->pixmapForTiled(); + auto left = r.left(); + auto top = r.top(); + auto right = r.left() + r.width(); + auto bottom = r.top() + r.height(); + auto w = pix.width() / cRetinaFactor(); + auto h = pix.height() / cRetinaFactor(); + auto sx = qFloor(left / w); + auto sy = qFloor((top - fromy) / h); + auto cx = qCeil(right / w); + auto cy = qCeil((bottom - fromy) / h); + for (auto i = sx; i < cx; ++i) { + for (auto j = sy; j < cy; ++j) { p.drawPixmap(QPointF(i * w, fromy + j * h), pix); } } } else { PainterHighQualityEnabler hq(p); + auto &pix = Window::Theme::Background()->pixmap(); QRect to, from; Window::Theme::ComputeBackgroundRects(fill, pix.size(), to, from); to.moveTop(to.top() + fromy); diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 8d6f6b5dcd..53710b6a69 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -1720,7 +1720,7 @@ void _writeMtpData() { key->write(data.stream); } - mtp.writeEncrypted(data, _localKey); + mtp.writeEncrypted(data); } void _readMtpData() { diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index d7d3c3a8e4..0c4c0928b0 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -148,6 +148,11 @@ MainWidget::MainWidget(QWidget *parent) : TWidget(parent) subscribe(Adaptive::Changed(), [this]() { updateAdaptiveLayout(); }); + auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + mediaOverviewUpdated(update); + })); + _dialogs->show(); if (Adaptive::OneColumn()) { _history->hide(); @@ -919,8 +924,9 @@ void MainWidget::clearHistory(PeerData *peer) { void MainWidget::addParticipants(PeerData *chatOrChannel, const QVector &users) { if (chatOrChannel->isChat()) { - for (QVector::const_iterator i = users.cbegin(), e = users.cend(); i != e; ++i) { - MTP::send(MTPmessages_AddChatUser(chatOrChannel->asChat()->inputChat, (*i)->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantFail, *i), 0, 5); + auto chat = chatOrChannel->asChat(); + for_const (auto user, users) { + MTP::send(MTPmessages_AddChatUser(chat->inputChat, user->inputUser, MTP_int(ForwardOnAdd)), rpcDone(&MainWidget::sentUpdatesReceived), rpcFail(&MainWidget::addParticipantFail, { user, chat }), 0, 5); } } else if (chatOrChannel->isChannel()) { QVector inputUsers; @@ -938,7 +944,7 @@ void MainWidget::addParticipants(PeerData *chatOrChannel, const QVectorbotInfo) { + } else if (error.type() == qstr("USER_ALREADY_PARTICIPANT") && data.user->botInfo) { text = lang(lng_bot_already_in_group); } else if (error.type() == qstr("PEER_FLOOD")) { - text = cantInviteError(); + text = PeerFloodErrorText((data.peer->isChat() || data.peer->isMegagroup()) ? PeerFloodType::InviteGroup : PeerFloodType::InviteChannel); } Ui::show(Box(text)); return false; @@ -970,7 +976,7 @@ bool MainWidget::addParticipantsFail(ChannelData *channel, const RPCError &error } else if (error.type() == qstr("USER_NOT_MUTUAL_CONTACT")) { // trying to return user who does not have me in contacts text = lang(channel->isMegagroup() ? lng_failed_add_not_mutual : lng_failed_add_not_mutual_channel); } else if (error.type() == qstr("PEER_FLOOD")) { - text = cantInviteError(); + text = PeerFloodErrorText(PeerFloodType::InviteGroup); } Ui::show(Box(text)); return false; @@ -1060,22 +1066,30 @@ bool MainWidget::sendMessageFail(const RPCError &error) { if (MTP::isDefaultHandledError(error)) return false; if (error.type() == qstr("PEER_FLOOD")) { - Ui::show(Box(cantInviteError())); + Ui::show(Box(PeerFloodErrorText(PeerFloodType::Send))); return true; } return false; } void MainWidget::onCacheBackground() { - auto &bg = Window::Theme::Background()->image(); if (Window::Theme::Background()->tile()) { - QImage result(_willCacheFor.width() * cIntRetinaFactor(), _willCacheFor.height() * cIntRetinaFactor(), QImage::Format_RGB32); + auto &bg = Window::Theme::Background()->pixmapForTiled(); + + auto result = QImage(_willCacheFor.width() * cIntRetinaFactor(), _willCacheFor.height() * cIntRetinaFactor(), QImage::Format_RGB32); result.setDevicePixelRatio(cRetinaFactor()); { QPainter p(&result); - int left = 0, top = 0, right = _willCacheFor.width(), bottom = _willCacheFor.height(); - float64 w = bg.width() / cRetinaFactor(), h = bg.height() / cRetinaFactor(); - int sx = 0, sy = 0, cx = qCeil(_willCacheFor.width() / w), cy = qCeil(_willCacheFor.height() / h); + auto left = 0; + auto top = 0; + auto right = _willCacheFor.width(); + auto bottom = _willCacheFor.height(); + auto w = bg.width() / cRetinaFactor(); + auto h = bg.height() / cRetinaFactor(); + auto sx = 0; + auto sy = 0; + auto cx = qCeil(_willCacheFor.width() / w); + auto cy = qCeil(_willCacheFor.height() / h); for (int i = sx; i < cx; ++i) { for (int j = sy; j < cy; ++j) { p.drawPixmap(QPointF(i * w, j * h), bg); @@ -1086,6 +1100,8 @@ void MainWidget::onCacheBackground() { _cachedY = 0; _cachedBackground = App::pixmapFromImageInPlace(std_::move(result)); } else { + auto &bg = Window::Theme::Background()->pixmap(); + QRect to, from; Window::Theme::ComputeBackgroundRects(_willCacheFor, bg.size(), to, from); _cachedX = to.x(); @@ -1370,12 +1386,13 @@ void MainWidget::overviewPreloaded(PeerData *peer, const MTPmessages_Messages &r App::history(peer->id)->overviewSliceDone(type, result, true); - if (App::wnd()) App::wnd()->mediaOverviewUpdated(peer, type); + Notify::mediaOverviewUpdated(peer, type); } -void MainWidget::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { +void MainWidget::mediaOverviewUpdated(const Notify::PeerUpdate &update) { + auto peer = update.peer; if (_overview && (_overview->peer() == peer || _overview->peer()->migrateFrom() == peer)) { - _overview->mediaOverviewUpdated(peer, type); + _overview->mediaOverviewUpdated(update); int32 mask = 0; History *h = peer ? App::historyLoaded((peer->migrateTo() ? peer->migrateTo() : peer)->id) : 0; @@ -1472,7 +1489,7 @@ void MainWidget::overviewLoaded(History *history, const MTPmessages_Messages &re history->overviewSliceDone(type, result); - if (App::wnd()) App::wnd()->mediaOverviewUpdated(history->peer, type); + Notify::mediaOverviewUpdated(history->peer, type); } void MainWidget::sendReadRequest(PeerData *peer, MsgId upTo) { @@ -2385,7 +2402,13 @@ void MainWidget::showMediaOverview(PeerData *peer, MediaOverviewType type, bool _mediaTypeMask = 0; _topBar->show(); resizeEvent(nullptr); - mediaOverviewUpdated(peer, type); + + // Send a fake update. + Notify::PeerUpdate update(peer); + update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged; + update.mediaTypesMask |= (1 << type); + mediaOverviewUpdated(update); + _overview->setLastScrollTop(lastScrollTop); if (!animationParams.oldContentCache.isNull()) { _overview->showAnimated(back ? Window::SlideDirection::FromLeft : Window::SlideDirection::FromRight, animationParams); @@ -4453,11 +4476,11 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { if (msg.msg) { if (auto msgRow = App::histItemById(msg)) { if (App::histItemById(msg.channel, d.vid.v)) { - History *h = msgRow->history(); - bool wasLast = (h->lastMsg == msgRow); + auto history = msgRow->history(); + auto wasLast = (history->lastMsg == msgRow); msgRow->destroy(); - if (wasLast && !h->lastMsg) { - checkPeerHistory(h->peer); + if (wasLast && !history->lastMsg) { + checkPeerHistory(history->peer); } _history->peerMessagesUpdated(); } else { @@ -4666,7 +4689,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } App::markPeerUpdated(user); - if (App::wnd()) App::wnd()->mediaOverviewUpdated(user, OverviewCount); + Notify::mediaOverviewUpdated(user, OverviewCount); } } break; diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index f857ee058f..11ae7fe224 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -24,6 +24,10 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "history/history_common.h" #include "core/single_timer.h" +namespace Notify { +struct PeerUpdate; +} // namespace Notify + namespace Dialogs { class Row; } // namespace Dialogs @@ -260,7 +264,11 @@ public: void deleteAllFromUser(ChannelData *channel, UserData *from); void addParticipants(PeerData *chatOrChannel, const QVector &users); - bool addParticipantFail(UserData *user, const RPCError &e); + struct UserAndPeer { + UserData *user; + PeerData *peer; + }; + bool addParticipantFail(UserAndPeer data, const RPCError &e); bool addParticipantsFail(ChannelData *channel, const RPCError &e); // for multi invite in channels void kickParticipant(ChatData *chat, UserData *user); @@ -302,7 +310,6 @@ public: void searchMessages(const QString &query, PeerData *inPeer); bool preloadOverview(PeerData *peer, MediaOverviewType type); void preloadOverviews(PeerData *peer); - void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); void changingMsgId(HistoryItem *row, MsgId newId); void itemEdited(HistoryItem *item); @@ -496,6 +503,7 @@ private: void messagesAffected(PeerData *peer, const MTPmessages_AffectedMessages &result); void overviewLoaded(History *history, const MTPmessages_Messages &result, mtpRequestId req); + void mediaOverviewUpdated(const Notify::PeerUpdate &update); Window::SectionSlideParams prepareShowAnimation(bool willHaveTopBarShadow); void showWideSectionAnimated(const Window::SectionMemento *memento, bool back, bool saveInStack); diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 750ba32fa4..940e34c27c 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -118,9 +118,6 @@ MainWindow::MainWindow() { connect(&_notifyWaitTimer, SIGNAL(timeout()), this, SLOT(notifyShowNext())); - _isActiveTimer.setSingleShot(true); - connect(&_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActive())); - connect(&_autoLockTimer, SIGNAL(timeout()), this, SLOT(checkAutoLock())); subscribe(Global::RefSelfChanged(), [this]() { updateGlobalMenu(); }); @@ -173,7 +170,9 @@ void MainWindow::initHook() { void MainWindow::onWindowActiveChanged() { checkHistoryActivation(); - QTimer::singleShot(1, this, SLOT(updateTrayMenu())); + QTimer::singleShot(1, base::lambda_slot_once(this, [this] { + updateTrayMenu(); + }), SLOT(action())); } void MainWindow::firstShow() { @@ -207,20 +206,14 @@ void MainWindow::firstShow() { createMediaView(); } -void MainWindow::clearWidgets() { +void MainWindow::clearWidgetsHook() { auto wasMain = (_main != nullptr); - Ui::hideLayer(true); _passcode.destroyDelayed(); _main.destroy(); _intro.destroy(); - if (_mediaView) { - hideMediaview(); - _mediaView->rpcClear(); - } if (wasMain) { App::clearHistories(); } - updateGlobalMenu(); } QPixmap MainWindow::grabInner() { @@ -261,7 +254,7 @@ void MainWindow::setupPasscode() { updateControlsGeometry(); if (_main) _main->hide(); - if (_mediaView) _mediaView->hide(); + hideMediaview(); Ui::hideSettingsAndLayer(true); if (_intro) _intro->hide(); if (animated) { @@ -300,9 +293,6 @@ void MainWindow::setupIntro() { cSetDialogsReceived(false); if (_intro && !_intro->isHidden() && !_main) return; - if (_mediaView) { - _mediaView->clearData(); - } Ui::hideSettingsAndLayer(true); auto animated = (_main || _passcode); @@ -447,31 +437,6 @@ PasscodeWidget *MainWindow::passcodeWidget() { return _passcode; } -void MainWindow::showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item) { - return (!item && lnk->peer()) ? showPhoto(lnk->photo(), lnk->peer()) : showPhoto(lnk->photo(), item); -} - -void MainWindow::showPhoto(PhotoData *photo, HistoryItem *item) { - if (_mediaView->isHidden()) Ui::hideLayer(true); - _mediaView->showPhoto(photo, item); - _mediaView->activateWindow(); - _mediaView->setFocus(); -} - -void MainWindow::showPhoto(PhotoData *photo, PeerData *peer) { - if (_mediaView->isHidden()) Ui::hideLayer(true); - _mediaView->showPhoto(photo, peer); - _mediaView->activateWindow(); - _mediaView->setFocus(); -} - -void MainWindow::showDocument(DocumentData *doc, HistoryItem *item) { - if (_mediaView->isHidden()) Ui::hideLayer(true); - _mediaView->showDocument(doc, item); - _mediaView->activateWindow(); - _mediaView->setFocus(); -} - void MainWindow::ui_showBox(object_ptr box, ShowLayerOptions options) { if (box) { if (!_layerBg) { @@ -504,10 +469,6 @@ bool MainWindow::ui_isLayerShown() { return _layerBg != nullptr; } -bool MainWindow::ui_isMediaViewShown() { - return _mediaView && !_mediaView->isHidden(); -} - void MainWindow::ui_showMediaPreview(DocumentData *document) { if (!document || ((!document->isAnimation() || !document->loaded()) && !document->sticker())) return; if (!_mediaPreview) { @@ -538,8 +499,8 @@ void MainWindow::ui_hideMediaPreview() { } PeerData *MainWindow::ui_getPeerForMouseAction() { - if (_mediaView && !_mediaView->isHidden()) { - return _mediaView->ui_getPeerForMouseAction(); + if (Ui::isMediaViewShown()) { + return Platform::MainWindow::ui_getPeerForMouseAction(); } else if (_main) { return _main->ui_getPeerForMouseAction(); } @@ -579,8 +540,9 @@ void MainWindow::themeUpdated(const Window::Theme::BackgroundUpdate &data) { } } -bool MainWindow::doWeReadServerHistory() const { - return isActive(false) && _main && !Ui::isLayerShown() && _main->doWeReadServerHistory(); +bool MainWindow::doWeReadServerHistory() { + updateIsActive(0); + return isActive() && _main && !Ui::isLayerShown() && _main->doWeReadServerHistory(); } void MainWindow::checkHistoryActivation() { @@ -694,7 +656,8 @@ void MainWindow::updateTrayMenu(bool force) { auto minimizeAction = actions.at(1); minimizeAction->setDisabled(!isVisible()); } else { - auto active = isActive(false); + updateIsActive(0); + auto active = isActive(); auto toggleAction = actions.at(0); disconnect(toggleAction, SIGNAL(triggered(bool)), this, SLOT(minimizeToTray())); disconnect(toggleAction, SIGNAL(triggered(bool)), this, SLOT(showFromTray())); @@ -752,14 +715,6 @@ void MainWindow::onLogout() { })); } -void MainWindow::updateGlobalMenu() { -#ifdef Q_OS_MAC - if (App::wnd()) { - psMacUpdateMenu(); - } -#endif -} - void MainWindow::quitFromTray() { App::quit(); } @@ -811,20 +766,23 @@ void MainWindow::fixOrder() { void MainWindow::showFromTray(QSystemTrayIcon::ActivationReason reason) { if (reason != QSystemTrayIcon::Context) { - QTimer::singleShot(1, this, SLOT(updateTrayMenu())); - QTimer::singleShot(1, this, SLOT(updateGlobalMenu())); + QTimer::singleShot(1, base::lambda_slot_once(this, [this] { + updateTrayMenu(); + updateGlobalMenu(); + }), SLOT(action())); activate(); Notify::unreadCounterUpdated(); } } void MainWindow::toggleTray(QSystemTrayIcon::ActivationReason reason) { - if ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) && isActive(false)) return; + updateIsActive(0); + if ((cPlatform() == dbipMac || cPlatform() == dbipMacOld) && isActive()) return; if (reason == QSystemTrayIcon::Context) { updateTrayMenu(true); QTimer::singleShot(1, this, SLOT(psShowTrayMenu())); } else { - if (isActive(false)) { + if (isActive()) { minimizeToTray(); } else { showFromTray(reason); @@ -1366,38 +1324,12 @@ void MainWindow::sendPaths() { } } -void MainWindow::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { - if (_main) _main->mediaOverviewUpdated(peer, type); - if (_mediaView && !_mediaView->isHidden()) { - _mediaView->mediaOverviewUpdated(peer, type); - } - if (type != OverviewCount) { - Notify::PeerUpdate update(peer); - update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged; - update.mediaTypesMask |= (1 << type); - Notify::peerUpdatedDelayed(update); - } -} - -void MainWindow::documentUpdated(DocumentData *doc) { - if (!_mediaView || _mediaView->isHidden()) return; - _mediaView->documentUpdated(doc); -} - void MainWindow::changingMsgId(HistoryItem *row, MsgId newId) { if (_main) _main->changingMsgId(row, newId); - if (!_mediaView || _mediaView->isHidden()) return; - _mediaView->changingMsgId(row, newId); + Platform::MainWindow::changingMsgId(row, newId); } -bool MainWindow::isActive(bool cached) const { - if (cached) return _isActive; - return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); -} - -void MainWindow::updateIsActive(int timeout) { - if (timeout) return _isActiveTimer.start(timeout); - _isActive = isActive(false); +void MainWindow::updateIsActiveHook() { if (_main) _main->updateOnline(); } diff --git a/Telegram/SourceFiles/mainwindow.h b/Telegram/SourceFiles/mainwindow.h index 93a09a63bb..a3a93f829c 100644 --- a/Telegram/SourceFiles/mainwindow.h +++ b/Telegram/SourceFiles/mainwindow.h @@ -98,12 +98,7 @@ public: MainWidget *mainWidget(); PasscodeWidget *passcodeWidget(); - void showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item = 0); - void showPhoto(PhotoData *photo, HistoryItem *item); - void showPhoto(PhotoData *photo, PeerData *item); - void showDocument(DocumentData *doc, HistoryItem *item); - - bool doWeReadServerHistory() const; + bool doWeReadServerHistory(); void activate(); @@ -135,11 +130,7 @@ public: void sendPaths(); - void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); - void documentUpdated(DocumentData *doc); - void changingMsgId(HistoryItem *row, MsgId newId); - - bool isActive(bool cached = true) const; + void changingMsgId(HistoryItem *row, MsgId newId) override; QImage iconWithCounter(int size, int count, style::color bg, style::color fg, bool smallIcon) override; @@ -152,15 +143,15 @@ public: } void showMainMenu(); + void updateTrayMenu(bool force = false) override; void ui_showBox(object_ptr box, ShowLayerOptions options); void ui_hideSettingsAndLayer(ShowLayerOptions options); bool ui_isLayerShown(); - bool ui_isMediaViewShown(); void ui_showMediaPreview(DocumentData *document); void ui_showMediaPreview(PhotoData *photo); void ui_hideMediaPreview(); - PeerData *ui_getPeerForMouseAction(); + PeerData *ui_getPeerForMouseAction() override; protected: bool eventFilter(QObject *o, QEvent *e) override; @@ -168,10 +159,10 @@ protected: void resizeEvent(QResizeEvent *e) override; void initHook() override; + void updateIsActiveHook() override; + void clearWidgetsHook() override; public slots: - void updateIsActive(int timeout = 0); - void checkAutoLock(); void showSettings(); @@ -190,13 +181,11 @@ public slots: void onClearFailed(int task, void *manager); void notifyShowNext(); - void updateTrayMenu(bool force = false); void onShowAddContact(); void onShowNewGroup(); void onShowNewChannel(); void onLogout(); - void updateGlobalMenu(); // for OS X top menu void app_activateClickHandler(ClickHandlerPtr handler, Qt::MouseButton button); @@ -239,16 +228,11 @@ private: object_ptr _layerBg = { nullptr }; object_ptr _mediaPreview = { nullptr }; - QTimer _isActiveTimer; - bool _isActive = false; - object_ptr _connecting = { nullptr }; object_ptr _testingThemeWarning = { nullptr }; Local::ClearManager *_clearManager = nullptr; - void clearWidgets(); - bool _inactivePress = false; QTimer _inactiveTimer; diff --git a/Telegram/SourceFiles/mediaview.cpp b/Telegram/SourceFiles/mediaview.cpp index b907f96869..925e1d50a8 100644 --- a/Telegram/SourceFiles/mediaview.cpp +++ b/Telegram/SourceFiles/mediaview.cpp @@ -36,6 +36,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "history/history_media_types.h" #include "window/window_theme_preview.h" #include "core/task_queue.h" +#include "observer_peer.h" namespace { @@ -90,6 +91,10 @@ MediaView::MediaView(QWidget*) : TWidget(nullptr) updateControls(); } }); + auto observeEvents = Notify::PeerUpdate::Flag::SharedMediaChanged; + subscribe(Notify::PeerUpdated(), Notify::PeerUpdatedHandler(observeEvents, [this](const Notify::PeerUpdate &update) { + mediaOverviewUpdated(update); + })); generateTransparentBrush(); @@ -148,8 +153,8 @@ void MediaView::moveToScreen() { _saveMsg.moveTo((width() - _saveMsg.width()) / 2, (height() - _saveMsg.height()) / 2); } -void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { - if (!_photo && !_doc) return; +void MediaView::mediaOverviewUpdated(const Notify::PeerUpdate &update) { + if (isHidden() || (!_photo && !_doc)) return; if (_photo && _overview == OverviewChatPhotos && _history && !_history->peer->isUser()) { auto lastChatPhoto = computeLastOverviewChatPhoto(); if (_index < 0 && _photo == lastChatPhoto.photo && _photo == _additionalChatPhoto) { @@ -161,7 +166,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { computeAdditionalChatPhoto(_history->peer, lastChatPhoto.photo); } - if (_history && (_history->peer == peer || (_migrated && _migrated->peer == peer)) && type == _overview && _msgid) { + if (_history && (_history->peer == update.peer || (_migrated && _migrated->peer == update.peer)) && (update.mediaTypesMask & (1 << _overview)) && _msgid) { _index = -1; if (_msgmigrated) { for (int i = 0, l = _migrated->overview[_overview].size(); i < l; ++i) { @@ -180,7 +185,7 @@ void MediaView::mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { } updateControls(); preloadData(0); - } else if (_user == peer && type == OverviewCount) { + } else if (_user == update.peer && update.mediaTypesMask & (1 << OverviewCount)) { if (!_photo) return; _index = -1; @@ -243,7 +248,12 @@ void MediaView::changingMsgId(HistoryItem *row, MsgId newId) { if (row->id == _msgid) { _msgid = newId; } - mediaOverviewUpdated(row->history()->peer, _overview); + + // Send a fake update. + Notify::PeerUpdate update(row->history()->peer); + update.flags |= Notify::PeerUpdate::Flag::SharedMediaChanged; + update.mediaTypesMask |= (1 << _overview); + mediaOverviewUpdated(update); } void MediaView::updateDocSize() { @@ -767,7 +777,7 @@ void MediaView::onSaveAs() { psBringToBack(this); auto filter = qsl("JPEG Image (*.jpg);;") + filedialogAllFilesFilter(); - bool gotName = filedialogGetSaveFile(file, lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg"))); + auto gotName = filedialogGetSaveFile(file, lang(lng_save_photo), filter, filedialogDefaultName(qsl("photo"), qsl(".jpg"))); psShowOverAll(this); if (gotName) { if (!file.isEmpty()) { @@ -1451,7 +1461,7 @@ void MediaView::initThemePreview() { }; Window::Theme::CurrentData current; current.backgroundId = Window::Theme::Background()->id(); - current.backgroundImage = Window::Theme::Background()->image(); + current.backgroundImage = Window::Theme::Background()->pixmap(); current.backgroundTiled = Window::Theme::Background()->tile(); base::TaskQueue::Normal().Put([path, current, callback = mutable_ready(std_::move(ready))]() { auto preview = Window::Theme::GeneratePreview(path, current); @@ -2841,12 +2851,12 @@ void MediaView::userPhotosLoaded(UserData *u, const MTPphotos_Photos &photos, mt u->photosCount = 0; } - for (QVector::const_iterator i = v->cbegin(), e = v->cend(); i != e; ++i) { - PhotoData *photo = App::feedPhoto(*i); + for (auto i = v->cbegin(), e = v->cend(); i != e; ++i) { + auto photo = App::feedPhoto(*i); photo->thumb->load(); u->photos.push_back(photo); } - if (App::wnd()) App::wnd()->mediaOverviewUpdated(u, OverviewCount); + Notify::mediaOverviewUpdated(u, OverviewCount); } void MediaView::updateHeader() { diff --git a/Telegram/SourceFiles/mediaview.h b/Telegram/SourceFiles/mediaview.h index 1d329aeb14..d24385a444 100644 --- a/Telegram/SourceFiles/mediaview.h +++ b/Telegram/SourceFiles/mediaview.h @@ -41,6 +41,10 @@ struct Preview; } // namespace Theme } // namespace Window +namespace Notify { +struct PeerUpdate; +} // namespace Notify + struct AudioPlaybackState; class MediaView : public TWidget, private base::Subscriber, public RPCSender, public ClickHandlerHost { @@ -67,7 +71,7 @@ public: updateOver(mapFromGlobal(QCursor::pos())); } - void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); + void mediaOverviewUpdated(const Notify::PeerUpdate &update); void documentUpdated(DocumentData *doc); void changingMsgId(HistoryItem *row, MsgId newId); diff --git a/Telegram/SourceFiles/observer_peer.h b/Telegram/SourceFiles/observer_peer.h index 5cf4f5b6b9..5af6520842 100644 --- a/Telegram/SourceFiles/observer_peer.h +++ b/Telegram/SourceFiles/observer_peer.h @@ -91,6 +91,13 @@ inline void peerUpdatedDelayed(PeerData *peer, PeerUpdate::Flags events) { } void peerUpdatedSendDelayed(); +inline void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type) { + PeerUpdate update(peer); + update.flags |= PeerUpdate::Flag::SharedMediaChanged; + update.mediaTypesMask |= (1 << type); + peerUpdatedDelayed(update); +} + class PeerUpdatedHandler { public: template diff --git a/Telegram/SourceFiles/overviewwidget.cpp b/Telegram/SourceFiles/overviewwidget.cpp index 2e71b138e4..eb61b60def 100644 --- a/Telegram/SourceFiles/overviewwidget.cpp +++ b/Telegram/SourceFiles/overviewwidget.cpp @@ -43,6 +43,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "history/history_media_types.h" #include "history/history_service_layout.h" #include "media/media_audio.h" +#include "observer_peer.h" // flick scroll taken from http://qt-project.org/doc/qt-4.8/demos-embedded-anomaly-src-flickcharm-cpp.html @@ -2164,8 +2165,8 @@ void OverviewWidget::doneShow() { onScroll(); } -void OverviewWidget::mediaOverviewUpdated(PeerData *p, MediaOverviewType t) { - if ((peer() == p || migratePeer() == p) && t == type()) { +void OverviewWidget::mediaOverviewUpdated(const Notify::PeerUpdate &update) { + if ((peer() == update.peer || migratePeer() == update.peer) && (update.mediaTypesMask & (1 << type()))) { _inner->mediaOverviewUpdated(); onScroll(); updateTopBarSelection(); diff --git a/Telegram/SourceFiles/overviewwidget.h b/Telegram/SourceFiles/overviewwidget.h index 0645e7744b..d72111a967 100644 --- a/Telegram/SourceFiles/overviewwidget.h +++ b/Telegram/SourceFiles/overviewwidget.h @@ -40,6 +40,10 @@ class FlatInput; class CrossButton; } // namespace Ui +namespace Notify { +struct PeerUpdate; +} // namespace Notify + class OverviewWidget; class OverviewInner : public TWidget, public Ui::AbstractTooltipShower, public RPCSender, private base::Subscriber { Q_OBJECT @@ -305,7 +309,7 @@ public: void doneShow(); - void mediaOverviewUpdated(PeerData *peer, MediaOverviewType type); + void mediaOverviewUpdated(const Notify::PeerUpdate &update); void changingMsgId(HistoryItem *row, MsgId newId); void itemRemoved(HistoryItem *item); diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp index 01fe867b6e..90da8e28f5 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.cpp +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.cpp @@ -195,7 +195,7 @@ void MainWindow::initHook() { setWindowIcon(wndIcon); } -bool MainWindow::psHasTrayIcon() const { +bool MainWindow::hasTrayIcon() const { return trayIcon || ((useAppIndicator || (useStatusIcon && trayIconChecked)) && (cWorkMode() != dbiwmWindowOnly)); } diff --git a/Telegram/SourceFiles/platform/linux/main_window_linux.h b/Telegram/SourceFiles/platform/linux/main_window_linux.h index 7246f6cb7b..3f691f7fe3 100644 --- a/Telegram/SourceFiles/platform/linux/main_window_linux.h +++ b/Telegram/SourceFiles/platform/linux/main_window_linux.h @@ -61,7 +61,7 @@ protected: void initHook() override; void unreadCounterChangedHook() override; - bool psHasTrayIcon() const; + bool hasTrayIcon() const override; QSystemTrayIcon *trayIcon = nullptr; QMenu *trayIconMenu = nullptr; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.h b/Telegram/SourceFiles/platform/mac/main_window_mac.h index 250524b890..6dfa5dabea 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.h +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.h @@ -82,11 +82,11 @@ protected: void unreadCounterChangedHook() override; QImage psTrayIcon(bool selected = false) const; - bool psHasTrayIcon() const { + bool hasTrayIcon() const override { return trayIcon; } - void psMacUpdateMenu(); + void updateGlobalMenuHook() override; QSystemTrayIcon *trayIcon = nullptr; QMenu *trayIconMenu = nullptr; diff --git a/Telegram/SourceFiles/platform/mac/main_window_mac.mm b/Telegram/SourceFiles/platform/mac/main_window_mac.mm index aa60566c56..2464cef446 100644 --- a/Telegram/SourceFiles/platform/mac/main_window_mac.mm +++ b/Telegram/SourceFiles/platform/mac/main_window_mac.mm @@ -391,8 +391,6 @@ void MainWindow::psFirstShow() { setPositionInited(); createGlobalMenu(); - - psMacUpdateMenu(); } void MainWindow::createGlobalMenu() { @@ -436,6 +434,8 @@ void MainWindow::createGlobalMenu() { psNewChannel = window->addAction(lang(lng_mac_menu_new_channel), App::wnd(), SLOT(onShowNewChannel())); window->addSeparator(); psShowTelegram = window->addAction(lang(lng_mac_menu_show), App::wnd(), SLOT(showFromTray())); + + updateGlobalMenu(); } namespace { @@ -492,10 +492,10 @@ void MainWindow::psUpdateSysMenu(Qt::WindowState state) { void MainWindow::psUpdateMargins() { } -void MainWindow::psMacUpdateMenu() { - if (!positionInited()) return; +void MainWindow::updateGlobalMenuHook() { + if (!App::wnd() || !positionInited()) return; - QWidget *focused = QApplication::focusWidget(); + auto focused = QApplication::focusWidget(); bool isLogged = !!App::self(), canUndo = false, canRedo = false, canCut = false, canCopy = false, canPaste = false, canDelete = false, canSelectAll = false; if (auto edit = qobject_cast(focused)) { canCut = canCopy = canDelete = edit->hasSelectedText(); @@ -513,6 +513,7 @@ void MainWindow::psMacUpdateMenu() { canCopy = list->canCopySelected(); canDelete = list->canDeleteSelected(); } + App::wnd()->updateIsActive(0); _forceDisabled(psLogout, !isLogged && !App::passcoded()); _forceDisabled(psUndo, !canUndo); _forceDisabled(psRedo, !canRedo); @@ -525,7 +526,7 @@ void MainWindow::psMacUpdateMenu() { _forceDisabled(psAddContact, !isLogged || App::passcoded()); _forceDisabled(psNewGroup, !isLogged || App::passcoded()); _forceDisabled(psNewChannel, !isLogged || App::passcoded()); - _forceDisabled(psShowTelegram, App::wnd()->isActive(false)); + _forceDisabled(psShowTelegram, App::wnd()->isActive()); } void MainWindow::psFlash() { @@ -540,7 +541,7 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *evt) { QEvent::Type t = evt->type(); if (t == QEvent::FocusIn || t == QEvent::FocusOut) { if (qobject_cast(obj) || qobject_cast(obj) || qobject_cast(obj)) { - psMacUpdateMenu(); + updateGlobalMenu(); } } return Window::MainWindow::eventFilter(obj, evt); diff --git a/Telegram/SourceFiles/platform/win/main_window_win.cpp b/Telegram/SourceFiles/platform/win/main_window_win.cpp index aeb86d9f7e..76a1234ed9 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.cpp +++ b/Telegram/SourceFiles/platform/win/main_window_win.cpp @@ -693,6 +693,14 @@ void MainWindow::psSetupTrayIcon() { trayIcon->show(); } +void MainWindow::showTrayTooltip() { + if (trayIcon && !cSeenTrayTooltip()) { + trayIcon->showMessage(str_const_toString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000); + cSetSeenTrayTooltip(true); + Local::writeSettings(); + } +} + void MainWindow::psUpdateWorkmode() { switch (cWorkMode()) { case dbiwmWindowAndTray: { @@ -809,7 +817,7 @@ void MainWindow::psFirstShow() { setWindowState(Qt::WindowMaximized); } - if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized()) || cStartInTray()) { + if ((cLaunchMode() == LaunchModeAutoStart && cStartMinimized() && !App::passcoded()) || cStartInTray()) { setWindowState(Qt::WindowMinimized); if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { hide(); diff --git a/Telegram/SourceFiles/platform/win/main_window_win.h b/Telegram/SourceFiles/platform/win/main_window_win.h index 4659fd100d..2e593afd04 100644 --- a/Telegram/SourceFiles/platform/win/main_window_win.h +++ b/Telegram/SourceFiles/platform/win/main_window_win.h @@ -93,7 +93,7 @@ protected: int32 screenNameChecksum(const QString &name) const override; void unreadCounterChangedHook() override; - bool psHasTrayIcon() const { + bool hasTrayIcon() const override { return trayIcon; } @@ -106,6 +106,8 @@ protected: void psSetupTrayIcon(); virtual void placeSmallCounter(QImage &img, int size, int count, style::color bg, const QPoint &shift, style::color color) = 0; + void showTrayTooltip() override; + QTimer psUpdatedPositionTimer; private: diff --git a/Telegram/SourceFiles/profile/profile_block_shared_media.cpp b/Telegram/SourceFiles/profile/profile_block_shared_media.cpp index 4ec6a965fe..84e5cbaeef 100644 --- a/Telegram/SourceFiles/profile/profile_block_shared_media.cpp +++ b/Telegram/SourceFiles/profile/profile_block_shared_media.cpp @@ -73,8 +73,8 @@ void SharedMediaWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { return; } - bool updated = false; - for (int i = 0; i < OverviewCount; ++i) { + auto updated = false; + for (auto i = 0; i != OverviewCount; ++i) { if (update.mediaTypesMask & (1 << i)) { refreshButton(static_cast(i)); updated = true; diff --git a/Telegram/SourceFiles/settings/settings_background_widget.cpp b/Telegram/SourceFiles/settings/settings_background_widget.cpp index c24d50a0e4..654b06d4e8 100644 --- a/Telegram/SourceFiles/settings/settings_background_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_background_widget.cpp @@ -173,7 +173,7 @@ void BackgroundRow::updateImage() { Painter p(&back); PainterHighQualityEnabler hq(p); - auto &pix = Window::Theme::Background()->image(); + auto &pix = Window::Theme::Background()->pixmap(); int sx = (pix.width() > pix.height()) ? ((pix.width() - pix.height()) / 2) : 0; int sy = (pix.height() > pix.width()) ? ((pix.height() - pix.width()) / 2) : 0; int s = (pix.width() > pix.height()) ? pix.height() : pix.width(); diff --git a/Telegram/SourceFiles/settings/settings_general_widget.cpp b/Telegram/SourceFiles/settings/settings_general_widget.cpp index 613bf50213..41fe739dbc 100644 --- a/Telegram/SourceFiles/settings/settings_general_widget.cpp +++ b/Telegram/SourceFiles/settings/settings_general_widget.cpp @@ -193,7 +193,10 @@ void GeneralWidget::refreshControls() { addChildRow(_enableTaskbarIcon, marginLarge, lang(lng_settings_workmode_window), SLOT(onEnableTaskbarIcon()), (cWorkMode() == dbiwmWindowOnly || cWorkMode() == dbiwmWindowAndTray)); addChildRow(_autoStart, marginSmall, lang(lng_settings_auto_start), SLOT(onAutoStart()), cAutoStart()); - addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), SLOT(onStartMinimized()), cStartMinimized()); + addChildRow(_startMinimized, marginLarge, slidedPadding, lang(lng_settings_start_min), SLOT(onStartMinimized()), (cStartMinimized() && !Global::LocalPasscode())); + subscribe(Global::RefLocalPasscodeChanged(), [this] { + _startMinimized->entity()->setChecked(cStartMinimized() && !Global::LocalPasscode()); + }); if (!cAutoStart()) { _startMinimized->hideFast(); } @@ -310,8 +313,18 @@ void GeneralWidget::onAutoStart() { } void GeneralWidget::onStartMinimized() { - cSetStartMinimized(_startMinimized->entity()->checked()); - Local::writeSettings(); + auto checked = _startMinimized->entity()->checked(); + if (Global::LocalPasscode()) { + if (checked) { + _startMinimized->entity()->setChecked(false); + Ui::show(Box(lang(lng_error_start_minimized_passcoded))); + } + return; + } + if (cStartMinimized() != checked) { + cSetStartMinimized(checked); + Local::writeSettings(); + } } void GeneralWidget::onAddInSendTo() { diff --git a/Telegram/SourceFiles/ui/widgets/tooltip.cpp b/Telegram/SourceFiles/ui/widgets/tooltip.cpp index 2ba943a6c3..4fbba46339 100644 --- a/Telegram/SourceFiles/ui/widgets/tooltip.cpp +++ b/Telegram/SourceFiles/ui/widgets/tooltip.cpp @@ -50,7 +50,13 @@ Tooltip::Tooltip() : TWidget(nullptr) { void Tooltip::onShow() { if (_shower) { - QString text = (App::wnd() && App::wnd()->isActive(false)) ? _shower->tooltipText() : QString(); + auto text = QString(); + if (auto window = App::wnd()) { + window->updateIsActive(0); + if (window->isActive()) { + text = _shower->tooltipText(); + } + } if (text.isEmpty()) { Hide(); } else { diff --git a/Telegram/SourceFiles/window/main_window.cpp b/Telegram/SourceFiles/window/main_window.cpp index 58b85f739f..c316a73fdf 100644 --- a/Telegram/SourceFiles/window/main_window.cpp +++ b/Telegram/SourceFiles/window/main_window.cpp @@ -33,7 +33,8 @@ namespace Window { MainWindow::MainWindow() : QWidget() , _positionUpdatedTimer(this) , _body(this) -, _titleText(qsl("Telegram")) { +, _titleText(qsl("Telegram")) +, _isActiveTimer(this) { subscribe(Theme::Background(), [this](const Theme::BackgroundUpdate &data) { if (data.paletteChanged()) { if (_title) { @@ -43,11 +44,14 @@ MainWindow::MainWindow() : QWidget() } }); subscribe(Global::RefUnreadCounterUpdate(), [this] { updateUnreadCounter(); }); + + _isActiveTimer->setSingleShot(true); + connect(_isActiveTimer, SIGNAL(timeout()), this, SLOT(updateIsActiveByTimer())); } bool MainWindow::hideNoQuit() { if (_mediaView && !_mediaView->isHidden()) { - _mediaView->hide(); + hideMediaview(); return true; } if (cWorkMode() == dbiwmTrayOnly || cWorkMode() == dbiwmWindowAndTray) { @@ -62,6 +66,59 @@ bool MainWindow::hideNoQuit() { Ui::showChatsList(); return true; } + return false; +} + +void MainWindow::clearWidgets() { + Ui::hideLayer(true); + if (_mediaView) { + hideMediaview(); + _mediaView->rpcClear(); + _mediaView->clearData(); + } + clearWidgetsHook(); + updateGlobalMenu(); +} + +void MainWindow::showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item) { + return (!item && lnk->peer()) ? showPhoto(lnk->photo(), lnk->peer()) : showPhoto(lnk->photo(), item); +} + +void MainWindow::showPhoto(PhotoData *photo, HistoryItem *item) { + if (_mediaView->isHidden()) Ui::hideLayer(true); + _mediaView->showPhoto(photo, item); + _mediaView->activateWindow(); + _mediaView->setFocus(); +} + +void MainWindow::showPhoto(PhotoData *photo, PeerData *peer) { + if (_mediaView->isHidden()) Ui::hideLayer(true); + _mediaView->showPhoto(photo, peer); + _mediaView->activateWindow(); + _mediaView->setFocus(); +} + +void MainWindow::showDocument(DocumentData *doc, HistoryItem *item) { + if (_mediaView->isHidden()) Ui::hideLayer(true); + _mediaView->showDocument(doc, item); + _mediaView->activateWindow(); + _mediaView->setFocus(); +} + +bool MainWindow::ui_isMediaViewShown() { + return _mediaView && !_mediaView->isHidden(); +} + +void MainWindow::updateIsActive(int timeout) { + if (timeout) { + return _isActiveTimer->start(timeout); + } + _isActive = computeIsActive(); + updateIsActiveHook(); +} + +bool MainWindow::computeIsActive() const { + return isActiveWindow() && isVisible() && !(windowState() & Qt::WindowMinimized); } void MainWindow::hideMediaview() { @@ -251,22 +308,31 @@ void MainWindow::savePosition(Qt::WindowState state) { } bool MainWindow::minimizeToTray() { - if (App::quitting() || !psHasTrayIcon()) return false; + if (App::quitting() || !hasTrayIcon()) return false; closeWithoutDestroy(); - if (cPlatform() == dbipWindows && trayIcon && !cSeenTrayTooltip()) { - trayIcon->showMessage(str_const_toString(AppName), lang(lng_tray_icon_text), QSystemTrayIcon::Information, 10000); - cSetSeenTrayTooltip(true); - Local::writeSettings(); - } updateIsActive(Global::OfflineBlurTimeout()); updateTrayMenu(); updateGlobalMenu(); + showTrayTooltip(); return true; } -void MainWindow::closeWithoutDestroy() { - hide(); +void MainWindow::documentUpdated(DocumentData *doc) { + if (!_mediaView || _mediaView->isHidden()) return; + _mediaView->documentUpdated(doc); +} + +void MainWindow::changingMsgId(HistoryItem *row, MsgId newId) { + if (!_mediaView || _mediaView->isHidden()) return; + _mediaView->changingMsgId(row, newId); +} + +PeerData *MainWindow::ui_getPeerForMouseAction() { + if (_mediaView && !_mediaView->isHidden()) { + return _mediaView->ui_getPeerForMouseAction(); + } + return nullptr; } MainWindow::~MainWindow() = default; diff --git a/Telegram/SourceFiles/window/main_window.h b/Telegram/SourceFiles/window/main_window.h index 7e586a3d71..0698e3288f 100644 --- a/Telegram/SourceFiles/window/main_window.h +++ b/Telegram/SourceFiles/window/main_window.h @@ -39,6 +39,10 @@ public: void init(); HitTestResult hitTest(const QPoint &p) const; + void updateIsActive(int timeout); + bool isActive() const { + return _isActive; + } bool positionInited() const { return _positionInited; @@ -51,16 +55,33 @@ public: return _titleText; } + void showPhoto(const PhotoOpenClickHandler *lnk, HistoryItem *item = 0); + void showPhoto(PhotoData *photo, HistoryItem *item); + void showPhoto(PhotoData *photo, PeerData *item); + void showDocument(DocumentData *doc, HistoryItem *item); + bool ui_isMediaViewShown(); + QWidget *filedialogParent(); + virtual void updateTrayMenu(bool force = false) { + } + + // TODO: rewrite using base::Observable + void documentUpdated(DocumentData *doc); + virtual void changingMsgId(HistoryItem *row, MsgId newId); + virtual ~MainWindow(); TWidget *bodyWidget() { return _body.data(); } + virtual PeerData *ui_getPeerForMouseAction(); public slots: bool minimizeToTray(); + void updateGlobalMenu() { + updateGlobalMenuHook(); + } protected: void resizeEvent(QResizeEvent *e) override; @@ -70,6 +91,13 @@ protected: virtual void initHook() { } + virtual void updateIsActiveHook() { + } + + void clearWidgets(); + virtual void clearWidgetsHook() { + } + virtual void stateChangedHook(Qt::WindowState state) { } @@ -83,6 +111,15 @@ protected: hide(); } + virtual void updateGlobalMenuHook() { + } + + virtual bool hasTrayIcon() const { + return false; + } + virtual void showTrayTooltip() { + } + // This one is overriden in Windows for historical reasons. virtual int32 screenNameChecksum(const QString &name) const; @@ -95,6 +132,9 @@ private slots: savePosition(); } void onReActivate(); + void updateIsActiveByTimer() { + updateIsActive(0); + } private: void updatePalette(); @@ -102,6 +142,8 @@ private: void updateUnreadCounter(); void initSize(); + bool computeIsActive() const; + object_ptr _positionUpdatedTimer; bool _positionInited = false; @@ -110,6 +152,9 @@ private: QString _titleText; + object_ptr _isActiveTimer; + bool _isActive = false; + object_ptr _mediaView = { nullptr }; }; diff --git a/Telegram/SourceFiles/window/window_theme.cpp b/Telegram/SourceFiles/window/window_theme.cpp index 604f081bbc..e4de88fb96 100644 --- a/Telegram/SourceFiles/window/window_theme.cpp +++ b/Telegram/SourceFiles/window/window_theme.cpp @@ -36,6 +36,8 @@ constexpr int kThemeFileSizeLimit = 5 * 1024 * 1024; constexpr int kThemeBackgroundSizeLimit = 4 * 1024 * 1024; constexpr int kThemeSchemeSizeLimit = 1024 * 1024; +constexpr int kMinimumTiledSize = 512; + struct Data { struct Applying { QString path; @@ -335,6 +337,8 @@ void initColor(style::color color, float64 hue, float64 saturation) { } void initColorsFromBackground(const QImage &img) { + t_assert(img.format() == QImage::Format_ARGB32_Premultiplied); + uint64 components[3] = { 0 }; uint64 componentsScroll[3] = { 0 }; auto w = img.width(); @@ -409,25 +413,50 @@ void ChatBackground::setImage(int32 id, QImage &&image) { Local::writeBackground(_id, (_id == kDefaultBackground || _id == kInitialBackground) ? QImage() : image); setPreparedImage(prepareBackgroundImage(std_::move(image))); } - t_assert(!_image.isNull()); + t_assert(!_pixmap.isNull() && !_pixmapForTiled.isNull()); notify(BackgroundUpdate(BackgroundUpdate::Type::New, _tile)); } void ChatBackground::setPreparedImage(QImage &&image) { + image = std_::move(image).convertToFormat(QImage::Format_ARGB32_Premultiplied); if (_id != kThemeBackground && _id != internal::kTestingThemeBackground) { initColorsFromBackground(image); } - _image = App::pixmapFromImageInPlace(std_::move(image)); + + auto width = image.width(); + auto height = image.height(); + t_assert(width > 0 && height > 0); + auto isSmallForTiled = (width < kMinimumTiledSize || height < kMinimumTiledSize); + if (isSmallForTiled) { + auto repeatTimesX = qCeil(kMinimumTiledSize / float64(width)); + auto repeatTimesY = qCeil(kMinimumTiledSize / float64(height)); + auto imageForTiled = QImage(width * repeatTimesX, height * repeatTimesY, QImage::Format_ARGB32_Premultiplied); + imageForTiled.setDevicePixelRatio(image.devicePixelRatio()); + auto imageForTiledBytes = imageForTiled.bits(); + auto bytesInLine = width * sizeof(uint32); + for (auto timesY = 0; timesY != repeatTimesY; ++timesY) { + auto imageBytes = image.constBits(); + for (auto y = 0; y != height; ++y) { + for (auto timesX = 0; timesX != repeatTimesX; ++timesX) { + memcpy(imageForTiledBytes, imageBytes, bytesInLine); + imageForTiledBytes += bytesInLine; + } + imageBytes += image.bytesPerLine(); + imageForTiledBytes += imageForTiled.bytesPerLine() - (repeatTimesX * bytesInLine); + } + } + _pixmapForTiled = App::pixmapFromImageInPlace(std_::move(imageForTiled)); + } + _pixmap = App::pixmapFromImageInPlace(std_::move(image)); + if (!isSmallForTiled) { + _pixmapForTiled = _pixmap; + } } int32 ChatBackground::id() const { return _id; } -const QPixmap &ChatBackground::image() const { - return _image; -} - bool ChatBackground::tile() const { return _tile; } @@ -441,7 +470,7 @@ bool ChatBackground::tileForSave() const { } void ChatBackground::ensureStarted() { - if (_image.isNull()) { + if (_pixmap.isNull()) { // We should start first, otherwise the default call // to start() will reset this value to _themeTile. start(); @@ -479,7 +508,7 @@ void ChatBackground::saveForRevert() { ensureStarted(); if (_id != internal::kTestingThemeBackground && _id != internal::kTestingDefaultBackground) { _idForRevert = _id; - _imageForRevert = std_::move(_image).toImage(); + _imageForRevert = std_::move(_pixmap).toImage(); _tileForRevert = _tile; } } @@ -507,7 +536,7 @@ void ChatBackground::setTestingDefaultTheme() { void ChatBackground::keepApplied() { if (_id == internal::kTestingThemeBackground) { _id = kThemeBackground; - _themeImage = _image.toImage(); + _themeImage = _pixmap.toImage(); _themeTile = _tile; writeNewBackgroundSettings(); } else if (_id == internal::kTestingDefaultBackground) { diff --git a/Telegram/SourceFiles/window/window_theme.h b/Telegram/SourceFiles/window/window_theme.h index 9171ef5a54..25169e10f3 100644 --- a/Telegram/SourceFiles/window/window_theme.h +++ b/Telegram/SourceFiles/window/window_theme.h @@ -103,7 +103,12 @@ public: void revert(); int32 id() const; - const QPixmap &image() const; + const QPixmap &pixmap() const { + return _pixmap; + } + const QPixmap &pixmapForTiled() const { + return _pixmapForTiled; + } bool tile() const; bool tileForSave() const; @@ -114,7 +119,8 @@ private: void writeNewBackgroundSettings(); int32 _id = internal::kUninitializedBackground; - QPixmap _image; + QPixmap _pixmap; + QPixmap _pixmapForTiled; bool _tile = false; QImage _themeImage; diff --git a/Telegram/SourceFiles/window/window_theme_preview.cpp b/Telegram/SourceFiles/window/window_theme_preview.cpp index c106cc49c4..5c31b39918 100644 --- a/Telegram/SourceFiles/window/window_theme_preview.cpp +++ b/Telegram/SourceFiles/window/window_theme_preview.cpp @@ -413,18 +413,26 @@ void Generator::paintHistoryBackground() { } _p->setClipRect(_history); if (tiled) { - auto left = _history.x(), top = _history.y(), right = _history.x() + _history.width(), bottom = _history.y() + _history.height(); - auto w = background.width() / cRetinaFactor(); - auto h = background.height() / cRetinaFactor(); - auto sx = qFloor(left / w); - auto sy = qFloor((top - fromy) / h); - auto cx = qCeil(right / w); - auto cy = qCeil((bottom - fromy) / h); - for (auto i = sx; i != cx; ++i) { - for (auto j = sy; j != cy; ++j) { - _p->drawImage(QPointF(_history.x() + i * w, _history.y() + fromy + j * h), background); + auto width = background.width(); + auto height = background.height(); + auto repeatTimesX = qCeil(_history.width() * cIntRetinaFactor() / float64(width)); + auto repeatTimesY = qCeil((_history.height() - fromy) * cIntRetinaFactor() / float64(height)); + auto imageForTiled = QImage(width * repeatTimesX, height * repeatTimesY, QImage::Format_ARGB32_Premultiplied); + imageForTiled.setDevicePixelRatio(background.devicePixelRatio()); + auto imageForTiledBytes = imageForTiled.bits(); + auto bytesInLine = width * sizeof(uint32); + for (auto timesY = 0; timesY != repeatTimesY; ++timesY) { + auto imageBytes = background.constBits(); + for (auto y = 0; y != height; ++y) { + for (auto timesX = 0; timesX != repeatTimesX; ++timesX) { + memcpy(imageForTiledBytes, imageBytes, bytesInLine); + imageForTiledBytes += bytesInLine; + } + imageBytes += background.bytesPerLine(); + imageForTiledBytes += imageForTiled.bytesPerLine() - (repeatTimesX * bytesInLine); } } + _p->drawImage(_history.x(), _history.y() + fromy, imageForTiled); } else { PainterHighQualityEnabler hq(*_p); diff --git a/Telegram/build/version b/Telegram/build/version index 8c9c04ee47..e70af82442 100644 --- a/Telegram/build/version +++ b/Telegram/build/version @@ -1,6 +1,6 @@ -AppVersion 10022 +AppVersion 10023 AppVersionStrMajor 0.10 -AppVersionStrSmall 0.10.22 -AppVersionStr 0.10.22 +AppVersionStrSmall 0.10.23 +AppVersionStr 0.10.23 AlphaChannel 1 BetaVersion 0