Minimal layer 72 support.

This commit is contained in:
John Preston 2017-11-20 23:54:05 +04:00
parent bccd801874
commit 6ca105a290
33 changed files with 917 additions and 350 deletions

View File

@ -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:";

View File

@ -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<MTPChannelParticipant> &list) {
applyLastParticipantsList(
peer,
fullCount,
list,
bots,
fromStart);
});
}
void ApiWrap::applyLastParticipantsList(
ChannelData *peer,
int fullCount,
const QVector<MTPChannelParticipant> &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<void(int fullCount, const QVector<MTPChannelParticipant> &list)> callbackList,
base::lambda<void()> 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<PeerData*> 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<int>(QDateTime(date).toTime_t()) - 1;
auto add_offset = -1;
auto offsetId = 0;
auto offsetDate = static_cast<int>(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<MTPMessage>* {
auto handleMessages = [](auto &messages) {
App::feedUsers(messages.vusers);
@ -1809,17 +1880,22 @@ void ApiWrap::jumpToDate(not_null<PeerData*> 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;
};

View File

@ -141,6 +141,11 @@ public:
}
void readFeaturedSetDelayed(uint64 setId);
void parseChannelParticipants(
const MTPchannels_ChannelParticipants &result,
base::lambda<void(int fullCount, const QVector<MTPChannelParticipant> &list)> callbackList,
base::lambda<void()> callbackNotModified = nullptr);
~ApiWrap();
private:
@ -167,7 +172,16 @@ private:
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<MTPChannelParticipant> &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);

View File

@ -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) {

View File

@ -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) {

View File

@ -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;

View File

@ -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 <typename Callback>
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 <typename Callback>
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

View File

@ -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<PeerClickHandler>(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<UserData*> user) const {
// Duplicated in ParticipantsBoxController::canEditAdmin :(
if (mgInfo) {

View File

@ -225,7 +225,7 @@ public:
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 @@ public:
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 @@ protected:
ImagePtr _userpic;
mutable EmptyUserpic _userpicEmpty;
StorageImageLocation _userpicLocation;
private:
void fillNames();
@ -1092,6 +1100,11 @@ public:
}
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 @@ private:
int _adminsCount = 1;
int _restrictedCount = 0;
int _kickedCount = 0;
MsgId _availableMinId = 0;
AdminRightFlags _adminRights;
RestrictionFlags _restrictions;

View File

@ -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<MTPMessage>*)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)) {

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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<MTPMessage> *v = 0;
auto v = (const QVector<MTPMessage>*)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<MediaOverviewType>(overviewIndex));
auto slice = std::vector<MsgId>();
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);
}
}
}
}

View File

@ -221,6 +221,7 @@ public:
bool isDisplayedEmpty() const;
void clear(bool leaveItems = false);
void clearUpTill(MsgId availableMinId);
virtual ~History();

View File

@ -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<MTPChannelParticipant> &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<UserData*> 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();
}
});

View File

@ -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<ChannelData*> channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant) {
auto GenerateParticipantChangeTextInner(
not_null<ChannelData*> 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<ChannelData*> channel, const MTPChannelParticipant &participant, const MTPChannelParticipant *oldParticipant = nullptr) {
@ -339,14 +349,18 @@ void GenerateItems(not_null<History*> 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*> 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*> 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()");
}
}

View File

@ -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;
}

View File

@ -591,9 +591,7 @@ public:
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.

View File

@ -951,6 +951,12 @@ void HistoryMessage::initMedia(const MTPMessageMedia *media) {
_media = std::make_unique<HistoryLocation>(this, LocationCoords(point.c_geoPoint()));
}
} break;
case mtpc_messageMediaGeoLive: {
auto &point = media->c_messageMediaGeoLive().vgeo;
if (point.type() == mtpc_geoPoint) {
_media = std::make_unique<HistoryLocation>(this, LocationCoords(point.c_geoPoint()));
}
} break;
case mtpc_messageMediaVenue: {
auto &d = media->c_messageMediaVenue();
if (d.vgeo.type() == mtpc_geoPoint) {

View File

@ -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;
}

View File

@ -2280,7 +2280,7 @@ void HistoryWidget::messagesReceived(PeerData *peer, const MTPmessages_Messages
return;
}
int32 count = 0;
auto count = 0;
const QVector<MTPMessage> 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;
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(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));
_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;
}
auto offsetDate = 0;
auto maxId = 0;
auto minId = 0;
auto historyHash = 0;
_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));
_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));
}

View File

@ -151,6 +151,7 @@ std::unique_ptr<Result> 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<internal::SendGeo>(r.vgeo.c_geoPoint());

View File

@ -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;
}

View File

@ -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;

View File

@ -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;
}
if (!v) return;
if (v->isEmpty()) {
case mtpc_messages_messagesNotModified: {
LOG(("API Error: received messages.messagesNotModified! (MainWidget::checkedHistory)"));
} break;
}
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();

View File

@ -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<MTPUser>(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())));
user = App::feedUsers(MTP_vector<MTPUser>(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));
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) {

View File

@ -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!"));

View File

@ -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);

View File

@ -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<UserData*> user) {
appendRow(user);
});
Auth().api().parseChannelParticipants(result, [&](
int fullCount,
const QVector<MTPChannelParticipant> &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<ChannelData*> channel, Role role, AdminDoneCallback adminDoneCallback, BannedDoneCallback bannedDoneCallback) : PeerListController(std::make_unique<AddParticipantBoxSearchController>(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<UserData*> user) {
appendRow(user);
});
Auth().api().parseChannelParticipants(result, [&](
int fullCount,
const QVector<MTPChannelParticipant> &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<UserData*> 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() {

View File

@ -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;

View File

@ -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 <range/v3/view/transform.hpp>
#include <range/v3/view/filter.hpp>
namespace Window {
namespace {
@ -500,44 +499,23 @@ void PeerMenuAddChannelMembers(not_null<ChannelData*> 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<MTPChannelParticipant> &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);
}

View File

@ -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