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