mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2025-06-03 21:54:05 +02:00
Unify message sending, track forum topic icons.
This commit is contained in:
parent
3b3792ef75
commit
9f652b0d3f
29 changed files with 477 additions and 259 deletions
|
@ -192,7 +192,7 @@ messageActionChatJoinedByRequest#ebbca3cb = MessageAction;
|
|||
messageActionWebViewDataSentMe#47dd8079 text:string data:string = MessageAction;
|
||||
messageActionWebViewDataSent#b4c38cb5 text:string = MessageAction;
|
||||
messageActionGiftPremium#aba0f5c6 currency:string amount:long months:int = MessageAction;
|
||||
messageActionTopicCreate#4619708d title:string = MessageAction;
|
||||
messageActionTopicCreate#6fa796ac flags:# title:string icon_emoji_id:flags.0?long = MessageAction;
|
||||
messageActionTopicEditTitle#ce0b23cd title:string = MessageAction;
|
||||
messageActionTopicEditIcon#820a6e2b emoji_document_id:long = MessageAction;
|
||||
|
||||
|
@ -1856,7 +1856,7 @@ channels.deleteParticipantHistory#367544db channel:InputChannel participant:Inpu
|
|||
channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates;
|
||||
channels.createForumTopic#21289f15 flags:# no_webpage:flags.3?true channel:InputChannel title:string icon_emoji_id:flags.3?long media:flags.0?InputMedia message:string random_id:long entities:flags.1?Vector<MessageEntity> send_as:flags.2?InputPeer = Updates;
|
||||
channels.createForumTopic#60bf3bc9 flags:# channel:InputChannel title:string icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates;
|
||||
channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics;
|
||||
channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector<int> = messages.ForumTopics;
|
||||
channels.editForumTitle#8881b9b1 channel:InputChannel topic_id:int title:string = Updates;
|
||||
|
|
|
@ -65,47 +65,40 @@ void Polls::create(
|
|||
sendFlags |= MTPmessages_SendMedia::Flag::f_send_as;
|
||||
}
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto replyTo = action.replyTo;
|
||||
history->sendRequestId = _api.request(MTPmessages_SendMedia(
|
||||
const auto replyTo = action.replyTo;
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
PollDataToInputMedia(&data),
|
||||
MTP_string(),
|
||||
MTP_long(base::RandomValue<uint64>()),
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) mutable {
|
||||
_session->updates().applyUpdates(result);
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
done();
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) mutable {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
fail();
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
_session->changes().historyUpdated(
|
||||
history,
|
||||
(action.options.scheduled
|
||||
? Data::HistoryUpdate::Flag::ScheduledSent
|
||||
: Data::HistoryUpdate::Flag::MessageSent));
|
||||
done();
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
fail();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -141,12 +141,14 @@ void SendExistingMedia(
|
|||
caption,
|
||||
HistoryMessageMarkupData());
|
||||
|
||||
auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
const auto performRequest = [=](const auto &repeatRequest) -> void {
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto usedFileReference = media->fileReference();
|
||||
history->sendRequestId = api->request(MTPmessages_SendMedia(
|
||||
const auto usedFileReference = media->fileReference();
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
|
@ -157,26 +159,20 @@ void SendExistingMedia(
|
|||
sentEntities,
|
||||
MTP_int(message.action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result, randomId);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (error.code() == 400
|
||||
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
|
||||
api->refreshFileReference(origin, [=](const auto &result) {
|
||||
if (media->fileReference() != usedFileReference) {
|
||||
repeatRequest(repeatRequest);
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (error.code() == 400
|
||||
&& error.type().startsWith(qstr("FILE_REFERENCE_"))) {
|
||||
api->refreshFileReference(origin, [=](const auto &result) {
|
||||
if (media->fileReference() != usedFileReference) {
|
||||
repeatRequest(repeatRequest);
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
});
|
||||
};
|
||||
performRequest(performRequest);
|
||||
|
@ -314,10 +310,11 @@ bool SendDice(MessageToSend &message) {
|
|||
TextWithEntities(),
|
||||
MTP_messageMediaDice(MTP_int(0), MTP_string(emoji)),
|
||||
HistoryMessageMarkupData());
|
||||
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = api->request(MTPmessages_SendMedia(
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMedia(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
|
@ -328,15 +325,9 @@ bool SendDice(MessageToSend &message) {
|
|||
MTP_vector<MTPMessageEntity>(),
|
||||
MTP_int(message.action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result, randomId);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
api->sendMessageFail(error, peer, randomId, newId);
|
||||
});
|
||||
api->finishForwarding(message.action);
|
||||
return true;
|
||||
|
|
|
@ -3479,53 +3479,47 @@ void ApiWrap::sendMessage(MessageToSend &&message) {
|
|||
sendFlags |= MTPmessages_SendMessage::Flag::f_schedule_date;
|
||||
}
|
||||
const auto viaBotId = UserId();
|
||||
const auto replyTo = action.replyTo;
|
||||
lastMessage = history->addNewLocalMessage(
|
||||
newId.msg,
|
||||
flags,
|
||||
viaBotId,
|
||||
action.replyTo,
|
||||
replyTo,
|
||||
HistoryItem::NewMessageDate(action.options.scheduled),
|
||||
messageFromId,
|
||||
messagePostAuthor,
|
||||
sending,
|
||||
media,
|
||||
HistoryMessageMarkupData());
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendMessage(
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMessage(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(action.replyTo),
|
||||
MTP_int(replyTo),
|
||||
msgText,
|
||||
MTP_long(randomId),
|
||||
MTPReplyMarkup(),
|
||||
sentEntities,
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) {
|
||||
applyUpdates(result, randomId);
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) {
|
||||
if (error.type() == qstr("MESSAGE_EMPTY")) {
|
||||
lastMessage->destroy();
|
||||
} else {
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (error.type() == qstr("MESSAGE_EMPTY")) {
|
||||
lastMessage->destroy();
|
||||
} else {
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
}
|
||||
if (clearCloudDraft) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3639,34 +3633,27 @@ void ApiWrap::sendInlineResult(
|
|||
history->startSavingCloudDraft();
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
history->sendRequestId = request(MTPmessages_SendInlineBotResult(
|
||||
const auto replyTo = action.replyTo;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendInlineBotResult(
|
||||
MTP_flags(sendFlags),
|
||||
peer->input,
|
||||
MTP_int(action.replyTo),
|
||||
MTP_int(replyTo),
|
||||
MTP_long(randomId),
|
||||
MTP_long(data->getQueryId()),
|
||||
MTP_string(data->getId()),
|
||||
MTP_int(action.options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) {
|
||||
applyUpdates(result, randomId);
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) {
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
finish();
|
||||
}).afterRequest(history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
sendMessageFail(error, peer, randomId, newId);
|
||||
history->finishSavingCloudDraft(
|
||||
UnixtimeFromMsgId(response.outerMsgId));
|
||||
});
|
||||
finishForwarding(action);
|
||||
}
|
||||
|
@ -3792,11 +3779,13 @@ void ApiWrap::sendMediaWithRandomId(
|
|||
: MTPmessages_SendMedia::Flag(0));
|
||||
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto peer = history->peer;
|
||||
const auto itemId = item->fullId();
|
||||
history->sendRequestId = request(MTPmessages_SendMedia(
|
||||
const auto peer = history->peer;
|
||||
const auto itemId = item->fullId();
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMedia(
|
||||
MTP_flags(flags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
|
@ -3807,20 +3796,12 @@ void ApiWrap::sendMediaWithRandomId(
|
|||
sentEntities,
|
||||
MTP_int(options.scheduled),
|
||||
(options.sendAs ? options.sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
applyUpdates(result);
|
||||
finish();
|
||||
|
||||
if (updateRecentStickers) {
|
||||
requestRecentStickersForce(true);
|
||||
}
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
if (updateRecentStickers) {
|
||||
requestRecentStickersForce(true);
|
||||
}
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
sendMessageFail(error, peer, randomId, itemId);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3904,33 +3885,28 @@ void ApiWrap::sendAlbumIfReady(not_null<SendingAlbum*> album) {
|
|||
? MTPmessages_SendMultiMedia::Flag::f_send_as
|
||||
: MTPmessages_SendMultiMedia::Flag(0));
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto peer = history->peer;
|
||||
history->sendRequestId = request(MTPmessages_SendMultiMedia(
|
||||
const auto peer = history->peer;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
uint64(0), // randomId
|
||||
MTPmessages_SendMultiMedia(
|
||||
MTP_flags(flags),
|
||||
peer->input,
|
||||
MTP_int(replyTo),
|
||||
MTP_vector<MTPInputSingleMedia>(medias),
|
||||
MTP_int(album->options.scheduled),
|
||||
(sendAs ? sendAs->input : MTP_inputPeerEmpty())
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
_sendingAlbums.remove(groupId);
|
||||
applyUpdates(result);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
if (const auto album = _sendingAlbums.take(groupId)) {
|
||||
for (const auto &item : (*album)->items) {
|
||||
sendMessageFail(error, peer, item.randomId, item.msgId);
|
||||
}
|
||||
} else {
|
||||
sendMessageFail(error, peer);
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
_sendingAlbums.remove(groupId);
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
if (const auto album = _sendingAlbums.take(groupId)) {
|
||||
for (const auto &item : (*album)->items) {
|
||||
sendMessageFail(error, peer, item.randomId, item.msgId);
|
||||
}
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
} else {
|
||||
sendMessageFail(error, peer);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -63,11 +63,13 @@ void ShareBotGame(
|
|||
const QString &shortName) {
|
||||
const auto history = chat->owner().history(chat);
|
||||
auto &histories = history->owner().histories();
|
||||
const auto requestType = Data::Histories::RequestType::Send;
|
||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
const auto api = &chat->session().api();
|
||||
history->sendRequestId = api->request(MTPmessages_SendMedia(
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
const auto replyTo = 0;
|
||||
histories.sendPreparedMessage(
|
||||
history,
|
||||
replyTo,
|
||||
randomId,
|
||||
MTPmessages_SendMedia(
|
||||
MTP_flags(0),
|
||||
chat->input,
|
||||
MTP_int(0),
|
||||
|
@ -81,16 +83,9 @@ void ShareBotGame(
|
|||
MTPVector<MTPMessageEntity>(),
|
||||
MTP_int(0), // schedule_date
|
||||
MTPInputPeer() // send_as
|
||||
)).done([=](const MTPUpdates &result) {
|
||||
api->applyUpdates(result, randomId);
|
||||
finish();
|
||||
}).fail([=](const MTP::Error &error) {
|
||||
api->sendMessageFail(error, chat);
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
), [=](const MTPUpdates &result, const MTP::Response &response) {
|
||||
}, [=](const MTP::Error &error, const MTP::Response &response) {
|
||||
chat->session().api().sendMessageFail(error, chat);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "main/main_session.h"
|
||||
#include "history/history.h"
|
||||
#include "history/view/history_view_replies_section.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "info/profile/info_profile_emoji_status_panel.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
@ -142,9 +143,16 @@ void EditForumTopicBox(
|
|||
box->closeBox();
|
||||
return;
|
||||
} else if (title->getLastText().trimmed().isEmpty()) {
|
||||
title->setFocus();
|
||||
title->showError();
|
||||
return;
|
||||
}
|
||||
controller->showSection(
|
||||
std::make_shared<HistoryView::RepliesMemento>(
|
||||
forum,
|
||||
forum->peer->forum()->reserveCreatingId(
|
||||
title->getLastText().trimmed(),
|
||||
state->iconId)),
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
#if 0 // #TODO forum create
|
||||
const auto randomId = base::RandomValue<uint64>();
|
||||
const auto api = &forum->session().api();
|
||||
|
@ -178,7 +186,7 @@ void EditForumTopicBox(
|
|||
const auto api = &forum->session().api();
|
||||
if (state->titleRequestId <= 0) {
|
||||
if (title->getLastText().trimmed().isEmpty()) {
|
||||
title->setFocus();
|
||||
title->showError();
|
||||
return;
|
||||
}
|
||||
state->titleRequestId = api->request(MTPchannels_EditForumTitle(
|
||||
|
|
|
@ -120,17 +120,24 @@ void Forum::applyReceivedTopics(
|
|||
}
|
||||
}
|
||||
|
||||
void Forum::applyTopicAdded(MsgId rootId, const QString &title) {
|
||||
void Forum::applyTopicAdded(
|
||||
MsgId rootId,
|
||||
const QString &title,
|
||||
DocumentId iconId) {
|
||||
if (const auto i = _topics.find(rootId); i != end(_topics)) {
|
||||
i->second->applyTitle(title);
|
||||
i->second->applyIconId(iconId);
|
||||
} else {
|
||||
const auto raw = _topics.emplace(
|
||||
rootId,
|
||||
std::make_unique<ForumTopic>(_history, rootId)
|
||||
).first->second.get();
|
||||
raw->applyTitle(title);
|
||||
raw->addToChatList(FilterId(), topicsList());
|
||||
_chatsListChanges.fire({});
|
||||
raw->applyIconId(iconId);
|
||||
if (!creating(rootId)) {
|
||||
raw->addToChatList(FilterId(), topicsList());
|
||||
_chatsListChanges.fire({});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -140,6 +147,30 @@ void Forum::applyTopicRemoved(MsgId rootId) {
|
|||
//}
|
||||
}
|
||||
|
||||
MsgId Forum::reserveCreatingId(
|
||||
const QString &title,
|
||||
DocumentId iconId) {
|
||||
const auto result = _history->owner().nextLocalMessageId();
|
||||
_creatingRootIds.emplace(result);
|
||||
applyTopicAdded(result, title, iconId);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Forum::discardCreatingId(MsgId rootId) {
|
||||
Expects(creating(rootId));
|
||||
|
||||
const auto i = _topics.find(rootId);
|
||||
if (i != end(_topics)) {
|
||||
Assert(!i->second->inChatList());
|
||||
_topics.erase(i);
|
||||
}
|
||||
_creatingRootIds.remove(rootId);
|
||||
}
|
||||
|
||||
bool Forum::creating(MsgId rootId) const {
|
||||
return _creatingRootIds.contains(rootId);
|
||||
}
|
||||
|
||||
ForumTopic *Forum::topicFor(not_null<HistoryItem*> item) {
|
||||
return topicFor(item->topicRootId());
|
||||
}
|
||||
|
@ -151,7 +182,7 @@ ForumTopic *Forum::topicFor(MsgId rootId) {
|
|||
}
|
||||
} else {
|
||||
// #TODO forum lang
|
||||
applyTopicAdded(rootId, "General! Created.");
|
||||
applyTopicAdded(rootId, "General! Created.", DocumentId(0));
|
||||
return _topics.find(rootId)->second.get();
|
||||
}
|
||||
return nullptr;
|
||||
|
|
|
@ -31,13 +31,22 @@ public:
|
|||
[[nodiscard]] rpl::producer<> chatsListChanges() const;
|
||||
[[nodiscard]] rpl::producer<> chatsListLoadedEvents() const;
|
||||
|
||||
void applyTopicAdded(MsgId rootId, const QString &title);
|
||||
void applyTopicAdded(
|
||||
MsgId rootId,
|
||||
const QString &title,
|
||||
DocumentId iconId);
|
||||
void applyTopicRemoved(MsgId rootId);
|
||||
[[nodiscard]] ForumTopic *topicFor(not_null<HistoryItem*> item);
|
||||
[[nodiscard]] ForumTopic *topicFor(MsgId rootId);
|
||||
|
||||
void applyReceivedTopics(const MTPmessages_ForumTopics &topics);
|
||||
|
||||
[[nodiscard]] MsgId reserveCreatingId(
|
||||
const QString &title,
|
||||
DocumentId iconId);
|
||||
void discardCreatingId(MsgId rootId);
|
||||
[[nodiscard]] bool creating(MsgId rootId) const;
|
||||
|
||||
private:
|
||||
void applyReceivedTopics(
|
||||
const MTPmessages_ForumTopics &topics,
|
||||
|
@ -54,6 +63,8 @@ private:
|
|||
MsgId _offsetTopicId = 0;
|
||||
bool _allLoaded = false;
|
||||
|
||||
base::flat_set<MsgId> _creatingRootIds;
|
||||
|
||||
rpl::event_stream<> _chatsListChanges;
|
||||
rpl::event_stream<> _chatsListLoadedEvents;
|
||||
|
||||
|
|
|
@ -10,27 +10,33 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_channel.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "dialogs/dialogs_main_list.h"
|
||||
#include "core/application.h"
|
||||
#include "core/core_settings.h"
|
||||
#include "history/history.h"
|
||||
#include "history/history_item.h"
|
||||
#include "ui/painter.h"
|
||||
|
||||
namespace Data {
|
||||
|
||||
ForumTopic::ForumTopic(not_null<History*> forum, MsgId rootId)
|
||||
: Entry(&forum->owner(), Type::ForumTopic)
|
||||
, _forum(forum)
|
||||
, _list(forum->peer->asChannel()->forum()->topicsList())
|
||||
ForumTopic::ForumTopic(not_null<History*> history, MsgId rootId)
|
||||
: Entry(&history->owner(), Type::ForumTopic)
|
||||
, _history(history)
|
||||
, _list(forum()->topicsList())
|
||||
, _rootId(rootId) {
|
||||
}
|
||||
|
||||
not_null<ChannelData*> ForumTopic::channel() const {
|
||||
return _forum->peer->asChannel();
|
||||
return _history->peer->asChannel();
|
||||
}
|
||||
|
||||
not_null<History*> ForumTopic::forum() const {
|
||||
return _forum;
|
||||
not_null<History*> ForumTopic::history() const {
|
||||
return _history;
|
||||
}
|
||||
|
||||
not_null<Forum*> ForumTopic::forum() const {
|
||||
return channel()->forum();
|
||||
}
|
||||
|
||||
MsgId ForumTopic::rootId() const {
|
||||
|
@ -110,7 +116,7 @@ void ForumTopic::applyTopicFields(
|
|||
|
||||
void ForumTopic::applyTopicTopMessage(MsgId topMessageId) {
|
||||
if (topMessageId) {
|
||||
const auto itemId = FullMsgId(_forum->peer->id, topMessageId);
|
||||
const auto itemId = FullMsgId(_history->peer->id, topMessageId);
|
||||
if (const auto item = owner().message(itemId)) {
|
||||
setLastServerMessage(item);
|
||||
} else {
|
||||
|
@ -193,6 +199,9 @@ void ForumTopic::setOutboxReadTill(MsgId upTo) {
|
|||
}
|
||||
|
||||
void ForumTopic::loadUserpic() {
|
||||
if (_icon) {
|
||||
[[maybe_unused]] const auto preload = _icon->ready();
|
||||
}
|
||||
}
|
||||
|
||||
void ForumTopic::paintUserpic(
|
||||
|
@ -201,7 +210,19 @@ void ForumTopic::paintUserpic(
|
|||
int x,
|
||||
int y,
|
||||
int size) const {
|
||||
// #TODO forum
|
||||
if (_icon) {
|
||||
const auto emoji = Data::FrameSizeFromTag(
|
||||
Data::CustomEmojiManager::SizeTag::Isolated
|
||||
) / style::DevicePixelRatio();
|
||||
_icon->paint(p, {
|
||||
.preview = st::windowBgOver->c,
|
||||
.now = crl::now(),
|
||||
.position = QPoint(
|
||||
x + (size - emoji) / 2,
|
||||
y + (size - emoji) / 2),
|
||||
.paused = false,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ForumTopic::requestChatListMessage() {
|
||||
|
@ -270,7 +291,15 @@ DocumentId ForumTopic::iconId() const {
|
|||
}
|
||||
|
||||
void ForumTopic::applyIconId(DocumentId iconId) {
|
||||
_iconId = iconId;
|
||||
if (_iconId != iconId) {
|
||||
_iconId = iconId;
|
||||
_icon = iconId
|
||||
? _history->owner().customEmojiManager().create(
|
||||
_iconId,
|
||||
[=] { updateChatListEntry(); },
|
||||
Data::CustomEmojiManager::SizeTag::Isolated)
|
||||
: nullptr;
|
||||
}
|
||||
updateChatListEntry();
|
||||
}
|
||||
|
||||
|
@ -348,7 +377,7 @@ Dialogs::UnreadState ForumTopic::chatListUnreadState() const {
|
|||
auto result = Dialogs::UnreadState();
|
||||
const auto count = _unreadCount.value_or(0);
|
||||
const auto mark = !count && _unreadMark;
|
||||
const auto muted = _forum->mute();
|
||||
const auto muted = _history->mute();
|
||||
result.messages = count;
|
||||
result.messagesMuted = muted ? count : 0;
|
||||
result.chats = count ? 1 : 0;
|
||||
|
|
|
@ -23,18 +23,20 @@ class Session;
|
|||
namespace Data {
|
||||
|
||||
class Session;
|
||||
class Forum;
|
||||
|
||||
class ForumTopic final : public Dialogs::Entry {
|
||||
public:
|
||||
static constexpr auto kGeneralId = 1;
|
||||
|
||||
ForumTopic(not_null<History*> forum, MsgId rootId);
|
||||
ForumTopic(not_null<History*> history, MsgId rootId);
|
||||
|
||||
ForumTopic(const ForumTopic &) = delete;
|
||||
ForumTopic &operator=(const ForumTopic &) = delete;
|
||||
|
||||
[[nodiscard]] not_null<ChannelData*> channel() const;
|
||||
[[nodiscard]] not_null<History*> forum() const;
|
||||
[[nodiscard]] not_null<History*> history() const;
|
||||
[[nodiscard]] not_null<Forum*> forum() const;
|
||||
[[nodiscard]] MsgId rootId() const;
|
||||
[[nodiscard]] bool isGeneral() const {
|
||||
return (_rootId == kGeneralId);
|
||||
|
@ -107,7 +109,7 @@ private:
|
|||
|
||||
int chatListNameVersion() const override;
|
||||
|
||||
const not_null<History*> _forum;
|
||||
const not_null<History*> _history;
|
||||
const not_null<Dialogs::MainList*> _list;
|
||||
const MsgId _rootId = 0;
|
||||
|
||||
|
@ -117,6 +119,8 @@ private:
|
|||
base::flat_set<QChar> _titleFirstLetters;
|
||||
int _titleVersion = 0;
|
||||
|
||||
std::unique_ptr<Ui::Text::CustomEmoji> _icon;
|
||||
|
||||
std::optional<MsgId> _inboxReadBefore;
|
||||
std::optional<MsgId> _outboxReadBefore;
|
||||
std::optional<int> _unreadCount;
|
||||
|
|
|
@ -841,6 +841,39 @@ int Histories::sendRequest(
|
|||
return id;
|
||||
}
|
||||
|
||||
int Histories::sendPreparedMessage(
|
||||
not_null<History*> history,
|
||||
MsgId replyTo,
|
||||
uint64 randomId,
|
||||
PreparedMessage message,
|
||||
Fn<void(const MTPUpdates&, const MTP::Response&)> done,
|
||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail) {
|
||||
return v::match(message, [&](const auto &request) {
|
||||
const auto type = RequestType::Send;
|
||||
return sendRequest(history, type, [=](Fn<void()> finish) {
|
||||
const auto session = &_owner->session();
|
||||
const auto api = &session->api();
|
||||
history->sendRequestId = api->request(
|
||||
base::duplicate(request)
|
||||
).done([=](
|
||||
const MTPUpdates &result,
|
||||
const MTP::Response &response) {
|
||||
api->applyUpdates(result, randomId);
|
||||
done(result, response);
|
||||
finish();
|
||||
}).fail([=](
|
||||
const MTP::Error &error,
|
||||
const MTP::Response &response) {
|
||||
fail(error, response);
|
||||
finish();
|
||||
}).afterRequest(
|
||||
history->sendRequestId
|
||||
).send();
|
||||
return history->sendRequestId;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void Histories::checkPostponed(not_null<History*> history, int id) {
|
||||
if (const auto state = lookup(history)) {
|
||||
finishSentRequest(history, state, id);
|
||||
|
|
|
@ -16,6 +16,11 @@ namespace Main {
|
|||
class Session;
|
||||
} // namespace Main
|
||||
|
||||
namespace MTP {
|
||||
class Error;
|
||||
struct Response;
|
||||
} // namespace MTP
|
||||
|
||||
namespace Data {
|
||||
|
||||
class Session;
|
||||
|
@ -90,6 +95,19 @@ public:
|
|||
Fn<mtpRequestId(Fn<void()> finish)> generator);
|
||||
void cancelRequest(int id);
|
||||
|
||||
using PreparedMessage = std::variant<
|
||||
MTPmessages_SendMessage,
|
||||
MTPmessages_SendMedia,
|
||||
MTPmessages_SendInlineBotResult,
|
||||
MTPmessages_SendMultiMedia>;
|
||||
int sendPreparedMessage(
|
||||
not_null<History*> history,
|
||||
MsgId replyTo,
|
||||
uint64 randomId,
|
||||
PreparedMessage message,
|
||||
Fn<void(const MTPUpdates&, const MTP::Response &)> done,
|
||||
Fn<void(const MTP::Error&, const MTP::Response&)> fail);
|
||||
|
||||
private:
|
||||
struct PostponedHistoryRequest {
|
||||
Fn<mtpRequestId(Fn<void()> finish)> generator;
|
||||
|
|
|
@ -16,6 +16,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_messages.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "lang/lang_keys.h"
|
||||
#include "apiwrap.h"
|
||||
|
@ -36,6 +37,13 @@ constexpr auto kMessagesPerPage = 50;
|
|||
HistoryService::PreparedText{ { .text = text } });
|
||||
}
|
||||
|
||||
[[nodiscard]] bool IsCreating(not_null<History*> history, MsgId rootId) {
|
||||
if (const auto forum = history->peer->forum()) {
|
||||
return forum->creating(rootId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
struct RepliesList::Viewer {
|
||||
|
@ -50,7 +58,8 @@ struct RepliesList::Viewer {
|
|||
|
||||
RepliesList::RepliesList(not_null<History*> history, MsgId rootId)
|
||||
: _history(history)
|
||||
, _rootId(rootId) {
|
||||
, _rootId(rootId)
|
||||
, _creating(IsCreating(history, rootId)) {
|
||||
}
|
||||
|
||||
RepliesList::~RepliesList() {
|
||||
|
@ -104,7 +113,9 @@ rpl::producer<MessagesSlice> RepliesList::source(
|
|||
|
||||
_history->owner().channelDifferenceTooLong(
|
||||
) | rpl::filter([=](not_null<ChannelData*> channel) {
|
||||
if (_history->peer != channel || !_skippedAfter.has_value()) {
|
||||
if (_creating
|
||||
|| _history->peer != channel
|
||||
|| !_skippedAfter.has_value()) {
|
||||
return false;
|
||||
}
|
||||
_skippedAfter = std::nullopt;
|
||||
|
@ -297,7 +308,8 @@ void RepliesList::injectRootDivider(
|
|||
}
|
||||
|
||||
bool RepliesList::buildFromData(not_null<Viewer*> viewer) {
|
||||
if (_list.empty() && _skippedBefore == 0 && _skippedAfter == 0) {
|
||||
if (_creating
|
||||
|| (_list.empty() && _skippedBefore == 0 && _skippedAfter == 0)) {
|
||||
viewer->slice.ids.clear();
|
||||
viewer->slice.nearestToAround = FullMsgId();
|
||||
viewer->slice.fullCount
|
||||
|
@ -429,6 +441,8 @@ HistoryItem *RepliesList::lookupRoot() {
|
|||
}
|
||||
|
||||
void RepliesList::loadAround(MsgId id) {
|
||||
Expects(!_creating);
|
||||
|
||||
if (_loadingAround && *_loadingAround == id) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ private:
|
|||
std::optional<MsgId> _loadingAround;
|
||||
HistoryService *_divider = nullptr;
|
||||
bool _dividerWithComments = false;
|
||||
bool _creating = false;
|
||||
int _beforeId = 0;
|
||||
int _afterId = 0;
|
||||
|
||||
|
|
|
@ -1244,7 +1244,21 @@ void Session::setupUserIsContactViewer() {
|
|||
}, _lifetime);
|
||||
}
|
||||
|
||||
Session::~Session() = default;
|
||||
Session::~Session() {
|
||||
// We must clear all forums before clearing customEmojiManager.
|
||||
// Because in Data::ForumTopic an Ui::Text::CustomEmoji is cached.
|
||||
auto forums = base::flat_set<not_null<ChannelData*>>();
|
||||
for (const auto &[peerId, peer] : _peers) {
|
||||
if (const auto channel = peer->asChannel()) {
|
||||
if (channel->isForum()) {
|
||||
forums.emplace(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const auto &channel : forums) {
|
||||
channel->setFlags(channel->flags() & ~ChannelDataFlag::Forum);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Method>
|
||||
void Session::enumerateItemViews(
|
||||
|
@ -3789,13 +3803,16 @@ void Session::refreshChatListEntry(Dialogs::Key key) {
|
|||
using namespace Dialogs;
|
||||
|
||||
const auto entry = key.entry();
|
||||
const auto history = key.history();
|
||||
const auto mainList = entry->asTopic()
|
||||
? entry->asTopic()->forum()->peer->forum()->topicsList()
|
||||
const auto history = entry->asHistory();
|
||||
const auto topic = entry->asTopic();
|
||||
const auto mainList = topic
|
||||
? topic->forum()->topicsList()
|
||||
: chatsList(entry->folder());
|
||||
auto event = ChatListEntryRefresh{ .key = key };
|
||||
const auto creating = event.existenceChanged = !entry->inChatList();
|
||||
if (event.existenceChanged) {
|
||||
if (creating && topic && topic->forum()->creating(topic->rootId())) {
|
||||
return;
|
||||
} else if (event.existenceChanged) {
|
||||
const auto mainRow = entry->addToChatList(0, mainList);
|
||||
_contactsNoChatsList.del(key, mainRow);
|
||||
} else {
|
||||
|
@ -3860,7 +3877,7 @@ void Session::removeChatListEntry(Dialogs::Key key) {
|
|||
}
|
||||
}
|
||||
const auto mainList = entry->asTopic()
|
||||
? entry->asTopic()->forum()->peer->forum()->topicsList()
|
||||
? entry->asTopic()->forum()->topicsList()
|
||||
: chatsList(entry->folder());
|
||||
entry->removeFromChatList(0, mainList);
|
||||
_chatListEntryRefreshes.fire(ChatListEntryRefresh{
|
||||
|
|
|
@ -59,7 +59,7 @@ History *Key::parentHistory() const {
|
|||
if (const auto result = history()) {
|
||||
return result;
|
||||
} else if (const auto child = topic()) {
|
||||
return child->forum();
|
||||
return child->history();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -385,7 +385,7 @@ void Widget::chosenRow(const ChosenRow &row) {
|
|||
const auto history = row.key.history();
|
||||
if (const auto topic = row.key.topic()) {
|
||||
controller()->showRepliesForMessage(
|
||||
topic->forum(),
|
||||
topic->history(),
|
||||
topic->rootId(),
|
||||
ShowAtUnreadMsgId,
|
||||
Window::SectionShow::Way::ClearStack);
|
||||
|
|
|
@ -1045,29 +1045,7 @@ bool HistoryItem::computeDropForwardedInfo() const {
|
|||
&& (!media || !media->forceForwardedInfo()));
|
||||
}
|
||||
|
||||
MsgId HistoryItem::replyToId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryItem::replyToTop() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToTop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryItem::topicRootId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()
|
||||
; reply && reply->topicPost) {
|
||||
return reply->replyToTop();
|
||||
}
|
||||
return Data::ForumTopic::kGeneralId;
|
||||
}
|
||||
|
||||
MsgId HistoryItem::inThread(MsgId rootId) const {
|
||||
bool HistoryItem::inThread(MsgId rootId) const {
|
||||
const auto checkId = (rootId == Data::ForumTopic::kGeneralId)
|
||||
? topicRootId()
|
||||
: replyToTop();
|
||||
|
|
|
@ -341,8 +341,7 @@ public:
|
|||
PeerId replier,
|
||||
std::optional<bool> unread) {
|
||||
}
|
||||
virtual void setReplyToTop(MsgId replyToTop) {
|
||||
}
|
||||
virtual void setReplyToTop(MsgId replyToTop) = 0;
|
||||
virtual void setPostAuthor(const QString &author) {
|
||||
}
|
||||
virtual void setRealId(MsgId newId);
|
||||
|
@ -405,10 +404,10 @@ public:
|
|||
virtual void setText(const TextWithEntities &textWithEntities) {
|
||||
}
|
||||
|
||||
[[nodiscard]] MsgId replyToId() const;
|
||||
[[nodiscard]] MsgId replyToTop() const;
|
||||
[[nodiscard]] MsgId topicRootId() const;
|
||||
[[nodiscard]] MsgId inThread(MsgId rootId) const;
|
||||
[[nodiscard]] virtual MsgId replyToId() const = 0;
|
||||
[[nodiscard]] virtual MsgId replyToTop() const = 0;
|
||||
[[nodiscard]] virtual MsgId topicRootId() const = 0;
|
||||
[[nodiscard]] bool inThread(MsgId rootId) const;
|
||||
|
||||
[[nodiscard]] not_null<PeerData*> author() const;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_changes.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_user.h"
|
||||
#include "data/data_web_page.h"
|
||||
#include "data/data_sponsored_messages.h"
|
||||
|
@ -1490,6 +1491,28 @@ TextWithEntities HistoryMessage::withLocalEntities(
|
|||
return textWithEntities;
|
||||
}
|
||||
|
||||
MsgId HistoryMessage::replyToId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToId();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryMessage::replyToTop() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()) {
|
||||
return reply->replyToTop();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryMessage::topicRootId() const {
|
||||
if (const auto reply = Get<HistoryMessageReply>()
|
||||
; reply && reply->topicPost) {
|
||||
return reply->replyToTop();
|
||||
}
|
||||
return Data::ForumTopic::kGeneralId;
|
||||
}
|
||||
|
||||
void HistoryMessage::setText(const TextWithEntities &textWithEntities) {
|
||||
for (const auto &entity : textWithEntities.entities) {
|
||||
auto type = entity.type();
|
||||
|
|
|
@ -180,6 +180,10 @@ public:
|
|||
void destroyHistoryEntry() override;
|
||||
[[nodiscard]] Storage::SharedMediaTypesMask sharedMediaTypes() const override;
|
||||
|
||||
[[nodiscard]] MsgId replyToId() const override;
|
||||
[[nodiscard]] MsgId replyToTop() const override;
|
||||
[[nodiscard]] MsgId topicRootId() const override;
|
||||
|
||||
void setText(const TextWithEntities &textWithEntities) override;
|
||||
[[nodiscard]] TextWithEntities originalText() const override;
|
||||
[[nodiscard]] auto originalTextWithLocalEntities() const
|
||||
|
|
|
@ -22,6 +22,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "history/view/history_view_item_preview.h"
|
||||
#include "data/data_folder.h"
|
||||
#include "data/data_forum.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_media_types.h"
|
||||
#include "data/data_game.h"
|
||||
|
@ -30,6 +31,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_chat.h"
|
||||
#include "data/data_changes.h"
|
||||
#include "data/data_group_call.h" // Data::GroupCall::id().
|
||||
#include "data/stickers/data_custom_emoji.h"
|
||||
#include "core/application.h"
|
||||
#include "core/click_handler_types.h"
|
||||
#include "base/unixtime.h"
|
||||
|
@ -652,13 +654,15 @@ void HistoryService::setMessageByAction(const MTPmessageAction &action) {
|
|||
auto result = PreparedText{};
|
||||
result.text = { "topic icon: " }; // #TODO forum lang
|
||||
result.text.append(TextWithEntities{
|
||||
" ",
|
||||
"@",
|
||||
{ EntityInText(
|
||||
EntityType::CustomEmoji,
|
||||
0,
|
||||
1,
|
||||
QString::number(+action.vemoji_document_id().v)) },
|
||||
Data::SerializeCustomEmojiId({
|
||||
.id = action.vemoji_document_id().v })) },
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
|
@ -800,7 +804,20 @@ void HistoryService::applyAction(const MTPMessageAction &action) {
|
|||
data.vmonths().v);
|
||||
}, [&](const MTPDmessageActionTopicCreate &data) {
|
||||
if (const auto forum = history()->peer->forum()) {
|
||||
forum->applyTopicAdded(id, qs(data.vtitle()));
|
||||
const auto iconId = DocumentId(0); // #TODO forum icon
|
||||
forum->applyTopicAdded(id, qs(data.vtitle()), iconId);
|
||||
}
|
||||
}, [&](const MTPDmessageActionTopicEditTitle &data) {
|
||||
if (const auto forum = history()->peer->forum()) {
|
||||
if (const auto topic = forum->topicFor(replyToTop())) {
|
||||
topic->applyTitle(qs(data.vtitle()));
|
||||
}
|
||||
}
|
||||
}, [&](const MTPDmessageActionTopicEditIcon &data) {
|
||||
if (const auto forum = history()->peer->forum()) {
|
||||
if (const auto topic = forum->topicFor(replyToTop())) {
|
||||
topic->applyIconId(data.vemoji_document_id().v);
|
||||
}
|
||||
}
|
||||
}, [](const auto &) {
|
||||
});
|
||||
|
@ -1299,6 +1316,36 @@ TextWithEntities HistoryService::inReplyText() const {
|
|||
return Ui::Text::Wrapped(result, EntityType::PlainLink);
|
||||
}
|
||||
|
||||
MsgId HistoryService::replyToId() const {
|
||||
return 0; // Don't render replies info in service, only handle threads.
|
||||
}
|
||||
|
||||
MsgId HistoryService::replyToTop() const {
|
||||
if (const auto data = GetDependentData()) {
|
||||
return data->topId;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
MsgId HistoryService::topicRootId() const {
|
||||
if (const auto data = GetDependentData()
|
||||
; data && data->topicPost) {
|
||||
return data->topId;
|
||||
}
|
||||
return Data::ForumTopic::kGeneralId;
|
||||
}
|
||||
|
||||
void HistoryService::setReplyToTop(MsgId replyToTop) {
|
||||
const auto data = GetDependentData();
|
||||
if (!data
|
||||
|| (data->topId == replyToTop)
|
||||
|| (data->topId != 0)
|
||||
|| isScheduled()) {
|
||||
return;
|
||||
}
|
||||
data->topId = replyToTop;
|
||||
}
|
||||
|
||||
std::unique_ptr<HistoryView::Element> HistoryService::createView(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
HistoryView::Element *replacing) {
|
||||
|
@ -1422,7 +1469,13 @@ void HistoryService::createFromMtp(const MTPDmessage &message) {
|
|||
|
||||
void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
||||
const auto type = message.vaction().type();
|
||||
if (type == mtpc_messageActionSetChatTheme) {
|
||||
if (type == mtpc_messageActionPinMessage) {
|
||||
UpdateComponents(HistoryServicePinned::Bit());
|
||||
} else if (type == mtpc_messageActionTopicCreate
|
||||
|| type == mtpc_messageActionTopicEditTitle
|
||||
|| type == mtpc_messageActionTopicEditIcon) {
|
||||
UpdateComponents(HistoryServiceTopicInfo::Bit());
|
||||
} else if (type == mtpc_messageActionSetChatTheme) {
|
||||
setupChatThemeChange();
|
||||
} else if (type == mtpc_messageActionSetMessagesTTL) {
|
||||
setupTTLChange();
|
||||
|
@ -1505,14 +1558,13 @@ void HistoryService::createFromMtp(const MTPDmessageService &message) {
|
|||
const auto peerId = data.vreply_to_peer_id()
|
||||
? peerFromMTP(*data.vreply_to_peer_id())
|
||||
: history()->peer->id;
|
||||
if (message.vaction().type() == mtpc_messageActionPinMessage) {
|
||||
UpdateComponents(HistoryServicePinned::Bit());
|
||||
}
|
||||
if (const auto dependent = GetDependentData()) {
|
||||
dependent->peerId = (peerId != history()->peer->id)
|
||||
? peerId
|
||||
: 0;
|
||||
dependent->msgId = data.vreply_to_msg_id().v;
|
||||
dependent->topId = data.vreply_to_top_id().value_or(
|
||||
data.vreply_to_msg_id().v);
|
||||
if (!updateDependent()) {
|
||||
RequestDependentMessageData(
|
||||
this,
|
||||
|
|
|
@ -15,9 +15,11 @@ class Service;
|
|||
|
||||
struct HistoryServiceDependentData {
|
||||
PeerId peerId = 0;
|
||||
MsgId msgId = 0;
|
||||
HistoryItem *msg = nullptr;
|
||||
ClickHandlerPtr lnk;
|
||||
MsgId msgId = 0;
|
||||
MsgId topId = 0;
|
||||
bool topicPost = false;
|
||||
};
|
||||
|
||||
struct HistoryServicePinned
|
||||
|
@ -25,6 +27,11 @@ struct HistoryServicePinned
|
|||
, public HistoryServiceDependentData {
|
||||
};
|
||||
|
||||
struct HistoryServiceTopicInfo
|
||||
: public RuntimeComponent<HistoryServiceTopicInfo, HistoryItem>
|
||||
, public HistoryServiceDependentData {
|
||||
};
|
||||
|
||||
struct HistoryServiceGameScore
|
||||
: public RuntimeComponent<HistoryServiceGameScore, HistoryItem>
|
||||
, public HistoryServiceDependentData {
|
||||
|
@ -129,6 +136,11 @@ public:
|
|||
ItemPreview toPreview(ToPreviewOptions options) const override;
|
||||
TextWithEntities inReplyText() const override;
|
||||
|
||||
MsgId replyToId() const override;
|
||||
MsgId replyToTop() const override;
|
||||
MsgId topicRootId() const override;
|
||||
void setReplyToTop(MsgId replyToTop) override;
|
||||
|
||||
std::unique_ptr<HistoryView::Element> createView(
|
||||
not_null<HistoryView::ElementDelegate*> delegate,
|
||||
HistoryView::Element *replacing = nullptr) override;
|
||||
|
@ -149,12 +161,14 @@ protected:
|
|||
|
||||
private:
|
||||
HistoryServiceDependentData *GetDependentData() {
|
||||
if (auto pinned = Get<HistoryServicePinned>()) {
|
||||
if (const auto pinned = Get<HistoryServicePinned>()) {
|
||||
return pinned;
|
||||
} else if (auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||
} else if (const auto gamescore = Get<HistoryServiceGameScore>()) {
|
||||
return gamescore;
|
||||
} else if (auto payment = Get<HistoryServicePayment>()) {
|
||||
} else if (const auto payment = Get<HistoryServicePayment>()) {
|
||||
return payment;
|
||||
} else if (const auto info = Get<HistoryServiceTopicInfo>()) {
|
||||
return info;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -72,6 +72,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "styles/style_window.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_boxes.h"
|
||||
#include "styles/style_layers.h"
|
||||
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
|
@ -332,6 +333,10 @@ RepliesWidget::RepliesWidget(
|
|||
}
|
||||
|
||||
RepliesWidget::~RepliesWidget() {
|
||||
if (_topic && _topic->forum()->creating(_rootId)) {
|
||||
_topic->forum()->discardCreatingId(_rootId);
|
||||
_topic = nullptr;
|
||||
}
|
||||
if (_readRequestTimer.isActive()) {
|
||||
sendReadTillRequest();
|
||||
}
|
||||
|
@ -895,7 +900,7 @@ std::optional<QString> RepliesWidget::writeRestriction() const {
|
|||
}
|
||||
|
||||
void RepliesWidget::pushReplyReturn(not_null<HistoryItem*> item) {
|
||||
if (item->history() == _history && item->replyToTop() == _rootId) {
|
||||
if (item->history() == _history && item->inThread(_rootId)) {
|
||||
_replyReturns.push_back(item->id);
|
||||
} else {
|
||||
return;
|
||||
|
@ -1542,7 +1547,30 @@ Dialogs::RowDescriptor RepliesWidget::activeChat() const {
|
|||
}
|
||||
|
||||
bool RepliesWidget::preventsClose(Fn<void()> &&continueCallback) const {
|
||||
return _composeControls->preventsClose(std::move(continueCallback));
|
||||
if (_composeControls->preventsClose(base::duplicate(continueCallback))) {
|
||||
return true;
|
||||
} else if (!_newTopicDiscarded
|
||||
&& _topic
|
||||
&& _topic->forum()->creating(_rootId)) {
|
||||
const auto weak = Ui::MakeWeak(this);
|
||||
auto sure = [=](Fn<void()> &&close) {
|
||||
if (const auto strong = weak.data()) {
|
||||
strong->_newTopicDiscarded = true;
|
||||
}
|
||||
close();
|
||||
if (continueCallback) {
|
||||
continueCallback();
|
||||
}
|
||||
};
|
||||
controller()->show(Ui::MakeConfirmBox({
|
||||
.text = rpl::single(u"Sure discard?"_q), // #TODO forum lang
|
||||
.confirmed = std::move(sure),
|
||||
.confirmText = tr::lng_record_lock_discard(),
|
||||
.confirmStyle = &st::attentionBoxButton,
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
QPixmap RepliesWidget::grabForShowAnimation(const Window::SectionSlideParams ¶ms) {
|
||||
|
@ -1628,7 +1656,7 @@ bool RepliesWidget::showMessage(
|
|||
&& _inner->viewByPosition(returnTo->position())
|
||||
&& returnTo->replyToId() == messageId) {
|
||||
return returnTo;
|
||||
} else if (!general && (returnTo->replyToTop() == _rootId)) {
|
||||
} else if (!general && returnTo->inThread(_rootId)) {
|
||||
return returnTo;
|
||||
}
|
||||
}
|
||||
|
@ -1655,7 +1683,6 @@ Window::SectionActionResult RepliesWidget::sendBotCommand(
|
|||
}
|
||||
|
||||
void RepliesWidget::replyToMessage(FullMsgId itemId) {
|
||||
// if (item->history() != _history || item->replyToTop() != _rootId) {
|
||||
_composeControls->replyToMessage(itemId);
|
||||
refreshTopBarActiveChat();
|
||||
}
|
||||
|
|
|
@ -269,10 +269,11 @@ private:
|
|||
[[nodiscard]] std::optional<QString> writeRestriction() const;
|
||||
|
||||
const not_null<History*> _history;
|
||||
const MsgId _rootId = 0;
|
||||
MsgId _rootId = 0;
|
||||
std::shared_ptr<Ui::ChatTheme> _theme;
|
||||
HistoryItem *_root = nullptr;
|
||||
Data::ForumTopic *_topic = nullptr;
|
||||
mutable bool _newTopicDiscarded = false;
|
||||
|
||||
std::shared_ptr<Data::RepliesList> _replies;
|
||||
rpl::variable<bool> _areComments = false;
|
||||
|
|
|
@ -21,9 +21,9 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "info/info_controller.h"
|
||||
#include "boxes/peer_list_box.h"
|
||||
#include "data/data_chat.h"
|
||||
#include "data/data_channel.h"
|
||||
#include "data/data_session.h"
|
||||
#include "data/data_forum_topic.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "styles/style_info.h"
|
||||
#include "styles/style_profile.h"
|
||||
|
@ -337,7 +337,7 @@ Key ContentMemento::key() const {
|
|||
}
|
||||
|
||||
ContentMemento::ContentMemento(not_null<Data::ForumTopic*> topic)
|
||||
: _peer(topic->forum()->peer)
|
||||
: _peer(topic->channel())
|
||||
, _migratedPeerId(_peer->migrateFrom() ? _peer->migrateFrom()->id : 0)
|
||||
, _topic(topic) {
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||
#include "data/data_media_types.h"
|
||||
#include "data/data_download_manager.h"
|
||||
#include "history/history_item.h"
|
||||
#include "history/history.h"
|
||||
#include "main/main_session.h"
|
||||
#include "window/window_session_controller.h"
|
||||
|
||||
|
@ -48,7 +47,7 @@ PeerData *Key::peer() const {
|
|||
if (const auto peer = std::get_if<not_null<PeerData*>>(&_value)) {
|
||||
return *peer;
|
||||
} else if (const auto topic = this->topic()) {
|
||||
return topic->forum()->peer;
|
||||
return topic->channel();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -257,7 +257,7 @@ void Uploader::sendProgressUpdate(
|
|||
const auto history = item->history();
|
||||
auto &manager = _api->session().sendProgressManager();
|
||||
manager.update(history, type, progress);
|
||||
if (const auto replyTo = item->replyToTop()) {
|
||||
if (const auto replyTo = item->topicRootId()) {
|
||||
if (history->peer->isMegagroup()) {
|
||||
manager.update(history, replyTo, type, progress);
|
||||
}
|
||||
|
|
|
@ -752,7 +752,7 @@ void Filler::addManageTopic() {
|
|||
return;
|
||||
}
|
||||
// #TODO forum lang
|
||||
const auto history = _topic->forum();
|
||||
const auto history = _topic->history();
|
||||
const auto rootId = _topic->rootId();
|
||||
const auto navigation = _controller;
|
||||
_addAction(u"Edit topic"_q, [=] {
|
||||
|
|
Loading…
Add table
Reference in a new issue