From a510bb54ec0eefd90c171f13c61d0a892212793b Mon Sep 17 00:00:00 2001 From: John Preston Date: Wed, 25 May 2016 15:09:05 +0300 Subject: [PATCH] Peer observers get notified about name/username changes. All peer observer notifications are async (delayed). --- Telegram/SourceFiles/apiwrap.cpp | 15 +-- Telegram/SourceFiles/app.cpp | 100 ++++++------------ Telegram/SourceFiles/app.h | 13 ++- Telegram/SourceFiles/application.cpp | 4 + Telegram/SourceFiles/boxes/addcontactbox.cpp | 10 +- Telegram/SourceFiles/core/observer.cpp | 42 ++++++-- Telegram/SourceFiles/core/observer.h | 35 ++++-- Telegram/SourceFiles/history.cpp | 7 +- Telegram/SourceFiles/localstorage.cpp | 10 +- Telegram/SourceFiles/mainwidget.cpp | 85 +++++++-------- Telegram/SourceFiles/mainwidget.h | 1 - Telegram/SourceFiles/observer_peer.cpp | 99 +++++++++++------ Telegram/SourceFiles/observer_peer.h | 26 +++-- .../SourceFiles/profile/profile_cover.cpp | 94 +++++++++------- Telegram/SourceFiles/profile/profile_cover.h | 9 +- Telegram/SourceFiles/settingswidget.cpp | 19 ++-- Telegram/SourceFiles/settingswidget.h | 11 +- Telegram/SourceFiles/structs.cpp | 81 ++++++++------ Telegram/SourceFiles/structs.h | 69 ++++++------ 19 files changed, 413 insertions(+), 317 deletions(-) diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index d49c68cc4..e555ccf91 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "apiwrap.h" +#include "observer_peer.h" #include "lang.h" #include "application.h" #include "mainwindow.h" @@ -178,8 +179,8 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt badVersion = (!vc.isEmpty() && vc.at(0).type() == mtpc_channel && vc.at(0).c_channel().vversion.v < peer->asChannel()->version); } - App::feedUsers(d.vusers, false); - App::feedChats(d.vchats, false); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); if (peer->isChat()) { if (d.vfull_chat.type() != mtpc_chatFull) { @@ -317,16 +318,17 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt } App::clearPeerUpdated(peer); emit fullPeerUpdated(peer); - App::emitPeerUpdated(); + + Notify::peerUpdatedSendDelayed(); } void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestId req) { const auto &d(result.c_userFull()); - App::feedUsers(MTP_vector(1, d.vuser), false); + App::feedUsersDelayed(MTP_vector(1, d.vuser)); if (d.has_profile_photo()) { App::feedPhoto(d.vprofile_photo); } - App::feedUserLink(MTP_int(peerToUser(peer->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link, false); + App::feedUserLinkDelayed(MTP_int(peerToUser(peer->id)), d.vlink.c_contacts_link().vmy_link, d.vlink.c_contacts_link().vforeign_link); if (App::main()) { App::main()->gotNotifySetting(MTP_inputNotifyPeer(peer->input), d.vnotify_settings); } @@ -347,7 +349,8 @@ void ApiWrap::gotUserFull(PeerData *peer, const MTPUserFull &result, mtpRequestI } App::clearPeerUpdated(peer); emit fullPeerUpdated(peer); - App::emitPeerUpdated(); + + Notify::peerUpdatedSendDelayed(); } bool ApiWrap::gotPeerFullFailed(PeerData *peer, const RPCError &error) { diff --git a/Telegram/SourceFiles/app.cpp b/Telegram/SourceFiles/app.cpp index a43eced3e..bdb4ad3dd 100644 --- a/Telegram/SourceFiles/app.cpp +++ b/Telegram/SourceFiles/app.cpp @@ -365,7 +365,7 @@ namespace { return (online > now); } - UserData *feedUsers(const MTPVector &users, bool emitPeerUpdated) { + UserData *feedUsersDelayed(const MTPVector &users) { UserData *result = nullptr; for_const (auto &user, users.c_vector().v) { UserData *data = nullptr; @@ -385,7 +385,7 @@ namespace { data->input = MTP_inputPeerUser(d.vid, MTP_long(0)); data->inputUser = MTP_inputUser(d.vid, MTP_long(0)); - data->setName(lang(lng_deleted), QString(), QString(), QString()); + data->setNameDelayed(lang(lng_deleted), QString(), QString(), QString()); data->setPhoto(MTP_userProfilePhotoEmpty()); data->access = UserNoAccess; data->flags = 0; @@ -426,7 +426,7 @@ namespace { } if (d.is_deleted()) { data->setPhone(QString()); - data->setName(lang(lng_deleted), QString(), QString(), QString()); + data->setNameDelayed(lang(lng_deleted), QString(), QString(), QString()); data->setPhoto(MTP_userProfilePhotoEmpty()); data->access = UserNoAccess; status = &emptyStatus; @@ -459,7 +459,7 @@ namespace { if (!minimal && d.is_self() && uname != data->username) { SignalHandlers::setCrashAnnotation("Username", uname); } - data->setName(fname, lname, pname, uname); + data->setNameDelayed(fname, lname, pname, uname); if (d.has_photo()) { data->setPhoto(d.vphoto); } else { @@ -525,18 +525,10 @@ namespace { Notify::userIsContactChanged(data); } - if (emitPeerUpdated) { - App::main()->peerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdated(update); - } - } else { - markPeerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); - } + markPeerUpdated(data); + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); } } result = data; @@ -545,7 +537,7 @@ namespace { return result; } - PeerData *feedChats(const MTPVector &chats, bool emitPeerUpdated) { + PeerData *feedChatsDelayed(const MTPVector &chats) { PeerData *result = nullptr; for_const (auto &chat, chats.c_vector().v) { PeerData *data = nullptr; @@ -561,9 +553,8 @@ namespace { data = App::chat(peerFromChat(d.vid.v)); data->input = MTP_inputPeerChat(d.vid); - data->updateName(qs(d.vtitle), QString(), QString()); - ChatData *cdata = data->asChat(); + cdata->setNameDelayed(qs(d.vtitle)); cdata->setPhoto(d.vphoto); cdata->date = d.vdate.v; @@ -620,9 +611,8 @@ namespace { data = App::chat(peerFromChat(d.vid.v)); data->input = MTP_inputPeerChat(d.vid); - data->updateName(qs(d.vtitle), QString(), QString()); - ChatData *cdata = data->asChat(); + cdata->setNameDelayed(qs(d.vtitle)); cdata->setPhoto(MTP_chatPhotoEmpty()); cdata->date = 0; cdata->count = -1; @@ -666,7 +656,7 @@ namespace { } } QString uname = d.has_username() ? textOneLine(qs(d.vusername)) : QString(); - cdata->setName(qs(d.vtitle), uname); + cdata->setNameDelayed(qs(d.vtitle), uname); cdata->isForbidden = false; cdata->flagsUpdated(); @@ -688,7 +678,7 @@ namespace { cdata->inputChannel = MTP_inputChannel(d.vid, d.vaccess_hash); - cdata->setName(qs(d.vtitle), QString()); + cdata->setNameDelayed(qs(d.vtitle), QString()); cdata->access = d.vaccess_hash.v; cdata->setPhoto(MTP_chatPhotoEmpty()); @@ -711,18 +701,10 @@ namespace { data->loadedStatus = PeerData::FullLoaded; } if (App::main()) { - if (emitPeerUpdated) { - App::main()->peerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdated(update); - } - } else { - markPeerUpdated(data); - if (update.flags) { - update.peer = data; - Notify::peerUpdatedDelayed(update); - } + markPeerUpdated(data); + if (update.flags) { + update.peer = data; + Notify::peerUpdatedDelayed(update); } } result = data; @@ -730,6 +712,18 @@ namespace { return result; } + UserData *feedUsers(const MTPVector &users) { + auto result = feedUsersDelayed(users); + Notify::peerUpdatedSendDelayed(); + return result; + } + + PeerData *feedChats(const MTPVector &chats) { + auto result = feedChatsDelayed(chats); + Notify::peerUpdatedSendDelayed(); + return result; + } + void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos, bool emitPeerUpdated) { ChatData *chat = 0; switch (p.type()) { @@ -1206,30 +1200,7 @@ namespace { } } - void feedUserLinks(const MTPVector &links, bool emitPeerUpdated) { - const auto &v(links.c_vector().v); - for (QVector::const_iterator i = v.cbegin(), e = v.cend(); i != e; ++i) { - const auto &dv(i->c_contacts_link()); - UserData *user = feedUsers(MTP_vector(1, dv.vuser), false); - MTPint userId(MTP_int(0)); - switch (dv.vuser.type()) { - case mtpc_userEmpty: userId = dv.vuser.c_userEmpty().vid; break; - case mtpc_user: userId = dv.vuser.c_user().vid; break; - } - if (userId.v) { - feedUserLink(userId, dv.vmy_link, dv.vforeign_link, false); - } - if (user && App::main()) { - if (emitPeerUpdated) { - App::main()->peerUpdated(user); - } else { - markPeerUpdated(user); - } - } - } - } - - void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink, bool emitPeerUpdated) { + void feedUserLinkDelayed(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink) { UserData *user = userLoaded(userId.v); if (user) { bool wasContact = (user->contact > 0); @@ -1262,15 +1233,9 @@ namespace { bool showPhone = !isServiceUser(user->id) && !user->isSelf() && !user->contact; bool showPhoneChanged = !isServiceUser(user->id) && !user->isSelf() && ((showPhone && !wasShowPhone) || (!showPhone && wasShowPhone)); if (showPhoneChanged) { - user->setName(textOneLine(user->firstName), textOneLine(user->lastName), showPhone ? App::formatPhone(user->phone) : QString(), textOneLine(user->username)); - } - if (App::main()) { - if (emitPeerUpdated) { - App::main()->peerUpdated(user); - } else { - markPeerUpdated(user); - } + user->setNameDelayed(textOneLine(user->firstName), textOneLine(user->lastName), showPhone ? App::formatPhone(user->phone) : QString(), textOneLine(user->username)); } + markPeerUpdated(user); } } @@ -1291,7 +1256,6 @@ namespace { App::main()->peerUpdated(i.key()); } } - Notify::peerUpdatedSendDelayed(); } PhotoData *feedPhoto(const MTPPhoto &photo, PhotoData *convert) { diff --git a/Telegram/SourceFiles/app.h b/Telegram/SourceFiles/app.h index 4e437b71b..4c58c332e 100644 --- a/Telegram/SourceFiles/app.h +++ b/Telegram/SourceFiles/app.h @@ -64,8 +64,13 @@ namespace App { QString onlineText(UserData *user, int32 nowOnServer, bool precise = false); bool onlineColorUse(UserData *user, int32 now); - UserData *feedUsers(const MTPVector &users, bool emitPeerUpdated = true); // returns last user - PeerData *feedChats(const MTPVector &chats, bool emitPeerUpdated = true); // returns last chat + UserData *feedUsers(const MTPVector &users); // returns last user + PeerData *feedChats(const MTPVector &chats); // returns last chat + + // Requires Notify::peerUpdatedSendDelayed() call after. + UserData *feedUsersDelayed(const MTPVector &users); // returns last user + PeerData *feedChatsDelayed(const MTPVector &chats); // returns last chat + void feedParticipants(const MTPChatParticipants &p, bool requestBotInfos, bool emitPeerUpdated = true); void feedParticipantAdd(const MTPDupdateChatParticipantAdd &d, bool emitPeerUpdated = true); void feedParticipantDelete(const MTPDupdateChatParticipantDelete &d, bool emitPeerUpdated = true); @@ -80,12 +85,10 @@ namespace App { void feedInboxRead(const PeerId &peer, MsgId upTo); void feedOutboxRead(const PeerId &peer, MsgId upTo); void feedWereDeleted(ChannelId channelId, const QVector &msgsIds); - void feedUserLinks(const MTPVector &links, bool emitPeerUpdated = true); - void feedUserLink(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink, bool emitPeerUpdated = true); + void feedUserLinkDelayed(MTPint userId, const MTPContactLink &myLink, const MTPContactLink &foreignLink); void markPeerUpdated(PeerData *data); void clearPeerUpdated(PeerData *data); - void emitPeerUpdated(); ImagePtr image(const MTPPhotoSize &size); StorageImageLocation imageLocation(int32 w, int32 h, const MTPFileLocation &loc); diff --git a/Telegram/SourceFiles/application.cpp b/Telegram/SourceFiles/application.cpp index 7e9850c5b..b73ecca3a 100644 --- a/Telegram/SourceFiles/application.cpp +++ b/Telegram/SourceFiles/application.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "langloaderplain.h" #include "localstorage.h" #include "autoupdater.h" +#include "core/observer.h" namespace { void mtpStateChanged(int32 dc, int32 state) { @@ -200,6 +201,7 @@ void Application::singleInstanceChecked() { Logs::multipleInstances(); } + Notify::startObservers(); Sandbox::start(); if (!Logs::started() || (!cManyInstance() && !Logs::instanceChecked())) { @@ -336,6 +338,8 @@ void Application::closeApplication() { if (_updateThread) _updateThread->quit(); _updateThread = 0; #endif + + Notify::finishObservers(); } #ifndef TDESKTOP_DISABLE_AUTOUPDATE diff --git a/Telegram/SourceFiles/boxes/addcontactbox.cpp b/Telegram/SourceFiles/boxes/addcontactbox.cpp index 2d37dff66..f1bea515d 100644 --- a/Telegram/SourceFiles/boxes/addcontactbox.cpp +++ b/Telegram/SourceFiles/boxes/addcontactbox.cpp @@ -30,6 +30,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "mainwidget.h" #include "mainwindow.h" #include "apiwrap.h" +#include "observer_peer.h" AddContactBox::AddContactBox(QString fname, QString lname, QString phone) : AbstractBox(st::boxWidth) , _user(0) @@ -206,7 +207,7 @@ bool AddContactBox::onSaveUserFail(const RPCError &error) { QString err(error.type()); QString firstName = _first.getLastText().trimmed(), lastName = _last.getLastText().trimmed(); if (err == "CHAT_TITLE_NOT_MODIFIED") { - _user->updateName(firstName, QString(), QString()); + _user->setName(firstName, lastName, _user->nameOrPhone, _user->username); emit closed(); return true; } else if (err == "NO_CHAT_TITLE") { @@ -222,8 +223,7 @@ void AddContactBox::onImportDone(const MTPcontacts_ImportedContacts &res) { if (isHidden() || !App::main()) return; const auto &d(res.c_contacts_importedContacts()); - App::feedUsers(d.vusers, false); - App::emitPeerUpdated(); + App::feedUsers(d.vusers); const auto &v(d.vimported.c_vector().v); UserData *user = nullptr; @@ -1157,7 +1157,9 @@ bool EditNameTitleBox::onSaveChatFail(const RPCError &error) { _requestId = 0; QString err(error.type()); if (err == qstr("CHAT_TITLE_NOT_MODIFIED") || err == qstr("CHAT_NOT_MODIFIED")) { - _peer->updateName(_sentName, QString(), QString()); + if (auto chatData = _peer->asChat()) { + chatData->setName(_sentName); + } emit closed(); return true; } else if (err == qstr("NO_CHAT_TITLE")) { diff --git a/Telegram/SourceFiles/core/observer.cpp b/Telegram/SourceFiles/core/observer.cpp index 5a8f2d389..607b28911 100644 --- a/Telegram/SourceFiles/core/observer.cpp +++ b/Telegram/SourceFiles/core/observer.cpp @@ -24,10 +24,45 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Notify { namespace { -UnregisterObserverCallback UnregisterCallbacks[256]; +using StartCallbacksList = QVector; +using FinishCallbacksList = QVector; +NeverFreedPointer StartCallbacks; +NeverFreedPointer FinishCallbacks; +UnregisterObserverCallback UnregisterCallbacks[256]/* = { nullptr }*/; } // namespace +void startObservers() { + if (!StartCallbacks) return; + + for (auto &callback : *StartCallbacks) { + callback(); + } +} + +void finishObservers() { + if (!FinishCallbacks) return; + + for (auto &callback : *FinishCallbacks) { + callback(); + } + StartCallbacks.clear(); + FinishCallbacks.clear(); +} + +ObservedEventRegistrator::ObservedEventRegistrator(ObservedEvent event +, StartObservedEventCallback startCallback +, FinishObservedEventCallback finishCallback +, UnregisterObserverCallback unregisterCallback) { + StartCallbacks.makeIfNull(); + StartCallbacks->push_back(startCallback); + + FinishCallbacks.makeIfNull(); + FinishCallbacks->push_back(finishCallback); + + UnregisterCallbacks[event] = unregisterCallback; +} + // Observer base interface. Observer::~Observer() { for_const (auto connection, _connections) { @@ -47,10 +82,6 @@ void unregisterObserver(ConnectionId connection) { } } -UnregisterObserverCallbackCreator::UnregisterObserverCallbackCreator(ObservedEvent event, UnregisterObserverCallback callback) { - UnregisterCallbacks[event] = callback; -} - namespace internal { void observerRegisteredDefault(Observer *observer, ConnectionId connection) { @@ -58,5 +89,4 @@ void observerRegisteredDefault(Observer *observer, ConnectionId connection) { } } // namespace internal - } // namespace Notify diff --git a/Telegram/SourceFiles/core/observer.h b/Telegram/SourceFiles/core/observer.h index 2f992cb0b..8ed722dbc 100644 --- a/Telegram/SourceFiles/core/observer.h +++ b/Telegram/SourceFiles/core/observer.h @@ -24,13 +24,36 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org namespace Notify { -class Observer; +using ObservedEvent = uchar; using ConnectionId = uint32; +// startObservers() must be called after main() started (not in a global variable constructor). +// finishObservers() must be called before main() finished (not in a global variable destructor). +void startObservers(); +void finishObservers(); + +using StartObservedEventCallback = void(*)(); +using UnregisterObserverCallback = void(*)(int connectionIndex); +using FinishObservedEventCallback = void(*)(); + +// Objects of this class should be constructed in global scope. +// startCallback will be called from Notify::startObservers(). +// finishCallback will be called from Notify::finishObservers(). +// unregisterCallback will be used to destroy connections. +class ObservedEventRegistrator { +public: + ObservedEventRegistrator(ObservedEvent event + , StartObservedEventCallback startCallback + , FinishObservedEventCallback finishCallback + , UnregisterObserverCallback unregisterCallback); + +}; + // Each observer type should have observerRegistered(Notify::ConnectionId connection) method. // Usually it is done by deriving the type from the Notify::Observer base class. // In destructor it should call Notify::unregisterObserver(connection) for all the connections. +class Observer; namespace internal { void observerRegisteredDefault(Observer *observer, ConnectionId connection); } // namespace internal @@ -49,21 +72,11 @@ private: }; -using ObservedEvent = uchar; inline ConnectionId observerConnectionId(ObservedEvent event, int connectionIndex) { t_assert(connectionIndex >= 0 && connectionIndex < 0x01000000); return (static_cast(event) << 24) | (connectionIndex + 1); } -using UnregisterObserverCallback = void(*)(int connectionIndex); - -// Usage: UnregisterObserverCallbackCreator creator(myEvent, myCallback); in global scope. -class UnregisterObserverCallbackCreator { -public: - UnregisterObserverCallbackCreator(ObservedEvent event, UnregisterObserverCallback callback); - -}; - // Handler is one of Function<> instantiations. template struct ObserversList { diff --git a/Telegram/SourceFiles/history.cpp b/Telegram/SourceFiles/history.cpp index 56ffe95f7..16917c74f 100644 --- a/Telegram/SourceFiles/history.cpp +++ b/Telegram/SourceFiles/history.cpp @@ -1153,9 +1153,10 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, } break; case mtpc_messageActionChatEditTitle: { - const auto &d(action.c_messageActionChatEditTitle()); - ChatData *chat = peer->asChat(); - if (chat) chat->updateName(qs(d.vtitle), QString(), QString()); + auto &d(action.c_messageActionChatEditTitle()); + if (auto chat = peer->asChat()) { + chat->setName(qs(d.vtitle)); + } } break; case mtpc_messageActionChatMigrateTo: { diff --git a/Telegram/SourceFiles/localstorage.cpp b/Telegram/SourceFiles/localstorage.cpp index 8df89e4c0..a94231f4a 100644 --- a/Telegram/SourceFiles/localstorage.cpp +++ b/Telegram/SourceFiles/localstorage.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "serialize/serialize_document.h" #include "serialize/serialize_common.h" +#include "observer_peer.h" #include "mainwidget.h" #include "mainwindow.h" #include "lang.h" @@ -3489,7 +3490,7 @@ namespace Local { QString pname = (showPhone && !phone.isEmpty()) ? App::formatPhone(phone) : QString(); if (!wasLoaded) { - user->setName(first, last, pname, username); + user->setNameDelayed(first, last, pname, username); user->access = access; user->flags = MTPDuser::Flags(flags); @@ -3524,7 +3525,7 @@ namespace Local { flags = (flagsData == 1) ? MTPDchat::Flags(MTPDchat::Flag::f_left) : MTPDchat::Flags(0); } if (!wasLoaded) { - chat->updateName(name, QString(), QString()); + chat->setNameDelayed(name); chat->count = count; chat->date = date; chat->version = version; @@ -3547,7 +3548,7 @@ namespace Local { from.stream >> name >> access >> date >> version >> forbidden >> flags >> invitationUrl; if (!wasLoaded) { - channel->updateName(name, QString(), QString()); + channel->setNameDelayed(name, QString()); channel->access = access; channel->date = date; channel->version = version; @@ -3743,7 +3744,8 @@ namespace Local { cRefSavedPeersByTime().insert(t, peer); peers.push_back(peer); } - App::emitPeerUpdated(); + + Notify::peerUpdatedSendDelayed(); if (App::api()) App::api()->requestPeers(peers); } diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 8c7b3becb..3a60bfb44 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "window/section_memento.h" #include "window/section_widget.h" #include "window/top_bar_widget.h" +#include "observer_peer.h" #include "apiwrap.h" #include "dialogswidget.h" #include "historywidget.h" @@ -696,12 +697,12 @@ void MainWidget::deleteHistoryPart(PeerData *peer, const MTPmessages_AffectedHis if (peer && peer->isChannel()) { if (peer->asChannel()->ptsUpdated(d.vpts.v, d.vpts_count.v)) { peer->asChannel()->ptsApplySkippedUpdates(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } } else { if (ptsUpdated(d.vpts.v, d.vpts_count.v)) { ptsApplySkippedUpdates(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } } @@ -725,10 +726,10 @@ void MainWidget::deleteMessages(PeerData *peer, const QVector &ids) { } void MainWidget::deletedContact(UserData *user, const MTPcontacts_Link &result) { - const auto &d(result.c_contacts_link()); - App::feedUsers(MTP_vector(1, d.vuser), false); - App::feedUserLink(MTP_int(peerToUser(user->id)), d.vmy_link, d.vforeign_link, false); - App::emitPeerUpdated(); + auto &d(result.c_contacts_link()); + App::feedUsersDelayed(MTP_vector(1, d.vuser)); + App::feedUserLinkDelayed(MTP_int(peerToUser(user->id)), d.vmy_link, d.vforeign_link); + Notify::peerUpdatedSendDelayed(); } void MainWidget::removeDialog(History *history) { @@ -790,7 +791,7 @@ void MainWidget::deleteAllFromUserPart(DeleteAllFromUserParams params, const MTP const auto &d(result.c_messages_affectedHistory()); if (params.channel->ptsUpdated(d.vpts.v, d.vpts_count.v)) { params.channel->ptsApplySkippedUpdates(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } int32 offset = d.voffset.v; @@ -1381,15 +1382,6 @@ void MainWidget::loadMediaBack(PeerData *peer, MediaOverviewType type, bool many _overviewLoad[type].insert(peer, MTP::send(MTPmessages_Search(MTP_flags(flags), peer->input, MTPstring(), filter, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(minId), MTP_int(limit)), rpcDone(&MainWidget::overviewLoaded, history))); } -void MainWidget::peerUsernameChanged(PeerData *peer) { - //if (_profile && _profile->peer() == peer) { TODO - // _profile->peerUsernameChanged(); - //} - if (App::settings() && peer == App::self()) { - App::settings()->usernameChanged(); - } -} - void MainWidget::checkLastUpdate(bool afterSleep) { uint64 n = getms(true); if (_lastUpdateTime && n > _lastUpdateTime + (afterSleep ? NoUpdatesAfterSleepTimeout : NoUpdatesTimeout)) { @@ -1463,12 +1455,12 @@ void MainWidget::messagesAffected(PeerData *peer, const MTPmessages_AffectedMess if (peer && peer->isChannel()) { if (peer->asChannel()->ptsUpdated(d.vpts.v, d.vpts_count.v)) { peer->asChannel()->ptsApplySkippedUpdates(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } } else { if (ptsUpdated(d.vpts.v, d.vpts_count.v)) { ptsApplySkippedUpdates(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } } if (History *h = App::historyLoaded(peer ? peer->id : 0)) { @@ -2426,7 +2418,7 @@ void MainWidget::windowShown() { void MainWidget::sentUpdatesReceived(uint64 randomId, const MTPUpdates &result) { feedUpdates(result, randomId); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } bool MainWidget::deleteChannelFailed(const RPCError &error) { @@ -2874,8 +2866,8 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha case mtpc_updates_channelDifference: { const auto &d(diff.c_updates_channelDifference()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats, false); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); _handlingChannelDifference = true; feedMessageIds(d.vother_updates); @@ -2945,7 +2937,7 @@ void MainWidget::gotChannelDifference(ChannelData *channel, const MTPupdates_Cha channel->ptsWaitingForShortPoll(timeout ? (timeout * 1000) : WaitForChannelGetDifference); } - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } void MainWidget::gotRangeDifference(ChannelData *channel, const MTPupdates_ChannelDifference &diff) { @@ -2961,8 +2953,8 @@ void MainWidget::gotRangeDifference(ChannelData *channel, const MTPupdates_Chann case mtpc_updates_channelDifferenceTooLong: { const auto &d(diff.c_updates_channelDifferenceTooLong()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); nextRequestPts = d.vpts.v; isFinal = d.is_final(); @@ -2971,8 +2963,8 @@ void MainWidget::gotRangeDifference(ChannelData *channel, const MTPupdates_Chann case mtpc_updates_channelDifference: { const auto &d(diff.c_updates_channelDifference()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats, false); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); _handlingChannelDifference = true; feedMessageIds(d.vother_updates); @@ -2992,7 +2984,7 @@ void MainWidget::gotRangeDifference(ChannelData *channel, const MTPupdates_Chann } } - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } bool MainWidget::failChannelDifference(ChannelData *channel, const RPCError &error) { @@ -3014,7 +3006,7 @@ void MainWidget::gotState(const MTPupdates_State &state) { _dialogs->loadDialogs(); updateOnline(); - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } void MainWidget::gotDifference(const MTPupdates_Difference &diff) { @@ -3029,8 +3021,6 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { noUpdatesTimer.start(NoUpdatesTimeout); _ptsWaiter.setRequesting(false); - - App::emitPeerUpdated(); } break; case mtpc_updates_differenceSlice: { const auto &d(diff.c_updates_differenceSlice()); @@ -3043,8 +3033,6 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { MTP_LOG(0, ("getDifference { good - after a slice of difference was received }%1").arg(cTestMode() ? " TESTMODE" : "")); getDifference(); - - App::emitPeerUpdated(); } break; case mtpc_updates_difference: { const auto &d(diff.c_updates_difference()); @@ -3053,6 +3041,7 @@ void MainWidget::gotDifference(const MTPupdates_Difference &diff) { gotState(d.vstate); } break; }; + Notify::peerUpdatedSendDelayed(); } bool MainWidget::getDifferenceTimeChanged(ChannelData *channel, int32 ms, ChannelGetDifferenceTime &channelCurTime, uint64 &curTime) { @@ -3142,8 +3131,8 @@ void MainWidget::ptsApplySkippedUpdates() { void MainWidget::feedDifference(const MTPVector &users, const MTPVector &chats, const MTPVector &msgs, const MTPVector &other) { App::wnd()->checkAutoLock(); - App::feedUsers(users, false); - App::feedChats(chats, false); + App::feedUsersDelayed(users); + App::feedChatsDelayed(chats); feedMessageIds(other); App::feedMsgs(msgs, NewMessageUnread); feedUpdateVector(other, true); @@ -3875,7 +3864,7 @@ void MainWidget::updateReceived(const mtpPrime *from, const mtpPrime *end) { if (!_ptsWaiter.requesting()) { feedUpdates(updates); } - App::emitPeerUpdated(); + Notify::peerUpdatedSendDelayed(); } catch (mtpErrorUnexpected &) { // just some other type } } @@ -3995,8 +3984,8 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } } - App::feedUsers(d.vusers, false); - App::feedChats(d.vchats, false); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); feedUpdateVector(d.vupdates); updSetState(0, d.vdate.v, updQts, d.vseq.v); @@ -4012,8 +4001,8 @@ void MainWidget::feedUpdates(const MTPUpdates &updates, uint64 randomId) { } } - App::feedUsers(d.vusers, false); - App::feedChats(d.vchats, false); + App::feedUsersDelayed(d.vusers); + App::feedChatsDelayed(d.vchats); feedUpdateVector(d.vupdates); updSetState(0, d.vdate.v, updQts, d.vseq.v); @@ -4338,13 +4327,12 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserName: { - const auto &d(update.c_updateUserName()); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { + auto &d(update.c_updateUserName()); + if (auto user = App::userLoaded(d.vuser_id.v)) { if (user->contact <= 0) { - user->setName(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername))); + user->setNameDelayed(textOneLine(qs(d.vfirst_name)), textOneLine(qs(d.vlast_name)), user->nameOrPhone, textOneLine(qs(d.vusername))); } else { - user->setName(textOneLine(user->firstName), textOneLine(user->lastName), user->nameOrPhone, textOneLine(qs(d.vusername))); + user->setNameDelayed(textOneLine(user->firstName), textOneLine(user->lastName), user->nameOrPhone, textOneLine(qs(d.vusername))); } App::markPeerUpdated(user); } @@ -4385,7 +4373,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateContactLink: { const auto &d(update.c_updateContactLink()); - App::feedUserLink(d.vuser_id, d.vmy_link, d.vforeign_link, false); + App::feedUserLinkDelayed(d.vuser_id, d.vmy_link, d.vforeign_link); } break; case mtpc_updateNotifySettings: { @@ -4399,11 +4387,10 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } break; case mtpc_updateUserPhone: { - const auto &d(update.c_updateUserPhone()); - UserData *user = App::userLoaded(d.vuser_id.v); - if (user) { + auto &d(update.c_updateUserPhone()); + if (auto user = App::userLoaded(d.vuser_id.v)) { user->setPhone(qs(d.vphone)); - user->setName(user->firstName, user->lastName, (user->contact || isServiceUser(user->id) || user->isSelf() || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), user->username); + user->setNameDelayed(user->firstName, user->lastName, (user->contact || isServiceUser(user->id) || user->isSelf() || user->phone.isEmpty()) ? QString() : App::formatPhone(user->phone), user->username); App::markPeerUpdated(user); } } break; diff --git a/Telegram/SourceFiles/mainwidget.h b/Telegram/SourceFiles/mainwidget.h index b395d2949..081bcaa7e 100644 --- a/Telegram/SourceFiles/mainwidget.h +++ b/Telegram/SourceFiles/mainwidget.h @@ -322,7 +322,6 @@ public: void itemEdited(HistoryItem *item); void loadMediaBack(PeerData *peer, MediaOverviewType type, bool many = false); - void peerUsernameChanged(PeerData *peer); void checkLastUpdate(bool afterSleep); void showAddContact(); diff --git a/Telegram/SourceFiles/observer_peer.cpp b/Telegram/SourceFiles/observer_peer.cpp index 9094ce5c2..c77ec90bf 100644 --- a/Telegram/SourceFiles/observer_peer.cpp +++ b/Telegram/SourceFiles/observer_peer.cpp @@ -23,81 +23,112 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "core/observer.h" +namespace App { +// Temp forward declaration (while all peer updates are not done through observers). +void emitPeerUpdated(); +} // namespace App + namespace Notify { namespace internal { namespace { constexpr ObservedEvent PeerUpdateEvent = 0x01; -ObserversList PeerUpdateObservers; +using PeerObserversList = ObserversList; +NeverFreedPointer PeerUpdateObservers; -void UnregisterCallback(int connectionIndex) { - unregisterObserver(PeerUpdateObservers, connectionIndex); +using SmallUpdatesList = QVector; +NeverFreedPointer SmallUpdates; +using AllUpdatesList = QMap; +NeverFreedPointer AllUpdates; + +void StartCallback() { + PeerUpdateObservers.makeIfNull(); + SmallUpdates.makeIfNull(); + AllUpdates.makeIfNull(); } -UnregisterObserverCallbackCreator creator(PeerUpdateEvent, UnregisterCallback); +void FinishCallback() { + PeerUpdateObservers.clear(); + SmallUpdates.clear(); + AllUpdates.clear(); +} +void UnregisterCallback(int connectionIndex) { + t_assert(!PeerUpdateObservers.isNull()); + unregisterObserver(*PeerUpdateObservers, connectionIndex); +} +ObservedEventRegistrator creator(PeerUpdateEvent, StartCallback, FinishCallback, UnregisterCallback); -QVector SmallPeerUpdates; -QMap AllPeerUpdates; +bool Started() { + return !PeerUpdateObservers.isNull(); +} } // namespace ConnectionId plainRegisterPeerObserver(PeerUpdateFlags events, PeerUpdateHandler &&handler) { - auto connectionId = registerObserver(PeerUpdateObservers, events, std_::forward(handler)); + t_assert(Started()); + auto connectionId = registerObserver(*PeerUpdateObservers, events, std_::forward(handler)); t_assert(connectionId >= 0 && connectionId < 0x01000000); return (static_cast(PeerUpdateEvent) << 24) | static_cast(connectionId + 1); } void mergePeerUpdate(PeerUpdate &mergeTo, const PeerUpdate &mergeFrom) { + if (!(mergeTo.flags & PeerUpdateFlag::NameChanged)) { + if (mergeFrom.flags & PeerUpdateFlag::NameChanged) { + mergeTo.oldNames = mergeFrom.oldNames; + mergeTo.oldNameFirstChars = mergeFrom.oldNameFirstChars; + } + } mergeTo.flags |= mergeFrom.flags; - - // merge fields used in mergeFrom.flags } } // namespace internal -void peerUpdated(const PeerUpdate &update) { - notifyObservers(internal::PeerUpdateObservers, update.flags, update); -} - void peerUpdatedDelayed(const PeerUpdate &update) { - int alreadySavedCount = internal::SmallPeerUpdates.size(); - for (int i = 0; i < alreadySavedCount; ++i) { - if (internal::SmallPeerUpdates.at(i).peer == update.peer) { - internal::mergePeerUpdate(internal::SmallPeerUpdates[i], update); + t_assert(internal::Started()); + + int existingUpdatesCount = internal::SmallUpdates->size(); + for (int i = 0; i < existingUpdatesCount; ++i) { + auto &existingUpdate = (*internal::SmallUpdates)[i]; + if (existingUpdate.peer == update.peer) { + internal::mergePeerUpdate(existingUpdate, update); return; } } - if (internal::AllPeerUpdates.isEmpty()) { - if (alreadySavedCount < 5) { - internal::SmallPeerUpdates.push_back(update); + if (internal::AllUpdates->isEmpty()) { + if (existingUpdatesCount < 5) { + internal::SmallUpdates->push_back(update); } else { - internal::AllPeerUpdates.insert(update.peer, update); + internal::AllUpdates->insert(update.peer, update); } } else { - auto it = internal::AllPeerUpdates.find(update.peer); - if (it != internal::AllPeerUpdates.cend()) { + auto it = internal::AllUpdates->find(update.peer); + if (it != internal::AllUpdates->cend()) { internal::mergePeerUpdate(it.value(), update); return; } - internal::AllPeerUpdates.insert(update.peer, update); + internal::AllUpdates->insert(update.peer, update); } } void peerUpdatedSendDelayed() { - if (internal::SmallPeerUpdates.isEmpty()) return; + App::emitPeerUpdated(); - decltype(internal::SmallPeerUpdates) smallList; - decltype(internal::AllPeerUpdates) allList; - std::swap(smallList, internal::SmallPeerUpdates); - std::swap(allList, internal::AllPeerUpdates); + t_assert(internal::Started()); + + if (internal::SmallUpdates->isEmpty()) return; + + internal::SmallUpdatesList smallList; + internal::AllUpdatesList allList; + std::swap(smallList, *internal::SmallUpdates); + std::swap(allList, *internal::AllUpdates); for_const (auto &update, smallList) { - peerUpdated(update); + notifyObservers(*internal::PeerUpdateObservers, update.flags, update); } for_const (auto &update, allList) { - peerUpdated(update); + notifyObservers(*internal::PeerUpdateObservers, update.flags, update); } - if (internal::SmallPeerUpdates.isEmpty()) { - std::swap(smallList, internal::SmallPeerUpdates); - internal::SmallPeerUpdates.resize(0); + if (internal::SmallUpdates->isEmpty()) { + std::swap(smallList, *internal::SmallUpdates); + internal::SmallUpdates->resize(0); } } diff --git a/Telegram/SourceFiles/observer_peer.h b/Telegram/SourceFiles/observer_peer.h index 76a7514b9..a490f0b11 100644 --- a/Telegram/SourceFiles/observer_peer.h +++ b/Telegram/SourceFiles/observer_peer.h @@ -26,27 +26,35 @@ namespace Notify { // Generic notifications about updates of some PeerData. // You can subscribe to them by Notify::registerPeerObserver(). +// 0x0000FFFFU for general peer updates (valid for any peer). +// 0xFFFF0000U for specific peer updates (valid for user / chat / channel). enum class PeerUpdateFlag { - //PeerNameChanged = 0x0001, + NameChanged = 0x00000001U, + UsernameChanged = 0x00000002U, - UserCanShareContact = 0x1001, + UserCanShareContact = 0x00010000U, - ChatCanEdit = 0x2001, + ChatCanEdit = 0x00010000U, - MegagroupCanEditPhoto = 0x4001, - MegagroupCanAddMembers = 0x4002, - - ChannelAmIn = 0x8001, + ChannelAmIn = 0x00010000U, + MegagroupCanEditPhoto = 0x00020000U, + MegagroupCanAddMembers = 0x00040000U, }; Q_DECLARE_FLAGS(PeerUpdateFlags, PeerUpdateFlag); Q_DECLARE_OPERATORS_FOR_FLAGS(PeerUpdateFlags); + struct PeerUpdate { - PeerData *peer = nullptr; + PeerUpdate(PeerData *updated = nullptr) : peer(updated) { + } + PeerData *peer; PeerUpdateFlags flags = 0; + + // NameChanged data + PeerData::Names oldNames; + PeerData::NameFirstChars oldNameFirstChars; }; -void peerUpdated(const PeerUpdate &update); void peerUpdatedDelayed(const PeerUpdate &update); void peerUpdatedSendDelayed(); diff --git a/Telegram/SourceFiles/profile/profile_cover.cpp b/Telegram/SourceFiles/profile/profile_cover.cpp index 24de8384a..46620a7e5 100644 --- a/Telegram/SourceFiles/profile/profile_cover.cpp +++ b/Telegram/SourceFiles/profile/profile_cover.cpp @@ -24,6 +24,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "styles/style_profile.h" #include "ui/buttons/round_button.h" #include "observer_peer.h" +#include "boxes/contactsbox.h" #include "lang.h" #include "apiwrap.h" #include "mainwidget.h" @@ -98,17 +99,16 @@ CoverWidget::CoverWidget(QWidget *parent, PeerData *peer) : TWidget(parent) , _photoButton(this, peer) { setAttribute(Qt::WA_OpaquePaintEvent); - using Flag = Notify::PeerUpdateFlag; - auto observeEvents = ButtonsUpdateFlags; + auto observeEvents = ButtonsUpdateFlags | Notify::PeerUpdateFlag::NameChanged; Notify::registerPeerObserver(observeEvents, this, &CoverWidget::notifyPeerUpdated); _photoButton->photoUpdated(); connect(_photoButton, SIGNAL(clicked()), this, SLOT(onPhotoShow())); - _nameText.setText(st::profileNameFont, App::peerName(_peer)); - updateStatusText(); + refreshNameText(); + refreshStatusText(); - updateButtons(); + refreshButtons(); } void CoverWidget::onPhotoShow() { @@ -121,31 +121,6 @@ void CoverWidget::onPhotoShow() { } } -void CoverWidget::onSendMessage() { - -} - -void CoverWidget::onShareContact() { - -} - -void CoverWidget::onSetPhoto() { - -} - -void CoverWidget::onAddMember() { - -} - -void CoverWidget::onJoin() { - -} - -void CoverWidget::onViewChannel() { - -} - - void CoverWidget::resizeToWidth(int newWidth) { int newHeight = 0; @@ -202,7 +177,23 @@ void CoverWidget::paintDivider(Painter &p) { st::profileDividerFill.fill(p, toFill); } -void CoverWidget::updateStatusText() { +void CoverWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { + if (update.peer == _peer) { + if ((update.flags & ButtonsUpdateFlags) != 0) { + refreshButtons(); + } + if (update.flags & Notify::PeerUpdateFlag::NameChanged) { + refreshNameText(); + } + } +} + +void CoverWidget::refreshNameText() { + _nameText.setText(st::profileNameFont, App::peerName(_peer)); + update(); +} + +void CoverWidget::refreshStatusText() { int currentTime = unixtime(); if (_peerUser) { _statusText = App::onlineText(_peerUser, currentTime, true); @@ -235,6 +226,7 @@ void CoverWidget::updateStatusText() { } else { _statusText = lang(lng_chat_status_unaccessible); } + update(); } bool CoverWidget::isUsingMegagroupOnlineCount() const { @@ -254,13 +246,7 @@ bool CoverWidget::isUsingMegagroupOnlineCount() const { return true; } -void CoverWidget::notifyPeerUpdated(const Notify::PeerUpdate &update) { - if (update.flags & ButtonsUpdateFlags) { - updateButtons(); - } -} - -void CoverWidget::updateButtons() { +void CoverWidget::refreshButtons() { if (_peerUser) { setUserButtons(); } else if (_peerChat) { @@ -336,4 +322,36 @@ void CoverWidget::setSecondaryButton(const QString &text, const char *slot) { } } +void CoverWidget::onSendMessage() { + Ui::showPeerHistory(_peer, ShowAtUnreadMsgId); +} + +void CoverWidget::onShareContact() { + App::main()->shareContactLayer(_peerUser); +} + +void CoverWidget::onSetPhoto() { + +} + +void CoverWidget::onAddMember() { + if (_peerChat) { + Ui::showLayer(new ContactsBox(_peerChat, MembersFilterRecent)); + } else if (_peerChannel && _peerChannel->mgInfo) { + MembersAlreadyIn already; + for (MegagroupInfo::LastParticipants::const_iterator i = _peerChannel->mgInfo->lastParticipants.cbegin(), e = _peerChannel->mgInfo->lastParticipants.cend(); i != e; ++i) { + already.insert(*i, true); + } + Ui::showLayer(new ContactsBox(_peerChannel, MembersFilterRecent, already)); + } +} + +void CoverWidget::onJoin() { + +} + +void CoverWidget::onViewChannel() { + Ui::showPeerHistory(_peer, ShowAtUnreadMsgId); +} + } // namespace Profile diff --git a/Telegram/SourceFiles/profile/profile_cover.h b/Telegram/SourceFiles/profile/profile_cover.h index ae84f15e1..96b7d668f 100644 --- a/Telegram/SourceFiles/profile/profile_cover.h +++ b/Telegram/SourceFiles/profile/profile_cover.h @@ -58,13 +58,14 @@ protected: void paintEvent(QPaintEvent *e) override; private: - void updateStatusText(); - bool isUsingMegagroupOnlineCount() const; - // Observed notifications. void notifyPeerUpdated(const Notify::PeerUpdate &update); - void updateButtons(); + void refreshNameText(); + void refreshStatusText(); + bool isUsingMegagroupOnlineCount() const; + + void refreshButtons(); void setUserButtons(); void setChatButtons(); void setMegagroupButtons(); diff --git a/Telegram/SourceFiles/settingswidget.cpp b/Telegram/SourceFiles/settingswidget.cpp index c7aaeec12..c08a12ab6 100644 --- a/Telegram/SourceFiles/settingswidget.cpp +++ b/Telegram/SourceFiles/settingswidget.cpp @@ -21,6 +21,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "stdafx.h" #include "settingswidget.h" +#include "observer_peer.h" #include "lang.h" #include "boxes/aboutbox.h" #include "mainwidget.h" @@ -205,6 +206,8 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent) , _telegramFAQ(this, lang(lng_settings_faq)) , _logOut(this, lang(lng_settings_logout), st::btnRedLink) , _supportGetRequest(0) { + Notify::registerPeerObserver(Notify::PeerUpdateFlag::UsernameChanged, this, &SettingsInner::notifyPeerUpdated); + if (self()) { self()->loadUserpic(); @@ -269,13 +272,13 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent) _newVersionText = lang(lng_settings_update_ready) + ' '; _newVersionWidth = st::linkFont->width(_newVersionText); - #ifndef TDESKTOP_DISABLE_AUTOUPDATE +#ifndef TDESKTOP_DISABLE_AUTOUPDATE Sandbox::connect(SIGNAL(updateChecking()), this, SLOT(onUpdateChecking())); Sandbox::connect(SIGNAL(updateLatest()), this, SLOT(onUpdateLatest())); Sandbox::connect(SIGNAL(updateProgress(qint64,qint64)), this, SLOT(onUpdateDownloading(qint64,qint64))); Sandbox::connect(SIGNAL(updateFailed()), this, SLOT(onUpdateFailed())); Sandbox::connect(SIGNAL(updateReady()), this, SLOT(onUpdateReady())); - #endif +#endif // chat options connect(&_replaceEmojis, SIGNAL(changed()), this, SLOT(onReplaceEmojis())); @@ -349,6 +352,14 @@ SettingsInner::SettingsInner(SettingsWidget *parent) : TWidget(parent) setMouseTracking(true); } +void SettingsInner::notifyPeerUpdated(const Notify::PeerUpdate &update) { + if (update.peer == App::self()) { + if (update.flags & Notify::PeerUpdateFlag::UsernameChanged) { + usernameChanged(); + } + } +} + void SettingsInner::peerUpdated(PeerData *data) { if (self() && data == self()) { if (self()->photoId && self()->photoId != UnknownPeerPhotoId) { @@ -1977,10 +1988,6 @@ void SettingsWidget::rpcClear() { _inner.rpcClear(); } -void SettingsWidget::usernameChanged() { - _inner.usernameChanged(); -} - void SettingsWidget::setInnerFocus() { _inner.setFocus(); } diff --git a/Telegram/SourceFiles/settingswidget.h b/Telegram/SourceFiles/settingswidget.h index 4162c9844..2c1c13814 100644 --- a/Telegram/SourceFiles/settingswidget.h +++ b/Telegram/SourceFiles/settingswidget.h @@ -23,8 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "ui/flatbutton.h" #include "ui/flatcheckbox.h" #include "sysbuttons.h" - -#include +#include "core/observer.h" class MainWindow; class Settings; @@ -57,7 +56,11 @@ private: }; -class SettingsInner : public TWidget, public RPCSender { +namespace Notify { +struct PeerUpdate; +} // namespace Notify + +class SettingsInner : public TWidget, public RPCSender, public Notify::Observer { Q_OBJECT public: @@ -188,6 +191,7 @@ public slots: void onTelegramFAQ(); private: + void notifyPeerUpdated(const Notify::PeerUpdate &update); void saveError(const QString &str = QString()); @@ -332,7 +336,6 @@ public: void updateDisplayNotify(); void rpcClear(); - void usernameChanged(); void setInnerFocus(); void needBackgroundUpdate(bool tile); diff --git a/Telegram/SourceFiles/structs.cpp b/Telegram/SourceFiles/structs.cpp index d1355380e..25170670a 100644 --- a/Telegram/SourceFiles/structs.cpp +++ b/Telegram/SourceFiles/structs.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2016 John Preston, https://desktop.telegram.org #include "lang.h" #include "inline_bots/inline_bot_layout_item.h" +#include "observer_peer.h" #include "history.h" #include "mainwidget.h" #include "application.h" @@ -99,18 +100,14 @@ NotifySettings globalNotifyAll, globalNotifyUsers, globalNotifyChats; NotifySettingsPtr globalNotifyAllPtr = UnknownNotifySettings, globalNotifyUsersPtr = UnknownNotifySettings, globalNotifyChatsPtr = UnknownNotifySettings; PeerData::PeerData(const PeerId &id) : id(id) -, loadedStatus(NotLoaded) , colorIndex(peerColorIndex(id)) , color(peerColor(colorIndex)) -, photoId(UnknownPeerPhotoId) -, nameVersion(0) -, notify(UnknownNotifySettings) , _userpic(isUser() ? userDefPhoto(colorIndex) : ((isChat() || isMegagroup()) ? chatDefPhoto(colorIndex) : channelDefPhoto(colorIndex))) { - if (!peerIsUser(id) && !peerIsChannel(id)) updateName(QString(), QString(), QString()); + nameText.setText(st::msgNameFont, QString(), _textNameOptions); } -void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername) { - if (name == newName && nameVersion > 0) { +void PeerData::updateNameDelayed(const QString &newName, const QString &newNameOrPhone, const QString &newUsername) { + if (name == newName) { if (isUser()) { if (asUser()->nameOrPhone == newNameOrPhone && asUser()->username == newUsername) { return; @@ -127,8 +124,17 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, ++nameVersion; name = newName; nameText.setText(st::msgNameFont, name, _textNameOptions); + + Notify::PeerUpdate update(this); + update.flags |= Notify::PeerUpdateFlag::NameChanged; + update.oldNames = names; + update.oldNameFirstChars = chars; + if (isUser()) { - asUser()->username = newUsername; + if (asUser()->username != newUsername) { + asUser()->username = newUsername; + update.flags |= Notify::PeerUpdateFlag::UsernameChanged; + } asUser()->setNameOrPhone(newNameOrPhone); } else if (isChannel()) { if (asChannel()->username != newUsername) { @@ -138,19 +144,14 @@ void PeerData::updateName(const QString &newName, const QString &newNameOrPhone, } else { asChannel()->flags |= MTPDchannel::Flag::f_username; } - if (App::main()) { - App::main()->peerUsernameChanged(this); - } + update.flags |= Notify::PeerUpdateFlag::UsernameChanged; } } - - Names oldNames = names; - NameFirstChars oldChars = chars; fillNames(); - if (App::main()) { - emit App::main()->peerNameChanged(this, oldNames, oldChars); + emit App::main()->peerNameChanged(this, update.oldNames, update.oldNameFirstChars); } + Notify::peerUpdatedDelayed(update); } void PeerData::setUserpic(ImagePtr userpic) { @@ -253,25 +254,27 @@ void PeerData::fillNames() { } } -void UserData::setName(const QString &first, const QString &last, const QString &phoneName, const QString &usern) { - bool updName = !first.isEmpty() || !last.isEmpty(), updUsername = (username != usern); +void UserData::setName(const QString &newFirstName, const QString &newLastName, const QString &newPhoneName, const QString &newUsername) { + setNameDelayed(newFirstName, newLastName, newPhoneName, newUsername); + Notify::peerUpdatedSendDelayed(); +} - if (updName && first.trimmed().isEmpty()) { - firstName = last; +void UserData::setNameDelayed(const QString &newFirstName, const QString &newLastName, const QString &newPhoneName, const QString &newUsername) { + bool changeName = !newFirstName.isEmpty() || !newLastName.isEmpty(); + + QString newFullName; + if (changeName && newFirstName.trimmed().isEmpty()) { + firstName = newLastName; lastName = QString(); - updateName(firstName, phoneName, usern); + newFullName = firstName; } else { - if (updName) { - firstName = first; - lastName = last; - } - updateName(lastName.isEmpty() ? firstName : lng_full_name(lt_first_name, firstName, lt_last_name, lastName), phoneName, usern); - } - if (updUsername) { - if (App::main()) { - App::main()->peerUsernameChanged(this); + if (changeName) { + firstName = newFirstName; + lastName = newLastName; } + newFullName = lastName.isEmpty() ? firstName : lng_full_name(lt_first_name, firstName, lt_last_name, lastName); } + updateNameDelayed(newFullName, newPhoneName, newUsername); } void UserData::setPhone(const QString &newPhone) { @@ -401,6 +404,15 @@ void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Loc } } +void ChatData::setName(const QString &newName) { + setNameDelayed(newName); + Notify::peerUpdatedSendDelayed(); +} + +void ChatData::setNameDelayed(const QString &newName) { + updateNameDelayed(newName.isEmpty() ? name : newName, QString(), QString()); +} + void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Local::readPeer as well PhotoId newPhotoId = photoId; ImagePtr newPhoto = _userpic; @@ -430,10 +442,13 @@ void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see } } -void ChannelData::setName(const QString &newName, const QString &usern) { - bool updName = !newName.isEmpty(), updUsername = (username != usern); +void ChannelData::setName(const QString &newName, const QString &newUsername) { + setNameDelayed(newName, newUsername); + Notify::peerUpdatedSendDelayed(); +} - updateName(newName.isEmpty() ? name : newName, QString(), usern); +void ChannelData::setNameDelayed(const QString &newName, const QString &newUsername) { + updateNameDelayed(newName.isEmpty() ? name : newName, QString(), newUsername); } void ChannelData::updateFull(bool force) { diff --git a/Telegram/SourceFiles/structs.h b/Telegram/SourceFiles/structs.h index da3d2d293..2b52bb830 100644 --- a/Telegram/SourceFiles/structs.h +++ b/Telegram/SourceFiles/structs.h @@ -274,10 +274,6 @@ public: ChatData *migrateFrom() const; ChannelData *migrateTo() const; - void updateName(const QString &newName, const QString &newNameOrPhone, const QString &newUsername); - - void fillNames(); - const Text &dialogName() const; const QString &shortName() const; const QString &userName() const; @@ -299,7 +295,7 @@ public: MinimalLoaded = 0x01, FullLoaded = 0x02, }; - LoadedStatus loadedStatus; + LoadedStatus loadedStatus = NotLoaded; MTPinputPeer input; int colorIndex; @@ -317,12 +313,12 @@ public: void saveUserpic(const QString &path) const; QPixmap genUserpic(int size) const; - PhotoId photoId; + PhotoId photoId = UnknownPeerPhotoId; StorageImageLocation photoLoc; - int nameVersion; + int nameVersion = 1; - NotifySettingsPtr notify; + NotifySettingsPtr notify = UnknownNotifySettings; // if this string is not empty we must not allow to open the // conversation and we must show this string instead @@ -338,10 +334,15 @@ public: } protected: + // Requires Notify::peerUpdatedSendDelayed() call after. + void updateNameDelayed(const QString &newName, const QString &newNameOrPhone, const QString &newUsername); + ImagePtr _userpic; ImagePtr currentUserpic() const; private: + void fillNames(); + ClickHandlerPtr _openLink; }; @@ -395,10 +396,16 @@ class UserData : public PeerData { public: UserData(const PeerId &id) : PeerData(id) { - setName(QString(), QString(), QString(), QString()); } void setPhoto(const MTPUserProfilePhoto &photo); - void setName(const QString &first, const QString &last, const QString &phoneName, const QString &username); + + void setName(const QString &newFirstName, const QString &newLastName + , const QString &newPhoneName, const QString &newUsername); + + // Requires Notify::peerUpdatedSendDelayed() call after. + void setNameDelayed(const QString &newFirstName, const QString &newLastName + , const QString &newPhoneName, const QString &newUsername); + void setPhone(const QString &newPhone); void setBotInfoVersion(int version); void setBotInfo(const MTPBotInfo &info); @@ -458,18 +465,15 @@ private: class ChatData : public PeerData { public: - ChatData(const PeerId &id) : PeerData(id) - , inputChat(MTP_int(bareId())) - , migrateToPtr(0) - , count(0) - , date(0) - , version(0) - , creator(0) - , flags(0) - , isForbidden(false) - , botStatus(0) { + ChatData(const PeerId &id) : PeerData(id), inputChat(MTP_int(bareId())) { } void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = UnknownPeerPhotoId); + + void setName(const QString &newName); + + // Requires Notify::peerUpdatedSendDelayed() call after. + void setNameDelayed(const QString &newName); + void invalidateParticipants() { participants = ChatData::Participants(); admins = ChatData::Admins(); @@ -483,15 +487,15 @@ public: MTPint inputChat; - ChannelData *migrateToPtr; + ChannelData *migrateToPtr = nullptr; - int count; - TimeId date; - int version; - UserId creator; + int count = 0; + TimeId date = 0; + int version = 0; + UserId creator = 0; - MTPDchat::Flags flags; - bool isForbidden; + MTPDchat::Flags flags = 0; + bool isForbidden = false; bool amIn() const { return !isForbidden && !haveLeft() && !wasKicked(); } @@ -532,7 +536,7 @@ public: LastAuthors lastAuthors; typedef OrderedSet MarkupSenders; MarkupSenders markupSenders; - int32 botStatus; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other + int botStatus = 0; // -1 - no bots, 0 - unknown, 1 - one bot, that sees all history, 2 - other // ImagePtr photoFull; QString invitationUrl; }; @@ -634,14 +638,15 @@ struct MegagroupInfo { class ChannelData : public PeerData { public: - ChannelData(const PeerId &id) : PeerData(id) - , inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))) - , mgInfo(nullptr) { - setName(QString(), QString()); + ChannelData(const PeerId &id) : PeerData(id), inputChannel(MTP_inputChannel(MTP_int(bareId()), MTP_long(0))) { } void setPhoto(const MTPChatPhoto &photo, const PhotoId &phId = UnknownPeerPhotoId); + void setName(const QString &name, const QString &username); + // Requires Notify::peerUpdatedSendDelayed() call after. + void setNameDelayed(const QString &name, const QString &username); + void updateFull(bool force = false); void fullUpdated();