diff --git a/Telegram/Resources/langs/lang.strings b/Telegram/Resources/langs/lang.strings index 7ee2a8ae585746..b37d0c0d88b785 100644 --- a/Telegram/Resources/langs/lang.strings +++ b/Telegram/Resources/langs/lang.strings @@ -1370,6 +1370,8 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org "lng_admin_log_invites_disabled" = "{from} disabled group invites"; "lng_admin_log_signatures_enabled" = "{from} enabled signatures"; "lng_admin_log_signatures_disabled" = "{from} disabled signatures"; +"lng_admin_log_history_made_hidden" = "{from} made group history hidden for new members"; +"lng_admin_log_history_made_visible" = "{from} made group history visible for new members"; "lng_admin_log_pinned_message" = "{from} pinned message:"; "lng_admin_log_unpinned_message" = "{from} unpinned message"; "lng_admin_log_edited_caption" = "{from} edited caption:"; diff --git a/Telegram/SourceFiles/apiwrap.cpp b/Telegram/SourceFiles/apiwrap.cpp index 2174e6525fb798..35fb935ab0e9a6 100644 --- a/Telegram/SourceFiles/apiwrap.cpp +++ b/Telegram/SourceFiles/apiwrap.cpp @@ -23,6 +23,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "data/data_drafts.h" #include "data/data_photo.h" #include "data/data_web_page.h" +#include "core/tl_help.h" #include "observer_peer.h" #include "lang/lang_keys.h" #include "application.h" @@ -198,32 +199,30 @@ void ApiWrap::resolveMessageDatas() { } void ApiWrap::gotMessageDatas(ChannelData *channel, const MTPmessages_Messages &msgs, mtpRequestId requestId) { + auto handleResult = [&](auto &&result) { + App::feedUsers(result.vusers); + App::feedChats(result.vchats); + App::feedMsgs(result.vmessages, NewMessageExisting); + }; switch (msgs.type()) { - case mtpc_messages_messages: { - auto &d(msgs.c_messages_messages()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageExisting); - } break; - - case mtpc_messages_messagesSlice: { - auto &d(msgs.c_messages_messagesSlice()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageExisting); - } break; - + case mtpc_messages_messages: + handleResult(msgs.c_messages_messages()); + break; + case mtpc_messages_messagesSlice: + handleResult(msgs.c_messages_messagesSlice()); + break; case mtpc_messages_channelMessages: { - auto &d(msgs.c_messages_channelMessages()); + auto &d = msgs.c_messages_channelMessages(); if (channel) { channel->ptsReceived(d.vpts.v); } else { LOG(("App Error: received messages.channelMessages when no channel was passed! (ApiWrap::gotDependencyItem)")); } - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageExisting); + handleResult(d); } break; + case mtpc_messages_messagesNotModified: + LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotDependencyItem)")); + break; } auto requests = messageDataRequests(channel, true); if (requests) { @@ -330,7 +329,7 @@ void ApiWrap::gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mt return; } auto &f = d.vfull_chat.c_channelFull(); - + channel->setAvailableMinId(f.vavailable_min_id.v); auto canViewAdmins = channel->canViewAdmins(); auto canViewMembers = channel->canViewMembers(); auto canEditStickers = channel->canEditStickers(); @@ -575,10 +574,19 @@ void ApiWrap::requestLastParticipants(ChannelData *channel, bool fromStart) { } } - auto requestId = request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsRecent(), MTP_int(fromStart ? 0 : channel->mgInfo->lastParticipants.size()), MTP_int(Global::ChatSizeMax()))).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + auto offset = fromStart ? 0 : channel->mgInfo->lastParticipants.size(); + auto participantsHash = 0; + auto requestId = request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsRecent(), + MTP_int(offset), + MTP_int(Global::ChatSizeMax()), + MTP_int(participantsHash) + )).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { lastParticipantsDone(channel, result, requestId); }).fail([this, channel](const RPCError &error, mtpRequestId requestId) { - if (_participantsRequests.value(channel) == requestId || _participantsRequests.value(channel) == -requestId) { + if (_participantsRequests.value(channel) == requestId + || _participantsRequests.value(channel) == -requestId) { _participantsRequests.remove(channel); } }).send(); @@ -591,7 +599,15 @@ void ApiWrap::requestBots(ChannelData *channel) { return; } - auto requestId = request(MTPchannels_GetParticipants(channel->inputChannel, MTP_channelParticipantsBots(), MTP_int(0), MTP_int(Global::ChatSizeMax()))).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + auto offset = 0; + auto participantsHash = 0; + auto requestId = request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsBots(), + MTP_int(offset), + MTP_int(Global::ChatSizeMax()), + MTP_int(participantsHash) + )).done([this, channel](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { lastParticipantsDone(channel, result, requestId); }).fail([this, channel](const RPCError &error, mtpRequestId requestId) { if (_botsRequests.value(channel) == requestId) { @@ -602,8 +618,12 @@ void ApiWrap::requestBots(ChannelData *channel) { _botsRequests.insert(channel, requestId); } -void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { - bool bots = (_botsRequests.value(peer) == requestId), fromStart = false; +void ApiWrap::lastParticipantsDone( + ChannelData *peer, + const MTPchannels_ChannelParticipants &result, + mtpRequestId requestId) { + auto bots = (_botsRequests.value(peer) == requestId); + auto fromStart = false; if (bots) { _botsRequests.remove(peer); } else { @@ -616,11 +636,28 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP _participantsRequests.remove(peer); } - if (!peer->mgInfo || result.type() != mtpc_channels_channelParticipants) return; + if (!peer->mgInfo) return; - History *h = 0; + parseChannelParticipants(result, [&]( + int fullCount, + const QVector &list) { + applyLastParticipantsList( + peer, + fullCount, + list, + bots, + fromStart); + }); +} + +void ApiWrap::applyLastParticipantsList( + ChannelData *peer, + int fullCount, + const QVector &list, + bool bots, + bool fromStart) { + auto h = bots ? App::historyLoaded(peer->id) : nullptr; if (bots) { - h = App::historyLoaded(peer->id); peer->mgInfo->bots.clear(); peer->mgInfo->botStatus = -1; } else if (fromStart) { @@ -629,16 +666,13 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP peer->mgInfo->lastParticipantsStatus = MegagroupInfo::LastParticipantsUpToDate; } - auto &d = result.c_channels_channelParticipants(); - auto &v = d.vparticipants.v; - App::feedUsers(d.vusers); auto added = false; auto needBotsInfos = false; auto botStatus = peer->mgInfo->botStatus; auto keyboardBotFound = !h || !h->lastKeyboardFrom; auto emptyAdminRights = MTP_channelAdminRights(MTP_flags(0)); auto emptyRestrictedRights = MTP_channelBannedRights(MTP_flags(0), MTP_int(0)); - for_const (auto &participant, v) { + for (auto &participant : list) { auto userId = UserId(0); auto adminCanEdit = false; auto adminRights = emptyAdminRights; @@ -701,12 +735,12 @@ void ApiWrap::lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelP if (!keyboardBotFound) { h->clearLastKeyboard(); } - int newMembersCount = qMax(d.vcount.v, v.count()); + int newMembersCount = qMax(fullCount, list.size()); if (newMembersCount > peer->membersCount()) { peer->setMembersCount(newMembersCount); } if (!bots) { - if (v.isEmpty()) { + if (list.isEmpty()) { peer->setMembersCount(peer->mgInfo->lastParticipants.size()); } Notify::PeerUpdate update(peer); @@ -819,16 +853,17 @@ void ApiWrap::requestChannelMembersForAdd( } request(base::take(_channelMembersForAddRequestId)).cancel(); - auto requestData = MTPchannels_GetParticipants( - channel->inputChannel, - MTP_channelParticipantsRecent(), - MTP_int(0), - MTP_int(Global::ChatSizeMax())); + auto offset = 0; + auto participantsHash = 0; _channelMembersForAdd = channel; - _channelMembersForAddRequestId = request( - std::move(requestData) - ).done([this](const MTPchannels_ChannelParticipants &result) { + _channelMembersForAddRequestId = request(MTPchannels_GetParticipants( + channel->inputChannel, + MTP_channelParticipantsRecent(), + MTP_int(offset), + MTP_int(Global::ChatSizeMax()), + MTP_int(participantsHash) + )).done([this](const MTPchannels_ChannelParticipants &result) { base::take(_channelMembersForAddRequestId); base::take(_channelMembersForAdd); base::take(_channelMembersForAddCallback)(result); @@ -1445,6 +1480,10 @@ void ApiWrap::gotWebPages(ChannelData *channel, const MTPmessages_Messages &msgs App::feedChats(d.vchats); v = &d.vmessages.v; } break; + + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (ApiWrap::gotWebPages)")); + } break; } if (!v) return; @@ -1673,6 +1712,25 @@ void ApiWrap::readFeaturedSets() { } } +void ApiWrap::parseChannelParticipants( + const MTPchannels_ChannelParticipants &result, + base::lambda &list)> callbackList, + base::lambda callbackNotModified) { + TLHelp::VisitChannelParticipants(result, ranges::overload([&]( + const MTPDchannels_channelParticipants &data) { + App::feedUsers(data.vusers); + if (callbackList) { + callbackList(data.vcount.v, data.vparticipants.v); + } + }, [&](mtpTypeId) { + if (callbackNotModified) { + callbackNotModified(); + } else { + LOG(("API Error: channels.channelParticipantsNotModified received!")); + } + })); +}; + void ApiWrap::applyUpdatesNoPtsCheck(const MTPUpdates &updates) { switch (updates.type()) { case mtpc_updateShortMessage: { @@ -1798,10 +1856,23 @@ void ApiWrap::jumpToDate(not_null peer, const QDate &date) { // API returns a message with date <= offset_date. // So we request a message with offset_date = desired_date - 1 and add_offset = -1. // This should give us the first message with date >= desired_date. - auto offset_date = static_cast(QDateTime(date).toTime_t()) - 1; - auto add_offset = -1; + auto offsetId = 0; + auto offsetDate = static_cast(QDateTime(date).toTime_t()) - 1; + auto addOffset = -1; auto limit = 1; - request(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(offset_date), MTP_int(add_offset), MTP_int(limit), MTP_int(0), MTP_int(0))).done([peer](const MTPmessages_Messages &result) { + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + request(MTPmessages_GetHistory( + peer->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(addOffset), + MTP_int(limit), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash) + )).done([peer](const MTPmessages_Messages &result) { auto getMessagesList = [&result, peer]() -> const QVector* { auto handleMessages = [](auto &messages) { App::feedUsers(messages.vusers); @@ -1809,17 +1880,22 @@ void ApiWrap::jumpToDate(not_null peer, const QDate &date) { return &messages.vmessages.v; }; switch (result.type()) { - case mtpc_messages_messages: return handleMessages(result.c_messages_messages()); - case mtpc_messages_messagesSlice: return handleMessages(result.c_messages_messagesSlice()); + case mtpc_messages_messages: + return handleMessages(result.c_messages_messages()); + case mtpc_messages_messagesSlice: + return handleMessages(result.c_messages_messagesSlice()); case mtpc_messages_channelMessages: { auto &messages = result.c_messages_channelMessages(); if (peer && peer->isChannel()) { peer->asChannel()->ptsReceived(messages.vpts.v); } else { - LOG(("API Error: received messages.channelMessages when no channel was passed! (MainWidget::showJumpToDate)")); + LOG(("API Error: received messages.channelMessages when no channel was passed! (ApiWrap::jumpToDate)")); } return handleMessages(messages); } break; + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (ApiWrap::jumpToDate)")); + } break; } return nullptr; }; diff --git a/Telegram/SourceFiles/apiwrap.h b/Telegram/SourceFiles/apiwrap.h index 8cc9de5477a869..99f01331605bc1 100644 --- a/Telegram/SourceFiles/apiwrap.h +++ b/Telegram/SourceFiles/apiwrap.h @@ -141,6 +141,11 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { } void readFeaturedSetDelayed(uint64 setId); + void parseChannelParticipants( + const MTPchannels_ChannelParticipants &result, + base::lambda &list)> callbackList, + base::lambda callbackNotModified = nullptr); + ~ApiWrap(); private: @@ -167,7 +172,16 @@ class ApiWrap : private MTP::Sender, private base::Subscriber { void gotChatFull(PeerData *peer, const MTPmessages_ChatFull &result, mtpRequestId req); void gotUserFull(UserData *user, const MTPUserFull &result, mtpRequestId req); - void lastParticipantsDone(ChannelData *peer, const MTPchannels_ChannelParticipants &result, mtpRequestId req); + void lastParticipantsDone( + ChannelData *peer, + const MTPchannels_ChannelParticipants &result, + mtpRequestId req); + void applyLastParticipantsList( + ChannelData *peer, + int fullCount, + const QVector &list, + bool bots, + bool fromStart); void resolveWebPages(); void gotWebPages(ChannelData *channel, const MTPmessages_Messages &result, mtpRequestId req); void gotStickerSet(uint64 setId, const MTPmessages_StickerSet &result); diff --git a/Telegram/SourceFiles/boxes/send_files_box.cpp b/Telegram/SourceFiles/boxes/send_files_box.cpp index 22a6ba1ca175d1..ccf7b2a4aa028d 100644 --- a/Telegram/SourceFiles/boxes/send_files_box.cpp +++ b/Telegram/SourceFiles/boxes/send_files_box.cpp @@ -778,7 +778,17 @@ void EditCaptionBox::onSave(bool ctrlShiftEnter) { flags |= MTPmessages_EditMessage::Flag::f_entities; } auto text = TextUtilities::PrepareForSending(_field->getLastText(), TextUtilities::PrepareTextOption::CheckLinks); - _saveRequestId = MTP::send(MTPmessages_EditMessage(MTP_flags(flags), item->history()->peer->input, MTP_int(item->id), MTP_string(text), MTPnullMarkup, sentEntities), rpcDone(&EditCaptionBox::saveDone), rpcFail(&EditCaptionBox::saveFail)); + _saveRequestId = MTP::send( + MTPmessages_EditMessage( + MTP_flags(flags), + item->history()->peer->input, + MTP_int(item->id), + MTP_string(text), + MTPnullMarkup, + sentEntities, + MTP_inputGeoPointEmpty()), + rpcDone(&EditCaptionBox::saveDone), + rpcFail(&EditCaptionBox::saveFail)); } void EditCaptionBox::saveDone(const MTPUpdates &updates) { diff --git a/Telegram/SourceFiles/calls/calls_box_controller.cpp b/Telegram/SourceFiles/calls/calls_box_controller.cpp index 5a9ab0bca3a633..6080a028a26225 100644 --- a/Telegram/SourceFiles/calls/calls_box_controller.cpp +++ b/Telegram/SourceFiles/calls/calls_box_controller.cpp @@ -245,7 +245,20 @@ void BoxController::loadMoreRows() { return; } - _loadRequestId = request(MTPmessages_Search(MTP_flags(0), MTP_inputPeerEmpty(), MTP_string(QString()), MTP_inputUserEmpty(), MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)), MTP_int(0), MTP_int(0), MTP_int(_offsetId), MTP_int(0), MTP_int(_offsetId ? kFirstPageCount : kPerPageCount), MTP_int(0), MTP_int(0))).done([this](const MTPmessages_Messages &result) { + _loadRequestId = request(MTPmessages_Search( + MTP_flags(0), + MTP_inputPeerEmpty(), + MTP_string(QString()), + MTP_inputUserEmpty(), + MTP_inputMessagesFilterPhoneCalls(MTP_flags(0)), + MTP_int(0), + MTP_int(0), + MTP_int(_offsetId), + MTP_int(0), + MTP_int(_offsetId ? kFirstPageCount : kPerPageCount), + MTP_int(0), + MTP_int(0) + )).done([this](const MTPmessages_Messages &result) { _loadRequestId = 0; auto handleResult = [this](auto &data) { @@ -261,7 +274,9 @@ void BoxController::loadMoreRows() { LOG(("API Error: received messages.channelMessages! (Calls::BoxController::preloadRows)")); handleResult(result.c_messages_channelMessages()); } break; - + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (Calls::BoxController::preloadRows)")); + } break; default: Unexpected("Type of messages.Messages (Calls::BoxController::preloadRows)"); } }).fail([this](const RPCError &error) { diff --git a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp index e9dff5c4512051..d52364b05883cc 100644 --- a/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp +++ b/Telegram/SourceFiles/chat_helpers/gifs_list_widget.cpp @@ -218,6 +218,7 @@ void GifsListWidget::inlineResultsDone(const MTPmessages_BotResults &result) { auto it = _inlineCache.find(_inlineQuery); auto adding = (it != _inlineCache.cend()); + // #TODO layer 72 feed users if (result.type() == mtpc_messages_botResults) { auto &d = result.c_messages_botResults(); auto &v = d.vresults.v; diff --git a/Telegram/SourceFiles/core/tl_help.h b/Telegram/SourceFiles/core/tl_help.h new file mode 100644 index 00000000000000..6d56f562d38c9b --- /dev/null +++ b/Telegram/SourceFiles/core/tl_help.h @@ -0,0 +1,63 @@ +/* +This file is part of Telegram Desktop, +the official desktop version of Telegram messaging app, see https://telegram.org + +Telegram Desktop is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +It is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +In addition, as a special exception, the copyright holders give permission +to link the code of portions of this program with the OpenSSL library. + +Full license: https://github.com/telegramdesktop/tdesktop/blob/master/LICENSE +Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org +*/ +#pragma once + +namespace TLHelp { + +template +inline auto VisitChannelParticipant( + const MTPChannelParticipant &p, + Callback &&callback) { + switch (p.type()) { + case mtpc_channelParticipant: + return callback(p.c_channelParticipant()); + case mtpc_channelParticipantSelf: + return callback(p.c_channelParticipantSelf()); + case mtpc_channelParticipantAdmin: + return callback(p.c_channelParticipantAdmin()); + case mtpc_channelParticipantCreator: + return callback(p.c_channelParticipantCreator()); + case mtpc_channelParticipantBanned: + return callback(p.c_channelParticipantBanned()); + default: Unexpected("Type in VisitChannelParticipant()"); + } +} + +inline UserId ReadChannelParticipantUserId(const MTPChannelParticipant &p) { + return VisitChannelParticipant(p, [](auto &&data) { + return data.vuser_id.v; + }); +} + +template +inline auto VisitChannelParticipants( + const MTPchannels_ChannelParticipants &p, + Callback &&callback) { + switch (p.type()) { + case mtpc_channels_channelParticipants: + return callback(p.c_channels_channelParticipants()); + case mtpc_channels_channelParticipantsNotModified: + return callback(p.type()); + default: Unexpected("Type in VisitChannelParticipants()"); + } +} + +} // namespace TLHelp diff --git a/Telegram/SourceFiles/data/data_peer.cpp b/Telegram/SourceFiles/data/data_peer.cpp index 2ce9c957b1714f..d4136543e16341 100644 --- a/Telegram/SourceFiles/data/data_peer.cpp +++ b/Telegram/SourceFiles/data/data_peer.cpp @@ -297,7 +297,7 @@ void PeerData::updateNameDelayed( ++nameVersion; name = newName; nameText.setText(st::msgNameStyle, name, _textNameOptions); - if (!_userpic) { + if (useEmptyUserpic()) { _userpicEmpty.set(_colorIndex, name); } @@ -331,9 +331,12 @@ ClickHandlerPtr PeerData::createOpenLink() { return MakeShared(this); } -void PeerData::setUserpic(ImagePtr userpic) { +void PeerData::setUserpic( + ImagePtr userpic, + StorageImageLocation location) { _userpic = userpic; - if (!_userpic || !_userpic->loaded()) { + _userpicLocation = location; + if (useEmptyUserpic()) { _userpicEmpty.set(_colorIndex, name); } else { _userpicEmpty.clear(); @@ -344,7 +347,9 @@ ImagePtr PeerData::currentUserpic() const { if (_userpic) { _userpic->load(); if (_userpic->loaded()) { - _userpicEmpty.clear(); + if (!useEmptyUserpic()) { + _userpicEmpty.clear(); + } return _userpic; } } @@ -376,10 +381,10 @@ void PeerData::paintUserpicSquare(Painter &p, int x, int y, int size) const { } StorageKey PeerData::userpicUniqueKey() const { - if (photoLoc.isNull() || !_userpic || !_userpic->loaded()) { + if (useEmptyUserpic()) { return _userpicEmpty.uniqueKey(); } - return storageKey(photoLoc); + return storageKey(_userpicLocation); } void PeerData::saveUserpic(const QString &path, int size) const { @@ -430,9 +435,10 @@ bool UserData::canShareThisContact() const { } void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer as well - PhotoId newPhotoId = photoId; - ImagePtr newPhoto = _userpic; - StorageImageLocation newPhotoLoc = photoLoc; + auto newPhotoId = photoId; + auto newPhoto = _userpic; + auto newPhotoLoc = _userpicLocation; + switch (p.type()) { case mtpc_userProfilePhoto: { const auto &d(p.c_userProfilePhoto()); @@ -453,10 +459,9 @@ void UserData::setPhoto(const MTPUserProfilePhoto &p) { // see Local::readPeer a newPhotoLoc = StorageImageLocation(); } break; } - if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != _userpicLocation) { photoId = newPhotoId; - setUserpic(newPhoto); - photoLoc = newPhotoLoc; + setUserpic(newPhoto, newPhotoLoc); Notify::peerUpdatedDelayed(this, UpdateFlag::PhotoChanged); } } @@ -649,12 +654,13 @@ bool UserData::hasCalls() const { } void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Local::readPeer as well - PhotoId newPhotoId = photoId; - ImagePtr newPhoto = _userpic; - StorageImageLocation newPhotoLoc = photoLoc; + auto newPhotoId = photoId; + auto newPhoto = _userpic; + auto newPhotoLoc = _userpicLocation; + switch (p.type()) { case mtpc_chatPhoto: { - const auto &d(p.c_chatPhoto()); + auto &d = p.c_chatPhoto(); if (phId != UnknownPeerPhotoId) { newPhotoId = phId; } @@ -669,10 +675,9 @@ void ChatData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Loc // photoFull = ImagePtr(); } break; } - if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != _userpicLocation) { photoId = newPhotoId; - setUserpic(newPhoto); - photoLoc = newPhotoLoc; + setUserpic(newPhoto, newPhotoLoc); Notify::peerUpdatedDelayed(this, UpdateFlag::PhotoChanged); } } @@ -717,12 +722,13 @@ ChannelData::ChannelData(const PeerId &id) } void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see Local::readPeer as well - PhotoId newPhotoId = photoId; - ImagePtr newPhoto = _userpic; - StorageImageLocation newPhotoLoc = photoLoc; + auto newPhotoId = photoId; + auto newPhoto = _userpic; + auto newPhotoLoc = _userpicLocation; + switch (p.type()) { case mtpc_chatPhoto: { - const auto &d(p.c_chatPhoto()); + auto &d = p.c_chatPhoto(); if (phId != UnknownPeerPhotoId) { newPhotoId = phId; } @@ -737,10 +743,9 @@ void ChannelData::setPhoto(const MTPChatPhoto &p, const PhotoId &phId) { // see // photoFull = ImagePtr(); } break; } - if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != photoLoc) { + if (newPhotoId != photoId || newPhoto.v() != _userpic.v() || newPhotoLoc != _userpicLocation) { photoId = newPhotoId; - setUserpic(newPhoto); - photoLoc = newPhotoLoc; + setUserpic(newPhoto, newPhotoLoc); Notify::peerUpdatedDelayed(this, UpdateFlag::PhotoChanged); } } @@ -943,6 +948,15 @@ void ChannelData::setRestrictionReason(const QString &text) { } } +void ChannelData::setAvailableMinId(MsgId availableMinId) { + if (_availableMinId != availableMinId) { + _availableMinId = availableMinId; + if (auto history = App::historyLoaded(this)) { + history->clearUpTill(availableMinId); + } + } +} + bool ChannelData::canEditLastAdmin(not_null user) const { // Duplicated in ParticipantsBoxController::canEditAdmin :( if (mgInfo) { diff --git a/Telegram/SourceFiles/data/data_peer.h b/Telegram/SourceFiles/data/data_peer.h index 8fbd168b591497..900413c765cc9b 100644 --- a/Telegram/SourceFiles/data/data_peer.h +++ b/Telegram/SourceFiles/data/data_peer.h @@ -225,7 +225,7 @@ class PeerData { int colorIndex() const { return _colorIndex; } - void setUserpic(ImagePtr userpic); + void setUserpic(ImagePtr userpic, StorageImageLocation location); void paintUserpic( Painter &p, int x, @@ -255,14 +255,21 @@ class PeerData { bool userpicLoaded() const { return _userpic->loaded(); } + bool useEmptyUserpic() const { + return _userpicLocation.isNull() + || !_userpic + || !_userpic->loaded(); + } StorageKey userpicUniqueKey() const; void saveUserpic(const QString &path, int size) const; void saveUserpicRounded(const QString &path, int size) const; QPixmap genUserpic(int size) const; QPixmap genUserpicRounded(int size) const; + StorageImageLocation userpicLocation() const { + return _userpicLocation; + } PhotoId photoId = UnknownPeerPhotoId; - StorageImageLocation photoLoc; int nameVersion = 1; @@ -292,6 +299,7 @@ class PeerData { ImagePtr _userpic; mutable EmptyUserpic _userpicEmpty; + StorageImageLocation _userpicLocation; private: void fillNames(); @@ -1092,6 +1100,11 @@ class ChannelData : public PeerData { } void setRestrictionReason(const QString &reason); + MsgId availableMinId() const { + return _availableMinId; + } + void setAvailableMinId(MsgId availableMinId); + private: void flagsUpdated(MTPDchannel::Flags diff); void fullFlagsUpdated(MTPDchannelFull::Flags diff); @@ -1107,6 +1120,7 @@ class ChannelData : public PeerData { int _adminsCount = 1; int _restrictedCount = 0; int _kickedCount = 0; + MsgId _availableMinId = 0; AdminRightFlags _adminRights; RestrictionFlags _restrictions; diff --git a/Telegram/SourceFiles/data/data_search_controller.cpp b/Telegram/SourceFiles/data/data_search_controller.cpp index 37cfcee75e1cfd..61e7eabe151b8b 100644 --- a/Telegram/SourceFiles/data/data_search_controller.cpp +++ b/Telegram/SourceFiles/data/data_search_controller.cpp @@ -105,7 +105,9 @@ SearchResult ParseSearchResult( SparseIdsLoadDirection direction, const MTPmessages_Messages &data) { auto result = SearchResult(); - auto &messages = *[&] { + result.noSkipRange = MsgRange{ messageId, messageId }; + + auto messages = [&] { switch (data.type()) { case mtpc_messages_messages: { auto &d = data.c_messages_messages(); @@ -135,14 +137,22 @@ SearchResult ParseSearchResult( result.fullCount = d.vcount.v; return &d.vmessages.v; } break; + + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (ParseSearchResult)")); + return (const QVector*)nullptr; + } break; } Unexpected("messages.Messages type in ParseSearchResult()"); }(); - result.noSkipRange = MsgRange{ messageId, messageId }; + if (!messages) { + return result; + } + auto addType = NewMessageExisting; - result.messageIds.reserve(messages.size()); - for (auto &message : messages) { + result.messageIds.reserve(messages->size()); + for (auto &message : *messages) { if (auto item = App::histories().addNewMessage(message, addType)) { if ((type == Storage::SharedMediaType::kCount) || item->sharedMediaTypes().test(type)) { diff --git a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp index eca1bdff71d50f..0f90da51c8e7d7 100644 --- a/Telegram/SourceFiles/dialogs/dialogs_widget.cpp +++ b/Telegram/SourceFiles/dialogs/dialogs_widget.cpp @@ -678,6 +678,15 @@ void DialogsWidget::searchReceived(DialogsSearchRequestType type, const MTPmessa } } } break; + + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (DialogsWidget::searchReceived)")); + if (type == DialogsSearchMigratedFromStart || type == DialogsSearchMigratedFromOffset) { + _searchFullMigrated = true; + } else { + _searchFull = true; + } + } break; } _searchRequest = 0; diff --git a/Telegram/SourceFiles/facades.cpp b/Telegram/SourceFiles/facades.cpp index e546134ed2ef2f..81dc39fa68c6b6 100644 --- a/Telegram/SourceFiles/facades.cpp +++ b/Telegram/SourceFiles/facades.cpp @@ -572,6 +572,7 @@ struct Data { int32 StickersFavedLimit = 5; int32 PinnedDialogsCountMax = 5; QString InternalLinksDomain = qsl("https://t.me/"); + int32 ChannelsReadMediaPeriod = 86400 * 7; int32 CallReceiveTimeoutMs = 20000; int32 CallRingTimeoutMs = 90000; int32 CallConnectTimeoutMs = 30000; @@ -694,6 +695,7 @@ DefineVar(Global, int32, StickersRecentLimit); DefineVar(Global, int32, StickersFavedLimit); DefineVar(Global, int32, PinnedDialogsCountMax); DefineVar(Global, QString, InternalLinksDomain); +DefineVar(Global, int32, ChannelsReadMediaPeriod); DefineVar(Global, int32, CallReceiveTimeoutMs); DefineVar(Global, int32, CallRingTimeoutMs); DefineVar(Global, int32, CallConnectTimeoutMs); diff --git a/Telegram/SourceFiles/facades.h b/Telegram/SourceFiles/facades.h index ab50fc7376983a..2a41ae83dd11a1 100644 --- a/Telegram/SourceFiles/facades.h +++ b/Telegram/SourceFiles/facades.h @@ -353,6 +353,7 @@ DeclareVar(int32, StickersRecentLimit); DeclareVar(int32, StickersFavedLimit); DeclareVar(int32, PinnedDialogsCountMax); DeclareVar(QString, InternalLinksDomain); +DeclareVar(int32, ChannelsReadMediaPeriod); DeclareVar(int32, CallReceiveTimeoutMs); DeclareVar(int32, CallRingTimeoutMs); DeclareVar(int32, CallConnectTimeoutMs); diff --git a/Telegram/SourceFiles/history/history.cpp b/Telegram/SourceFiles/history/history.cpp index edef4dc3c0d93e..9d14e5e40e19f1 100644 --- a/Telegram/SourceFiles/history/history.cpp +++ b/Telegram/SourceFiles/history/history.cpp @@ -859,6 +859,13 @@ HistoryItem *History::createItem(const MTPMessage &msg, bool applyServiceAction, default: badMedia = MediaCheckResult::Unsupported; break; } break; + case mtpc_messageMediaGeoLive: + switch (m.vmedia.c_messageMediaGeoLive().vgeo.type()) { + case mtpc_geoPoint: break; + case mtpc_geoPointEmpty: badMedia = MediaCheckResult::Empty; break; + default: badMedia = MediaCheckResult::Unsupported; break; + } + break; case mtpc_messageMediaPhoto: { auto &photo = m.vmedia.c_messageMediaPhoto(); if (photo.has_ttl_seconds()) { @@ -1236,21 +1243,27 @@ void History::addUnreadMentionsSlice(const MTPmessages_Messages &result) { } break; case mtpc_messages_channelMessages: { - LOG(("API Error: unexpected messages.channelMessages in History::addUnreadMentionsSlice")); + LOG(("API Error: unexpected messages.channelMessages! (History::addUnreadMentionsSlice)")); auto &d = result.c_messages_channelMessages(); messages = getMessages(d); count = d.vcount.v; } break; + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (History::addUnreadMentionsSlice)")); + } break; + default: Unexpected("type in History::addUnreadMentionsSlice"); } auto added = false; - for (auto &message : *messages) { - if (auto item = addToHistory(message)) { - if (item->mentionsMe() && item->isMediaUnread()) { - _unreadMentions.insert(item->id); - added = true; + if (messages) { + for (auto &message : *messages) { + if (auto item = addToHistory(message)) { + if (item->mentionsMe() && item->isMediaUnread()) { + _unreadMentions.insert(item->id); + added = true; + } } } } @@ -2363,6 +2376,25 @@ void History::clear(bool leaveItems) { } } +void History::clearUpTill(MsgId availableMinId) { + auto minId = minMsgId(); + if (!minId || minId >= availableMinId) { + return; + } + do { + auto item = blocks.front()->items.front(); + auto itemId = item->id; + if (IsServerMsgId(itemId) && itemId >= availableMinId) { + break; + } + item->destroy(); + } while (!isEmpty()); + + if (!lastMsg) { + App::main()->checkPeerHistory(peer); + } +} + void History::clearBlocks(bool leaveItems) { Blocks lst; std::swap(lst, blocks); @@ -2463,7 +2495,8 @@ void History::overviewSliceDone( const MTPmessages_Messages &result, bool onlyCounts) { auto fullCount = 0; - const QVector *v = 0; + auto v = (const QVector*)nullptr; + switch (result.type()) { case mtpc_messages_messages: { auto &d = result.c_messages_messages(); @@ -2495,10 +2528,14 @@ void History::overviewSliceDone( v = &d.vmessages.v; } break; + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (History::overviewSliceDone, onlyCounts %1)").arg(Logs::b(onlyCounts))); + } break; + default: return; } - if (!onlyCounts && v->isEmpty()) { + if (!onlyCounts && (!v || v->isEmpty())) { _overviewCountData[overviewIndex] = 0; } @@ -2506,15 +2543,17 @@ void History::overviewSliceDone( auto sharedMediaType = ConvertSharedMediaType( static_cast(overviewIndex)); auto slice = std::vector(); - slice.reserve(v->size()); - for (auto i = v->cbegin(), e = v->cend(); i != e; ++i) { - if (auto item = App::histories().addNewMessage(*i, NewMessageExisting)) { - auto itemId = item->id; - _overview[overviewIndex].insert(itemId); - if (item->sharedMediaTypes().test(sharedMediaType)) { - slice.push_back(itemId); - accumulate_min(noSkipRange.from, itemId); - accumulate_max(noSkipRange.till, itemId); + if (v) { + slice.reserve(v->size()); + for (auto &message : *v) { + if (auto item = App::histories().addNewMessage(message, NewMessageExisting)) { + auto itemId = item->id; + _overview[overviewIndex].insert(itemId); + if (item->sharedMediaTypes().test(sharedMediaType)) { + slice.push_back(itemId); + accumulate_min(noSkipRange.from, itemId); + accumulate_max(noSkipRange.till, itemId); + } } } } diff --git a/Telegram/SourceFiles/history/history.h b/Telegram/SourceFiles/history/history.h index 64b91a98397da8..9fd8ea805b5d0b 100644 --- a/Telegram/SourceFiles/history/history.h +++ b/Telegram/SourceFiles/history/history.h @@ -221,6 +221,7 @@ class History { bool isDisplayedEmpty() const; void clear(bool leaveItems = false); + void clearUpTill(MsgId availableMinId); virtual ~History(); diff --git a/Telegram/SourceFiles/history/history_admin_log_inner.cpp b/Telegram/SourceFiles/history/history_admin_log_inner.cpp index b22bd46e6453a0..532014cf19da2a 100644 --- a/Telegram/SourceFiles/history/history_admin_log_inner.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_inner.cpp @@ -35,6 +35,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "auth_session.h" #include "ui/widgets/popup_menu.h" #include "core/file_utilities.h" +#include "core/tl_help.h" #include "lang/lang_keys.h" #include "boxes/edit_participant_box.h" @@ -342,29 +343,43 @@ void InnerWidget::applySearch(const QString &query) { } void InnerWidget::requestAdmins() { - request(MTPchannels_GetParticipants(_channel->inputChannel, MTP_channelParticipantsAdmins(), MTP_int(0), MTP_int(kMaxChannelAdmins))).done([this](const MTPchannels_ChannelParticipants &result) { - Expects(result.type() == mtpc_channels_channelParticipants); - auto &participants = result.c_channels_channelParticipants(); - App::feedUsers(participants.vusers); - for (auto &participant : participants.vparticipants.v) { - auto getUserId = [&participant] { - switch (participant.type()) { - case mtpc_channelParticipant: return participant.c_channelParticipant().vuser_id.v; - case mtpc_channelParticipantSelf: return participant.c_channelParticipantSelf().vuser_id.v; - case mtpc_channelParticipantAdmin: return participant.c_channelParticipantAdmin().vuser_id.v; - case mtpc_channelParticipantCreator: return participant.c_channelParticipantCreator().vuser_id.v; - case mtpc_channelParticipantBanned: return participant.c_channelParticipantBanned().vuser_id.v; - default: Unexpected("Type in AdminLog::Widget::showFilter()"); - } - }; - if (auto user = App::userLoaded(getUserId())) { + auto participantsHash = 0; + request(MTPchannels_GetParticipants( + _channel->inputChannel, + MTP_channelParticipantsAdmins(), + MTP_int(0), + MTP_int(kMaxChannelAdmins), + MTP_int(participantsHash) + )).done([this](const MTPchannels_ChannelParticipants &result) { + auto readCanEdit = ranges::overload([](const MTPDchannelParticipantAdmin &v) { + return v.is_can_edit(); + }, [](auto &&) { + return false; + }); + Auth().api().parseChannelParticipants(result, [&]( + int fullCount, + const QVector &list) { + auto filtered = ( + list + ) | ranges::view::transform([&](const MTPChannelParticipant &p) { + return std::make_pair( + TLHelp::ReadChannelParticipantUserId(p), + TLHelp::VisitChannelParticipant(p, readCanEdit)); + }) | ranges::view::transform([&](auto &&pair) { + return std::make_pair( + App::userLoaded(pair.first), + pair.second); + }) | ranges::view::filter([&](auto &&pair) { + return (pair.first != nullptr); + }); + + for (auto [user, canEdit] : filtered) { _admins.push_back(user); - auto canEdit = (participant.type() == mtpc_channelParticipantAdmin) && (participant.c_channelParticipantAdmin().is_can_edit()); if (canEdit) { _adminsCanEdit.push_back(user); } } - } + }); if (_admins.empty()) { _admins.push_back(App::self()); } @@ -1047,17 +1062,26 @@ void InnerWidget::suggestRestrictUser(not_null user) { } else { request(MTPchannels_GetParticipant(_channel->inputChannel, user->inputUser)).done([this, editRestrictions](const MTPchannels_ChannelParticipant &result) { Expects(result.type() == mtpc_channels_channelParticipant); + auto &participant = result.c_channels_channelParticipant(); App::feedUsers(participant.vusers); auto type = participant.vparticipant.type(); if (type == mtpc_channelParticipantBanned) { - editRestrictions(false, participant.vparticipant.c_channelParticipantBanned().vbanned_rights); + auto &banned = participant.vparticipant.c_channelParticipantBanned(); + editRestrictions(false, banned.vbanned_rights); } else { - auto hasAdminRights = (type == mtpc_channelParticipantAdmin || type == mtpc_channelParticipantCreator); - editRestrictions(hasAdminRights, MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); + auto hasAdminRights = (type == mtpc_channelParticipantAdmin) + || (type == mtpc_channelParticipantCreator); + auto bannedRights = MTP_channelBannedRights( + MTP_flags(0), + MTP_int(0)); + editRestrictions(hasAdminRights, bannedRights); } }).fail([this, editRestrictions](const RPCError &error) { - editRestrictions(false, MTP_channelBannedRights(MTP_flags(0), MTP_int(0))); + auto bannedRights = MTP_channelBannedRights( + MTP_flags(0), + MTP_int(0)); + editRestrictions(false, bannedRights); }).send(); } }); diff --git a/Telegram/SourceFiles/history/history_admin_log_item.cpp b/Telegram/SourceFiles/history/history_admin_log_item.cpp index 34c76622762649..138ccaa99ee672 100644 --- a/Telegram/SourceFiles/history/history_admin_log_item.cpp +++ b/Telegram/SourceFiles/history/history_admin_log_item.cpp @@ -25,6 +25,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "history/history_admin_log_inner.h" #include "lang/lang_keys.h" #include "boxes/sticker_set_box.h" +#include "core/tl_help.h" #include "messenger.h" namespace AdminLog { @@ -205,43 +206,52 @@ auto GenerateUserString(MTPint userId) { return lng_admin_log_user_with_username__generic(lt_name, name, lt_mention, mention); } -auto GenerateParticipantChangeTextInner(not_null channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant) { +auto GenerateParticipantChangeTextInner( + not_null channel, + const MTPChannelParticipant &participant, + const MTPChannelParticipant *oldParticipant) { auto oldType = oldParticipant ? oldParticipant->type() : 0; - auto resultForParticipant = [channel, oldParticipant, oldType](auto &&data) { + auto readResult = ranges::overload([](const MTPDchannelParticipantCreator &data) { + // No valid string here :( + return lng_admin_log_invited__generic( + lt_user, + GenerateUserString(data.vuser_id)); + }, [&](const MTPDchannelParticipantAdmin &data) { + auto user = GenerateUserString(data.vuser_id); + return GenerateAdminChangeText( + channel, + user, + &data.vadmin_rights, + (oldType == mtpc_channelParticipantAdmin) + ? &oldParticipant->c_channelParticipantAdmin().vadmin_rights + : nullptr); + }, [&](const MTPDchannelParticipantBanned &data) { + auto user = GenerateUserString(data.vuser_id); + return GenerateBannedChangeText( + user, + &data.vbanned_rights, + (oldType == mtpc_channelParticipantBanned) + ? &oldParticipant->c_channelParticipantBanned().vbanned_rights + : nullptr); + }, [&](auto &&data) { auto user = GenerateUserString(data.vuser_id); if (oldType == mtpc_channelParticipantAdmin) { - return GenerateAdminChangeText(channel, user, nullptr, &oldParticipant->c_channelParticipantAdmin().vadmin_rights); + return GenerateAdminChangeText( + channel, + user, + nullptr, + &oldParticipant->c_channelParticipantAdmin().vadmin_rights); } else if (oldType == mtpc_channelParticipantBanned) { - return GenerateBannedChangeText(user, nullptr, &oldParticipant->c_channelParticipantBanned().vbanned_rights); + return GenerateBannedChangeText( + user, + nullptr, + &oldParticipant->c_channelParticipantBanned().vbanned_rights); } return lng_admin_log_invited__generic(lt_user, user); - }; - - switch (participant.type()) { - case mtpc_channelParticipantCreator: { - // No valid string here :( - auto &data = participant.c_channelParticipantCreator(); - return lng_admin_log_invited__generic(lt_user, GenerateUserString(data.vuser_id)); - } break; - - case mtpc_channelParticipant: return resultForParticipant(participant.c_channelParticipant()); - case mtpc_channelParticipantSelf: return resultForParticipant(participant.c_channelParticipantSelf()); - - case mtpc_channelParticipantAdmin: { - auto &data = participant.c_channelParticipantAdmin(); - auto user = GenerateUserString(data.vuser_id); - return GenerateAdminChangeText(channel, user, &data.vadmin_rights, (oldType == mtpc_channelParticipantAdmin) ? &oldParticipant->c_channelParticipantAdmin().vadmin_rights : nullptr); - } break; + }); - case mtpc_channelParticipantBanned: { - auto &data = participant.c_channelParticipantBanned(); - auto user = GenerateUserString(data.vuser_id); - return GenerateBannedChangeText(user, &data.vbanned_rights, (oldType == mtpc_channelParticipantBanned) ? &oldParticipant->c_channelParticipantBanned().vbanned_rights : nullptr); - } break; - } - - Unexpected("Participant type in GenerateParticipantChangeTextInner()"); + return TLHelp::VisitChannelParticipant(participant, readResult); } TextWithEntities GenerateParticipantChangeText(not_null channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant = nullptr) { @@ -339,14 +349,18 @@ void GenerateItems(not_null history, LocalIdManager &idManager, const auto createToggleInvites = [&](const MTPDchannelAdminLogEventActionToggleInvites &action) { auto enabled = (action.vnew_value.type() == mtpc_boolTrue); - auto text = (enabled ? lng_admin_log_invites_enabled : lng_admin_log_invites_disabled)(lt_from, fromLinkText); - addSimpleServiceMessage(text); + auto text = (enabled + ? lng_admin_log_invites_enabled + : lng_admin_log_invites_disabled); + addSimpleServiceMessage(text(lt_from, fromLinkText)); }; auto createToggleSignatures = [&](const MTPDchannelAdminLogEventActionToggleSignatures &action) { auto enabled = (action.vnew_value.type() == mtpc_boolTrue); - auto text = (enabled ? lng_admin_log_signatures_enabled : lng_admin_log_signatures_disabled)(lt_from, fromLinkText); - addSimpleServiceMessage(text); + auto text = (enabled + ? lng_admin_log_signatures_enabled + : lng_admin_log_signatures_disabled); + addSimpleServiceMessage(text(lt_from, fromLinkText)); }; auto createUpdatePinned = [&](const MTPDchannelAdminLogEventActionUpdatePinned &action) { @@ -393,13 +407,17 @@ void GenerateItems(not_null history, LocalIdManager &idManager, const }; auto createParticipantJoin = [&]() { - auto text = (channel->isMegagroup() ? lng_admin_log_participant_joined : lng_admin_log_participant_joined_channel)(lt_from, fromLinkText); - addSimpleServiceMessage(text); + auto text = (channel->isMegagroup() + ? lng_admin_log_participant_joined + : lng_admin_log_participant_joined_channel); + addSimpleServiceMessage(text(lt_from, fromLinkText)); }; auto createParticipantLeave = [&]() { - auto text = (channel->isMegagroup() ? lng_admin_log_participant_left : lng_admin_log_participant_left_channel)(lt_from, fromLinkText); - addSimpleServiceMessage(text); + auto text = (channel->isMegagroup() + ? lng_admin_log_participant_left + : lng_admin_log_participant_left_channel); + addSimpleServiceMessage(text(lt_from, fromLinkText)); }; auto createParticipantInvite = [&](const MTPDchannelAdminLogEventActionParticipantInvite &action) { @@ -448,22 +466,77 @@ void GenerateItems(not_null history, LocalIdManager &idManager, const } }; + auto createTogglePreHistoryHidden = [&](const MTPDchannelAdminLogEventActionTogglePreHistoryHidden &action) { + auto hidden = (action.vnew_value.type() == mtpc_boolTrue); + auto text = (hidden + ? lng_admin_log_history_made_hidden + : lng_admin_log_history_made_visible); + addSimpleServiceMessage(text(lt_from, fromLinkText)); + }; + switch (action.type()) { - case mtpc_channelAdminLogEventActionChangeTitle: createChangeTitle(action.c_channelAdminLogEventActionChangeTitle()); break; - case mtpc_channelAdminLogEventActionChangeAbout: createChangeAbout(action.c_channelAdminLogEventActionChangeAbout()); break; - case mtpc_channelAdminLogEventActionChangeUsername: createChangeUsername(action.c_channelAdminLogEventActionChangeUsername()); break; - case mtpc_channelAdminLogEventActionChangePhoto: createChangePhoto(action.c_channelAdminLogEventActionChangePhoto()); break; - case mtpc_channelAdminLogEventActionToggleInvites: createToggleInvites(action.c_channelAdminLogEventActionToggleInvites()); break; - case mtpc_channelAdminLogEventActionToggleSignatures: createToggleSignatures(action.c_channelAdminLogEventActionToggleSignatures()); break; - case mtpc_channelAdminLogEventActionUpdatePinned: createUpdatePinned(action.c_channelAdminLogEventActionUpdatePinned()); break; - case mtpc_channelAdminLogEventActionEditMessage: createEditMessage(action.c_channelAdminLogEventActionEditMessage()); break; - case mtpc_channelAdminLogEventActionDeleteMessage: createDeleteMessage(action.c_channelAdminLogEventActionDeleteMessage()); break; - case mtpc_channelAdminLogEventActionParticipantJoin: createParticipantJoin(); break; - case mtpc_channelAdminLogEventActionParticipantLeave: createParticipantLeave(); break; - case mtpc_channelAdminLogEventActionParticipantInvite: createParticipantInvite(action.c_channelAdminLogEventActionParticipantInvite()); break; - case mtpc_channelAdminLogEventActionParticipantToggleBan: createParticipantToggleBan(action.c_channelAdminLogEventActionParticipantToggleBan()); break; - case mtpc_channelAdminLogEventActionParticipantToggleAdmin: createParticipantToggleAdmin(action.c_channelAdminLogEventActionParticipantToggleAdmin()); break; - case mtpc_channelAdminLogEventActionChangeStickerSet: createChangeStickerSet(action.c_channelAdminLogEventActionChangeStickerSet()); break; + case mtpc_channelAdminLogEventActionChangeTitle: + createChangeTitle( + action.c_channelAdminLogEventActionChangeTitle()); + break; + case mtpc_channelAdminLogEventActionChangeAbout: + createChangeAbout( + action.c_channelAdminLogEventActionChangeAbout()); + break; + case mtpc_channelAdminLogEventActionChangeUsername: + createChangeUsername( + action.c_channelAdminLogEventActionChangeUsername()); + break; + case mtpc_channelAdminLogEventActionChangePhoto: + createChangePhoto( + action.c_channelAdminLogEventActionChangePhoto()); + break; + case mtpc_channelAdminLogEventActionToggleInvites: + createToggleInvites( + action.c_channelAdminLogEventActionToggleInvites()); + break; + case mtpc_channelAdminLogEventActionToggleSignatures: + createToggleSignatures( + action.c_channelAdminLogEventActionToggleSignatures()); + break; + case mtpc_channelAdminLogEventActionUpdatePinned: + createUpdatePinned( + action.c_channelAdminLogEventActionUpdatePinned()); + break; + case mtpc_channelAdminLogEventActionEditMessage: + createEditMessage( + action.c_channelAdminLogEventActionEditMessage()); + break; + case mtpc_channelAdminLogEventActionDeleteMessage: + createDeleteMessage( + action.c_channelAdminLogEventActionDeleteMessage()); + break; + case mtpc_channelAdminLogEventActionParticipantJoin: + createParticipantJoin(); + break; + case mtpc_channelAdminLogEventActionParticipantLeave: + createParticipantLeave(); + break; + case mtpc_channelAdminLogEventActionParticipantInvite: + createParticipantInvite( + action.c_channelAdminLogEventActionParticipantInvite()); + break; + case mtpc_channelAdminLogEventActionParticipantToggleBan: + createParticipantToggleBan( + action.c_channelAdminLogEventActionParticipantToggleBan()); + break; + case mtpc_channelAdminLogEventActionParticipantToggleAdmin: + createParticipantToggleAdmin( + action.c_channelAdminLogEventActionParticipantToggleAdmin()); + break; + case mtpc_channelAdminLogEventActionChangeStickerSet: + createChangeStickerSet( + action.c_channelAdminLogEventActionChangeStickerSet()); + break; + case mtpc_channelAdminLogEventActionTogglePreHistoryHidden: + createTogglePreHistoryHidden( + action.c_channelAdminLogEventActionTogglePreHistoryHidden()); + break; default: Unexpected("channelAdminLogEventAction type in AdminLog::Item::Item()"); } } diff --git a/Telegram/SourceFiles/history/history_item.cpp b/Telegram/SourceFiles/history/history_item.cpp index d752912559204c..aa33adba06a2a6 100644 --- a/Telegram/SourceFiles/history/history_item.cpp +++ b/Telegram/SourceFiles/history/history_item.cpp @@ -669,6 +669,17 @@ void HistoryItem::finishEditionToEmpty() { } } +bool HistoryItem::isMediaUnread() const { + if (!mentionsMe() && _history->peer->isChannel()) { + auto now = ::date(unixtime()); + auto passed = date.secsTo(now); + if (passed >= Global::ChannelsReadMediaPeriod()) { + return false; + } + } + return _flags & MTPDmessage::Flag::f_media_unread; +} + void HistoryItem::markMediaRead() { _flags &= ~MTPDmessage::Flag::f_media_unread; @@ -862,7 +873,9 @@ bool HistoryItem::canForward() const { bool HistoryItem::canEdit(const QDateTime &cur) const { auto messageToMyself = _history->peer->isSelf(); - auto messageTooOld = messageToMyself ? false : (date.secsTo(cur) >= Global::EditTimeLimit()); + auto messageTooOld = messageToMyself + ? false + : (date.secsTo(cur) >= Global::EditTimeLimit()); if (id < 0 || messageTooOld) { return false; } diff --git a/Telegram/SourceFiles/history/history_item.h b/Telegram/SourceFiles/history/history_item.h index 7d557cf61c21f9..aa2aebe84c8350 100644 --- a/Telegram/SourceFiles/history/history_item.h +++ b/Telegram/SourceFiles/history/history_item.h @@ -591,9 +591,7 @@ class HistoryItem : public HistoryElement, public RuntimeComposer, public ClickH bool mentionsMe() const { return _flags & MTPDmessage::Flag::f_mentioned; } - bool isMediaUnread() const { - return _flags & MTPDmessage::Flag::f_media_unread; - } + bool isMediaUnread() const; void markMediaRead(); // Zero result means this message is not self-destructing right now. diff --git a/Telegram/SourceFiles/history/history_message.cpp b/Telegram/SourceFiles/history/history_message.cpp index 58be62ec0412ce..64ee89b7c07e3d 100644 --- a/Telegram/SourceFiles/history/history_message.cpp +++ b/Telegram/SourceFiles/history/history_message.cpp @@ -951,6 +951,12 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media) { _media = std::make_unique(this, LocationCoords(point.c_geoPoint())); } } break; + case mtpc_messageMediaGeoLive: { + auto &point = media->c_messageMediaGeoLive().vgeo; + if (point.type() == mtpc_geoPoint) { + _media = std::make_unique(this, LocationCoords(point.c_geoPoint())); + } + } break; case mtpc_messageMediaVenue: { auto &d = media->c_messageMediaVenue(); if (d.vgeo.type() == mtpc_geoPoint) { diff --git a/Telegram/SourceFiles/history/history_service.cpp b/Telegram/SourceFiles/history/history_service.cpp index b421e185494297..e78dd620135d38 100644 --- a/Telegram/SourceFiles/history/history_service.cpp +++ b/Telegram/SourceFiles/history/history_service.cpp @@ -163,6 +163,12 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { return result; }; + auto prepareCustomAction = [&](const MTPDmessageActionCustomAction &action) { + auto result = PreparedText {}; + result.text = qs(action.vmessage); + return result; + }; + auto messageText = PreparedText {}; switch (action.type()) { @@ -182,6 +188,7 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) { case mtpc_messageActionPhoneCall: Unexpected("PhoneCall type in HistoryService."); case mtpc_messageActionPaymentSent: messageText = preparePaymentSentText(); break; case mtpc_messageActionScreenshotTaken: messageText = prepareScreenshotTaken(); break; + case mtpc_messageActionCustomAction: messageText = prepareCustomAction(action.c_messageActionCustomAction()); break; default: messageText.text = lang(lng_message_empty); break; } diff --git a/Telegram/SourceFiles/history/history_widget.cpp b/Telegram/SourceFiles/history/history_widget.cpp index cfa32a6e9b17d3..8423699af14936 100644 --- a/Telegram/SourceFiles/history/history_widget.cpp +++ b/Telegram/SourceFiles/history/history_widget.cpp @@ -2280,7 +2280,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages return; } - int32 count = 0; + auto count = 0; const QVector emptyList, *histList = &emptyList; switch (messages.type()) { case mtpc_messages_messages: { @@ -2309,6 +2309,9 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages histList = &d.vmessages.v; count = d.vcount.v; } break; + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (HistoryWidget::messagesReceived)")); + } break; } if (_preloadRequest == requestId) { @@ -2436,7 +2439,7 @@ void HistoryWidget::firstLoadMessages() { if (!_history || _firstLoadRequest) return; auto from = _peer; - auto offset_id = 0; + auto offsetId = 0; auto offset = 0; auto loadCount = kMessagesPerPage; if (_showAtMsgId == ShowAtUnreadMsgId) { @@ -2444,11 +2447,11 @@ void HistoryWidget::firstLoadMessages() { _history->getReadyFor(_showAtMsgId); from = _migrated->peer; offset = -loadCount / 2; - offset_id = _migrated->inboxReadBefore; + offsetId = _migrated->inboxReadBefore; } else if (_history->unreadCount()) { _history->getReadyFor(_showAtMsgId); offset = -loadCount / 2; - offset_id = _history->inboxReadBefore; + offsetId = _history->inboxReadBefore; } else { _history->getReadyFor(ShowAtTheEndMsgId); } @@ -2458,19 +2461,35 @@ void HistoryWidget::firstLoadMessages() { } else if (_showAtMsgId > 0) { _history->getReadyFor(_showAtMsgId); offset = -loadCount / 2; - offset_id = _showAtMsgId; + offsetId = _showAtMsgId; } else if (_showAtMsgId < 0 && _history->isChannel()) { if (_showAtMsgId < 0 && -_showAtMsgId < ServerMaxMsgId && _migrated) { _history->getReadyFor(_showAtMsgId); from = _migrated->peer; offset = -loadCount / 2; - offset_id = -_showAtMsgId; + offsetId = -_showAtMsgId; } else if (_showAtMsgId == SwitchAtTopMsgId) { _history->getReadyFor(_showAtMsgId); } } - _firstLoadRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed)); + auto offsetDate = 0; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + + _firstLoadRequest = MTP::send( + MTPmessages_GetHistory( + from->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(offset), + MTP_int(loadCount), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + rpcDone(&HistoryWidget::messagesReceived, from), + rpcFail(&HistoryWidget::messagesFailed)); } void HistoryWidget::loadMessages() { @@ -2486,11 +2505,28 @@ void HistoryWidget::loadMessages() { return; } - auto offset_id = from->minMsgId(); + auto offsetId = from->minMsgId(); auto offset = 0; - auto loadCount = offset_id ? kMessagesPerPage : kMessagesPerPageFirst; - - _preloadRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed)); + auto loadCount = offsetId + ? kMessagesPerPage + : kMessagesPerPageFirst; + auto offsetDate = 0; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + + _preloadRequest = MTP::send( + MTPmessages_GetHistory( + from->peer->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(offset), + MTP_int(loadCount), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + rpcDone(&HistoryWidget::messagesReceived, from->peer), + rpcFail(&HistoryWidget::messagesFailed)); } void HistoryWidget::loadMessagesDown() { @@ -2500,22 +2536,37 @@ void HistoryWidget::loadMessagesDown() { return firstLoadMessages(); } - bool loadMigrated = _migrated && !(_migrated->isEmpty() || _migrated->loadedAtBottom() || (!_history->isEmpty() && !_history->loadedAtTop())); - History *from = loadMigrated ? _migrated : _history; + auto loadMigrated = _migrated && !(_migrated->isEmpty() || _migrated->loadedAtBottom() || (!_history->isEmpty() && !_history->loadedAtTop())); + auto from = loadMigrated ? _migrated : _history; if (from->loadedAtBottom()) { return; } auto loadCount = kMessagesPerPage; auto offset = -loadCount; - auto offset_id = from->maxMsgId(); - if (!offset_id) { + auto offsetId = from->maxMsgId(); + if (!offsetId) { if (loadMigrated || !_migrated) return; - ++offset_id; + ++offsetId; ++offset; } - - _preloadDownRequest = MTP::send(MTPmessages_GetHistory(from->peer->input, MTP_int(offset_id + 1), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from->peer), rpcFail(&HistoryWidget::messagesFailed)); + auto offsetDate = 0; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + + _preloadDownRequest = MTP::send( + MTPmessages_GetHistory( + from->peer->input, + MTP_int(offsetId + 1), + MTP_int(offsetDate), + MTP_int(offset), + MTP_int(loadCount), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + rpcDone(&HistoryWidget::messagesReceived, from->peer), + rpcFail(&HistoryWidget::messagesFailed)); } void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { @@ -2525,17 +2576,17 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { _delayedShowAtMsgId = showAtMsgId; auto from = _peer; - auto offset_id = 0; + auto offsetId = 0; auto offset = 0; auto loadCount = kMessagesPerPage; if (_delayedShowAtMsgId == ShowAtUnreadMsgId) { if (_migrated && _migrated->unreadCount()) { from = _migrated->peer; offset = -loadCount / 2; - offset_id = _migrated->inboxReadBefore; + offsetId = _migrated->inboxReadBefore; } else if (_history->unreadCount()) { offset = -loadCount / 2; - offset_id = _history->inboxReadBefore; + offsetId = _history->inboxReadBefore; } else { loadCount = kMessagesPerPageFirst; } @@ -2543,16 +2594,31 @@ void HistoryWidget::delayedShowAt(MsgId showAtMsgId) { loadCount = kMessagesPerPageFirst; } else if (_delayedShowAtMsgId > 0) { offset = -loadCount / 2; - offset_id = _delayedShowAtMsgId; + offsetId = _delayedShowAtMsgId; } else if (_delayedShowAtMsgId < 0 && _history->isChannel()) { if (_delayedShowAtMsgId < 0 && -_delayedShowAtMsgId < ServerMaxMsgId && _migrated) { from = _migrated->peer; offset = -loadCount / 2; - offset_id = -_delayedShowAtMsgId; + offsetId = -_delayedShowAtMsgId; } } + auto offsetDate = 0; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; - _delayedShowAtRequest = MTP::send(MTPmessages_GetHistory(from->input, MTP_int(offset_id), MTP_int(0), MTP_int(offset), MTP_int(loadCount), MTP_int(0), MTP_int(0)), rpcDone(&HistoryWidget::messagesReceived, from), rpcFail(&HistoryWidget::messagesFailed)); + _delayedShowAtRequest = MTP::send( + MTPmessages_GetHistory( + from->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(offset), + MTP_int(loadCount), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + rpcDone(&HistoryWidget::messagesReceived, from), + rpcFail(&HistoryWidget::messagesFailed)); } void HistoryWidget::onScroll() { @@ -2709,6 +2775,7 @@ void HistoryWidget::saveEditMsg() { if (!sentEntities.v.isEmpty()) { sendFlags |= MTPmessages_EditMessage::Flag::f_entities; } + _saveEditMsgRequestId = MTP::send( MTPmessages_EditMessage( MTP_flags(sendFlags), @@ -2716,7 +2783,8 @@ void HistoryWidget::saveEditMsg() { MTP_int(_editMsgId), MTP_string(sending.text), MTPnullMarkup, - sentEntities), + sentEntities, + MTP_inputGeoPointEmpty()), rpcDone(&HistoryWidget::saveEditMsgDone, _history), rpcFail(&HistoryWidget::saveEditMsgFail, _history)); } diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp index c4b3af240f7701..c57ea053315351 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_result.cpp @@ -151,6 +151,7 @@ std::unique_ptr Result::create(uint64 queryId, const MTPBotInlineResult } break; case mtpc_botInlineMessageMediaGeo: { + // #TODO layer 72 save period and send live location?.. auto &r = message->c_botInlineMessageMediaGeo(); if (r.vgeo.type() == mtpc_geoPoint) { result->sendData = std::make_unique(r.vgeo.c_geoPoint()); diff --git a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp index ddc059aa718280..d220e7abd2fe26 100644 --- a/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_bot_send_data.cpp @@ -70,7 +70,14 @@ SendDataCommon::SentMTPMessageFields SendGeo::getSentMessageFields() const { SendDataCommon::SentMTPMessageFields SendVenue::getSentMessageFields() const { SentMTPMessageFields result; - result.media = MTP_messageMediaVenue(_location.toMTP(), MTP_string(_title), MTP_string(_address), MTP_string(_provider), MTP_string(_venueId)); + auto venueType = QString(); + result.media = MTP_messageMediaVenue( + _location.toMTP(), + MTP_string(_title), + MTP_string(_address), + MTP_string(_provider), + MTP_string(_venueId), + MTP_string(venueType)); return result; } diff --git a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp index dbf7253e1d7790..ddd1ece42fddd4 100644 --- a/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp +++ b/Telegram/SourceFiles/inline_bots/inline_results_widget.cpp @@ -1021,6 +1021,7 @@ void Widget::inlineResultsDone(const MTPmessages_BotResults &result) { auto it = _inlineCache.find(_inlineQuery); auto adding = (it != _inlineCache.cend()); + // #TODO layer 72 feed users if (result.type() == mtpc_messages_botResults) { auto &d = result.c_messages_botResults(); auto &v = d.vresults.v; diff --git a/Telegram/SourceFiles/mainwidget.cpp b/Telegram/SourceFiles/mainwidget.cpp index 98c0d80ec42dfb..71189e35c05bd9 100644 --- a/Telegram/SourceFiles/mainwidget.cpp +++ b/Telegram/SourceFiles/mainwidget.cpp @@ -1301,7 +1301,24 @@ bool MainWidget::kickParticipantFail(ChatData *chat, const RPCError &error) { } void MainWidget::checkPeerHistory(PeerData *peer) { - MTP::send(MTPmessages_GetHistory(peer->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), rpcDone(&MainWidget::checkedHistory, peer)); + auto offsetId = 0; + auto offsetDate = 0; + auto addOffset = 0; + auto limit = 1; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + MTP::send( + MTPmessages_GetHistory( + peer->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(addOffset), + MTP_int(limit), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + rpcDone(&MainWidget::checkedHistory, peer)); } void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &result) { @@ -1332,10 +1349,13 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu App::feedChats(d.vchats); v = &d.vmessages.v; } break; + + case mtpc_messages_messagesNotModified: { + LOG(("API Error: received messages.messagesNotModified! (MainWidget::checkedHistory)")); + } break; } - if (!v) return; - if (v->isEmpty()) { + if (!v || v->isEmpty()) { if (peer->isChat() && !peer->asChat()->haveLeft()) { auto h = App::historyLoaded(peer->id); if (h) Local::addSavedPeer(peer, h->lastMsgDate); @@ -1353,13 +1373,13 @@ void MainWidget::checkedHistory(PeerData *peer, const MTPmessages_Messages &resu deleteConversation(peer, false); } } else { - History *h = App::history(peer->id); + auto h = App::history(peer->id); if (!h->lastMsg) { h->addNewMessage((*v)[0], NewMessageLast); } if (!h->lastMsgDate.isNull() && h->loadedAtBottom()) { if (peer->isChannel() && peer->asChannel()->inviter > 0 && h->lastMsgDate <= peer->asChannel()->inviteDate && peer->asChannel()->amIn()) { - if (UserData *from = App::userLoaded(peer->asChannel()->inviter)) { + if (auto from = App::userLoaded(peer->asChannel()->inviter)) { h->asChannelHistory()->insertJoinedMessage(true); _history->peerMessagesUpdated(h->peer->id); } @@ -2105,28 +2125,29 @@ void MainWidget::insertCheckedServiceNotification(const TextWithEntities &messag } void MainWidget::serviceHistoryDone(const MTPmessages_Messages &msgs) { + auto handleResult = [&](auto &&result) { + App::feedUsers(result.vusers); + App::feedChats(result.vchats); + App::feedMsgs(result.vmessages, NewMessageLast); + }; + switch (msgs.type()) { - case mtpc_messages_messages: { - auto &d(msgs.c_messages_messages()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageLast); - } break; + case mtpc_messages_messages: + handleResult(msgs.c_messages_messages()); + break; - case mtpc_messages_messagesSlice: { - auto &d(msgs.c_messages_messagesSlice()); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageLast); - } break; + case mtpc_messages_messagesSlice: + handleResult(msgs.c_messages_messagesSlice()); + break; - case mtpc_messages_channelMessages: { - auto &d(msgs.c_messages_channelMessages()); + case mtpc_messages_channelMessages: LOG(("API Error: received messages.channelMessages! (MainWidget::serviceHistoryDone)")); - App::feedUsers(d.vusers); - App::feedChats(d.vchats); - App::feedMsgs(d.vmessages, NewMessageLast); - } break; + handleResult(msgs.c_messages_channelMessages()); + break; + + case mtpc_messages_messagesNotModified: + LOG(("API Error: received messages.messagesNotModified! (MainWidget::serviceHistoryDone)")); + break; } App::wnd()->showDelayedServiceMsgs(); @@ -5170,7 +5191,7 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { case mtpc_updateChannelWebPage: { auto &d = update.c_updateChannelWebPage(); - // update web page anyway + // Update web page anyway. App::feedWebPage(d.vwebpage); _history->updatePreview(); webPagesOrGamesUpdate(); @@ -5453,6 +5474,13 @@ void MainWidget::feedUpdate(const MTPUpdate &update) { } } break; + case mtpc_updateChannelAvailableMessages: { + auto &d = update.c_updateChannelAvailableMessages(); + if (auto channel = App::channelLoaded(d.vchannel_id.v)) { + channel->setAvailableMinId(d.vavailable_min_id.v); + } + } break; + ////// Cloud sticker sets case mtpc_updateNewStickerSet: { auto &d = update.c_updateNewStickerSet(); diff --git a/Telegram/SourceFiles/mainwindow.cpp b/Telegram/SourceFiles/mainwindow.cpp index 93233f1dc622ae..906ee61d18a3d5 100644 --- a/Telegram/SourceFiles/mainwindow.cpp +++ b/Telegram/SourceFiles/mainwindow.cpp @@ -287,12 +287,43 @@ void MainWindow::showDelayedServiceMsgs() { void MainWindow::sendServiceHistoryRequest() { if (!_main || !_main->started() || _delayedServiceMsgs.isEmpty() || _serviceHistoryRequest) return; - UserData *user = App::userLoaded(ServiceUserId); + auto user = App::userLoaded(ServiceUserId); if (!user) { auto userFlags = MTPDuser::Flag::f_first_name | MTPDuser::Flag::f_phone | MTPDuser::Flag::f_status | MTPDuser::Flag::f_verified; - user = App::feedUsers(MTP_vector(1, MTP_user(MTP_flags(userFlags), MTP_int(ServiceUserId), MTPlong(), MTP_string("Telegram"), MTPstring(), MTPstring(), MTP_string("42777"), MTP_userProfilePhotoEmpty(), MTP_userStatusRecently(), MTPint(), MTPstring(), MTPstring(), MTPstring()))); - } - _serviceHistoryRequest = MTP::send(MTPmessages_GetHistory(user->input, MTP_int(0), MTP_int(0), MTP_int(0), MTP_int(1), MTP_int(0), MTP_int(0)), _main->rpcDone(&MainWidget::serviceHistoryDone), _main->rpcFail(&MainWidget::serviceHistoryFail)); + user = App::feedUsers(MTP_vector(1, MTP_user( + MTP_flags(userFlags), + MTP_int(ServiceUserId), + MTPlong(), + MTP_string("Telegram"), + MTPstring(), + MTPstring(), + MTP_string("42777"), + MTP_userProfilePhotoEmpty(), + MTP_userStatusRecently(), + MTPint(), + MTPstring(), + MTPstring(), + MTPstring()))); + } + auto offsetId = 0; + auto offsetDate = 0; + auto addOffset = 0; + auto limit = 1; + auto maxId = 0; + auto minId = 0; + auto historyHash = 0; + _serviceHistoryRequest = MTP::send( + MTPmessages_GetHistory( + user->input, + MTP_int(offsetId), + MTP_int(offsetDate), + MTP_int(addOffset), + MTP_int(limit), + MTP_int(maxId), + MTP_int(minId), + MTP_int(historyHash)), + _main->rpcDone(&MainWidget::serviceHistoryDone), + _main->rpcFail(&MainWidget::serviceHistoryFail)); } void MainWindow::setupMain(const MTPUser *self) { diff --git a/Telegram/SourceFiles/mtproto/config_loader.cpp b/Telegram/SourceFiles/mtproto/config_loader.cpp index 6ac65de5e27ddf..e8ae79ece41ca8 100644 --- a/Telegram/SourceFiles/mtproto/config_loader.cpp +++ b/Telegram/SourceFiles/mtproto/config_loader.cpp @@ -161,6 +161,7 @@ void ConfigLoader::sendSpecialRequest() { void ConfigLoader::specialConfigLoaded(const MTPConfig &result) { Expects(result.type() == mtpc_config); + auto &data = result.c_config(); if (data.vdc_options.v.empty()) { LOG(("MTP Error: config with empty dc_options received!")); diff --git a/Telegram/SourceFiles/mtproto/mtp_instance.cpp b/Telegram/SourceFiles/mtproto/mtp_instance.cpp index 255de3cd28cc73..338253042b9e37 100644 --- a/Telegram/SourceFiles/mtproto/mtp_instance.cpp +++ b/Telegram/SourceFiles/mtproto/mtp_instance.cpp @@ -608,6 +608,7 @@ void Instance::Private::configLoadDone(const MTPConfig &result) { Global::SetStickersFavedLimit(data.vstickers_faved_limit.v); Global::SetPinnedDialogsCountMax(data.vpinned_dialogs_count_max.v); Messenger::Instance().setInternalLinkDomain(qs(data.vme_url_prefix)); + Global::SetChannelsReadMediaPeriod(data.vchannels_read_media_period.v); Global::SetCallReceiveTimeoutMs(data.vcall_receive_timeout_ms.v); Global::SetCallRingTimeoutMs(data.vcall_ring_timeout_ms.v); Global::SetCallConnectTimeoutMs(data.vcall_connect_timeout_ms.v); diff --git a/Telegram/SourceFiles/profile/profile_channel_controllers.cpp b/Telegram/SourceFiles/profile/profile_channel_controllers.cpp index 0f815a2e9af05b..ac18bb556a0ffa 100644 --- a/Telegram/SourceFiles/profile/profile_channel_controllers.cpp +++ b/Telegram/SourceFiles/profile/profile_channel_controllers.cpp @@ -24,6 +24,7 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/edit_participant_box.h" #include "boxes/confirm_box.h" #include "boxes/add_contact_box.h" +#include "core/tl_help.h" #include "auth_session.h" #include "apiwrap.h" #include "lang/lang_keys.h" @@ -443,31 +444,40 @@ void ParticipantsBoxController::loadMoreRows() { return MTP_channelParticipantsBanned(MTP_string(QString())); } return MTP_channelParticipantsKicked(MTP_string(QString())); - }; + }(); // First query is small and fast, next loads a lot of rows. auto perPage = (_offset > 0) ? kParticipantsPerPage : kParticipantsFirstPageCount; - _loadRequestId = request(MTPchannels_GetParticipants(_channel->inputChannel, filter(), MTP_int(_offset), MTP_int(perPage))).done([this](const MTPchannels_ChannelParticipants &result) { - Expects(result.type() == mtpc_channels_channelParticipants); - + auto participantsHash = 0; + + _loadRequestId = request(MTPchannels_GetParticipants( + _channel->inputChannel, + filter, + MTP_int(_offset), + MTP_int(perPage), + MTP_int(participantsHash) + )).done([this](const MTPchannels_ChannelParticipants &result) { auto firstLoad = !_offset; _loadRequestId = 0; - auto &participants = result.c_channels_channelParticipants(); - App::feedUsers(participants.vusers); - - auto &list = participants.vparticipants.v; - if (list.isEmpty()) { - // To be sure - wait for a whole empty result list. - _allLoaded = true; - } else { - for_const (auto &participant, list) { - ++_offset; - HandleParticipant(participant, _role, &_additional, [this](not_null user) { - appendRow(user); - }); + Auth().api().parseChannelParticipants(result, [&]( + int fullCount, + const QVector &list) { + for (auto &participant : list) { + HandleParticipant( + participant, + _role, + &_additional, + [&](auto user) { appendRow(user); }); } - } + if (auto size = list.size()) { + _offset += size; + } else { + // To be sure - wait for a whole empty result list. + _allLoaded = true; + } + }); + if (delegate()->peerListFullRowsCount() > 0) { sortByOnline(); if (firstLoad) { @@ -1009,13 +1019,21 @@ bool ParticipantsBoxSearchController::loadMoreRows() { case Role::Kicked: return MTP_channelParticipantsKicked(MTP_string(_query)); } Unexpected("Role in ParticipantsBoxSearchController::loadMoreRows()"); - }; + }(); // For search we request a lot of rows from the first query. // (because we've waited for search request by timer already, // so we don't expect it to be fast, but we want to fill cache). auto perPage = kParticipantsPerPage; - _requestId = request(MTPchannels_GetParticipants(_channel->inputChannel, filter(), MTP_int(_offset), MTP_int(perPage))).done([this, perPage](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + auto participantsHash = 0; + + _requestId = request(MTPchannels_GetParticipants( + _channel->inputChannel, + filter, + MTP_int(_offset), + MTP_int(perPage), + MTP_int(participantsHash) + )).done([this, perPage](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { searchDone(requestId, result, perPage); }).fail([this](const RPCError &error, mtpRequestId requestId) { if (_requestId == requestId) { @@ -1033,28 +1051,34 @@ bool ParticipantsBoxSearchController::loadMoreRows() { return true; } -void ParticipantsBoxSearchController::searchDone(mtpRequestId requestId, const MTPchannels_ChannelParticipants &result, int requestedCount) { - Expects(result.type() == mtpc_channels_channelParticipants); - - auto &participants = result.c_channels_channelParticipants(); +void ParticipantsBoxSearchController::searchDone( + mtpRequestId requestId, + const MTPchannels_ChannelParticipants &result, + int requestedCount) { auto query = _query; if (requestId) { - App::feedUsers(participants.vusers); - auto it = _queries.find(requestId); - if (it != _queries.cend()) { - query = it->second.text; - if (it->second.offset == 0) { - auto &entry = _cache[query]; - entry.result = result; - entry.requestedCount = requestedCount; + Auth().api().parseChannelParticipants(result, [&](auto&&...) { + auto it = _queries.find(requestId); + if (it != _queries.cend()) { + query = it->second.text; + if (it->second.offset == 0) { + auto &entry = _cache[query]; + entry.result = result; + entry.requestedCount = requestedCount; + } + _queries.erase(it); } - _queries.erase(it); - } + }); } - if (_requestId == requestId) { - _requestId = 0; - auto &list = participants.vparticipants.v; + if (_requestId != requestId) { + return; + } + + _requestId = 0; + TLHelp::VisitChannelParticipants(result, ranges::overload([&]( + const MTPDchannels_channelParticipants &data) { + auto &list = data.vparticipants.v; if (list.size() < requestedCount) { // We want cache to have full information about a query with small // results count (if we don't need the second request). So we don't @@ -1068,8 +1092,11 @@ void ParticipantsBoxSearchController::searchDone(mtpRequestId requestId, const M }); } _offset += list.size(); - delegate()->peerListSearchRefreshRows(); - } + }, [&](mtpTypeId type) { + _allLoaded = true; + })); + + delegate()->peerListSearchRefreshRows(); } AddParticipantBoxController::AddParticipantBoxController(not_null channel, Role role, AdminDoneCallback adminDoneCallback, BannedDoneCallback bannedDoneCallback) : PeerListController(std::make_unique(channel, &_additional)) @@ -1120,26 +1147,34 @@ void AddParticipantBoxController::loadMoreRows() { // First query is small and fast, next loads a lot of rows. auto perPage = (_offset > 0) ? kParticipantsPerPage : kParticipantsFirstPageCount; - _loadRequestId = request(MTPchannels_GetParticipants(_channel->inputChannel, MTP_channelParticipantsRecent(), MTP_int(_offset), MTP_int(perPage))).done([this](const MTPchannels_ChannelParticipants &result) { - Expects(result.type() == mtpc_channels_channelParticipants); - + auto participantsHash = 0; + + _loadRequestId = request(MTPchannels_GetParticipants( + _channel->inputChannel, + MTP_channelParticipantsRecent(), + MTP_int(_offset), + MTP_int(perPage), + MTP_int(participantsHash) + )).done([this](const MTPchannels_ChannelParticipants &result) { _loadRequestId = 0; - auto &participants = result.c_channels_channelParticipants(); - App::feedUsers(participants.vusers); - - auto &list = participants.vparticipants.v; - if (list.isEmpty()) { - // To be sure - wait for a whole empty result list. - _allLoaded = true; - } else { - for_const (auto &participant, list) { - ++_offset; - HandleParticipant(participant, &_additional, [this](not_null user) { - appendRow(user); - }); + Auth().api().parseChannelParticipants(result, [&]( + int fullCount, + const QVector &list) { + for (auto &participant : list) { + HandleParticipant( + participant, + &_additional, + [this](auto user) { appendRow(user); }); } - } + if (auto size = list.size()) { + _offset += size; + } else { + // To be sure - wait for a whole empty result list. + _allLoaded = true; + } + }); + if (delegate()->peerListFullRowsCount() > 0) { setDescriptionText(QString()); } else if (_allLoaded) { @@ -1632,7 +1667,15 @@ void AddParticipantBoxSearchController::requestParticipants() { // (because we've waited for search request by timer already, // so we don't expect it to be fast, but we want to fill cache). auto perPage = kParticipantsPerPage; - _requestId = request(MTPchannels_GetParticipants(_channel->inputChannel, MTP_channelParticipantsSearch(MTP_string(_query)), MTP_int(_offset), MTP_int(perPage))).done([this, perPage](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { + auto participantsHash = 0; + + _requestId = request(MTPchannels_GetParticipants( + _channel->inputChannel, + MTP_channelParticipantsSearch(MTP_string(_query)), + MTP_int(_offset), + MTP_int(perPage), + MTP_int(participantsHash) + )).done([this, perPage](const MTPchannels_ChannelParticipants &result, mtpRequestId requestId) { searchParticipantsDone(requestId, result, perPage); }).fail([this](const RPCError &error, mtpRequestId requestId) { if (_requestId == requestId) { @@ -1649,27 +1692,29 @@ void AddParticipantBoxSearchController::requestParticipants() { } void AddParticipantBoxSearchController::searchParticipantsDone(mtpRequestId requestId, const MTPchannels_ChannelParticipants &result, int requestedCount) { - Expects(result.type() == mtpc_channels_channelParticipants); - - auto &participants = result.c_channels_channelParticipants(); auto query = _query; if (requestId) { - App::feedUsers(participants.vusers); - auto it = _participantsQueries.find(requestId); - if (it != _participantsQueries.cend()) { - query = it->second.text; - if (it->second.offset == 0) { - auto &entry = _participantsCache[query]; - entry.result = result; - entry.requestedCount = requestedCount; + Auth().api().parseChannelParticipants(result, [&](auto&&...) { + auto it = _participantsQueries.find(requestId); + if (it != _participantsQueries.cend()) { + query = it->second.text; + if (it->second.offset == 0) { + auto &entry = _participantsCache[query]; + entry.result = result; + entry.requestedCount = requestedCount; + } + _participantsQueries.erase(it); } - _participantsQueries.erase(it); - } + }); } - if (_requestId == requestId) { - _requestId = 0; - auto &list = participants.vparticipants.v; + if (_requestId != requestId) { + return; + } + _requestId = 0; + TLHelp::VisitChannelParticipants(result, ranges::overload([&]( + const MTPDchannels_channelParticipants &data) { + auto &list = data.vparticipants.v; if (list.size() < requestedCount) { // We want cache to have full information about a query with small // results count (if we don't need the second request). So we don't @@ -1680,14 +1725,21 @@ void AddParticipantBoxSearchController::searchParticipantsDone(mtpRequestId requ loadMoreRows(); } } - for_const (auto &participant, list) { - AddParticipantBoxController::HandleParticipant(participant, _additional, [this](not_null user) { - delegate()->peerListSearchAddRow(user); - }); + auto addUser = [&](auto user) { + delegate()->peerListSearchAddRow(user); + }; + for (auto &participant : list) { + AddParticipantBoxController::HandleParticipant( + participant, + _additional, + addUser); } _offset += list.size(); - delegate()->peerListSearchRefreshRows(); - } + }, [&](mtpTypeId type) { + _participantsLoaded = true; + })); + + delegate()->peerListSearchRefreshRows(); } void AddParticipantBoxSearchController::requestGlobal() { diff --git a/Telegram/SourceFiles/storage/localstorage.cpp b/Telegram/SourceFiles/storage/localstorage.cpp index 6aaf0d9ae6d8c2..51e1dfba4afc02 100644 --- a/Telegram/SourceFiles/storage/localstorage.cpp +++ b/Telegram/SourceFiles/storage/localstorage.cpp @@ -4011,7 +4011,7 @@ uint32 _peerSize(PeerData *peer) { void _writePeer(QDataStream &stream, PeerData *peer) { stream << quint64(peer->id) << quint64(peer->photoId); - Serialize::writeStorageImageLocation(stream, peer->photoLoc); + Serialize::writeStorageImageLocation(stream, peer->userpicLocation()); if (peer->isUser()) { UserData *user = peer->asUser(); @@ -4040,7 +4040,7 @@ PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { quint64 peerId = 0, photoId = 0; from.stream >> peerId >> photoId; - StorageImageLocation photoLoc(Serialize::readStorageImageLocation(from.stream)); + auto photoLoc = Serialize::readStorageImageLocation(from.stream); PeerData *result = App::peerLoaded(peerId); bool wasLoaded = (result != nullptr); @@ -4087,7 +4087,9 @@ PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { user->inputUser = MTP_inputUser(MTP_int(peerToUser(user->id)), MTP_long(user->accessHash())); } - user->setUserpic(photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc)); + user->setUserpic( + photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc), + photoLoc); } } else if (result->isChat()) { ChatData *chat = result->asChat(); @@ -4120,7 +4122,9 @@ PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { chat->input = MTP_inputPeerChat(MTP_int(peerToChat(chat->id))); chat->inputChat = MTP_int(peerToChat(chat->id)); - chat->setUserpic(photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc)); + chat->setUserpic( + photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc), + photoLoc); } } else if (result->isChannel()) { ChannelData *channel = result->asChannel(); @@ -4144,7 +4148,9 @@ PeerData *_readPeer(FileReadDescriptor &from, int32 fileVersion = 0) { channel->input = MTP_inputPeerChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); channel->inputChannel = MTP_inputChannel(MTP_int(peerToChannel(channel->id)), MTP_long(access)); - channel->setUserpic(photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc)); + channel->setUserpic( + photoLoc.isNull() ? ImagePtr() : ImagePtr(photoLoc), + photoLoc); } } return result; diff --git a/Telegram/SourceFiles/window/window_peer_menu.cpp b/Telegram/SourceFiles/window/window_peer_menu.cpp index 705023a27f3cfb..62de9863e10935 100644 --- a/Telegram/SourceFiles/window/window_peer_menu.cpp +++ b/Telegram/SourceFiles/window/window_peer_menu.cpp @@ -27,14 +27,13 @@ Copyright (c) 2014-2017 John Preston, https://desktop.telegram.org #include "boxes/report_box.h" #include "boxes/peer_list_controllers.h" #include "boxes/peers/manage_peer_box.h" +#include "core/tl_help.h" #include "auth_session.h" #include "apiwrap.h" #include "mainwidget.h" #include "observer_peer.h" #include "styles/style_boxes.h" #include "window/window_controller.h" -#include -#include namespace Window { namespace { @@ -500,44 +499,23 @@ void PeerMenuAddChannelMembers(not_null channel) { return; } auto callback = [channel](const MTPchannels_ChannelParticipants &result) { - Expects(result.type() == mtpc_channels_channelParticipants); - - auto &participants = result.c_channels_channelParticipants(); - App::feedUsers(participants.vusers); - - auto applyToParticipant = []( - const MTPChannelParticipant &p, - auto &&method) { - switch (p.type()) { - case mtpc_channelParticipant: - return method(p.c_channelParticipant()); - case mtpc_channelParticipantSelf: - return method(p.c_channelParticipantSelf()); - case mtpc_channelParticipantAdmin: - return method(p.c_channelParticipantAdmin()); - case mtpc_channelParticipantCreator: - return method(p.c_channelParticipantCreator()); - case mtpc_channelParticipantBanned: - return method(p.c_channelParticipantBanned()); - default: Unexpected("Type in PeerMenuAddChannelMembers()"); - } - }; - - auto already = ( - participants.vparticipants.v - ) | ranges::view::transform([&](auto &&participant) { - return applyToParticipant(participant, [](auto &&data) { - return data.vuser_id.v; + Auth().api().parseChannelParticipants(result, [&]( + int fullCount, + const QVector &list) { + auto already = ( + list + ) | ranges::view::transform([&](auto &&p) { + return TLHelp::ReadChannelParticipantUserId(p); + }) | ranges::view::transform([](UserId userId) { + return App::userLoaded(userId); + }) | ranges::view::filter([](UserData *user) { + return (user != nullptr); }); - }) | ranges::view::transform([](UserId userId) { - return App::userLoaded(userId); - }) | ranges::view::filter([](UserData *user) { - return (user != nullptr); - }) | ranges::to_vector; - AddParticipantsBoxController::Start( - channel, - { already.begin(), already.end() }); + AddParticipantsBoxController::Start( + channel, + { already.begin(), already.end() }); + }); }; Auth().api().requestChannelMembersForAdd(channel, callback); } diff --git a/Telegram/gyp/telegram_sources.txt b/Telegram/gyp/telegram_sources.txt index 476bb0ff336268..72aa165054d362 100644 --- a/Telegram/gyp/telegram_sources.txt +++ b/Telegram/gyp/telegram_sources.txt @@ -144,6 +144,7 @@ <(src_loc)/core/file_utilities.h <(src_loc)/core/single_timer.cpp <(src_loc)/core/single_timer.h +<(src_loc)/core/tl_help.h <(src_loc)/core/utils.cpp <(src_loc)/core/utils.h <(src_loc)/core/version.h