mirror of
https://github.com/AyuGram/AyuGramDesktop.git
synced 2026-07-25 06:54:43 +00:00
Support no-topics recipient state in bot-forums.
This commit is contained in:
@@ -459,6 +459,7 @@ https://github.com/telegramdesktop/tdesktop/blob/master/LEGAL
|
|||||||
"lng_contacts_not_found" = "No contacts found";
|
"lng_contacts_not_found" = "No contacts found";
|
||||||
"lng_topics_not_found" = "No topics found.";
|
"lng_topics_not_found" = "No topics found.";
|
||||||
"lng_forum_all_messages" = "All Messages";
|
"lng_forum_all_messages" = "All Messages";
|
||||||
|
"lng_forum_create_new_topic" = "Create New Thread";
|
||||||
"lng_dlg_search_for_messages" = "Search for messages";
|
"lng_dlg_search_for_messages" = "Search for messages";
|
||||||
"lng_update_telegram" = "Update Telegram";
|
"lng_update_telegram" = "Update Telegram";
|
||||||
"lng_dlg_search_in" = "Search messages in";
|
"lng_dlg_search_in" = "Search messages in";
|
||||||
|
|||||||
@@ -3529,7 +3529,6 @@ void ApiWrap::forwardMessages(
|
|||||||
if (shared) {
|
if (shared) {
|
||||||
++shared->requestsLeft;
|
++shared->requestsLeft;
|
||||||
}
|
}
|
||||||
const auto requestType = Data::Histories::RequestType::Send;
|
|
||||||
const auto idsCopy = localIds;
|
const auto idsCopy = localIds;
|
||||||
const auto scheduled = action.options.scheduled;
|
const auto scheduled = action.options.scheduled;
|
||||||
const auto starsPaid = std::min(
|
const auto starsPaid = std::min(
|
||||||
@@ -3540,57 +3539,80 @@ void ApiWrap::forwardMessages(
|
|||||||
action.options.starsApproved -= starsPaid;
|
action.options.starsApproved -= starsPaid;
|
||||||
oneFlags |= SendFlag::f_allow_paid_stars;
|
oneFlags |= SendFlag::f_allow_paid_stars;
|
||||||
}
|
}
|
||||||
histories.sendRequest(history, requestType, [=](Fn<void()> finish) {
|
auto buildMessage = [=](
|
||||||
history->sendRequestId = request(MTPmessages_ForwardMessages(
|
not_null<History*> history,
|
||||||
MTP_flags(oneFlags),
|
FullReplyTo replyTo)
|
||||||
|
-> Data::Histories::PreparedMessage {
|
||||||
|
const auto kGeneralId = Data::ForumTopic::kGeneralId;
|
||||||
|
const auto realTopMsgId = (replyTo.topicRootId == kGeneralId)
|
||||||
|
? MsgId(0)
|
||||||
|
: replyTo.topicRootId;
|
||||||
|
auto flags = oneFlags;
|
||||||
|
if (realTopMsgId) {
|
||||||
|
flags |= SendFlag::f_top_msg_id;
|
||||||
|
} else {
|
||||||
|
flags &= ~SendFlag::f_top_msg_id;
|
||||||
|
}
|
||||||
|
return MTPmessages_ForwardMessages(
|
||||||
|
MTP_flags(flags),
|
||||||
forwardFrom->input(),
|
forwardFrom->input(),
|
||||||
MTP_vector<MTPint>(ids),
|
MTP_vector<MTPint>(ids),
|
||||||
MTP_vector<MTPlong>(randomIds),
|
MTP_vector<MTPlong>(randomIds),
|
||||||
peer->input(),
|
history->peer->input(),
|
||||||
MTP_int(topMsgId),
|
MTP_int(realTopMsgId),
|
||||||
(action.options.suggest
|
(action.options.suggest
|
||||||
? ReplyToForMTP(history, action.replyTo)
|
? ReplyToForMTP(history, replyTo)
|
||||||
: monoforumPeer
|
: monoforumPeer
|
||||||
? MTP_inputReplyToMonoForum(monoforumPeer->input())
|
? MTP_inputReplyToMonoForum(
|
||||||
|
monoforumPeer->input())
|
||||||
: MTPInputReplyTo()),
|
: MTPInputReplyTo()),
|
||||||
MTP_int(action.options.scheduled),
|
MTP_int(action.options.scheduled),
|
||||||
MTP_int(action.options.scheduleRepeatPeriod),
|
MTP_int(action.options.scheduleRepeatPeriod),
|
||||||
(sendAs ? sendAs->input() : MTP_inputPeerEmpty()),
|
(sendAs
|
||||||
Data::ShortcutIdToMTP(_session, action.options.shortcutId),
|
? sendAs->input()
|
||||||
|
: MTP_inputPeerEmpty()),
|
||||||
|
Data::ShortcutIdToMTP(
|
||||||
|
&history->session(),
|
||||||
|
action.options.shortcutId),
|
||||||
MTP_long(action.options.effectId),
|
MTP_long(action.options.effectId),
|
||||||
MTPint(), // video_timestamp
|
MTPint(),
|
||||||
MTP_long(starsPaid),
|
MTP_long(starsPaid),
|
||||||
Api::SuggestToMTP(action.options.suggest)
|
Api::SuggestToMTP(action.options.suggest));
|
||||||
)).done([=](const MTPUpdates &result) {
|
};
|
||||||
|
histories.sendPreparedMessage(
|
||||||
|
history,
|
||||||
|
FullReplyTo{ .topicRootId = topicRootId },
|
||||||
|
uint64(0),
|
||||||
|
std::move(buildMessage),
|
||||||
|
[=](const MTPUpdates &result, const MTP::Response &) {
|
||||||
if (!scheduled) {
|
if (!scheduled) {
|
||||||
this->updates().checkForSentToScheduled(result);
|
_session->api().updates().checkForSentToScheduled(
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
applyUpdates(result);
|
|
||||||
if (shared && !--shared->requestsLeft) {
|
if (shared && !--shared->requestsLeft) {
|
||||||
shared->callback();
|
shared->callback();
|
||||||
}
|
}
|
||||||
finish();
|
if (peer->isSelf() && _session->premium()) {
|
||||||
if (peer->isSelf() && session().premium()) {
|
|
||||||
ProcessRecentSelfForwards(
|
ProcessRecentSelfForwards(
|
||||||
_session,
|
_session,
|
||||||
result,
|
result,
|
||||||
peer->id,
|
peer->id,
|
||||||
forwardFrom->id);
|
forwardFrom->id);
|
||||||
}
|
}
|
||||||
}).fail([=](const MTP::Error &error) {
|
},
|
||||||
|
[=](const MTP::Error &error, const MTP::Response &) {
|
||||||
if (idsCopy) {
|
if (idsCopy) {
|
||||||
for (const auto &[randomId, itemId] : *idsCopy) {
|
for (const auto &[randomId, itemId] : *idsCopy) {
|
||||||
sendMessageFail(error, peer, randomId, itemId);
|
_session->api().sendMessageFail(
|
||||||
|
error,
|
||||||
|
peer,
|
||||||
|
randomId,
|
||||||
|
itemId);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sendMessageFail(error, peer);
|
_session->api().sendMessageFail(error, peer);
|
||||||
}
|
}
|
||||||
finish();
|
});
|
||||||
}).afterRequest(
|
|
||||||
history->sendRequestId
|
|
||||||
).send();
|
|
||||||
return history->sendRequestId;
|
|
||||||
});
|
|
||||||
|
|
||||||
ids.resize(0);
|
ids.resize(0);
|
||||||
randomIds.resize(0);
|
randomIds.resize(0);
|
||||||
|
|||||||
@@ -1096,10 +1096,16 @@ auto ChooseTopicBoxController::Row::generateNameWords() const
|
|||||||
return _topic->chatListNameWords();
|
return _topic->chatListNameWords();
|
||||||
}
|
}
|
||||||
|
|
||||||
ChooseTopicBoxController::AllMessagesRow::AllMessagesRow()
|
QString ChooseTopicBoxController::AllMessagesRow::name() const {
|
||||||
: PeerListRow(PeerListRowId(0)) {
|
return _userCreatesTopics
|
||||||
const auto name = tr::lng_forum_all_messages(tr::now);
|
? tr::lng_forum_create_new_topic(tr::now)
|
||||||
const auto words = TextUtilities::PrepareSearchWords(name);
|
: tr::lng_forum_all_messages(tr::now);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChooseTopicBoxController::AllMessagesRow::AllMessagesRow(bool userCreatesTopics)
|
||||||
|
: PeerListRow(PeerListRowId(0))
|
||||||
|
, _userCreatesTopics(userCreatesTopics) {
|
||||||
|
const auto words = TextUtilities::PrepareSearchWords(name());
|
||||||
for (const auto &word : words) {
|
for (const auto &word : words) {
|
||||||
_nameWords.emplace(word);
|
_nameWords.emplace(word);
|
||||||
_nameFirstLetters.emplace(word[0]);
|
_nameFirstLetters.emplace(word[0]);
|
||||||
@@ -1107,23 +1113,26 @@ ChooseTopicBoxController::AllMessagesRow::AllMessagesRow()
|
|||||||
}
|
}
|
||||||
|
|
||||||
QString ChooseTopicBoxController::AllMessagesRow::generateName() {
|
QString ChooseTopicBoxController::AllMessagesRow::generateName() {
|
||||||
return tr::lng_forum_all_messages(tr::now);
|
return name();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ChooseTopicBoxController::AllMessagesRow::generateShortName() {
|
QString ChooseTopicBoxController::AllMessagesRow::generateShortName() {
|
||||||
return tr::lng_forum_all_messages(tr::now);
|
return name();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ChooseTopicBoxController::AllMessagesRow::generatePaintUserpicCallback(
|
auto ChooseTopicBoxController::AllMessagesRow::generatePaintUserpicCallback(
|
||||||
bool forceRound)
|
bool forceRound)
|
||||||
-> PaintRoundImageCallback {
|
-> PaintRoundImageCallback {
|
||||||
return [](
|
return [userCreatesTopics = _userCreatesTopics](
|
||||||
Painter &p,
|
Painter &p,
|
||||||
int x,
|
int x,
|
||||||
int y,
|
int y,
|
||||||
int outerWidth,
|
int outerWidth,
|
||||||
int size) {
|
int size) {
|
||||||
st::menuIconChats.paintInCenter(
|
const auto &icon = userCreatesTopics
|
||||||
|
? st::menuIconDiscussion
|
||||||
|
: st::menuIconChats;
|
||||||
|
icon.paintInCenter(
|
||||||
p,
|
p,
|
||||||
QRect(x, y - st::lineWidth, size, size));
|
QRect(x, y - st::lineWidth, size, size));
|
||||||
};
|
};
|
||||||
@@ -1206,8 +1215,10 @@ void ChooseTopicBoxController::refreshRows(bool initial) {
|
|||||||
if (_forum->bot()
|
if (_forum->bot()
|
||||||
&& !delegate()->peerListFindRow(PeerListRowId(0))
|
&& !delegate()->peerListFindRow(PeerListRowId(0))
|
||||||
&& (!_filter || _filter(_forum->history()))) {
|
&& (!_filter || _filter(_forum->history()))) {
|
||||||
|
const auto userCreatesTopics = Data::IsBotUserCreatesTopics(
|
||||||
|
_forum->peer());
|
||||||
delegate()->peerListAppendRow(
|
delegate()->peerListAppendRow(
|
||||||
std::make_unique<AllMessagesRow>());
|
std::make_unique<AllMessagesRow>(userCreatesTopics));
|
||||||
added = true;
|
added = true;
|
||||||
}
|
}
|
||||||
for (const auto &row : _forum->topicsList()->indexed()->all()) {
|
for (const auto &row : _forum->topicsList()->indexed()->all()) {
|
||||||
|
|||||||
@@ -393,7 +393,7 @@ private:
|
|||||||
|
|
||||||
class AllMessagesRow final : public PeerListRow {
|
class AllMessagesRow final : public PeerListRow {
|
||||||
public:
|
public:
|
||||||
AllMessagesRow();
|
explicit AllMessagesRow(bool userCreatesTopics);
|
||||||
|
|
||||||
QString generateName() override;
|
QString generateName() override;
|
||||||
QString generateShortName() override;
|
QString generateShortName() override;
|
||||||
@@ -406,8 +406,11 @@ private:
|
|||||||
-> const base::flat_set<QString> & override;
|
-> const base::flat_set<QString> & override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
[[nodiscard]] QString name() const;
|
||||||
|
|
||||||
base::flat_set<QChar> _nameFirstLetters;
|
base::flat_set<QChar> _nameFirstLetters;
|
||||||
base::flat_set<QString> _nameWords;
|
base::flat_set<QString> _nameWords;
|
||||||
|
bool _userCreatesTopics = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1683,6 +1683,7 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
|||||||
std::optional<TimeId> videoTimestamp) {
|
std::optional<TimeId> videoTimestamp) {
|
||||||
struct State final {
|
struct State final {
|
||||||
base::flat_set<mtpRequestId> requests;
|
base::flat_set<mtpRequestId> requests;
|
||||||
|
mtpRequestId nextRequestKey = 0;
|
||||||
};
|
};
|
||||||
const auto state = std::make_shared<State>();
|
const auto state = std::make_shared<State>();
|
||||||
return [=](
|
return [=](
|
||||||
@@ -1732,13 +1733,6 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
|||||||
for (const auto &fullId : existingIds) {
|
for (const auto &fullId : existingIds) {
|
||||||
mtpMsgIds.push_back(MTP_int(fullId.msg));
|
mtpMsgIds.push_back(MTP_int(fullId.msg));
|
||||||
}
|
}
|
||||||
const auto generateRandom = [&] {
|
|
||||||
auto result = QVector<MTPlong>(existingIds.size());
|
|
||||||
for (auto &value : result) {
|
|
||||||
value = base::RandomValue<MTPlong>();
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
auto &api = history->session().api();
|
auto &api = history->session().api();
|
||||||
auto &histories = history->owner().histories();
|
auto &histories = history->owner().histories();
|
||||||
const auto donePhraseArgs = CreateForwardedMessagePhraseArgs(
|
const auto donePhraseArgs = CreateForwardedMessagePhraseArgs(
|
||||||
@@ -1747,103 +1741,170 @@ ShareBox::SubmitCallback ShareBox::DefaultForwardCallback(
|
|||||||
const auto showRecentForwardsToSelf = result.size() == 1
|
const auto showRecentForwardsToSelf = result.size() == 1
|
||||||
&& result.front()->peer()->isSelf()
|
&& result.front()->peer()->isSelf()
|
||||||
&& history->session().premium();
|
&& history->session().premium();
|
||||||
const auto requestType = Data::Histories::RequestType::Send;
|
|
||||||
for (const auto thread : result) {
|
for (const auto thread : result) {
|
||||||
|
const auto peer = thread->peer();
|
||||||
|
const auto threadHistory = thread->owningHistory();
|
||||||
|
const auto forum = threadHistory->asForum();
|
||||||
|
const auto needNewTopic = forum
|
||||||
|
&& forum->bot()
|
||||||
|
&& Data::IsBotUserCreatesTopics(peer)
|
||||||
|
&& !thread->asTopic();
|
||||||
|
const auto effectiveThread = [&]() -> not_null<Data::Thread*> {
|
||||||
|
if (needNewTopic) {
|
||||||
|
const auto topic = forum->reserveNewBotTopic();
|
||||||
|
Assert(topic != nullptr);
|
||||||
|
return topic;
|
||||||
|
}
|
||||||
|
return thread;
|
||||||
|
}();
|
||||||
|
|
||||||
if (!comment.text.isEmpty()) {
|
if (!comment.text.isEmpty()) {
|
||||||
auto message = Api::MessageToSend(
|
auto message = Api::MessageToSend(
|
||||||
Api::SendAction(thread, options));
|
Api::SendAction(effectiveThread, options));
|
||||||
message.textWithTags = comment;
|
message.textWithTags = comment;
|
||||||
message.action.clearDraft = false;
|
message.action.clearDraft = false;
|
||||||
api.sendMessage(std::move(message));
|
api.sendMessage(std::move(message));
|
||||||
}
|
}
|
||||||
const auto topicRootId = thread->topicRootId();
|
|
||||||
const auto sublistPeer = thread->maybeSublistPeer();
|
const auto topicRootId = effectiveThread->topicRootId();
|
||||||
const auto kGeneralId = Data::ForumTopic::kGeneralId;
|
const auto sublistPeer = needNewTopic
|
||||||
const auto topMsgId = (topicRootId == kGeneralId)
|
? nullptr
|
||||||
? MsgId(0)
|
: thread->maybeSublistPeer();
|
||||||
: topicRootId;
|
const auto fromPeer = history->peer;
|
||||||
const auto peer = thread->peer();
|
const auto msgCount = int(existingIds.size());
|
||||||
const auto threadHistory = thread->owningHistory();
|
|
||||||
const auto starsPaid = std::min(
|
const auto starsPaid = std::min(
|
||||||
peer->starsPerMessageChecked(),
|
peer->starsPerMessageChecked(),
|
||||||
options.starsApproved);
|
options.starsApproved);
|
||||||
if (starsPaid) {
|
if (starsPaid) {
|
||||||
options.starsApproved -= starsPaid;
|
options.starsApproved -= starsPaid;
|
||||||
}
|
}
|
||||||
histories.sendRequest(threadHistory, requestType, [=](
|
const auto sendFlags = commonSendFlags
|
||||||
Fn<void()> finish) {
|
| (ShouldSendSilent(peer, options)
|
||||||
const auto session = &threadHistory->session();
|
? Flag::f_silent
|
||||||
auto &api = session->api();
|
: Flag(0))
|
||||||
const auto sendFlags = commonSendFlags
|
| (options.shortcutId
|
||||||
| (topMsgId ? Flag::f_top_msg_id : Flag(0))
|
? Flag::f_quick_reply_shortcut
|
||||||
| (ShouldSendSilent(peer, options)
|
: Flag(0))
|
||||||
? Flag::f_silent
|
| (starsPaid ? Flag::f_allow_paid_stars : Flag())
|
||||||
: Flag(0))
|
| (sublistPeer ? Flag::f_reply_to : Flag())
|
||||||
| (options.shortcutId
|
| (options.suggest ? Flag::f_suggested_post : Flag())
|
||||||
? Flag::f_quick_reply_shortcut
|
| (options.effectId ? Flag::f_effect : Flag());
|
||||||
: Flag(0))
|
auto buildMessage = [=](
|
||||||
| (starsPaid ? Flag::f_allow_paid_stars : Flag())
|
not_null<History*> history,
|
||||||
| (sublistPeer ? Flag::f_reply_to : Flag())
|
FullReplyTo replyTo)
|
||||||
| (options.suggest ? Flag::f_suggested_post : Flag())
|
-> Data::Histories::PreparedMessage {
|
||||||
| (options.effectId ? Flag::f_effect : Flag());
|
const auto kGeneralId
|
||||||
threadHistory->sendRequestId = api.request(
|
= Data::ForumTopic::kGeneralId;
|
||||||
MTPmessages_ForwardMessages(
|
const auto realTopMsgId
|
||||||
MTP_flags(sendFlags),
|
= (replyTo.topicRootId == kGeneralId)
|
||||||
history->peer->input(),
|
? MsgId(0)
|
||||||
MTP_vector<MTPint>(mtpMsgIds),
|
: replyTo.topicRootId;
|
||||||
MTP_vector<MTPlong>(generateRandom()),
|
auto flags = sendFlags;
|
||||||
peer->input(),
|
if (realTopMsgId) {
|
||||||
MTP_int(topMsgId),
|
flags |= Flag::f_top_msg_id;
|
||||||
(sublistPeer
|
} else {
|
||||||
? MTP_inputReplyToMonoForum(sublistPeer->input())
|
flags &= ~Flag::f_top_msg_id;
|
||||||
: MTPInputReplyTo()),
|
}
|
||||||
MTP_int(options.scheduled),
|
auto randoms = QVector<MTPlong>(msgCount);
|
||||||
MTP_int(options.scheduleRepeatPeriod),
|
for (auto &value : randoms) {
|
||||||
MTP_inputPeerEmpty(), // send_as
|
value = base::RandomValue<MTPlong>();
|
||||||
Data::ShortcutIdToMTP(session, options.shortcutId),
|
}
|
||||||
MTP_long(options.effectId),
|
return MTPmessages_ForwardMessages(
|
||||||
MTP_int(videoTimestamp.value_or(0)),
|
MTP_flags(flags),
|
||||||
MTP_long(starsPaid),
|
fromPeer->input(),
|
||||||
Api::SuggestToMTP(options.suggest)
|
MTP_vector<MTPint>(mtpMsgIds),
|
||||||
)).done([=](const MTPUpdates &updates, mtpRequestId reqId) {
|
MTP_vector<MTPlong>(randoms),
|
||||||
threadHistory->session().api().applyUpdates(updates);
|
history->peer->input(),
|
||||||
if (showRecentForwardsToSelf) {
|
MTP_int(realTopMsgId),
|
||||||
ApiWrap::ProcessRecentSelfForwards(
|
(sublistPeer
|
||||||
&threadHistory->session(),
|
? MTP_inputReplyToMonoForum(
|
||||||
updates,
|
sublistPeer->input())
|
||||||
peer->id,
|
: MTPInputReplyTo()),
|
||||||
history->peer->id);
|
MTP_int(options.scheduled),
|
||||||
}
|
MTP_int(options.scheduleRepeatPeriod),
|
||||||
state->requests.remove(reqId);
|
MTP_inputPeerEmpty(),
|
||||||
if (state->requests.empty()) {
|
Data::ShortcutIdToMTP(
|
||||||
if (show->valid()) {
|
&history->session(),
|
||||||
auto phrase = rpl::variable<TextWithEntities>(
|
options.shortcutId),
|
||||||
ChatHelpers::ForwardedMessagePhrase(
|
MTP_long(options.effectId),
|
||||||
donePhraseArgs)).current();
|
MTP_int(videoTimestamp.value_or(0)),
|
||||||
if (!phrase.empty()) {
|
MTP_long(starsPaid),
|
||||||
show->showToast(std::move(phrase));
|
Api::SuggestToMTP(options.suggest));
|
||||||
}
|
};
|
||||||
show->hideLayer();
|
const auto requestDone = [=](
|
||||||
|
const MTPUpdates &updates,
|
||||||
|
mtpRequestId requestKey) {
|
||||||
|
if (showRecentForwardsToSelf) {
|
||||||
|
ApiWrap::ProcessRecentSelfForwards(
|
||||||
|
&threadHistory->session(),
|
||||||
|
updates,
|
||||||
|
peer->id,
|
||||||
|
history->peer->id);
|
||||||
|
}
|
||||||
|
state->requests.remove(requestKey);
|
||||||
|
if (state->requests.empty()) {
|
||||||
|
if (show->valid()) {
|
||||||
|
auto phrase = rpl::variable<
|
||||||
|
TextWithEntities>(
|
||||||
|
ChatHelpers::ForwardedMessagePhrase(
|
||||||
|
donePhraseArgs)).current();
|
||||||
|
if (!phrase.empty()) {
|
||||||
|
show->showToast(std::move(phrase));
|
||||||
}
|
}
|
||||||
|
show->hideLayer();
|
||||||
}
|
}
|
||||||
finish();
|
}
|
||||||
}).fail([=](const MTP::Error &error) {
|
};
|
||||||
const auto type = error.type();
|
const auto requestFail = [=](
|
||||||
if (type.startsWith(u"ALLOW_PAYMENT_REQUIRED_"_q)) {
|
const MTP::Error &error,
|
||||||
show->showToast(u"Payment requirements changed. "
|
mtpRequestId requestKey) {
|
||||||
"Please, try again."_q);
|
const auto type = error.type();
|
||||||
} else if (type == u"VOICE_MESSAGES_FORBIDDEN"_q) {
|
if (type.startsWith(
|
||||||
show->showToast(
|
u"ALLOW_PAYMENT_REQUIRED_"_q)) {
|
||||||
tr::lng_restricted_send_voice_messages(
|
show->showToast(
|
||||||
tr::now,
|
u"Payment requirements changed. "
|
||||||
lt_user,
|
"Please, try again."_q);
|
||||||
peer->name()));
|
} else if (type
|
||||||
|
== u"VOICE_MESSAGES_FORBIDDEN"_q) {
|
||||||
|
show->showToast(
|
||||||
|
tr::lng_restricted_send_voice_messages(
|
||||||
|
tr::now,
|
||||||
|
lt_user,
|
||||||
|
peer->name()));
|
||||||
|
}
|
||||||
|
state->requests.remove(requestKey);
|
||||||
|
if (state->requests.empty()) {
|
||||||
|
if (show->valid()) {
|
||||||
|
show->hideLayer();
|
||||||
}
|
}
|
||||||
finish();
|
}
|
||||||
}).afterRequest(threadHistory->sendRequestId).send();
|
};
|
||||||
return threadHistory->sendRequestId;
|
const auto requestKey = ++state->nextRequestKey;
|
||||||
});
|
state->requests.insert(requestKey);
|
||||||
state->requests.insert(threadHistory->sendRequestId);
|
histories.sendPreparedMessage(
|
||||||
|
threadHistory,
|
||||||
|
FullReplyTo{ .topicRootId = topicRootId },
|
||||||
|
uint64(0),
|
||||||
|
std::move(buildMessage),
|
||||||
|
[=](const MTPUpdates &updates,
|
||||||
|
const MTP::Response &) {
|
||||||
|
requestDone(updates, requestKey);
|
||||||
|
},
|
||||||
|
[=](const MTP::Error &error,
|
||||||
|
const MTP::Response &) {
|
||||||
|
requestFail(error, requestKey);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (state->requests.empty()) {
|
||||||
|
if (show->valid()) {
|
||||||
|
auto phrase = rpl::variable<TextWithEntities>(
|
||||||
|
ChatHelpers::ForwardedMessagePhrase(
|
||||||
|
donePhraseArgs)).current();
|
||||||
|
if (!phrase.empty()) {
|
||||||
|
show->showToast(std::move(phrase));
|
||||||
|
}
|
||||||
|
show->hideLayer();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -527,6 +527,15 @@ MsgId Forum::reserveCreatingId(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ForumTopic *Forum::reserveNewBotTopic() {
|
||||||
|
const auto &colors = ForumTopicColorIds();
|
||||||
|
const auto colorId = colors[base::RandomIndex(colors.size())];
|
||||||
|
return topicFor(reserveCreatingId(
|
||||||
|
tr::lng_bot_new_chat(tr::now),
|
||||||
|
colorId,
|
||||||
|
DocumentId()));
|
||||||
|
}
|
||||||
|
|
||||||
void Forum::discardCreatingId(MsgId rootId) {
|
void Forum::discardCreatingId(MsgId rootId) {
|
||||||
Expects(creating(rootId));
|
Expects(creating(rootId));
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ public:
|
|||||||
void discardCreatingId(MsgId rootId);
|
void discardCreatingId(MsgId rootId);
|
||||||
[[nodiscard]] bool creating(MsgId rootId) const;
|
[[nodiscard]] bool creating(MsgId rootId) const;
|
||||||
void created(MsgId rootId, MsgId realId);
|
void created(MsgId rootId, MsgId realId);
|
||||||
|
[[nodiscard]] ForumTopic *reserveNewBotTopic();
|
||||||
|
|
||||||
void clearAllUnreadMentions();
|
void clearAllUnreadMentions();
|
||||||
void clearAllUnreadReactions();
|
void clearAllUnreadReactions();
|
||||||
|
|||||||
@@ -112,7 +112,8 @@ public:
|
|||||||
MTPmessages_SendMessage,
|
MTPmessages_SendMessage,
|
||||||
MTPmessages_SendMedia,
|
MTPmessages_SendMedia,
|
||||||
MTPmessages_SendInlineBotResult,
|
MTPmessages_SendInlineBotResult,
|
||||||
MTPmessages_SendMultiMedia>;
|
MTPmessages_SendMultiMedia,
|
||||||
|
MTPmessages_ForwardMessages>;
|
||||||
int sendPreparedMessage(
|
int sendPreparedMessage(
|
||||||
not_null<History*> history,
|
not_null<History*> history,
|
||||||
FullReplyTo replyTo,
|
FullReplyTo replyTo,
|
||||||
|
|||||||
@@ -2231,9 +2231,9 @@ std::optional<uint8> ColorIndexFromColor(const MTPPeerColor *color) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsBotCanManageTopics(not_null<PeerData*> peer) {
|
bool IsBotUserCreatesTopics(not_null<PeerData*> peer) {
|
||||||
if (const auto user = peer->asUser()) {
|
if (const auto user = peer->asUser()) {
|
||||||
return user->botInfo && user->botInfo->canManageTopics;
|
return user->botInfo && user->botInfo->userCreatesTopics;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -678,6 +678,6 @@ void SetTopPinnedMessageId(
|
|||||||
[[nodiscard]] uint64 BackgroundEmojiIdFromColor(const MTPPeerColor *color);
|
[[nodiscard]] uint64 BackgroundEmojiIdFromColor(const MTPPeerColor *color);
|
||||||
[[nodiscard]] std::optional<uint8> ColorIndexFromColor(const MTPPeerColor *);
|
[[nodiscard]] std::optional<uint8> ColorIndexFromColor(const MTPPeerColor *);
|
||||||
|
|
||||||
[[nodiscard]] bool IsBotCanManageTopics(not_null<PeerData*>);
|
[[nodiscard]] bool IsBotUserCreatesTopics(not_null<PeerData*>);
|
||||||
|
|
||||||
} // namespace Data
|
} // namespace Data
|
||||||
|
|||||||
@@ -564,6 +564,28 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||||||
result->setStarsPerMessage(0);
|
result->setStarsPerMessage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!minimal) {
|
||||||
|
result->setBotInfoVersion(data.vbot_info_version().value_or(-1));
|
||||||
|
if (const auto info = result->botInfo.get()) {
|
||||||
|
info->readsAllHistory = data.is_bot_chat_history();
|
||||||
|
if (info->cantJoinGroups != data.is_bot_nochats()) {
|
||||||
|
info->cantJoinGroups = data.is_bot_nochats();
|
||||||
|
flags |= UpdateFlag::BotCanBeInvited;
|
||||||
|
}
|
||||||
|
if (const auto value = data.vbot_inline_placeholder()) {
|
||||||
|
info->inlinePlaceholder = '_' + qs(*value);
|
||||||
|
} else {
|
||||||
|
info->inlinePlaceholder = QString();
|
||||||
|
}
|
||||||
|
info->supportsAttachMenu = data.is_bot_attach_menu();
|
||||||
|
info->supportsBusiness = data.is_bot_business();
|
||||||
|
info->canEditInformation = data.is_bot_can_edit();
|
||||||
|
info->activeUsers = data.vbot_active_users().value_or_empty();
|
||||||
|
info->hasMainApp = data.is_bot_has_main_app();
|
||||||
|
info->userCreatesTopics = data.is_bot_forum_can_manage_topics();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using Flag = UserDataFlag;
|
using Flag = UserDataFlag;
|
||||||
const auto flagsMask = Flag::Deleted
|
const auto flagsMask = Flag::Deleted
|
||||||
| Flag::Verified
|
| Flag::Verified
|
||||||
@@ -739,28 +761,6 @@ not_null<UserData*> Session::processUser(const MTPUser &data) {
|
|||||||
result->setEmojiStatus(EmojiStatusId());
|
result->setEmojiStatus(EmojiStatusId());
|
||||||
}
|
}
|
||||||
if (!minimal) {
|
if (!minimal) {
|
||||||
if (const auto botInfoVersion = data.vbot_info_version()) {
|
|
||||||
result->setBotInfoVersion(botInfoVersion->v);
|
|
||||||
result->botInfo->readsAllHistory = data.is_bot_chat_history();
|
|
||||||
if (result->botInfo->cantJoinGroups != data.is_bot_nochats()) {
|
|
||||||
result->botInfo->cantJoinGroups = data.is_bot_nochats();
|
|
||||||
flags |= UpdateFlag::BotCanBeInvited;
|
|
||||||
}
|
|
||||||
if (const auto placeholder = data.vbot_inline_placeholder()) {
|
|
||||||
result->botInfo->inlinePlaceholder = '_' + qs(*placeholder);
|
|
||||||
} else {
|
|
||||||
result->botInfo->inlinePlaceholder = QString();
|
|
||||||
}
|
|
||||||
result->botInfo->supportsAttachMenu = data.is_bot_attach_menu();
|
|
||||||
result->botInfo->supportsBusiness = data.is_bot_business();
|
|
||||||
result->botInfo->canEditInformation = data.is_bot_can_edit();
|
|
||||||
result->botInfo->activeUsers = data.vbot_active_users().value_or_empty();
|
|
||||||
result->botInfo->hasMainApp = data.is_bot_has_main_app();
|
|
||||||
result->botInfo->canManageTopics
|
|
||||||
= data.is_bot_forum_can_manage_topics();
|
|
||||||
} else {
|
|
||||||
result->setBotInfoVersion(-1);
|
|
||||||
}
|
|
||||||
result->setIsContact(data.is_contact()
|
result->setIsContact(data.is_contact()
|
||||||
|| data.is_mutual_contact());
|
|| data.is_mutual_contact());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ struct BotInfo {
|
|||||||
bool canManageEmojiStatus : 1 = false;
|
bool canManageEmojiStatus : 1 = false;
|
||||||
bool supportsBusiness : 1 = false;
|
bool supportsBusiness : 1 = false;
|
||||||
bool hasMainApp : 1 = false;
|
bool hasMainApp : 1 = false;
|
||||||
bool canManageTopics : 1 = false;
|
bool userCreatesTopics : 1 = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Data::Forum> _forum;
|
std::unique_ptr<Data::Forum> _forum;
|
||||||
|
|||||||
@@ -4719,12 +4719,12 @@ void HistoryWidget::hideSelectorControlsAnimated() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Api::SendAction HistoryWidget::prepareSendAction(
|
Api::SendAction HistoryWidget::prepareSendAction(
|
||||||
Api::SendOptions options) const {
|
Api::SendOptions options) {
|
||||||
auto result = Api::SendAction(_history, options);
|
auto result = Api::SendAction(_history, options);
|
||||||
result.replyTo = replyTo();
|
result.replyTo = replyTo();
|
||||||
|
|
||||||
if (const auto forum = _history->asForum()) {
|
if (const auto forum = _history->asForum()) {
|
||||||
if (Data::IsBotCanManageTopics(_history->peer)) {
|
if (forum->bot() && Data::IsBotUserCreatesTopics(_history->peer)) {
|
||||||
const auto readyRootId = [&]() -> MsgId {
|
const auto readyRootId = [&]() -> MsgId {
|
||||||
if (const auto id = result.replyTo.messageId) {
|
if (const auto id = result.replyTo.messageId) {
|
||||||
if (const auto item = session().data().message(id)) {
|
if (const auto item = session().data().message(id)) {
|
||||||
@@ -4737,14 +4737,15 @@ Api::SendAction HistoryWidget::prepareSendAction(
|
|||||||
result.replyTo.topicRootId = readyRootId;
|
result.replyTo.topicRootId = readyRootId;
|
||||||
} else {
|
} else {
|
||||||
if (!_creatingBotTopic) {
|
if (!_creatingBotTopic) {
|
||||||
const auto &colors = Data::ForumTopicColorIds();
|
_creatingBotTopic = forum->reserveNewBotTopic();
|
||||||
const auto colorId
|
auto draft = _history->forwardDraft(MsgId(0), PeerId());
|
||||||
= colors[base::RandomIndex(colors.size())];
|
if (!draft.ids.empty()) {
|
||||||
_creatingBotTopic = forum->topicFor(
|
_history->setForwardDraft(MsgId(0), PeerId(), {});
|
||||||
forum->reserveCreatingId(
|
_history->setForwardDraft(
|
||||||
tr::lng_bot_new_chat(tr::now),
|
_creatingBotTopic->rootId(),
|
||||||
colorId,
|
PeerId(),
|
||||||
DocumentId()));
|
std::move(draft));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
result = Api::SendAction(_creatingBotTopic, options);
|
result = Api::SendAction(_creatingBotTopic, options);
|
||||||
result.replyTo.topicRootId = _creatingBotTopic->rootId();
|
result.replyTo.topicRootId = _creatingBotTopic->rootId();
|
||||||
@@ -6302,7 +6303,7 @@ void HistoryWidget::updateFieldPlaceholder() {
|
|||||||
}
|
}
|
||||||
} else if (const auto user = peer->asUser()) {
|
} else if (const auto user = peer->asUser()) {
|
||||||
if (const auto &info = user->botInfo) {
|
if (const auto &info = user->botInfo) {
|
||||||
if (info->forum() && !info->canManageTopics) {
|
if (info->forum() && !info->userCreatesTopics) {
|
||||||
return tr::lng_bot_off_thread_ph();
|
return tr::lng_bot_off_thread_ph();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -422,7 +422,7 @@ private:
|
|||||||
void messageDataReceived(not_null<PeerData*> peer, MsgId msgId);
|
void messageDataReceived(not_null<PeerData*> peer, MsgId msgId);
|
||||||
|
|
||||||
[[nodiscard]] Api::SendAction prepareSendAction(
|
[[nodiscard]] Api::SendAction prepareSendAction(
|
||||||
Api::SendOptions options) const;
|
Api::SendOptions options);
|
||||||
void sendVoice(const VoiceToSend &data);
|
void sendVoice(const VoiceToSend &data);
|
||||||
void send(Api::SendOptions options);
|
void send(Api::SendOptions options);
|
||||||
void sendWithModifiers(Qt::KeyboardModifiers modifiers);
|
void sendWithModifiers(Qt::KeyboardModifiers modifiers);
|
||||||
|
|||||||
@@ -636,7 +636,7 @@ bool AboutView::aboveHistory() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const auto info = _history->peer->asUser()->botInfo.get();
|
const auto info = _history->peer->asUser()->botInfo.get();
|
||||||
return !(info->canManageTopics
|
return !(info->userCreatesTopics
|
||||||
&& info->startToken.isEmpty()
|
&& info->startToken.isEmpty()
|
||||||
&& (!_history->isEmpty() || _history->lastMessage()));
|
&& (!_history->isEmpty() || _history->lastMessage()));
|
||||||
}
|
}
|
||||||
@@ -696,7 +696,7 @@ bool AboutView::refresh() {
|
|||||||
_version = 0;
|
_version = 0;
|
||||||
return false;
|
return false;
|
||||||
} else if (_history->peer->isForum()
|
} else if (_history->peer->isForum()
|
||||||
&& info->canManageTopics
|
&& info->userCreatesTopics
|
||||||
&& info->startToken.isEmpty()
|
&& info->startToken.isEmpty()
|
||||||
&& (!_history->isEmpty() || _history->lastMessage())) {
|
&& (!_history->isEmpty() || _history->lastMessage())) {
|
||||||
if (_item) {
|
if (_item) {
|
||||||
|
|||||||
@@ -453,7 +453,7 @@ void SubsectionTabs::startFillingSlider(
|
|||||||
).append(' ').append(peer->shortName()),
|
).append(' ').append(peer->shortName()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// } else if (Data::IsBotCanManageTopics(item.thread->peer())) {
|
// } else if (Data::IsBotUserCreatesTopics(item.thread->peer())) {
|
||||||
// sections.push_back({
|
// sections.push_back({
|
||||||
// .text = { tr::lng_bot_new_chat(tr::now) },
|
// .text = { tr::lng_bot_new_chat(tr::now) },
|
||||||
// });
|
// });
|
||||||
|
|||||||
@@ -654,28 +654,31 @@ bool MainWidget::sendPaths(
|
|||||||
|
|
||||||
bool MainWidget::filesOrForwardDrop(
|
bool MainWidget::filesOrForwardDrop(
|
||||||
not_null<Data::Thread*> thread,
|
not_null<Data::Thread*> thread,
|
||||||
not_null<const QMimeData*> data) {
|
not_null<const QMimeData*> data,
|
||||||
if (const auto forum = thread->asForum()) {
|
bool forumResolved) {
|
||||||
Window::ShowDropMediaBox(
|
if (!forumResolved) {
|
||||||
_controller,
|
if (const auto forum = thread->asForum()) {
|
||||||
Core::ShareMimeMediaData(data),
|
Window::ShowDropMediaBox(
|
||||||
forum);
|
_controller,
|
||||||
if (_hider) {
|
Core::ShareMimeMediaData(data),
|
||||||
_hider->startHide();
|
forum);
|
||||||
clearHider(_hider);
|
if (_hider) {
|
||||||
|
_hider->startHide();
|
||||||
|
clearHider(_hider);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (const auto history = thread->asHistory()
|
||||||
|
; history && history->peer->monoforum()) {
|
||||||
|
Window::ShowDropMediaBox(
|
||||||
|
_controller,
|
||||||
|
Core::ShareMimeMediaData(data),
|
||||||
|
history->peer->monoforum());
|
||||||
|
if (_hider) {
|
||||||
|
_hider->startHide();
|
||||||
|
clearHider(_hider);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
} else if (const auto history = thread->asHistory()
|
|
||||||
; history && history->peer->monoforum()) {
|
|
||||||
Window::ShowDropMediaBox(
|
|
||||||
_controller,
|
|
||||||
Core::ShareMimeMediaData(data),
|
|
||||||
history->peer->monoforum());
|
|
||||||
if (_hider) {
|
|
||||||
_hider->startHide();
|
|
||||||
clearHider(_hider);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
if (data->hasFormat(u"application/x-td-forward"_q)) {
|
if (data->hasFormat(u"application/x-td-forward"_q)) {
|
||||||
auto draft = Data::ForwardDraft{
|
auto draft = Data::ForwardDraft{
|
||||||
|
|||||||
@@ -161,7 +161,8 @@ public:
|
|||||||
const QString &text) const;
|
const QString &text) const;
|
||||||
bool filesOrForwardDrop(
|
bool filesOrForwardDrop(
|
||||||
not_null<Data::Thread*> thread,
|
not_null<Data::Thread*> thread,
|
||||||
not_null<const QMimeData*> data);
|
not_null<const QMimeData*> data,
|
||||||
|
bool forumResolved = false);
|
||||||
|
|
||||||
void sendBotCommand(Bot::SendCommandRequest request);
|
void sendBotCommand(Bot::SendCommandRequest request);
|
||||||
void hideSingleUseKeyboard(FullMsgId replyToId);
|
void hideSingleUseKeyboard(FullMsgId replyToId);
|
||||||
|
|||||||
@@ -3278,7 +3278,7 @@ base::weak_qptr<Ui::BoxContent> ShowDropMediaBox(
|
|||||||
navigation
|
navigation
|
||||||
](not_null<Data::Thread*> thread) mutable {
|
](not_null<Data::Thread*> thread) mutable {
|
||||||
const auto content = navigation->parentController()->content();
|
const auto content = navigation->parentController()->content();
|
||||||
if (!content->filesOrForwardDrop(thread, data.get())) {
|
if (!content->filesOrForwardDrop(thread, data.get(), true)) {
|
||||||
return;
|
return;
|
||||||
} else if (const auto strong = *weak) {
|
} else if (const auto strong = *weak) {
|
||||||
strong->closeBox();
|
strong->closeBox();
|
||||||
@@ -3318,7 +3318,7 @@ base::weak_qptr<Ui::BoxContent> ShowDropMediaBox(
|
|||||||
navigation
|
navigation
|
||||||
](not_null<Data::SavedSublist*> sublist) mutable {
|
](not_null<Data::SavedSublist*> sublist) mutable {
|
||||||
const auto content = navigation->parentController()->content();
|
const auto content = navigation->parentController()->content();
|
||||||
if (!content->filesOrForwardDrop(sublist, data.get())) {
|
if (!content->filesOrForwardDrop(sublist, data.get(), true)) {
|
||||||
return;
|
return;
|
||||||
} else if (const auto strong = *weak) {
|
} else if (const auto strong = *weak) {
|
||||||
strong->closeBox();
|
strong->closeBox();
|
||||||
|
|||||||
Reference in New Issue
Block a user